Watch
0
0
Fork
You've already forked hyperhive
0
hyperhive/frontend/packages/swarm-ui/src/ui/select-field/SelectField.tsx
iris 5fdbf0b452 swarm-ui: add required hive dropdown to CreateAgentPage
Closes #3434.

Agent creation had no way to record which hive an agent runs on.
POST /api/agents now requires a hive, so the roster fetched off
GET /api/hives backs a required SelectField here rather than a
free-text field. Single-hive swarms auto-select their only hive;
multi-hive swarms show a disabled placeholder and force an explicit
choice.

Rebuilt on top of the #3448 form kit (merged after this branch was
originally opened): reuses TextField/SelectField/Button instead of
page-scoped input chrome, and SelectField gains an optional disabled
placeholder option (needed for the loading/empty/multi-hive states
here, generalizes cleanly for future callers). Form goes back to a
column layout per mara's earlier visual feedback on this same page
(two fields of different natural width no longer line up in a row).
2026-08-18 21:02:17 +02:00

61 lines
1.7 KiB
TypeScript

// <SelectField> — a labelled `<select>`, `TextField`'s sibling for the
// "pick one of these" shape (the hive-choice dropdown the create-agent
// form needs is the motivating caller). Options are plain
// value/label pairs, not `ComponentChildren` — every real caller so far
// has flat string options, and generic children would need a second
// primitive (`SelectField.Option`) for zero real benefit today.
import { FormField } from '../form-field/FormField.js';
export interface SelectOption {
value: string;
label: string;
}
export function SelectField({
id,
label,
value,
onChange,
options,
required,
disabled,
placeholder,
}: {
id: string;
label: string;
value: string;
onChange: (value: string) => void;
options: SelectOption[];
required?: boolean;
disabled?: boolean;
// Rendered as a disabled, always-first `value=""` option — for a
// required select with no default (e.g. a multi-hive roster: no
// single right answer to pre-select), so the control shows something
// other than silently landing on whatever option happens to be first.
// Omit when the field always has a real default (`value` never `''`).
placeholder?: string;
}) {
return (
<FormField label={label} htmlFor={id}>
<select
id={id}
class="ui-form-control"
value={value}
required={required}
disabled={disabled}
onChange={(e) => onChange((e.target as HTMLSelectElement).value)}
>
{placeholder !== undefined && (
<option value="" disabled>
{placeholder}
</option>
)}
{options.map((o) => (
<option key={o.value} value={o.value}>
{o.label}
</option>
))}
</select>
</FormField>
);
}