milestone 20: declarative configuration for iac

This commit is contained in:
2026-08-11 23:31:40 +02:00
parent 2f29121e27
commit d76afc147a
74 changed files with 6722 additions and 1949 deletions
+19 -2
View File
@@ -7,9 +7,17 @@ import ClientEditDialog from "./ClientEditDialog";
import PrefixesEditor from "./PrefixesEditor";
import InlineError from "@/lib/InlineError";
import { smallButtonClass, tableWrapClass } from "@/ui/classes";
import { READ_ONLY_HINT, useReadOnlyConfig } from "@/features/settings/authority";
const cellClass = "px-3 py-2";
/**
* Deleting an observed row discards runtime state the file never declared, so
* it stays live under file authority; deleting a hand-edited row contradicts
* the file and is the one client DELETE the server answers 403 (ruling 7).
*/
const DECLARED_CLIENT_NOTE = "This client is declared in the configuration file; remove it there and restart.";
export default function ClientsPage() {
const { data: clients } = useSuspenseQuery(clientsQuery());
const { data: prefixes } = useSuspenseQuery(clientPrefixesQuery());
@@ -18,6 +26,7 @@ export default function ClientsPage() {
const deleteMutation = useMutation(clientDeleteMutation(queryClient));
const [editing, setEditing] = useState<Client | null>(null);
const [confirmingId, setConfirmingId] = useState<number | null>(null);
const readOnly = useReadOnlyConfig();
return (
<section>
@@ -86,14 +95,22 @@ export default function ClientsPage() {
<button
type="button"
onClick={() => setEditing(client)}
className={smallButtonClass}
disabled={readOnly}
title={readOnly ? READ_ONLY_HINT : undefined}
className={`${smallButtonClass} disabled:opacity-50`}
>
Edit
</button>
<button
type="button"
onClick={() => setConfirmingId(client.id)}
className={`${smallButtonClass} text-red-700 dark:text-red-400`}
disabled={readOnly && client.hand_edited}
title={
readOnly && client.hand_edited
? DECLARED_CLIENT_NOTE
: undefined
}
className={`${smallButtonClass} text-red-700 disabled:opacity-50 dark:text-red-400`}
>
Delete
</button>