| 1 | import { asArray } from "./array"; |
| 2 | import { desktopHost } from "./desktopHost"; |
| 3 | import { mockProjectGroups } from "./mockProjectTreeOrganization"; |
| 4 | import type { |
| 5 | ProjectNode, |
| 6 | ProjectTopicKey, |
| 7 | ProjectTopicPage, |
| 8 | ProjectTopicPageRequest, |
| 9 | ProjectTreeChangedV2, |
| 10 | SessionCatalogBindings, |
| 11 | } from "./types"; |
| 12 | |
| 13 | export function onProjectTreeChangedV2(cb: (event: ProjectTreeChangedV2) => void): () => void { |
| 14 | const host = desktopHost(); |
| 15 | if (host.kind !== "none") { |
| 16 | return host.events.on("project-tree:changed-v2", (payload?: unknown) => { |
| 17 | if (!payload || typeof payload !== "object") return; |
| 18 | const event = payload as Partial<ProjectTreeChangedV2>; |
| 19 | cb({ |
| 20 | revision: typeof event.revision === "number" ? event.revision : 0, |
| 21 | roots: asArray(event.roots).filter((root): root is string => typeof root === "string"), |
| 22 | reason: typeof event.reason === "string" ? event.reason : "changed", |
| 23 | }); |
| 24 | }); |
| 25 | } |
| 26 | return () => {}; |
| 27 | } |
| 28 | |
| 29 | export function makeMockSessionCatalogBindings(cloneProjectTree: () => ProjectNode[]): SessionCatalogBindings { |
| 30 | const listProjectTopics = async (req: ProjectTopicPageRequest): Promise<ProjectTopicPage> => { |
| 31 | const folder = req.scope === "global" |
| 32 | ? cloneProjectTree().find((item) => item.kind === "global_folder") |
| 33 | : cloneProjectTree().find((item) => item.kind === "project" && item.root === req.workspaceRoot); |
| 34 | const query = (req.query ?? "").trim().toLocaleLowerCase(); |
| 35 | const created = req.sortMode === "created"; |
| 36 | const groups = mockProjectGroups(req.scope, req.workspaceRoot ?? ""); |
| 37 | const grouped = new Set(groups.flatMap((group) => group.topicIds ?? [])); |
| 38 | const selectedGroup = groups.find((group) => group.id === req.groupId); |
| 39 | const all = asArray(folder?.children) |
| 40 | .filter((item) => !query || item.label.toLocaleLowerCase().includes(query)) |
| 41 | .filter((item) => !req.excludePinned || !item.pinned) |
| 42 | .filter((item) => req.groupFilter !== "ungrouped" || !grouped.has(item.topicId ?? "")) |
| 43 | .filter((item) => req.groupFilter !== "group" || Boolean(selectedGroup?.topicIds?.includes(item.topicId ?? ""))) |
| 44 | .sort((left, right) => Number(Boolean(right.pinned)) - Number(Boolean(left.pinned)) |
| 45 | || (created ? right.createdAt || right.lastActivityAt || 0 : right.lastActivityAt || right.createdAt || 0) |
| 46 | - (created ? left.createdAt || left.lastActivityAt || 0 : left.lastActivityAt || left.createdAt || 0) |
| 47 | || (left.topicId ?? "").localeCompare(right.topicId ?? "")); |
| 48 | const start = Math.max(0, Number.parseInt(req.cursor ?? "0", 10) || 0); |
| 49 | const limit = Math.min(200, Math.max(1, req.limit ?? 50)); |
| 50 | const items = all.slice(start, start + limit); |
| 51 | return { |
| 52 | items, |
| 53 | nextCursor: start + items.length < all.length ? String(start + items.length) : undefined, |
| 54 | revision: 1, |
| 55 | complete: true, |
| 56 | readyDirectories: 1, |
| 57 | pendingDirectories: 0, |
| 58 | failedDirectories: 0, |
| 59 | }; |
| 60 | }; |
| 61 | return { |
| 62 | async GetProjectTreeSnapshot() { |
| 63 | return { |
| 64 | revision: 1, |
| 65 | projects: cloneProjectTree().map((project) => ({ |
| 66 | ...project, |
| 67 | children: asArray(project.children).filter((topic) => Boolean(topic.pinned)), |
| 68 | })), |
| 69 | catalog: { state: "ready", mode: "memory", revision: 1, indexed: 4, total: 4, repairPending: 0, sourceCount: 4, unindexedTargetCount: 0, canRebuild: false }, |
| 70 | indexed: 4, |
| 71 | total: 4, |
| 72 | indexingDone: true, |
| 73 | }; |
| 74 | }, |
| 75 | ListProjectTopics: listProjectTopics, |
| 76 | async GetTopicSummary(key: ProjectTopicKey) { |
| 77 | const page = await listProjectTopics({ scope: key.scope, workspaceRoot: key.workspaceRoot, limit: 200 }); |
| 78 | return page.items.find((item) => item.topicId === key.topicId) |
| 79 | ?? { key: "", kind: key.scope === "global" ? "global_topic" : "topic", label: "", children: [] }; |
| 80 | }, |
| 81 | async GetSessionCatalogStatus() { |
| 82 | return { state: "ready", mode: "memory", revision: 1, indexed: 4, total: 4, repairPending: 0, sourceCount: 4, unindexedTargetCount: 0, canRebuild: false }; |
| 83 | }, |
| 84 | async RebuildSessionCatalog() {}, |
| 85 | }; |
| 86 | } |
| 87 |