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).
61 lines
1.7 KiB
TypeScript
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>
|
|
);
|
|
}
|