Skip to content
Closed
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
21 changes: 6 additions & 15 deletions src/app/src/composables/useContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,19 +139,14 @@ export const useContext = createSharedComposable((
}
},
[StudioItemActionId.RevertItem]: async (item: TreeItem) => {
// Get collections from document item or use default media collection
for (const collection of item.collections) {
const id = generateIdFromFsPath(item.fsPath, collection)
await activeTree.value.draft.revert(id)
}
await activeTree.value.draft.revert(item.id)
},
[StudioItemActionId.RenameItem]: async (params: TreeItem | RenameFileParams) => {
const { item, newFsPath } = params as RenameFileParams

// Revert file
if (item.type === 'file') {
const id = generateIdFromFsPath(item.fsPath, item.collections[0])
await activeTree.value.draft.rename([{ id, newFsPath }])
await activeTree.value.draft.rename([{ id: item.id, newFsPath }])
return
}

Expand All @@ -160,7 +155,7 @@ export const useContext = createSharedComposable((
if (descendants.length > 0) {
const itemsToRename = descendants.map((descendant) => {
return {
id: generateIdFromFsPath(descendant.fsPath, descendant.collections[0]),
id: descendant.id,
newFsPath: descendant.fsPath.replace(item.fsPath, newFsPath),
}
})
Expand All @@ -171,25 +166,21 @@ export const useContext = createSharedComposable((
[StudioItemActionId.DeleteItem]: async (item: TreeItem) => {
// Delete file
if (item.type === 'file') {
const id = generateIdFromFsPath(item.fsPath, item.collections![0])
await activeTree.value.draft.remove([id])
await activeTree.value.draft.remove([item.id])
return
}

// Delete folder
const descendants = findDescendantsFileItemsFromFsPath(activeTree.value.root.value, item.fsPath)
if (descendants.length > 0) {
const ids: string[] = descendants.map((descendant) => {
return generateIdFromFsPath(descendant.fsPath, descendant.collections![0])
})
const ids: string[] = descendants.map(descendant => descendant.id)
await activeTree.value.draft.remove(ids)
}
},
[StudioItemActionId.DuplicateItem]: async (item: TreeItem) => {
// Duplicate file
if (item.type === 'file') {
const id = generateIdFromFsPath(item.fsPath, item.collections![0])
const draftItem = await activeTree.value.draft.duplicate(id)
const draftItem = await activeTree.value.draft.duplicate(item.id)
await activeTree.value.selectItemByFsPath(draftItem!.id)
return
}
Expand Down
4 changes: 2 additions & 2 deletions src/app/src/composables/useTree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { StudioFeature, TreeStatus, type StudioHost, type TreeItem, DraftStatus
import { ref, computed } from 'vue'
import type { useDraftDocuments } from './useDraftDocuments'
import type { useDraftMedias } from './useDraftMedias'
import { buildTree, findItemFromFsPath, findItemFromRoute, findParentFromFsPath, generateIdFromFsPath } from '../utils/tree'
import { buildTree, findItemFromFsPath, findItemFromRoute, findParentFromFsPath } from '../utils/tree'
import type { RouteLocationNormalized } from 'vue-router'
import { useHooks } from './useHooks'
import { useStudioState } from './useStudioState'
Expand Down Expand Up @@ -53,7 +53,7 @@ export const useTree = (type: StudioFeature, host: StudioHost, draft: ReturnType
setLocation(type, currentItem.value.fsPath)

if (item?.type === 'file') {
await draft.selectById(generateIdFromFsPath(item.fsPath, item.collections![0]))
await draft.selectById(item.id)

if (
!preferences.value.syncEditorAndRoute
Expand Down
1 change: 1 addition & 0 deletions src/app/src/types/tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ export interface TreeItem {
routePath?: string
children?: TreeItem[]
hide?: boolean
id: string
}
3 changes: 3 additions & 0 deletions src/app/src/utils/tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ TreeItem[] {
type: 'file',
prefix,
collections: [dbItem.id.split('/')[0]],
id: dbItem.id,
}

if (dbItem.fsPath.endsWith('.gitkeep')) {
Expand Down Expand Up @@ -122,6 +123,7 @@ TreeItem[] {
children: [],
prefix: dirPrefix,
collections: [dbItem.id.split('/')[0]],
id: dirFsPath,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
id: dirFsPath,
id: joinURL(dbItem.id.split('/')[0], dirFsPath),

Directory items are assigned id: dirFsPath without including the collection prefix, which breaks the revert, rename, and delete operations on directories and their descendants because the ID matching logic in findDescendantsFromId will fail.

View Details

Analysis

Directory ID mismatch breaks revert, rename, and delete operations

What fails: Directory items in buildTree() receive IDs without collection prefixes (e.g., blog/posts) while file items get full database IDs (e.g., content/blog/posts/file.md), causing findDescendantsFromId() to fail when performing operations on directories and their descendants.

How to reproduce:

  1. Create files in collection: content/blog/posts/file1.md, content/blog/posts/file2.md
  2. Call findDescendantsFromId(draftItems, 'blog/posts') to find directory descendants
  3. Result: 0 descendants found (should find 2 files)

What happens: findDescendantsFromId() uses item.id.startsWith(id + '/') but fails because file IDs like content/blog/posts/file1.md don't start with blog/posts/. Directory operations (revert, rename, delete) fail to find and process nested files.

Expected: Directory IDs should include collection prefix (content/blog/posts) to match their descendant file IDs, allowing findDescendantsFromId() to correctly identify directory contents.

}

directoryMap.set(dirFsPath, directory)
Expand Down Expand Up @@ -150,6 +152,7 @@ TreeItem[] {
type: 'file',
prefix,
collections: [dbItem.id.split('/')[0]],
id: dbItem.id,
}

if (dbItem.fsPath.endsWith('.gitkeep')) {
Expand Down
11 changes: 5 additions & 6 deletions src/module/src/runtime/utils/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,11 @@ export function getCollection(collectionName: string, collections: Record<string
}

export function getCollectionSource(id: string, collection: CollectionInfo) {
const [_, ...rest] = id.split(/[/:]/)
const path = rest.join('/')

const matchedSource = collection.source.find((source) => {
const include = minimatch(path, source.include, { dot: true })
const exclude = source.exclude?.some(exclude => minimatch(path, exclude))
const filePath = generateFsPathFromId(id, source)

const include = minimatch(filePath, source.include, { dot: true })
const exclude = source.exclude?.some(exclude => minimatch(filePath, exclude))

return include && !exclude
})
Expand All @@ -82,7 +81,7 @@ export function generateFsPathFromId(id: string, source: CollectionInfo['source'

const { fixed } = parseSourceBase(source)

const pathWithoutFixed = path.substring(fixed.length)
const pathWithoutFixed = source.prefix === '/' ? path : path.substring(fixed.length)
return join(fixed, pathWithoutFixed)
}

Expand Down
Loading