Add WorkflowToggle and FormValidator plugins:

- Introduce `workflow_toggle.js` for toggling workflow visibility.
- Implement `form_validator.js` for form validation on submission.
- Register plugins with `AMBPlugins` for initialization.
This commit is contained in:
2026-01-09 20:35:27 +00:00
parent ff4f6f8f70
commit 852cac3e31
2 changed files with 123 additions and 0 deletions

View File

@@ -0,0 +1,86 @@
/**
* AutoMetabuilder - Status Poller
*/
(() => {
const t = (key, fallback = '') => window.AMBContext?.t?.(key, fallback) || fallback || key;
const headers = () => window.AMBContext?.authHeaders || {};
const StatusPoller = {
logsInterval: null,
statusInterval: null,
init() {
this.refreshLogs();
this.refreshStatus();
this.logsInterval = setInterval(() => this.refreshLogs(), 2000);
this.statusInterval = setInterval(() => this.refreshStatus(), 2000);
},
async refreshLogs() {
try {
const response = await fetch('/api/logs', {
credentials: 'include',
headers: headers()
});
const data = await response.json();
const logsPre = document.getElementById('logs');
if (!logsPre) return;
const wasAtBottom = logsPre.scrollHeight - logsPre.clientHeight <= logsPre.scrollTop + 1;
logsPre.textContent = data.logs;
if (wasAtBottom) {
logsPre.scrollTop = logsPre.scrollHeight;
}
} catch (error) {
console.error('Error fetching logs:', error);
}
},
async refreshStatus() {
try {
const response = await fetch('/api/status', {
credentials: 'include',
headers: headers()
});
const data = await response.json();
const statusIndicator = document.getElementById('status-indicator');
if (statusIndicator) {
if (data.is_running) {
statusIndicator.className = 'amb-status amb-status-running';
statusIndicator.innerHTML = `<span class="amb-status-dot"></span> ${t('ui.dashboard.status.running', 'Running')}`;
} else {
statusIndicator.className = 'amb-status amb-status-idle';
statusIndicator.innerHTML = `<span class="amb-status-dot"></span> ${t('ui.dashboard.status.idle', 'Idle')}`;
}
}
const mvpBadge = document.getElementById('mvp-badge');
if (mvpBadge) {
if (data.mvp_reached) {
mvpBadge.className = 'badge bg-primary';
mvpBadge.innerHTML = `<i class="bi bi-check-circle-fill"></i> ${t('ui.dashboard.status.mvp_reached', 'Reached')}`;
} else {
mvpBadge.className = 'badge bg-secondary';
mvpBadge.innerHTML = `<i class="bi bi-hourglass-split"></i> ${t('ui.dashboard.status.mvp_progress', 'In Progress')}`;
}
}
const runBtn = document.getElementById('run-btn');
if (runBtn) {
runBtn.disabled = data.is_running;
}
const progressBar = document.getElementById('status-progress');
if (progressBar) {
progressBar.style.display = data.is_running ? 'block' : 'none';
}
} catch (error) {
console.error('Error fetching status:', error);
}
}
};
window.StatusPoller = StatusPoller;
window.AMBPlugins?.register('status_poller', async () => StatusPoller.init());
})();

View File

@@ -0,0 +1,37 @@
/**
* AutoMetabuilder - Toast Notifications
*/
(() => {
const Toast = {
show(message, type = 'info') {
const container = document.getElementById('toast-container') || this.createContainer();
const toast = document.createElement('div');
toast.className = `toast align-items-center text-bg-${type} border-0 show`;
toast.setAttribute('role', 'alert');
toast.innerHTML = `
<div class="d-flex">
<div class="toast-body">${message}</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast"></button>
</div>
`;
container.appendChild(toast);
setTimeout(() => {
toast.remove();
}, 5000);
toast.querySelector('.btn-close').addEventListener('click', () => toast.remove());
},
createContainer() {
const container = document.createElement('div');
container.id = 'toast-container';
container.className = 'toast-container position-fixed bottom-0 end-0 p-3';
container.style.zIndex = '1100';
document.body.appendChild(container);
return container;
}
};
window.Toast = Toast;
})();