@webiny/app-file-manager 6.4.12-beta.5 → 6.5.0-beta.1
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/app.js +21 -2
- package/app.js.map +1 -1
- package/domain/tagsHelpers.d.ts +2 -2
- package/domain/types.d.ts +0 -8
- package/features/permissions/abstractions.d.ts +2 -2
- package/features/permissions/feature.d.ts +2 -2
- package/features/shared/FILE_FIELDS.js +4 -0
- package/features/shared/FILE_FIELDS.js.map +1 -1
- package/modules/AiEnrichment/AiImageEnrichmentEventHandler.d.ts +18 -0
- package/modules/AiEnrichment/AiImageEnrichmentEventHandler.js +33 -0
- package/modules/AiEnrichment/AiImageEnrichmentEventHandler.js.map +1 -0
- package/modules/AiEnrichment/feature.d.ts +1 -0
- package/modules/AiEnrichment/feature.js +11 -0
- package/modules/AiEnrichment/feature.js.map +1 -0
- package/modules/AiEnrichment/index.d.ts +2 -0
- package/modules/AiEnrichment/index.js +9 -0
- package/modules/AiEnrichment/index.js.map +1 -0
- package/modules/HeadlessCms/fieldType/AssetFieldSettingsModifier.d.ts +26 -0
- package/modules/HeadlessCms/fieldType/AssetFieldSettingsModifier.js +39 -0
- package/modules/HeadlessCms/fieldType/AssetFieldSettingsModifier.js.map +1 -0
- package/modules/HeadlessCms/fieldType/AssetFieldType.d.ts +34 -0
- package/modules/HeadlessCms/fieldType/AssetFieldType.js +42 -0
- package/modules/HeadlessCms/fieldType/AssetFieldType.js.map +1 -0
- package/modules/HeadlessCms/fieldType/AssetFormFieldType.d.ts +21 -0
- package/modules/HeadlessCms/fieldType/AssetFormFieldType.js +42 -0
- package/modules/HeadlessCms/fieldType/AssetFormFieldType.js.map +1 -0
- package/modules/HeadlessCms/fieldType/AssetInputRenderer.d.ts +15 -0
- package/modules/HeadlessCms/fieldType/AssetInputRenderer.js +20 -0
- package/modules/HeadlessCms/fieldType/AssetInputRenderer.js.map +1 -0
- package/modules/HeadlessCms/fieldType/AssetInputsRenderer.d.ts +15 -0
- package/modules/HeadlessCms/fieldType/AssetInputsRenderer.js +20 -0
- package/modules/HeadlessCms/fieldType/AssetInputsRenderer.js.map +1 -0
- package/modules/HeadlessCms/fieldType/FileFieldSettingsModifier.d.ts +16 -0
- package/modules/HeadlessCms/fieldType/FileFieldSettingsModifier.js +33 -0
- package/modules/HeadlessCms/fieldType/FileFieldSettingsModifier.js.map +1 -0
- package/modules/HeadlessCms/fieldType/FileFieldType.d.ts +25 -0
- package/modules/HeadlessCms/fieldType/FileFieldType.js +38 -0
- package/modules/HeadlessCms/fieldType/FileFieldType.js.map +1 -0
- package/modules/HeadlessCms/fieldType/FileInputRenderer.d.ts +15 -0
- package/modules/HeadlessCms/fieldType/FileInputRenderer.js +19 -0
- package/modules/HeadlessCms/fieldType/FileInputRenderer.js.map +1 -0
- package/modules/HeadlessCms/fieldType/FileInputsRenderer.d.ts +15 -0
- package/modules/HeadlessCms/fieldType/FileInputsRenderer.js +19 -0
- package/modules/HeadlessCms/fieldType/FileInputsRenderer.js.map +1 -0
- package/modules/HeadlessCms/fieldType/feature.d.ts +1 -0
- package/modules/HeadlessCms/fieldType/feature.js +27 -0
- package/modules/HeadlessCms/fieldType/feature.js.map +1 -0
- package/modules/HeadlessCms/fieldType/isAssetField.d.ts +2 -0
- package/modules/HeadlessCms/fieldType/isAssetField.js +4 -0
- package/modules/HeadlessCms/fieldType/isAssetField.js.map +1 -0
- package/package.json +25 -35
- package/presentation/FileActions/FileDetails/EditImage.d.ts +2 -0
- package/presentation/FileActions/FileDetails/EditImage.js +39 -0
- package/presentation/FileActions/FileDetails/EditImage.js.map +1 -0
- package/presentation/FileActions/index.js +4 -0
- package/presentation/FileActions/index.js.map +1 -1
- package/presentation/FileDetails/FileDetailsPresenter.d.ts +2 -0
- package/presentation/FileDetails/FileDetailsPresenter.js +5 -0
- package/presentation/FileDetails/FileDetailsPresenter.js.map +1 -1
- package/presentation/FileDetails/FileDetailsPresenter.test.js +1 -0
- package/presentation/FileDetails/FileDetailsPresenter.test.js.map +1 -1
- package/presentation/FileDetails/abstractions.d.ts +2 -0
- package/presentation/FileDetails/abstractions.js.map +1 -1
- package/presentation/FileDetails/components/Content.d.ts +5 -4
- package/presentation/FileDetails/components/FileDetailsDrawer.d.ts +2 -2
- package/presentation/FileList/FileListDataSource.d.ts +8 -12
- package/presentation/FileList/FileListDataSource.js +47 -87
- package/presentation/FileList/FileListDataSource.js.map +1 -1
- package/presentation/FileList/FileListPresenter.test.js +9 -3
- package/presentation/FileList/FileListPresenter.test.js.map +1 -1
- package/presentation/FileList/FileManagerPresenter.d.ts +1 -0
- package/presentation/FileList/FileManagerPresenter.js +15 -5
- package/presentation/FileList/FileManagerPresenter.js.map +1 -1
- package/presentation/FileList/abstractions.d.ts +3 -0
- package/presentation/FileList/abstractions.js.map +1 -1
- package/presentation/FileList/components/BulkActions/BulkActionBar.d.ts +2 -2
- package/presentation/FileList/components/BulkActions/BulkActionDelete.d.ts +2 -2
- package/presentation/FileList/components/BulkActions/BulkActionMove.d.ts +2 -2
- package/presentation/FileList/components/BulkActions/index.d.ts +0 -1
- package/presentation/FileList/components/BulkActions/index.js +0 -1
- package/presentation/FileList/components/BulkActions/useBulkActionWorker.d.ts +9 -8
- package/presentation/FileList/components/BulkActions/useBulkActionWorker.js +3 -9
- package/presentation/FileList/components/BulkActions/useBulkActionWorker.js.map +1 -1
- package/presentation/FileList/components/Filters/SubFoldersToggle.d.ts +2 -2
- package/presentation/FileList/components/Filters/TagsFilter.d.ts +2 -2
- package/presentation/FileList/components/Filters/TypeFilter.d.ts +2 -2
- package/presentation/FileList/components/Grid/FileGrid.d.ts +2 -2
- package/presentation/FileList/components/Grid/FileGrid.js +1 -1
- package/presentation/FileList/components/Grid/FileGrid.js.map +1 -1
- package/presentation/FileList/components/Grid/FileGrid.test.js +18 -7
- package/presentation/FileList/components/Grid/FileGrid.test.js.map +1 -1
- package/presentation/FileList/components/Header/FileManagerHeader.d.ts +2 -2
- package/presentation/FileList/components/Search/SearchBar.d.ts +2 -2
- package/presentation/FileList/components/Table/FileTable.d.ts +2 -2
- package/presentation/FileList/components/Table/FileTable.js +1 -1
- package/presentation/FileList/components/Table/FileTable.js.map +1 -1
- package/presentation/FileList/components/Table/FileTable.test.js +9 -4
- package/presentation/FileList/components/Table/FileTable.test.js.map +1 -1
- package/presentation/FileList/components/Upload/UploadProgress.d.ts +2 -2
- package/presentation/FileManager/FileManagerView.js +4 -2
- package/presentation/FileManager/FileManagerView.js.map +1 -1
- package/presentation/FileManager/RouteParamsSync.d.ts +2 -0
- package/presentation/FileManager/RouteParamsSync.js +30 -0
- package/presentation/FileManager/RouteParamsSync.js.map +1 -0
- package/presentation/Settings/components/SettingsView.d.ts +2 -2
- package/presentation/config/DefaultFileManagerConfig.js +1 -4
- package/presentation/config/DefaultFileManagerConfig.js.map +1 -1
- package/presentation/config/FileManagerViewConfig.d.ts +19 -25
- package/presentation/config/configComponents/Browser/BulkAction.d.ts +10 -8
- package/presentation/config/configComponents/Browser/BulkAction.js +3 -9
- package/presentation/config/configComponents/Browser/BulkAction.js.map +1 -1
- package/presentation/config/configComponents/Browser/FileAction.d.ts +2 -1
- package/presentation/config/configComponents/Browser/FolderAction.d.ts +2 -1
- package/presentation/config/configComponents/Browser/Table/Column.d.ts +9 -8
- package/presentation/config/configComponents/Browser/Table/index.d.ts +9 -9
- package/presentation/config/configComponents/Browser/index.d.ts +20 -20
- package/presentation/config/configComponents/Browser/index.js +0 -8
- package/presentation/config/configComponents/Browser/index.js.map +1 -1
- package/presentation/config/configComponents/FileDetails/index.d.ts +4 -2
- package/presentation/config/getThumbnailRenderer.js +1 -1
- package/presentation/config/getThumbnailRenderer.js.map +1 -1
- package/presentation/config/thumbnailRenderers/CroppedFileImage.d.ts +18 -0
- package/presentation/config/thumbnailRenderers/CroppedFileImage.js +66 -0
- package/presentation/config/thumbnailRenderers/CroppedFileImage.js.map +1 -0
- package/presentation/config/thumbnailRenderers/FilePreviewImageRenderer.js +6 -9
- package/presentation/config/thumbnailRenderers/FilePreviewImageRenderer.js.map +1 -1
- package/presentation/config/thumbnailRenderers/GridItemImageRenderer.js +6 -9
- package/presentation/config/thumbnailRenderers/GridItemImageRenderer.js.map +1 -1
- package/presentation/config/thumbnailRenderers/TableItemImageRenderer.js +6 -9
- package/presentation/config/thumbnailRenderers/TableItemImageRenderer.js.map +1 -1
- package/presentation/fieldRenderers/CmsAssetPickerRenderer.d.ts +22 -0
- package/presentation/fieldRenderers/CmsAssetPickerRenderer.js +56 -0
- package/presentation/fieldRenderers/CmsAssetPickerRenderer.js.map +1 -0
- package/presentation/fieldRenderers/CmsFilePickerRenderer.d.ts +13 -0
- package/presentation/fieldRenderers/CmsFilePickerRenderer.js +36 -0
- package/presentation/fieldRenderers/CmsFilePickerRenderer.js.map +1 -0
- package/presentation/fieldRenderers/CmsImageEditorDialog.d.ts +7 -0
- package/presentation/fieldRenderers/CmsImageEditorDialog.js +32 -0
- package/presentation/fieldRenderers/CmsImageEditorDialog.js.map +1 -0
- package/presentation/fieldRenderers/CmsMultiAssetPickerRenderer.d.ts +18 -0
- package/presentation/fieldRenderers/CmsMultiAssetPickerRenderer.js +88 -0
- package/presentation/fieldRenderers/CmsMultiAssetPickerRenderer.js.map +1 -0
- package/presentation/fieldRenderers/CmsMultiFilePickerRenderer.d.ts +13 -0
- package/presentation/fieldRenderers/CmsMultiFilePickerRenderer.js +60 -0
- package/presentation/fieldRenderers/CmsMultiFilePickerRenderer.js.map +1 -0
- package/presentation/fieldRenderers/CroppedAssetThumb.d.ts +15 -0
- package/presentation/fieldRenderers/CroppedAssetThumb.js +25 -0
- package/presentation/fieldRenderers/CroppedAssetThumb.js.map +1 -0
- package/presentation/fieldRenderers/assetValue.d.ts +10 -0
- package/presentation/fieldRenderers/assetValue.js +94 -0
- package/presentation/fieldRenderers/assetValue.js.map +1 -0
- package/presentation/fieldRenderers/assetValue.test.js +54 -0
- package/presentation/fieldRenderers/assetValue.test.js.map +1 -0
- package/presentation/hooks/useCmsImageEditor.d.ts +10 -0
- package/presentation/hooks/useCmsImageEditor.js +76 -0
- package/presentation/hooks/useCmsImageEditor.js.map +1 -0
- package/presentation/hooks/useEditImage.d.ts +14 -0
- package/presentation/hooks/useEditImage.js +67 -0
- package/presentation/hooks/useEditImage.js.map +1 -0
- package/routes.d.ts +1 -0
- package/routes.js +2 -1
- package/routes.js.map +1 -1
- package/modules/HeadlessCms/fileField.d.ts +0 -2
- package/modules/HeadlessCms/fileField.js +0 -44
- package/modules/HeadlessCms/fileField.js.map +0 -1
- package/modules/HeadlessCms/fileRenderer/fileField.d.ts +0 -2
- package/modules/HeadlessCms/fileRenderer/fileField.js +0 -53
- package/modules/HeadlessCms/fileRenderer/fileField.js.map +0 -1
- package/modules/HeadlessCms/fileRenderer/fileFields.d.ts +0 -2
- package/modules/HeadlessCms/fileRenderer/fileFields.js +0 -73
- package/modules/HeadlessCms/fileRenderer/fileFields.js.map +0 -1
- package/modules/HeadlessCms/fileRenderer/utils.d.ts +0 -2
- package/modules/HeadlessCms/fileRenderer/utils.js +0 -15
- package/modules/HeadlessCms/fileRenderer/utils.js.map +0 -1
- package/modules/HeadlessCms/index.d.ts +0 -1
- package/modules/HeadlessCms/index.js +0 -14
- package/modules/HeadlessCms/index.js.map +0 -1
- package/modules/Settings/graphql.d.ts +0 -12
- package/modules/Settings/graphql.js +0 -36
- package/modules/Settings/graphql.js.map +0 -1
- package/modules/Settings/views/FileManagerSettings.d.ts +0 -2
- package/modules/Settings/views/FileManagerSettings.js +0 -134
- package/modules/Settings/views/FileManagerSettings.js.map +0 -1
- package/presentation/FileList/components/BulkActions/BatchEditorDialog/AddOperation.d.ts +0 -7
- package/presentation/FileList/components/BulkActions/BatchEditorDialog/AddOperation.js +0 -15
- package/presentation/FileList/components/BulkActions/BatchEditorDialog/AddOperation.js.map +0 -1
- package/presentation/FileList/components/BulkActions/BatchEditorDialog/BatchEditor.d.ts +0 -15
- package/presentation/FileList/components/BulkActions/BatchEditorDialog/BatchEditor.js +0 -44
- package/presentation/FileList/components/BulkActions/BatchEditorDialog/BatchEditor.js.map +0 -1
- package/presentation/FileList/components/BulkActions/BatchEditorDialog/BatchEditorDialog.d.ts +0 -15
- package/presentation/FileList/components/BulkActions/BatchEditorDialog/BatchEditorDialog.js +0 -52
- package/presentation/FileList/components/BulkActions/BatchEditorDialog/BatchEditorDialog.js.map +0 -1
- package/presentation/FileList/components/BulkActions/BatchEditorDialog/BatchEditorDialogPresenter.d.ts +0 -61
- package/presentation/FileList/components/BulkActions/BatchEditorDialog/BatchEditorDialogPresenter.js +0 -111
- package/presentation/FileList/components/BulkActions/BatchEditorDialog/BatchEditorDialogPresenter.js.map +0 -1
- package/presentation/FileList/components/BulkActions/BatchEditorDialog/BatchEditorDialogPresenter.test.js +0 -372
- package/presentation/FileList/components/BulkActions/BatchEditorDialog/BatchEditorDialogPresenter.test.js.map +0 -1
- package/presentation/FileList/components/BulkActions/BatchEditorDialog/FieldRenderer.d.ts +0 -8
- package/presentation/FileList/components/BulkActions/BatchEditorDialog/FieldRenderer.js +0 -31
- package/presentation/FileList/components/BulkActions/BatchEditorDialog/FieldRenderer.js.map +0 -1
- package/presentation/FileList/components/BulkActions/BatchEditorDialog/Operation.d.ts +0 -11
- package/presentation/FileList/components/BulkActions/BatchEditorDialog/Operation.js +0 -33
- package/presentation/FileList/components/BulkActions/BatchEditorDialog/Operation.js.map +0 -1
- package/presentation/FileList/components/BulkActions/BatchEditorDialog/index.d.ts +0 -1
- package/presentation/FileList/components/BulkActions/BatchEditorDialog/index.js +0 -1
- package/presentation/FileList/components/BulkActions/BulkActionEdit.d.ts +0 -4
- package/presentation/FileList/components/BulkActions/BulkActionEdit.js +0 -105
- package/presentation/FileList/components/BulkActions/BulkActionEdit.js.map +0 -1
- package/presentation/config/configComponents/Browser/FolderFieldDecorator.d.ts +0 -7
- package/presentation/config/configComponents/Browser/FolderFieldDecorator.js +0 -11
- package/presentation/config/configComponents/Browser/FolderFieldDecorator.js.map +0 -1
- /package/presentation/{FileList/components/BulkActions/BatchEditorDialog/BatchEditorDialogPresenter.test.d.ts → fieldRenderers/assetValue.test.d.ts} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presentation/FileList/FileListPresenter.test.js","sources":["../../../src/presentation/FileList/FileListPresenter.test.ts"],"sourcesContent":["// @vitest-environment jsdom\nimport { describe, it, expect, vi, beforeEach } from \"vitest\";\nimport { observable, runInAction } from \"mobx\";\nimport { Container } from \"@webiny/di\";\nimport { ListCache } from \"@webiny/app-admin/features/listCache/index.js\";\nimport { ListPresenter } from \"@webiny/app-admin/presentation/listPresenter/abstractions.js\";\nimport { FolderTreePresenter } from \"@webiny/app-aco/presentation/folderTree/abstractions.js\";\nimport { FileManagerPermissions } from \"../../features/permissions/abstractions.js\";\nimport { GetSettingsRepository } from \"../../features/settings/abstractions.js\";\nimport { ListTagsRepository } from \"../../features/tags/abstractions.js\";\nimport { FileUploader } from \"../../features/fileUploader/abstractions.js\";\nimport { LocalStorage } from \"@webiny/app/features/localStorage\";\nimport { ListFilesUseCase } from \"../../features/listFiles/abstractions.js\";\nimport { FilesListCache } from \"../../features/shared/abstractions.js\";\nimport { GetDescendantFoldersUseCase } from \"@webiny/app-aco/features/folders/getDescendantFolders/abstractions.js\";\nimport { FileModelProvider } from \"../../features/fileModel/abstractions.js\";\nimport { FileDetailsPresenter } from \"../FileDetails/abstractions.js\";\nimport type { IFileDetailsPresenter } from \"../FileDetails/abstractions.js\";\nimport { FileManagerPresenter as Abstraction, type IFileManagerPresenter } from \"./abstractions.js\";\nimport { FileManagerPresenter } from \"./FileManagerPresenter.js\";\nimport type { FmFile } from \"../../features/shared/types.js\";\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction createMockListPresenter(): ListPresenter.Interface<FmFile> {\n const vmState = observable({\n rows: [] as FmFile[],\n sort: null as { field: string; direction: \"ASC\" | \"DESC\" } | null,\n filters: {} as Record<string, unknown>,\n search: \"\",\n appliedQuery: null as\n | import(\"@webiny/app-admin/presentation/listPresenter/abstractions.js\").IDataSourceQuery\n | null,\n pagination: {\n hasMore: false,\n loading: false,\n loadingMore: false,\n totalCount: 0,\n currentCount: 0\n },\n selection: {\n selectedIds: new Set<string>(),\n selectedCount: 0,\n allSelected: false\n },\n empty: true,\n emptyWithFilters: false,\n error: null as\n | import(\"@webiny/app-admin/presentation/listPresenter/abstractions.js\").IListError\n | null\n });\n\n return {\n get vm() {\n return vmState;\n },\n actions: {\n search: { set: vi.fn(), clear: vi.fn() },\n sort: { set: vi.fn(), toggle: vi.fn() },\n filter: { set: vi.fn(), clear: vi.fn(), clearAll: vi.fn() },\n selection: {\n toggle: vi.fn(),\n selectRangeTo: vi.fn(),\n selectAll: vi.fn(),\n deselectAll: vi.fn(),\n selectRows: vi.fn(),\n isSelected: vi.fn().mockReturnValue(false)\n },\n loadMore: vi.fn().mockResolvedValue(undefined),\n refresh: vi.fn().mockResolvedValue(undefined)\n },\n init: vi.fn()\n };\n}\n\nfunction createMockFolderTreePresenter(): FolderTreePresenter.Interface {\n const state = observable({\n folders: [],\n tree: [],\n currentFolderId: null as string | null,\n currentFolder: null,\n loading: false,\n operation: { active: false, mode: null },\n isRootFolder: true,\n currentFolderTitle: \"All Files\",\n childFolders: [],\n loadingNodeIds: []\n });\n\n return {\n get vm() {\n return state;\n },\n selectFolder: vi.fn(),\n createFolder: vi.fn(),\n editFolder: vi.fn(),\n deleteFolder: vi.fn().mockResolvedValue(undefined),\n moveFolder: vi.fn().mockResolvedValue(undefined),\n loadChildFolders: vi.fn().mockResolvedValue(undefined),\n canManageStructure: vi.fn().mockReturnValue(true),\n getAncestorIds: vi.fn().mockReturnValue([]),\n submitOperation: vi.fn().mockResolvedValue(true),\n cancelOperation: vi.fn(),\n onFolderChange: vi.fn().mockReturnValue(() => {})\n };\n}\n\nfunction createMockPermissions(): FileManagerPermissions.Interface {\n return {\n canAccess: vi.fn().mockReturnValue(true),\n canRead: vi.fn().mockReturnValue(true),\n canCreate: vi.fn().mockReturnValue(true),\n canEdit: vi.fn().mockReturnValue(false),\n canDelete: vi.fn().mockReturnValue(false),\n canAction: vi.fn().mockReturnValue(true)\n } as unknown as FileManagerPermissions.Interface;\n}\n\nfunction createMockSettingsRepository(): GetSettingsRepository.Interface {\n return {\n execute: vi.fn().mockResolvedValue({\n uploadMinFileSize: \"0\",\n uploadMaxFileSize: \"10485760\",\n srcPrefix: \"https://cdn.example.com/\"\n }),\n save: vi.fn().mockImplementation(async (data: Record<string, unknown>) => data),\n settings: null\n };\n}\n\nfunction createMockTagsRepository(): ListTagsRepository.Interface {\n return {\n execute: vi.fn().mockResolvedValue([]),\n tags: [{ tag: \"photo\", count: 5 }]\n };\n}\n\nfunction createMockFileUploader(): FileUploader.Interface {\n return {\n vm: {\n jobs: [],\n overallProgress: { sent: 0, total: 0, percentage: 0 },\n isUploading: false,\n completedCount: 0,\n failedCount: 0\n },\n upload: vi.fn().mockResolvedValue(undefined),\n uploadMany: vi.fn().mockResolvedValue(undefined),\n abort: vi.fn(),\n clear: vi.fn()\n };\n}\n\nfunction createMockLocalStorage(): LocalStorage.Interface {\n const store = new Map<string, unknown>();\n return {\n get: vi.fn((key: string) => store.get(key)) as LocalStorage.Interface[\"get\"],\n set: vi.fn(<T>(key: string, value: T): void => {\n store.set(key, value);\n }),\n remove: vi.fn((key: string) => {\n store.delete(key);\n }),\n clear: vi.fn(() => store.clear()),\n keys: vi.fn(() => Array.from(store.keys()))\n };\n}\n\nfunction createMockListFilesUseCase(): ListFilesUseCase.Interface {\n return {\n execute: vi.fn().mockResolvedValue({\n data: [],\n meta: { cursor: null, hasMoreItems: false, totalCount: 0 }\n })\n };\n}\n\nfunction createMockGetDescendantFoldersUseCase(): GetDescendantFoldersUseCase.Interface {\n return {\n execute: vi.fn().mockReturnValue([])\n };\n}\n\nfunction createMockFileDetailsPresenter(): IFileDetailsPresenter {\n return {\n vm: {\n file: null,\n loading: null,\n form: {\n layout: [],\n errors: [],\n isDirty: false,\n isValid: null,\n submitCount: 0,\n focusField: vi.fn(),\n getData: vi.fn(() => ({})),\n setData: vi.fn()\n },\n previewUrl: null,\n permissions: { canEdit: true, canDelete: true }\n },\n loadFile: vi.fn().mockResolvedValue(undefined),\n saveFile: vi.fn().mockResolvedValue(undefined)\n };\n}\n\n// ---------------------------------------------------------------------------\n// Container setup\n// ---------------------------------------------------------------------------\n\ninterface Mocks {\n listPresenter: ListPresenter.Interface<FmFile>;\n folderTreePresenter: FolderTreePresenter.Interface;\n fileDetailsPresenter: IFileDetailsPresenter;\n permissions: FileManagerPermissions.Interface;\n settingsRepository: GetSettingsRepository.Interface;\n tagsRepository: ListTagsRepository.Interface;\n fileUploader: FileUploader.Interface;\n localStorage: LocalStorage.Interface;\n listFilesUseCase: ListFilesUseCase.Interface;\n cache: ListCache<FmFile>;\n getDescendantFoldersUseCase: GetDescendantFoldersUseCase.Interface;\n fileModelProvider: FileModelProvider.Interface;\n}\n\nfunction createMocks(): Mocks {\n return {\n listPresenter: createMockListPresenter(),\n folderTreePresenter: createMockFolderTreePresenter(),\n fileDetailsPresenter: createMockFileDetailsPresenter(),\n permissions: createMockPermissions(),\n settingsRepository: createMockSettingsRepository(),\n tagsRepository: createMockTagsRepository(),\n fileUploader: createMockFileUploader(),\n localStorage: createMockLocalStorage(),\n listFilesUseCase: createMockListFilesUseCase(),\n cache: new ListCache<FmFile>(),\n getDescendantFoldersUseCase: createMockGetDescendantFoldersUseCase(),\n fileModelProvider: {\n getModel: vi.fn().mockResolvedValue({ fields: [] })\n }\n };\n}\n\nfunction createContainer(mocks: Mocks) {\n const container = new Container();\n\n container.registerInstance(ListPresenter, mocks.listPresenter);\n container.registerInstance(FolderTreePresenter, mocks.folderTreePresenter);\n container.registerInstance(FileDetailsPresenter, mocks.fileDetailsPresenter);\n container.registerInstance(FileManagerPermissions, mocks.permissions);\n container.registerInstance(GetSettingsRepository, mocks.settingsRepository);\n container.registerInstance(ListTagsRepository, mocks.tagsRepository);\n container.registerInstance(FileUploader, mocks.fileUploader);\n container.registerInstance(LocalStorage, mocks.localStorage);\n container.registerInstance(ListFilesUseCase, mocks.listFilesUseCase);\n container.registerInstance(FilesListCache, mocks.cache);\n container.registerInstance(GetDescendantFoldersUseCase, mocks.getDescendantFoldersUseCase);\n container.registerInstance(FileModelProvider, mocks.fileModelProvider);\n\n // Register the real FileListPresenter implementation.\n container.register(FileManagerPresenter).inSingletonScope();\n\n return container;\n}\n\n// ---------------------------------------------------------------------------\n// Tests\n// ---------------------------------------------------------------------------\n\ndescribe(\"FileListPresenter\", () => {\n let mocks: Mocks;\n let presenter: IFileManagerPresenter;\n\n beforeEach(() => {\n mocks = createMocks();\n const container = createContainer(mocks);\n presenter = container.resolve(Abstraction);\n });\n\n // -----------------------------------------------------------------------\n // Composition: ListPresenter and FolderTreePresenter initialized.\n // -----------------------------------------------------------------------\n\n it(\"should call listPresenter.init with a DataSource and initialSort on init()\", () => {\n presenter.init();\n\n expect(mocks.listPresenter.init).toHaveBeenCalledTimes(1);\n const config = (mocks.listPresenter.init as ReturnType<typeof vi.fn>).mock.calls[0][0];\n expect(config.dataSource).toBeDefined();\n expect(config.initialSort).toEqual({ field: \"createdOn\", direction: \"DESC\" });\n });\n\n it(\"should forward ListPresenter.vm data as vm.list\", () => {\n presenter.init();\n expect(presenter.vm.list.rows).toEqual(mocks.listPresenter.vm.rows);\n expect(presenter.vm.list.sort).toEqual(mocks.listPresenter.vm.sort);\n expect(presenter.vm.list.search).toBe(mocks.listPresenter.vm.search);\n expect(presenter.vm.list.empty).toBe(mocks.listPresenter.vm.empty);\n });\n\n it(\"should forward FolderTreePresenter.vm as vm.folders\", () => {\n presenter.init();\n expect(presenter.vm.folders).toBe(mocks.folderTreePresenter.vm);\n });\n\n // -----------------------------------------------------------------------\n // Folder change wiring.\n // -----------------------------------------------------------------------\n\n it(\"should set folderId filter when folder changes\", async () => {\n presenter.init();\n\n // Simulate folder selection via MobX observable change.\n runInAction(() => {\n (mocks.folderTreePresenter.vm as any).currentFolderId = \"folder-abc\";\n });\n\n // MobX reaction fires synchronously in the same tick after runInAction.\n expect(mocks.listPresenter.actions.filter.set).toHaveBeenCalledWith(\n \"folderId\",\n \"folder-abc\"\n );\n });\n\n it(\"should set folderId to root when folder is set to null\", () => {\n presenter.init();\n\n // First set a folder.\n runInAction(() => {\n (mocks.folderTreePresenter.vm as any).currentFolderId = \"folder-1\";\n });\n\n // Then clear it.\n runInAction(() => {\n (mocks.folderTreePresenter.vm as any).currentFolderId = null;\n });\n\n expect(mocks.listPresenter.actions.filter.set).toHaveBeenCalledWith(\"folderId\", \"root\");\n });\n\n // -----------------------------------------------------------------------\n // Permission flags forwarded to vm.\n // -----------------------------------------------------------------------\n\n it(\"should expose permission flags in vm.permissions\", () => {\n presenter.init();\n\n expect(presenter.vm.permissions.canRead).toBe(true);\n expect(presenter.vm.permissions.canCreate).toBe(true);\n expect(presenter.vm.permissions.canEdit).toBe(false);\n expect(presenter.vm.permissions.canDelete).toBe(false);\n });\n\n // -----------------------------------------------------------------------\n // View mode persistence via LocalStorage.\n // -----------------------------------------------------------------------\n\n it(\"should default viewMode to 'grid'\", () => {\n expect(presenter.vm.viewMode).toBe(\"grid\");\n });\n\n it(\"should update viewMode and persist to localStorage\", () => {\n presenter.actions.setViewMode(\"grid\");\n\n expect(presenter.vm.viewMode).toBe(\"grid\");\n expect(mocks.localStorage.set).toHaveBeenCalledWith(\"fm:viewMode\", \"grid\");\n });\n\n it(\"should restore viewMode from localStorage on construction\", () => {\n // Pre-seed localStorage with \"grid\" before creating the presenter.\n const seededMocks = createMocks();\n (seededMocks.localStorage.get as ReturnType<typeof vi.fn>).mockReturnValue(\"grid\");\n\n const container = createContainer(seededMocks);\n const seededPresenter: IFileManagerPresenter = container.resolve(Abstraction);\n\n expect(seededPresenter.vm.viewMode).toBe(\"grid\");\n });\n\n // -----------------------------------------------------------------------\n // Upload action.\n // -----------------------------------------------------------------------\n\n it(\"should call fileUploader.uploadMany when actions.upload is called\", async () => {\n presenter.init();\n\n const file1 = {\n id: \"f1\",\n name: \"test.txt\",\n type: \"text/plain\",\n size: 7,\n src: { file: new File([\"content\"], \"test.txt\", { type: \"text/plain\" }), base64: null }\n };\n const file2 = {\n id: \"f2\",\n name: \"photo.png\",\n type: \"image/png\",\n size: 3,\n src: { file: new File([\"img\"], \"photo.png\", { type: \"image/png\" }), base64: null }\n };\n\n await presenter.actions.upload([file1, file2]);\n\n expect(mocks.fileUploader.uploadMany).toHaveBeenCalledTimes(1);\n const args = (mocks.fileUploader.uploadMany as ReturnType<typeof vi.fn>).mock.calls[0][0];\n expect(args).toHaveLength(2);\n expect(args[0].data.name).toBe(\"test.txt\");\n expect(args[0].data.type).toBe(\"text/plain\");\n expect(args[1].data.name).toBe(\"photo.png\");\n expect(args[1].data.type).toBe(\"image/png\");\n });\n\n // -----------------------------------------------------------------------\n // loading: true only during initial load (no rows yet).\n // -----------------------------------------------------------------------\n\n it(\"should be loading when pagination is loading and no rows exist\", () => {\n presenter.init();\n runInAction(() => {\n (mocks.listPresenter.vm as any).rows = [];\n (mocks.listPresenter.vm as any).pagination.loading = true;\n });\n expect(presenter.vm.loading).toBe(true);\n });\n\n it(\"should not be loading when rows already exist\", () => {\n presenter.init();\n runInAction(() => {\n (mocks.listPresenter.vm as any).rows = [{ id: \"file-1\" }];\n (mocks.listPresenter.vm as any).pagination.loading = true;\n });\n expect(presenter.vm.loading).toBe(false);\n });\n\n it(\"should not be loading when pagination is not loading\", () => {\n presenter.init();\n runInAction(() => {\n (mocks.listPresenter.vm as any).rows = [];\n (mocks.listPresenter.vm as any).pagination.loading = false;\n });\n expect(presenter.vm.loading).toBe(false);\n });\n\n // -----------------------------------------------------------------------\n // empty: accounts for both files and child folders.\n // -----------------------------------------------------------------------\n\n it(\"should be empty when no files and no child folders\", () => {\n presenter.init();\n runInAction(() => {\n (mocks.listPresenter.vm as any).rows = [];\n (mocks.listPresenter.vm as any).pagination.loading = false;\n });\n expect(presenter.vm.empty).toBe(true);\n });\n\n it(\"should not be empty when there are files\", () => {\n presenter.init();\n runInAction(() => {\n (mocks.listPresenter.vm as any).rows = [{ id: \"file-1\" }];\n (mocks.listPresenter.vm as any).pagination.loading = false;\n });\n expect(presenter.vm.empty).toBe(false);\n });\n\n it(\"should not be empty when there are child folders but no files\", () => {\n presenter.init();\n runInAction(() => {\n (mocks.listPresenter.vm as any).rows = [];\n (mocks.listPresenter.vm as any).pagination.loading = false;\n (mocks.folderTreePresenter.vm as any).childFolders = [{ id: \"folder-1\" }];\n });\n expect(presenter.vm.empty).toBe(false);\n });\n\n it(\"should not be empty while loading\", () => {\n presenter.init();\n runInAction(() => {\n (mocks.listPresenter.vm as any).rows = [];\n (mocks.listPresenter.vm as any).pagination.loading = true;\n });\n expect(presenter.vm.empty).toBe(false);\n });\n\n it(\"should be empty when child folders exist but folders are hidden (search active)\", () => {\n presenter.init();\n runInAction(() => {\n (mocks.listPresenter.vm as any).rows = [];\n (mocks.listPresenter.vm as any).pagination.loading = false;\n (mocks.listPresenter.vm as any).appliedQuery = {\n search: \"photo\",\n filters: { folderId: \"root\" }\n };\n (mocks.folderTreePresenter.vm as any).childFolders = [{ id: \"folder-1\" }];\n });\n expect(presenter.vm.empty).toBe(true);\n });\n\n // -----------------------------------------------------------------------\n // showFolders computed from appliedQuery.\n // -----------------------------------------------------------------------\n\n it(\"should show folders when appliedQuery is null\", () => {\n presenter.init();\n expect(presenter.vm.showFolders).toBe(true);\n });\n\n it(\"should show folders when appliedQuery has no search and only folderId filter\", () => {\n presenter.init();\n runInAction(() => {\n (mocks.listPresenter.vm as any).appliedQuery = {\n filters: { folderId: \"root\" }\n };\n });\n expect(presenter.vm.showFolders).toBe(true);\n });\n\n it(\"should hide folders when appliedQuery has a search\", () => {\n presenter.init();\n runInAction(() => {\n (mocks.listPresenter.vm as any).appliedQuery = {\n search: \"photo\",\n filters: { folderId: \"root\" }\n };\n });\n expect(presenter.vm.showFolders).toBe(false);\n });\n\n it(\"should hide folders when appliedQuery has non-folderId filters\", () => {\n presenter.init();\n runInAction(() => {\n (mocks.listPresenter.vm as any).appliedQuery = {\n filters: { folderId: \"root\", tags: [\"photo\"] }\n };\n });\n expect(presenter.vm.showFolders).toBe(false);\n });\n\n it(\"should show folders again when appliedQuery filters are cleared\", () => {\n presenter.init();\n runInAction(() => {\n (mocks.listPresenter.vm as any).appliedQuery = {\n filters: { folderId: \"root\", type: \"image\" }\n };\n });\n expect(presenter.vm.showFolders).toBe(false);\n\n runInAction(() => {\n (mocks.listPresenter.vm as any).appliedQuery = {\n filters: { folderId: \"root\" }\n };\n });\n expect(presenter.vm.showFolders).toBe(true);\n });\n});\n"],"names":["createMockListPresenter","vmState","observable","Set","vi","undefined","createMockFolderTreePresenter","state","createMockPermissions","createMockSettingsRepository","data","createMockTagsRepository","createMockFileUploader","createMockLocalStorage","store","Map","key","value","Array","createMockListFilesUseCase","createMockGetDescendantFoldersUseCase","createMockFileDetailsPresenter","createMocks","ListCache","createContainer","mocks","container","Container","ListPresenter","FolderTreePresenter","FileDetailsPresenter","FileManagerPermissions","GetSettingsRepository","ListTagsRepository","FileUploader","LocalStorage","ListFilesUseCase","FilesListCache","GetDescendantFoldersUseCase","FileModelProvider","FileManagerPresenter","describe","presenter","beforeEach","Abstraction","it","expect","config","runInAction","seededMocks","seededPresenter","file1","File","file2","args"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"presentation/FileList/FileListPresenter.test.js","sources":["../../../src/presentation/FileList/FileListPresenter.test.ts"],"sourcesContent":["// @vitest-environment jsdom\nimport { describe, it, expect, vi, beforeEach } from \"vitest\";\nimport { observable, runInAction } from \"mobx\";\nimport { Container } from \"@webiny/di\";\nimport { ListCache } from \"@webiny/app-admin/features/listCache/index.js\";\nimport { ListPresenter } from \"@webiny/app-admin/presentation/listPresenter/abstractions.js\";\nimport { FolderTreePresenter } from \"@webiny/app-aco/presentation/folderTree/abstractions.js\";\nimport { FileManagerPermissions } from \"../../features/permissions/abstractions.js\";\nimport { GetSettingsRepository } from \"../../features/settings/abstractions.js\";\nimport { ListTagsRepository } from \"../../features/tags/abstractions.js\";\nimport { FileUploader } from \"../../features/fileUploader/abstractions.js\";\nimport { LocalStorage } from \"@webiny/app/features/localStorage\";\nimport { ListFilesUseCase } from \"../../features/listFiles/abstractions.js\";\nimport { FilesListCache } from \"../../features/shared/abstractions.js\";\nimport { GetDescendantFoldersUseCase } from \"@webiny/app-aco/features/folders/getDescendantFolders/abstractions.js\";\nimport { FileModelProvider } from \"../../features/fileModel/abstractions.js\";\nimport { FileDetailsPresenter } from \"../FileDetails/abstractions.js\";\nimport type { IFileDetailsPresenter } from \"../FileDetails/abstractions.js\";\nimport { FileManagerPresenter as Abstraction, type IFileManagerPresenter } from \"./abstractions.js\";\nimport { FileManagerPresenter } from \"./FileManagerPresenter.js\";\nimport type { FmFile } from \"../../features/shared/types.js\";\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction createMockListPresenter(): ListPresenter.Interface<FmFile> {\n const vmState = observable({\n rows: [] as FmFile[],\n sort: null as { field: string; direction: \"ASC\" | \"DESC\" } | null,\n filters: {} as Record<string, unknown>,\n search: \"\",\n appliedQuery: null as\n | import(\"@webiny/app-admin/presentation/listPresenter/abstractions.js\").IDataSourceQuery\n | null,\n pagination: {\n hasMore: false,\n loading: false,\n loadingMore: false,\n totalCount: 0,\n currentCount: 0\n },\n selection: {\n selectedIds: new Set<string>(),\n selectedCount: 0,\n allSelected: false,\n label: \"\"\n },\n showingFilters: false,\n empty: true,\n emptyWithFilters: false,\n error: null as\n | import(\"@webiny/app-admin/presentation/listPresenter/abstractions.js\").IListError\n | null\n });\n\n return {\n get vm() {\n return vmState;\n },\n actions: {\n search: { set: vi.fn(), clear: vi.fn() },\n sort: { set: vi.fn(), toggle: vi.fn() },\n filter: {\n set: vi.fn(),\n clear: vi.fn(),\n clearAll: vi.fn(),\n show: vi.fn(),\n hide: vi.fn()\n },\n selection: {\n toggle: vi.fn(),\n selectRangeTo: vi.fn(),\n selectAll: vi.fn(),\n deselectAll: vi.fn(),\n selectRows: vi.fn(),\n isSelected: vi.fn().mockReturnValue(false)\n },\n loadMore: vi.fn().mockResolvedValue(undefined),\n refresh: vi.fn().mockResolvedValue(undefined)\n },\n init: vi.fn()\n };\n}\n\nfunction createMockFolderTreePresenter(): FolderTreePresenter.Interface {\n const state = observable({\n folders: [],\n tree: [],\n currentFolderId: null as string | null,\n currentFolder: null,\n loading: false,\n operation: { active: false, mode: null },\n isRootFolder: true,\n currentFolderTitle: \"All Files\",\n childFolders: [],\n loadingNodeIds: []\n });\n\n return {\n get vm() {\n return state;\n },\n selectFolder: vi.fn(),\n createFolder: vi.fn(),\n editFolder: vi.fn(),\n deleteFolder: vi.fn().mockResolvedValue(undefined),\n moveFolder: vi.fn().mockResolvedValue(undefined),\n loadChildFolders: vi.fn().mockResolvedValue(undefined),\n canManageStructure: vi.fn().mockReturnValue(true),\n getAncestorIds: vi.fn().mockReturnValue([]),\n submitOperation: vi.fn().mockResolvedValue(true),\n cancelOperation: vi.fn(),\n onFolderChange: vi.fn().mockReturnValue(() => {})\n };\n}\n\nfunction createMockPermissions(): FileManagerPermissions.Interface {\n return {\n canAccess: vi.fn().mockReturnValue(true),\n canRead: vi.fn().mockReturnValue(true),\n canCreate: vi.fn().mockReturnValue(true),\n canEdit: vi.fn().mockReturnValue(false),\n canDelete: vi.fn().mockReturnValue(false),\n canAction: vi.fn().mockReturnValue(true)\n } as unknown as FileManagerPermissions.Interface;\n}\n\nfunction createMockSettingsRepository(): GetSettingsRepository.Interface {\n return {\n execute: vi.fn().mockResolvedValue({\n uploadMinFileSize: \"0\",\n uploadMaxFileSize: \"10485760\",\n srcPrefix: \"https://cdn.example.com/\"\n }),\n save: vi.fn().mockImplementation(async (data: Record<string, unknown>) => data),\n settings: null\n };\n}\n\nfunction createMockTagsRepository(): ListTagsRepository.Interface {\n return {\n execute: vi.fn().mockResolvedValue([]),\n tags: [{ tag: \"photo\", count: 5 }]\n };\n}\n\nfunction createMockFileUploader(): FileUploader.Interface {\n return {\n vm: {\n jobs: [],\n overallProgress: { sent: 0, total: 0, percentage: 0 },\n isUploading: false,\n completedCount: 0,\n failedCount: 0\n },\n upload: vi.fn().mockResolvedValue(undefined),\n uploadMany: vi.fn().mockResolvedValue(undefined),\n abort: vi.fn(),\n clear: vi.fn()\n };\n}\n\nfunction createMockLocalStorage(): LocalStorage.Interface {\n const store = new Map<string, unknown>();\n return {\n get: vi.fn((key: string) => store.get(key)) as LocalStorage.Interface[\"get\"],\n set: vi.fn(<T>(key: string, value: T): void => {\n store.set(key, value);\n }),\n remove: vi.fn((key: string) => {\n store.delete(key);\n }),\n clear: vi.fn(() => store.clear()),\n keys: vi.fn(() => Array.from(store.keys()))\n };\n}\n\nfunction createMockListFilesUseCase(): ListFilesUseCase.Interface {\n return {\n execute: vi.fn().mockResolvedValue({\n data: [],\n meta: { cursor: null, hasMoreItems: false, totalCount: 0 }\n })\n };\n}\n\nfunction createMockGetDescendantFoldersUseCase(): GetDescendantFoldersUseCase.Interface {\n return {\n execute: vi.fn().mockReturnValue([])\n };\n}\n\nfunction createMockFileDetailsPresenter(): IFileDetailsPresenter {\n return {\n vm: {\n file: null,\n loading: null,\n form: {\n layout: [],\n errors: [],\n hasErrors: false,\n isDirty: false,\n isValid: null,\n submitCount: 0,\n focusField: vi.fn(),\n getData: vi.fn(() => ({})),\n setData: vi.fn()\n },\n previewUrl: null,\n permissions: { canEdit: true, canDelete: true }\n },\n loadFile: vi.fn().mockResolvedValue(undefined),\n saveFile: vi.fn().mockResolvedValue(undefined),\n setFile: vi.fn()\n };\n}\n\n// ---------------------------------------------------------------------------\n// Container setup\n// ---------------------------------------------------------------------------\n\ninterface Mocks {\n listPresenter: ListPresenter.Interface<FmFile>;\n folderTreePresenter: FolderTreePresenter.Interface;\n fileDetailsPresenter: IFileDetailsPresenter;\n permissions: FileManagerPermissions.Interface;\n settingsRepository: GetSettingsRepository.Interface;\n tagsRepository: ListTagsRepository.Interface;\n fileUploader: FileUploader.Interface;\n localStorage: LocalStorage.Interface;\n listFilesUseCase: ListFilesUseCase.Interface;\n cache: ListCache<FmFile>;\n getDescendantFoldersUseCase: GetDescendantFoldersUseCase.Interface;\n fileModelProvider: FileModelProvider.Interface;\n}\n\nfunction createMocks(): Mocks {\n return {\n listPresenter: createMockListPresenter(),\n folderTreePresenter: createMockFolderTreePresenter(),\n fileDetailsPresenter: createMockFileDetailsPresenter(),\n permissions: createMockPermissions(),\n settingsRepository: createMockSettingsRepository(),\n tagsRepository: createMockTagsRepository(),\n fileUploader: createMockFileUploader(),\n localStorage: createMockLocalStorage(),\n listFilesUseCase: createMockListFilesUseCase(),\n cache: new ListCache<FmFile>(),\n getDescendantFoldersUseCase: createMockGetDescendantFoldersUseCase(),\n fileModelProvider: {\n getModel: vi.fn().mockResolvedValue({ fields: [] })\n }\n };\n}\n\nfunction createContainer(mocks: Mocks) {\n const container = new Container();\n\n container.registerInstance(ListPresenter, mocks.listPresenter);\n container.registerInstance(FolderTreePresenter, mocks.folderTreePresenter);\n container.registerInstance(FileDetailsPresenter, mocks.fileDetailsPresenter);\n container.registerInstance(FileManagerPermissions, mocks.permissions);\n container.registerInstance(GetSettingsRepository, mocks.settingsRepository);\n container.registerInstance(ListTagsRepository, mocks.tagsRepository);\n container.registerInstance(FileUploader, mocks.fileUploader);\n container.registerInstance(LocalStorage, mocks.localStorage);\n container.registerInstance(ListFilesUseCase, mocks.listFilesUseCase);\n container.registerInstance(FilesListCache, mocks.cache);\n container.registerInstance(GetDescendantFoldersUseCase, mocks.getDescendantFoldersUseCase);\n container.registerInstance(FileModelProvider, mocks.fileModelProvider);\n\n // Register the real FileListPresenter implementation.\n container.register(FileManagerPresenter).inSingletonScope();\n\n return container;\n}\n\n// ---------------------------------------------------------------------------\n// Tests\n// ---------------------------------------------------------------------------\n\ndescribe(\"FileListPresenter\", () => {\n let mocks: Mocks;\n let presenter: IFileManagerPresenter;\n\n beforeEach(() => {\n mocks = createMocks();\n const container = createContainer(mocks);\n presenter = container.resolve(Abstraction);\n });\n\n // -----------------------------------------------------------------------\n // Composition: ListPresenter and FolderTreePresenter initialized.\n // -----------------------------------------------------------------------\n\n it(\"should call listPresenter.init with a DataSource and initialSort on init()\", () => {\n presenter.init();\n\n expect(mocks.listPresenter.init).toHaveBeenCalledTimes(1);\n const config = (mocks.listPresenter.init as ReturnType<typeof vi.fn>).mock.calls[0][0];\n expect(config.dataSource).toBeDefined();\n expect(config.initialSort).toEqual({ field: \"createdOn\", direction: \"DESC\" });\n });\n\n it(\"should forward ListPresenter.vm data as vm.list\", () => {\n presenter.init();\n expect(presenter.vm.list.rows).toEqual(mocks.listPresenter.vm.rows);\n expect(presenter.vm.list.sort).toEqual(mocks.listPresenter.vm.sort);\n expect(presenter.vm.list.search).toBe(mocks.listPresenter.vm.search);\n expect(presenter.vm.list.empty).toBe(mocks.listPresenter.vm.empty);\n });\n\n it(\"should forward FolderTreePresenter.vm as vm.folders\", () => {\n presenter.init();\n expect(presenter.vm.folders).toBe(mocks.folderTreePresenter.vm);\n });\n\n // -----------------------------------------------------------------------\n // Folder change wiring.\n // -----------------------------------------------------------------------\n\n it(\"should set folderId filter when folder changes\", async () => {\n presenter.init();\n\n // Simulate folder selection via MobX observable change.\n runInAction(() => {\n (mocks.folderTreePresenter.vm as any).currentFolderId = \"folder-abc\";\n });\n\n // MobX reaction fires synchronously in the same tick after runInAction.\n expect(mocks.listPresenter.actions.filter.set).toHaveBeenCalledWith(\n \"folderId\",\n \"folder-abc\"\n );\n });\n\n it(\"should set folderId to root when folder is set to null\", () => {\n presenter.init();\n\n // First set a folder.\n runInAction(() => {\n (mocks.folderTreePresenter.vm as any).currentFolderId = \"folder-1\";\n });\n\n // Then clear it.\n runInAction(() => {\n (mocks.folderTreePresenter.vm as any).currentFolderId = null;\n });\n\n expect(mocks.listPresenter.actions.filter.set).toHaveBeenCalledWith(\"folderId\", \"root\");\n });\n\n // -----------------------------------------------------------------------\n // Permission flags forwarded to vm.\n // -----------------------------------------------------------------------\n\n it(\"should expose permission flags in vm.permissions\", () => {\n presenter.init();\n\n expect(presenter.vm.permissions.canRead).toBe(true);\n expect(presenter.vm.permissions.canCreate).toBe(true);\n expect(presenter.vm.permissions.canEdit).toBe(false);\n expect(presenter.vm.permissions.canDelete).toBe(false);\n });\n\n // -----------------------------------------------------------------------\n // View mode persistence via LocalStorage.\n // -----------------------------------------------------------------------\n\n it(\"should default viewMode to 'grid'\", () => {\n expect(presenter.vm.viewMode).toBe(\"grid\");\n });\n\n it(\"should update viewMode and persist to localStorage\", () => {\n presenter.actions.setViewMode(\"grid\");\n\n expect(presenter.vm.viewMode).toBe(\"grid\");\n expect(mocks.localStorage.set).toHaveBeenCalledWith(\"fm:viewMode\", \"grid\");\n });\n\n it(\"should restore viewMode from localStorage on construction\", () => {\n // Pre-seed localStorage with \"grid\" before creating the presenter.\n const seededMocks = createMocks();\n (seededMocks.localStorage.get as ReturnType<typeof vi.fn>).mockReturnValue(\"grid\");\n\n const container = createContainer(seededMocks);\n const seededPresenter: IFileManagerPresenter = container.resolve(Abstraction);\n\n expect(seededPresenter.vm.viewMode).toBe(\"grid\");\n });\n\n // -----------------------------------------------------------------------\n // Upload action.\n // -----------------------------------------------------------------------\n\n it(\"should call fileUploader.uploadMany when actions.upload is called\", async () => {\n presenter.init();\n\n const file1 = {\n id: \"f1\",\n name: \"test.txt\",\n type: \"text/plain\",\n size: 7,\n src: { file: new File([\"content\"], \"test.txt\", { type: \"text/plain\" }), base64: null }\n };\n const file2 = {\n id: \"f2\",\n name: \"photo.png\",\n type: \"image/png\",\n size: 3,\n src: { file: new File([\"img\"], \"photo.png\", { type: \"image/png\" }), base64: null }\n };\n\n await presenter.actions.upload([file1, file2]);\n\n expect(mocks.fileUploader.uploadMany).toHaveBeenCalledTimes(1);\n const args = (mocks.fileUploader.uploadMany as ReturnType<typeof vi.fn>).mock.calls[0][0];\n expect(args).toHaveLength(2);\n expect(args[0].data.name).toBe(\"test.txt\");\n expect(args[0].data.type).toBe(\"text/plain\");\n expect(args[1].data.name).toBe(\"photo.png\");\n expect(args[1].data.type).toBe(\"image/png\");\n });\n\n // -----------------------------------------------------------------------\n // loading: true only during initial load (no rows yet).\n // -----------------------------------------------------------------------\n\n it(\"should be loading when pagination is loading and no rows exist\", () => {\n presenter.init();\n runInAction(() => {\n (mocks.listPresenter.vm as any).rows = [];\n (mocks.listPresenter.vm as any).pagination.loading = true;\n });\n expect(presenter.vm.loading).toBe(true);\n });\n\n it(\"should not be loading when rows already exist\", () => {\n presenter.init();\n runInAction(() => {\n (mocks.listPresenter.vm as any).rows = [{ id: \"file-1\" }];\n (mocks.listPresenter.vm as any).pagination.loading = true;\n });\n expect(presenter.vm.loading).toBe(false);\n });\n\n it(\"should not be loading when pagination is not loading\", () => {\n presenter.init();\n runInAction(() => {\n (mocks.listPresenter.vm as any).rows = [];\n (mocks.listPresenter.vm as any).pagination.loading = false;\n });\n expect(presenter.vm.loading).toBe(false);\n });\n\n // -----------------------------------------------------------------------\n // empty: accounts for both files and child folders.\n // -----------------------------------------------------------------------\n\n it(\"should be empty when no files and no child folders\", () => {\n presenter.init();\n runInAction(() => {\n (mocks.listPresenter.vm as any).rows = [];\n (mocks.listPresenter.vm as any).pagination.loading = false;\n });\n expect(presenter.vm.empty).toBe(true);\n });\n\n it(\"should not be empty when there are files\", () => {\n presenter.init();\n runInAction(() => {\n (mocks.listPresenter.vm as any).rows = [{ id: \"file-1\" }];\n (mocks.listPresenter.vm as any).pagination.loading = false;\n });\n expect(presenter.vm.empty).toBe(false);\n });\n\n it(\"should not be empty when there are child folders but no files\", () => {\n presenter.init();\n runInAction(() => {\n (mocks.listPresenter.vm as any).rows = [];\n (mocks.listPresenter.vm as any).pagination.loading = false;\n (mocks.folderTreePresenter.vm as any).childFolders = [{ id: \"folder-1\" }];\n });\n expect(presenter.vm.empty).toBe(false);\n });\n\n it(\"should not be empty while loading\", () => {\n presenter.init();\n runInAction(() => {\n (mocks.listPresenter.vm as any).rows = [];\n (mocks.listPresenter.vm as any).pagination.loading = true;\n });\n expect(presenter.vm.empty).toBe(false);\n });\n\n it(\"should be empty when child folders exist but folders are hidden (search active)\", () => {\n presenter.init();\n runInAction(() => {\n (mocks.listPresenter.vm as any).rows = [];\n (mocks.listPresenter.vm as any).pagination.loading = false;\n (mocks.listPresenter.vm as any).appliedQuery = {\n search: \"photo\",\n filters: { folderId: \"root\" }\n };\n (mocks.folderTreePresenter.vm as any).childFolders = [{ id: \"folder-1\" }];\n });\n expect(presenter.vm.empty).toBe(true);\n });\n\n // -----------------------------------------------------------------------\n // showFolders computed from appliedQuery.\n // -----------------------------------------------------------------------\n\n it(\"should show folders when appliedQuery is null\", () => {\n presenter.init();\n expect(presenter.vm.showFolders).toBe(true);\n });\n\n it(\"should show folders when appliedQuery has no search and only folderId filter\", () => {\n presenter.init();\n runInAction(() => {\n (mocks.listPresenter.vm as any).appliedQuery = {\n filters: { folderId: \"root\" }\n };\n });\n expect(presenter.vm.showFolders).toBe(true);\n });\n\n it(\"should hide folders when appliedQuery has a search\", () => {\n presenter.init();\n runInAction(() => {\n (mocks.listPresenter.vm as any).appliedQuery = {\n search: \"photo\",\n filters: { folderId: \"root\" }\n };\n });\n expect(presenter.vm.showFolders).toBe(false);\n });\n\n it(\"should hide folders when appliedQuery has non-folderId filters\", () => {\n presenter.init();\n runInAction(() => {\n (mocks.listPresenter.vm as any).appliedQuery = {\n filters: { folderId: \"root\", tags: [\"photo\"] }\n };\n });\n expect(presenter.vm.showFolders).toBe(false);\n });\n\n it(\"should show folders again when appliedQuery filters are cleared\", () => {\n presenter.init();\n runInAction(() => {\n (mocks.listPresenter.vm as any).appliedQuery = {\n filters: { folderId: \"root\", type: \"image\" }\n };\n });\n expect(presenter.vm.showFolders).toBe(false);\n\n runInAction(() => {\n (mocks.listPresenter.vm as any).appliedQuery = {\n filters: { folderId: \"root\" }\n };\n });\n expect(presenter.vm.showFolders).toBe(true);\n });\n});\n"],"names":["createMockListPresenter","vmState","observable","Set","vi","undefined","createMockFolderTreePresenter","state","createMockPermissions","createMockSettingsRepository","data","createMockTagsRepository","createMockFileUploader","createMockLocalStorage","store","Map","key","value","Array","createMockListFilesUseCase","createMockGetDescendantFoldersUseCase","createMockFileDetailsPresenter","createMocks","ListCache","createContainer","mocks","container","Container","ListPresenter","FolderTreePresenter","FileDetailsPresenter","FileManagerPermissions","GetSettingsRepository","ListTagsRepository","FileUploader","LocalStorage","ListFilesUseCase","FilesListCache","GetDescendantFoldersUseCase","FileModelProvider","FileManagerPresenter","describe","presenter","beforeEach","Abstraction","it","expect","config","runInAction","seededMocks","seededPresenter","file1","File","file2","args"],"mappings":"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"}
|
|
@@ -37,6 +37,7 @@ declare class FileManagerPresenterImpl implements IFileManagerPresenter {
|
|
|
37
37
|
dispose(): void;
|
|
38
38
|
private isLoading;
|
|
39
39
|
private isEmpty;
|
|
40
|
+
private getSortedChildFolders;
|
|
40
41
|
private shouldShowFolders;
|
|
41
42
|
}
|
|
42
43
|
export declare const FileManagerPresenter: typeof FileManagerPresenterImpl & {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { computed, makeAutoObservable, reaction, runInAction } from "mobx";
|
|
2
2
|
import { ListPresenter } from "@webiny/app-admin/presentation/listPresenter/abstractions.js";
|
|
3
3
|
import { FolderTreePresenter } from "@webiny/app-aco/presentation/folderTree/abstractions.js";
|
|
4
|
+
import { sortFolders } from "@webiny/app-aco";
|
|
4
5
|
import { LocalStorage } from "@webiny/app/features/localStorage";
|
|
5
6
|
import { GetDescendantFoldersUseCase } from "@webiny/app-aco/features/folders/getDescendantFolders/abstractions.js";
|
|
6
7
|
import { FileManagerPresenter } from "./abstractions.js";
|
|
@@ -46,7 +47,9 @@ class FileManagerPresenterImpl {
|
|
|
46
47
|
filter: {
|
|
47
48
|
set: (key, value)=>this.listPresenter.actions.filter.set(key, value),
|
|
48
49
|
clear: (key)=>this.listPresenter.actions.filter.clear(key),
|
|
49
|
-
clearAll: ()=>this.listPresenter.actions.filter.clearAll()
|
|
50
|
+
clearAll: ()=>this.listPresenter.actions.filter.clearAll(),
|
|
51
|
+
show: ()=>this.listPresenter.actions.filter.show(),
|
|
52
|
+
hide: ()=>this.listPresenter.actions.filter.hide()
|
|
50
53
|
},
|
|
51
54
|
selection: {
|
|
52
55
|
toggle: (id)=>this.listPresenter.actions.selection.toggle(id),
|
|
@@ -146,6 +149,7 @@ class FileManagerPresenterImpl {
|
|
|
146
149
|
loading: this.isLoading(),
|
|
147
150
|
empty: this.isEmpty(),
|
|
148
151
|
showFolders: this.shouldShowFolders(),
|
|
152
|
+
childFolders: this.getSortedChildFolders(),
|
|
149
153
|
viewMode: this._viewMode,
|
|
150
154
|
dragging: this._dragging,
|
|
151
155
|
showingFilters: this._showingFilters
|
|
@@ -155,15 +159,17 @@ class FileManagerPresenterImpl {
|
|
|
155
159
|
const initialFolderId = config?.initialFolderId ?? this.localStorage.get(LAST_FOLDER_KEY) ?? "root";
|
|
156
160
|
this._persistFolder = !config?.initialFolderId;
|
|
157
161
|
const dataSource = new FileListDataSource(this.listFilesUseCase, this.filesListCache, this.getDescendantFoldersUseCase, config?.scope);
|
|
162
|
+
const initialFilters = {
|
|
163
|
+
folderId: initialFolderId
|
|
164
|
+
};
|
|
165
|
+
if (config?.accept && config.accept.length > 0) initialFilters["accept"] = config.accept;
|
|
158
166
|
this.listPresenter.init({
|
|
159
167
|
dataSource,
|
|
160
168
|
initialSort: {
|
|
161
169
|
field: "createdOn",
|
|
162
170
|
direction: "DESC"
|
|
163
171
|
},
|
|
164
|
-
initialFilters
|
|
165
|
-
folderId: initialFolderId
|
|
166
|
-
},
|
|
172
|
+
initialFilters,
|
|
167
173
|
limit: 50
|
|
168
174
|
});
|
|
169
175
|
if ("root" !== initialFolderId) this.folderTreePresenter.selectFolder(initialFolderId);
|
|
@@ -194,11 +200,15 @@ class FileManagerPresenterImpl {
|
|
|
194
200
|
if (this.shouldShowFolders() && this.folderTreePresenter.vm.childFolders.length > 0) return false;
|
|
195
201
|
return true;
|
|
196
202
|
}
|
|
203
|
+
getSortedChildFolders() {
|
|
204
|
+
if (!this.shouldShowFolders()) return [];
|
|
205
|
+
return sortFolders(this.folderTreePresenter.vm.childFolders ?? [], this.listPresenter.vm.appliedQuery?.sort);
|
|
206
|
+
}
|
|
197
207
|
shouldShowFolders() {
|
|
198
208
|
const { appliedQuery } = this.listPresenter.vm;
|
|
199
209
|
if (!appliedQuery) return true;
|
|
200
210
|
if (appliedQuery.search) return false;
|
|
201
|
-
const filterKeys = Object.keys(appliedQuery.filters ?? {}).filter((k)=>"folderId" !== k);
|
|
211
|
+
const filterKeys = Object.keys(appliedQuery.filters ?? {}).filter((k)=>"folderId" !== k && "accept" !== k);
|
|
202
212
|
if (filterKeys.length > 0) return false;
|
|
203
213
|
return true;
|
|
204
214
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presentation/FileList/FileManagerPresenter.js","sources":["../../../src/presentation/FileList/FileManagerPresenter.ts"],"sourcesContent":["import { makeAutoObservable, reaction, runInAction, computed } from \"mobx\";\nimport type { FmFile } from \"@webiny/sdk\";\nimport type { CmsModel } from \"@webiny/app-headless-cms-common/types/index.js\";\nimport { ListPresenter } from \"@webiny/app-admin/presentation/listPresenter/abstractions.js\";\nimport { FolderTreePresenter } from \"@webiny/app-aco/presentation/folderTree/abstractions.js\";\nimport { LocalStorage } from \"@webiny/app/features/localStorage\";\nimport { GetDescendantFoldersUseCase } from \"@webiny/app-aco/features/folders/getDescendantFolders/abstractions.js\";\nimport {\n FileManagerPresenter as Abstraction,\n type IFileManagerPresenter,\n type IFileManagerViewModel,\n type IFileManagerActions,\n type IFileManagerInitConfig\n} from \"./abstractions.js\";\nimport { FileListDataSource } from \"./FileListDataSource.js\";\nimport { FileDetailsPresenter } from \"../FileDetails/abstractions.js\";\nimport { FileManagerPermissions } from \"~/features/permissions/abstractions.js\";\nimport { ListTagsRepository } from \"~/features/tags/index.js\";\nimport { FileUploader } from \"~/features/fileUploader/index.js\";\nimport { ListFilesUseCase } from \"~/features/listFiles/index.js\";\nimport { FilesListCache } from \"~/features/shared/index.js\";\nimport { FileModelProvider } from \"~/features/fileModel/index.js\";\nimport type { IFileDetailsPresenter } from \"../FileDetails/abstractions.js\";\nimport type { SelectedFile } from \"@webiny/app-admin/presentation/browserFilePicker/index.js\";\n\nconst VIEW_MODE_KEY = \"fm:viewMode\";\nconst LAST_FOLDER_KEY = \"fm:lastFolder\";\n\nclass FileManagerPresenterImpl implements IFileManagerPresenter {\n private _viewMode: \"table\" | \"grid\" = \"grid\";\n private _dragging = false;\n private _disposeReaction: (() => void) | null = null;\n private _fileDetails: IFileDetailsPresenter | null = null;\n private _showingFilters = false;\n private _fileModel: CmsModel | null = null;\n private _persistFolder = true;\n\n constructor(\n private listPresenter: ListPresenter.Interface<FmFile>,\n private folderTreePresenter: FolderTreePresenter.Interface,\n private fileDetailsPresenter: FileDetailsPresenter.Interface,\n private permissions: FileManagerPermissions.Interface,\n private tagsRepository: ListTagsRepository.Interface,\n private fileUploader: FileUploader.Interface,\n private localStorage: LocalStorage.Interface,\n private listFilesUseCase: ListFilesUseCase.Interface,\n private filesListCache: FilesListCache.Interface,\n private getDescendantFoldersUseCase: GetDescendantFoldersUseCase.Interface,\n private fileModelProvider: FileModelProvider.Interface\n ) {\n makeAutoObservable<\n FileManagerPresenterImpl,\n \"_disposeReaction\" | \"fileDetailsPresenter\" | \"_persistFolder\"\n >(this, {\n _disposeReaction: false,\n fileDetailsPresenter: false,\n _persistFolder: false,\n vm: computed\n });\n\n const stored = this.localStorage.get<\"table\" | \"grid\">(VIEW_MODE_KEY);\n if (stored === \"table\" || stored === \"grid\") {\n this._viewMode = stored;\n }\n }\n\n get vm(): IFileManagerViewModel {\n return {\n fileModel: this._fileModel,\n list: this.listPresenter.vm,\n folders: this.folderTreePresenter.vm,\n fileDetails: this._fileDetails,\n // Flat booleans for UI visibility (e.g., show/hide buttons).\n // Per-file methods for ownership-aware checks (e.g., \"own\" scope).\n permissions: {\n canRead: this.permissions.canRead(\"file\"),\n canCreate: this.permissions.canCreate(\"file\"),\n canEdit: this.permissions.canEdit(\"file\"),\n canDelete: this.permissions.canDelete(\"file\"),\n canEditFile: (file: FmFile) => this.permissions.canEdit(\"file\", file),\n canDeleteFile: (file: FmFile) => this.permissions.canDelete(\"file\", file)\n },\n upload: {\n jobs: this.fileUploader.vm.jobs,\n overallProgress: {\n percentage: this.fileUploader.vm.overallProgress.percentage,\n bytesSent: this.fileUploader.vm.overallProgress.sent,\n totalBytes: this.fileUploader.vm.overallProgress.total\n },\n isUploading: this.fileUploader.vm.isUploading\n },\n tags: this.tagsRepository.tags,\n loading: this.isLoading(),\n empty: this.isEmpty(),\n showFolders: this.shouldShowFolders(),\n viewMode: this._viewMode,\n dragging: this._dragging,\n showingFilters: this._showingFilters\n };\n }\n\n actions: IFileManagerActions = {\n search: {\n set: (query: string) => this.listPresenter.actions.search.set(query),\n clear: () => this.listPresenter.actions.search.clear()\n },\n sort: {\n set: (field: string, direction: \"ASC\" | \"DESC\") =>\n this.listPresenter.actions.sort.set(field, direction),\n toggle: (field: string) => this.listPresenter.actions.sort.toggle(field)\n },\n filter: {\n set: (key: string, value: unknown) => this.listPresenter.actions.filter.set(key, value),\n clear: (key: string) => this.listPresenter.actions.filter.clear(key),\n clearAll: () => this.listPresenter.actions.filter.clearAll()\n },\n selection: {\n toggle: (id: string) => this.listPresenter.actions.selection.toggle(id),\n selectRangeTo: (id: string) => this.listPresenter.actions.selection.selectRangeTo(id),\n selectAll: () => this.listPresenter.actions.selection.selectAll(),\n deselectAll: () => this.listPresenter.actions.selection.deselectAll(),\n selectRows: (ids: string[]) => this.listPresenter.actions.selection.selectRows(ids),\n isSelected: (id: string) => this.listPresenter.actions.selection.isSelected(id)\n },\n loadMore: () => this.listPresenter.actions.loadMore(),\n refresh: () => this.listPresenter.actions.refresh(),\n upload: async (files: SelectedFile[]) => {\n const folderId = this.folderTreePresenter.vm.currentFolderId ?? \"root\";\n await this.fileUploader.uploadMany(\n files.map(file => ({\n file: file.src.file,\n data: {\n name: file.name,\n type: file.type,\n location: { folderId }\n }\n }))\n );\n this.fileUploader.clear();\n },\n setViewMode: (mode: \"table\" | \"grid\") => {\n this._viewMode = mode;\n this.localStorage.set(VIEW_MODE_KEY, mode);\n },\n setDragging: (dragging: boolean) => {\n this._dragging = dragging;\n },\n showFilters: () => {\n this._showingFilters = true;\n },\n hideFilters: () => {\n this._showingFilters = false;\n },\n showFileDetails: (id: string) => {\n this._fileDetails = this.fileDetailsPresenter;\n void this.fileDetailsPresenter.loadFile(id);\n },\n hideFileDetails: () => {\n this._fileDetails = null;\n },\n folders: {\n // Clear search when navigating to a folder — gives the user a clean slate.\n selectFolder: (folderId: string | null) => {\n this.listPresenter.actions.search.clear();\n this.folderTreePresenter.selectFolder(folderId);\n },\n createFolder: (parentFolderId?: string) =>\n this.folderTreePresenter.createFolder(parentFolderId),\n editFolder: (folderId: string) => this.folderTreePresenter.editFolder(folderId),\n deleteFolder: (folderId: string) => this.folderTreePresenter.deleteFolder(folderId),\n moveFolder: (folderId: string, targetParentId: string | null) =>\n this.folderTreePresenter.moveFolder(folderId, targetParentId),\n loadChildFolders: (parentIds: string[]) =>\n this.folderTreePresenter.loadChildFolders(parentIds),\n canManageStructure: (folderId: string) =>\n this.folderTreePresenter.canManageStructure(folderId),\n getAncestorIds: (folderId: string) => this.folderTreePresenter.getAncestorIds(folderId),\n submitOperation: () => this.folderTreePresenter.submitOperation(),\n cancelOperation: () => {\n this.folderTreePresenter.cancelOperation();\n }\n }\n };\n\n init(config?: IFileManagerInitConfig): void {\n const initialFolderId =\n config?.initialFolderId ?? this.localStorage.get<string>(LAST_FOLDER_KEY) ?? \"root\";\n\n // Don't persist folder navigation when an explicit initial folder is provided (e.g., overlay).\n this._persistFolder = !config?.initialFolderId;\n\n const dataSource = new FileListDataSource(\n this.listFilesUseCase,\n this.filesListCache,\n this.getDescendantFoldersUseCase,\n config?.scope\n );\n\n this.listPresenter.init({\n dataSource,\n initialSort: { field: \"createdOn\", direction: \"DESC\" },\n initialFilters: { folderId: initialFolderId },\n limit: 50\n });\n\n if (initialFolderId !== \"root\") {\n this.folderTreePresenter.selectFolder(initialFolderId);\n }\n\n // Sync folder navigation → file list: when the user selects a folder in the tree,\n // update the folderId filter so the file list re-queries for that folder's contents.\n this._disposeReaction = reaction(\n () => this.folderTreePresenter.vm.currentFolderId,\n folderId => {\n const effectiveFolderId = folderId ?? \"root\";\n this.listPresenter.actions.filter.set(\"folderId\", effectiveFolderId);\n\n if (this._persistFolder) {\n this.localStorage.set(LAST_FOLDER_KEY, effectiveFolderId);\n }\n }\n );\n\n void this.tagsRepository.execute({});\n\n // Load the CMS model in the background. The FileModelModule already kicks off\n // loading at app startup, so this usually resolves from cache instantly.\n // The view shows a loading overlay until `_fileModel` is set.\n void this.fileModelProvider.getModel().then(model => {\n runInAction(() => {\n this._fileModel = model;\n });\n });\n }\n\n dispose(): void {\n if (this._disposeReaction) {\n this._disposeReaction();\n this._disposeReaction = null;\n }\n }\n\n private isLoading(): boolean {\n return this.listPresenter.vm.pagination.loading && this.listPresenter.vm.rows.length === 0;\n }\n\n private isEmpty(): boolean {\n if (this.listPresenter.vm.pagination.loading) {\n return false;\n }\n\n if (this.listPresenter.vm.rows.length > 0) {\n return false;\n }\n\n if (this.shouldShowFolders() && this.folderTreePresenter.vm.childFolders.length > 0) {\n return false;\n }\n\n return true;\n }\n\n // Hide folders when the user is actively filtering or searching.\n // Uses `appliedQuery` (not `vm.search`) so folders stay visible while typing\n // and only disappear once the debounced query has actually executed.\n private shouldShowFolders(): boolean {\n const { appliedQuery } = this.listPresenter.vm;\n if (!appliedQuery) {\n return true;\n }\n\n if (appliedQuery.search) {\n return false;\n }\n\n // `folderId` is always present as a default filter; ignore it.\n const filterKeys = Object.keys(appliedQuery.filters ?? {}).filter(k => k !== \"folderId\");\n if (filterKeys.length > 0) {\n return false;\n }\n\n return true;\n }\n}\n\nexport const FileManagerPresenter = Abstraction.createImplementation({\n implementation: FileManagerPresenterImpl,\n dependencies: [\n ListPresenter,\n FolderTreePresenter,\n FileDetailsPresenter,\n FileManagerPermissions,\n ListTagsRepository,\n FileUploader,\n LocalStorage,\n ListFilesUseCase,\n FilesListCache,\n GetDescendantFoldersUseCase,\n FileModelProvider\n ]\n});\n"],"names":["VIEW_MODE_KEY","LAST_FOLDER_KEY","FileManagerPresenterImpl","listPresenter","folderTreePresenter","fileDetailsPresenter","permissions","tagsRepository","fileUploader","localStorage","listFilesUseCase","filesListCache","getDescendantFoldersUseCase","fileModelProvider","query","field","direction","key","value","id","ids","files","folderId","file","mode","dragging","parentFolderId","targetParentId","parentIds","makeAutoObservable","computed","stored","config","initialFolderId","dataSource","FileListDataSource","reaction","effectiveFolderId","model","runInAction","appliedQuery","filterKeys","Object","k","FileManagerPresenter","Abstraction","ListPresenter","FolderTreePresenter","FileDetailsPresenter","FileManagerPermissions","ListTagsRepository","FileUploader","LocalStorage","ListFilesUseCase","FilesListCache","GetDescendantFoldersUseCase","FileModelProvider"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"presentation/FileList/FileManagerPresenter.js","sources":["../../../src/presentation/FileList/FileManagerPresenter.ts"],"sourcesContent":["import { makeAutoObservable, reaction, runInAction, computed } from \"mobx\";\nimport type { FmFile } from \"@webiny/sdk\";\nimport type { CmsModel } from \"@webiny/app-headless-cms-common/types/index.js\";\nimport { ListPresenter } from \"@webiny/app-admin/presentation/listPresenter/abstractions.js\";\nimport { FolderTreePresenter } from \"@webiny/app-aco/presentation/folderTree/abstractions.js\";\nimport { sortFolders } from \"@webiny/app-aco\";\nimport { LocalStorage } from \"@webiny/app/features/localStorage\";\nimport { GetDescendantFoldersUseCase } from \"@webiny/app-aco/features/folders/getDescendantFolders/abstractions.js\";\nimport {\n FileManagerPresenter as Abstraction,\n type IFileManagerPresenter,\n type IFileManagerViewModel,\n type IFileManagerActions,\n type IFileManagerInitConfig\n} from \"./abstractions.js\";\nimport { FileListDataSource } from \"./FileListDataSource.js\";\nimport { FileDetailsPresenter } from \"../FileDetails/abstractions.js\";\nimport { FileManagerPermissions } from \"~/features/permissions/abstractions.js\";\nimport { ListTagsRepository } from \"~/features/tags/index.js\";\nimport { FileUploader } from \"~/features/fileUploader/index.js\";\nimport { ListFilesUseCase } from \"~/features/listFiles/index.js\";\nimport { FilesListCache } from \"~/features/shared/index.js\";\nimport { FileModelProvider } from \"~/features/fileModel/index.js\";\nimport type { IFileDetailsPresenter } from \"../FileDetails/abstractions.js\";\nimport type { SelectedFile } from \"@webiny/app-admin/presentation/browserFilePicker/index.js\";\n\nconst VIEW_MODE_KEY = \"fm:viewMode\";\nconst LAST_FOLDER_KEY = \"fm:lastFolder\";\n\nclass FileManagerPresenterImpl implements IFileManagerPresenter {\n private _viewMode: \"table\" | \"grid\" = \"grid\";\n private _dragging = false;\n private _disposeReaction: (() => void) | null = null;\n private _fileDetails: IFileDetailsPresenter | null = null;\n private _showingFilters = false;\n private _fileModel: CmsModel | null = null;\n private _persistFolder = true;\n\n constructor(\n private listPresenter: ListPresenter.Interface<FmFile>,\n private folderTreePresenter: FolderTreePresenter.Interface,\n private fileDetailsPresenter: FileDetailsPresenter.Interface,\n private permissions: FileManagerPermissions.Interface,\n private tagsRepository: ListTagsRepository.Interface,\n private fileUploader: FileUploader.Interface,\n private localStorage: LocalStorage.Interface,\n private listFilesUseCase: ListFilesUseCase.Interface,\n private filesListCache: FilesListCache.Interface,\n private getDescendantFoldersUseCase: GetDescendantFoldersUseCase.Interface,\n private fileModelProvider: FileModelProvider.Interface\n ) {\n makeAutoObservable<\n FileManagerPresenterImpl,\n \"_disposeReaction\" | \"fileDetailsPresenter\" | \"_persistFolder\"\n >(this, {\n _disposeReaction: false,\n fileDetailsPresenter: false,\n _persistFolder: false,\n vm: computed\n });\n\n const stored = this.localStorage.get<\"table\" | \"grid\">(VIEW_MODE_KEY);\n if (stored === \"table\" || stored === \"grid\") {\n this._viewMode = stored;\n }\n }\n\n get vm(): IFileManagerViewModel {\n return {\n fileModel: this._fileModel,\n list: this.listPresenter.vm,\n folders: this.folderTreePresenter.vm,\n fileDetails: this._fileDetails,\n // Flat booleans for UI visibility (e.g., show/hide buttons).\n // Per-file methods for ownership-aware checks (e.g., \"own\" scope).\n permissions: {\n canRead: this.permissions.canRead(\"file\"),\n canCreate: this.permissions.canCreate(\"file\"),\n canEdit: this.permissions.canEdit(\"file\"),\n canDelete: this.permissions.canDelete(\"file\"),\n canEditFile: (file: FmFile) => this.permissions.canEdit(\"file\", file),\n canDeleteFile: (file: FmFile) => this.permissions.canDelete(\"file\", file)\n },\n upload: {\n jobs: this.fileUploader.vm.jobs,\n overallProgress: {\n percentage: this.fileUploader.vm.overallProgress.percentage,\n bytesSent: this.fileUploader.vm.overallProgress.sent,\n totalBytes: this.fileUploader.vm.overallProgress.total\n },\n isUploading: this.fileUploader.vm.isUploading\n },\n tags: this.tagsRepository.tags,\n loading: this.isLoading(),\n empty: this.isEmpty(),\n showFolders: this.shouldShowFolders(),\n childFolders: this.getSortedChildFolders(),\n viewMode: this._viewMode,\n dragging: this._dragging,\n showingFilters: this._showingFilters\n };\n }\n\n actions: IFileManagerActions = {\n search: {\n set: (query: string) => this.listPresenter.actions.search.set(query),\n clear: () => this.listPresenter.actions.search.clear()\n },\n sort: {\n set: (field: string, direction: \"ASC\" | \"DESC\") =>\n this.listPresenter.actions.sort.set(field, direction),\n toggle: (field: string) => this.listPresenter.actions.sort.toggle(field)\n },\n filter: {\n set: (key: string, value: unknown) => this.listPresenter.actions.filter.set(key, value),\n clear: (key: string) => this.listPresenter.actions.filter.clear(key),\n clearAll: () => this.listPresenter.actions.filter.clearAll(),\n show: () => this.listPresenter.actions.filter.show(),\n hide: () => this.listPresenter.actions.filter.hide()\n },\n selection: {\n toggle: (id: string) => this.listPresenter.actions.selection.toggle(id),\n selectRangeTo: (id: string) => this.listPresenter.actions.selection.selectRangeTo(id),\n selectAll: () => this.listPresenter.actions.selection.selectAll(),\n deselectAll: () => this.listPresenter.actions.selection.deselectAll(),\n selectRows: (ids: string[]) => this.listPresenter.actions.selection.selectRows(ids),\n isSelected: (id: string) => this.listPresenter.actions.selection.isSelected(id)\n },\n loadMore: () => this.listPresenter.actions.loadMore(),\n refresh: () => this.listPresenter.actions.refresh(),\n upload: async (files: SelectedFile[]) => {\n const folderId = this.folderTreePresenter.vm.currentFolderId ?? \"root\";\n await this.fileUploader.uploadMany(\n files.map(file => ({\n file: file.src.file,\n data: {\n name: file.name,\n type: file.type,\n location: { folderId }\n }\n }))\n );\n this.fileUploader.clear();\n },\n setViewMode: (mode: \"table\" | \"grid\") => {\n this._viewMode = mode;\n this.localStorage.set(VIEW_MODE_KEY, mode);\n },\n setDragging: (dragging: boolean) => {\n this._dragging = dragging;\n },\n showFilters: () => {\n this._showingFilters = true;\n },\n hideFilters: () => {\n this._showingFilters = false;\n },\n showFileDetails: (id: string) => {\n this._fileDetails = this.fileDetailsPresenter;\n void this.fileDetailsPresenter.loadFile(id);\n },\n hideFileDetails: () => {\n this._fileDetails = null;\n },\n folders: {\n // Clear search when navigating to a folder — gives the user a clean slate.\n selectFolder: (folderId: string | null) => {\n this.listPresenter.actions.search.clear();\n this.folderTreePresenter.selectFolder(folderId);\n },\n createFolder: (parentFolderId?: string) =>\n this.folderTreePresenter.createFolder(parentFolderId),\n editFolder: (folderId: string) => this.folderTreePresenter.editFolder(folderId),\n deleteFolder: (folderId: string) => this.folderTreePresenter.deleteFolder(folderId),\n moveFolder: (folderId: string, targetParentId: string | null) =>\n this.folderTreePresenter.moveFolder(folderId, targetParentId),\n loadChildFolders: (parentIds: string[]) =>\n this.folderTreePresenter.loadChildFolders(parentIds),\n canManageStructure: (folderId: string) =>\n this.folderTreePresenter.canManageStructure(folderId),\n getAncestorIds: (folderId: string) => this.folderTreePresenter.getAncestorIds(folderId),\n submitOperation: () => this.folderTreePresenter.submitOperation(),\n cancelOperation: () => {\n this.folderTreePresenter.cancelOperation();\n }\n }\n };\n\n init(config?: IFileManagerInitConfig): void {\n const initialFolderId =\n config?.initialFolderId ?? this.localStorage.get<string>(LAST_FOLDER_KEY) ?? \"root\";\n\n // Don't persist folder navigation when an explicit initial folder is provided (e.g., overlay).\n this._persistFolder = !config?.initialFolderId;\n\n const dataSource = new FileListDataSource(\n this.listFilesUseCase,\n this.filesListCache,\n this.getDescendantFoldersUseCase,\n config?.scope\n );\n\n const initialFilters: Record<string, unknown> = { folderId: initialFolderId };\n if (config?.accept && config.accept.length > 0) {\n initialFilters[\"accept\"] = config.accept;\n }\n\n this.listPresenter.init({\n dataSource,\n initialSort: { field: \"createdOn\", direction: \"DESC\" },\n initialFilters,\n limit: 50\n });\n\n if (initialFolderId !== \"root\") {\n this.folderTreePresenter.selectFolder(initialFolderId);\n }\n\n // Sync folder navigation → file list: when the user selects a folder in the tree,\n // update the folderId filter so the file list re-queries for that folder's contents.\n this._disposeReaction = reaction(\n () => this.folderTreePresenter.vm.currentFolderId,\n folderId => {\n const effectiveFolderId = folderId ?? \"root\";\n this.listPresenter.actions.filter.set(\"folderId\", effectiveFolderId);\n\n if (this._persistFolder) {\n this.localStorage.set(LAST_FOLDER_KEY, effectiveFolderId);\n }\n }\n );\n\n void this.tagsRepository.execute({});\n\n // Load the CMS model in the background. The FileModelModule already kicks off\n // loading at app startup, so this usually resolves from cache instantly.\n // The view shows a loading overlay until `_fileModel` is set.\n void this.fileModelProvider.getModel().then(model => {\n runInAction(() => {\n this._fileModel = model;\n });\n });\n }\n\n dispose(): void {\n if (this._disposeReaction) {\n this._disposeReaction();\n this._disposeReaction = null;\n }\n }\n\n private isLoading(): boolean {\n return this.listPresenter.vm.pagination.loading && this.listPresenter.vm.rows.length === 0;\n }\n\n private isEmpty(): boolean {\n if (this.listPresenter.vm.pagination.loading) {\n return false;\n }\n\n if (this.listPresenter.vm.rows.length > 0) {\n return false;\n }\n\n if (this.shouldShowFolders() && this.folderTreePresenter.vm.childFolders.length > 0) {\n return false;\n }\n\n return true;\n }\n\n private getSortedChildFolders() {\n if (!this.shouldShowFolders()) {\n return [];\n }\n return sortFolders(\n this.folderTreePresenter.vm.childFolders ?? [],\n this.listPresenter.vm.appliedQuery?.sort\n );\n }\n\n // Hide folders when the user is actively filtering or searching.\n // Uses `appliedQuery` (not `vm.search`) so folders stay visible while typing\n // and only disappear once the debounced query has actually executed.\n private shouldShowFolders(): boolean {\n const { appliedQuery } = this.listPresenter.vm;\n if (!appliedQuery) {\n return true;\n }\n\n if (appliedQuery.search) {\n return false;\n }\n\n // `folderId` is always present as a default filter; ignore it.\n const filterKeys = Object.keys(appliedQuery.filters ?? {}).filter(\n k => k !== \"folderId\" && k !== \"accept\"\n );\n if (filterKeys.length > 0) {\n return false;\n }\n\n return true;\n }\n}\n\nexport const FileManagerPresenter = Abstraction.createImplementation({\n implementation: FileManagerPresenterImpl,\n dependencies: [\n ListPresenter,\n FolderTreePresenter,\n FileDetailsPresenter,\n FileManagerPermissions,\n ListTagsRepository,\n FileUploader,\n LocalStorage,\n ListFilesUseCase,\n FilesListCache,\n GetDescendantFoldersUseCase,\n FileModelProvider\n ]\n});\n"],"names":["VIEW_MODE_KEY","LAST_FOLDER_KEY","FileManagerPresenterImpl","listPresenter","folderTreePresenter","fileDetailsPresenter","permissions","tagsRepository","fileUploader","localStorage","listFilesUseCase","filesListCache","getDescendantFoldersUseCase","fileModelProvider","query","field","direction","key","value","id","ids","files","folderId","file","mode","dragging","parentFolderId","targetParentId","parentIds","makeAutoObservable","computed","stored","config","initialFolderId","dataSource","FileListDataSource","initialFilters","reaction","effectiveFolderId","model","runInAction","sortFolders","appliedQuery","filterKeys","Object","k","FileManagerPresenter","Abstraction","ListPresenter","FolderTreePresenter","FileDetailsPresenter","FileManagerPermissions","ListTagsRepository","FileUploader","LocalStorage","ListFilesUseCase","FilesListCache","GetDescendantFoldersUseCase","FileModelProvider"],"mappings":"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"}
|
|
@@ -3,6 +3,7 @@ import type { CmsModel } from "@webiny/app-headless-cms-common/types/index.js";
|
|
|
3
3
|
import type { IListViewModel } from "@webiny/app-admin/presentation/listPresenter/abstractions.js";
|
|
4
4
|
import type { IListActions } from "@webiny/app-admin/presentation/listPresenter/abstractions.js";
|
|
5
5
|
import type { IFolderTreeViewModel } from "@webiny/app-aco/presentation/folderTree/abstractions.js";
|
|
6
|
+
import type { FolderDto } from "@webiny/app-aco";
|
|
6
7
|
import type { IFileDetailsPresenter } from "../FileDetails/abstractions.js";
|
|
7
8
|
import type { FmFile } from "../../features/shared/types.js";
|
|
8
9
|
import type { FmTag } from "../../features/shared/types.js";
|
|
@@ -10,6 +11,7 @@ import type { UploadJob } from "../../features/fileUploader/abstractions.js";
|
|
|
10
11
|
export interface IFileManagerInitConfig {
|
|
11
12
|
initialFolderId?: string;
|
|
12
13
|
scope?: string;
|
|
14
|
+
accept?: string[];
|
|
13
15
|
}
|
|
14
16
|
export interface IFileManagerViewModel {
|
|
15
17
|
fileModel: CmsModel | null;
|
|
@@ -29,6 +31,7 @@ export interface IFileManagerViewModel {
|
|
|
29
31
|
loading: boolean;
|
|
30
32
|
empty: boolean;
|
|
31
33
|
showFolders: boolean;
|
|
34
|
+
childFolders: FolderDto[];
|
|
32
35
|
viewMode: "table" | "grid";
|
|
33
36
|
dragging: boolean;
|
|
34
37
|
showingFilters: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presentation/FileList/abstractions.js","sources":["../../../src/presentation/FileList/abstractions.ts"],"sourcesContent":["import { createAbstraction } from \"@webiny/feature/admin\";\nimport type { SelectedFile } from \"@webiny/app-admin/presentation/browserFilePicker/index.js\";\nimport type { CmsModel } from \"@webiny/app-headless-cms-common/types/index.js\";\nimport type { IListViewModel } from \"@webiny/app-admin/presentation/listPresenter/abstractions.js\";\nimport type { IListActions } from \"@webiny/app-admin/presentation/listPresenter/abstractions.js\";\nimport type { IFolderTreeViewModel } from \"@webiny/app-aco/presentation/folderTree/abstractions.js\";\nimport type { IFileDetailsPresenter } from \"../FileDetails/abstractions.js\";\nimport type { FmFile } from \"../../features/shared/types.js\";\nimport type { FmTag } from \"../../features/shared/types.js\";\nimport type { UploadJob } from \"../../features/fileUploader/abstractions.js\";\n\n// ---------------------------------------------------------------------------\n// Init config passed to presenter.init().\n// ---------------------------------------------------------------------------\n\nexport interface IFileManagerInitConfig {\n initialFolderId?: string;\n scope?: string;\n}\n\n// ---------------------------------------------------------------------------\n// FileManagerViewModel\n// ---------------------------------------------------------------------------\n\nexport interface IFileManagerViewModel {\n fileModel: CmsModel | null;\n list: IListViewModel<FmFile>;\n folders: IFolderTreeViewModel;\n fileDetails: IFileDetailsPresenter | null;\n tags: FmTag[];\n upload: {\n jobs: UploadJob[];\n overallProgress: { percentage: number; bytesSent: number; totalBytes: number };\n isUploading: boolean;\n };\n loading: boolean;\n empty: boolean;\n showFolders: boolean;\n viewMode: \"table\" | \"grid\";\n dragging: boolean;\n showingFilters: boolean;\n permissions: {\n canRead: boolean;\n canCreate: boolean;\n canEdit: boolean;\n canDelete: boolean;\n canEditFile: (file: FmFile) => boolean;\n canDeleteFile: (file: FmFile) => boolean;\n };\n}\n\n// ---------------------------------------------------------------------------\n// Folder actions exposed by the FileManagerPresenter.\n// ---------------------------------------------------------------------------\n\nexport interface IFolderActions {\n selectFolder(folderId: string | null): void;\n createFolder(parentFolderId?: string): void;\n editFolder(folderId: string): void;\n deleteFolder(folderId: string): Promise<void>;\n moveFolder(folderId: string, targetParentId: string | null): Promise<void>;\n loadChildFolders(parentIds: string[]): Promise<void>;\n canManageStructure(folderId: string): boolean;\n getAncestorIds(folderId: string): string[];\n submitOperation(): Promise<boolean>;\n cancelOperation(): void;\n}\n\n// ---------------------------------------------------------------------------\n// FileManagerPresenter actions (extends ListActions with domain-specific actions).\n// ---------------------------------------------------------------------------\n\nexport interface IFileManagerActions extends IListActions {\n showFileDetails(id: string): void;\n hideFileDetails(): void;\n upload(files: SelectedFile[]): Promise<void>;\n setViewMode(mode: \"table\" | \"grid\"): void;\n setDragging(dragging: boolean): void;\n showFilters(): void;\n hideFilters(): void;\n folders: IFolderActions;\n}\n\n// ---------------------------------------------------------------------------\n// IFileManagerPresenter\n// ---------------------------------------------------------------------------\n\nexport interface IFileManagerPresenter {\n vm: IFileManagerViewModel;\n actions: IFileManagerActions;\n init(config?: IFileManagerInitConfig): void;\n dispose(): void;\n}\n\nexport const FileManagerPresenter =\n createAbstraction<IFileManagerPresenter>(\"FileManagerPresenter\");\n\nexport namespace FileManagerPresenter {\n export type Interface = IFileManagerPresenter;\n export type ViewModel = IFileManagerViewModel;\n export type Actions = IFileManagerActions;\n export type InitConfig = IFileManagerInitConfig;\n}\n"],"names":["FileManagerPresenter","createAbstraction"],"mappings":";
|
|
1
|
+
{"version":3,"file":"presentation/FileList/abstractions.js","sources":["../../../src/presentation/FileList/abstractions.ts"],"sourcesContent":["import { createAbstraction } from \"@webiny/feature/admin\";\nimport type { SelectedFile } from \"@webiny/app-admin/presentation/browserFilePicker/index.js\";\nimport type { CmsModel } from \"@webiny/app-headless-cms-common/types/index.js\";\nimport type { IListViewModel } from \"@webiny/app-admin/presentation/listPresenter/abstractions.js\";\nimport type { IListActions } from \"@webiny/app-admin/presentation/listPresenter/abstractions.js\";\nimport type { IFolderTreeViewModel } from \"@webiny/app-aco/presentation/folderTree/abstractions.js\";\nimport type { FolderDto } from \"@webiny/app-aco\";\nimport type { IFileDetailsPresenter } from \"../FileDetails/abstractions.js\";\nimport type { FmFile } from \"../../features/shared/types.js\";\nimport type { FmTag } from \"../../features/shared/types.js\";\nimport type { UploadJob } from \"../../features/fileUploader/abstractions.js\";\n\n// ---------------------------------------------------------------------------\n// Init config passed to presenter.init().\n// ---------------------------------------------------------------------------\n\nexport interface IFileManagerInitConfig {\n initialFolderId?: string;\n scope?: string;\n accept?: string[];\n}\n\n// ---------------------------------------------------------------------------\n// FileManagerViewModel\n// ---------------------------------------------------------------------------\n\nexport interface IFileManagerViewModel {\n fileModel: CmsModel | null;\n list: IListViewModel<FmFile>;\n folders: IFolderTreeViewModel;\n fileDetails: IFileDetailsPresenter | null;\n tags: FmTag[];\n upload: {\n jobs: UploadJob[];\n overallProgress: { percentage: number; bytesSent: number; totalBytes: number };\n isUploading: boolean;\n };\n loading: boolean;\n empty: boolean;\n showFolders: boolean;\n childFolders: FolderDto[];\n viewMode: \"table\" | \"grid\";\n dragging: boolean;\n showingFilters: boolean;\n permissions: {\n canRead: boolean;\n canCreate: boolean;\n canEdit: boolean;\n canDelete: boolean;\n canEditFile: (file: FmFile) => boolean;\n canDeleteFile: (file: FmFile) => boolean;\n };\n}\n\n// ---------------------------------------------------------------------------\n// Folder actions exposed by the FileManagerPresenter.\n// ---------------------------------------------------------------------------\n\nexport interface IFolderActions {\n selectFolder(folderId: string | null): void;\n createFolder(parentFolderId?: string): void;\n editFolder(folderId: string): void;\n deleteFolder(folderId: string): Promise<void>;\n moveFolder(folderId: string, targetParentId: string | null): Promise<void>;\n loadChildFolders(parentIds: string[]): Promise<void>;\n canManageStructure(folderId: string): boolean;\n getAncestorIds(folderId: string): string[];\n submitOperation(): Promise<boolean>;\n cancelOperation(): void;\n}\n\n// ---------------------------------------------------------------------------\n// FileManagerPresenter actions (extends ListActions with domain-specific actions).\n// ---------------------------------------------------------------------------\n\nexport interface IFileManagerActions extends IListActions {\n showFileDetails(id: string): void;\n hideFileDetails(): void;\n upload(files: SelectedFile[]): Promise<void>;\n setViewMode(mode: \"table\" | \"grid\"): void;\n setDragging(dragging: boolean): void;\n showFilters(): void;\n hideFilters(): void;\n folders: IFolderActions;\n}\n\n// ---------------------------------------------------------------------------\n// IFileManagerPresenter\n// ---------------------------------------------------------------------------\n\nexport interface IFileManagerPresenter {\n vm: IFileManagerViewModel;\n actions: IFileManagerActions;\n init(config?: IFileManagerInitConfig): void;\n dispose(): void;\n}\n\nexport const FileManagerPresenter =\n createAbstraction<IFileManagerPresenter>(\"FileManagerPresenter\");\n\nexport namespace FileManagerPresenter {\n export type Interface = IFileManagerPresenter;\n export type ViewModel = IFileManagerViewModel;\n export type Actions = IFileManagerActions;\n export type InitConfig = IFileManagerInitConfig;\n}\n"],"names":["FileManagerPresenter","createAbstraction"],"mappings":";AAiGO,MAAMA,uBACTC,kBAAyC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
export declare const getFilesLabel: (count?: number) => string;
|
|
3
|
-
export declare const BulkActionBar: (() => React.JSX.Element | null) &
|
|
4
|
-
|
|
3
|
+
export declare const BulkActionBar: (() => React.JSX.Element | null) & {
|
|
4
|
+
displayName: string;
|
|
5
5
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
export declare const BulkActionDelete: (() => React.JSX.Element | null) &
|
|
3
|
-
|
|
2
|
+
export declare const BulkActionDelete: (() => React.JSX.Element | null) & {
|
|
3
|
+
displayName: string;
|
|
4
4
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
export declare const BulkActionMove: (() => React.JSX.Element) &
|
|
3
|
-
|
|
2
|
+
export declare const BulkActionMove: (() => React.JSX.Element) & {
|
|
3
|
+
displayName: string;
|
|
4
4
|
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export { BulkActionBar, getFilesLabel } from "./BulkActionBar.js";
|
|
2
2
|
export { BulkActionDelete } from "./BulkActionDelete.js";
|
|
3
3
|
export { BulkActionMove } from "./BulkActionMove.js";
|
|
4
|
-
export { BulkActionEdit } from "./BulkActionEdit.js";
|
|
5
4
|
export { BulkAction } from "./useBulkActionWorker.js";
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export { BulkActionBar, getFilesLabel } from "./BulkActionBar.js";
|
|
2
2
|
export { BulkActionDelete } from "./BulkActionDelete.js";
|
|
3
3
|
export { BulkActionMove } from "./BulkActionMove.js";
|
|
4
|
-
export { BulkActionEdit } from "./BulkActionEdit.js";
|
|
5
4
|
export { BulkAction } from "./useBulkActionWorker.js";
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import type { CallbackParams } from "@webiny/app-admin";
|
|
2
2
|
import type { FmFile } from "../../../../features/shared/types.js";
|
|
3
3
|
import { getFilesLabel } from "./BulkActionBar.js";
|
|
4
|
+
declare const useWorker: () => {
|
|
5
|
+
items: FmFile[];
|
|
6
|
+
process: (callback: (items: FmFile[]) => void) => void;
|
|
7
|
+
processInSeries: (callback: ({ item, allItems, report }: CallbackParams<FmFile>) => Promise<void>, chunkSize?: number) => Promise<void>;
|
|
8
|
+
resetItems: () => void;
|
|
9
|
+
results: import("@webiny/app-admin").Result[];
|
|
10
|
+
resetResults: () => Promise<void>;
|
|
11
|
+
};
|
|
4
12
|
export declare const BulkAction: {
|
|
5
13
|
useButtons: () => import("@webiny/app-admin/components/Buttons/useButtons.js").ButtonsProviderContext;
|
|
6
|
-
useWorker:
|
|
7
|
-
items: FmFile[];
|
|
8
|
-
process: (callback: (items: FmFile[]) => void) => void;
|
|
9
|
-
processInSeries: (callback: ({ item, allItems, report }: CallbackParams<FmFile>) => Promise<void>, chunkSize?: number) => Promise<void>;
|
|
10
|
-
resetItems: () => void;
|
|
11
|
-
results: import("@webiny/app-admin").Result[];
|
|
12
|
-
resetResults: () => Promise<void>;
|
|
13
|
-
};
|
|
14
|
+
useWorker: typeof useWorker;
|
|
14
15
|
useDialog: () => import("@webiny/app-admin").UseDialogWithReportResponse;
|
|
15
16
|
};
|
|
16
17
|
export { getFilesLabel };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useCallback,
|
|
1
|
+
import { useCallback, useMemo, useRef } from "react";
|
|
2
2
|
import { Worker, useButtons, useDialogWithReport } from "@webiny/app-admin";
|
|
3
3
|
import { useFileManagerPresenter } from "../../FileManagerPresenterProvider.js";
|
|
4
4
|
const useWorker = ()=>{
|
|
@@ -11,13 +11,7 @@ const useWorker = ()=>{
|
|
|
11
11
|
vm.list.selection.selectedIds,
|
|
12
12
|
vm.list.rows
|
|
13
13
|
]);
|
|
14
|
-
useEffect(()=>{
|
|
15
|
-
worker.items = selectedFiles;
|
|
16
|
-
}, [
|
|
17
|
-
selectedFiles.length
|
|
18
|
-
]);
|
|
19
14
|
const resetItems = useCallback(()=>{
|
|
20
|
-
worker.items = [];
|
|
21
15
|
actions.selection.deselectAll();
|
|
22
16
|
}, []);
|
|
23
17
|
const resetResults = useCallback(async ()=>{
|
|
@@ -25,8 +19,8 @@ const useWorker = ()=>{
|
|
|
25
19
|
}, []);
|
|
26
20
|
return {
|
|
27
21
|
items: selectedFiles,
|
|
28
|
-
process: (callback)=>worker.process(callback),
|
|
29
|
-
processInSeries: async (callback, chunkSize)=>worker.processInSeries(callback, chunkSize),
|
|
22
|
+
process: (callback)=>worker.process(selectedFiles, callback),
|
|
23
|
+
processInSeries: async (callback, chunkSize)=>worker.processInSeries(selectedFiles, callback, chunkSize),
|
|
30
24
|
resetItems,
|
|
31
25
|
results: worker.results,
|
|
32
26
|
resetResults
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presentation/FileList/components/BulkActions/useBulkActionWorker.js","sources":["../../../../../src/presentation/FileList/components/BulkActions/useBulkActionWorker.ts"],"sourcesContent":["import { useCallback,
|
|
1
|
+
{"version":3,"file":"presentation/FileList/components/BulkActions/useBulkActionWorker.js","sources":["../../../../../src/presentation/FileList/components/BulkActions/useBulkActionWorker.ts"],"sourcesContent":["import { useCallback, useMemo, useRef } from \"react\";\nimport type { CallbackParams } from \"@webiny/app-admin\";\nimport { useButtons, useDialogWithReport, Worker } from \"@webiny/app-admin\";\nimport { useFileManagerPresenter } from \"../../FileManagerPresenterProvider.js\";\nimport type { FmFile } from \"~/features/shared/types.js\";\nimport { getFilesLabel } from \"./BulkActionBar.js\";\n\n// Hook that bridges the new presenter-based selection with the Worker pattern.\nconst useWorker = () => {\n const { vm, actions } = useFileManagerPresenter();\n const { current: worker } = useRef(new Worker<FmFile>());\n\n const selectedFiles = useMemo(() => {\n const { selectedIds } = vm.list.selection;\n return vm.list.rows.filter(row => selectedIds.has(row.id));\n }, [vm.list.selection.selectedIds, vm.list.rows]);\n\n const resetItems = useCallback(() => {\n actions.selection.deselectAll();\n }, []);\n\n const resetResults = useCallback(async () => {\n worker.resetResults();\n }, []);\n\n return {\n items: selectedFiles,\n process: (callback: (items: FmFile[]) => void) => worker.process(selectedFiles, callback),\n processInSeries: async (\n callback: ({ item, allItems, report }: CallbackParams<FmFile>) => Promise<void>,\n chunkSize?: number\n ) => worker.processInSeries(selectedFiles, callback, chunkSize),\n resetItems,\n results: worker.results,\n resetResults\n };\n};\n\n// Compose the BulkAction utilities for the new v2 architecture.\nexport const BulkAction = {\n useButtons,\n useWorker,\n useDialog: useDialogWithReport\n};\n\nexport { getFilesLabel };\n"],"names":["useWorker","vm","actions","useFileManagerPresenter","worker","useRef","Worker","selectedFiles","useMemo","selectedIds","row","resetItems","useCallback","resetResults","callback","chunkSize","BulkAction","useButtons","useDialogWithReport"],"mappings":";;;AAQA,MAAMA,YAAY;IACd,MAAM,EAAEC,EAAE,EAAEC,OAAO,EAAE,GAAGC;IACxB,MAAM,EAAE,SAASC,MAAM,EAAE,GAAGC,OAAO,IAAIC;IAEvC,MAAMC,gBAAgBC,QAAQ;QAC1B,MAAM,EAAEC,WAAW,EAAE,GAAGR,GAAG,IAAI,CAAC,SAAS;QACzC,OAAOA,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAACS,CAAAA,MAAOD,YAAY,GAAG,CAACC,IAAI,EAAE;IAC5D,GAAG;QAACT,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW;QAAEA,GAAG,IAAI,CAAC,IAAI;KAAC;IAEhD,MAAMU,aAAaC,YAAY;QAC3BV,QAAQ,SAAS,CAAC,WAAW;IACjC,GAAG,EAAE;IAEL,MAAMW,eAAeD,YAAY;QAC7BR,OAAO,YAAY;IACvB,GAAG,EAAE;IAEL,OAAO;QACH,OAAOG;QACP,SAAS,CAACO,WAAwCV,OAAO,OAAO,CAACG,eAAeO;QAChF,iBAAiB,OACbA,UACAC,YACCX,OAAO,eAAe,CAACG,eAAeO,UAAUC;QACrDJ;QACA,SAASP,OAAO,OAAO;QACvBS;IACJ;AACJ;AAGO,MAAMG,aAAa;IACtBC,YAAUA;IACVjB,WAAAA;IACA,WAAWkB;AACf"}
|
|
@@ -4,6 +4,6 @@ import React from "react";
|
|
|
4
4
|
* Sets the "includeSubFolders" filter which the FileListDataSource uses
|
|
5
5
|
* to expand the folder scope via GetDescendantFoldersUseCase.
|
|
6
6
|
*/
|
|
7
|
-
export declare const SubFoldersToggle: (() => React.JSX.Element) &
|
|
8
|
-
|
|
7
|
+
export declare const SubFoldersToggle: (() => React.JSX.Element) & {
|
|
8
|
+
displayName: string;
|
|
9
9
|
};
|
|
@@ -4,6 +4,6 @@ import React from "react";
|
|
|
4
4
|
* Reads available tags from vm.tags, supports AND/OR filter modes,
|
|
5
5
|
* and dispatches changes via presenter.actions.filter.set("tags", ...).
|
|
6
6
|
*/
|
|
7
|
-
export declare const TagsFilter: (() => React.JSX.Element) &
|
|
8
|
-
|
|
7
|
+
export declare const TagsFilter: (() => React.JSX.Element) & {
|
|
8
|
+
displayName: string;
|
|
9
9
|
};
|
|
@@ -3,6 +3,6 @@ import React from "react";
|
|
|
3
3
|
* File type filter component wired to the FileListPresenter.
|
|
4
4
|
* Sets the "type" filter via presenter.actions.filter.set/clear.
|
|
5
5
|
*/
|
|
6
|
-
export declare const TypeFilter: (() => React.JSX.Element) &
|
|
7
|
-
|
|
6
|
+
export declare const TypeFilter: (() => React.JSX.Element) & {
|
|
7
|
+
displayName: string;
|
|
8
8
|
};
|
|
@@ -4,6 +4,6 @@ import React from "react";
|
|
|
4
4
|
* Renders file thumbnail cards and folder cards in a responsive grid layout.
|
|
5
5
|
* Wires click-to-select through presenter.actions.selection.
|
|
6
6
|
*/
|
|
7
|
-
export declare const FileGrid: (() => React.JSX.Element) &
|
|
8
|
-
|
|
7
|
+
export declare const FileGrid: (() => React.JSX.Element) & {
|
|
8
|
+
displayName: string;
|
|
9
9
|
};
|
|
@@ -116,7 +116,7 @@ const FileGrid_FileGrid = observer(function() {
|
|
|
116
116
|
const presenter = useFileManagerPresenter();
|
|
117
117
|
const { vm, actions } = presenter;
|
|
118
118
|
const overlay = useOverlay();
|
|
119
|
-
const childFolders = vm.
|
|
119
|
+
const childFolders = vm.childFolders;
|
|
120
120
|
const handleFolderNavigate = useCallback((folderId)=>{
|
|
121
121
|
actions.folders.selectFolder(folderId);
|
|
122
122
|
}, [
|