Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
2 changes: 0 additions & 2 deletions packages/store/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
5 changes: 0 additions & 5 deletions packages/store/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -35,7 +33,6 @@ import { prepareWorkspaceSlice } from "./workspace/workspace-slice"

export type StoreState = WorkspaceSlice &
TabSlice &
CollectionSlice &
AISettingsSlice &
EditorSlice &
GitSyncSlice &
Expand All @@ -59,7 +56,6 @@ export type MditStore = UseBoundStore<StoreApi<StoreState>>
export const createMditStore = (
dependencies: MditStoreDependencies,
): MditStore => {
const createCollectionSlice = prepareCollectionSlice()
const createEditorSlice = prepareEditorSlice()
const createImageEditSlice = prepareImageEditSlice()
const createAISettingsSlice = prepareAISettingsSlice(dependencies.aiSettings)
Expand All @@ -71,7 +67,6 @@ export const createMditStore = (
const createWorkspaceSlice = prepareWorkspaceSlice(dependencies.workspace)

return create<StoreState>()((...args) => ({
...createCollectionSlice(...args),
...createTabSlice(...args),
...createWorkspaceSlice(...args),
...createAISettingsSlice(...args),
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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,
Expand All @@ -26,15 +23,14 @@ const makeDir = (
children,
})

const createCollectionTestStore = () => {
const createSlice = prepareCollectionSlice()
return createStore<any>()((set, get, api) => ({
const createCollectionTestStore = () =>
createStore<any>()((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({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,59 +1,107 @@
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<WorkspaceSlice["entryCreated"]>[0]
type EntriesDeletedInput = Parameters<WorkspaceSlice["entriesDeleted"]>[0]
type EntryRenamedInput = Parameters<WorkspaceSlice["entryRenamed"]>[0]
type EntryMovedInput = Parameters<WorkspaceSlice["entryMoved"]>[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
onEntryRenamed: (input: EntryRenamedInput) => void
onEntryMoved: (input: EntryMovedInput) => void
}

export const prepareCollectionSlice =
(): StateCreator<CollectionSlice & WorkspaceSlice, [], [], CollectionSlice> =>
(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>,
): WorkspaceCollectionState => ({
currentCollectionPath: null,
lastCollectionPath: null,
collectionEntries: [],
...overrides,
})

export const createWorkspaceCollectionActions = <
TStoreState extends CollectionStoreState,
>(
set: StoreApi<TStoreState>["setState"],
get: StoreApi<TStoreState>["getState"],
): WorkspaceCollectionActions => {
const setCollectionState = (
partial:
| Partial<WorkspaceCollectionState>
| ((state: TStoreState) => Partial<WorkspaceCollectionState>),
) => {
set(
partial as
| Partial<TStoreState>
| ((state: TStoreState) => Partial<TStoreState>),
)
}
Comment thread
hhhjin marked this conversation as resolved.

return {
setCurrentCollectionPath: (path) => {
set((state) => {
setCollectionState((state) => {
const nextPath =
typeof path === "function" ? path(state.currentCollectionPath) : path
return {
Expand All @@ -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,
Expand All @@ -96,19 +135,17 @@ export const prepareCollectionSlice =
}
},

getCurrentCollectionPath: () => get().currentCollectionPath,

refreshCollectionEntries: () => {
set((state) => ({
setCollectionState((state) => ({
collectionEntries: computeCollectionEntries(
state.currentCollectionPath,
get().entries,
),
}))
},

onEntryCreated: () => {
set((state) => ({
onEntryCreated: (_input) => {
setCollectionState((state) => ({
collectionEntries: computeCollectionEntries(
state.currentCollectionPath,
get().entries,
Expand All @@ -117,7 +154,7 @@ export const prepareCollectionSlice =
},

onEntriesDeleted: ({ paths }) => {
set((state) => {
setCollectionState((state) => {
const { currentCollectionPath, lastCollectionPath } = state
const shouldClearCurrentCollectionPath =
currentCollectionPath !== null &&
Expand Down Expand Up @@ -149,7 +186,7 @@ export const prepareCollectionSlice =
},

onEntryRenamed: ({ oldPath, newPath, isDirectory }) => {
set((state) => {
setCollectionState((state) => {
const nextCurrentCollectionPath = isDirectory
? replacePathPrefixIfDescendant(
state.currentCollectionPath,
Expand Down Expand Up @@ -177,7 +214,7 @@ export const prepareCollectionSlice =
},

onEntryMoved: ({ sourcePath, newPath, isDirectory }) => {
set((state) => {
setCollectionState((state) => {
const nextCurrentCollectionPath = isDirectory
? replacePathPrefixIfDescendant(
state.currentCollectionPath,
Expand All @@ -203,6 +240,5 @@ export const prepareCollectionSlice =
}
})
},
})

export const createCollectionSlice = prepareCollectionSlice()
}
}
3 changes: 1 addition & 2 deletions packages/store/src/workspace/fs/structure-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Loading
Loading