Adicionar botão Interromper no terminal e corrigir botão Retomar
- Botão Interromper na toolbar do terminal para matar execuções ativas - Endpoint POST /executions/cancel-all para cancelar agentes e pipelines - Botão aparece/esconde automaticamente conforme execuções ativas - Corrigir condição do botão Retomar para pipelines antigas sem failedAtStep
This commit is contained in:
@@ -481,6 +481,10 @@
|
||||
<span class="ws-indicator ws-indicator--disconnected" id="terminal-ws-dot"></span>
|
||||
<span id="terminal-ws-label">Desconectado</span>
|
||||
</div>
|
||||
<button class="btn btn--danger btn--sm btn--icon-text" type="button" id="terminal-stop-btn" aria-label="Interromper execução" hidden>
|
||||
<i data-lucide="square"></i>
|
||||
<span>Interromper</span>
|
||||
</button>
|
||||
<button class="btn btn--ghost btn--sm btn--icon-text" type="button" id="terminal-clear-btn" aria-label="Limpar terminal">
|
||||
<i data-lucide="trash-2"></i>
|
||||
<span>Limpar</span>
|
||||
|
||||
@@ -118,6 +118,7 @@ const API = {
|
||||
status() { return API.request('GET', '/system/status'); },
|
||||
info() { return API.request('GET', '/system/info'); },
|
||||
activeExecutions() { return API.request('GET', '/executions/active'); },
|
||||
cancelAll() { return API.request('POST', '/executions/cancel-all'); },
|
||||
},
|
||||
|
||||
settings: {
|
||||
|
||||
@@ -555,6 +555,18 @@ const App = {
|
||||
|
||||
on('pipeline-execute-submit', 'click', () => PipelinesUI._executeFromModal());
|
||||
|
||||
on('terminal-stop-btn', 'click', async () => {
|
||||
try {
|
||||
await API.system.cancelAll();
|
||||
Terminal.stopProcessing();
|
||||
Terminal.addLine('Todas as execuções foram interrompidas.', 'error');
|
||||
Toast.warning('Execuções interrompidas');
|
||||
App._updateActiveBadge();
|
||||
} catch (err) {
|
||||
Toast.error(`Erro ao interromper: ${err.message}`);
|
||||
}
|
||||
});
|
||||
|
||||
on('terminal-clear-btn', 'click', () => {
|
||||
Terminal.clear();
|
||||
Terminal.disableChat();
|
||||
@@ -960,6 +972,9 @@ const App = {
|
||||
if (countEl) countEl.textContent = count;
|
||||
if (badge) badge.style.display = count > 0 ? 'flex' : 'none';
|
||||
|
||||
const stopBtn = document.getElementById('terminal-stop-btn');
|
||||
if (stopBtn) stopBtn.hidden = count === 0;
|
||||
|
||||
const terminalSelect = document.getElementById('terminal-execution-select');
|
||||
if (terminalSelect && Array.isArray(active)) {
|
||||
const existing = new Set(
|
||||
|
||||
@@ -102,7 +102,7 @@ const HistoryUI = {
|
||||
<i data-lucide="eye"></i>
|
||||
Ver detalhes
|
||||
</button>
|
||||
${(exec.status === 'error' && exec.type === 'pipeline' && exec.failedAtStep !== undefined) ? `
|
||||
${(exec.status === 'error' && exec.type === 'pipeline') ? `
|
||||
<button class="btn btn-ghost btn-sm" data-action="resume-pipeline" data-id="${exec.id}" type="button" title="Retomar do passo ${(exec.failedAtStep || 0) + 1}">
|
||||
<i data-lucide="play"></i>
|
||||
Retomar
|
||||
|
||||
@@ -8,7 +8,7 @@ import * as manager from '../agents/manager.js';
|
||||
import { tasksStore, settingsStore, executionsStore, webhooksStore, notificationsStore, secretsStore, agentVersionsStore } from '../store/db.js';
|
||||
import * as scheduler from '../agents/scheduler.js';
|
||||
import * as pipeline from '../agents/pipeline.js';
|
||||
import { getBinPath, updateMaxConcurrent } from '../agents/executor.js';
|
||||
import { getBinPath, updateMaxConcurrent, cancelAllExecutions, getActiveExecutions } from '../agents/executor.js';
|
||||
import { invalidateAgentMapCache } from '../agents/pipeline.js';
|
||||
import { cached } from '../cache/index.js';
|
||||
import { readdirSync, readFileSync, unlinkSync, existsSync, mkdirSync } from 'fs';
|
||||
@@ -838,6 +838,23 @@ router.get('/executions/active', (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/executions/cancel-all', (req, res) => {
|
||||
try {
|
||||
const activePipelines = pipeline.getActivePipelines();
|
||||
for (const p of activePipelines) {
|
||||
pipeline.cancelPipeline(p.pipelineId);
|
||||
}
|
||||
cancelAllExecutions();
|
||||
const running = executionsStore.getAll().filter(e => e.status === 'running' || e.status === 'awaiting_approval');
|
||||
for (const e of running) {
|
||||
executionsStore.update(e.id, { status: 'canceled', endedAt: new Date().toISOString() });
|
||||
}
|
||||
res.json({ cancelled: true });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/executions/recent', (req, res) => {
|
||||
try {
|
||||
const limit = parseInt(req.query.limit) || 20;
|
||||
|
||||
Reference in New Issue
Block a user