diff --git a/webui/src/components/settings/SettingsView.tsx b/webui/src/components/settings/SettingsView.tsx index b71e47542..ad1ee727e 100644 --- a/webui/src/components/settings/SettingsView.tsx +++ b/webui/src/components/settings/SettingsView.tsx @@ -3312,6 +3312,7 @@ function ModelsSettings({ const tx = (key: string, fallback: string, values?: Record) => t(key, { defaultValue: fallback, ...(values ?? {}) }); const [editorOpen, setEditorOpen] = useState(false); + const [editorRowKey, setEditorRowKey] = useState(null); const [advancedOpen, setAdvancedOpen] = useState(false); const [draggedCallOrderIndex, setDraggedCallOrderIndex] = useState(null); const [dragOverCallOrderIndex, setDragOverCallOrderIndex] = useState(null); @@ -3338,6 +3339,10 @@ function ModelsSettings({ })), ]; const selectedPreset = namedPresetsByName.get(form.modelPreset) ?? null; + const activeEditorRowKey = + editorRowKey ?? + presetRows.find((row) => row.name === selectedPreset?.name)?.key ?? + null; useEffect(() => { setAdvancedOpen(false); }, [editorOpen, selectedPreset?.name]); @@ -3374,8 +3379,12 @@ function ModelsSettings({ selectedPreset && callOrder.includes(selectedPreset.name), ); const callOrderBusy = orderSaving || saving; - const selectPreset = (preset: SettingsPayload["model_presets"][number]) => { - const toggleCurrentPreset = !creating && selectedPreset?.name === preset.name; + const selectPreset = ( + preset: SettingsPayload["model_presets"][number], + rowKey: string, + ) => { + const toggleCurrentPreset = + !creating && selectedPreset?.name === preset.name && activeEditorRowKey === rowKey; onSelectConfiguration(); if (toggleCurrentPreset) { setEditorOpen((open) => !open); @@ -3392,6 +3401,7 @@ function ModelsSettings({ temperature: preset.temperature, reasoningEffort: preset.reasoning_effort ?? "", })); + setEditorRowKey(rowKey); setEditorOpen(true); }; @@ -3432,9 +3442,8 @@ function ModelsSettings({ onChangeCallOrder(next); }; - const renderPresetEditor = (key: string) => ( + const renderPresetEditor = () => (
preset && selectPreset(preset)} + onClick={() => preset && selectPreset(preset, key)} className="flex min-w-0 flex-1 items-center gap-3 rounded-[12px] text-left outline-none focus-visible:ring-2 focus-visible:ring-ring" > {ordered ? ( @@ -3846,9 +3856,14 @@ function ModelsSettings({ aria-hidden /> -
, - isSelected ? renderPresetEditor(`editor:${key}`) : null, - ]; + + ); + return ( +
+ {presetRow} + {isSelected ? renderPresetEditor() : null} +
+ ); })}
@@ -3859,6 +3874,7 @@ function ModelsSettings({ className="rounded-full" disabled={callOrderBusy} onClick={() => { + setEditorRowKey(null); setEditorOpen(true); onBeginCreate(); }} @@ -3878,7 +3894,7 @@ function ModelsSettings({ ) : null}
- {creating && editorOpen ? renderPresetEditor("editor:new") : null} + {creating && editorOpen ? renderPresetEditor() : null} )} diff --git a/webui/src/tests/settings-view.test.tsx b/webui/src/tests/settings-view.test.tsx index e0e509a3f..96e7fdbe8 100644 --- a/webui/src/tests/settings-view.test.tsx +++ b/webui/src/tests/settings-view.test.tsx @@ -2166,6 +2166,8 @@ describe("SettingsView Apps catalog", () => { expect(trigger).toHaveAttribute("aria-pressed", "true"); expect(trigger).toHaveAttribute("aria-expanded", "true"); expect(trigger).toHaveAttribute("aria-controls", "model-preset-editor"); + expect(row.parentElement).toHaveAttribute("role", "listitem"); + expect(row.parentElement?.parentElement).toHaveAttribute("role", "list"); expect(row.nextElementSibling).toBe(editor); expect(editor).toHaveClass( "slide-in-from-top-1", @@ -2317,7 +2319,17 @@ describe("SettingsView Apps catalog", () => { renderSettingsView({ initialSection: "models", initialSettings: initialPayload }); const primaryRow = screen.getByTestId("model-call-order-row-primary"); - const firstBackupRow = screen.getAllByTestId("model-call-order-row-backup")[0]; + const backupRows = screen.getAllByTestId("model-call-order-row-backup"); + const firstBackupRow = backupRows[0]; + const secondBackupRow = backupRows[1]; + const secondBackupTrigger = within(secondBackupRow).getAllByRole("button")[0]; + fireEvent.click(secondBackupTrigger); + expect(screen.getAllByTestId("model-preset-editor")).toHaveLength(1); + expect(secondBackupRow.nextElementSibling).toBe( + screen.getByTestId("model-preset-editor"), + ); + fireEvent.click(secondBackupTrigger); + const dataTransfer = { dropEffect: "move", effectAllowed: "move",