@webiny/app-aco 6.4.5 → 6.6.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/Actions/DeleteFolder/DeleteFolder.js +1 -1
- package/components/Actions/DeleteFolder/DeleteFolder.js.map +1 -1
- package/components/AdvancedSearch/domain/Filter.d.ts +1 -1
- package/components/AdvancedSearch/domain/FilterRepositoryFactory.d.ts +2 -2
- package/components/AdvancedSearch/domain/FilterRepositoryFactory.js.map +1 -1
- package/components/AdvancedSearch/gateways/FiltersGraphQLGateway.d.ts +2 -2
- package/components/AdvancedSearch/gateways/FiltersGraphQLGateway.js +9 -10
- package/components/AdvancedSearch/gateways/FiltersGraphQLGateway.js.map +1 -1
- package/components/AdvancedSearch/gateways/filters.gql.d.ts +5 -5
- package/components/AdvancedSearch/gateways/filters.gql.js +5 -6
- package/components/AdvancedSearch/gateways/filters.gql.js.map +1 -1
- package/components/AdvancedSearch/useFilterRepository.js +7 -2
- package/components/AdvancedSearch/useFilterRepository.js.map +1 -1
- package/components/Table/cells/CellAuthor.d.ts +2 -0
- package/components/Table/cells/CellAuthor.js +10 -0
- package/components/Table/cells/CellAuthor.js.map +1 -0
- package/components/Table/cells/CellCreated.d.ts +2 -0
- package/components/Table/cells/CellCreated.js +13 -0
- package/components/Table/cells/CellCreated.js.map +1 -0
- package/components/Table/cells/CellModified.d.ts +2 -0
- package/components/Table/cells/CellModified.js +13 -0
- package/components/Table/cells/CellModified.js.map +1 -0
- package/components/Table/cells/index.d.ts +3 -0
- package/components/Table/cells/index.js +3 -0
- package/components/Table/createTableData.d.ts +7 -5
- package/components/Table/createTableData.js +22 -7
- package/components/Table/createTableData.js.map +1 -1
- package/components/Table/index.d.ts +2 -2
- package/components/Table/index.js +2 -2
- package/components/index.d.ts +0 -1
- package/components/index.js +0 -1
- package/config/AcoConfig.d.ts +8 -12
- package/config/advanced-search/FieldRenderer.d.ts +3 -1
- package/config/folder/Action.d.ts +1 -1
- package/config/folder/index.d.ts +3 -2
- package/config/index.d.ts +0 -1
- package/config/index.js +0 -1
- package/config/record/Action.d.ts +1 -1
- package/config/record/index.d.ts +1 -1
- package/config/table/Column.d.ts +8 -39
- package/config/table/Column.js +4 -67
- package/config/table/Column.js.map +1 -1
- package/config/table/Sorting.d.ts +2 -11
- package/config/table/Sorting.js +1 -28
- package/config/table/index.d.ts +5 -9
- package/contexts/index.d.ts +0 -3
- package/contexts/index.js +0 -3
- package/dialogs/DialogSetPermissions/graphql.d.ts +1 -1
- package/dialogs/DialogSetPermissions/graphql.js +1 -2
- package/dialogs/DialogSetPermissions/graphql.js.map +1 -1
- package/dialogs/useCreateDialog.js +2 -2
- package/dialogs/useCreateDialog.js.map +1 -1
- package/dialogs/useEditDialog.js +2 -2
- package/dialogs/useEditDialog.js.map +1 -1
- package/dialogs/useSetPermissionsDialog.js +16 -4
- package/dialogs/useSetPermissionsDialog.js.map +1 -1
- package/domain/folder/Folder.d.ts +2 -1
- package/domain/folder/Folder.js.map +1 -1
- package/features/folders/createFolder/CreateFolderGqlGateway.d.ts +3 -3
- package/features/folders/createFolder/CreateFolderGqlGateway.js +15 -16
- package/features/folders/createFolder/CreateFolderGqlGateway.js.map +1 -1
- package/features/folders/deleteFolder/DeleteFolderGqlGateway.d.ts +3 -3
- package/features/folders/deleteFolder/DeleteFolderGqlGateway.js +5 -6
- package/features/folders/deleteFolder/DeleteFolderGqlGateway.js.map +1 -1
- package/features/folders/folderModelProvider/FolderModelProvider.js +29 -31
- package/features/folders/folderModelProvider/FolderModelProvider.js.map +1 -1
- package/features/folders/folderModelProvider/GetFolderModelGqlGateway.d.ts +3 -3
- package/features/folders/folderModelProvider/GetFolderModelGqlGateway.js +5 -7
- package/features/folders/folderModelProvider/GetFolderModelGqlGateway.js.map +1 -1
- package/features/folders/getFolder/GetFolderGqlGateway.d.ts +3 -3
- package/features/folders/getFolder/GetFolderGqlGateway.js +5 -7
- package/features/folders/getFolder/GetFolderGqlGateway.js.map +1 -1
- package/features/folders/getFolderExtensionsFields/GetFolderExtensionsFieldsUseCase.d.ts +3 -3
- package/features/folders/getFolderExtensionsFields/useFolderExtensionsFields.d.ts +3 -3
- package/features/folders/listFolders/ListFoldersGqlGateway.d.ts +1 -1
- package/features/folders/listFolders/ListFoldersGqlGateway.js +1 -2
- package/features/folders/listFolders/ListFoldersGqlGateway.js.map +1 -1
- package/features/folders/listFolders/useListFolders.d.ts +1 -1
- package/features/folders/listFoldersByParentIds/ListFoldersByParentIdsGqlGateway.d.ts +3 -3
- package/features/folders/listFoldersByParentIds/ListFoldersByParentIdsGqlGateway.js +5 -7
- package/features/folders/listFoldersByParentIds/ListFoldersByParentIdsGqlGateway.js.map +1 -1
- package/features/folders/listFoldersByParentIds/useListFoldersByParentIds.d.ts +2 -2
- package/features/folders/loadFolderHierarchy/useLoadFolderHierarchy.d.ts +2 -2
- package/features/folders/updateFolder/UpdateFolderGqlGateway.d.ts +3 -3
- package/features/folders/updateFolder/UpdateFolderGqlGateway.js +5 -6
- package/features/folders/updateFolder/UpdateFolderGqlGateway.js.map +1 -1
- package/hooks/index.d.ts +0 -6
- package/hooks/index.js +0 -6
- package/index.d.ts +3 -2
- package/index.js +2 -2
- package/package.json +16 -23
- package/presentation/folderTree/FolderTreePresenter.js +8 -8
- package/presentation/folderTree/FolderTreePresenter.js.map +1 -1
- package/presentation/folderTree/FolderTreePresenter.test.js +4 -2
- package/presentation/folderTree/FolderTreePresenter.test.js.map +1 -1
- package/table.types.d.ts +2 -9
- package/types.d.ts +5 -26
- package/types.js.map +1 -1
- package/components/Extensions/Extensions.d.ts +0 -2
- package/components/Extensions/Extensions.js +0 -30
- package/components/Extensions/Extensions.js.map +0 -1
- package/components/Extensions/index.d.ts +0 -1
- package/components/Extensions/index.js +0 -1
- package/config/folder/createFolderFieldDecoratorFactory.d.ts +0 -13
- package/config/folder/createFolderFieldDecoratorFactory.js +0 -17
- package/config/folder/createFolderFieldDecoratorFactory.js.map +0 -1
- package/config/table/Sorting.js.map +0 -1
- package/contexts/acoList.d.ts +0 -49
- package/contexts/acoList.js +0 -303
- package/contexts/acoList.js.map +0 -1
- package/contexts/app.d.ts +0 -33
- package/contexts/app.js +0 -47
- package/contexts/app.js.map +0 -1
- package/contexts/folders.d.ts +0 -12
- package/contexts/folders.js +0 -32
- package/contexts/folders.js.map +0 -1
- package/contexts/navigateFolder.d.ts +0 -17
- package/contexts/navigateFolder.js +0 -54
- package/contexts/navigateFolder.js.map +0 -1
- package/contexts/records.d.ts +0 -31
- package/contexts/records.js +0 -316
- package/contexts/records.js.map +0 -1
- package/exports/admin/aco.d.ts +0 -2
- package/exports/admin/aco.js +0 -2
- package/graphql/app.gql.d.ts +0 -17
- package/graphql/app.gql.js +0 -22
- package/graphql/app.gql.js.map +0 -1
- package/graphql/records/common.d.ts +0 -4
- package/graphql/records/common.js +0 -57
- package/graphql/records/common.js.map +0 -1
- package/graphql/records/getRecord.d.ts +0 -2
- package/graphql/records/getRecord.js +0 -5
- package/graphql/records/getRecord.js.map +0 -1
- package/graphql/records/listRecords.d.ts +0 -2
- package/graphql/records/listRecords.js +0 -26
- package/graphql/records/listRecords.js.map +0 -1
- package/graphql/records/moveRecord.d.ts +0 -2
- package/graphql/records/moveRecord.js +0 -16
- package/graphql/records/moveRecord.js.map +0 -1
- package/graphql/records/types.d.ts +0 -108
- package/graphql/records/types.js +0 -0
- package/graphql/records.gql.d.ts +0 -3
- package/graphql/records.gql.js +0 -3
- package/handlers.d.ts +0 -23
- package/handlers.js +0 -22
- package/handlers.js.map +0 -1
- package/hooks/useAcoApp.d.ts +0 -2
- package/hooks/useAcoApp.js +0 -16
- package/hooks/useAcoApp.js.map +0 -1
- package/hooks/useAcoList.d.ts +0 -3
- package/hooks/useAcoList.js +0 -10
- package/hooks/useAcoList.js.map +0 -1
- package/hooks/useFolderModel.d.ts +0 -2
- package/hooks/useFolderModel.js +0 -16
- package/hooks/useFolderModel.js.map +0 -1
- package/hooks/useFoldersType.d.ts +0 -1
- package/hooks/useFoldersType.js +0 -12
- package/hooks/useFoldersType.js.map +0 -1
- package/hooks/useNavigateFolder.d.ts +0 -2
- package/hooks/useNavigateFolder.js +0 -10
- package/hooks/useNavigateFolder.js.map +0 -1
- package/hooks/useRecords.d.ts +0 -62
- package/hooks/useRecords.js +0 -64
- package/hooks/useRecords.js.map +0 -1
- package/hooks/useTags.d.ts +0 -14
- package/hooks/useTags.js +0 -27
- package/hooks/useTags.js.map +0 -1
- package/sorting.d.ts +0 -9
- package/sorting.js +0 -31
- package/sorting.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webiny/app-aco",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.6.0-alpha.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./index.js",
|
|
@@ -15,23 +15,18 @@
|
|
|
15
15
|
"author": "Webiny Ltd.",
|
|
16
16
|
"license": "MIT",
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@
|
|
19
|
-
"@webiny/
|
|
20
|
-
"@webiny/app": "6.
|
|
21
|
-
"@webiny/app-
|
|
22
|
-
"@webiny/app-
|
|
23
|
-
"@webiny/
|
|
24
|
-
"@webiny/
|
|
25
|
-
"@webiny/
|
|
26
|
-
"@webiny/
|
|
27
|
-
"@webiny/
|
|
28
|
-
"@webiny/
|
|
29
|
-
"@webiny/
|
|
30
|
-
"@webiny/utils": "6.4.5",
|
|
31
|
-
"@webiny/validation": "6.4.5",
|
|
32
|
-
"dot-prop-immutable": "2.1.1",
|
|
33
|
-
"graphql": "16.14.2",
|
|
34
|
-
"graphql-tag": "2.12.7",
|
|
18
|
+
"@webiny/admin-ui": "6.6.0-alpha.0",
|
|
19
|
+
"@webiny/app": "6.6.0-alpha.0",
|
|
20
|
+
"@webiny/app-admin": "6.6.0-alpha.0",
|
|
21
|
+
"@webiny/app-headless-cms-common": "6.6.0-alpha.0",
|
|
22
|
+
"@webiny/app-utils": "6.6.0-alpha.0",
|
|
23
|
+
"@webiny/feature": "6.6.0-alpha.0",
|
|
24
|
+
"@webiny/form": "6.6.0-alpha.0",
|
|
25
|
+
"@webiny/icons": "6.6.0-alpha.0",
|
|
26
|
+
"@webiny/react-properties": "6.6.0-alpha.0",
|
|
27
|
+
"@webiny/shared-aco": "6.6.0-alpha.0",
|
|
28
|
+
"@webiny/utils": "6.6.0-alpha.0",
|
|
29
|
+
"@webiny/validation": "6.6.0-alpha.0",
|
|
35
30
|
"lodash": "4.18.1",
|
|
36
31
|
"mobx": "6.16.1",
|
|
37
32
|
"mobx-react-lite": "4.1.1",
|
|
@@ -42,13 +37,11 @@
|
|
|
42
37
|
},
|
|
43
38
|
"devDependencies": {
|
|
44
39
|
"@types/react": "18.3.31",
|
|
45
|
-
"@webiny/build-tools": "6.
|
|
40
|
+
"@webiny/build-tools": "6.6.0-alpha.0",
|
|
46
41
|
"@webiny/di": "1.0.2",
|
|
47
|
-
"@webiny/wcp": "6.
|
|
48
|
-
"apollo-client": "2.6.10",
|
|
49
|
-
"apollo-link": "1.2.14",
|
|
42
|
+
"@webiny/wcp": "6.6.0-alpha.0",
|
|
50
43
|
"rimraf": "6.1.3",
|
|
51
|
-
"typescript": "
|
|
44
|
+
"typescript": "7.0.2",
|
|
52
45
|
"vitest": "4.1.10"
|
|
53
46
|
},
|
|
54
47
|
"publishConfig": {
|
|
@@ -66,9 +66,10 @@ class FolderTreePresenterImpl {
|
|
|
66
66
|
};
|
|
67
67
|
}
|
|
68
68
|
selectFolder(folderId) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
const normalized = folderId === ROOT_FOLDER ? null : folderId;
|
|
70
|
+
this.currentFolderId = normalized;
|
|
71
|
+
if (normalized) this.loadChildFolders([
|
|
72
|
+
normalized
|
|
72
73
|
]);
|
|
73
74
|
}
|
|
74
75
|
onFolderChange(callback) {
|
|
@@ -115,8 +116,8 @@ class FolderTreePresenterImpl {
|
|
|
115
116
|
const form = this.formModelFactory.create({
|
|
116
117
|
fields: (fields)=>({
|
|
117
118
|
title: fields.text().label("Title").required("Title is required"),
|
|
118
|
-
slug: fields.text().label("Slug").required("Slug is required").computedUntilDirty((
|
|
119
|
-
const title =
|
|
119
|
+
slug: fields.text().label("Slug").required("Slug is required").computedUntilDirty(({ form })=>{
|
|
120
|
+
const title = form.field("title").getValue();
|
|
120
121
|
return slugify(String(title ?? ""), {
|
|
121
122
|
replacement: "-",
|
|
122
123
|
lower: true,
|
|
@@ -149,8 +150,8 @@ class FolderTreePresenterImpl {
|
|
|
149
150
|
const form = this.formModelFactory.create({
|
|
150
151
|
fields: (fields)=>({
|
|
151
152
|
title: fields.text().label("Name").required("Name is required"),
|
|
152
|
-
slug: fields.text().label("Slug").required("Slug is required").computedUntilDirty((
|
|
153
|
-
const title =
|
|
153
|
+
slug: fields.text().label("Slug").required("Slug is required").computedUntilDirty(({ form })=>{
|
|
154
|
+
const title = form.field("title").getValue();
|
|
154
155
|
return slugify(String(title ?? ""), {
|
|
155
156
|
replacement: "-",
|
|
156
157
|
lower: true,
|
|
@@ -199,7 +200,6 @@ class FolderTreePresenterImpl {
|
|
|
199
200
|
permissions: folder?.permissions ?? []
|
|
200
201
|
});
|
|
201
202
|
}
|
|
202
|
-
await this.loadFolders();
|
|
203
203
|
runInAction(()=>{
|
|
204
204
|
this.operation = {
|
|
205
205
|
active: false,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presentation/folderTree/FolderTreePresenter.js","sources":["../../../src/presentation/folderTree/FolderTreePresenter.ts"],"sourcesContent":["import { makeAutoObservable, reaction, runInAction } from \"mobx\";\nimport slugify from \"slugify\";\nimport {\n FolderTreePresenter as Abstraction,\n type IFolderTreeNode,\n type IFolderTreeViewModel,\n type IFolderOperationState\n} from \"./abstractions.js\";\nimport { ROOT_FOLDER } from \"~/constants.js\";\nimport { FoldersCache, FoldersContext } from \"~/features/folders/abstractions.js\";\nimport { ListFoldersUseCase } from \"~/features/folders/listFolders/abstractions.js\";\nimport { ListFoldersByParentIdsUseCase } from \"~/features/folders/listFoldersByParentIds/abstractions.js\";\nimport { CreateFolderUseCase } from \"~/features/folders/createFolder/abstractions.js\";\nimport { UpdateFolderUseCase } from \"~/features/folders/updateFolder/abstractions.js\";\nimport { DeleteFolderUseCase } from \"~/features/folders/deleteFolder/abstractions.js\";\nimport { GetFolderAncestorsUseCase } from \"~/features/folders/getFolderAncestors/abstractions.js\";\nimport { GetFolderLevelPermissionUseCase } from \"~/features/folders/getFolderLevelPermission/abstractions.js\";\nimport { FormModelFactory } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport type { Folder } from \"~/domain/folder/Folder.js\";\nimport type { FolderDto } from \"~/domain/folder/FolderDto.js\";\nimport { FolderDtoMapper } from \"~/domain/folder/FolderDtoMapper.js\";\n\ntype FolderChangeCallback = (folderId: string | null) => void;\n\nclass FolderTreePresenterImpl implements Abstraction.Interface {\n private currentFolderId: string | null = null;\n private loading = false;\n private _loadingNodeIds: string[] = [];\n private operation: IFolderOperationState = { active: false, mode: null };\n private callbacks: Set<FolderChangeCallback> = new Set();\n private disposed = false;\n\n constructor(\n private foldersContext: FoldersContext.Interface,\n private foldersCache: FoldersCache.Interface,\n private listFoldersUseCase: ListFoldersUseCase.Interface,\n private listFoldersByParentIdsUseCase: ListFoldersByParentIdsUseCase.Interface,\n private createFolderUseCase: CreateFolderUseCase.Interface,\n private updateFolderUseCase: UpdateFolderUseCase.Interface,\n private deleteFolderUseCase: DeleteFolderUseCase.Interface,\n private getFolderAncestorsUseCase: GetFolderAncestorsUseCase.Interface,\n private getFolderLevelPermissionUseCase: GetFolderLevelPermissionUseCase.Interface,\n private formModelFactory: FormModelFactory.Interface\n ) {\n makeAutoObservable<FolderTreePresenterImpl, \"callbacks\">(\n this,\n { callbacks: false },\n { autoBind: true }\n );\n\n reaction(\n () => this.currentFolderId,\n folderId => {\n if (!this.disposed) {\n this.callbacks.forEach(cb => cb(folderId));\n }\n }\n );\n\n void this.loadFolders();\n }\n\n get vm(): IFolderTreeViewModel {\n const tree = this.buildTree();\n const allFolders = this.foldersCache.getItems();\n const currentNode = this.findNode(this.currentFolderId, tree);\n const currentFolder = this.findFolder(this.currentFolderId);\n const childNodes = currentNode\n ? currentNode.children\n : tree.filter(n => n.id !== ROOT_FOLDER);\n return {\n folders: allFolders.map(f => FolderDtoMapper.toDTO(f)),\n tree,\n currentFolderId: this.currentFolderId,\n currentFolder: currentFolder ? FolderDtoMapper.toDTO(currentFolder) : null,\n isRootFolder: this.currentFolderId === null,\n currentFolderTitle: currentNode?.name ?? \"All Files\",\n childFolders: childNodes\n .map(n => {\n const folder = allFolders.find(f => f.id === n.id);\n return folder ? FolderDtoMapper.toDTO(folder) : null;\n })\n .filter((f): f is FolderDto => f !== null),\n loading: this.loading,\n loadingNodeIds: this._loadingNodeIds,\n operation: this.operation\n };\n }\n\n selectFolder(folderId: string | null): void {\n this.currentFolderId = folderId;\n if (folderId) {\n void this.loadChildFolders([folderId]);\n }\n }\n\n onFolderChange(callback: FolderChangeCallback): () => void {\n this.callbacks.add(callback);\n return () => {\n this.callbacks.delete(callback);\n };\n }\n\n async loadChildFolders(parentIds: string[]): Promise<void> {\n const fetchableIds = parentIds.filter(id => id !== ROOT_FOLDER && id !== \"0\");\n if (fetchableIds.length === 0) {\n return;\n }\n\n runInAction(() => {\n this._loadingNodeIds = fetchableIds;\n });\n\n try {\n await this.listFoldersByParentIdsUseCase.execute(fetchableIds);\n } finally {\n runInAction(() => {\n this._loadingNodeIds = [];\n });\n }\n }\n\n async moveFolder(folderId: string, targetParentId: string | null): Promise<void> {\n const folders = this.foldersCache.getItems();\n const folder = folders.find(f => f.id === folderId);\n if (!folder) {\n return;\n }\n\n await this.updateFolderUseCase.execute({\n id: folderId,\n title: folder.title,\n slug: folder.slug,\n type: this.foldersContext.type,\n parentId: targetParentId,\n permissions: folder.permissions\n });\n\n await this.loadFolders();\n }\n\n canManageStructure(folderId: string): boolean {\n return this.getFolderLevelPermissionUseCase.execute(folderId, \"canManageStructure\");\n }\n\n getAncestorIds(folderId: string): string[] {\n return this.getFolderAncestorsUseCase.execute(folderId).map(f => f.id);\n }\n\n createFolder(parentFolderId?: string): void {\n const form = this.formModelFactory.create({\n fields: fields => ({\n title: fields.text().label(\"Title\").required(\"Title is required\"),\n slug: fields\n .text()\n .label(\"Slug\")\n .required(\"Slug is required\")\n .computedUntilDirty(f => {\n const title = f.field(\"title\").getValue();\n return slugify(String(title ?? \"\"), {\n replacement: \"-\",\n lower: true,\n remove: /[*#\\?<>_\\{\\}\\[\\]+~.()'\"!:;@]/g,\n trim: false\n });\n }),\n parentId: fields\n .text()\n .label(\"Parent folder\")\n .renderer(\"folderTree\" as any)\n }),\n layout: layout => [layout.row(\"title\"), layout.row(\"slug\"), layout.row(\"parentId\")]\n });\n\n form.setData({ parentId: parentFolderId ?? null });\n\n this.operation = {\n active: true,\n mode: \"create\",\n parentFolderId,\n form\n };\n }\n\n editFolder(folderId: string): void {\n const folders = this.foldersCache.getItems();\n const folder = folders.find(f => f.id === folderId);\n if (!folder) {\n return;\n }\n\n const form = this.formModelFactory.create({\n fields: fields => ({\n title: fields.text().label(\"Name\").required(\"Name is required\"),\n slug: fields\n .text()\n .label(\"Slug\")\n .required(\"Slug is required\")\n .computedUntilDirty(f => {\n const title = f.field(\"title\").getValue();\n return slugify(String(title ?? \"\"), {\n replacement: \"-\",\n lower: true,\n remove: /[*#\\?<>_\\{\\}\\[\\]+~.()'\"!:;@]/g,\n trim: false\n });\n })\n }),\n layout: layout => [layout.row(\"title\"), layout.row(\"slug\")]\n });\n\n form.setData({ title: folder.title, slug: folder.slug });\n\n this.operation = {\n active: true,\n mode: \"edit\",\n folderId,\n form\n };\n }\n\n async submitOperation(): Promise<boolean> {\n const { mode, form, parentFolderId, folderId } = this.operation;\n if (!form || !mode) {\n return false;\n }\n\n const data = await form.submit<{ title: string; slug: string; parentId?: string | null }>();\n if (!data) {\n return false;\n }\n\n if (mode === \"create\") {\n await this.createFolderUseCase.execute({\n title: data.title,\n slug: data.slug,\n type: this.foldersContext.type,\n parentId: data.parentId ?? parentFolderId ?? null,\n permissions: []\n });\n } else if (mode === \"edit\" && folderId) {\n const folders = this.foldersCache.getItems();\n const folder = folders.find(f => f.id === folderId);\n\n await this.updateFolderUseCase.execute({\n id: folderId,\n title: data.title,\n slug: data.slug,\n type: this.foldersContext.type,\n parentId: folder?.parentId ?? null,\n permissions: folder?.permissions ?? []\n });\n }\n\n await this.loadFolders();\n\n runInAction(() => {\n this.operation = { active: false, mode: null };\n });\n\n return true;\n }\n\n async deleteFolder(folderId: string): Promise<void> {\n const folders = this.foldersCache.getItems();\n const folder = folders.find(f => f.id === folderId);\n const parentId = folder?.parentId ?? null;\n\n this.operation = {\n active: true,\n mode: \"delete\",\n folderId\n };\n\n await this.deleteFolderUseCase.execute(folderId);\n await this.loadFolders();\n\n runInAction(() => {\n this.operation = { active: false, mode: null };\n this.currentFolderId = parentId;\n });\n }\n\n cancelOperation(): void {\n this.operation = { active: false, mode: null };\n }\n\n private async loadFolders(): Promise<void> {\n runInAction(() => {\n this.loading = true;\n });\n\n try {\n await this.listFoldersUseCase.execute();\n } finally {\n runInAction(() => {\n this.loading = false;\n });\n }\n }\n\n private buildTree(): IFolderTreeNode[] {\n const folders = this.foldersCache.getItems();\n return this.buildTreeFromFolders(folders);\n }\n\n private buildTreeFromFolders(folders: Folder[]): IFolderTreeNode[] {\n const nodeMap = new Map<string, IFolderTreeNode>();\n\n for (const folder of folders) {\n nodeMap.set(folder.id, {\n id: folder.id,\n name: folder.title,\n slug: folder.slug,\n parentId: folder.parentId,\n children: [],\n hasNonInheritedPermissions: folder.hasNonInheritedPermissions ?? false,\n canManagePermissions: folder.canManagePermissions ?? false,\n canManageStructure: folder.canManageStructure ?? true\n });\n }\n\n const roots: IFolderTreeNode[] = [];\n for (const folder of folders) {\n const node = nodeMap.get(folder.id)!;\n if (folder.parentId && nodeMap.has(folder.parentId)) {\n nodeMap.get(folder.parentId)!.children.push(node);\n } else {\n roots.push(node);\n }\n }\n\n return roots;\n }\n\n private findFolder(folderId: string | null): Folder | null {\n if (!folderId) {\n return null;\n }\n\n return this.foldersCache.getItem(f => f.id === folderId) ?? null;\n }\n\n private findNode(folderId: string | null, nodes: IFolderTreeNode[]): IFolderTreeNode | null {\n if (folderId === null) {\n return null;\n }\n\n for (const node of nodes) {\n if (node.id === folderId) {\n return node;\n }\n const found = this.findNode(folderId, node.children);\n if (found) {\n return found;\n }\n }\n\n return null;\n }\n}\n\nexport const FolderTreePresenter = Abstraction.createImplementation({\n implementation: FolderTreePresenterImpl,\n dependencies: [\n FoldersContext,\n FoldersCache,\n ListFoldersUseCase,\n ListFoldersByParentIdsUseCase,\n CreateFolderUseCase,\n UpdateFolderUseCase,\n DeleteFolderUseCase,\n GetFolderAncestorsUseCase,\n GetFolderLevelPermissionUseCase,\n FormModelFactory\n ]\n});\n"],"names":["FolderTreePresenterImpl","foldersContext","foldersCache","listFoldersUseCase","listFoldersByParentIdsUseCase","createFolderUseCase","updateFolderUseCase","deleteFolderUseCase","getFolderAncestorsUseCase","getFolderLevelPermissionUseCase","formModelFactory","Set","makeAutoObservable","reaction","folderId","cb","tree","allFolders","currentNode","currentFolder","childNodes","n","ROOT_FOLDER","f","FolderDtoMapper","folder","callback","parentIds","fetchableIds","id","runInAction","targetParentId","folders","parentFolderId","form","fields","title","slugify","String","layout","mode","data","parentId","nodeMap","Map","roots","node","nodes","found","FolderTreePresenter","Abstraction","FoldersContext","FoldersCache","ListFoldersUseCase","ListFoldersByParentIdsUseCase","CreateFolderUseCase","UpdateFolderUseCase","DeleteFolderUseCase","GetFolderAncestorsUseCase","GetFolderLevelPermissionUseCase","FormModelFactory"],"mappings":";;;;;;;;;;;;;;AAwBA,MAAMA;IAQF,YACYC,cAAwC,EACxCC,YAAoC,EACpCC,kBAAgD,EAChDC,6BAAsE,EACtEC,mBAAkD,EAClDC,mBAAkD,EAClDC,mBAAkD,EAClDC,yBAA8D,EAC9DC,+BAA0E,EAC1EC,gBAA4C,CACtD;aAVUT,cAAc,GAAdA;aACAC,YAAY,GAAZA;aACAC,kBAAkB,GAAlBA;aACAC,6BAA6B,GAA7BA;aACAC,mBAAmB,GAAnBA;aACAC,mBAAmB,GAAnBA;aACAC,mBAAmB,GAAnBA;aACAC,yBAAyB,GAAzBA;aACAC,+BAA+B,GAA/BA;aACAC,gBAAgB,GAAhBA;aAjBJ,eAAe,GAAkB;aACjC,OAAO,GAAG;aACV,eAAe,GAAa,EAAE;aAC9B,SAAS,GAA0B;YAAE,QAAQ;YAAO,MAAM;QAAK;aAC/D,SAAS,GAA8B,IAAIC;aAC3C,QAAQ,GAAG;QAcfC,mBACI,IAAI,EACJ;YAAE,WAAW;QAAM,GACnB;YAAE,UAAU;QAAK;QAGrBC,SACI,IAAM,IAAI,CAAC,eAAe,EAC1BC,CAAAA;YACI,IAAI,CAAC,IAAI,CAAC,QAAQ,EACd,IAAI,CAAC,SAAS,CAAC,OAAO,CAACC,CAAAA,KAAMA,GAAGD;QAExC;QAGC,IAAI,CAAC,WAAW;IACzB;IAEA,IAAI,KAA2B;QAC3B,MAAME,OAAO,IAAI,CAAC,SAAS;QAC3B,MAAMC,aAAa,IAAI,CAAC,YAAY,CAAC,QAAQ;QAC7C,MAAMC,cAAc,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,eAAe,EAAEF;QACxD,MAAMG,gBAAgB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,eAAe;QAC1D,MAAMC,aAAaF,cACbA,YAAY,QAAQ,GACpBF,KAAK,MAAM,CAACK,CAAAA,IAAKA,EAAE,EAAE,KAAKC;QAChC,OAAO;YACH,SAASL,WAAW,GAAG,CAACM,CAAAA,IAAKC,gBAAgB,KAAK,CAACD;YACnDP;YACA,iBAAiB,IAAI,CAAC,eAAe;YACrC,eAAeG,gBAAgBK,gBAAgB,KAAK,CAACL,iBAAiB;YACtE,cAAc,AAAyB,SAAzB,IAAI,CAAC,eAAe;YAClC,oBAAoBD,aAAa,QAAQ;YACzC,cAAcE,WACT,GAAG,CAACC,CAAAA;gBACD,MAAMI,SAASR,WAAW,IAAI,CAACM,CAAAA,IAAKA,EAAE,EAAE,KAAKF,EAAE,EAAE;gBACjD,OAAOI,SAASD,gBAAgB,KAAK,CAACC,UAAU;YACpD,GACC,MAAM,CAAC,CAACF,IAAsBA,AAAM,SAANA;YACnC,SAAS,IAAI,CAAC,OAAO;YACrB,gBAAgB,IAAI,CAAC,eAAe;YACpC,WAAW,IAAI,CAAC,SAAS;QAC7B;IACJ;IAEA,aAAaT,QAAuB,EAAQ;QACxC,IAAI,CAAC,eAAe,GAAGA;QACvB,IAAIA,UACK,IAAI,CAAC,gBAAgB,CAAC;YAACA;SAAS;IAE7C;IAEA,eAAeY,QAA8B,EAAc;QACvD,IAAI,CAAC,SAAS,CAAC,GAAG,CAACA;QACnB,OAAO;YACH,IAAI,CAAC,SAAS,CAAC,MAAM,CAACA;QAC1B;IACJ;IAEA,MAAM,iBAAiBC,SAAmB,EAAiB;QACvD,MAAMC,eAAeD,UAAU,MAAM,CAACE,CAAAA,KAAMA,OAAOP,eAAeO,AAAO,QAAPA;QAClE,IAAID,AAAwB,MAAxBA,aAAa,MAAM,EACnB;QAGJE,YAAY;YACR,IAAI,CAAC,eAAe,GAAGF;QAC3B;QAEA,IAAI;YACA,MAAM,IAAI,CAAC,6BAA6B,CAAC,OAAO,CAACA;QACrD,SAAU;YACNE,YAAY;gBACR,IAAI,CAAC,eAAe,GAAG,EAAE;YAC7B;QACJ;IACJ;IAEA,MAAM,WAAWhB,QAAgB,EAAEiB,cAA6B,EAAiB;QAC7E,MAAMC,UAAU,IAAI,CAAC,YAAY,CAAC,QAAQ;QAC1C,MAAMP,SAASO,QAAQ,IAAI,CAACT,CAAAA,IAAKA,EAAE,EAAE,KAAKT;QAC1C,IAAI,CAACW,QACD;QAGJ,MAAM,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC;YACnC,IAAIX;YACJ,OAAOW,OAAO,KAAK;YACnB,MAAMA,OAAO,IAAI;YACjB,MAAM,IAAI,CAAC,cAAc,CAAC,IAAI;YAC9B,UAAUM;YACV,aAAaN,OAAO,WAAW;QACnC;QAEA,MAAM,IAAI,CAAC,WAAW;IAC1B;IAEA,mBAAmBX,QAAgB,EAAW;QAC1C,OAAO,IAAI,CAAC,+BAA+B,CAAC,OAAO,CAACA,UAAU;IAClE;IAEA,eAAeA,QAAgB,EAAY;QACvC,OAAO,IAAI,CAAC,yBAAyB,CAAC,OAAO,CAACA,UAAU,GAAG,CAACS,CAAAA,IAAKA,EAAE,EAAE;IACzE;IAEA,aAAaU,cAAuB,EAAQ;QACxC,MAAMC,OAAO,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC;YACtC,QAAQC,CAAAA,SAAW;oBACf,OAAOA,OAAO,IAAI,GAAG,KAAK,CAAC,SAAS,QAAQ,CAAC;oBAC7C,MAAMA,OACD,IAAI,GACJ,KAAK,CAAC,QACN,QAAQ,CAAC,oBACT,kBAAkB,CAACZ,CAAAA;wBAChB,MAAMa,QAAQb,EAAE,KAAK,CAAC,SAAS,QAAQ;wBACvC,OAAOc,QAAQC,OAAOF,SAAS,KAAK;4BAChC,aAAa;4BACb,OAAO;4BACP,QAAQ;4BACR,MAAM;wBACV;oBACJ;oBACJ,UAAUD,OACL,IAAI,GACJ,KAAK,CAAC,iBACN,QAAQ,CAAC;gBAClB;YACA,QAAQI,CAAAA,SAAU;oBAACA,OAAO,GAAG,CAAC;oBAAUA,OAAO,GAAG,CAAC;oBAASA,OAAO,GAAG,CAAC;iBAAY;QACvF;QAEAL,KAAK,OAAO,CAAC;YAAE,UAAUD,kBAAkB;QAAK;QAEhD,IAAI,CAAC,SAAS,GAAG;YACb,QAAQ;YACR,MAAM;YACNA;YACAC;QACJ;IACJ;IAEA,WAAWpB,QAAgB,EAAQ;QAC/B,MAAMkB,UAAU,IAAI,CAAC,YAAY,CAAC,QAAQ;QAC1C,MAAMP,SAASO,QAAQ,IAAI,CAACT,CAAAA,IAAKA,EAAE,EAAE,KAAKT;QAC1C,IAAI,CAACW,QACD;QAGJ,MAAMS,OAAO,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC;YACtC,QAAQC,CAAAA,SAAW;oBACf,OAAOA,OAAO,IAAI,GAAG,KAAK,CAAC,QAAQ,QAAQ,CAAC;oBAC5C,MAAMA,OACD,IAAI,GACJ,KAAK,CAAC,QACN,QAAQ,CAAC,oBACT,kBAAkB,CAACZ,CAAAA;wBAChB,MAAMa,QAAQb,EAAE,KAAK,CAAC,SAAS,QAAQ;wBACvC,OAAOc,QAAQC,OAAOF,SAAS,KAAK;4BAChC,aAAa;4BACb,OAAO;4BACP,QAAQ;4BACR,MAAM;wBACV;oBACJ;gBACR;YACA,QAAQG,CAAAA,SAAU;oBAACA,OAAO,GAAG,CAAC;oBAAUA,OAAO,GAAG,CAAC;iBAAQ;QAC/D;QAEAL,KAAK,OAAO,CAAC;YAAE,OAAOT,OAAO,KAAK;YAAE,MAAMA,OAAO,IAAI;QAAC;QAEtD,IAAI,CAAC,SAAS,GAAG;YACb,QAAQ;YACR,MAAM;YACNX;YACAoB;QACJ;IACJ;IAEA,MAAM,kBAAoC;QACtC,MAAM,EAAEM,IAAI,EAAEN,IAAI,EAAED,cAAc,EAAEnB,QAAQ,EAAE,GAAG,IAAI,CAAC,SAAS;QAC/D,IAAI,CAACoB,QAAQ,CAACM,MACV,OAAO;QAGX,MAAMC,OAAO,MAAMP,KAAK,MAAM;QAC9B,IAAI,CAACO,MACD,OAAO;QAGX,IAAID,AAAS,aAATA,MACA,MAAM,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC;YACnC,OAAOC,KAAK,KAAK;YACjB,MAAMA,KAAK,IAAI;YACf,MAAM,IAAI,CAAC,cAAc,CAAC,IAAI;YAC9B,UAAUA,KAAK,QAAQ,IAAIR,kBAAkB;YAC7C,aAAa,EAAE;QACnB;aACG,IAAIO,AAAS,WAATA,QAAmB1B,UAAU;YACpC,MAAMkB,UAAU,IAAI,CAAC,YAAY,CAAC,QAAQ;YAC1C,MAAMP,SAASO,QAAQ,IAAI,CAACT,CAAAA,IAAKA,EAAE,EAAE,KAAKT;YAE1C,MAAM,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC;gBACnC,IAAIA;gBACJ,OAAO2B,KAAK,KAAK;gBACjB,MAAMA,KAAK,IAAI;gBACf,MAAM,IAAI,CAAC,cAAc,CAAC,IAAI;gBAC9B,UAAUhB,QAAQ,YAAY;gBAC9B,aAAaA,QAAQ,eAAe,EAAE;YAC1C;QACJ;QAEA,MAAM,IAAI,CAAC,WAAW;QAEtBK,YAAY;YACR,IAAI,CAAC,SAAS,GAAG;gBAAE,QAAQ;gBAAO,MAAM;YAAK;QACjD;QAEA,OAAO;IACX;IAEA,MAAM,aAAahB,QAAgB,EAAiB;QAChD,MAAMkB,UAAU,IAAI,CAAC,YAAY,CAAC,QAAQ;QAC1C,MAAMP,SAASO,QAAQ,IAAI,CAACT,CAAAA,IAAKA,EAAE,EAAE,KAAKT;QAC1C,MAAM4B,WAAWjB,QAAQ,YAAY;QAErC,IAAI,CAAC,SAAS,GAAG;YACb,QAAQ;YACR,MAAM;YACNX;QACJ;QAEA,MAAM,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAACA;QACvC,MAAM,IAAI,CAAC,WAAW;QAEtBgB,YAAY;YACR,IAAI,CAAC,SAAS,GAAG;gBAAE,QAAQ;gBAAO,MAAM;YAAK;YAC7C,IAAI,CAAC,eAAe,GAAGY;QAC3B;IACJ;IAEA,kBAAwB;QACpB,IAAI,CAAC,SAAS,GAAG;YAAE,QAAQ;YAAO,MAAM;QAAK;IACjD;IAEA,MAAc,cAA6B;QACvCZ,YAAY;YACR,IAAI,CAAC,OAAO,GAAG;QACnB;QAEA,IAAI;YACA,MAAM,IAAI,CAAC,kBAAkB,CAAC,OAAO;QACzC,SAAU;YACNA,YAAY;gBACR,IAAI,CAAC,OAAO,GAAG;YACnB;QACJ;IACJ;IAEQ,YAA+B;QACnC,MAAME,UAAU,IAAI,CAAC,YAAY,CAAC,QAAQ;QAC1C,OAAO,IAAI,CAAC,oBAAoB,CAACA;IACrC;IAEQ,qBAAqBA,OAAiB,EAAqB;QAC/D,MAAMW,UAAU,IAAIC;QAEpB,KAAK,MAAMnB,UAAUO,QACjBW,QAAQ,GAAG,CAAClB,OAAO,EAAE,EAAE;YACnB,IAAIA,OAAO,EAAE;YACb,MAAMA,OAAO,KAAK;YAClB,MAAMA,OAAO,IAAI;YACjB,UAAUA,OAAO,QAAQ;YACzB,UAAU,EAAE;YACZ,4BAA4BA,OAAO,0BAA0B,IAAI;YACjE,sBAAsBA,OAAO,oBAAoB,IAAI;YACrD,oBAAoBA,OAAO,kBAAkB,IAAI;QACrD;QAGJ,MAAMoB,QAA2B,EAAE;QACnC,KAAK,MAAMpB,UAAUO,QAAS;YAC1B,MAAMc,OAAOH,QAAQ,GAAG,CAAClB,OAAO,EAAE;YAClC,IAAIA,OAAO,QAAQ,IAAIkB,QAAQ,GAAG,CAAClB,OAAO,QAAQ,GAC9CkB,QAAQ,GAAG,CAAClB,OAAO,QAAQ,EAAG,QAAQ,CAAC,IAAI,CAACqB;iBAE5CD,MAAM,IAAI,CAACC;QAEnB;QAEA,OAAOD;IACX;IAEQ,WAAW/B,QAAuB,EAAiB;QACvD,IAAI,CAACA,UACD,OAAO;QAGX,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,CAACS,CAAAA,IAAKA,EAAE,EAAE,KAAKT,aAAa;IAChE;IAEQ,SAASA,QAAuB,EAAEiC,KAAwB,EAA0B;QACxF,IAAIjC,AAAa,SAAbA,UACA,OAAO;QAGX,KAAK,MAAMgC,QAAQC,MAAO;YACtB,IAAID,KAAK,EAAE,KAAKhC,UACZ,OAAOgC;YAEX,MAAME,QAAQ,IAAI,CAAC,QAAQ,CAAClC,UAAUgC,KAAK,QAAQ;YACnD,IAAIE,OACA,OAAOA;QAEf;QAEA,OAAO;IACX;AACJ;AAEO,MAAMC,0CAAsBC,oBAAAA,oBAAgC,CAAC;IAChE,gBAAgBlD;IAChB,cAAc;QACVmD;QACAC;QACAC;QACAC;QACAC;QACAC;QACAC;QACAC;QACAC;QACAC;KACH;AACL"}
|
|
1
|
+
{"version":3,"file":"presentation/folderTree/FolderTreePresenter.js","sources":["../../../src/presentation/folderTree/FolderTreePresenter.ts"],"sourcesContent":["import { makeAutoObservable, reaction, runInAction } from \"mobx\";\nimport slugify from \"slugify\";\nimport {\n FolderTreePresenter as Abstraction,\n type IFolderTreeNode,\n type IFolderTreeViewModel,\n type IFolderOperationState\n} from \"./abstractions.js\";\nimport { ROOT_FOLDER } from \"~/constants.js\";\nimport { FoldersCache, FoldersContext } from \"~/features/folders/abstractions.js\";\nimport { ListFoldersUseCase } from \"~/features/folders/listFolders/abstractions.js\";\nimport { ListFoldersByParentIdsUseCase } from \"~/features/folders/listFoldersByParentIds/abstractions.js\";\nimport { CreateFolderUseCase } from \"~/features/folders/createFolder/abstractions.js\";\nimport { UpdateFolderUseCase } from \"~/features/folders/updateFolder/abstractions.js\";\nimport { DeleteFolderUseCase } from \"~/features/folders/deleteFolder/abstractions.js\";\nimport { GetFolderAncestorsUseCase } from \"~/features/folders/getFolderAncestors/abstractions.js\";\nimport { GetFolderLevelPermissionUseCase } from \"~/features/folders/getFolderLevelPermission/abstractions.js\";\nimport { FormModelFactory } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport type { Folder } from \"~/domain/folder/Folder.js\";\nimport type { FolderDto } from \"~/domain/folder/FolderDto.js\";\nimport { FolderDtoMapper } from \"~/domain/folder/FolderDtoMapper.js\";\n\ntype FolderChangeCallback = (folderId: string | null) => void;\n\nclass FolderTreePresenterImpl implements Abstraction.Interface {\n private currentFolderId: string | null = null;\n private loading = false;\n private _loadingNodeIds: string[] = [];\n private operation: IFolderOperationState = { active: false, mode: null };\n private callbacks: Set<FolderChangeCallback> = new Set();\n private disposed = false;\n\n constructor(\n private foldersContext: FoldersContext.Interface,\n private foldersCache: FoldersCache.Interface,\n private listFoldersUseCase: ListFoldersUseCase.Interface,\n private listFoldersByParentIdsUseCase: ListFoldersByParentIdsUseCase.Interface,\n private createFolderUseCase: CreateFolderUseCase.Interface,\n private updateFolderUseCase: UpdateFolderUseCase.Interface,\n private deleteFolderUseCase: DeleteFolderUseCase.Interface,\n private getFolderAncestorsUseCase: GetFolderAncestorsUseCase.Interface,\n private getFolderLevelPermissionUseCase: GetFolderLevelPermissionUseCase.Interface,\n private formModelFactory: FormModelFactory.Interface\n ) {\n makeAutoObservable<FolderTreePresenterImpl, \"callbacks\">(\n this,\n { callbacks: false },\n { autoBind: true }\n );\n\n reaction(\n () => this.currentFolderId,\n folderId => {\n if (!this.disposed) {\n this.callbacks.forEach(cb => cb(folderId));\n }\n }\n );\n\n void this.loadFolders();\n }\n\n get vm(): IFolderTreeViewModel {\n const tree = this.buildTree();\n const allFolders = this.foldersCache.getItems();\n const currentNode = this.findNode(this.currentFolderId, tree);\n const currentFolder = this.findFolder(this.currentFolderId);\n const childNodes = currentNode\n ? currentNode.children\n : tree.filter(n => n.id !== ROOT_FOLDER);\n return {\n folders: allFolders.map(f => FolderDtoMapper.toDTO(f)),\n tree,\n currentFolderId: this.currentFolderId,\n currentFolder: currentFolder ? FolderDtoMapper.toDTO(currentFolder) : null,\n isRootFolder: this.currentFolderId === null,\n currentFolderTitle: currentNode?.name ?? \"All Files\",\n childFolders: childNodes\n .map(n => {\n const folder = allFolders.find(f => f.id === n.id);\n return folder ? FolderDtoMapper.toDTO(folder) : null;\n })\n .filter((f): f is FolderDto => f !== null),\n loading: this.loading,\n loadingNodeIds: this._loadingNodeIds,\n operation: this.operation\n };\n }\n\n selectFolder(folderId: string | null): void {\n const normalized = folderId === ROOT_FOLDER ? null : folderId;\n this.currentFolderId = normalized;\n if (normalized) {\n void this.loadChildFolders([normalized]);\n }\n }\n\n onFolderChange(callback: FolderChangeCallback): () => void {\n this.callbacks.add(callback);\n return () => {\n this.callbacks.delete(callback);\n };\n }\n\n async loadChildFolders(parentIds: string[]): Promise<void> {\n const fetchableIds = parentIds.filter(id => id !== ROOT_FOLDER && id !== \"0\");\n if (fetchableIds.length === 0) {\n return;\n }\n\n runInAction(() => {\n this._loadingNodeIds = fetchableIds;\n });\n\n try {\n await this.listFoldersByParentIdsUseCase.execute(fetchableIds);\n } finally {\n runInAction(() => {\n this._loadingNodeIds = [];\n });\n }\n }\n\n async moveFolder(folderId: string, targetParentId: string | null): Promise<void> {\n const folders = this.foldersCache.getItems();\n const folder = folders.find(f => f.id === folderId);\n if (!folder) {\n return;\n }\n\n await this.updateFolderUseCase.execute({\n id: folderId,\n title: folder.title,\n slug: folder.slug,\n type: this.foldersContext.type,\n parentId: targetParentId,\n permissions: folder.permissions\n });\n\n await this.loadFolders();\n }\n\n canManageStructure(folderId: string): boolean {\n return this.getFolderLevelPermissionUseCase.execute(folderId, \"canManageStructure\");\n }\n\n getAncestorIds(folderId: string): string[] {\n return this.getFolderAncestorsUseCase.execute(folderId).map(f => f.id);\n }\n\n createFolder(parentFolderId?: string): void {\n const form = this.formModelFactory.create({\n fields: fields => ({\n title: fields.text().label(\"Title\").required(\"Title is required\"),\n slug: fields\n .text()\n .label(\"Slug\")\n .required(\"Slug is required\")\n .computedUntilDirty(({ form }) => {\n const title = form.field(\"title\").getValue();\n return slugify(String(title ?? \"\"), {\n replacement: \"-\",\n lower: true,\n remove: /[*#\\?<>_\\{\\}\\[\\]+~.()'\"!:;@]/g,\n trim: false\n });\n }),\n parentId: fields\n .text()\n .label(\"Parent folder\")\n .renderer(\"folderTree\" as any)\n }),\n layout: layout => [layout.row(\"title\"), layout.row(\"slug\"), layout.row(\"parentId\")]\n });\n\n form.setData({ parentId: parentFolderId ?? null });\n\n this.operation = {\n active: true,\n mode: \"create\",\n parentFolderId,\n form\n };\n }\n\n editFolder(folderId: string): void {\n const folders = this.foldersCache.getItems();\n const folder = folders.find(f => f.id === folderId);\n if (!folder) {\n return;\n }\n\n const form = this.formModelFactory.create({\n fields: fields => ({\n title: fields.text().label(\"Name\").required(\"Name is required\"),\n slug: fields\n .text()\n .label(\"Slug\")\n .required(\"Slug is required\")\n .computedUntilDirty(({ form }) => {\n const title = form.field(\"title\").getValue();\n return slugify(String(title ?? \"\"), {\n replacement: \"-\",\n lower: true,\n remove: /[*#\\?<>_\\{\\}\\[\\]+~.()'\"!:;@]/g,\n trim: false\n });\n })\n }),\n layout: layout => [layout.row(\"title\"), layout.row(\"slug\")]\n });\n\n form.setData({ title: folder.title, slug: folder.slug });\n\n this.operation = {\n active: true,\n mode: \"edit\",\n folderId,\n form\n };\n }\n\n async submitOperation(): Promise<boolean> {\n const { mode, form, parentFolderId, folderId } = this.operation;\n if (!form || !mode) {\n return false;\n }\n\n const data = await form.submit<{ title: string; slug: string; parentId?: string | null }>();\n if (!data) {\n return false;\n }\n\n if (mode === \"create\") {\n await this.createFolderUseCase.execute({\n title: data.title,\n slug: data.slug,\n type: this.foldersContext.type,\n parentId: data.parentId ?? parentFolderId ?? null,\n permissions: []\n });\n } else if (mode === \"edit\" && folderId) {\n const folders = this.foldersCache.getItems();\n const folder = folders.find(f => f.id === folderId);\n\n await this.updateFolderUseCase.execute({\n id: folderId,\n title: data.title,\n slug: data.slug,\n type: this.foldersContext.type,\n parentId: folder?.parentId ?? null,\n permissions: folder?.permissions ?? []\n });\n }\n\n runInAction(() => {\n this.operation = { active: false, mode: null };\n });\n\n return true;\n }\n\n async deleteFolder(folderId: string): Promise<void> {\n const folders = this.foldersCache.getItems();\n const folder = folders.find(f => f.id === folderId);\n const parentId = folder?.parentId ?? null;\n\n this.operation = {\n active: true,\n mode: \"delete\",\n folderId\n };\n\n await this.deleteFolderUseCase.execute(folderId);\n await this.loadFolders();\n\n runInAction(() => {\n this.operation = { active: false, mode: null };\n this.currentFolderId = parentId;\n });\n }\n\n cancelOperation(): void {\n this.operation = { active: false, mode: null };\n }\n\n private async loadFolders(): Promise<void> {\n runInAction(() => {\n this.loading = true;\n });\n\n try {\n await this.listFoldersUseCase.execute();\n } finally {\n runInAction(() => {\n this.loading = false;\n });\n }\n }\n\n private buildTree(): IFolderTreeNode[] {\n const folders = this.foldersCache.getItems();\n return this.buildTreeFromFolders(folders);\n }\n\n private buildTreeFromFolders(folders: Folder[]): IFolderTreeNode[] {\n const nodeMap = new Map<string, IFolderTreeNode>();\n\n for (const folder of folders) {\n nodeMap.set(folder.id, {\n id: folder.id,\n name: folder.title,\n slug: folder.slug,\n parentId: folder.parentId,\n children: [],\n hasNonInheritedPermissions: folder.hasNonInheritedPermissions ?? false,\n canManagePermissions: folder.canManagePermissions ?? false,\n canManageStructure: folder.canManageStructure ?? true\n });\n }\n\n const roots: IFolderTreeNode[] = [];\n for (const folder of folders) {\n const node = nodeMap.get(folder.id)!;\n if (folder.parentId && nodeMap.has(folder.parentId)) {\n nodeMap.get(folder.parentId)!.children.push(node);\n } else {\n roots.push(node);\n }\n }\n\n return roots;\n }\n\n private findFolder(folderId: string | null): Folder | null {\n if (!folderId) {\n return null;\n }\n\n return this.foldersCache.getItem(f => f.id === folderId) ?? null;\n }\n\n private findNode(folderId: string | null, nodes: IFolderTreeNode[]): IFolderTreeNode | null {\n if (folderId === null) {\n return null;\n }\n\n for (const node of nodes) {\n if (node.id === folderId) {\n return node;\n }\n const found = this.findNode(folderId, node.children);\n if (found) {\n return found;\n }\n }\n\n return null;\n }\n}\n\nexport const FolderTreePresenter = Abstraction.createImplementation({\n implementation: FolderTreePresenterImpl,\n dependencies: [\n FoldersContext,\n FoldersCache,\n ListFoldersUseCase,\n ListFoldersByParentIdsUseCase,\n CreateFolderUseCase,\n UpdateFolderUseCase,\n DeleteFolderUseCase,\n GetFolderAncestorsUseCase,\n GetFolderLevelPermissionUseCase,\n FormModelFactory\n ]\n});\n"],"names":["FolderTreePresenterImpl","foldersContext","foldersCache","listFoldersUseCase","listFoldersByParentIdsUseCase","createFolderUseCase","updateFolderUseCase","deleteFolderUseCase","getFolderAncestorsUseCase","getFolderLevelPermissionUseCase","formModelFactory","Set","makeAutoObservable","reaction","folderId","cb","tree","allFolders","currentNode","currentFolder","childNodes","n","ROOT_FOLDER","f","FolderDtoMapper","folder","normalized","callback","parentIds","fetchableIds","id","runInAction","targetParentId","folders","parentFolderId","form","fields","title","slugify","String","layout","mode","data","parentId","nodeMap","Map","roots","node","nodes","found","FolderTreePresenter","Abstraction","FoldersContext","FoldersCache","ListFoldersUseCase","ListFoldersByParentIdsUseCase","CreateFolderUseCase","UpdateFolderUseCase","DeleteFolderUseCase","GetFolderAncestorsUseCase","GetFolderLevelPermissionUseCase","FormModelFactory"],"mappings":"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"}
|
|
@@ -107,6 +107,7 @@ function createMockFormModel() {
|
|
|
107
107
|
isDirty: false,
|
|
108
108
|
isValid: null,
|
|
109
109
|
errors: [],
|
|
110
|
+
hasErrors: false,
|
|
110
111
|
submitCount: 0,
|
|
111
112
|
focusField: vi.fn(),
|
|
112
113
|
getData: vi.fn(()=>({})),
|
|
@@ -114,7 +115,8 @@ function createMockFormModel() {
|
|
|
114
115
|
},
|
|
115
116
|
getFieldBuilders: vi.fn(()=>[]),
|
|
116
117
|
resolveChildLayout: vi.fn(()=>[]),
|
|
117
|
-
registry: {}
|
|
118
|
+
registry: {},
|
|
119
|
+
traverse: vi.fn()
|
|
118
120
|
};
|
|
119
121
|
return form;
|
|
120
122
|
}
|
|
@@ -400,7 +402,7 @@ describe("FolderTreePresenter", ()=>{
|
|
|
400
402
|
presenter.createFolder("root-1");
|
|
401
403
|
await presenter.submitOperation();
|
|
402
404
|
expect(createFolderUseCase.execute).toHaveBeenCalledTimes(1);
|
|
403
|
-
expect(listFolders.execute).toHaveBeenCalledTimes(
|
|
405
|
+
expect(listFolders.execute).toHaveBeenCalledTimes(1);
|
|
404
406
|
});
|
|
405
407
|
});
|
|
406
408
|
describe("editFolder", ()=>{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presentation/folderTree/FolderTreePresenter.test.js","sources":["../../../src/presentation/folderTree/FolderTreePresenter.test.ts"],"sourcesContent":["import { describe, it, expect, vi } from \"vitest\";\nimport { Container } from \"@webiny/di\";\nimport { FolderTreePresenter as Abstraction } from \"./abstractions.js\";\nimport { FolderTreePresenterFeature } from \"./feature.js\";\nimport { FoldersCache, FoldersContext } from \"~/features/folders/abstractions.js\";\nimport { ListFoldersUseCase } from \"~/features/folders/listFolders/abstractions.js\";\nimport { CreateFolderUseCase } from \"~/features/folders/createFolder/abstractions.js\";\nimport { UpdateFolderUseCase } from \"~/features/folders/updateFolder/abstractions.js\";\nimport { DeleteFolderUseCase } from \"~/features/folders/deleteFolder/abstractions.js\";\nimport { ListFoldersByParentIdsUseCase } from \"~/features/folders/listFoldersByParentIds/abstractions.js\";\nimport { GetFolderAncestorsUseCase } from \"~/features/folders/getFolderAncestors/abstractions.js\";\nimport { GetFolderLevelPermissionUseCase } from \"~/features/folders/getFolderLevelPermission/abstractions.js\";\nimport { FormModelFactory } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport { ListCache } from \"~/features/folders/cache/index.js\";\nimport { Folder } from \"~/domain/folder/Folder.js\";\nimport type {\n IFormModel,\n IFormModelConfig,\n IField\n} from \"@webiny/app-admin/features/formModel/abstractions.js\";\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nconst TYPE = \"FmFile\";\n\nfunction createFolder(data: {\n id: string;\n title: string;\n slug: string;\n parentId: string | null;\n}): Folder {\n return Folder.create({\n ...data,\n type: TYPE,\n permissions: []\n });\n}\n\nfunction createFlatFolders(): Folder[] {\n return [\n createFolder({ id: \"root-1\", title: \"Documents\", slug: \"documents\", parentId: null }),\n createFolder({ id: \"root-2\", title: \"Images\", slug: \"images\", parentId: null }),\n createFolder({ id: \"child-1\", title: \"Invoices\", slug: \"invoices\", parentId: \"root-1\" }),\n createFolder({\n id: \"child-2\",\n title: \"Contracts\",\n slug: \"contracts\",\n parentId: \"root-1\"\n }),\n createFolder({\n id: \"grandchild-1\",\n title: \"2024\",\n slug: \"2024\",\n parentId: \"child-1\"\n })\n ];\n}\n\n// ---------------------------------------------------------------------------\n// Mock FormModel\n// ---------------------------------------------------------------------------\n\nfunction createMockField(): IField {\n let value: unknown = undefined;\n return {\n getValue: vi.fn(() => value),\n setValue: vi.fn((v: unknown) => {\n value = v;\n }),\n setDisabled: vi.fn(),\n setVisible: vi.fn(),\n remove: vi.fn(),\n addBeforeChange: vi.fn(),\n addAfterChange: vi.fn(),\n addAfterSetValue: vi.fn(),\n addOnBlur: vi.fn(),\n blur: vi.fn(),\n as: vi.fn()\n } as unknown as IField;\n}\n\nfunction createMockFormModel(): IFormModel {\n const fields = new Map<string, IField>();\n let data: Record<string, unknown> = {};\n\n const form: IFormModel = {\n field(name: string) {\n if (!fields.has(name)) {\n fields.set(name, createMockField());\n }\n return fields.get(name)!;\n },\n fields: vi.fn(),\n layout: vi.fn() as IFormModel[\"layout\"],\n setLayout: vi.fn(),\n addRule: vi.fn(),\n getData: vi.fn(() => data),\n setData: vi.fn((d: Record<string, unknown>) => {\n data = d;\n }),\n reset: vi.fn(),\n validate: vi.fn(async () => true),\n submit: vi.fn(async () => data) as IFormModel[\"submit\"],\n evaluateRules: vi.fn(() => ({ visible: true, disabled: false })),\n focusField: vi.fn(),\n isDirty: false,\n isValid: null,\n submitted: false,\n submitCount: 0,\n errors: [],\n vm: {\n layout: [],\n isDirty: false,\n isValid: null,\n errors: [],\n submitCount: 0,\n focusField: vi.fn(),\n getData: vi.fn(() => ({})),\n setData: vi.fn()\n },\n getFieldBuilders: vi.fn(() => []),\n resolveChildLayout: vi.fn(() => []),\n registry: {} as IFormModel[\"registry\"]\n };\n\n return form;\n}\n\n// ---------------------------------------------------------------------------\n// Mock use cases\n// ---------------------------------------------------------------------------\n\nclass MockListFoldersUseCase implements ListFoldersUseCase.Interface {\n execute = vi.fn(async () => {});\n}\n\nclass MockCreateFolderUseCase implements CreateFolderUseCase.Interface {\n execute = vi.fn(async () => {});\n}\n\nclass MockUpdateFolderUseCase implements UpdateFolderUseCase.Interface {\n execute = vi.fn(async () => {});\n}\n\nclass MockDeleteFolderUseCase implements DeleteFolderUseCase.Interface {\n execute = vi.fn(async () => {});\n}\n\nclass MockFormModelFactory {\n create = vi.fn((_config: IFormModelConfig) => createMockFormModel());\n}\n\n// ---------------------------------------------------------------------------\n// Setup\n// ---------------------------------------------------------------------------\n\nfunction createTestPresenter(folders: Folder[] = []) {\n const container = new Container();\n const foldersCache = new ListCache<Folder>();\n const listFolders = new MockListFoldersUseCase();\n const createFolderUseCase = new MockCreateFolderUseCase();\n const updateFolderUseCase = new MockUpdateFolderUseCase();\n const deleteFolderUseCase = new MockDeleteFolderUseCase();\n const formModelFactory = new MockFormModelFactory();\n\n // Pre-populate cache.\n if (folders.length > 0) {\n foldersCache.addItems(folders);\n }\n\n container.registerInstance(FoldersContext, { type: TYPE });\n container.registerInstance(FoldersCache, foldersCache);\n container.registerInstance(ListFoldersUseCase, listFolders);\n container.registerInstance(CreateFolderUseCase, createFolderUseCase);\n container.registerInstance(UpdateFolderUseCase, updateFolderUseCase);\n container.registerInstance(DeleteFolderUseCase, deleteFolderUseCase);\n container.registerInstance(ListFoldersByParentIdsUseCase, {\n execute: vi.fn().mockResolvedValue(undefined)\n });\n container.registerInstance(GetFolderAncestorsUseCase, {\n execute: vi.fn().mockReturnValue([])\n });\n container.registerInstance(GetFolderLevelPermissionUseCase, {\n execute: vi.fn().mockReturnValue(true)\n });\n container.registerInstance(\n FormModelFactory,\n formModelFactory as unknown as FormModelFactory.Interface\n );\n\n FolderTreePresenterFeature.register(container);\n\n const presenter = container.resolve(Abstraction);\n\n return {\n presenter,\n foldersCache,\n listFolders,\n createFolderUseCase,\n updateFolderUseCase,\n deleteFolderUseCase,\n formModelFactory\n };\n}\n\n// ---------------------------------------------------------------------------\n// Tests\n// ---------------------------------------------------------------------------\n\ndescribe(\"FolderTreePresenter\", () => {\n // -------------------------------------------------------------------\n // Scoped initialization via FoldersContext\n // -------------------------------------------------------------------\n\n describe(\"scoped initialization\", () => {\n it(\"should load folders on construction via ListFoldersUseCase\", () => {\n const { listFolders } = createTestPresenter();\n expect(listFolders.execute).toHaveBeenCalledTimes(1);\n });\n\n it(\"should not require an init(type) method — type comes from FoldersContext\", () => {\n const { presenter } = createTestPresenter();\n // The presenter has no init method — it reads type from injected FoldersContext.\n expect((presenter as any).init).toBeUndefined();\n });\n\n it(\"should start with loading=true then resolve to false\", async () => {\n const { presenter } = createTestPresenter();\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n });\n });\n\n // -------------------------------------------------------------------\n // Tree computation from flat folder list\n // -------------------------------------------------------------------\n\n describe(\"tree computation\", () => {\n it(\"should build a nested tree from a flat folder list\", async () => {\n const folders = createFlatFolders();\n const { presenter } = createTestPresenter(folders);\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n const { tree } = presenter.vm;\n\n // Two root nodes.\n expect(tree).toHaveLength(2);\n expect(tree[0].name).toBe(\"Documents\");\n expect(tree[1].name).toBe(\"Images\");\n\n // Documents has 2 children.\n expect(tree[0].children).toHaveLength(2);\n expect(tree[0].children[0].name).toBe(\"Invoices\");\n expect(tree[0].children[1].name).toBe(\"Contracts\");\n\n // Invoices has 1 grandchild.\n expect(tree[0].children[0].children).toHaveLength(1);\n expect(tree[0].children[0].children[0].name).toBe(\"2024\");\n\n // Images has no children.\n expect(tree[1].children).toHaveLength(0);\n });\n\n it(\"should return an empty tree when cache is empty\", async () => {\n const { presenter } = createTestPresenter([]);\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n expect(presenter.vm.tree).toEqual([]);\n });\n\n it(\"should treat folders with unknown parentId as root nodes\", async () => {\n const folders = [\n createFolder({\n id: \"orphan\",\n title: \"Orphan\",\n slug: \"orphan\",\n parentId: \"non-existent\"\n })\n ];\n const { presenter } = createTestPresenter(folders);\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n expect(presenter.vm.tree).toHaveLength(1);\n expect(presenter.vm.tree[0].name).toBe(\"Orphan\");\n });\n\n it(\"should map folder properties correctly to tree nodes\", async () => {\n const folders = [\n createFolder({\n id: \"f1\",\n title: \"My Folder\",\n slug: \"my-folder\",\n parentId: null\n })\n ];\n const { presenter } = createTestPresenter(folders);\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n const node = presenter.vm.tree[0];\n expect(node.id).toBe(\"f1\");\n expect(node.name).toBe(\"My Folder\");\n expect(node.slug).toBe(\"my-folder\");\n expect(node.parentId).toBeNull();\n expect(node.children).toEqual([]);\n });\n });\n\n // -------------------------------------------------------------------\n // selectFolder and onFolderChange\n // -------------------------------------------------------------------\n\n describe(\"selectFolder\", () => {\n it(\"should update currentFolderId\", async () => {\n const folders = createFlatFolders();\n const { presenter } = createTestPresenter(folders);\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n expect(presenter.vm.currentFolderId).toBeNull();\n\n presenter.selectFolder(\"root-1\");\n expect(presenter.vm.currentFolderId).toBe(\"root-1\");\n });\n\n it(\"should update currentFolder to the matching folder\", async () => {\n const folders = createFlatFolders();\n const { presenter } = createTestPresenter(folders);\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n presenter.selectFolder(\"child-1\");\n expect(presenter.vm.currentFolder).not.toBeNull();\n expect(presenter.vm.currentFolder!.id).toBe(\"child-1\");\n expect(presenter.vm.currentFolder!.title).toBe(\"Invoices\");\n });\n\n it(\"should set currentFolder to null when selecting root (null)\", async () => {\n const folders = createFlatFolders();\n const { presenter } = createTestPresenter(folders);\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n presenter.selectFolder(\"root-1\");\n expect(presenter.vm.currentFolder).not.toBeNull();\n\n presenter.selectFolder(null);\n expect(presenter.vm.currentFolderId).toBeNull();\n expect(presenter.vm.currentFolder).toBeNull();\n });\n\n it(\"should find deeply nested folders as currentFolder\", async () => {\n const folders = createFlatFolders();\n const { presenter } = createTestPresenter(folders);\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n presenter.selectFolder(\"grandchild-1\");\n expect(presenter.vm.currentFolder).not.toBeNull();\n expect(presenter.vm.currentFolder!.title).toBe(\"2024\");\n });\n });\n\n describe(\"onFolderChange\", () => {\n it(\"should fire callbacks when currentFolderId changes\", async () => {\n const folders = createFlatFolders();\n const { presenter } = createTestPresenter(folders);\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n const callback = vi.fn();\n presenter.onFolderChange(callback);\n\n presenter.selectFolder(\"root-1\");\n\n // MobX reaction fires synchronously for simple observable changes.\n expect(callback).toHaveBeenCalledTimes(1);\n expect(callback).toHaveBeenCalledWith(\"root-1\");\n });\n\n it(\"should fire callback with null when navigating to root\", async () => {\n const folders = createFlatFolders();\n const { presenter } = createTestPresenter(folders);\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n presenter.selectFolder(\"root-1\");\n\n const callback = vi.fn();\n presenter.onFolderChange(callback);\n\n presenter.selectFolder(null);\n expect(callback).toHaveBeenCalledWith(null);\n });\n\n it(\"should support multiple callbacks\", async () => {\n const { presenter } = createTestPresenter(createFlatFolders());\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n const cb1 = vi.fn();\n const cb2 = vi.fn();\n presenter.onFolderChange(cb1);\n presenter.onFolderChange(cb2);\n\n presenter.selectFolder(\"root-2\");\n\n expect(cb1).toHaveBeenCalledWith(\"root-2\");\n expect(cb2).toHaveBeenCalledWith(\"root-2\");\n });\n\n it(\"should return an unsubscribe function that stops callbacks\", async () => {\n const { presenter } = createTestPresenter(createFlatFolders());\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n const callback = vi.fn();\n const unsubscribe = presenter.onFolderChange(callback);\n\n presenter.selectFolder(\"root-1\");\n expect(callback).toHaveBeenCalledTimes(1);\n\n unsubscribe();\n\n presenter.selectFolder(\"root-2\");\n // Should not have been called again after unsubscribe.\n expect(callback).toHaveBeenCalledTimes(1);\n });\n\n it(\"should not fire callback when selecting the same folder\", async () => {\n const { presenter } = createTestPresenter(createFlatFolders());\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n presenter.selectFolder(\"root-1\");\n\n const callback = vi.fn();\n presenter.onFolderChange(callback);\n\n // Select the same folder again.\n presenter.selectFolder(\"root-1\");\n expect(callback).not.toHaveBeenCalled();\n });\n });\n\n // -------------------------------------------------------------------\n // createFolder / editFolder — operation state with FormModel\n // -------------------------------------------------------------------\n\n describe(\"createFolder\", () => {\n it(\"should set operation state with mode 'create' and a FormModel\", async () => {\n const { presenter, formModelFactory } = createTestPresenter(createFlatFolders());\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n presenter.createFolder(\"root-1\");\n\n expect(presenter.vm.operation.active).toBe(true);\n expect(presenter.vm.operation.mode).toBe(\"create\");\n expect(presenter.vm.operation.parentFolderId).toBe(\"root-1\");\n expect(presenter.vm.operation.form).toBeDefined();\n expect(formModelFactory.create).toHaveBeenCalledTimes(1);\n });\n\n it(\"should set parentFolderId to undefined when creating at root\", async () => {\n const { presenter } = createTestPresenter(createFlatFolders());\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n presenter.createFolder();\n\n expect(presenter.vm.operation.active).toBe(true);\n expect(presenter.vm.operation.mode).toBe(\"create\");\n expect(presenter.vm.operation.parentFolderId).toBeUndefined();\n });\n\n it(\"should wire submitOperation to CreateFolderUseCase\", async () => {\n const { presenter, createFolderUseCase, listFolders } =\n createTestPresenter(createFlatFolders());\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n presenter.createFolder(\"root-1\");\n\n await presenter.submitOperation();\n\n expect(createFolderUseCase.execute).toHaveBeenCalledTimes(1);\n expect(listFolders.execute).toHaveBeenCalledTimes(2);\n });\n });\n\n describe(\"editFolder\", () => {\n it(\"should set operation state with mode 'edit' and a FormModel\", async () => {\n const { presenter, formModelFactory } = createTestPresenter(createFlatFolders());\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n presenter.editFolder(\"root-1\");\n\n expect(presenter.vm.operation.active).toBe(true);\n expect(presenter.vm.operation.mode).toBe(\"edit\");\n expect(presenter.vm.operation.folderId).toBe(\"root-1\");\n expect(presenter.vm.operation.form).toBeDefined();\n expect(formModelFactory.create).toHaveBeenCalledTimes(1);\n });\n\n it(\"should pre-populate form with existing folder data\", async () => {\n const mockForm = createMockFormModel();\n const { presenter, formModelFactory } = createTestPresenter(createFlatFolders());\n formModelFactory.create.mockReturnValue(mockForm);\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n presenter.editFolder(\"root-1\");\n\n expect(mockForm.setData).toHaveBeenCalledWith({\n title: \"Documents\",\n slug: \"documents\"\n });\n });\n\n it(\"should do nothing when editing a non-existent folder\", async () => {\n const { presenter, formModelFactory } = createTestPresenter(createFlatFolders());\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n presenter.editFolder(\"non-existent\");\n\n expect(presenter.vm.operation.active).toBe(false);\n expect(presenter.vm.operation.mode).toBeNull();\n expect(formModelFactory.create).not.toHaveBeenCalled();\n });\n });\n\n // -------------------------------------------------------------------\n // deleteFolder — navigates to parent and updates tree\n // -------------------------------------------------------------------\n\n describe(\"deleteFolder\", () => {\n it(\"should call DeleteFolderUseCase with the folder id\", async () => {\n const { presenter, deleteFolderUseCase } = createTestPresenter(createFlatFolders());\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n await presenter.deleteFolder(\"child-1\");\n\n expect(deleteFolderUseCase.execute).toHaveBeenCalledWith(\"child-1\");\n });\n\n it(\"should set operation state with mode 'delete' during deletion\", async () => {\n const { presenter, deleteFolderUseCase } = createTestPresenter(createFlatFolders());\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n // Make delete hang so we can inspect intermediate state.\n let resolveDelete!: () => void;\n deleteFolderUseCase.execute.mockReturnValueOnce(\n new Promise<void>(resolve => {\n resolveDelete = resolve;\n })\n );\n\n const deletePromise = presenter.deleteFolder(\"child-1\");\n\n expect(presenter.vm.operation.active).toBe(true);\n expect(presenter.vm.operation.mode).toBe(\"delete\");\n expect(presenter.vm.operation.folderId).toBe(\"child-1\");\n\n resolveDelete();\n await deletePromise;\n\n // After completion, operation should be reset.\n expect(presenter.vm.operation.active).toBe(false);\n expect(presenter.vm.operation.mode).toBeNull();\n });\n\n it(\"should navigate to parent folder after deletion\", async () => {\n const { presenter } = createTestPresenter(createFlatFolders());\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n // child-1 has parentId \"root-1\".\n await presenter.deleteFolder(\"child-1\");\n\n expect(presenter.vm.currentFolderId).toBe(\"root-1\");\n });\n\n it(\"should navigate to root (null) when deleting a root folder\", async () => {\n const { presenter } = createTestPresenter(createFlatFolders());\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n // root-1 has parentId null.\n await presenter.deleteFolder(\"root-1\");\n\n expect(presenter.vm.currentFolderId).toBeNull();\n });\n\n it(\"should refresh the folder list after deletion\", async () => {\n const { presenter, listFolders } = createTestPresenter(createFlatFolders());\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n await presenter.deleteFolder(\"child-1\");\n\n // Initial load + refresh after delete.\n expect(listFolders.execute).toHaveBeenCalledTimes(2);\n });\n\n it(\"should fire onFolderChange callback when navigating to parent after delete\", async () => {\n const { presenter } = createTestPresenter(createFlatFolders());\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n const callback = vi.fn();\n presenter.onFolderChange(callback);\n\n // child-1 has parentId \"root-1\".\n await presenter.deleteFolder(\"child-1\");\n\n expect(callback).toHaveBeenCalledWith(\"root-1\");\n });\n });\n\n // -------------------------------------------------------------------\n // Operation state reset\n // -------------------------------------------------------------------\n\n describe(\"operation state\", () => {\n it(\"should start with inactive operation state\", async () => {\n const { presenter } = createTestPresenter();\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n expect(presenter.vm.operation.active).toBe(false);\n expect(presenter.vm.operation.mode).toBeNull();\n });\n });\n});\n"],"names":["TYPE","createFolder","data","Folder","createFlatFolders","createMockField","value","vi","v","createMockFormModel","fields","Map","form","name","d","MockListFoldersUseCase","MockCreateFolderUseCase","MockUpdateFolderUseCase","MockDeleteFolderUseCase","MockFormModelFactory","_config","createTestPresenter","folders","container","Container","foldersCache","ListCache","listFolders","createFolderUseCase","updateFolderUseCase","deleteFolderUseCase","formModelFactory","FoldersContext","FoldersCache","ListFoldersUseCase","CreateFolderUseCase","UpdateFolderUseCase","DeleteFolderUseCase","ListFoldersByParentIdsUseCase","undefined","GetFolderAncestorsUseCase","GetFolderLevelPermissionUseCase","FormModelFactory","FolderTreePresenterFeature","presenter","Abstraction","describe","it","expect","tree","node","callback","cb1","cb2","unsubscribe","mockForm","resolveDelete","Promise","resolve","deletePromise"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"presentation/folderTree/FolderTreePresenter.test.js","sources":["../../../src/presentation/folderTree/FolderTreePresenter.test.ts"],"sourcesContent":["import { describe, it, expect, vi } from \"vitest\";\nimport { Container } from \"@webiny/di\";\nimport { FolderTreePresenter as Abstraction } from \"./abstractions.js\";\nimport { FolderTreePresenterFeature } from \"./feature.js\";\nimport { FoldersCache, FoldersContext } from \"~/features/folders/abstractions.js\";\nimport { ListFoldersUseCase } from \"~/features/folders/listFolders/abstractions.js\";\nimport { CreateFolderUseCase } from \"~/features/folders/createFolder/abstractions.js\";\nimport { UpdateFolderUseCase } from \"~/features/folders/updateFolder/abstractions.js\";\nimport { DeleteFolderUseCase } from \"~/features/folders/deleteFolder/abstractions.js\";\nimport { ListFoldersByParentIdsUseCase } from \"~/features/folders/listFoldersByParentIds/abstractions.js\";\nimport { GetFolderAncestorsUseCase } from \"~/features/folders/getFolderAncestors/abstractions.js\";\nimport { GetFolderLevelPermissionUseCase } from \"~/features/folders/getFolderLevelPermission/abstractions.js\";\nimport { FormModelFactory } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport { ListCache } from \"~/features/folders/cache/index.js\";\nimport { Folder } from \"~/domain/folder/Folder.js\";\nimport type {\n IFormModel,\n IFormModelConfig,\n IField\n} from \"@webiny/app-admin/features/formModel/abstractions.js\";\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nconst TYPE = \"FmFile\";\n\nfunction createFolder(data: {\n id: string;\n title: string;\n slug: string;\n parentId: string | null;\n}): Folder {\n return Folder.create({\n ...data,\n type: TYPE,\n permissions: []\n });\n}\n\nfunction createFlatFolders(): Folder[] {\n return [\n createFolder({ id: \"root-1\", title: \"Documents\", slug: \"documents\", parentId: null }),\n createFolder({ id: \"root-2\", title: \"Images\", slug: \"images\", parentId: null }),\n createFolder({ id: \"child-1\", title: \"Invoices\", slug: \"invoices\", parentId: \"root-1\" }),\n createFolder({\n id: \"child-2\",\n title: \"Contracts\",\n slug: \"contracts\",\n parentId: \"root-1\"\n }),\n createFolder({\n id: \"grandchild-1\",\n title: \"2024\",\n slug: \"2024\",\n parentId: \"child-1\"\n })\n ];\n}\n\n// ---------------------------------------------------------------------------\n// Mock FormModel\n// ---------------------------------------------------------------------------\n\nfunction createMockField(): IField {\n let value: unknown = undefined;\n return {\n getValue: vi.fn(() => value),\n setValue: vi.fn((v: unknown) => {\n value = v;\n }),\n setDisabled: vi.fn(),\n setVisible: vi.fn(),\n remove: vi.fn(),\n addBeforeChange: vi.fn(),\n addAfterChange: vi.fn(),\n addAfterSetValue: vi.fn(),\n addOnBlur: vi.fn(),\n blur: vi.fn(),\n as: vi.fn()\n } as unknown as IField;\n}\n\nfunction createMockFormModel(): IFormModel {\n const fields = new Map<string, IField>();\n let data: Record<string, unknown> = {};\n\n const form: IFormModel = {\n field(name: string) {\n if (!fields.has(name)) {\n fields.set(name, createMockField());\n }\n return fields.get(name)!;\n },\n fields: vi.fn(),\n layout: vi.fn() as IFormModel[\"layout\"],\n setLayout: vi.fn(),\n addRule: vi.fn(),\n getData: vi.fn(() => data),\n setData: vi.fn((d: Record<string, unknown>) => {\n data = d;\n }),\n reset: vi.fn(),\n validate: vi.fn(async () => true),\n submit: vi.fn(async () => data) as IFormModel[\"submit\"],\n evaluateRules: vi.fn(() => ({ visible: true, disabled: false })),\n focusField: vi.fn(),\n isDirty: false,\n isValid: null,\n submitted: false,\n submitCount: 0,\n errors: [],\n vm: {\n layout: [],\n isDirty: false,\n isValid: null,\n errors: [],\n hasErrors: false,\n submitCount: 0,\n focusField: vi.fn(),\n getData: vi.fn(() => ({})),\n setData: vi.fn()\n },\n getFieldBuilders: vi.fn(() => []),\n resolveChildLayout: vi.fn(() => []),\n registry: {} as IFormModel[\"registry\"],\n traverse: vi.fn()\n };\n\n return form;\n}\n\n// ---------------------------------------------------------------------------\n// Mock use cases\n// ---------------------------------------------------------------------------\n\nclass MockListFoldersUseCase implements ListFoldersUseCase.Interface {\n execute = vi.fn(async () => {});\n}\n\nclass MockCreateFolderUseCase implements CreateFolderUseCase.Interface {\n execute = vi.fn(async () => {});\n}\n\nclass MockUpdateFolderUseCase implements UpdateFolderUseCase.Interface {\n execute = vi.fn(async () => {});\n}\n\nclass MockDeleteFolderUseCase implements DeleteFolderUseCase.Interface {\n execute = vi.fn(async () => {});\n}\n\nclass MockFormModelFactory {\n create = vi.fn((_config: IFormModelConfig) => createMockFormModel());\n}\n\n// ---------------------------------------------------------------------------\n// Setup\n// ---------------------------------------------------------------------------\n\nfunction createTestPresenter(folders: Folder[] = []) {\n const container = new Container();\n const foldersCache = new ListCache<Folder>();\n const listFolders = new MockListFoldersUseCase();\n const createFolderUseCase = new MockCreateFolderUseCase();\n const updateFolderUseCase = new MockUpdateFolderUseCase();\n const deleteFolderUseCase = new MockDeleteFolderUseCase();\n const formModelFactory = new MockFormModelFactory();\n\n // Pre-populate cache.\n if (folders.length > 0) {\n foldersCache.addItems(folders);\n }\n\n container.registerInstance(FoldersContext, { type: TYPE });\n container.registerInstance(FoldersCache, foldersCache);\n container.registerInstance(ListFoldersUseCase, listFolders);\n container.registerInstance(CreateFolderUseCase, createFolderUseCase);\n container.registerInstance(UpdateFolderUseCase, updateFolderUseCase);\n container.registerInstance(DeleteFolderUseCase, deleteFolderUseCase);\n container.registerInstance(ListFoldersByParentIdsUseCase, {\n execute: vi.fn().mockResolvedValue(undefined)\n });\n container.registerInstance(GetFolderAncestorsUseCase, {\n execute: vi.fn().mockReturnValue([])\n });\n container.registerInstance(GetFolderLevelPermissionUseCase, {\n execute: vi.fn().mockReturnValue(true)\n });\n container.registerInstance(\n FormModelFactory,\n formModelFactory as unknown as FormModelFactory.Interface\n );\n\n FolderTreePresenterFeature.register(container);\n\n const presenter = container.resolve(Abstraction);\n\n return {\n presenter,\n foldersCache,\n listFolders,\n createFolderUseCase,\n updateFolderUseCase,\n deleteFolderUseCase,\n formModelFactory\n };\n}\n\n// ---------------------------------------------------------------------------\n// Tests\n// ---------------------------------------------------------------------------\n\ndescribe(\"FolderTreePresenter\", () => {\n // -------------------------------------------------------------------\n // Scoped initialization via FoldersContext\n // -------------------------------------------------------------------\n\n describe(\"scoped initialization\", () => {\n it(\"should load folders on construction via ListFoldersUseCase\", () => {\n const { listFolders } = createTestPresenter();\n expect(listFolders.execute).toHaveBeenCalledTimes(1);\n });\n\n it(\"should not require an init(type) method — type comes from FoldersContext\", () => {\n const { presenter } = createTestPresenter();\n // The presenter has no init method — it reads type from injected FoldersContext.\n expect((presenter as any).init).toBeUndefined();\n });\n\n it(\"should start with loading=true then resolve to false\", async () => {\n const { presenter } = createTestPresenter();\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n });\n });\n\n // -------------------------------------------------------------------\n // Tree computation from flat folder list\n // -------------------------------------------------------------------\n\n describe(\"tree computation\", () => {\n it(\"should build a nested tree from a flat folder list\", async () => {\n const folders = createFlatFolders();\n const { presenter } = createTestPresenter(folders);\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n const { tree } = presenter.vm;\n\n // Two root nodes.\n expect(tree).toHaveLength(2);\n expect(tree[0].name).toBe(\"Documents\");\n expect(tree[1].name).toBe(\"Images\");\n\n // Documents has 2 children.\n expect(tree[0].children).toHaveLength(2);\n expect(tree[0].children[0].name).toBe(\"Invoices\");\n expect(tree[0].children[1].name).toBe(\"Contracts\");\n\n // Invoices has 1 grandchild.\n expect(tree[0].children[0].children).toHaveLength(1);\n expect(tree[0].children[0].children[0].name).toBe(\"2024\");\n\n // Images has no children.\n expect(tree[1].children).toHaveLength(0);\n });\n\n it(\"should return an empty tree when cache is empty\", async () => {\n const { presenter } = createTestPresenter([]);\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n expect(presenter.vm.tree).toEqual([]);\n });\n\n it(\"should treat folders with unknown parentId as root nodes\", async () => {\n const folders = [\n createFolder({\n id: \"orphan\",\n title: \"Orphan\",\n slug: \"orphan\",\n parentId: \"non-existent\"\n })\n ];\n const { presenter } = createTestPresenter(folders);\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n expect(presenter.vm.tree).toHaveLength(1);\n expect(presenter.vm.tree[0].name).toBe(\"Orphan\");\n });\n\n it(\"should map folder properties correctly to tree nodes\", async () => {\n const folders = [\n createFolder({\n id: \"f1\",\n title: \"My Folder\",\n slug: \"my-folder\",\n parentId: null\n })\n ];\n const { presenter } = createTestPresenter(folders);\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n const node = presenter.vm.tree[0];\n expect(node.id).toBe(\"f1\");\n expect(node.name).toBe(\"My Folder\");\n expect(node.slug).toBe(\"my-folder\");\n expect(node.parentId).toBeNull();\n expect(node.children).toEqual([]);\n });\n });\n\n // -------------------------------------------------------------------\n // selectFolder and onFolderChange\n // -------------------------------------------------------------------\n\n describe(\"selectFolder\", () => {\n it(\"should update currentFolderId\", async () => {\n const folders = createFlatFolders();\n const { presenter } = createTestPresenter(folders);\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n expect(presenter.vm.currentFolderId).toBeNull();\n\n presenter.selectFolder(\"root-1\");\n expect(presenter.vm.currentFolderId).toBe(\"root-1\");\n });\n\n it(\"should update currentFolder to the matching folder\", async () => {\n const folders = createFlatFolders();\n const { presenter } = createTestPresenter(folders);\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n presenter.selectFolder(\"child-1\");\n expect(presenter.vm.currentFolder).not.toBeNull();\n expect(presenter.vm.currentFolder!.id).toBe(\"child-1\");\n expect(presenter.vm.currentFolder!.title).toBe(\"Invoices\");\n });\n\n it(\"should set currentFolder to null when selecting root (null)\", async () => {\n const folders = createFlatFolders();\n const { presenter } = createTestPresenter(folders);\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n presenter.selectFolder(\"root-1\");\n expect(presenter.vm.currentFolder).not.toBeNull();\n\n presenter.selectFolder(null);\n expect(presenter.vm.currentFolderId).toBeNull();\n expect(presenter.vm.currentFolder).toBeNull();\n });\n\n it(\"should find deeply nested folders as currentFolder\", async () => {\n const folders = createFlatFolders();\n const { presenter } = createTestPresenter(folders);\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n presenter.selectFolder(\"grandchild-1\");\n expect(presenter.vm.currentFolder).not.toBeNull();\n expect(presenter.vm.currentFolder!.title).toBe(\"2024\");\n });\n });\n\n describe(\"onFolderChange\", () => {\n it(\"should fire callbacks when currentFolderId changes\", async () => {\n const folders = createFlatFolders();\n const { presenter } = createTestPresenter(folders);\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n const callback = vi.fn();\n presenter.onFolderChange(callback);\n\n presenter.selectFolder(\"root-1\");\n\n // MobX reaction fires synchronously for simple observable changes.\n expect(callback).toHaveBeenCalledTimes(1);\n expect(callback).toHaveBeenCalledWith(\"root-1\");\n });\n\n it(\"should fire callback with null when navigating to root\", async () => {\n const folders = createFlatFolders();\n const { presenter } = createTestPresenter(folders);\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n presenter.selectFolder(\"root-1\");\n\n const callback = vi.fn();\n presenter.onFolderChange(callback);\n\n presenter.selectFolder(null);\n expect(callback).toHaveBeenCalledWith(null);\n });\n\n it(\"should support multiple callbacks\", async () => {\n const { presenter } = createTestPresenter(createFlatFolders());\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n const cb1 = vi.fn();\n const cb2 = vi.fn();\n presenter.onFolderChange(cb1);\n presenter.onFolderChange(cb2);\n\n presenter.selectFolder(\"root-2\");\n\n expect(cb1).toHaveBeenCalledWith(\"root-2\");\n expect(cb2).toHaveBeenCalledWith(\"root-2\");\n });\n\n it(\"should return an unsubscribe function that stops callbacks\", async () => {\n const { presenter } = createTestPresenter(createFlatFolders());\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n const callback = vi.fn();\n const unsubscribe = presenter.onFolderChange(callback);\n\n presenter.selectFolder(\"root-1\");\n expect(callback).toHaveBeenCalledTimes(1);\n\n unsubscribe();\n\n presenter.selectFolder(\"root-2\");\n // Should not have been called again after unsubscribe.\n expect(callback).toHaveBeenCalledTimes(1);\n });\n\n it(\"should not fire callback when selecting the same folder\", async () => {\n const { presenter } = createTestPresenter(createFlatFolders());\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n presenter.selectFolder(\"root-1\");\n\n const callback = vi.fn();\n presenter.onFolderChange(callback);\n\n // Select the same folder again.\n presenter.selectFolder(\"root-1\");\n expect(callback).not.toHaveBeenCalled();\n });\n });\n\n // -------------------------------------------------------------------\n // createFolder / editFolder — operation state with FormModel\n // -------------------------------------------------------------------\n\n describe(\"createFolder\", () => {\n it(\"should set operation state with mode 'create' and a FormModel\", async () => {\n const { presenter, formModelFactory } = createTestPresenter(createFlatFolders());\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n presenter.createFolder(\"root-1\");\n\n expect(presenter.vm.operation.active).toBe(true);\n expect(presenter.vm.operation.mode).toBe(\"create\");\n expect(presenter.vm.operation.parentFolderId).toBe(\"root-1\");\n expect(presenter.vm.operation.form).toBeDefined();\n expect(formModelFactory.create).toHaveBeenCalledTimes(1);\n });\n\n it(\"should set parentFolderId to undefined when creating at root\", async () => {\n const { presenter } = createTestPresenter(createFlatFolders());\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n presenter.createFolder();\n\n expect(presenter.vm.operation.active).toBe(true);\n expect(presenter.vm.operation.mode).toBe(\"create\");\n expect(presenter.vm.operation.parentFolderId).toBeUndefined();\n });\n\n it(\"should wire submitOperation to CreateFolderUseCase\", async () => {\n const { presenter, createFolderUseCase, listFolders } =\n createTestPresenter(createFlatFolders());\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n presenter.createFolder(\"root-1\");\n\n await presenter.submitOperation();\n\n expect(createFolderUseCase.execute).toHaveBeenCalledTimes(1);\n expect(listFolders.execute).toHaveBeenCalledTimes(1);\n });\n });\n\n describe(\"editFolder\", () => {\n it(\"should set operation state with mode 'edit' and a FormModel\", async () => {\n const { presenter, formModelFactory } = createTestPresenter(createFlatFolders());\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n presenter.editFolder(\"root-1\");\n\n expect(presenter.vm.operation.active).toBe(true);\n expect(presenter.vm.operation.mode).toBe(\"edit\");\n expect(presenter.vm.operation.folderId).toBe(\"root-1\");\n expect(presenter.vm.operation.form).toBeDefined();\n expect(formModelFactory.create).toHaveBeenCalledTimes(1);\n });\n\n it(\"should pre-populate form with existing folder data\", async () => {\n const mockForm = createMockFormModel();\n const { presenter, formModelFactory } = createTestPresenter(createFlatFolders());\n formModelFactory.create.mockReturnValue(mockForm);\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n presenter.editFolder(\"root-1\");\n\n expect(mockForm.setData).toHaveBeenCalledWith({\n title: \"Documents\",\n slug: \"documents\"\n });\n });\n\n it(\"should do nothing when editing a non-existent folder\", async () => {\n const { presenter, formModelFactory } = createTestPresenter(createFlatFolders());\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n presenter.editFolder(\"non-existent\");\n\n expect(presenter.vm.operation.active).toBe(false);\n expect(presenter.vm.operation.mode).toBeNull();\n expect(formModelFactory.create).not.toHaveBeenCalled();\n });\n });\n\n // -------------------------------------------------------------------\n // deleteFolder — navigates to parent and updates tree\n // -------------------------------------------------------------------\n\n describe(\"deleteFolder\", () => {\n it(\"should call DeleteFolderUseCase with the folder id\", async () => {\n const { presenter, deleteFolderUseCase } = createTestPresenter(createFlatFolders());\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n await presenter.deleteFolder(\"child-1\");\n\n expect(deleteFolderUseCase.execute).toHaveBeenCalledWith(\"child-1\");\n });\n\n it(\"should set operation state with mode 'delete' during deletion\", async () => {\n const { presenter, deleteFolderUseCase } = createTestPresenter(createFlatFolders());\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n // Make delete hang so we can inspect intermediate state.\n let resolveDelete!: () => void;\n deleteFolderUseCase.execute.mockReturnValueOnce(\n new Promise<void>(resolve => {\n resolveDelete = resolve;\n })\n );\n\n const deletePromise = presenter.deleteFolder(\"child-1\");\n\n expect(presenter.vm.operation.active).toBe(true);\n expect(presenter.vm.operation.mode).toBe(\"delete\");\n expect(presenter.vm.operation.folderId).toBe(\"child-1\");\n\n resolveDelete();\n await deletePromise;\n\n // After completion, operation should be reset.\n expect(presenter.vm.operation.active).toBe(false);\n expect(presenter.vm.operation.mode).toBeNull();\n });\n\n it(\"should navigate to parent folder after deletion\", async () => {\n const { presenter } = createTestPresenter(createFlatFolders());\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n // child-1 has parentId \"root-1\".\n await presenter.deleteFolder(\"child-1\");\n\n expect(presenter.vm.currentFolderId).toBe(\"root-1\");\n });\n\n it(\"should navigate to root (null) when deleting a root folder\", async () => {\n const { presenter } = createTestPresenter(createFlatFolders());\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n // root-1 has parentId null.\n await presenter.deleteFolder(\"root-1\");\n\n expect(presenter.vm.currentFolderId).toBeNull();\n });\n\n it(\"should refresh the folder list after deletion\", async () => {\n const { presenter, listFolders } = createTestPresenter(createFlatFolders());\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n await presenter.deleteFolder(\"child-1\");\n\n // Initial load + refresh after delete.\n expect(listFolders.execute).toHaveBeenCalledTimes(2);\n });\n\n it(\"should fire onFolderChange callback when navigating to parent after delete\", async () => {\n const { presenter } = createTestPresenter(createFlatFolders());\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n const callback = vi.fn();\n presenter.onFolderChange(callback);\n\n // child-1 has parentId \"root-1\".\n await presenter.deleteFolder(\"child-1\");\n\n expect(callback).toHaveBeenCalledWith(\"root-1\");\n });\n });\n\n // -------------------------------------------------------------------\n // Operation state reset\n // -------------------------------------------------------------------\n\n describe(\"operation state\", () => {\n it(\"should start with inactive operation state\", async () => {\n const { presenter } = createTestPresenter();\n\n await vi.waitFor(() => {\n expect(presenter.vm.loading).toBe(false);\n });\n\n expect(presenter.vm.operation.active).toBe(false);\n expect(presenter.vm.operation.mode).toBeNull();\n });\n });\n});\n"],"names":["TYPE","createFolder","data","Folder","createFlatFolders","createMockField","value","vi","v","createMockFormModel","fields","Map","form","name","d","MockListFoldersUseCase","MockCreateFolderUseCase","MockUpdateFolderUseCase","MockDeleteFolderUseCase","MockFormModelFactory","_config","createTestPresenter","folders","container","Container","foldersCache","ListCache","listFolders","createFolderUseCase","updateFolderUseCase","deleteFolderUseCase","formModelFactory","FoldersContext","FoldersCache","ListFoldersUseCase","CreateFolderUseCase","UpdateFolderUseCase","DeleteFolderUseCase","ListFoldersByParentIdsUseCase","undefined","GetFolderAncestorsUseCase","GetFolderLevelPermissionUseCase","FormModelFactory","FolderTreePresenterFeature","presenter","Abstraction","describe","it","expect","tree","node","callback","cb1","cb2","unsubscribe","mockForm","resolveDelete","Promise","resolve","deletePromise"],"mappings":"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"}
|
package/table.types.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { FolderDto } from "./domain/folder/FolderDto.js";
|
|
2
2
|
import type { FolderIdentityDto } from "./domain/folder/FolderIdentity.js";
|
|
3
3
|
import type { GenericSearchData, Location } from "./types.js";
|
|
4
|
+
export type { TableRow, RecordTableRow } from "@webiny/app-admin/components/Table/table.types.js";
|
|
5
|
+
import type { TableRow } from "@webiny/app-admin/components/Table/table.types.js";
|
|
4
6
|
export interface SearchRecordItem<TData extends GenericSearchData = GenericSearchData> {
|
|
5
7
|
id: string;
|
|
6
8
|
type: string;
|
|
@@ -18,15 +20,6 @@ export interface SearchRecordItem<TData extends GenericSearchData = GenericSearc
|
|
|
18
20
|
}
|
|
19
21
|
export type MovableSearchRecordItem = Pick<SearchRecordItem, "id" | "location">;
|
|
20
22
|
export type DeletableSearchRecordItem = Pick<SearchRecordItem, "id" | "location">;
|
|
21
|
-
export interface TableRow<TData = unknown> {
|
|
22
|
-
id: string;
|
|
23
|
-
$selectable: boolean;
|
|
24
|
-
$type: string;
|
|
25
|
-
data: TData;
|
|
26
|
-
}
|
|
27
23
|
export interface FolderTableRow extends TableRow<FolderDto> {
|
|
28
24
|
$type: "FOLDER";
|
|
29
25
|
}
|
|
30
|
-
export interface RecordTableRow<TData> extends TableRow<TData> {
|
|
31
|
-
$type: "RECORD";
|
|
32
|
-
}
|
package/types.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import type { CmsModel, CmsModelField, CmsModelFieldSettings } from "@webiny/app-headless-cms-common/types/index.js";
|
|
2
|
-
export type { CmsIdentity } from "@webiny/app-headless-cms-common/types/index.js";
|
|
3
1
|
export type * from "@webiny/shared-aco/flp/flp.types.js";
|
|
4
|
-
export type * from "./graphql/records/types.js";
|
|
5
2
|
export type * from "./table.types.js";
|
|
3
|
+
export interface CmsIdentity {
|
|
4
|
+
id: string;
|
|
5
|
+
displayName: string;
|
|
6
|
+
type: string;
|
|
7
|
+
}
|
|
6
8
|
export interface FolderLevelPermissionsTarget<TMeta = Record<string, any>> {
|
|
7
9
|
id: string;
|
|
8
10
|
target: string;
|
|
@@ -38,31 +40,8 @@ export interface AcoError {
|
|
|
38
40
|
message: string;
|
|
39
41
|
data?: Record<string, any> | null;
|
|
40
42
|
}
|
|
41
|
-
export type ListSearchRecordsSortItem = `${string}_ASC` | `${string}_DESC`;
|
|
42
|
-
export type ListSearchRecordsSort = ListSearchRecordsSortItem[];
|
|
43
43
|
export interface ListMeta {
|
|
44
44
|
cursor: string | null;
|
|
45
45
|
totalCount: number;
|
|
46
46
|
hasMoreItems: boolean;
|
|
47
47
|
}
|
|
48
|
-
/**
|
|
49
|
-
* Apps.
|
|
50
|
-
*/
|
|
51
|
-
export interface AcoModel extends CmsModel {
|
|
52
|
-
fields: AcoModelField[];
|
|
53
|
-
}
|
|
54
|
-
export interface AcoModelFieldSettingsAco {
|
|
55
|
-
enabled?: boolean;
|
|
56
|
-
header?: boolean;
|
|
57
|
-
}
|
|
58
|
-
export interface AcoModelFieldSettings {
|
|
59
|
-
aco?: AcoModelFieldSettingsAco;
|
|
60
|
-
}
|
|
61
|
-
export interface AcoModelField extends CmsModelField {
|
|
62
|
-
settings?: CmsModelFieldSettings & AcoModelFieldSettings;
|
|
63
|
-
}
|
|
64
|
-
export interface AcoApp {
|
|
65
|
-
id: string;
|
|
66
|
-
model: AcoModel;
|
|
67
|
-
getFields: () => AcoModelField[];
|
|
68
|
-
}
|
package/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sources":["../src/types.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"types.js","sources":["../src/types.ts"],"sourcesContent":["export type * from \"@webiny/shared-aco/flp/flp.types.js\";\nexport type * from \"~/table.types.js\";\n\nexport interface CmsIdentity {\n id: string;\n displayName: string;\n type: string;\n}\n\nexport interface FolderLevelPermissionsTarget<TMeta = Record<string, any>> {\n id: string;\n target: string;\n name: string;\n type: string;\n meta: TMeta;\n}\n\nexport type GenericSearchData = {\n [key: string]: any;\n};\n\nexport interface Location {\n folderId: string;\n}\n\nexport interface TagItem {\n tag: string;\n}\n\nexport type Loading<T extends string> = { [P in T]?: boolean };\n\nexport type LoadingActions =\n | \"INIT\"\n | \"LIST\"\n | \"LIST_MORE\"\n | \"GET\"\n | \"CREATE\"\n | \"UPDATE\"\n | \"DELETE\"\n | \"MOVE\";\n\nexport const LoadingActionsEnum = {\n init: \"INIT\",\n list: \"LIST\",\n listMore: \"LIST_MORE\",\n get: \"GET\",\n create: \"CREATE\",\n update: \"UPDATE\",\n delete: \"DELETE\",\n move: \"MOVE\"\n};\n\nexport interface AcoError {\n code: string;\n message: string;\n data?: Record<string, any> | null;\n}\n\nexport interface ListMeta {\n cursor: string | null;\n totalCount: number;\n hasMoreItems: boolean;\n}\n"],"names":["LoadingActionsEnum"],"mappings":"AAyCO,MAAMA,qBAAqB;IAC9B,MAAM;IACN,MAAM;IACN,UAAU;IACV,KAAK;IACL,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,MAAM;AACV"}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import react from "react";
|
|
2
|
-
import { CompositionScope } from "@webiny/app-admin";
|
|
3
|
-
import { Fields, ModelProvider } from "@webiny/app-headless-cms-common";
|
|
4
|
-
import { Bind, BindPrefix } from "@webiny/form";
|
|
5
|
-
import { useFolderExtensionsFields } from "../../features/folders/getFolderExtensionsFields/index.js";
|
|
6
|
-
import { useFolderModel } from "../../hooks/useFolderModel.js";
|
|
7
|
-
const Extensions = ()=>{
|
|
8
|
-
const { fields } = useFolderExtensionsFields();
|
|
9
|
-
const folderModel = useFolderModel();
|
|
10
|
-
if (0 === fields.length || !folderModel) return null;
|
|
11
|
-
return /*#__PURE__*/ react.createElement(CompositionScope, {
|
|
12
|
-
name: "aco.folderDetails.extensionFields"
|
|
13
|
-
}, /*#__PURE__*/ react.createElement(ModelProvider, {
|
|
14
|
-
model: folderModel
|
|
15
|
-
}, /*#__PURE__*/ react.createElement(BindPrefix, {
|
|
16
|
-
name: "extensions"
|
|
17
|
-
}, /*#__PURE__*/ react.createElement("div", {
|
|
18
|
-
className: "mt-lg"
|
|
19
|
-
}, /*#__PURE__*/ react.createElement(Fields, {
|
|
20
|
-
contentModel: folderModel,
|
|
21
|
-
Bind: Bind,
|
|
22
|
-
fields: fields,
|
|
23
|
-
layout: fields.map((field)=>[
|
|
24
|
-
field.fieldId
|
|
25
|
-
])
|
|
26
|
-
})))));
|
|
27
|
-
};
|
|
28
|
-
export { Extensions };
|
|
29
|
-
|
|
30
|
-
//# sourceMappingURL=Extensions.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"components/Extensions/Extensions.js","sources":["../../../src/components/Extensions/Extensions.tsx"],"sourcesContent":["import React from \"react\";\nimport { CompositionScope } from \"@webiny/app-admin\";\nimport { ModelProvider, Fields } from \"@webiny/app-headless-cms-common\";\nimport { Bind, BindPrefix } from \"@webiny/form\";\nimport { useFolderExtensionsFields } from \"~/features/folders/getFolderExtensionsFields/index.js\";\nimport { useFolderModel } from \"~/hooks/useFolderModel.js\";\n\nexport const Extensions = () => {\n const { fields } = useFolderExtensionsFields();\n const folderModel = useFolderModel();\n\n if (fields.length === 0 || !folderModel) {\n return null;\n }\n\n return (\n <CompositionScope name={\"aco.folderDetails.extensionFields\"}>\n <ModelProvider model={folderModel}>\n <BindPrefix name={\"extensions\"}>\n <div className={\"mt-lg\"}>\n <Fields\n contentModel={folderModel}\n // @ts-expect-error\n Bind={Bind}\n fields={fields}\n layout={fields.map(field => [field.fieldId])}\n />\n </div>\n </BindPrefix>\n </ModelProvider>\n </CompositionScope>\n );\n};\n"],"names":["Extensions","fields","useFolderExtensionsFields","folderModel","useFolderModel","CompositionScope","ModelProvider","BindPrefix","Fields","Bind","field"],"mappings":";;;;;;AAOO,MAAMA,aAAa;IACtB,MAAM,EAAEC,MAAM,EAAE,GAAGC;IACnB,MAAMC,cAAcC;IAEpB,IAAIH,AAAkB,MAAlBA,OAAO,MAAM,IAAU,CAACE,aACxB,OAAO;IAGX,OAAO,WAAP,GACI,oBAACE,kBAAgBA;QAAC,MAAM;qBACpB,oBAACC,eAAaA;QAAC,OAAOH;qBAClB,oBAACI,YAAUA;QAAC,MAAM;qBACd,oBAAC;QAAI,WAAW;qBACZ,oBAACC,QAAMA;QACH,cAAcL;QAEd,MAAMM;QACN,QAAQR;QACR,QAAQA,OAAO,GAAG,CAACS,CAAAA,QAAS;gBAACA,MAAM,OAAO;aAAC;;AAOvE"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./Extensions.js";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./Extensions.js";
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import type { GenericComponent, Decorator } from "@webiny/app-admin";
|
|
3
|
-
import { FieldElement } from "@webiny/app-headless-cms-common";
|
|
4
|
-
export type FieldProps = React.ComponentProps<typeof FieldElement>;
|
|
5
|
-
export interface FieldDecoratorProps {
|
|
6
|
-
id?: string;
|
|
7
|
-
modelIds?: string[];
|
|
8
|
-
}
|
|
9
|
-
export interface FolderFieldDecoratorParams {
|
|
10
|
-
scope?: string;
|
|
11
|
-
shouldDecorate: (decoratorProps: FieldDecoratorProps, componentProps: FieldProps) => boolean;
|
|
12
|
-
}
|
|
13
|
-
export declare const createFolderFieldDecoratorFactory: ({ scope, shouldDecorate }: FolderFieldDecoratorParams) => (decorator: Decorator<GenericComponent<FieldProps>>) => (props: FieldDecoratorProps) => React.JSX.Element;
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import react from "react";
|
|
2
|
-
import { Compose, CompositionScope, createConditionalDecorator } from "@webiny/app-admin";
|
|
3
|
-
import { FieldElement } from "@webiny/app-headless-cms-common";
|
|
4
|
-
const createFolderFieldDecoratorFactory = ({ scope = "*", shouldDecorate })=>(decorator)=>function(props) {
|
|
5
|
-
const conditionalDecorator = createConditionalDecorator(shouldDecorate, decorator, props);
|
|
6
|
-
return /*#__PURE__*/ react.createElement(CompositionScope, {
|
|
7
|
-
name: scope
|
|
8
|
-
}, /*#__PURE__*/ react.createElement(CompositionScope, {
|
|
9
|
-
name: "aco.folderDetails.extensionFields"
|
|
10
|
-
}, /*#__PURE__*/ react.createElement(Compose, {
|
|
11
|
-
component: FieldElement,
|
|
12
|
-
with: conditionalDecorator
|
|
13
|
-
})));
|
|
14
|
-
};
|
|
15
|
-
export { createFolderFieldDecoratorFactory };
|
|
16
|
-
|
|
17
|
-
//# sourceMappingURL=createFolderFieldDecoratorFactory.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config/folder/createFolderFieldDecoratorFactory.js","sources":["../../../src/config/folder/createFolderFieldDecoratorFactory.tsx"],"sourcesContent":["import React from \"react\";\nimport type { GenericComponent, Decorator } from \"@webiny/app-admin\";\nimport { Compose, createConditionalDecorator, CompositionScope } from \"@webiny/app-admin\";\nimport { FieldElement } from \"@webiny/app-headless-cms-common\";\n\nexport type FieldProps = React.ComponentProps<typeof FieldElement>;\n\nexport interface FieldDecoratorProps {\n id?: string;\n modelIds?: string[];\n}\n\nexport interface FolderFieldDecoratorParams {\n scope?: string;\n shouldDecorate: (decoratorProps: FieldDecoratorProps, componentProps: FieldProps) => boolean;\n}\n\nexport const createFolderFieldDecoratorFactory =\n ({ scope = \"*\", shouldDecorate }: FolderFieldDecoratorParams) =>\n (decorator: Decorator<GenericComponent<FieldProps>>) => {\n return function FieldDecorator(props: FieldDecoratorProps) {\n const conditionalDecorator = createConditionalDecorator(\n shouldDecorate,\n decorator,\n props\n );\n\n return (\n <CompositionScope name={scope}>\n <CompositionScope name={\"aco.folderDetails.extensionFields\"}>\n <Compose component={FieldElement} with={conditionalDecorator} />\n </CompositionScope>\n </CompositionScope>\n );\n };\n };\n"],"names":["createFolderFieldDecoratorFactory","scope","shouldDecorate","decorator","props","conditionalDecorator","createConditionalDecorator","CompositionScope","Compose","FieldElement"],"mappings":";;;AAiBO,MAAMA,oCACT,CAAC,EAAEC,QAAQ,GAAG,EAAEC,cAAc,EAA8B,GAC5D,CAACC,YACU,SAAwBC,KAA0B;YACrD,MAAMC,uBAAuBC,2BACzBJ,gBACAC,WACAC;YAGJ,OAAO,WAAP,GACI,oBAACG,kBAAgBA;gBAAC,MAAMN;6BACpB,oBAACM,kBAAgBA;gBAAC,MAAM;6BACpB,oBAACC,SAAOA;gBAAC,WAAWC;gBAAc,MAAMJ;;QAIxD"}
|