milestone 32: task-shaped configuration, file mode as a rendering, config status api
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { configStatusQuery } from "@/lib/queries";
|
||||
import type { ConfigStatus } from "@/lib/types";
|
||||
|
||||
/**
|
||||
* Configuration authority as the UI must treat it: three states, never two.
|
||||
*
|
||||
* `undefined` is not database mode. Until `/api/config/status` answers, the
|
||||
* running process may be file-managed, and a form rendered on that guess
|
||||
* invites edits the server will reject. So a page shows neither an editable
|
||||
* form nor a definition list until the query resolves, and a failed query is
|
||||
* an explicit error with a way to retry.
|
||||
*/
|
||||
export type Authority =
|
||||
| { state: "pending" }
|
||||
| { state: "failed"; error: unknown; retry: () => void }
|
||||
| { state: "resolved"; status: ConfigStatus };
|
||||
|
||||
/**
|
||||
* The running server's configuration status. Every page may call this — it is
|
||||
* the shared `["configStatus"]` key, so one subscription serves them all from
|
||||
* cache.
|
||||
*/
|
||||
export function useAuthority(): Authority {
|
||||
const query = useQuery(configStatusQuery());
|
||||
if (query.isPending) return { state: "pending" };
|
||||
if (query.isError) {
|
||||
return {
|
||||
state: "failed",
|
||||
error: query.error,
|
||||
retry: () => void query.refetch(),
|
||||
};
|
||||
}
|
||||
return { state: "resolved", status: query.data };
|
||||
}
|
||||
|
||||
/**
|
||||
* True unless the server has said the database owns the configuration.
|
||||
*
|
||||
* The lock is global and it fails closed: pending, failed and `managed_file`
|
||||
* all read as locked, because only a resolved database authority proves a
|
||||
* configuration mutation can succeed. Runtime actions — pause, update now,
|
||||
* reload certificates, deleting an observed client, login and logout — do not
|
||||
* consult it; they work under every authority.
|
||||
*/
|
||||
export function useReadOnlyConfig(): boolean {
|
||||
const authority = useAuthority();
|
||||
return !(authority.state === "resolved" && authority.status.authority === "database");
|
||||
}
|
||||
Reference in New Issue
Block a user