Files
DDI/web/src/components/ClusterSelect.tsx
T
sir_melonchenandClaude Opus 5.5 15bdb03c14 feat(web): clusters, TSIG keys, zones and records (M5)
- Clusters page: DNS/DHCP clusters with members, transfer key, DNS
  options and Kea HA settings; member picking limited to free agents of
  the role, client-side checks of the membership rules.
- TSIG keys page: create, edit, rotate, delete; secrets only after an
  explicit, audited retrieval and shown once.
- Zones page with derived zones ("take over") and zone detail with
  type-specific record forms and hints for dynamic zones and AD.
- Networks, agents and generator settings show/assign clusters; files,
  diffs and pending changes are grouped by target, secret files are
  never shown.
- Pages are lazy-loaded per route (main bundle 600 KB -> 480 KB).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 14:51:26 +02:00

37 lines
1.1 KiB
TypeScript

// SPDX-License-Identifier: LicenseRef-DDI-Proprietary
import { useClusters, type AgentRole } from '../clusters';
interface Props {
id: string;
role: AgentRole;
/** Cluster ID; null for the default. */
value: string | null;
onChange: (value: string | null) => void;
/** Text of the empty option (default cluster or default group). */
emptyLabel: string;
}
/** Select of the clusters of one role with an empty option for the default. */
export function ClusterSelect({ id, role, value, onChange, emptyLabel }: Props) {
const clusters = useClusters();
const list = (clusters.data?.items ?? []).filter((c) => c.role === role);
return (
<select
id={id}
value={value ?? ''}
onChange={(e) => {
onChange(e.target.value || null);
}}
>
<option value="">{emptyLabel}</option>
{list.map((c) => (
<option key={c.id} value={c.id}>
{c.name}
</option>
))}
{/* Keep an unknown value selectable until the list has loaded. */}
{value && !list.some((c) => c.id === value) && <option value={value}>{value}</option>}
</select>
);
}