Skip to content

Commit 01b6565

Browse files
committed
feat(profile-selector): persist order settings
1 parent 5ce0f51 commit 01b6565

File tree

6 files changed

+29
-14
lines changed

6 files changed

+29
-14
lines changed

packages/types/src/global-settings.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export const globalSettingsSchema = z.object({
3737
currentApiConfigName: z.string().optional(),
3838
listApiConfigMeta: z.array(providerSettingsEntrySchema).optional(),
3939
pinnedApiConfigs: z.record(z.string(), z.boolean()).optional(),
40+
apiConfigCustomOrder: z.array(z.string()).optional(),
4041

4142
lastShownAnnouncementId: z.string().optional(),
4243
customInstructions: z.string().optional(),
@@ -249,6 +250,7 @@ export const EVALS_SETTINGS: RooCodeSettings = {
249250
lastShownAnnouncementId: "jul-09-2025-3-23-0",
250251

251252
pinnedApiConfigs: {},
253+
apiConfigCustomOrder: [],
252254

253255
autoApprovalEnabled: true,
254256
alwaysAllowReadOnly: true,

src/core/webview/ClineProvider.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1645,6 +1645,7 @@ export class ClineProvider
16451645
openRouterImageApiKey,
16461646
openRouterImageGenerationSelectedModel,
16471647
openRouterUseMiddleOutTransform,
1648+
apiConfigCustomOrder,
16481649
} = await this.getState()
16491650

16501651
const telemetryKey = process.env.POSTHOG_API_KEY
@@ -1720,6 +1721,7 @@ export class ClineProvider
17201721
currentApiConfigName: currentApiConfigName ?? "default",
17211722
listApiConfigMeta: listApiConfigMeta ?? [],
17221723
pinnedApiConfigs: pinnedApiConfigs ?? {},
1724+
apiConfigCustomOrder: apiConfigCustomOrder ?? [],
17231725
mode: mode ?? defaultModeSlug,
17241726
customModePrompts: customModePrompts ?? {},
17251727
customSupportPrompts: customSupportPrompts ?? {},
@@ -1929,6 +1931,7 @@ export class ClineProvider
19291931
currentApiConfigName: stateValues.currentApiConfigName ?? "default",
19301932
listApiConfigMeta: stateValues.listApiConfigMeta ?? [],
19311933
pinnedApiConfigs: stateValues.pinnedApiConfigs ?? {},
1934+
apiConfigCustomOrder: stateValues.apiConfigCustomOrder ?? [],
19321935
modeApiConfigs: stateValues.modeApiConfigs ?? ({} as Record<Mode, string>),
19331936
customModePrompts: stateValues.customModePrompts ?? {},
19341937
customSupportPrompts: stateValues.customSupportPrompts ?? {},

src/core/webview/webviewMessageHandler.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1388,6 +1388,12 @@ export const webviewMessageHandler = async (
13881388
await provider.postStateToWebview()
13891389
}
13901390
break
1391+
case "setApiConfigCustomOrder":
1392+
if (message.values && Array.isArray(message.values.customOrder)) {
1393+
await updateGlobalState("apiConfigCustomOrder", message.values.customOrder)
1394+
// No need to call postStateToWebview here as the UI already updated optimistically
1395+
}
1396+
break
13911397
case "enhancementApiConfigId":
13921398
await updateGlobalState("enhancementApiConfigId", message.text)
13931399
await provider.postStateToWebview()

src/shared/ExtensionMessage.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ export type ExtensionState = Pick<
205205
| "currentApiConfigName"
206206
| "listApiConfigMeta"
207207
| "pinnedApiConfigs"
208+
| "apiConfigCustomOrder"
208209
// | "lastShownAnnouncementId"
209210
| "customInstructions"
210211
// | "taskHistory" // Optional in GlobalSettings, required here.

src/shared/WebviewMessage.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ export interface WebviewMessage {
175175
| "maxDiagnosticMessages"
176176
| "searchFiles"
177177
| "toggleApiConfigPin"
178+
| "setApiConfigCustomOrder"
178179
| "setHistoryPreviewCollapsed"
179180
| "hasOpenedModeSelector"
180181
| "cloudButtonClicked"

webview-ui/src/components/chat/ApiConfigSelector.tsx

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { useRooPortal } from "@/components/ui/hooks/useRooPortal"
88
import { Popover, PopoverContent, PopoverTrigger, StandardTooltip } from "@/components/ui"
99
import { vscode } from "@/utils/vscode"
1010
import { Button } from "@/components/ui"
11+
import { useExtensionState } from "@/context/ExtensionStateContext"
1112

1213
import { IconButton } from "./IconButton"
1314

@@ -29,10 +30,6 @@ interface ApiConfigSelectorProps {
2930
listApiConfigMeta: Array<{ id: string; name: string; modelId?: string }>
3031
pinnedApiConfigs?: Record<string, boolean>
3132
togglePinnedApiConfig: (id: string) => void
32-
sortMode?: SortMode
33-
customOrder?: string[]
34-
onSortModeChange?: (mode: SortMode) => void
35-
onCustomOrderChange?: (order: string[]) => void
3633
}
3734

3835
export const ApiConfigSelector = ({
@@ -45,10 +42,9 @@ export const ApiConfigSelector = ({
4542
listApiConfigMeta,
4643
pinnedApiConfigs,
4744
togglePinnedApiConfig,
48-
sortMode: externalSortMode,
49-
customOrder: externalCustomOrder = [],
5045
}: ApiConfigSelectorProps) => {
5146
const { t } = useTranslation()
47+
const { apiConfigCustomOrder: persistedCustomOrder } = useExtensionState()
5248
const [open, setOpen] = useState(false)
5349
const [searchValue, setSearchValue] = useState("")
5450
const [isReorderMode, setIsReorderMode] = useState(false)
@@ -59,12 +55,12 @@ export const ApiConfigSelector = ({
5955
})
6056

6157
// Internal state for sort mode and custom order when parent doesn't provide them
62-
const [internalSortMode, setInternalSortMode] = useState<SortMode>("alphabetical")
58+
const [sortMode, setSortMode] = useState<SortMode>("alphabetical")
6359
const [internalCustomOrder, setInternalCustomOrder] = useState<string[]>([])
6460

65-
// Use external props if provided, otherwise use internal state
66-
const sortMode = externalSortMode ?? internalSortMode
67-
const customOrder = externalCustomOrder.length > 0 ? externalCustomOrder : internalCustomOrder
61+
// Use persisted state then internal state as fallback
62+
const customOrder =
63+
persistedCustomOrder && persistedCustomOrder.length > 0 ? persistedCustomOrder : internalCustomOrder
6864

6965
const portalContainer = useRooPortal("roo-portal")
7066
const scrollContainerRef = useRef<HTMLDivElement | null>(null)
@@ -78,13 +74,13 @@ export const ApiConfigSelector = ({
7874
sorted.sort((a, b) => a.name.localeCompare(b.name))
7975
break
8076
case "custom":
81-
if (customOrder.length > 0) {
77+
if (customOrder && customOrder.length > 0) {
8278
// Sort by custom order, with unordered items at the end
83-
const orderMap = new Map(customOrder.map((id, index) => [id, index]))
79+
const orderMap = new Map(customOrder.map((id: string, index: number) => [id, index]))
8480
sorted.sort((a, b) => {
8581
const aIndex = orderMap.get(a.id) ?? Number.MAX_SAFE_INTEGER
8682
const bIndex = orderMap.get(b.id) ?? Number.MAX_SAFE_INTEGER
87-
return aIndex - bIndex
83+
return (aIndex as number) - (bIndex as number)
8884
})
8985
}
9086
break
@@ -132,7 +128,7 @@ export const ApiConfigSelector = ({
132128

133129
const handleSortModeChange = useCallback((mode: SortMode) => {
134130
// Always update internal state as fallback
135-
setInternalSortMode(mode)
131+
setSortMode(mode)
136132

137133
if (mode !== "custom") {
138134
setIsReorderMode(false)
@@ -176,6 +172,12 @@ export const ApiConfigSelector = ({
176172
const newCustomOrder = newOrder.map((config) => config.id)
177173
// Always update internal state as fallback
178174
setInternalCustomOrder(newCustomOrder)
175+
176+
// Persist the custom order to storage
177+
vscode.postMessage({
178+
type: "setApiConfigCustomOrder",
179+
values: { customOrder: newCustomOrder },
180+
})
179181
},
180182
[filteredConfigs],
181183
)

0 commit comments

Comments
 (0)