218 lines
7.6 KiB
JavaScript
218 lines
7.6 KiB
JavaScript
// ── Session Edit Page ──
|
|
|
|
let _sessionImageData = null;
|
|
let _sessionPasteHandler = null;
|
|
|
|
function _createCommandRow(container, name = '', command = '', type = 'background') {
|
|
const item = document.createElement('div');
|
|
item.className = 'custom-command-item';
|
|
item.innerHTML = `
|
|
<div class="custom-command-fields">
|
|
<select class="cmd-type">
|
|
<option value="background">Hintergrund</option>
|
|
<option value="foreground">Vordergrund</option>
|
|
<option value="message">Nachricht</option>
|
|
</select>
|
|
<input type="text" class="cmd-name" placeholder="Name (z.B. Deploy)" value="${_escAttr(name)}">
|
|
<input type="text" class="cmd-command" placeholder="${type === 'message' ? 'Nachricht...' : 'Befehl (z.B. ./deploy.sh)'}" value="${_escAttr(command)}">
|
|
</div>
|
|
<button type="button" class="remove-cmd-btn icon-btn"><i class="fa fa-times"></i></button>
|
|
`;
|
|
const typeSelect = item.querySelector('.cmd-type');
|
|
typeSelect.value = type;
|
|
typeSelect.addEventListener('change', () => {
|
|
const cmdInput = item.querySelector('.cmd-command');
|
|
cmdInput.placeholder = typeSelect.value === 'message' ? 'Nachricht...' : 'Befehl (z.B. ./deploy.sh)';
|
|
});
|
|
item.querySelector('.remove-cmd-btn').addEventListener('click', () => item.remove());
|
|
container.appendChild(item);
|
|
}
|
|
|
|
function _escAttr(str) {
|
|
return str.replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>');
|
|
}
|
|
|
|
function _getCommandsFromUI(container) {
|
|
const items = container.querySelectorAll('.custom-command-item');
|
|
const commands = [];
|
|
for (const item of items) {
|
|
const name = item.querySelector('.cmd-name').value.trim();
|
|
const command = item.querySelector('.cmd-command').value.trim();
|
|
const type = item.querySelector('.cmd-type').value;
|
|
if (name || command) commands.push({ name, command, type });
|
|
}
|
|
return commands.length > 0 ? commands : null;
|
|
}
|
|
|
|
registerPage('session', {
|
|
async init(params) {
|
|
const sessionId = params.id;
|
|
const isNew = !sessionId;
|
|
let session = null;
|
|
|
|
if (!isNew) {
|
|
session = await apiGetSession(sessionId);
|
|
if (!session) return navigateTo('dashboard');
|
|
}
|
|
|
|
const titleEl = document.getElementById('sessionPageTitle');
|
|
const nameEl = document.getElementById('sessionName');
|
|
const descEl = document.getElementById('sessionDescription');
|
|
const contextEl = document.getElementById('sessionContext');
|
|
const workspaceEl = document.getElementById('sessionWorkspace');
|
|
const agentSelect = document.getElementById('agentSelect');
|
|
const imagePreview = document.getElementById('sessionImagePreview');
|
|
const imageInput = document.getElementById('sessionImageInput');
|
|
const imageBtn = document.getElementById('sessionImageBtn');
|
|
const imageClearBtn = document.getElementById('sessionImageClearBtn');
|
|
const saveBtn = document.getElementById('sessionSaveBtn');
|
|
const cancelBtn = document.getElementById('sessionCancelBtn');
|
|
const deleteBtn = document.getElementById('sessionDeleteBtn');
|
|
const openChatBtn = document.getElementById('openChatBtn');
|
|
const commandsList = document.getElementById('customCommandsList');
|
|
const addCommandBtn = document.getElementById('addCommandBtn');
|
|
|
|
_sessionImageData = null;
|
|
|
|
if (session) {
|
|
titleEl.textContent = session.name || 'Unbenannt';
|
|
nameEl.value = session.name || '';
|
|
descEl.value = session.description || '';
|
|
contextEl.value = session.context || '';
|
|
workspaceEl.value = session.workspace || '';
|
|
_sessionImageData = session.image || null;
|
|
deleteBtn.hidden = false;
|
|
openChatBtn.disabled = false;
|
|
|
|
if (session.image) {
|
|
imagePreview.innerHTML = `<img src="${session.image}" alt="">`;
|
|
}
|
|
|
|
// Custom Commands laden
|
|
if (session.customCommands) {
|
|
try {
|
|
const cmds = typeof session.customCommands === 'string'
|
|
? JSON.parse(session.customCommands)
|
|
: session.customCommands;
|
|
for (const cmd of cmds) {
|
|
_createCommandRow(commandsList, cmd.name || '', cmd.command || '', cmd.type || 'background');
|
|
}
|
|
} catch (e) { /* ignore parse errors */ }
|
|
}
|
|
} else {
|
|
titleEl.textContent = 'Neue Session';
|
|
deleteBtn.hidden = true;
|
|
openChatBtn.disabled = true;
|
|
}
|
|
|
|
// Befehl hinzufügen
|
|
addCommandBtn.addEventListener('click', () => _createCommandRow(commandsList));
|
|
|
|
// Agents laden
|
|
const agents = await apiGetAgents();
|
|
agentSelect.innerHTML = '<option value="">-- Kein Agent --</option>';
|
|
for (const a of agents) {
|
|
const opt = document.createElement('option');
|
|
opt.value = a.agentId;
|
|
opt.textContent = `${a.name} (${a.model})`;
|
|
agentSelect.appendChild(opt);
|
|
}
|
|
if (session && session.agentId) agentSelect.value = session.agentId;
|
|
|
|
// Bild Upload
|
|
imageBtn.addEventListener('click', () => imageInput.click());
|
|
imageInput.addEventListener('change', () => {
|
|
const file = imageInput.files[0];
|
|
if (!file) return;
|
|
const reader = new FileReader();
|
|
reader.onload = () => {
|
|
_sessionImageData = reader.result;
|
|
imagePreview.innerHTML = `<img src="${reader.result}" alt="">`;
|
|
};
|
|
reader.readAsDataURL(file);
|
|
});
|
|
|
|
imageClearBtn.addEventListener('click', () => {
|
|
_sessionImageData = null;
|
|
imagePreview.innerHTML = '?';
|
|
imageInput.value = '';
|
|
});
|
|
|
|
// Bild Paste (Ctrl+V)
|
|
document.addEventListener('paste', _sessionPasteHandler = (e) => {
|
|
const items = e.clipboardData?.items;
|
|
if (!items) return;
|
|
for (const item of items) {
|
|
if (item.type.startsWith('image/')) {
|
|
e.preventDefault();
|
|
const file = item.getAsFile();
|
|
if (!file) return;
|
|
const reader = new FileReader();
|
|
reader.onload = () => {
|
|
_sessionImageData = reader.result;
|
|
imagePreview.innerHTML = `<img src="${reader.result}" alt="">`;
|
|
};
|
|
reader.readAsDataURL(file);
|
|
return;
|
|
}
|
|
}
|
|
});
|
|
|
|
// Workspace Browse
|
|
const workspaceBrowse = document.getElementById('sessionWorkspaceBrowse');
|
|
if (workspaceBrowse) {
|
|
workspaceBrowse.addEventListener('click', () => {
|
|
openFolderBrowser({
|
|
startPath: workspaceEl.value.trim() || '/',
|
|
onSelect(path) {
|
|
workspaceEl.value = path;
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
// Speichern
|
|
saveBtn.addEventListener('click', async () => {
|
|
const commands = _getCommandsFromUI(commandsList);
|
|
const data = {
|
|
name: nameEl.value.trim() || 'Unbenannt',
|
|
description: descEl.value.trim(),
|
|
image: _sessionImageData,
|
|
agentId: agentSelect.value || null,
|
|
context: contextEl.value || null,
|
|
workspace: workspaceEl.value.trim() || null,
|
|
customCommands: commands
|
|
};
|
|
|
|
if (isNew) {
|
|
await apiCreateSession(data);
|
|
} else {
|
|
await apiUpdateSession(sessionId, data);
|
|
}
|
|
navigateTo('dashboard');
|
|
});
|
|
|
|
// Abbrechen
|
|
cancelBtn.addEventListener('click', () => navigateTo('dashboard'));
|
|
|
|
// Löschen
|
|
deleteBtn.addEventListener('click', async () => {
|
|
if (!confirm('Session wirklich löschen?')) return;
|
|
await apiDeleteSession(sessionId);
|
|
navigateTo('dashboard');
|
|
});
|
|
|
|
// Chat öffnen
|
|
openChatBtn.addEventListener('click', () => {
|
|
navigateTo('chat', { id: sessionId });
|
|
});
|
|
},
|
|
destroy() {
|
|
if (_sessionPasteHandler) {
|
|
document.removeEventListener('paste', _sessionPasteHandler);
|
|
_sessionPasteHandler = null;
|
|
}
|
|
_sessionImageData = null;
|
|
}
|
|
});
|