fix(sidebar): add project sort modes (#2067)
* fix(sidebar): add project sort modes * fix(sidebar): preserve manual sort order * fix(sidebar): move sort state before render --------- Co-authored-by: bashrusakh <bashrusakh@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
co-authored by
bashrusakh
parent
f6326e1c35
commit
bfaf62e222
@@ -46,6 +46,7 @@ interface VSCodeWorkspaceFolderConfig {
|
||||
interface ProjectsStore {
|
||||
projects: ProjectEntry[];
|
||||
activeProjectId: string | null;
|
||||
manualProjectOrder: string[];
|
||||
|
||||
addProject: (path: string, options?: { label?: string; id?: string }) => ProjectEntry | null;
|
||||
removeProject: (id: string) => void;
|
||||
@@ -315,6 +316,17 @@ const readPersistedProjects = (): ProjectEntry[] => {
|
||||
}
|
||||
};
|
||||
|
||||
const readPersistedManualOrder = (): string[] => {
|
||||
try {
|
||||
const raw = safeStorage.getItem(getProjectsStorageKey() + ':manualOrder');
|
||||
if (!raw) return [];
|
||||
const parsed = JSON.parse(raw);
|
||||
return Array.isArray(parsed) ? parsed.filter((id): id is string => typeof id === 'string') : [];
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
const readPersistedActiveProjectId = (): string | null => {
|
||||
try {
|
||||
const raw = safeStorage.getItem(getActiveProjectStorageKey())
|
||||
@@ -347,11 +359,22 @@ const cacheProjects = (projects: ProjectEntry[], activeProjectId: string | null)
|
||||
}
|
||||
};
|
||||
|
||||
const persistProjects = (projects: ProjectEntry[], activeProjectId: string | null) => {
|
||||
const persistProjects = (projects: ProjectEntry[], activeProjectId: string | null, manualOrder?: string[]) => {
|
||||
cacheProjects(projects, activeProjectId);
|
||||
if (manualOrder) {
|
||||
persistManualProjectOrder(manualOrder);
|
||||
}
|
||||
void updateDesktopSettings({ projects, activeProjectId: activeProjectId ?? undefined });
|
||||
};
|
||||
|
||||
const persistManualProjectOrder = (manualOrder: string[]) => {
|
||||
try {
|
||||
safeStorage.setItem(getProjectsStorageKey() + ':manualOrder', JSON.stringify(manualOrder));
|
||||
} catch {
|
||||
// ignored
|
||||
}
|
||||
};
|
||||
|
||||
const initialProjects = readPersistedProjects();
|
||||
const normalizeVSCodeWorkspaceFolders = (folders: VSCodeWorkspaceFolderConfig[]): VSCodeWorkspaceFolderConfig[] => {
|
||||
const result: VSCodeWorkspaceFolderConfig[] = [];
|
||||
@@ -536,6 +559,7 @@ export const useProjectsStore = create<ProjectsStore>()(
|
||||
devtools((set, get) => ({
|
||||
projects: effectiveInitialProjects,
|
||||
activeProjectId: initialActiveProjectId,
|
||||
manualProjectOrder: readPersistedManualOrder(),
|
||||
|
||||
validateProjectPath: (path: string): ProjectPathValidationResult => {
|
||||
if (typeof path !== 'string' || path.trim().length === 0) {
|
||||
@@ -604,8 +628,9 @@ export const useProjectsStore = create<ProjectsStore>()(
|
||||
nextActiveId = nextProjects[0]?.id ?? null;
|
||||
}
|
||||
|
||||
set({ projects: nextProjects, activeProjectId: nextActiveId });
|
||||
persistProjects(nextProjects, nextActiveId);
|
||||
const nextManualOrder = get().manualProjectOrder.filter((oid) => oid !== id);
|
||||
set({ projects: nextProjects, activeProjectId: nextActiveId, manualProjectOrder: nextManualOrder });
|
||||
persistProjects(nextProjects, nextActiveId, nextManualOrder);
|
||||
|
||||
// Clean up worktree entries for the removed project
|
||||
if (project) {
|
||||
@@ -647,7 +672,7 @@ export const useProjectsStore = create<ProjectsStore>()(
|
||||
);
|
||||
|
||||
set({ projects: nextProjects, activeProjectId: id });
|
||||
persistProjects(nextProjects, id);
|
||||
persistProjects(nextProjects, id, get().manualProjectOrder);
|
||||
|
||||
opencodeClient.setDirectory(target.path);
|
||||
useDirectoryStore.getState().setDirectory(target.path, { showOverlay: false });
|
||||
@@ -672,7 +697,7 @@ export const useProjectsStore = create<ProjectsStore>()(
|
||||
);
|
||||
|
||||
set({ projects: nextProjects, activeProjectId: id });
|
||||
persistProjects(nextProjects, id);
|
||||
persistProjects(nextProjects, id, get().manualProjectOrder);
|
||||
},
|
||||
|
||||
renameProject: (id: string, label: string) => {
|
||||
@@ -689,7 +714,7 @@ export const useProjectsStore = create<ProjectsStore>()(
|
||||
project.id === id ? { ...project, label: trimmed } : project
|
||||
);
|
||||
set({ projects: nextProjects });
|
||||
persistProjects(nextProjects, activeProjectId);
|
||||
persistProjects(nextProjects, activeProjectId, get().manualProjectOrder);
|
||||
},
|
||||
|
||||
updateProjectMeta: (id: string, meta: {
|
||||
@@ -726,7 +751,7 @@ export const useProjectsStore = create<ProjectsStore>()(
|
||||
return updated;
|
||||
});
|
||||
set({ projects: nextProjects });
|
||||
persistProjects(nextProjects, activeProjectId);
|
||||
persistProjects(nextProjects, activeProjectId, get().manualProjectOrder);
|
||||
},
|
||||
|
||||
uploadProjectIcon: async (id: string, file: File) => {
|
||||
@@ -863,8 +888,9 @@ export const useProjectsStore = create<ProjectsStore>()(
|
||||
const [moved] = nextProjects.splice(fromIndex, 1);
|
||||
nextProjects.splice(toIndex, 0, moved);
|
||||
|
||||
set({ projects: nextProjects });
|
||||
persistProjects(nextProjects, activeProjectId);
|
||||
const newOrder = nextProjects.map((p) => p.id);
|
||||
set({ projects: nextProjects, manualProjectOrder: newOrder });
|
||||
persistProjects(nextProjects, activeProjectId, newOrder);
|
||||
},
|
||||
|
||||
resetForRuntimeSwitch: () => {
|
||||
@@ -876,7 +902,7 @@ export const useProjectsStore = create<ProjectsStore>()(
|
||||
const nextActiveProjectId = projects.some((project) => project.id === activeProjectId)
|
||||
? activeProjectId
|
||||
: projects[0]?.id ?? null;
|
||||
set({ projects, activeProjectId: nextActiveProjectId });
|
||||
set({ projects, activeProjectId: nextActiveProjectId, manualProjectOrder: [] });
|
||||
},
|
||||
|
||||
synchronizeFromSettings: (settings: DesktopSettings) => {
|
||||
@@ -903,6 +929,7 @@ export const useProjectsStore = create<ProjectsStore>()(
|
||||
if (activeExists) {
|
||||
set({ activeProjectId: incomingActive });
|
||||
cacheProjects(current.projects, incomingActive);
|
||||
persistManualProjectOrder(get().manualProjectOrder);
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -915,8 +942,11 @@ export const useProjectsStore = create<ProjectsStore>()(
|
||||
return;
|
||||
}
|
||||
|
||||
set({ projects: incomingProjects, activeProjectId: incomingActive });
|
||||
const incomingIds = new Set(incomingProjects.map((p) => p.id));
|
||||
const cleanedOrder = get().manualProjectOrder.filter((id) => incomingIds.has(id));
|
||||
set({ projects: incomingProjects, activeProjectId: incomingActive, manualProjectOrder: cleanedOrder });
|
||||
cacheProjects(incomingProjects, incomingActive);
|
||||
persistManualProjectOrder(cleanedOrder);
|
||||
|
||||
if (incomingActive) {
|
||||
const activeProject = incomingProjects.find((project) => project.id === incomingActive);
|
||||
|
||||
Reference in New Issue
Block a user