mirror of
https://github.com/0xWheatyz/handler.git
synced 2026-08-30 22:16:25 +00:00
feat(app): model backend picker on the spawn screen
Fetch the registered model backends (/claude/models) alongside the fleet poll and offer the enabled ones in a Model select on the spawn form, defaulting to the Claude subscription — the mobile counterpart of the web dashboard's per-spawn dropdown. The select is hidden when no backends are registered, and Select itself now takes value/label pairs as well as bare strings. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01731mKtVzsfeT4Vi3TvkR48
This commit is contained in:
@@ -14,7 +14,11 @@ import { Icon } from "./Icon";
|
||||
* Leeworks Select, ported from components/forms/Select.jsx. Native <select>
|
||||
* has no cross-platform styling in RN, so the field opens a bottom sheet of
|
||||
* options — same visual field (value + chevron), real picking behavior.
|
||||
* Options are either bare strings (value doubles as the label) or
|
||||
* value/label pairs, matching the web dashboard's Select.
|
||||
*/
|
||||
export type SelectOption = string | { value: string; label: string };
|
||||
|
||||
export function Select({
|
||||
label,
|
||||
options,
|
||||
@@ -22,13 +26,18 @@ export function Select({
|
||||
onChange,
|
||||
}: {
|
||||
label: string;
|
||||
options: string[];
|
||||
options: SelectOption[];
|
||||
value: string;
|
||||
onChange: (v: string) => void;
|
||||
}) {
|
||||
const { colors } = useTheme();
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const opts = options.map((o) =>
|
||||
typeof o === "string" ? { value: o, label: o } : o,
|
||||
);
|
||||
const current = opts.find((o) => o.value === value);
|
||||
|
||||
return (
|
||||
<View style={{ gap: 6 }}>
|
||||
<Text style={[styles.label, { color: colors.textHeading }]}>{label}</Text>
|
||||
@@ -40,7 +49,7 @@ export function Select({
|
||||
]}
|
||||
>
|
||||
<Text style={[text.body, { color: colors.textHeading, flex: 1 }]}>
|
||||
{value}
|
||||
{current?.label ?? value}
|
||||
</Text>
|
||||
<Icon name="chevronDown" size={16} color={colors.textMuted} />
|
||||
</Pressable>
|
||||
@@ -54,13 +63,13 @@ export function Select({
|
||||
shadows.raised,
|
||||
]}
|
||||
>
|
||||
{options.map((opt) => {
|
||||
const on = opt === value;
|
||||
{opts.map((opt) => {
|
||||
const on = opt.value === value;
|
||||
return (
|
||||
<Pressable
|
||||
key={opt}
|
||||
key={opt.value}
|
||||
onPress={() => {
|
||||
onChange(opt);
|
||||
onChange(opt.value);
|
||||
setOpen(false);
|
||||
}}
|
||||
style={({ pressed }) => [
|
||||
@@ -78,7 +87,7 @@ export function Select({
|
||||
},
|
||||
]}
|
||||
>
|
||||
{opt}
|
||||
{opt.label}
|
||||
</Text>
|
||||
{on && <Icon name="chevronRight" size={16} color={colors.textMuted} />}
|
||||
</Pressable>
|
||||
|
||||
Reference in New Issue
Block a user