ui: Apply everywhere — power toggles, plan preview, no start/stop/install

Rework the dashboard around convergence:
- ServiceControls / ServiceCard / JobCard: replace start/restart/stop
  with a Power toggle (set enabled → apply, i.e. activate/deactivate)
  plus Restart (the one imperative bounce).
- ToolDetail: install/uninstall becomes an Enable/Disable toggle;
  `installed` stays the live state, `enabled` the desired one.
- ConfigPanel Apply and CreateDeploymentForm now POST /apply (one
  converge that renders + restarts only what changed) instead of
  /deploy + a separate start/restart.
- New ConvergePanel on Overview: a terraform-style Preview (POST /apply
  plan=true) showing would-activate/restart/deactivate, then Apply.
- useApply + useSetEnabled hooks; `enabled` added to Service/Job/
  Deployment types; both handle the self-restart connection drop.

Backend: PUT /config/deployments/{name}/enabled sets desired on/off
(edit config; caller runs apply) — the declarative toggle the UI uses.

Dashboard builds clean (tsc + vite); 59 API tests pass; live /apply and
/services?enabled verified after an api restart.
This commit is contained in:
2026-07-02 11:49:54 -07:00
parent 5d15d18e1d
commit f422c1879d
13 changed files with 292 additions and 121 deletions

View File

@@ -1,6 +1,6 @@
import { useParams } from "react-router-dom"
import { Clock } from "lucide-react"
import { useJob, useStatus } from "@/services/api/hooks"
import { useJob } from "@/services/api/hooks"
import { LogViewer } from "@/components/LogViewer"
import { DetailHeader } from "@/components/detail/DetailHeader"
import { ServiceControls } from "@/components/detail/ServiceControls"
@@ -10,8 +10,6 @@ import { ConfigPanel } from "@/components/detail/ConfigPanel"
export function ScheduledDetailPage() {
const { name } = useParams<{ name: string }>()
const { data: deployment, isLoading, error, refetch } = useJob(name ?? "")
const { data: statusResp } = useStatus()
const health = statusResp?.statuses.find((s) => s.id === name)
if (isLoading) {
return (
@@ -38,7 +36,7 @@ export function ScheduledDetailPage() {
stack={deployment.stack}
source={deployment.source}
>
<ServiceControls name={deployment.id} health={health} />
<ServiceControls name={deployment.id} enabled={deployment.enabled} />
</DetailHeader>
{deployment.schedule && (