2026-03-06 17:22:59 +02:00
|
|
|
import React from 'react';
|
2026-07-12 00:03:37 +11:00
|
|
|
import {
|
|
|
|
|
getArchivedScopeKey,
|
|
|
|
|
resolveArchivedFolderName,
|
|
|
|
|
} from '../utils';
|
2026-07-13 23:18:12 +03:00
|
|
|
import type { SessionOwnershipIndex } from '../sessionOwnership';
|
2026-03-06 17:22:59 +02:00
|
|
|
|
2026-06-26 19:27:53 +03:00
|
|
|
type ProjectForArchivedFolders = {
|
2026-07-13 23:18:12 +03:00
|
|
|
id: string;
|
2026-03-06 17:22:59 +02:00
|
|
|
normalizedPath: string;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
type FolderEntry = {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
sessionIds: string[];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
type Args = {
|
2026-07-21 20:52:20 +03:00
|
|
|
enabled?: boolean;
|
2026-03-06 17:22:59 +02:00
|
|
|
normalizedProjects: ProjectForArchivedFolders[];
|
2026-07-13 23:18:12 +03:00
|
|
|
ownership: SessionOwnershipIndex;
|
2026-03-06 17:22:59 +02:00
|
|
|
isSessionsLoading: boolean;
|
2026-07-13 23:18:12 +03:00
|
|
|
hasAuthoritativeGlobalSessions: boolean;
|
|
|
|
|
isWorktreeTopologyLoading: boolean;
|
|
|
|
|
unresolvedWorktreeProjectPaths: ReadonlySet<string>;
|
2026-03-06 17:22:59 +02:00
|
|
|
foldersMap: Record<string, FolderEntry[]>;
|
|
|
|
|
createFolder: (scopeKey: string, name: string, parentId?: string | null) => FolderEntry;
|
|
|
|
|
addSessionToFolder: (scopeKey: string, folderId: string, sessionId: string) => void;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const useArchivedAutoFolders = (args: Args): void => {
|
|
|
|
|
const {
|
|
|
|
|
normalizedProjects,
|
2026-07-21 20:52:20 +03:00
|
|
|
enabled = true,
|
2026-07-13 23:18:12 +03:00
|
|
|
ownership,
|
2026-03-06 17:22:59 +02:00
|
|
|
isSessionsLoading,
|
2026-07-13 23:18:12 +03:00
|
|
|
hasAuthoritativeGlobalSessions,
|
|
|
|
|
isWorktreeTopologyLoading,
|
|
|
|
|
unresolvedWorktreeProjectPaths,
|
2026-03-06 17:22:59 +02:00
|
|
|
foldersMap,
|
|
|
|
|
createFolder,
|
|
|
|
|
addSessionToFolder,
|
|
|
|
|
} = args;
|
|
|
|
|
|
|
|
|
|
React.useEffect(() => {
|
2026-07-21 20:52:20 +03:00
|
|
|
if (!enabled || isSessionsLoading || !hasAuthoritativeGlobalSessions || isWorktreeTopologyLoading) {
|
2026-03-06 17:22:59 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
normalizedProjects.forEach((project) => {
|
2026-07-13 23:18:12 +03:00
|
|
|
if (unresolvedWorktreeProjectPaths.has(project.normalizedPath)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2026-03-06 17:22:59 +02:00
|
|
|
const scopeKey = getArchivedScopeKey(project.normalizedPath);
|
2026-07-13 23:18:12 +03:00
|
|
|
const projectArchivedSessions = ownership.archivedSessionsByProject.get(project.id) ?? [];
|
2026-03-06 17:22:59 +02:00
|
|
|
const existingFolders = foldersMap[scopeKey] ?? [];
|
|
|
|
|
const folderByName = new Map(existingFolders.map((folder) => [folder.name.toLowerCase(), folder]));
|
|
|
|
|
|
|
|
|
|
projectArchivedSessions.forEach((session) => {
|
|
|
|
|
const folderName = resolveArchivedFolderName(session, project.normalizedPath);
|
|
|
|
|
const key = folderName.toLowerCase();
|
|
|
|
|
let folder = folderByName.get(key);
|
|
|
|
|
if (!folder) {
|
|
|
|
|
folder = createFolder(scopeKey, folderName);
|
|
|
|
|
folderByName.set(key, folder);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!folder.sessionIds.includes(session.id)) {
|
|
|
|
|
addSessionToFolder(scopeKey, folder.id, session.id);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}, [
|
|
|
|
|
normalizedProjects,
|
2026-07-21 20:52:20 +03:00
|
|
|
enabled,
|
2026-07-13 23:18:12 +03:00
|
|
|
ownership,
|
2026-03-06 17:22:59 +02:00
|
|
|
isSessionsLoading,
|
2026-07-13 23:18:12 +03:00
|
|
|
hasAuthoritativeGlobalSessions,
|
|
|
|
|
isWorktreeTopologyLoading,
|
|
|
|
|
unresolvedWorktreeProjectPaths,
|
2026-03-06 17:22:59 +02:00
|
|
|
foldersMap,
|
|
|
|
|
createFolder,
|
|
|
|
|
addSessionToFolder,
|
|
|
|
|
]);
|
|
|
|
|
};
|