Add whisper docker dependency controls to dashboard
This commit is contained in:
@@ -21,7 +21,9 @@ let _lastCouncilResult = null;
|
||||
let _lastCouncilError = null;
|
||||
let _lastServices = [];
|
||||
let _lastLocalBackends = [];
|
||||
let _lastDockerDependencies = [];
|
||||
let _localBackendActionState = new Map();
|
||||
let _dockerDependencyActionState = new Map();
|
||||
let _serviceConfigState = {
|
||||
open: false,
|
||||
serviceName: null,
|
||||
@@ -39,6 +41,12 @@ const LOCAL_BACKEND_ACTION_LABELS = {
|
||||
stop: 'Stop',
|
||||
update: 'Update',
|
||||
};
|
||||
const DOCKER_DEPENDENCY_ACTION_LABELS = {
|
||||
start: 'Start',
|
||||
restart: 'Restart',
|
||||
stop: 'Stop',
|
||||
update: 'Update',
|
||||
};
|
||||
const SERVICE_TOGGLE_PATCH_PATHS = {
|
||||
heartbeat: 'automation.heartbeat.enabled',
|
||||
daily_briefing: 'automation.daily_briefing.enabled',
|
||||
@@ -1624,6 +1632,7 @@ function updateDockerDependencies(dockerDependenciesData) {
|
||||
if (!el) {return;}
|
||||
|
||||
const dependencies = dockerDependenciesData?.dependencies ?? [];
|
||||
_lastDockerDependencies = dependencies;
|
||||
|
||||
if (dependencies.length === 0) {
|
||||
el.innerHTML = '<div class="text-sm text-zinc-500">No docker dependencies detected</div>';
|
||||
@@ -1631,6 +1640,9 @@ function updateDockerDependencies(dockerDependenciesData) {
|
||||
}
|
||||
|
||||
el.innerHTML = dependencies.map((dependency) => {
|
||||
const dependencyId = String(dependency.id ?? '');
|
||||
const actionState = _dockerDependencyActionState.get(dependencyId) ?? null;
|
||||
const isPending = Boolean(actionState?.pending);
|
||||
const state = String(dependency.state ?? 'unknown');
|
||||
const health = String(dependency.health ?? 'unknown');
|
||||
const statusText = String(dependency.statusText ?? state);
|
||||
@@ -1645,6 +1657,23 @@ function updateDockerDependencies(dockerDependenciesData) {
|
||||
? 'text-red-500'
|
||||
: 'text-zinc-400';
|
||||
const containerName = dependency.containerName ? String(dependency.containerName) : '—';
|
||||
const availableActions = Array.isArray(dependency.availableActions)
|
||||
? dependency.availableActions.filter((value) => ['start', 'restart', 'stop', 'update'].includes(String(value)))
|
||||
: [];
|
||||
const actionMessage = actionState?.message
|
||||
? `<div class="text-xs ${actionState.tone === 'error' ? 'text-red-400' : actionState.tone === 'success' ? 'text-green-400' : 'text-zinc-400'}">${escapeHtml(String(actionState.message))}</div>`
|
||||
: '';
|
||||
const actionButtons = availableActions.length > 0
|
||||
? availableActions.map((action) => {
|
||||
const key = String(action);
|
||||
const label = DOCKER_DEPENDENCY_ACTION_LABELS[key] ?? key;
|
||||
return `<button class="docker-dependency-action-btn px-2 py-1 text-xs border border-zinc-700 rounded text-zinc-200 hover:bg-zinc-800 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
data-dependency-id="${escapeHtml(dependencyId)}"
|
||||
data-action="${escapeHtml(key)}"
|
||||
${isPending ? 'disabled' : ''}
|
||||
title="${escapeHtml(`${label} ${dependency.name ?? dependencyId}`)}">${escapeHtml(label)}</button>`;
|
||||
}).join('')
|
||||
: '<span class="text-xs text-zinc-500">No actions available</span>';
|
||||
|
||||
return `<div class="bg-zinc-900 border border-zinc-800 rounded-lg p-3 flex flex-col gap-2">
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
@@ -1656,8 +1685,19 @@ function updateDockerDependencies(dockerDependenciesData) {
|
||||
<div class="text-xs text-zinc-500">State: <span class="font-mono text-zinc-400">${escapeHtml(state)}</span> · Health: <span class="font-mono text-zinc-400">${escapeHtml(health)}</span></div>
|
||||
<div class="text-xs ${configuredClass}">${escapeHtml(configuredText)}</div>
|
||||
${dependency.error ? `<div class="text-xs text-red-400">Error: ${escapeHtml(String(dependency.error))}</div>` : ''}
|
||||
${actionMessage}
|
||||
<div class="flex flex-wrap gap-2">${actionButtons}</div>
|
||||
</div>`;
|
||||
}).join('');
|
||||
|
||||
el.querySelectorAll('.docker-dependency-action-btn').forEach((button) => {
|
||||
button.addEventListener('click', async () => {
|
||||
const dependencyId = button.getAttribute('data-dependency-id');
|
||||
const action = button.getAttribute('data-action');
|
||||
if (!dependencyId || !action) {return;}
|
||||
await handleDockerDependencyAction(dependencyId, action);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function handleLocalBackendAction(backendId, action) {
|
||||
@@ -1702,6 +1742,48 @@ async function handleLocalBackendAction(backendId, action) {
|
||||
}
|
||||
}
|
||||
|
||||
async function handleDockerDependencyAction(dependencyId, action) {
|
||||
if (!_dashboardClient) {return;}
|
||||
const actionLabel = DOCKER_DEPENDENCY_ACTION_LABELS[action] ?? action;
|
||||
_dockerDependencyActionState.set(dependencyId, { pending: true, tone: 'neutral', message: `${actionLabel} requested…` });
|
||||
updateDockerDependencies({ dependencies: _lastDockerDependencies });
|
||||
|
||||
try {
|
||||
const result = await _dashboardClient.call('system.dockerDependencyControl', {
|
||||
dependency: dependencyId,
|
||||
action,
|
||||
});
|
||||
const status = result?.status;
|
||||
const resultMessage = typeof result?.message === 'string' ? result.message : null;
|
||||
if (status && typeof status === 'object') {
|
||||
_lastDockerDependencies = _lastDockerDependencies.map((dependency) =>
|
||||
dependency.id === dependencyId ? status : dependency);
|
||||
}
|
||||
_dockerDependencyActionState.set(dependencyId, {
|
||||
pending: false,
|
||||
tone: 'success',
|
||||
message: resultMessage ? `${actionLabel} completed: ${resultMessage}` : `${actionLabel} completed`,
|
||||
});
|
||||
updateDockerDependencies({ dependencies: _lastDockerDependencies });
|
||||
|
||||
const refreshed = await fetchSlow(_dashboardClient);
|
||||
if (refreshed?.localBackends) {
|
||||
updateLocalBackends(refreshed.localBackends);
|
||||
}
|
||||
if (refreshed?.dockerDependencies) {
|
||||
updateDockerDependencies(refreshed.dockerDependencies);
|
||||
}
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
_dockerDependencyActionState.set(dependencyId, {
|
||||
pending: false,
|
||||
tone: 'error',
|
||||
message: `${actionLabel} failed: ${message}`,
|
||||
});
|
||||
updateDockerDependencies({ dependencies: _lastDockerDependencies });
|
||||
}
|
||||
}
|
||||
|
||||
function getConfigValue(path, fallbackValue) {
|
||||
const value = getByPath(_lastAssistantConfig, path);
|
||||
return value === undefined ? fallbackValue : value;
|
||||
@@ -2052,7 +2134,9 @@ export const DashboardPage = {
|
||||
_assistantDraftTouchedAt = 0;
|
||||
_lastServices = [];
|
||||
_lastLocalBackends = [];
|
||||
_lastDockerDependencies = [];
|
||||
_localBackendActionState = new Map();
|
||||
_dockerDependencyActionState = new Map();
|
||||
_serviceConfigState = {
|
||||
open: false,
|
||||
serviceName: null,
|
||||
|
||||
Reference in New Issue
Block a user