feat: inherit model-picker reorder/accordion persistence and shift-delete from otto-ui (#1833)
* feat(model-picker): drag-to-reorder providers and persist accordion state Ports two model/provider picker QoL features from otto-ui: - Persist collapsed state of picker sections (favorites, recent, each provider) via a new persisted zustand store so collapse survives remounts and reloads, shared across every picker surface. - Desktop drag-to-reorder of provider sections (whole header as the mouse activator, 8px threshold so a plain click still toggles collapse), with the order persisted in useUIStore.providerOrder and applied across ModelControls, ModelMultiSelect and ModelSelector. Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * feat(sessions): shift-click quick action hard-deletes thread without prompt Ports the shift-quick-delete feature from otto-ui. The sidebar quick action (normally archive) becomes a no-prompt hard delete while Shift is held: the icon switches to a trash bin, the affordance turns destructive, and the click bypasses the confirmation dialog via a new skipConfirm source flag. A shared useShiftKeyHeld hook (single window listener set, useSyncExternalStore) keeps only the small action button re-rendering on Shift state changes, and resets on window blur so the affordance can't get stuck after alt-tab. Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> --------- Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
co-authored by
Serhii Dziupin
parent
e7b952cbcb
commit
3e3cd82a47
@@ -577,6 +577,7 @@ interface UIStore {
|
||||
|
||||
favoriteModels: Array<{ providerID: string; modelID: string }>;
|
||||
hiddenModels: Array<{ providerID: string; modelID: string }>;
|
||||
providerOrder: string[];
|
||||
collapsedModelProviders: string[];
|
||||
recentModels: Array<{ providerID: string; modelID: string }>;
|
||||
recentAgents: string[];
|
||||
@@ -727,6 +728,7 @@ interface UIStore {
|
||||
overProviderID: string,
|
||||
overModelID: string,
|
||||
) => void;
|
||||
setProviderOrder: (orderedProviderIDs: string[]) => void;
|
||||
toggleHiddenModel: (providerID: string, modelID: string) => void;
|
||||
isHiddenModel: (providerID: string, modelID: string) => boolean;
|
||||
hideAllModels: (providerID: string, modelIDs: string[]) => void;
|
||||
@@ -861,6 +863,7 @@ export const useUIStore = create<UIStore>()(
|
||||
mobileKeyboardMode: getStoredMobileKeyboardMode(),
|
||||
favoriteModels: [],
|
||||
hiddenModels: [],
|
||||
providerOrder: [],
|
||||
collapsedModelProviders: [],
|
||||
recentModels: [],
|
||||
recentAgents: [],
|
||||
@@ -1735,6 +1738,17 @@ export const useUIStore = create<UIStore>()(
|
||||
});
|
||||
},
|
||||
|
||||
setProviderOrder: (orderedProviderIDs) => {
|
||||
set((state) => {
|
||||
const next = orderedProviderIDs.filter((id) => typeof id === 'string' && id.length > 0);
|
||||
const current = state.providerOrder;
|
||||
if (current.length === next.length && current.every((id, index) => id === next[index])) {
|
||||
return state;
|
||||
}
|
||||
return { providerOrder: next };
|
||||
});
|
||||
},
|
||||
|
||||
toggleHiddenModel: (providerID, modelID) => {
|
||||
set((state) => {
|
||||
const exists = state.hiddenModels.some(
|
||||
@@ -2217,6 +2231,7 @@ export const useUIStore = create<UIStore>()(
|
||||
cornerRadius: state.cornerRadius,
|
||||
favoriteModels: state.favoriteModels,
|
||||
hiddenModels: state.hiddenModels,
|
||||
providerOrder: state.providerOrder,
|
||||
collapsedModelProviders: state.collapsedModelProviders,
|
||||
recentModels: state.recentModels,
|
||||
recentAgents: state.recentAgents,
|
||||
|
||||
Reference in New Issue
Block a user