import { createContext, useContext, useState, type ReactNode } from 'react' import { runOnServers, type ServerAction, type ServerParams } from '../api/hub-run' import { RunFlow, pickerServers, type RunRequest } from '../screens/apps/RunFlow' import { HubWritable } from './hub-write' /* Behind a hub, a change that belongs on several servers at once (Blocked and Allowed, the blocking switch, the block lists, the cache) goes through the same three steps as the apps: pick the servers, wait, read what happened on each, with "Retry failed". This is the glue: · `HubServerIds`: every server the hub fronts, given by the shell. The picker lists all of them and disables the ones the hub holds no admin token for, with the reason. · `useAllServersFlow`: `start(spec)` opens the flow, `flow` is the element to render. · `HubAll`: what a section provides to the controls inside it when "All servers" is chosen and the role may make the change. A control that finds `null` there behaves as it always did. */ export const HubServerIds = createContext([]) export interface AllSpec { action: ServerAction params?: ServerParams title: string intro?: ReactNode confirmLabel?: string /** The servers ticked at the start; every writable one when absent. */ preselected?: string[] /** After the flow closes, told whether any server changed. */ onDone?: (changed: boolean) => void } export type StartAll = (spec: AllSpec) => void export const HubAll = createContext(null) export function useAllServersFlow(token: string | null): { start: StartAll; flow: ReactNode } { const ids = useContext(HubServerIds) const writable = useContext(HubWritable) const [open, setOpen] = useState<{ spec: AllSpec; request: RunRequest } | null>(null) const start: StartAll = (spec) => { const request: RunRequest = { title: spec.title, intro: spec.intro, confirmLabel: spec.confirmLabel ?? 'Run', servers: pickerServers(ids.map((id) => ({ id, writable: writable.includes(id) }))), preselected: spec.preselected ?? ids.filter((id) => writable.includes(id)), run: (targets) => runOnServers(token, spec.action, spec.params ?? {}, targets), } setOpen({ spec, request }) } const flow = open === null ? null : ( { const done = open.spec.onDone setOpen(null) done?.(changed) }} /> ) return { start, flow } }