mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 13:52:20 +00:00
refactor(settings): migrate the five remaining selects to the NativeSelect primitive
MB7's CF-52 sweep retired three drift-prone NATIVE_SELECT_CLASS clones behind the shared NativeSelect primitive. The AI provider section carried five more raw <select> declarations with their own copy of the border + bg + height contract — exactly the drift the primitive was introduced to cure. Swap them over so the AI provider, OpenAI model, Anthropic model, local model, and Add-provider pickers all render through the same styled wrapper as the rest of Settings.
This commit is contained in:
1 parent
374b410f46
commit
b10ec6261d
1 file changed
+24
-21
@@ -31,6 +31,7 @@ import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { NativeSelect } from "@/components/ui/native-select";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { PasswordInput } from "@/components/ui/password-input";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
@@ -341,12 +342,14 @@ function ProviderStatusBadges({
|
||||
}
|
||||
|
||||
/**
|
||||
* The single Pulldown that drives every form below it. Uses a native
|
||||
* `<select>` so the SSR-only settings test renders deterministically
|
||||
* without a portal-based Radix tree. Mobile: full-width, height matched
|
||||
* to the shared 36-px input contract used everywhere else in Settings
|
||||
* (`<Input>` is `h-9`); tap target stays comfortable thanks to the
|
||||
* full-width chevron region.
|
||||
* The single Pulldown that drives every form below it. Uses the
|
||||
* shared `<NativeSelect>` primitive so the SSR-only settings test
|
||||
* renders deterministically without a portal-based Radix tree, and so
|
||||
* the visual contract stays uniform with the other settings pickers
|
||||
* that landed behind the same primitive in MB7 / CF-52. Mobile:
|
||||
* full-width, height matched to the shared 36 px input contract used
|
||||
* everywhere else in Settings; tap target stays comfortable thanks to
|
||||
* the full-width chevron region.
|
||||
*/
|
||||
function ActiveProviderSelect({
|
||||
value,
|
||||
@@ -367,7 +370,7 @@ function ActiveProviderSelect({
|
||||
<Label htmlFor="ai-active-provider-select">
|
||||
{t("settings.ai.activeProviderLabel")}
|
||||
</Label>
|
||||
<select
|
||||
<NativeSelect
|
||||
id="ai-active-provider-select"
|
||||
data-testid="ai-active-provider-select"
|
||||
value={value}
|
||||
@@ -375,14 +378,14 @@ function ActiveProviderSelect({
|
||||
const next = e.target.value;
|
||||
if (isProviderType(next)) onChange(next);
|
||||
}}
|
||||
className="bg-background border-input mt-1 h-9 w-full rounded-md border px-3 text-sm sm:max-w-md"
|
||||
className="mt-1 sm:max-w-md"
|
||||
>
|
||||
{PROVIDER_TYPES.map((p) => (
|
||||
<option key={p} value={p}>
|
||||
{t(`settings.ai.providerSelect.${p}` as const)}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</NativeSelect>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -820,12 +823,12 @@ function OpenAIProviderForm({
|
||||
<Label htmlFor="ai-openai-model">
|
||||
{t("settings.ai.openai.modelSelect")}
|
||||
</Label>
|
||||
<select
|
||||
<NativeSelect
|
||||
id="ai-openai-model"
|
||||
data-testid="ai-openai-model"
|
||||
value={modelChoice}
|
||||
onChange={(e) => setModelChoice(e.target.value)}
|
||||
className="bg-background border-input mt-1 h-9 w-full rounded-md border px-2 text-sm"
|
||||
className="mt-1"
|
||||
>
|
||||
<option value="">{t("settings.ai.modelOptionDefault")}</option>
|
||||
{OPENAI_MODEL_PRESETS.map((m) => (
|
||||
@@ -836,7 +839,7 @@ function OpenAIProviderForm({
|
||||
<option value={CUSTOM_MODEL_SENTINEL}>
|
||||
{t("settings.ai.openai.modelOptionCustom")}
|
||||
</option>
|
||||
</select>
|
||||
</NativeSelect>
|
||||
</div>
|
||||
|
||||
{modelChoice === CUSTOM_MODEL_SENTINEL && (
|
||||
@@ -1005,11 +1008,11 @@ function AnthropicProviderForm({
|
||||
<Label htmlFor="ai-anthropic-model">
|
||||
{t("settings.ai.modelLabel")}
|
||||
</Label>
|
||||
<select
|
||||
<NativeSelect
|
||||
id="ai-anthropic-model"
|
||||
value={modelChoice}
|
||||
onChange={(e) => setModelChoice(e.target.value)}
|
||||
className="bg-background border-input mt-1 h-9 w-full rounded-md border px-2 text-sm"
|
||||
className="mt-1"
|
||||
>
|
||||
<option value="">{t("settings.ai.modelOptionDefault")}</option>
|
||||
{ANTHROPIC_MODEL_PRESETS.map((m) => (
|
||||
@@ -1020,7 +1023,7 @@ function AnthropicProviderForm({
|
||||
<option value={CUSTOM_MODEL_SENTINEL}>
|
||||
{t("settings.ai.modelOptionCustom")}
|
||||
</option>
|
||||
</select>
|
||||
</NativeSelect>
|
||||
</div>
|
||||
|
||||
{modelChoice === CUSTOM_MODEL_SENTINEL && (
|
||||
@@ -1163,11 +1166,11 @@ function LocalProviderForm({
|
||||
</div>
|
||||
<div>
|
||||
<Label htmlFor="ai-local-model">{t("settings.ai.modelLabel")}</Label>
|
||||
<select
|
||||
<NativeSelect
|
||||
id="ai-local-model"
|
||||
value={modelChoice}
|
||||
onChange={(e) => setModelChoice(e.target.value)}
|
||||
className="bg-background border-input mt-1 h-9 w-full rounded-md border px-2 text-sm"
|
||||
className="mt-1"
|
||||
>
|
||||
<option value="">{t("settings.ai.modelOptionDefault")}</option>
|
||||
{LOCAL_MODEL_PRESETS.map((m) => (
|
||||
@@ -1178,7 +1181,7 @@ function LocalProviderForm({
|
||||
<option value={CUSTOM_MODEL_SENTINEL}>
|
||||
{t("settings.ai.modelOptionCustom")}
|
||||
</option>
|
||||
</select>
|
||||
</NativeSelect>
|
||||
</div>
|
||||
{modelChoice === CUSTOM_MODEL_SENTINEL && (
|
||||
<div>
|
||||
@@ -1507,18 +1510,18 @@ function AddProviderControl({
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
<select
|
||||
<NativeSelect
|
||||
aria-label={t("settings.ai.providerChain.addProvider")}
|
||||
value={picked}
|
||||
onChange={(e) => setPicked(e.target.value)}
|
||||
className="bg-background border-input h-9 rounded-md border px-2 text-sm"
|
||||
className="w-auto"
|
||||
>
|
||||
{addable.map((p) => (
|
||||
<option key={p} value={p}>
|
||||
{t(`settings.ai.providerChain.types.${p}`)}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</NativeSelect>
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
|
||||
Reference in new issue
Block a user