mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
feat: add sorting and pinning for modes and API profiles
- Add global state fields for sorting preferences (modeSortingMode, pinnedModes, customModeOrder, apiProfileSortingMode, customApiProfileOrder) - Implement pinning functionality for modes similar to existing API profile pinning - Update ModeSelector component to support pinning and respect sorting preferences - Update ApiConfigSelector to respect manual sorting when enabled - Add message handlers for new sorting operations - Update ExtensionStateContext to include sorting settings and setters - Modify ClineProvider to pass sorting settings to webview - Add TypeScript type definitions for all new sorting operations Implements #7496
This commit is contained in:
parent
6ef9dbd873
commit
e4b5d3cb36
8 changed files with 293 additions and 31 deletions
|
|
@ -38,6 +38,13 @@ export const globalSettingsSchema = z.object({
|
|||
listApiConfigMeta: z.array(providerSettingsEntrySchema).optional(),
|
||||
pinnedApiConfigs: z.record(z.string(), z.boolean()).optional(),
|
||||
|
||||
// Mode and API profile sorting preferences
|
||||
modeSortingMode: z.enum(["alphabetical", "manual"]).optional(),
|
||||
pinnedModes: z.record(z.string(), z.boolean()).optional(),
|
||||
customModeOrder: z.array(z.string()).optional(),
|
||||
apiProfileSortingMode: z.enum(["alphabetical", "manual"]).optional(),
|
||||
customApiProfileOrder: z.array(z.string()).optional(),
|
||||
|
||||
lastShownAnnouncementId: z.string().optional(),
|
||||
customInstructions: z.string().optional(),
|
||||
taskHistory: z.array(historyItemSchema).optional(),
|
||||
|
|
@ -232,6 +239,13 @@ export const EVALS_SETTINGS: RooCodeSettings = {
|
|||
|
||||
pinnedApiConfigs: {},
|
||||
|
||||
// Default sorting settings
|
||||
modeSortingMode: "alphabetical",
|
||||
pinnedModes: {},
|
||||
customModeOrder: [],
|
||||
apiProfileSortingMode: "alphabetical",
|
||||
customApiProfileOrder: [],
|
||||
|
||||
autoApprovalEnabled: true,
|
||||
alwaysAllowReadOnly: true,
|
||||
alwaysAllowReadOnlyOutsideWorkspace: false,
|
||||
|
|
|
|||
|
|
@ -1726,6 +1726,11 @@ export class ClineProvider
|
|||
currentApiConfigName,
|
||||
listApiConfigMeta,
|
||||
pinnedApiConfigs,
|
||||
modeSortingMode,
|
||||
pinnedModes,
|
||||
customModeOrder,
|
||||
apiProfileSortingMode,
|
||||
customApiProfileOrder,
|
||||
mode,
|
||||
customModePrompts,
|
||||
customSupportPrompts,
|
||||
|
|
@ -1835,6 +1840,11 @@ export class ClineProvider
|
|||
currentApiConfigName: currentApiConfigName ?? "default",
|
||||
listApiConfigMeta: listApiConfigMeta ?? [],
|
||||
pinnedApiConfigs: pinnedApiConfigs ?? {},
|
||||
modeSortingMode: modeSortingMode ?? "alphabetical",
|
||||
pinnedModes: pinnedModes ?? {},
|
||||
customModeOrder: customModeOrder ?? [],
|
||||
apiProfileSortingMode: apiProfileSortingMode ?? "alphabetical",
|
||||
customApiProfileOrder: customApiProfileOrder ?? [],
|
||||
mode: mode ?? defaultModeSlug,
|
||||
customModePrompts: customModePrompts ?? {},
|
||||
customSupportPrompts: customSupportPrompts ?? {},
|
||||
|
|
@ -2031,6 +2041,11 @@ export class ClineProvider
|
|||
currentApiConfigName: stateValues.currentApiConfigName ?? "default",
|
||||
listApiConfigMeta: stateValues.listApiConfigMeta ?? [],
|
||||
pinnedApiConfigs: stateValues.pinnedApiConfigs ?? {},
|
||||
modeSortingMode: stateValues.modeSortingMode ?? "alphabetical",
|
||||
pinnedModes: stateValues.pinnedModes ?? {},
|
||||
customModeOrder: stateValues.customModeOrder ?? [],
|
||||
apiProfileSortingMode: stateValues.apiProfileSortingMode ?? "alphabetical",
|
||||
customApiProfileOrder: stateValues.customApiProfileOrder ?? [],
|
||||
modeApiConfigs: stateValues.modeApiConfigs ?? ({} as Record<Mode, string>),
|
||||
customModePrompts: stateValues.customModePrompts ?? {},
|
||||
customSupportPrompts: stateValues.customSupportPrompts ?? {},
|
||||
|
|
|
|||
|
|
@ -1358,6 +1358,45 @@ export const webviewMessageHandler = async (
|
|||
await provider.postStateToWebview()
|
||||
}
|
||||
break
|
||||
case "toggleModePin":
|
||||
if (message.text) {
|
||||
const currentPinned = getGlobalState("pinnedModes") ?? {}
|
||||
const updatedPinned: Record<string, boolean> = { ...currentPinned }
|
||||
|
||||
if (currentPinned[message.text]) {
|
||||
delete updatedPinned[message.text]
|
||||
} else {
|
||||
updatedPinned[message.text] = true
|
||||
}
|
||||
|
||||
await updateGlobalState("pinnedModes", updatedPinned)
|
||||
await provider.postStateToWebview()
|
||||
}
|
||||
break
|
||||
case "modeSortingMode":
|
||||
if (message.text === "alphabetical" || message.text === "manual") {
|
||||
await updateGlobalState("modeSortingMode", message.text)
|
||||
await provider.postStateToWebview()
|
||||
}
|
||||
break
|
||||
case "apiProfileSortingMode":
|
||||
if (message.text === "alphabetical" || message.text === "manual") {
|
||||
await updateGlobalState("apiProfileSortingMode", message.text)
|
||||
await provider.postStateToWebview()
|
||||
}
|
||||
break
|
||||
case "customModeOrder":
|
||||
if (message.values && Array.isArray(message.values)) {
|
||||
await updateGlobalState("customModeOrder", message.values)
|
||||
await provider.postStateToWebview()
|
||||
}
|
||||
break
|
||||
case "customApiProfileOrder":
|
||||
if (message.values && Array.isArray(message.values)) {
|
||||
await updateGlobalState("customApiProfileOrder", message.values)
|
||||
await provider.postStateToWebview()
|
||||
}
|
||||
break
|
||||
case "enhancementApiConfigId":
|
||||
await updateGlobalState("enhancementApiConfigId", message.text)
|
||||
await provider.postStateToWebview()
|
||||
|
|
|
|||
|
|
@ -201,6 +201,11 @@ export type ExtensionState = Pick<
|
|||
| "currentApiConfigName"
|
||||
| "listApiConfigMeta"
|
||||
| "pinnedApiConfigs"
|
||||
| "modeSortingMode"
|
||||
| "pinnedModes"
|
||||
| "customModeOrder"
|
||||
| "apiProfileSortingMode"
|
||||
| "customApiProfileOrder"
|
||||
// | "lastShownAnnouncementId"
|
||||
| "customInstructions"
|
||||
// | "taskHistory" // Optional in GlobalSettings, required here.
|
||||
|
|
|
|||
|
|
@ -172,8 +172,13 @@ export interface WebviewMessage {
|
|||
| "maxDiagnosticMessages"
|
||||
| "searchFiles"
|
||||
| "toggleApiConfigPin"
|
||||
| "toggleModePin"
|
||||
| "setHistoryPreviewCollapsed"
|
||||
| "hasOpenedModeSelector"
|
||||
| "modeSortingMode"
|
||||
| "apiProfileSortingMode"
|
||||
| "customModeOrder"
|
||||
| "customApiProfileOrder"
|
||||
| "accountButtonClicked"
|
||||
| "rooCloudSignIn"
|
||||
| "rooCloudSignOut"
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { cn } from "@/lib/utils"
|
|||
import { useRooPortal } from "@/components/ui/hooks/useRooPortal"
|
||||
import { Popover, PopoverContent, PopoverTrigger, StandardTooltip } from "@/components/ui"
|
||||
import { useAppTranslation } from "@/i18n/TranslationContext"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { vscode } from "@/utils/vscode"
|
||||
import { Button } from "@/components/ui"
|
||||
|
||||
|
|
@ -39,6 +40,9 @@ export const ApiConfigSelector = ({
|
|||
const [searchValue, setSearchValue] = useState("")
|
||||
const portalContainer = useRooPortal("roo-portal")
|
||||
|
||||
// Get sorting preferences from extension state
|
||||
const { apiProfileSortingMode, customApiProfileOrder } = useExtensionState()
|
||||
|
||||
// Create searchable items for fuzzy search.
|
||||
const searchableItems = useMemo(
|
||||
() =>
|
||||
|
|
@ -65,12 +69,40 @@ export const ApiConfigSelector = ({
|
|||
return matchingItems
|
||||
}, [listApiConfigMeta, searchValue, fzfInstance])
|
||||
|
||||
// Sort configs based on sorting preferences
|
||||
const sortedConfigs = useMemo(() => {
|
||||
const sorted = [...filteredConfigs]
|
||||
|
||||
if (apiProfileSortingMode === "manual" && customApiProfileOrder && customApiProfileOrder.length > 0) {
|
||||
// Sort based on custom order
|
||||
sorted.sort((a, b) => {
|
||||
const aIndex = customApiProfileOrder.indexOf(a.id)
|
||||
const bIndex = customApiProfileOrder.indexOf(b.id)
|
||||
|
||||
// If both are in custom order, sort by their position
|
||||
if (aIndex !== -1 && bIndex !== -1) {
|
||||
return aIndex - bIndex
|
||||
}
|
||||
// If only one is in custom order, it comes first
|
||||
if (aIndex !== -1) return -1
|
||||
if (bIndex !== -1) return 1
|
||||
// Otherwise maintain original order
|
||||
return 0
|
||||
})
|
||||
} else {
|
||||
// Alphabetical sorting (default)
|
||||
sorted.sort((a, b) => a.name.localeCompare(b.name))
|
||||
}
|
||||
|
||||
return sorted
|
||||
}, [filteredConfigs, apiProfileSortingMode, customApiProfileOrder])
|
||||
|
||||
// Separate pinned and unpinned configs.
|
||||
const { pinnedConfigs, unpinnedConfigs } = useMemo(() => {
|
||||
const pinned = filteredConfigs.filter((config) => pinnedApiConfigs?.[config.id])
|
||||
const unpinned = filteredConfigs.filter((config) => !pinnedApiConfigs?.[config.id])
|
||||
const pinned = sortedConfigs.filter((config) => pinnedApiConfigs?.[config.id])
|
||||
const unpinned = sortedConfigs.filter((config) => !pinnedApiConfigs?.[config.id])
|
||||
return { pinnedConfigs: pinned, unpinnedConfigs: unpinned }
|
||||
}, [filteredConfigs, pinnedApiConfigs])
|
||||
}, [sortedConfigs, pinnedApiConfigs])
|
||||
|
||||
const handleSelect = useCallback(
|
||||
(configId: string) => {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import { cn } from "@/lib/utils"
|
|||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { useAppTranslation } from "@/i18n/TranslationContext"
|
||||
import { useRooPortal } from "@/components/ui/hooks/useRooPortal"
|
||||
import { Popover, PopoverContent, PopoverTrigger, StandardTooltip } from "@/components/ui"
|
||||
import { Popover, PopoverContent, PopoverTrigger, StandardTooltip, Button } from "@/components/ui"
|
||||
|
||||
import { IconButton } from "./IconButton"
|
||||
|
||||
|
|
@ -45,7 +45,14 @@ export const ModeSelector = ({
|
|||
const [searchValue, setSearchValue] = React.useState("")
|
||||
const searchInputRef = React.useRef<HTMLInputElement>(null)
|
||||
const portalContainer = useRooPortal("roo-portal")
|
||||
const { hasOpenedModeSelector, setHasOpenedModeSelector } = useExtensionState()
|
||||
const {
|
||||
hasOpenedModeSelector,
|
||||
setHasOpenedModeSelector,
|
||||
modeSortingMode,
|
||||
pinnedModes,
|
||||
togglePinnedMode,
|
||||
customModeOrder,
|
||||
} = useExtensionState()
|
||||
const { t } = useAppTranslation()
|
||||
|
||||
const trackModeSelectorOpened = React.useCallback(() => {
|
||||
|
|
@ -99,9 +106,44 @@ export const ModeSelector = ({
|
|||
[descriptionSearchItems],
|
||||
)
|
||||
|
||||
// Sort modes based on sorting preferences
|
||||
const sortedModes = React.useMemo(() => {
|
||||
let sorted = [...modes]
|
||||
|
||||
if (modeSortingMode === "manual" && customModeOrder && customModeOrder.length > 0) {
|
||||
// Sort based on custom order
|
||||
sorted.sort((a, b) => {
|
||||
const aIndex = customModeOrder.indexOf(a.slug)
|
||||
const bIndex = customModeOrder.indexOf(b.slug)
|
||||
|
||||
// If both are in custom order, sort by their position
|
||||
if (aIndex !== -1 && bIndex !== -1) {
|
||||
return aIndex - bIndex
|
||||
}
|
||||
// If only one is in custom order, it comes first
|
||||
if (aIndex !== -1) return -1
|
||||
if (bIndex !== -1) return 1
|
||||
// Otherwise maintain original order
|
||||
return 0
|
||||
})
|
||||
} else {
|
||||
// Alphabetical sorting (default)
|
||||
sorted.sort((a, b) => a.name.localeCompare(b.name))
|
||||
}
|
||||
|
||||
// Apply pinning - pinned modes come first
|
||||
if (pinnedModes) {
|
||||
const pinned = sorted.filter((mode) => pinnedModes[mode.slug])
|
||||
const unpinned = sorted.filter((mode) => !pinnedModes[mode.slug])
|
||||
sorted = [...pinned, ...unpinned]
|
||||
}
|
||||
|
||||
return sorted
|
||||
}, [modes, modeSortingMode, pinnedModes, customModeOrder])
|
||||
|
||||
// Filter modes based on search value using fuzzy search with priority.
|
||||
const filteredModes = React.useMemo(() => {
|
||||
if (!searchValue) return modes
|
||||
if (!searchValue) return sortedModes
|
||||
|
||||
// First search in names/slugs.
|
||||
const nameMatches = nameFzfInstance.find(searchValue)
|
||||
|
|
@ -118,8 +160,13 @@ export const ModeSelector = ({
|
|||
.map((result) => result.item.original),
|
||||
]
|
||||
|
||||
return combinedResults
|
||||
}, [modes, searchValue, nameFzfInstance, descriptionFzfInstance])
|
||||
// Preserve the sorting order after filtering
|
||||
const sortedFilteredResults = sortedModes.filter((mode) =>
|
||||
combinedResults.some((result) => result.slug === mode.slug),
|
||||
)
|
||||
|
||||
return sortedFilteredResults
|
||||
}, [sortedModes, searchValue, nameFzfInstance, descriptionFzfInstance])
|
||||
|
||||
const onClearSearch = React.useCallback(() => {
|
||||
setSearchValue("")
|
||||
|
|
@ -230,29 +277,24 @@ export const ModeSelector = ({
|
|||
</div>
|
||||
) : (
|
||||
<div className="py-1">
|
||||
{filteredModes.map((mode) => (
|
||||
<div
|
||||
key={mode.slug}
|
||||
onClick={() => handleSelect(mode.slug)}
|
||||
className={cn(
|
||||
"px-3 py-1.5 text-sm cursor-pointer flex items-center",
|
||||
"hover:bg-vscode-list-hoverBackground",
|
||||
mode.slug === value
|
||||
? "bg-vscode-list-activeSelectionBackground text-vscode-list-activeSelectionForeground"
|
||||
: "",
|
||||
)}
|
||||
data-testid="mode-selector-item">
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="font-bold truncate">{mode.name}</div>
|
||||
{mode.description && (
|
||||
<div className="text-xs text-vscode-descriptionForeground truncate">
|
||||
{mode.description}
|
||||
</div>
|
||||
{/* Show pinned modes first if any */}
|
||||
{pinnedModes &&
|
||||
Object.keys(pinnedModes).length > 0 &&
|
||||
filteredModes.filter((mode) => pinnedModes[mode.slug]).length > 0 && (
|
||||
<>
|
||||
{filteredModes
|
||||
.filter((mode) => pinnedModes[mode.slug])
|
||||
.map((mode) => renderModeItem(mode, true))}
|
||||
{/* Separator between pinned and unpinned */}
|
||||
{filteredModes.filter((mode) => !pinnedModes[mode.slug]).length > 0 && (
|
||||
<div className="mx-1 my-1 h-px bg-vscode-dropdown-foreground/10" />
|
||||
)}
|
||||
</div>
|
||||
{mode.slug === value && <Check className="ml-auto size-4 p-0.5" />}
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
{/* Show unpinned modes */}
|
||||
{filteredModes
|
||||
.filter((mode) => !pinnedModes || !pinnedModes[mode.slug])
|
||||
.map((mode) => renderModeItem(mode, false))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -301,4 +343,53 @@ export const ModeSelector = ({
|
|||
</PopoverContent>
|
||||
</Popover>
|
||||
)
|
||||
|
||||
function renderModeItem(mode: (typeof modes)[0], isPinned: boolean) {
|
||||
const isSelected = mode.slug === value
|
||||
|
||||
return (
|
||||
<div
|
||||
key={mode.slug}
|
||||
onClick={() => handleSelect(mode.slug)}
|
||||
className={cn(
|
||||
"px-3 py-1.5 text-sm cursor-pointer flex items-center group",
|
||||
"hover:bg-vscode-list-hoverBackground",
|
||||
isSelected
|
||||
? "bg-vscode-list-activeSelectionBackground text-vscode-list-activeSelectionForeground"
|
||||
: "",
|
||||
)}
|
||||
data-testid="mode-selector-item">
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="font-bold truncate">{mode.name}</div>
|
||||
{mode.description && (
|
||||
<div className="text-xs text-vscode-descriptionForeground truncate">{mode.description}</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
{isSelected && (
|
||||
<div className="size-5 p-1 flex items-center justify-center">
|
||||
<Check className="size-3" />
|
||||
</div>
|
||||
)}
|
||||
<StandardTooltip content={isPinned ? t("chat:unpin") : t("chat:pin")}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
tabIndex={-1}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
togglePinnedMode?.(mode.slug)
|
||||
vscode.postMessage({ type: "toggleModePin", text: mode.slug })
|
||||
}}
|
||||
className={cn("size-5 flex items-center justify-center", {
|
||||
"opacity-0 group-hover:opacity-100": !isPinned && !isSelected,
|
||||
"bg-accent opacity-100": isPinned,
|
||||
})}>
|
||||
<span className="codicon codicon-pin text-xs opacity-50" />
|
||||
</Button>
|
||||
</StandardTooltip>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,18 @@ export interface ExtensionStateContextType extends ExtensionState {
|
|||
mdmCompliant?: boolean
|
||||
hasOpenedModeSelector: boolean // New property to track if user has opened mode selector
|
||||
setHasOpenedModeSelector: (value: boolean) => void // Setter for the new property
|
||||
// Mode and API profile sorting settings
|
||||
modeSortingMode?: "alphabetical" | "manual"
|
||||
setModeSortingMode: (value: "alphabetical" | "manual") => void
|
||||
pinnedModes?: Record<string, boolean>
|
||||
setPinnedModes: (value: Record<string, boolean>) => void
|
||||
togglePinnedMode: (modeSlug: string) => void
|
||||
customModeOrder?: string[]
|
||||
setCustomModeOrder: (value: string[]) => void
|
||||
apiProfileSortingMode?: "alphabetical" | "manual"
|
||||
setApiProfileSortingMode: (value: "alphabetical" | "manual") => void
|
||||
customApiProfileOrder?: string[]
|
||||
setCustomApiProfileOrder: (value: string[]) => void
|
||||
alwaysAllowFollowupQuestions: boolean // New property for follow-up questions auto-approve
|
||||
setAlwaysAllowFollowupQuestions: (value: boolean) => void // Setter for the new property
|
||||
followupAutoApproveTimeoutMs: number | undefined // Timeout in ms for auto-approving follow-up questions
|
||||
|
|
@ -224,6 +236,11 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
|
|||
maxImageFileSize: 5, // Default max image file size in MB
|
||||
maxTotalImageSize: 20, // Default max total image size in MB
|
||||
pinnedApiConfigs: {}, // Empty object for pinned API configs
|
||||
modeSortingMode: "alphabetical" as const, // Default mode sorting
|
||||
pinnedModes: {}, // Empty object for pinned modes
|
||||
customModeOrder: [], // Empty array for custom mode order
|
||||
apiProfileSortingMode: "alphabetical" as const, // Default API profile sorting
|
||||
customApiProfileOrder: [], // Empty array for custom API profile order
|
||||
terminalZshOhMy: false, // Default Oh My Zsh integration setting
|
||||
maxConcurrentFileReads: 5, // Default concurrent file reads
|
||||
terminalZshP10k: false, // Default Powerlevel10k integration setting
|
||||
|
|
@ -292,7 +309,26 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
|
|||
switch (message.type) {
|
||||
case "state": {
|
||||
const newState = message.state!
|
||||
setState((prevState) => mergeExtensionState(prevState, newState))
|
||||
setState((prevState) => {
|
||||
const merged = mergeExtensionState(prevState, newState)
|
||||
// Handle new sorting settings if present
|
||||
if ((newState as any).modeSortingMode !== undefined) {
|
||||
;(merged as any).modeSortingMode = (newState as any).modeSortingMode
|
||||
}
|
||||
if ((newState as any).pinnedModes !== undefined) {
|
||||
;(merged as any).pinnedModes = (newState as any).pinnedModes
|
||||
}
|
||||
if ((newState as any).customModeOrder !== undefined) {
|
||||
;(merged as any).customModeOrder = (newState as any).customModeOrder
|
||||
}
|
||||
if ((newState as any).apiProfileSortingMode !== undefined) {
|
||||
;(merged as any).apiProfileSortingMode = (newState as any).apiProfileSortingMode
|
||||
}
|
||||
if ((newState as any).customApiProfileOrder !== undefined) {
|
||||
;(merged as any).customApiProfileOrder = (newState as any).customApiProfileOrder
|
||||
}
|
||||
return merged
|
||||
})
|
||||
setShowWelcome(!checkExistKey(newState.apiConfiguration))
|
||||
setDidHydrateState(true)
|
||||
// Update alwaysAllowFollowupQuestions if present in state message
|
||||
|
|
@ -410,6 +446,11 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
|
|||
marketplaceItems,
|
||||
marketplaceInstalledMetadata,
|
||||
profileThresholds: state.profileThresholds ?? {},
|
||||
modeSortingMode: (state as any).modeSortingMode,
|
||||
pinnedModes: (state as any).pinnedModes,
|
||||
customModeOrder: (state as any).customModeOrder,
|
||||
apiProfileSortingMode: (state as any).apiProfileSortingMode,
|
||||
customApiProfileOrder: (state as any).customApiProfileOrder,
|
||||
alwaysAllowFollowupQuestions,
|
||||
followupAutoApproveTimeoutMs,
|
||||
remoteControlEnabled: state.remoteControlEnabled ?? false,
|
||||
|
|
@ -502,6 +543,26 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
|
|||
setHistoryPreviewCollapsed: (value) =>
|
||||
setState((prevState) => ({ ...prevState, historyPreviewCollapsed: value })),
|
||||
setHasOpenedModeSelector: (value) => setState((prevState) => ({ ...prevState, hasOpenedModeSelector: value })),
|
||||
setModeSortingMode: (value) => setState((prevState) => ({ ...prevState, modeSortingMode: value }) as any),
|
||||
setPinnedModes: (value) => setState((prevState) => ({ ...prevState, pinnedModes: value }) as any),
|
||||
togglePinnedMode: (modeSlug) =>
|
||||
setState((prevState) => {
|
||||
const currentPinned = (prevState as any).pinnedModes || {}
|
||||
const newPinned = {
|
||||
...currentPinned,
|
||||
[modeSlug]: !currentPinned[modeSlug],
|
||||
}
|
||||
// If the mode is now unpinned, remove it from the object
|
||||
if (!newPinned[modeSlug]) {
|
||||
delete newPinned[modeSlug]
|
||||
}
|
||||
return { ...prevState, pinnedModes: newPinned } as any
|
||||
}),
|
||||
setCustomModeOrder: (value) => setState((prevState) => ({ ...prevState, customModeOrder: value }) as any),
|
||||
setApiProfileSortingMode: (value) =>
|
||||
setState((prevState) => ({ ...prevState, apiProfileSortingMode: value }) as any),
|
||||
setCustomApiProfileOrder: (value) =>
|
||||
setState((prevState) => ({ ...prevState, customApiProfileOrder: value }) as any),
|
||||
setAutoCondenseContext: (value) => setState((prevState) => ({ ...prevState, autoCondenseContext: value })),
|
||||
setAutoCondenseContextPercent: (value) =>
|
||||
setState((prevState) => ({ ...prevState, autoCondenseContextPercent: value })),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue