From 0e65ed66d495099701314b2d6a4131ca25ab7cfb Mon Sep 17 00:00:00 2001 From: hhhjin Date: Wed, 8 Apr 2026 00:09:21 +0900 Subject: [PATCH] refactor: move collection slice into workspace --- .../collection/helpers/collection-entries.ts | 2 +- packages/store/src/core.ts | 2 - packages/store/src/index.ts | 5 - .../collection/index.test.ts} | 22 +-- .../collection/index.ts} | 154 +++++++++++------- .../src/workspace/fs/structure-actions.ts | 3 +- .../src/workspace/lifecycle/actions.test.ts | 27 ++- .../store/src/workspace/lifecycle/domain.ts | 5 +- .../workspace/shared/action-test-helpers.ts | 4 - packages/store/src/workspace/tree/actions.ts | 3 +- .../store/src/workspace/tree/entry-actions.ts | 23 +-- .../store/src/workspace/workspace-ports.ts | 7 +- .../store/src/workspace/workspace-slice.ts | 12 +- .../store/src/workspace/workspace-state.ts | 8 +- 14 files changed, 155 insertions(+), 122 deletions(-) rename packages/store/src/{collection/tests/collection-slice.test.ts => workspace/collection/index.test.ts} (86%) rename packages/store/src/{collection/collection-slice.ts => workspace/collection/index.ts} (67%) diff --git a/packages/store/src/collection/helpers/collection-entries.ts b/packages/store/src/collection/helpers/collection-entries.ts index 6b65e29b..c0a2af3e 100644 --- a/packages/store/src/collection/helpers/collection-entries.ts +++ b/packages/store/src/collection/helpers/collection-entries.ts @@ -1,5 +1,5 @@ import { findEntryByPath } from "../../workspace/tree/domain/entry-tree" -import type { WorkspaceEntry } from "../../workspace/workspace-slice" +import type { WorkspaceEntry } from "../../workspace/workspace-state" /** * Computes collection entries (markdown files) for a given collection path. diff --git a/packages/store/src/core.ts b/packages/store/src/core.ts index a93cf7b6..631c4d6e 100644 --- a/packages/store/src/core.ts +++ b/packages/store/src/core.ts @@ -21,8 +21,6 @@ export type { } from "./ai-settings/credentials" export type { OllamaModels } from "./ai-settings/ollama-types" export type { BrowserStorageLike } from "./browser-storage" -export type { CollectionSlice } from "./collection/collection-slice" -export { prepareCollectionSlice } from "./collection/collection-slice" export type { EditorSlice } from "./editor/editor-slice" export { prepareEditorSlice } from "./editor/editor-slice" export type { diff --git a/packages/store/src/index.ts b/packages/store/src/index.ts index 4f5ed60b..299c2a0e 100644 --- a/packages/store/src/index.ts +++ b/packages/store/src/index.ts @@ -4,8 +4,6 @@ import { type AISettingsSliceDependencies, prepareAISettingsSlice, } from "./ai-settings/ai-settings-slice" -import type { CollectionSlice } from "./collection/collection-slice" -import { prepareCollectionSlice } from "./collection/collection-slice" import type { EditorSlice } from "./editor/editor-slice" import { prepareEditorSlice } from "./editor/editor-slice" import type { GitSyncSlice } from "./git-sync/git-sync-slice" @@ -35,7 +33,6 @@ import { prepareWorkspaceSlice } from "./workspace/workspace-slice" export type StoreState = WorkspaceSlice & TabSlice & - CollectionSlice & AISettingsSlice & EditorSlice & GitSyncSlice & @@ -59,7 +56,6 @@ export type MditStore = UseBoundStore> export const createMditStore = ( dependencies: MditStoreDependencies, ): MditStore => { - const createCollectionSlice = prepareCollectionSlice() const createEditorSlice = prepareEditorSlice() const createImageEditSlice = prepareImageEditSlice() const createAISettingsSlice = prepareAISettingsSlice(dependencies.aiSettings) @@ -71,7 +67,6 @@ export const createMditStore = ( const createWorkspaceSlice = prepareWorkspaceSlice(dependencies.workspace) return create()((...args) => ({ - ...createCollectionSlice(...args), ...createTabSlice(...args), ...createWorkspaceSlice(...args), ...createAISettingsSlice(...args), diff --git a/packages/store/src/collection/tests/collection-slice.test.ts b/packages/store/src/workspace/collection/index.test.ts similarity index 86% rename from packages/store/src/collection/tests/collection-slice.test.ts rename to packages/store/src/workspace/collection/index.test.ts index 331bcd17..5a195438 100644 --- a/packages/store/src/collection/tests/collection-slice.test.ts +++ b/packages/store/src/workspace/collection/index.test.ts @@ -1,6 +1,9 @@ import { describe, expect, it } from "vitest" import { createStore } from "zustand/vanilla" -import { prepareCollectionSlice } from "../collection-slice" +import { + buildWorkspaceCollectionState, + createWorkspaceCollectionActions, +} from "./index" type EntryLike = { path: string @@ -9,12 +12,6 @@ type EntryLike = { children?: EntryLike[] } -// const makeFile = (path: string, name: string): EntryLike => ({ -// path, -// name, -// isDirectory: false, -// }) - const makeDir = ( path: string, name: string, @@ -26,15 +23,14 @@ const makeDir = ( children, }) -const createCollectionTestStore = () => { - const createSlice = prepareCollectionSlice() - return createStore()((set, get, api) => ({ +const createCollectionTestStore = () => + createStore()((set, get) => ({ + ...buildWorkspaceCollectionState(), entries: [], - ...createSlice(set, get, api), + ...createWorkspaceCollectionActions(set, get), })) -} -describe("collection-slice event handlers", () => { +describe("workspace collection event handlers", () => { it("onEntriesDeleted clears current and last paths when affected", () => { const store = createCollectionTestStore() store.setState({ diff --git a/packages/store/src/collection/collection-slice.ts b/packages/store/src/workspace/collection/index.ts similarity index 67% rename from packages/store/src/collection/collection-slice.ts rename to packages/store/src/workspace/collection/index.ts index bb1823ef..1d5f9062 100644 --- a/packages/store/src/collection/collection-slice.ts +++ b/packages/store/src/workspace/collection/index.ts @@ -1,43 +1,47 @@ import { isPathEqualOrDescendant } from "@mdit/utils/path-utils" -import type { StateCreator } from "zustand" -import type { - WorkspaceEntry, - WorkspaceSlice, -} from "../workspace/workspace-slice" -import { computeCollectionEntries } from "./helpers/collection-entries" - -type EntryCreatedInput = Parameters[0] -type EntriesDeletedInput = Parameters[0] -type EntryRenamedInput = Parameters[0] -type EntryMovedInput = Parameters[0] +import type { StoreApi } from "zustand" +import { computeCollectionEntries } from "../../collection/helpers/collection-entries" +import type { WorkspaceEntry } from "../workspace-state" + +type EntryCreatedInput = { + parentPath: string + entry: WorkspaceEntry + expandParent?: boolean + expandNewDirectory?: boolean +} -const replacePathPrefixIfDescendant = ( - path: string | null, - oldPath: string, - newPath: string, -): string | null => { - if (!path || !isPathEqualOrDescendant(path, oldPath)) { - return path - } +type EntriesDeletedInput = { + paths: string[] +} - if (path === oldPath) { - return newPath - } +type EntryRenamedInput = { + oldPath: string + newPath: string + isDirectory: boolean + newName: string + clearSyncedName?: boolean +} - return `${newPath}${path.slice(oldPath.length)}` +type EntryMovedInput = { + sourcePath: string + destinationDirPath: string + newPath: string + isDirectory: boolean + refreshContent?: boolean } -export type CollectionSlice = { +export type WorkspaceCollectionState = { currentCollectionPath: string | null lastCollectionPath: string | null collectionEntries: WorkspaceEntry[] +} + +export type WorkspaceCollectionActions = { setCurrentCollectionPath: ( path: string | null | ((prev: string | null) => string | null), ) => void - clearLastCollectionPath: () => void resetCollectionPath: () => void toggleCollectionView: () => void - getCurrentCollectionPath: () => string | null refreshCollectionEntries: () => void onEntryCreated: (input: EntryCreatedInput) => void onEntriesDeleted: (input: EntriesDeletedInput) => void @@ -45,15 +49,59 @@ export type CollectionSlice = { onEntryMoved: (input: EntryMovedInput) => void } -export const prepareCollectionSlice = - (): StateCreator => - (set, get) => ({ - currentCollectionPath: null, - lastCollectionPath: null, - collectionEntries: [], +export type WorkspaceCollectionSlice = WorkspaceCollectionState & + WorkspaceCollectionActions + +type CollectionStoreState = WorkspaceCollectionState & { + entries: WorkspaceEntry[] +} + +const replacePathPrefixIfDescendant = ( + path: string | null, + oldPath: string, + newPath: string, +): string | null => { + if (!path || !isPathEqualOrDescendant(path, oldPath)) { + return path + } + + if (path === oldPath) { + return newPath + } + + return `${newPath}${path.slice(oldPath.length)}` +} + +export const buildWorkspaceCollectionState = ( + overrides?: Partial, +): WorkspaceCollectionState => ({ + currentCollectionPath: null, + lastCollectionPath: null, + collectionEntries: [], + ...overrides, +}) + +export const createWorkspaceCollectionActions = < + TStoreState extends CollectionStoreState, +>( + set: StoreApi["setState"], + get: StoreApi["getState"], +): WorkspaceCollectionActions => { + const setCollectionState = ( + partial: + | Partial + | ((state: TStoreState) => Partial), + ) => { + set( + partial as + | Partial + | ((state: TStoreState) => Partial), + ) + } + return { setCurrentCollectionPath: (path) => { - set((state) => { + setCollectionState((state) => { const nextPath = typeof path === "function" ? path(state.currentCollectionPath) : path return { @@ -65,28 +113,19 @@ export const prepareCollectionSlice = }) }, - clearLastCollectionPath: () => { - set({ - lastCollectionPath: null, - }) - }, - resetCollectionPath: () => { - set({ - currentCollectionPath: null, - lastCollectionPath: null, - collectionEntries: [], - }) + setCollectionState(buildWorkspaceCollectionState()) }, toggleCollectionView: () => { const { currentCollectionPath, lastCollectionPath } = get() if (currentCollectionPath !== null) { - // Close the view - set({ currentCollectionPath: null, collectionEntries: [] }) + setCollectionState({ + currentCollectionPath: null, + collectionEntries: [], + }) } else if (lastCollectionPath !== null) { - // Restore the last opened path - set({ + setCollectionState({ currentCollectionPath: lastCollectionPath, collectionEntries: computeCollectionEntries( lastCollectionPath, @@ -96,10 +135,8 @@ export const prepareCollectionSlice = } }, - getCurrentCollectionPath: () => get().currentCollectionPath, - refreshCollectionEntries: () => { - set((state) => ({ + setCollectionState((state) => ({ collectionEntries: computeCollectionEntries( state.currentCollectionPath, get().entries, @@ -107,8 +144,8 @@ export const prepareCollectionSlice = })) }, - onEntryCreated: () => { - set((state) => ({ + onEntryCreated: (_input) => { + setCollectionState((state) => ({ collectionEntries: computeCollectionEntries( state.currentCollectionPath, get().entries, @@ -117,7 +154,7 @@ export const prepareCollectionSlice = }, onEntriesDeleted: ({ paths }) => { - set((state) => { + setCollectionState((state) => { const { currentCollectionPath, lastCollectionPath } = state const shouldClearCurrentCollectionPath = currentCollectionPath !== null && @@ -149,7 +186,7 @@ export const prepareCollectionSlice = }, onEntryRenamed: ({ oldPath, newPath, isDirectory }) => { - set((state) => { + setCollectionState((state) => { const nextCurrentCollectionPath = isDirectory ? replacePathPrefixIfDescendant( state.currentCollectionPath, @@ -177,7 +214,7 @@ export const prepareCollectionSlice = }, onEntryMoved: ({ sourcePath, newPath, isDirectory }) => { - set((state) => { + setCollectionState((state) => { const nextCurrentCollectionPath = isDirectory ? replacePathPrefixIfDescendant( state.currentCollectionPath, @@ -203,6 +240,5 @@ export const prepareCollectionSlice = } }) }, - }) - -export const createCollectionSlice = prepareCollectionSlice() + } +} diff --git a/packages/store/src/workspace/fs/structure-actions.ts b/packages/store/src/workspace/fs/structure-actions.ts index 77261946..d7e5ad0f 100644 --- a/packages/store/src/workspace/fs/structure-actions.ts +++ b/packages/store/src/workspace/fs/structure-actions.ts @@ -155,8 +155,7 @@ export const createFsStructureActions = ( return } - const currentCollectionPath = - ctx.ports.collection.getCurrentCollectionPath() + const { currentCollectionPath } = ctx.get() const activeTabPath = getActiveTabPathForWorkspacePolicy(ctx) let targetDirectory = workspacePath diff --git a/packages/store/src/workspace/lifecycle/actions.test.ts b/packages/store/src/workspace/lifecycle/actions.test.ts index 88bedafd..94d4912c 100644 --- a/packages/store/src/workspace/lifecycle/actions.test.ts +++ b/packages/store/src/workspace/lifecycle/actions.test.ts @@ -33,6 +33,11 @@ describe("lifecycle-actions", () => { workspacePath: "/old", recentWorkspacePaths: ["/old"], unwatchFn: unwatch, + currentCollectionPath: "/old/folder", + lastCollectionPath: "/old/folder", + collectionEntries: [ + { path: "/old/folder/note.md", name: "note.md", isDirectory: false }, + ], }) deps.historyRepository.listWorkspacePaths.mockResolvedValue([ "/new", @@ -44,9 +49,11 @@ describe("lifecycle-actions", () => { expect(unwatch).toHaveBeenCalledTimes(1) expect(deps.historyRepository.touchWorkspace).toHaveBeenCalledWith("/new") expect(deps.historyRepository.listWorkspacePaths).toHaveBeenCalled() - expect(getState().resetCollectionPath).toHaveBeenCalled() expect(getState().resetIndexingState).toHaveBeenCalled() expect(getState().getIndexingConfig).toHaveBeenCalledWith("/new") + expect(getState().currentCollectionPath).toBeNull() + expect(getState().lastCollectionPath).toBeNull() + expect(getState().collectionEntries).toEqual([]) expect(getState().workspacePath).toBe("/new") expect(getState().unwatchFn).toBeNull() }) @@ -118,6 +125,11 @@ describe("lifecycle-actions", () => { workspacePath: "/old", recentWorkspacePaths: ["/old", "/other"], unwatchFn: unwatch, + currentCollectionPath: "/old/folder", + lastCollectionPath: "/old/folder", + collectionEntries: [ + { path: "/old/folder/note.md", name: "note.md", isDirectory: false }, + ], }) deps.historyRepository.listWorkspacePaths.mockResolvedValue(["/other"]) @@ -125,8 +137,10 @@ describe("lifecycle-actions", () => { expect(unwatch).toHaveBeenCalledTimes(1) expect(deps.historyRepository.removeWorkspace).toHaveBeenCalledWith("/old") - expect(getState().resetCollectionPath).toHaveBeenCalled() expect(getState().resetIndexingState).toHaveBeenCalled() + expect(getState().currentCollectionPath).toBeNull() + expect(getState().lastCollectionPath).toBeNull() + expect(getState().collectionEntries).toEqual([]) expect(getState().workspacePath).toBeNull() expect(getState().unwatchFn).toBeNull() }) @@ -181,6 +195,11 @@ describe("lifecycle-actions", () => { setState({ workspacePath: "/old", unwatchFn: unwatch, + currentCollectionPath: "/old/folder", + lastCollectionPath: "/old/folder", + collectionEntries: [ + { path: "/old/folder/note.md", name: "note.md", isDirectory: false }, + ], }) deps.historyRepository.listWorkspacePaths.mockResolvedValue(["/new"]) deps.fileSystemRepository.isExistingDirectory.mockResolvedValue(true) @@ -188,9 +207,11 @@ describe("lifecycle-actions", () => { await bootstrapWorkspace(actions) expect(unwatch).toHaveBeenCalledTimes(1) - expect(getState().resetCollectionPath).toHaveBeenCalled() expect(getState().resetIndexingState).toHaveBeenCalled() expect(getState().getIndexingConfig).toHaveBeenCalledWith("/new") + expect(getState().currentCollectionPath).toBeNull() + expect(getState().lastCollectionPath).toBeNull() + expect(getState().collectionEntries).toEqual([]) expect(getState().workspacePath).toBe("/new") expect(getState().unwatchFn).toBeNull() }) diff --git a/packages/store/src/workspace/lifecycle/domain.ts b/packages/store/src/workspace/lifecycle/domain.ts index 2d35532c..90aaa7e8 100644 --- a/packages/store/src/workspace/lifecycle/domain.ts +++ b/packages/store/src/workspace/lifecycle/domain.ts @@ -1,6 +1,5 @@ import { isPathEqualOrDescendant } from "@mdit/utils/path-utils" import { resolve } from "pathe" -import type { CollectionSlice } from "../../collection/collection-slice" import type { IndexingSlice } from "../../indexing/indexing-slice" import type { TabSlice } from "../../tab/tab-slice" import type { WorkspaceActionContext } from "../workspace-action-context" @@ -53,9 +52,7 @@ export const resetWorkspaceState = ( unwatchFn: resolveUnwatchFnForWorkspaceTransition(ctx, workspacePath), }), ) - const state = ctx.get() as Partial - state.resetCollectionPath?.() - state.resetIndexingState?.() + ;(ctx.get() as Partial).resetIndexingState?.() } export const closeWorkspaceTabs = async ( diff --git a/packages/store/src/workspace/shared/action-test-helpers.ts b/packages/store/src/workspace/shared/action-test-helpers.ts index a4667891..5714baf3 100644 --- a/packages/store/src/workspace/shared/action-test-helpers.ts +++ b/packages/store/src/workspace/shared/action-test-helpers.ts @@ -117,15 +117,11 @@ export function createActionTestContext() { return activeTab?.path ?? null }), }, - collection: { - getCurrentCollectionPath: vi.fn(() => state.currentCollectionPath), - }, } state = { ...buildWorkspaceState(), openTabSnapshots: [], - currentCollectionPath: null, chatConfig: null, refreshCodexOAuthForTarget: vi.fn().mockResolvedValue(undefined), getEntryByPath: vi.fn((path: string) => diff --git a/packages/store/src/workspace/tree/actions.ts b/packages/store/src/workspace/tree/actions.ts index e4483b56..3e74dca0 100644 --- a/packages/store/src/workspace/tree/actions.ts +++ b/packages/store/src/workspace/tree/actions.ts @@ -1,4 +1,3 @@ -import type { CollectionSlice } from "../../collection/collection-slice" import type { WorkspaceActionContext } from "../workspace-action-context" import type { WorkspaceEntry } from "../workspace-state" import { findEntryByPath } from "./domain/entry-tree" @@ -40,7 +39,7 @@ export const createTreeActions = ( if (options?.emitEvent === false) { return } - ;(ctx.get() as Partial).refreshCollectionEntries?.() + ctx.get().refreshCollectionEntries() }, refreshWorkspaceEntries: async () => { diff --git a/packages/store/src/workspace/tree/entry-actions.ts b/packages/store/src/workspace/tree/entry-actions.ts index 68f40557..c2554c8a 100644 --- a/packages/store/src/workspace/tree/entry-actions.ts +++ b/packages/store/src/workspace/tree/entry-actions.ts @@ -1,4 +1,3 @@ -import type { CollectionSlice } from "../../collection/collection-slice" import type { TabSlice } from "../../tab/tab-slice" import { addExpandedDirectories, @@ -14,6 +13,7 @@ import { persistPinnedDirectoriesIfChanged, } from "../directory-ui/runtime/persistence" import type { WorkspaceActionContext } from "../workspace-action-context" +import type { WorkspaceSlice } from "../workspace-slice" import type { WorkspaceEntry } from "../workspace-state" import { addEntryToState, @@ -24,18 +24,7 @@ import { updateEntryMetadata, } from "./domain/entry-tree" -type WorkspaceTreeStoreState = Partial & { - workspacePath: string | null - entries: WorkspaceEntry[] - expandedDirectories: string[] - pinnedDirectories: string[] - updateEntries: ( - entries: - | WorkspaceEntry[] - | ((entries: WorkspaceEntry[]) => WorkspaceEntry[]), - options?: { emitEvent?: boolean }, - ) => void -} +type WorkspaceTreeStoreState = WorkspaceSlice & Partial export type WorkspaceTreeEntryActions = { entryCreated: (input: { @@ -86,7 +75,7 @@ export const createTreeEntryActions = ( : addEntryToState(entries, parentPath, entry) store.updateEntries(nextEntries, { emitEvent: false }) - ;(store as typeof store & Partial).onEntryCreated?.({ + store.onEntryCreated({ parentPath, entry, expandParent, @@ -120,7 +109,7 @@ export const createTreeEntryActions = ( emitEvent: false, }) ;(store as typeof store & Partial).removePathsFromHistory?.(paths) - ;(store as typeof store & Partial).onEntriesDeleted?.({ + store.onEntriesDeleted({ paths, }) @@ -170,7 +159,7 @@ export const createTreeEntryActions = ( oldPath, newPath, ) - ;(store as typeof store & Partial).onEntryRenamed?.({ + store.onEntryRenamed({ oldPath, newPath, isDirectory, @@ -239,7 +228,7 @@ export const createTreeEntryActions = ( sourcePath, newPath, ) - ;(store as typeof store & Partial).onEntryMoved?.({ + store.onEntryMoved({ sourcePath, destinationDirPath, newPath, diff --git a/packages/store/src/workspace/workspace-ports.ts b/packages/store/src/workspace/workspace-ports.ts index a1971a80..d77e2537 100644 --- a/packages/store/src/workspace/workspace-ports.ts +++ b/packages/store/src/workspace/workspace-ports.ts @@ -1,12 +1,10 @@ -import type { CollectionSlice } from "../collection/collection-slice" import type { TabSlice } from "../tab/tab-slice" export type WorkspacePorts = { tab: Pick - collection: Pick } -type WorkspacePortSource = TabSlice & CollectionSlice +type WorkspacePortSource = TabSlice export const createWorkspacePorts = ( get: () => WorkspacePortSource, @@ -15,7 +13,4 @@ export const createWorkspacePorts = ( getOpenTabSnapshots: () => get().getOpenTabSnapshots(), getActiveTabPath: () => get().getActiveTabPath(), }, - collection: { - getCurrentCollectionPath: () => get().getCurrentCollectionPath(), - }, }) diff --git a/packages/store/src/workspace/workspace-slice.ts b/packages/store/src/workspace/workspace-slice.ts index f6a61bba..207cf4aa 100644 --- a/packages/store/src/workspace/workspace-slice.ts +++ b/packages/store/src/workspace/workspace-slice.ts @@ -3,8 +3,11 @@ import { DEFAULT_LOCAL_MUTATION_TTL_MS, } from "@mdit/local-fs-origin" import type { StateCreator } from "zustand" -import type { CollectionSlice } from "../collection/collection-slice" import type { TabSlice } from "../tab/tab-slice" +import { + createWorkspaceCollectionActions, + type WorkspaceCollectionSlice, +} from "./collection" import { createDirectoryUiActions, type WorkspaceDirectoryUiActions, @@ -35,9 +38,11 @@ export type WorkspaceActions = WorkspaceTreeActions & WorkspaceEntrySessionActions & WorkspaceWatchActions -export type WorkspaceSlice = WorkspaceState & WorkspaceActions +export type WorkspaceSlice = WorkspaceState & + WorkspaceCollectionSlice & + WorkspaceActions -type WorkspaceSliceStoreState = WorkspaceSlice & TabSlice & CollectionSlice +type WorkspaceSliceStoreState = WorkspaceSlice & TabSlice export const prepareWorkspaceSlice = ( @@ -59,6 +64,7 @@ export const prepareWorkspaceSlice = return { ...buildWorkspaceState({ isLoading: true }), + ...createWorkspaceCollectionActions(set, get), ...createTreeActions(actionContext), ...createDirectoryUiActions(actionContext), ...createLifecycleActions(actionContext), diff --git a/packages/store/src/workspace/workspace-state.ts b/packages/store/src/workspace/workspace-state.ts index 141e81da..a7306d4d 100644 --- a/packages/store/src/workspace/workspace-state.ts +++ b/packages/store/src/workspace/workspace-state.ts @@ -1,3 +1,8 @@ +import { + buildWorkspaceCollectionState, + type WorkspaceCollectionState, +} from "./collection" + type UnwatchFn = () => void | Promise export type WorkspaceEntry = { @@ -14,7 +19,7 @@ export type WorkspaceEntrySelection = { anchorId: string | null } -export type WorkspaceState = { +export type WorkspaceState = WorkspaceCollectionState & { isLoading: boolean isEditMode: boolean workspacePath: string | null @@ -33,6 +38,7 @@ export type WorkspaceState = { export const buildWorkspaceState = ( overrides?: Partial, ): WorkspaceState => ({ + ...buildWorkspaceCollectionState(), isLoading: false, isEditMode: false, workspacePath: null,