// ============================================================ // Callbacks: CRUD management // ============================================================ import { t, showToast, escapeHtml, closeDialog, showConfirm, getAuthHeaders, hasCredentials } from './core.js'; import { IconSelect } from './icon-select.js'; import { callbackEventIcons } from './icons.js'; export let callbackFormDirty = false; export function setCallbackFormDirty(value) { callbackFormDirty = value; } let _callbackEventIconSelect = null; function _ensureCallbackEventIconSelect() { if (_callbackEventIconSelect) return; const select = document.getElementById('callbackName'); if (!select) return; const items = Object.entries(callbackEventIcons).map(([value, icon]) => ({ value, icon, label: value, })); _callbackEventIconSelect = new IconSelect({ target: select, items, columns: 3, placeholder: t('callbacks.placeholder.event'), onChange: () => { callbackFormDirty = true; }, }); } let _loadCallbacksPromise = null; export async function loadCallbacksTable() { if (_loadCallbacksPromise) return _loadCallbacksPromise; _loadCallbacksPromise = _loadCallbacksTableImpl(); _loadCallbacksPromise.finally(() => { _loadCallbacksPromise = null; }); return _loadCallbacksPromise; } async function _loadCallbacksTableImpl() { const tbody = document.getElementById('callbacksTableBody'); try { const response = await fetch('/api/callbacks/list', { headers: getAuthHeaders() }); if (!response.ok) { throw new Error('Failed to fetch callbacks'); } const callbacksList = await response.json(); if (callbacksList.length === 0) { tbody.innerHTML = '

' + t('callbacks.empty') + '

'; return; } tbody.innerHTML = callbacksList.map(callback => ` ${escapeHtml(callback.name)} ${escapeHtml(callback.command)} ${callback.timeout}s
`).join(''); } catch (error) { console.error('Error loading callbacks:', error); tbody.innerHTML = `${escapeHtml(t('callbacks.msg.load_failed'))}`; } } export function showAddCallbackDialog() { const dialog = document.getElementById('callbackDialog'); const form = document.getElementById('callbackForm'); const title = document.getElementById('callbackDialogTitle'); form.reset(); document.getElementById('callbackIsEdit').value = 'false'; document.getElementById('callbackName').disabled = false; title.textContent = t('callbacks.dialog.add'); _ensureCallbackEventIconSelect(); if (_callbackEventIconSelect) _callbackEventIconSelect.setValue('', false); callbackFormDirty = false; document.body.classList.add('dialog-open'); dialog.showModal(); } export async function showEditCallbackDialog(callbackName) { const dialog = document.getElementById('callbackDialog'); const title = document.getElementById('callbackDialogTitle'); try { const response = await fetch('/api/callbacks/list', { headers: getAuthHeaders() }); if (!response.ok) { throw new Error('Failed to fetch callback details'); } const callbacksList = await response.json(); const callback = callbacksList.find(c => c.name === callbackName); if (!callback) { showToast(t('callbacks.msg.not_found'), 'error'); return; } document.getElementById('callbackIsEdit').value = 'true'; document.getElementById('callbackName').value = callbackName; document.getElementById('callbackName').disabled = true; _ensureCallbackEventIconSelect(); if (_callbackEventIconSelect) _callbackEventIconSelect.setValue(callbackName, false); document.getElementById('callbackCommand').value = callback.command; document.getElementById('callbackTimeout').value = callback.timeout; document.getElementById('callbackWorkingDir').value = callback.working_dir || ''; title.textContent = t('callbacks.dialog.edit'); callbackFormDirty = false; document.body.classList.add('dialog-open'); dialog.showModal(); } catch (error) { console.error('Error loading callback for edit:', error); showToast(t('callbacks.msg.load_failed'), 'error'); } } export async function closeCallbackDialog() { if (callbackFormDirty) { if (!await showConfirm(t('callbacks.confirm.unsaved'))) { return; } } const dialog = document.getElementById('callbackDialog'); callbackFormDirty = false; closeDialog(dialog); document.body.classList.remove('dialog-open'); } export async function saveCallback(event) { event.preventDefault(); const submitBtn = event.target.querySelector('button[type="submit"]'); if (submitBtn) submitBtn.disabled = true; const isEdit = document.getElementById('callbackIsEdit').value === 'true'; const callbackName = document.getElementById('callbackName').value; const data = { command: document.getElementById('callbackCommand').value, timeout: parseInt(document.getElementById('callbackTimeout').value) || 30, working_dir: document.getElementById('callbackWorkingDir').value || null, shell: true }; const encodedName = encodeURIComponent(callbackName); const endpoint = isEdit ? `/api/callbacks/update/${encodedName}` : `/api/callbacks/create/${encodedName}`; const method = isEdit ? 'PUT' : 'POST'; try { const response = await fetch(endpoint, { method, headers: { 'Content-Type': 'application/json', ...getAuthHeaders() }, body: JSON.stringify(data) }); const result = await response.json(); if (response.ok && result.success) { showToast(t(isEdit ? 'callbacks.msg.updated' : 'callbacks.msg.created'), 'success'); callbackFormDirty = false; closeCallbackDialog(); loadCallbacksTable(); } else { showToast(result.detail || t(isEdit ? 'callbacks.msg.update_failed' : 'callbacks.msg.create_failed'), 'error'); } } catch (error) { console.error('Error saving callback:', error); showToast(t(isEdit ? 'callbacks.msg.update_failed' : 'callbacks.msg.create_failed'), 'error'); } finally { if (submitBtn) submitBtn.disabled = false; } } export async function deleteCallbackConfirm(callbackName) { if (!await showConfirm(t('callbacks.confirm.delete').replace('{name}', callbackName))) { return; } try { const response = await fetch(`/api/callbacks/delete/${encodeURIComponent(callbackName)}`, { method: 'DELETE', headers: getAuthHeaders() }); const result = await response.json(); if (response.ok && result.success) { showToast(t('callbacks.msg.deleted'), 'success'); loadCallbacksTable(); } else { showToast(result.detail || t('callbacks.msg.delete_failed'), 'error'); } } catch (error) { console.error('Error deleting callback:', error); showToast(t('callbacks.msg.delete_failed'), 'error'); } }