408 lines
16 KiB
JavaScript
408 lines
16 KiB
JavaScript
// workflow-module.js
|
|
(function() {
|
|
// Workflow-Modul-Zustand
|
|
let workflowState = {
|
|
selectedFiles: [],
|
|
selectedAgents: [],
|
|
prompt: "",
|
|
logs: [],
|
|
results: [],
|
|
isRunning: false
|
|
};
|
|
|
|
// DOM-Elemente
|
|
let availableFiles, selectedFiles, emptyFilesState,
|
|
fileInput, uploadBtn, promptInput, promptSelect,
|
|
agentList, resetBtn, startWorkflowBtn,
|
|
executionLog, resultsContainer,
|
|
emptyResultsState, resultsList;
|
|
|
|
// Initialisierungsfunktion für das Workflow-Modul
|
|
function initWorkflowModule(globalState) {
|
|
// DOM-Elemente referenzieren
|
|
availableFiles = document.getElementById('available-files');
|
|
selectedFiles = document.getElementById('selected-files');
|
|
emptyFilesState = document.getElementById('empty-files-state');
|
|
fileInput = document.getElementById('file-input');
|
|
uploadBtn = document.getElementById('upload-btn');
|
|
promptInput = document.getElementById('prompt-input');
|
|
promptSelect = document.getElementById('prompt-select');
|
|
agentList = document.getElementById('agent-list');
|
|
resetBtn = document.getElementById('reset-btn');
|
|
startWorkflowBtn = document.getElementById('start-workflow-btn');
|
|
executionLog = document.getElementById('execution-log');
|
|
resultsContainer = document.getElementById('results-container');
|
|
emptyResultsState = document.getElementById('empty-results-state');
|
|
resultsList = document.getElementById('results-list');
|
|
|
|
// Event-Listener hinzufügen
|
|
setupEventListeners(globalState);
|
|
|
|
// Initialdaten rendern
|
|
renderFiles(globalState);
|
|
renderPromptSelector(globalState);
|
|
renderAgents(globalState);
|
|
}
|
|
|
|
// Event-Listener einrichten
|
|
function setupEventListeners(globalState) {
|
|
// Datei-Upload
|
|
uploadBtn.addEventListener('click', () => fileInput.click());
|
|
fileInput.addEventListener('change',
|
|
window.globalUtils.handleFileUpload(fileInput, (newFile) => {
|
|
// Nach erfolgreichem Upload
|
|
workflowState.selectedFiles.push(newFile);
|
|
renderSelectedFiles();
|
|
renderFiles(globalState);
|
|
})
|
|
);
|
|
|
|
// Prompt-Eingabe
|
|
promptInput.addEventListener('input', (e) => {
|
|
workflowState.prompt = e.target.value;
|
|
});
|
|
|
|
// Prompt-Auswahl
|
|
promptSelect.addEventListener('change', () => {
|
|
const selectedPromptId = promptSelect.value;
|
|
if (selectedPromptId) {
|
|
const selectedPrompt = globalState.availablePrompts.find(p => p.id === selectedPromptId);
|
|
if (selectedPrompt) {
|
|
promptInput.value = selectedPrompt.content;
|
|
workflowState.prompt = selectedPrompt.content;
|
|
}
|
|
}
|
|
});
|
|
|
|
// Zurücksetzen
|
|
resetBtn.addEventListener('click', resetWorkflow);
|
|
|
|
// Workflow starten
|
|
startWorkflowBtn.addEventListener('click', () => runWorkflow(globalState));
|
|
}
|
|
|
|
// Verfügbare Dateien rendern
|
|
function renderFiles(globalState) {
|
|
availableFiles.innerHTML = '';
|
|
globalState.availableFiles.forEach(file => {
|
|
const li = document.createElement('li');
|
|
li.className = 'file-item';
|
|
const isSelected = workflowState.selectedFiles.some(f => f.id === file.id);
|
|
li.innerHTML = `
|
|
<div class="file-item-name">
|
|
<input type="checkbox" id="file-${file.id}" ${isSelected ? 'checked' : ''}>
|
|
<label for="file-${file.id}">
|
|
<i class="fas ${file.type === 'document' ? 'fa-file-alt' : 'fa-file-image'}"></i>
|
|
${file.name}
|
|
</label>
|
|
</div>
|
|
<span class="file-item-info">${file.size || ''}</span>
|
|
`;
|
|
const checkbox = li.querySelector(`#file-${file.id}`);
|
|
checkbox.addEventListener('change', () => {
|
|
if (checkbox.checked) {
|
|
workflowState.selectedFiles.push(file);
|
|
} else {
|
|
workflowState.selectedFiles = workflowState.selectedFiles.filter(f => f.id !== file.id);
|
|
}
|
|
renderSelectedFiles();
|
|
});
|
|
availableFiles.appendChild(li);
|
|
});
|
|
}
|
|
|
|
// Ausgewählte Dateien rendern
|
|
function renderSelectedFiles() {
|
|
if (workflowState.selectedFiles.length === 0) {
|
|
emptyFilesState.style.display = 'flex';
|
|
selectedFiles.innerHTML = '';
|
|
} else {
|
|
emptyFilesState.style.display = 'none';
|
|
selectedFiles.innerHTML = '';
|
|
workflowState.selectedFiles.forEach(file => {
|
|
const li = document.createElement('li');
|
|
li.className = 'selected-file-item';
|
|
li.innerHTML = `
|
|
<div class="file-item-name">
|
|
<i class="fas ${file.type === 'document' ? 'fa-file-alt' : 'fa-file-image'}"></i>
|
|
${file.name}
|
|
</div>
|
|
<button class="remove-file-btn" data-id="${file.id}">
|
|
<i class="fas fa-times"></i>
|
|
</button>
|
|
`;
|
|
selectedFiles.appendChild(li);
|
|
});
|
|
|
|
// Event-Listener für Entfernen-Buttons
|
|
document.querySelectorAll('.remove-file-btn').forEach(btn => {
|
|
btn.addEventListener('click', () => {
|
|
const fileId = btn.getAttribute('data-id');
|
|
workflowState.selectedFiles = workflowState.selectedFiles.filter(f => f.id !== fileId);
|
|
renderSelectedFiles();
|
|
renderFiles(window.globalState);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
// Prompt-Auswahlbox rendern
|
|
function renderPromptSelector(globalState) {
|
|
// Existierende Optionen entfernen (außer der ersten)
|
|
while (promptSelect.options.length > 1) {
|
|
promptSelect.remove(1);
|
|
}
|
|
|
|
// Prompts aus dem globalen State hinzufügen
|
|
globalState.availablePrompts.forEach(prompt => {
|
|
const option = document.createElement('option');
|
|
option.value = prompt.id;
|
|
option.textContent = prompt.content.substring(0, 50) + (prompt.content.length > 50 ? '...' : '');
|
|
promptSelect.appendChild(option);
|
|
});
|
|
}
|
|
|
|
// Agenten rendern
|
|
function renderAgents(globalState) {
|
|
agentList.innerHTML = '';
|
|
|
|
// Agenten für den aktuellen Workspace filtern
|
|
const workspaceAgents = globalState.availableAgents.filter(
|
|
agent => agent.workspace_id === globalState.currentWorkspace?.id
|
|
);
|
|
|
|
if (workspaceAgents.length === 0) {
|
|
agentList.innerHTML = '<div class="empty-state">Keine Agenten im ausgewählten Workspace verfügbar.</div>';
|
|
return;
|
|
}
|
|
|
|
workspaceAgents.forEach(agent => {
|
|
const li = document.createElement('li');
|
|
li.className = 'agent-item';
|
|
const isSelected = workflowState.selectedAgents.some(a => a.id === agent.id);
|
|
li.innerHTML = `
|
|
<div class="agent-header">
|
|
<input type="checkbox" id="agent-${agent.id}" class="agent-checkbox" ${isSelected ? 'checked' : ''}>
|
|
<label for="agent-${agent.id}" class="agent-name">${agent.name}</label>
|
|
</div>
|
|
<div class="agent-description">${agent.description || ''}</div>
|
|
`;
|
|
const checkbox = li.querySelector(`#agent-${agent.id}`);
|
|
checkbox.addEventListener('change', () => {
|
|
if (checkbox.checked) {
|
|
workflowState.selectedAgents.push(agent);
|
|
} else {
|
|
workflowState.selectedAgents = workflowState.selectedAgents.filter(a => a.id !== agent.id);
|
|
}
|
|
});
|
|
agentList.appendChild(li);
|
|
});
|
|
}
|
|
|
|
// Ausführungsprotokoll aktualisieren
|
|
function addLogEntry(message, type = 'info') {
|
|
const log = {
|
|
id: `log_${Date.now()}`,
|
|
message,
|
|
type,
|
|
timestamp: new Date().toISOString()
|
|
};
|
|
workflowState.logs.push(log);
|
|
renderLogs();
|
|
return log;
|
|
}
|
|
|
|
// Protokoll rendern
|
|
function renderLogs() {
|
|
if (workflowState.logs.length === 0) {
|
|
executionLog.innerHTML = '<div class="log-empty-state">Workflow noch nicht gestartet. Protokoll wird hier angezeigt.</div>';
|
|
return;
|
|
}
|
|
|
|
executionLog.innerHTML = '';
|
|
workflowState.logs.forEach(log => {
|
|
const logEntry = document.createElement('div');
|
|
logEntry.className = 'log-entry';
|
|
logEntry.innerHTML = `
|
|
<span class="log-time">[${new Date(log.timestamp).toLocaleTimeString()}]</span>
|
|
<span class="log-message log-${log.type}">${log.message}</span>
|
|
`;
|
|
executionLog.appendChild(logEntry);
|
|
});
|
|
|
|
// Zum Ende scrollen
|
|
executionLog.scrollTop = executionLog.scrollHeight;
|
|
}
|
|
|
|
// Ergebnis hinzufügen
|
|
function addResult(result) {
|
|
workflowState.results.push(result);
|
|
renderResults();
|
|
}
|
|
|
|
// Ergebnisse rendern
|
|
function renderResults() {
|
|
if (workflowState.results.length === 0) {
|
|
emptyResultsState.style.display = 'flex';
|
|
resultsList.style.display = 'none';
|
|
return;
|
|
}
|
|
|
|
emptyResultsState.style.display = 'none';
|
|
resultsList.style.display = 'block';
|
|
resultsList.innerHTML = '';
|
|
|
|
workflowState.results.forEach(result => {
|
|
const resultItem = document.createElement('div');
|
|
resultItem.className = 'result-item';
|
|
|
|
if (result.type === 'text') {
|
|
resultItem.innerHTML = `
|
|
<div class="result-header">
|
|
<div>
|
|
<div class="result-title">${result.title}</div>
|
|
<div class="result-agent">Erstellt von: ${result.agent_name}</div>
|
|
</div>
|
|
<button class="save-btn">
|
|
<i class="fas fa-save"></i> Speichern
|
|
</button>
|
|
</div>
|
|
<div class="result-content">${result.content}</div>
|
|
`;
|
|
} else if (result.type === 'chart') {
|
|
resultItem.innerHTML = `
|
|
<div class="result-header">
|
|
<div>
|
|
<div class="result-title">${result.title}</div>
|
|
<div class="result-agent">Erstellt von: ${result.agent_name}</div>
|
|
</div>
|
|
<button class="save-btn">
|
|
<i class="fas fa-save"></i> Speichern
|
|
</button>
|
|
</div>
|
|
<div class="chart-container">
|
|
<div class="chart-title">Umsatzentwicklung nach Quartal</div>
|
|
<div>${result.content}</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
resultsList.appendChild(resultItem);
|
|
});
|
|
}
|
|
|
|
// Workflow-Ausführung
|
|
async function runWorkflow(globalState) {
|
|
if (workflowState.selectedFiles.length === 0 ||
|
|
workflowState.selectedAgents.length === 0 ||
|
|
!workflowState.prompt.trim()) {
|
|
alert("Bitte wählen Sie Dateien und Agenten aus und geben Sie einen Prompt ein.");
|
|
return;
|
|
}
|
|
|
|
workflowState.isRunning = true;
|
|
workflowState.logs = [];
|
|
workflowState.results = [];
|
|
|
|
startWorkflowBtn.textContent = 'Wird ausgeführt...';
|
|
startWorkflowBtn.classList.add('running');
|
|
startWorkflowBtn.disabled = true;
|
|
|
|
renderLogs();
|
|
renderResults();
|
|
|
|
try {
|
|
// API-Aufruf an das Backend für Workflow-Ausführung
|
|
const workflowData = {
|
|
workspace_id: globalState.currentWorkspace.id,
|
|
files: workflowState.selectedFiles.map(file => file.id),
|
|
agents: workflowState.selectedAgents.map(agent => agent.id),
|
|
prompt: workflowState.prompt,
|
|
workflow_name: "Workflow " + new Date().toLocaleString()
|
|
};
|
|
|
|
const response = await window.globalUtils.postData('/api/workflow/run', workflowData);
|
|
|
|
if (response && response.workflow_id) {
|
|
const workflowId = response.workflow_id;
|
|
addLogEntry("Workflow gestartet", "info");
|
|
addLogEntry(`Workflow-ID: ${workflowId}`, "info");
|
|
|
|
// Polling für Workflow-Status und -Ergebnisse starten
|
|
pollWorkflowStatus(workflowId);
|
|
} else {
|
|
throw new Error("Workflow konnte nicht gestartet werden");
|
|
}
|
|
} catch (error) {
|
|
console.error("Fehler beim Starten des Workflows:", error);
|
|
workflowState.isRunning = false;
|
|
startWorkflowBtn.textContent = 'Workflow starten';
|
|
startWorkflowBtn.classList.remove('running');
|
|
startWorkflowBtn.disabled = false;
|
|
|
|
addLogEntry(`Fehler beim Starten des Workflows: ${error.message}`, "error");
|
|
}
|
|
}
|
|
|
|
// Workflow-Status abfragen
|
|
async function pollWorkflowStatus(workflowId) {
|
|
try {
|
|
// Status abrufen
|
|
const status = await window.globalUtils.fetchData(`/api/workflow/${workflowId}/status`);
|
|
|
|
// Logs abrufen und anzeigen
|
|
const logs = await window.globalUtils.fetchData(`/api/workflow/${workflowId}/logs`);
|
|
workflowState.logs = logs;
|
|
renderLogs();
|
|
|
|
// Status aktualisieren
|
|
if (status) {
|
|
// Fortschritt anzeigen
|
|
addLogEntry(`Fortschritt: ${Math.round(status.progress * 100)}%`, "info");
|
|
|
|
// Wenn der Workflow abgeschlossen ist, Ergebnisse abrufen
|
|
if (status.status === 'completed' || status.status === 'failed') {
|
|
const results = await window.globalUtils.fetchData(`/api/workflow/${workflowId}/results`);
|
|
workflowState.results = results;
|
|
renderResults();
|
|
|
|
addLogEntry(`Workflow ${status.status === 'completed' ? 'erfolgreich beendet' : 'fehlgeschlagen'}`,
|
|
status.status === 'completed' ? "success" : "error");
|
|
|
|
workflowState.isRunning = false;
|
|
startWorkflowBtn.textContent = 'Workflow starten';
|
|
startWorkflowBtn.classList.remove('running');
|
|
startWorkflowBtn.disabled = false;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Weiteres Polling nach einer kurzen Verzögerung
|
|
setTimeout(() => pollWorkflowStatus(workflowId), 2000);
|
|
} catch (error) {
|
|
console.error("Fehler beim Abrufen des Workflow-Status:", error);
|
|
addLogEntry(`Fehler beim Abrufen des Workflow-Status: ${error.message}`, "error");
|
|
|
|
workflowState.isRunning = false;
|
|
startWorkflowBtn.textContent = 'Workflow starten';
|
|
startWorkflowBtn.classList.remove('running');
|
|
startWorkflowBtn.disabled = false;
|
|
}
|
|
}
|
|
|
|
// Workflow zurücksetzen
|
|
function resetWorkflow() {
|
|
workflowState.selectedFiles = [];
|
|
workflowState.selectedAgents = [];
|
|
promptInput.value = "";
|
|
promptSelect.selectedIndex = 0;
|
|
workflowState.prompt = "";
|
|
|
|
renderFiles(window.globalState);
|
|
renderSelectedFiles();
|
|
renderAgents(window.globalState);
|
|
}
|
|
|
|
// Modul-Initialisierung exportieren
|
|
window.initWorkflowModule = initWorkflowModule;
|
|
})();
|