@webiny/app-file-manager 6.4.0-beta.0 → 6.4.0-beta.2

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.
Files changed (26) hide show
  1. package/features/shared/FILE_FIELDS.js +1 -0
  2. package/features/shared/FILE_FIELDS.js.map +1 -1
  3. package/package.json +19 -21
  4. package/presentation/FileList/FileListPresenter.test.js +28 -10
  5. package/presentation/FileList/FileListPresenter.test.js.map +1 -1
  6. package/presentation/FileList/FileManagerPresenter.js +1 -1
  7. package/presentation/FileList/FileManagerPresenter.js.map +1 -1
  8. package/presentation/FileList/abstractions.d.ts +2 -1
  9. package/presentation/FileList/abstractions.js.map +1 -1
  10. package/presentation/FileList/components/Empty/Empty.d.ts +2 -2
  11. package/presentation/FileList/components/Empty/Empty.js.map +1 -1
  12. package/presentation/FileList/components/Upload/index.d.ts +0 -1
  13. package/presentation/FileList/components/Upload/index.js +0 -1
  14. package/presentation/FileManager/FileManagerView.js +21 -25
  15. package/presentation/FileManager/FileManagerView.js.map +1 -1
  16. package/presentation/FileManager/outputFileSelectionError.d.ts +2 -0
  17. package/presentation/{config → FileManager}/outputFileSelectionError.js +1 -1
  18. package/presentation/FileManager/outputFileSelectionError.js.map +1 -0
  19. package/presentation/FileList/components/Upload/DropZone.d.ts +0 -19
  20. package/presentation/FileList/components/Upload/DropZone.js +0 -96
  21. package/presentation/FileList/components/Upload/DropZone.js.map +0 -1
  22. package/presentation/adapters/toFolderDto.d.ts +0 -3
  23. package/presentation/adapters/toFolderDto.js +0 -30
  24. package/presentation/adapters/toFolderDto.js.map +0 -1
  25. package/presentation/config/outputFileSelectionError.d.ts +0 -2
  26. package/presentation/config/outputFileSelectionError.js.map +0 -1
@@ -1,6 +1,7 @@
1
1
  const FILE_FIELDS = [
2
2
  "id",
3
3
  "name",
4
+ "description",
4
5
  "key",
5
6
  "src",
6
7
  "type",
@@ -1 +1 @@
1
- {"version":3,"file":"features/shared/FILE_FIELDS.js","sources":["../../../src/features/shared/FILE_FIELDS.ts"],"sourcesContent":["export const FILE_FIELDS = [\n \"id\",\n \"name\",\n \"key\",\n \"src\",\n \"type\",\n \"size\",\n \"tags\",\n \"createdOn\",\n \"savedOn\",\n \"modifiedOn\",\n \"createdBy.id\",\n \"createdBy.displayName\",\n \"createdBy.type\",\n \"savedBy.id\",\n \"savedBy.displayName\",\n \"savedBy.type\",\n \"modifiedBy.id\",\n \"modifiedBy.displayName\",\n \"modifiedBy.type\",\n \"location.folderId\",\n \"metadata.image.width\",\n \"metadata.image.height\",\n \"metadata.image.format\",\n \"metadata.image.orientation\",\n \"metadata.exif\",\n \"metadata.iptc\",\n \"accessControl.type\"\n];\n"],"names":["FILE_FIELDS"],"mappings":"AAAO,MAAMA,cAAc;IACvB;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACH"}
1
+ {"version":3,"file":"features/shared/FILE_FIELDS.js","sources":["../../../src/features/shared/FILE_FIELDS.ts"],"sourcesContent":["export const FILE_FIELDS = [\n \"id\",\n \"name\",\n \"description\",\n \"key\",\n \"src\",\n \"type\",\n \"size\",\n \"tags\",\n \"createdOn\",\n \"savedOn\",\n \"modifiedOn\",\n \"createdBy.id\",\n \"createdBy.displayName\",\n \"createdBy.type\",\n \"savedBy.id\",\n \"savedBy.displayName\",\n \"savedBy.type\",\n \"modifiedBy.id\",\n \"modifiedBy.displayName\",\n \"modifiedBy.type\",\n \"location.folderId\",\n \"metadata.image.width\",\n \"metadata.image.height\",\n \"metadata.image.format\",\n \"metadata.image.orientation\",\n \"metadata.exif\",\n \"metadata.iptc\",\n \"accessControl.type\"\n];\n"],"names":["FILE_FIELDS"],"mappings":"AAAO,MAAMA,cAAc;IACvB;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACH"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webiny/app-file-manager",
3
- "version": "6.4.0-beta.0",
3
+ "version": "6.4.0-beta.2",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./index.js",
@@ -16,22 +16,22 @@
16
16
  "@apollo/react-common": "3.1.4",
17
17
  "@apollo/react-components": "3.1.5",
18
18
  "@types/react": "18.3.28",
19
- "@webiny/admin-ui": "6.4.0-beta.0",
20
- "@webiny/app": "6.4.0-beta.0",
21
- "@webiny/app-aco": "6.4.0-beta.0",
22
- "@webiny/app-admin": "6.4.0-beta.0",
23
- "@webiny/app-headless-cms": "6.4.0-beta.0",
24
- "@webiny/app-headless-cms-common": "6.4.0-beta.0",
25
- "@webiny/app-websockets": "6.4.0-beta.0",
26
- "@webiny/di": "0.2.3",
27
- "@webiny/feature": "6.4.0-beta.0",
28
- "@webiny/form": "6.4.0-beta.0",
29
- "@webiny/icons": "6.4.0-beta.0",
30
- "@webiny/plugins": "6.4.0-beta.0",
31
- "@webiny/react-composition": "6.4.0-beta.0",
32
- "@webiny/react-properties": "6.4.0-beta.0",
33
- "@webiny/sdk": "6.4.0-beta.0",
34
- "@webiny/validation": "6.4.0-beta.0",
19
+ "@webiny/admin-ui": "6.4.0-beta.2",
20
+ "@webiny/app": "6.4.0-beta.2",
21
+ "@webiny/app-aco": "6.4.0-beta.2",
22
+ "@webiny/app-admin": "6.4.0-beta.2",
23
+ "@webiny/app-headless-cms": "6.4.0-beta.2",
24
+ "@webiny/app-headless-cms-common": "6.4.0-beta.2",
25
+ "@webiny/app-websockets": "6.4.0-beta.2",
26
+ "@webiny/di": "1.0.1",
27
+ "@webiny/feature": "6.4.0-beta.2",
28
+ "@webiny/form": "6.4.0-beta.2",
29
+ "@webiny/icons": "6.4.0-beta.2",
30
+ "@webiny/plugins": "6.4.0-beta.2",
31
+ "@webiny/react-composition": "6.4.0-beta.2",
32
+ "@webiny/react-properties": "6.4.0-beta.2",
33
+ "@webiny/sdk": "6.4.0-beta.2",
34
+ "@webiny/validation": "6.4.0-beta.2",
35
35
  "apollo-cache": "1.3.5",
36
36
  "apollo-client": "2.6.10",
37
37
  "apollo-link": "1.2.14",
@@ -47,15 +47,13 @@
47
47
  "mobx": "6.15.3",
48
48
  "mobx-react-lite": "4.1.1",
49
49
  "react": "18.3.1",
50
- "react-butterfiles": "1.3.3",
51
- "react-custom-scrollbars": "4.2.1",
52
50
  "react-dom": "18.3.1",
53
51
  "react-lazy-load": "4.0.1",
54
52
  "zod": "4.4.3"
55
53
  },
56
54
  "devDependencies": {
57
55
  "@svgr/webpack": "8.1.0",
58
- "@webiny/build-tools": "6.4.0-beta.0",
56
+ "@webiny/build-tools": "6.4.0-beta.2",
59
57
  "rimraf": "6.1.3",
60
58
  "typescript": "6.0.3",
61
59
  "vitest": "4.1.6"
@@ -64,5 +62,5 @@
64
62
  "access": "public",
65
63
  "directory": "dist"
66
64
  },
67
- "gitHead": "a545d7529828af07d08d49c3da1bcb967483b9ce"
65
+ "gitHead": "872f9f50baa1ff6915a5f338216f84bf0b6dfd24"
68
66
  }
@@ -318,16 +318,34 @@ describe("FileListPresenter", ()=>{
318
318
  });
319
319
  it("should call fileUploader.uploadMany when actions.upload is called", async ()=>{
320
320
  presenter.init();
321
- const file1 = new File([
322
- "content"
323
- ], "test.txt", {
324
- type: "text/plain"
325
- });
326
- const file2 = new File([
327
- "img"
328
- ], "photo.png", {
329
- type: "image/png"
330
- });
321
+ const file1 = {
322
+ id: "f1",
323
+ name: "test.txt",
324
+ type: "text/plain",
325
+ size: 7,
326
+ src: {
327
+ file: new File([
328
+ "content"
329
+ ], "test.txt", {
330
+ type: "text/plain"
331
+ }),
332
+ base64: null
333
+ }
334
+ };
335
+ const file2 = {
336
+ id: "f2",
337
+ name: "photo.png",
338
+ type: "image/png",
339
+ size: 3,
340
+ src: {
341
+ file: new File([
342
+ "img"
343
+ ], "photo.png", {
344
+ type: "image/png"
345
+ }),
346
+ base64: null
347
+ }
348
+ };
331
349
  await presenter.actions.upload([
332
350
  file1,
333
351
  file2
@@ -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 = new File([\"content\"], \"test.txt\", { type: \"text/plain\" });\n const file2 = new File([\"img\"], \"photo.png\", { type: \"image/png\" });\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 // 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 },\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 // 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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"}
@@ -61,7 +61,7 @@ class FileManagerPresenterImpl {
61
61
  upload: async (files)=>{
62
62
  const folderId = this.folderTreePresenter.vm.currentFolderId ?? "root";
63
63
  await this.fileUploader.uploadMany(files.map((file)=>({
64
- file,
64
+ file: file.src.file,
65
65
  data: {
66
66
  name: file.name,
67
67
  type: file.type,
@@ -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\";\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 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: File[]) => {\n const folderId = this.folderTreePresenter.vm.currentFolderId ?? \"root\";\n await this.fileUploader.uploadMany(\n files.map(file => ({\n 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 // 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 { 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 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 // 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,3 +1,4 @@
1
+ import type { SelectedFile } from "@webiny/app-admin/presentation/browserFilePicker/index.js";
1
2
  import type { CmsModel } from "@webiny/app-headless-cms-common/types/index.js";
2
3
  import type { IListViewModel } from "@webiny/app-admin/presentation/listPresenter/abstractions.js";
3
4
  import type { IListActions } from "@webiny/app-admin/presentation/listPresenter/abstractions.js";
@@ -53,7 +54,7 @@ export interface IFolderActions {
53
54
  export interface IFileManagerActions extends IListActions {
54
55
  showFileDetails(id: string): void;
55
56
  hideFileDetails(): void;
56
- upload(files: File[]): Promise<void>;
57
+ upload(files: SelectedFile[]): Promise<void>;
57
58
  setViewMode(mode: "table" | "grid"): void;
58
59
  setDragging(dragging: boolean): void;
59
60
  showFilters(): void;
@@ -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 { 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 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: File[]): 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":";AA2FO,MAAMA,uBACTC,kBAAyC"}
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 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":";AA4FO,MAAMA,uBACTC,kBAAyC"}
@@ -1,7 +1,7 @@
1
1
  import React from "react";
2
- import type { FilesRenderChildren } from "react-butterfiles";
2
+ import type { BrowserFilePickerRenderProps } from "@webiny/app-admin/presentation/browserFilePicker/index.js";
3
3
  interface EmptyViewProps {
4
- browseFiles: FilesRenderChildren["browseFiles"];
4
+ browseFiles: BrowserFilePickerRenderProps["browseFiles"];
5
5
  isSearchResult?: boolean;
6
6
  }
7
7
  export declare const Empty: ({ browseFiles, isSearchResult }: EmptyViewProps) => React.JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"presentation/FileList/components/Empty/Empty.js","sources":["../../../../../src/presentation/FileList/components/Empty/Empty.tsx"],"sourcesContent":["import React from \"react\";\nimport type { FilesRenderChildren } from \"react-butterfiles\";\n\nimport { NoPermissions } from \"~/presentation/FileList/components/NoPermissions/index.js\";\nimport { useFileManagerPresenter } from \"../../FileManagerPresenterProvider.js\";\nimport { NoResults } from \"~/presentation/FileList/components/NoResults/index.js\";\nimport { FileDropArea } from \"~/presentation/FileList/components/FileDropArea/index.js\";\n\ninterface EmptyViewProps {\n browseFiles: FilesRenderChildren[\"browseFiles\"];\n isSearchResult?: boolean;\n}\n\nexport const Empty = ({ browseFiles, isSearchResult }: EmptyViewProps) => {\n const { vm } = useFileManagerPresenter();\n const { canRead } = vm.permissions;\n\n if (!canRead) {\n return <NoPermissions />;\n }\n\n if (isSearchResult) {\n return <NoResults />;\n }\n\n return (\n <FileDropArea\n empty\n onClick={() => browseFiles()}\n title={\"Drag & Drop files here\"}\n description={\n \"You can also upload files from your computer by clicking the button below\"\n }\n />\n );\n};\n"],"names":["Empty","browseFiles","isSearchResult","vm","useFileManagerPresenter","canRead","NoPermissions","NoResults","FileDropArea"],"mappings":";;;;;AAaO,MAAMA,QAAQ,CAAC,EAAEC,WAAW,EAAEC,cAAc,EAAkB;IACjE,MAAM,EAAEC,EAAE,EAAE,GAAGC;IACf,MAAM,EAAEC,OAAO,EAAE,GAAGF,GAAG,WAAW;IAElC,IAAI,CAACE,SACD,OAAO,WAAP,GAAO,oBAACC,eAAaA;IAGzB,IAAIJ,gBACA,OAAO,WAAP,GAAO,oBAACK,WAASA;IAGrB,OAAO,WAAP,GACI,oBAACC,cAAYA;QACT;QACA,SAAS,IAAMP;QACf,OAAO;QACP,aACI;;AAIhB"}
1
+ {"version":3,"file":"presentation/FileList/components/Empty/Empty.js","sources":["../../../../../src/presentation/FileList/components/Empty/Empty.tsx"],"sourcesContent":["import React from \"react\";\nimport type { BrowserFilePickerRenderProps } from \"@webiny/app-admin/presentation/browserFilePicker/index.js\";\n\nimport { NoPermissions } from \"~/presentation/FileList/components/NoPermissions/index.js\";\nimport { useFileManagerPresenter } from \"../../FileManagerPresenterProvider.js\";\nimport { NoResults } from \"~/presentation/FileList/components/NoResults/index.js\";\nimport { FileDropArea } from \"~/presentation/FileList/components/FileDropArea/index.js\";\n\ninterface EmptyViewProps {\n browseFiles: BrowserFilePickerRenderProps[\"browseFiles\"];\n isSearchResult?: boolean;\n}\n\nexport const Empty = ({ browseFiles, isSearchResult }: EmptyViewProps) => {\n const { vm } = useFileManagerPresenter();\n const { canRead } = vm.permissions;\n\n if (!canRead) {\n return <NoPermissions />;\n }\n\n if (isSearchResult) {\n return <NoResults />;\n }\n\n return (\n <FileDropArea\n empty\n onClick={() => browseFiles()}\n title={\"Drag & Drop files here\"}\n description={\n \"You can also upload files from your computer by clicking the button below\"\n }\n />\n );\n};\n"],"names":["Empty","browseFiles","isSearchResult","vm","useFileManagerPresenter","canRead","NoPermissions","NoResults","FileDropArea"],"mappings":";;;;;AAaO,MAAMA,QAAQ,CAAC,EAAEC,WAAW,EAAEC,cAAc,EAAkB;IACjE,MAAM,EAAEC,EAAE,EAAE,GAAGC;IACf,MAAM,EAAEC,OAAO,EAAE,GAAGF,GAAG,WAAW;IAElC,IAAI,CAACE,SACD,OAAO,WAAP,GAAO,oBAACC,eAAaA;IAGzB,IAAIJ,gBACA,OAAO,WAAP,GAAO,oBAACK,WAASA;IAGrB,OAAO,WAAP,GACI,oBAACC,cAAYA;QACT;QACA,SAAS,IAAMP;QACf,OAAO;QACP,aACI;;AAIhB"}
@@ -1,2 +1 @@
1
- export { DropZone } from "./DropZone.js";
2
1
  export { UploadProgress } from "./UploadProgress.js";
@@ -1,2 +1 @@
1
- export { DropZone } from "./DropZone.js";
2
1
  export { UploadProgress } from "./UploadProgress.js";
@@ -1,9 +1,9 @@
1
1
  import react, { useCallback, useEffect, useMemo } from "react";
2
2
  import { DiContainerProvider, useContainer, useFeature } from "@webiny/app";
3
3
  import { observer } from "mobx-react-lite";
4
- import react_butterfiles from "react-butterfiles";
4
+ import { BrowserFilePicker } from "@webiny/app-admin/presentation/browserFilePicker/index.js";
5
5
  import debounce from "lodash/debounce.js";
6
- import { Heading, OverlayLoader, Scrollbar, Separator, useToast } from "@webiny/admin-ui";
6
+ import { Heading, OverlayLoader, ScrollArea, Separator, useToast } from "@webiny/admin-ui";
7
7
  import { i18n } from "@webiny/app/i18n/index.js";
8
8
  import { DialogsProvider, LeftPanel, OverlayLayout, RightPanel, SplitView, useHotkeys } from "@webiny/app-admin";
9
9
  import { FoldersFeature } from "@webiny/app-aco/features/folders/feature.js";
@@ -20,7 +20,6 @@ import { FileUploaderFeature } from "../../features/fileUploader/feature.js";
20
20
  import { ListTagsFeature } from "../../features/tags/feature.js";
21
21
  import { GetSettingsFeature } from "../../features/settings/feature.js";
22
22
  import { FileManagerViewWithConfig, useFileManagerConfig } from "../config/FileManagerViewConfig.js";
23
- import { outputFileSelectionError } from "../config/outputFileSelectionError.js";
24
23
  import { FolderTree } from "@webiny/app-aco/presentation/folderTree/FolderTree.js";
25
24
  import { BottomInfoBar } from "../FileList/components/BottomInfoBar/index.js";
26
25
  import { BulkActionBar } from "../FileList/components/BulkActions/index.js";
@@ -34,6 +33,7 @@ import { TagsList } from "../FileList/components/TagsList/index.js";
34
33
  import { UploadProgress } from "../FileList/components/Upload/index.js";
35
34
  import { GetSettingsRepository } from "../../features/settings/abstractions.js";
36
35
  import { OverlayProvider, useOverlay } from "./OverlayContext.js";
36
+ import { outputFileSelectionError } from "./outputFileSelectionError.js";
37
37
  const t = i18n.ns("app-admin/file-manager/file-manager-view");
38
38
  const FileManagerView_FileManagerViewLayout = observer(function() {
39
39
  const { vm, actions } = useFileManagerPresenter();
@@ -57,7 +57,19 @@ const FileManagerView_FileManagerViewLayout = observer(function() {
57
57
  title: "File upload complete."
58
58
  });
59
59
  };
60
- const loadMoreOnScroll = useCallback(debounce(async ({ scrollFrame })=>{
60
+ const onError = useCallback((errors)=>{
61
+ const message = outputFileSelectionError(errors);
62
+ if (message) toast.showWarningToast({
63
+ title: message
64
+ });
65
+ else {
66
+ toast.showWarningToast({
67
+ title: "Couldn't process selected files."
68
+ });
69
+ console.error(errors);
70
+ }
71
+ }, []);
72
+ const loadMoreOnScroll = useCallback(debounce(async (scrollFrame)=>{
61
73
  if (scrollFrame.top > 0.8) actions.loadMore();
62
74
  }, 200), [
63
75
  vm.list.pagination,
@@ -74,27 +86,13 @@ const FileManagerView_FileManagerViewLayout = observer(function() {
74
86
  if ("table" === vm.viewMode) return /*#__PURE__*/ react.createElement(FileTable, null);
75
87
  return /*#__PURE__*/ react.createElement(FileGrid, null);
76
88
  };
77
- const content = /*#__PURE__*/ react.createElement(react_butterfiles, {
89
+ const content = /*#__PURE__*/ react.createElement(BrowserFilePicker, {
78
90
  multiple: true,
79
91
  maxSize: settings ? settings.uploadMaxFileSize + "b" : "1TB",
80
92
  multipleMaxSize: "1TB",
81
93
  accept: overlay?.accept ?? [],
82
- onSuccess: (files)=>{
83
- const filesToUpload = files.map((file)=>file.src.file).filter(Boolean);
84
- uploadFiles(filesToUpload);
85
- },
86
- onError: (errors)=>{
87
- const message = outputFileSelectionError(errors);
88
- if (message) toast.showWarningToast({
89
- title: message
90
- });
91
- else {
92
- toast.showWarningToast({
93
- title: "Couldn't process selected files."
94
- });
95
- console.error(errors);
96
- }
97
- }
94
+ onSuccess: uploadFiles,
95
+ onError: onError
98
96
  }, ({ getDropZoneProps, browseFiles })=>/*#__PURE__*/ react.createElement(react.Fragment, null, /*#__PURE__*/ react.createElement(FileDetailsDrawer, null), /*#__PURE__*/ react.createElement(SplitView, {
99
97
  namespace: "fm/file/list"
100
98
  }, /*#__PURE__*/ react.createElement(LeftPanel, {
@@ -149,10 +147,8 @@ const FileManagerView_FileManagerViewLayout = observer(function() {
149
147
  }
150
148
  }),
151
149
  "data-testid": "fm-list-wrapper"
152
- }, !overlay && /*#__PURE__*/ react.createElement(BulkActionBar, null), /*#__PURE__*/ react.createElement(Scrollbar, {
153
- onScrollFrame: (scrollFrame)=>loadMoreOnScroll({
154
- scrollFrame
155
- })
150
+ }, !overlay && /*#__PURE__*/ react.createElement(BulkActionBar, null), /*#__PURE__*/ react.createElement(ScrollArea, {
151
+ onScroll: loadMoreOnScroll
156
152
  }, renderList(browseFiles)), vm.dragging && /*#__PURE__*/ react.createElement(FileDropPlaceholder, null), /*#__PURE__*/ react.createElement(UploadProgress, null)), /*#__PURE__*/ react.createElement(BottomInfoBar, {
157
153
  accept: overlay?.accept ?? [],
158
154
  listing: vm.list.pagination.loadingMore,
@@ -1 +1 @@
1
- {"version":3,"file":"presentation/FileManager/FileManagerView.js","sources":["../../../src/presentation/FileManager/FileManagerView.tsx"],"sourcesContent":["import React, { useMemo, useEffect, useCallback } from \"react\";\nimport { DiContainerProvider, useContainer, useFeature } from \"@webiny/app\";\nimport { observer } from \"mobx-react-lite\";\nimport type { FilesRenderChildren } from \"react-butterfiles\";\nimport Files from \"react-butterfiles\";\nimport debounce from \"lodash/debounce.js\";\nimport type { positionValues } from \"react-custom-scrollbars\";\nimport { Heading, OverlayLoader, Scrollbar, Separator, useToast } from \"@webiny/admin-ui\";\nimport { i18n } from \"@webiny/app/i18n/index.js\";\nimport {\n LeftPanel,\n OverlayLayout,\n RightPanel,\n SplitView,\n DialogsProvider,\n useHotkeys\n} from \"@webiny/app-admin\";\nimport { FoldersFeature } from \"@webiny/app-aco/features/folders/feature.js\";\nimport { FolderTreePresenterFeature } from \"@webiny/app-aco/presentation/folderTree/feature.js\";\nimport { FileManagerPresenterFeature } from \"~/presentation/FileList/feature.js\";\nimport {\n FileManagerPresenterProvider,\n useFileManagerPresenter\n} from \"~/presentation/FileList/FileManagerPresenterProvider.js\";\nimport { FileDetailsPresenterFeature } from \"~/presentation/FileDetails/feature.js\";\nimport { SharedCacheFeature } from \"~/features/shared/feature.js\";\nimport { ListFilesFeature } from \"~/features/listFiles/feature.js\";\nimport { GetFileFeature } from \"~/features/getFile/feature.js\";\nimport { DeleteFileFeature } from \"~/features/deleteFile/feature.js\";\nimport { UpdateFileFeature } from \"~/features/updateFile/feature.js\";\nimport { FileUploaderFeature } from \"~/features/fileUploader/feature.js\";\nimport { ListTagsFeature } from \"~/features/tags/feature.js\";\nimport { GetSettingsFeature } from \"~/features/settings/feature.js\";\nimport {\n FileManagerViewWithConfig,\n useFileManagerConfig\n} from \"~/presentation/config/FileManagerViewConfig.js\";\nimport { outputFileSelectionError } from \"~/presentation/config/outputFileSelectionError.js\";\nimport { FolderTree } from \"@webiny/app-aco/presentation/folderTree/FolderTree.js\";\nimport { BottomInfoBar } from \"~/presentation/FileList/components/BottomInfoBar/index.js\";\nimport { BulkActionBar } from \"~/presentation/FileList/components/BulkActions/index.js\";\nimport { FileDropPlaceholder } from \"~/presentation/FileList/components/FileDropPlaceholder/index.js\";\nimport { Empty } from \"~/presentation/FileList/components/Empty/index.js\";\nimport { FileDetailsDrawer } from \"~/presentation/FileDetails/components/FileDetailsDrawer.js\";\nimport { FileGrid } from \"~/presentation/FileList/components/Grid/index.js\";\nimport { FileManagerHeader } from \"~/presentation/FileList/components/Header/FileManagerHeader.js\";\nimport { FileTable } from \"~/presentation/FileList/components/Table/index.js\";\nimport { TagsList } from \"~/presentation/FileList/components/TagsList/index.js\";\nimport { UploadProgress } from \"~/presentation/FileList/components/Upload/index.js\";\nimport { GetSettingsRepository } from \"~/features/settings/abstractions.js\";\nimport { OverlayProvider, useOverlay } from \"./OverlayContext.js\";\n\nimport type { FmFile } from \"~/features/shared/types.js\";\n\nexport interface FileManagerViewProps {\n overlay?: boolean;\n onChange?: (files: FmFile[]) => void;\n onClose?: () => void;\n multiple?: boolean;\n accept?: string[];\n scope?: string;\n children?: React.ReactNode;\n}\n\nconst t = i18n.ns(\"app-admin/file-manager/file-manager-view\");\n\n// ---------------------------------------------------------------------------\n// Layout — uses original UI components, wired to the presenter.\n// ---------------------------------------------------------------------------\n\nconst FileManagerViewLayout = observer(function FileManagerViewLayout() {\n const { vm, actions } = useFileManagerPresenter();\n const { browser } = useFileManagerConfig();\n const overlay = useOverlay();\n const toast = useToast();\n\n useHotkeys({\n zIndex: 20,\n keys: {\n esc: () => overlay && overlay.onClose()\n }\n });\n\n const container = useContainer();\n const settingsRepository = useMemo(() => container.resolve(GetSettingsRepository), [container]);\n const settings = settingsRepository.settings;\n\n const uploadFiles = async (files: File[]) => {\n await actions.upload(files);\n toast.showSuccessToast({ title: \"File upload complete.\" });\n };\n\n const loadMoreOnScroll = useCallback(\n debounce(async ({ scrollFrame }: { scrollFrame: positionValues }) => {\n if (scrollFrame.top > 0.8) {\n void actions.loadMore();\n }\n }, 200),\n [vm.list.pagination, actions]\n );\n\n if (!vm.fileModel) {\n return <OverlayLoader text={t`Preparing File Manager...`} />;\n }\n\n const renderList = (browseFiles: FilesRenderChildren[\"browseFiles\"]) => {\n if (!vm.list.pagination.loading && vm.list.rows.length === 0) {\n return <Empty isSearchResult={!vm.showFolders} browseFiles={browseFiles} />;\n }\n\n if (vm.viewMode === \"table\") {\n return <FileTable />;\n }\n\n return <FileGrid />;\n };\n\n const content = (\n <Files\n multiple\n maxSize={settings ? settings.uploadMaxFileSize + \"b\" : \"1TB\"}\n multipleMaxSize={\"1TB\"}\n accept={overlay?.accept ?? []}\n onSuccess={files => {\n const filesToUpload = files.map(file => file.src.file).filter(Boolean) as File[];\n void uploadFiles(filesToUpload);\n }}\n onError={errors => {\n const message = outputFileSelectionError(errors);\n if (message) {\n toast.showWarningToast({ title: message });\n } else {\n toast.showWarningToast({ title: \"Couldn't process selected files.\" });\n console.error(errors);\n }\n }}\n >\n {({ getDropZoneProps, browseFiles }) => (\n <>\n <FileDetailsDrawer />\n <SplitView namespace={\"fm/file/list\"}>\n <LeftPanel span={2}>\n <div className={\"flex flex-col h-main-content\"}>\n <div className={\"py-sm px-md\"}>\n <Heading level={5}>{t`File Manager`}</Heading>\n </div>\n <Separator />\n <div className={\"shrink-0 overflow-y-auto max-h-[66vh]\"}>\n <FolderTree\n vm={vm.folders}\n actions={actions.folders}\n folderActions={browser.folder.actions}\n dropConfirmation={browser.folder.dropConfirmation}\n enableActions={true}\n enableCreate={true}\n />\n </div>\n {browser.filterByTags ? (\n <>\n <Separator />\n <div className={\"flex-1 overflow-y-auto min-h-0\"}>\n <TagsList\n loading={false}\n activeTags={\n (vm.list.filters[\"tags\"] as string[]) ?? []\n }\n tags={vm.tags.map(tag => ({\n tag: tag.tag,\n count: tag.count\n }))}\n onActivatedTagsChange={tags => {\n if (tags.length > 0) {\n actions.filter.set(\"tags\", tags);\n } else {\n actions.filter.clear(\"tags\");\n actions.filter.clear(\"tags_rule\");\n }\n }}\n />\n </div>\n </>\n ) : null}\n </div>\n </LeftPanel>\n <RightPanel span={10}>\n <div\n className={\"flex flex-col relative\"}\n style={{ height: \"calc(100vh - 45px\" }}\n >\n <FileManagerHeader browseFiles={browseFiles} />\n <div\n className={\"flex-1\"}\n {...getDropZoneProps({\n onDragEnter: () => actions.setDragging(true),\n onDrop: () => actions.setDragging(false),\n onDragLeave: (e: React.DragEvent) => {\n if (\n !e.relatedTarget ||\n !e.currentTarget.contains(e.relatedTarget as Node)\n ) {\n actions.setDragging(false);\n }\n }\n })}\n data-testid={\"fm-list-wrapper\"}\n >\n {!overlay && <BulkActionBar />}\n <Scrollbar\n onScrollFrame={scrollFrame =>\n loadMoreOnScroll({ scrollFrame })\n }\n >\n {renderList(browseFiles)}\n </Scrollbar>\n {vm.dragging && <FileDropPlaceholder />}\n <UploadProgress />\n </div>\n <BottomInfoBar\n accept={overlay?.accept ?? []}\n listing={vm.list.pagination.loadingMore}\n loading={vm.list.pagination.loading}\n totalCount={vm.list.pagination.totalCount}\n currentCount={vm.list.pagination.currentCount}\n />\n </div>\n </RightPanel>\n </SplitView>\n </>\n )}\n </Files>\n );\n\n if (overlay) {\n return (\n <OverlayLayout variant={\"strong\"} onExited={() => overlay.onClose()}>\n {content}\n </OverlayLayout>\n );\n }\n\n return content;\n});\n\n// ---------------------------------------------------------------------------\n// Inner component that resolves the presenter from the scoped container.\n// ---------------------------------------------------------------------------\n\nconst FileManagerViewInner = observer(\n ({\n overlay = false,\n onChange,\n onClose,\n multiple,\n accept,\n scope,\n children\n }: FileManagerViewProps) => {\n const { presenter } = useFeature(FileManagerPresenterFeature);\n\n const overlayConfig = useMemo(() => {\n if (!overlay || !onChange || !onClose) {\n return null;\n }\n\n const handleFileClick = (file: FmFile) => {\n if (multiple) {\n presenter.actions.selection.toggle(file.id);\n } else {\n onChange([file]);\n }\n };\n\n const confirmSelection = () => {\n const selectedIds = presenter.vm.list.selection.selectedIds;\n const selectedFiles = presenter.vm.list.rows.filter(f => selectedIds.has(f.id));\n if (selectedFiles.length > 0) {\n onChange(selectedFiles);\n }\n };\n\n return {\n onFileClick: handleFileClick,\n confirmSelection,\n onClose,\n accept: accept ?? [],\n multiple: multiple ?? false\n };\n }, [overlay, onChange, onClose, multiple, accept]);\n\n useEffect(() => {\n presenter.init({ scope });\n return () => presenter.dispose();\n }, [presenter, overlay, scope]);\n\n const inner = (\n <DialogsProvider>\n <FileManagerViewWithConfig>\n <FileManagerPresenterProvider presenter={presenter}>\n <FileManagerViewLayout />\n {children}\n </FileManagerPresenterProvider>\n </FileManagerViewWithConfig>\n </DialogsProvider>\n );\n\n if (overlayConfig) {\n return <OverlayProvider config={overlayConfig}>{inner}</OverlayProvider>;\n }\n\n return inner;\n }\n);\n\n// ---------------------------------------------------------------------------\n// FileManagerView — sets up DI container and renders the inner component.\n// ---------------------------------------------------------------------------\n\nexport const FileManagerView = (props: FileManagerViewProps) => {\n const container = useContainer();\n\n const scopedContainer = useMemo(() => {\n const child = container.createChildContainer();\n\n SharedCacheFeature.register(child);\n FoldersFeature.register(child, { type: \"FmFile\" });\n FolderTreePresenterFeature.register(child);\n ListFilesFeature.register(child);\n GetFileFeature.register(child);\n DeleteFileFeature.register(child);\n UpdateFileFeature.register(child);\n FileUploaderFeature.register(child);\n ListTagsFeature.register(child);\n GetSettingsFeature.register(child);\n FileDetailsPresenterFeature.register(child);\n FileManagerPresenterFeature.register(child);\n\n return child;\n }, []);\n\n return (\n <DiContainerProvider container={scopedContainer}>\n <FileManagerViewInner {...props} />\n </DiContainerProvider>\n );\n};\n"],"names":["t","i18n","FileManagerViewLayout","observer","vm","actions","useFileManagerPresenter","browser","useFileManagerConfig","overlay","useOverlay","toast","useToast","useHotkeys","container","useContainer","settingsRepository","useMemo","GetSettingsRepository","settings","uploadFiles","files","loadMoreOnScroll","useCallback","debounce","scrollFrame","OverlayLoader","renderList","browseFiles","Empty","FileTable","FileGrid","content","Files","filesToUpload","file","Boolean","errors","message","outputFileSelectionError","console","getDropZoneProps","FileDetailsDrawer","SplitView","LeftPanel","Heading","Separator","FolderTree","TagsList","tag","tags","RightPanel","FileManagerHeader","e","BulkActionBar","Scrollbar","FileDropPlaceholder","UploadProgress","BottomInfoBar","OverlayLayout","FileManagerViewInner","onChange","onClose","multiple","accept","scope","children","presenter","useFeature","FileManagerPresenterFeature","overlayConfig","handleFileClick","confirmSelection","selectedIds","selectedFiles","f","useEffect","inner","DialogsProvider","FileManagerViewWithConfig","FileManagerPresenterProvider","OverlayProvider","FileManagerView","props","scopedContainer","child","SharedCacheFeature","FoldersFeature","FolderTreePresenterFeature","ListFilesFeature","GetFileFeature","DeleteFileFeature","UpdateFileFeature","FileUploaderFeature","ListTagsFeature","GetSettingsFeature","FileDetailsPresenterFeature","DiContainerProvider"],"mappings":"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"}
1
+ {"version":3,"file":"presentation/FileManager/FileManagerView.js","sources":["../../../src/presentation/FileManager/FileManagerView.tsx"],"sourcesContent":["import React, { useMemo, useEffect, useCallback } from \"react\";\nimport { DiContainerProvider, useContainer, useFeature } from \"@webiny/app\";\nimport { observer } from \"mobx-react-lite\";\nimport {\n BrowserFilePicker,\n type BrowserFilePickerRenderProps\n} from \"@webiny/app-admin/presentation/browserFilePicker/index.js\";\nimport debounce from \"lodash/debounce.js\";\nimport { Heading, OverlayLoader, ScrollArea, Separator, useToast } from \"@webiny/admin-ui\";\nimport { i18n } from \"@webiny/app/i18n/index.js\";\nimport {\n LeftPanel,\n OverlayLayout,\n RightPanel,\n SplitView,\n DialogsProvider,\n useHotkeys\n} from \"@webiny/app-admin\";\nimport { FoldersFeature } from \"@webiny/app-aco/features/folders/feature.js\";\nimport { FolderTreePresenterFeature } from \"@webiny/app-aco/presentation/folderTree/feature.js\";\nimport { FileManagerPresenterFeature } from \"~/presentation/FileList/feature.js\";\nimport {\n FileManagerPresenterProvider,\n useFileManagerPresenter\n} from \"~/presentation/FileList/FileManagerPresenterProvider.js\";\nimport { FileDetailsPresenterFeature } from \"~/presentation/FileDetails/feature.js\";\nimport { SharedCacheFeature } from \"~/features/shared/feature.js\";\nimport { ListFilesFeature } from \"~/features/listFiles/feature.js\";\nimport { GetFileFeature } from \"~/features/getFile/feature.js\";\nimport { DeleteFileFeature } from \"~/features/deleteFile/feature.js\";\nimport { UpdateFileFeature } from \"~/features/updateFile/feature.js\";\nimport { FileUploaderFeature } from \"~/features/fileUploader/feature.js\";\nimport { ListTagsFeature } from \"~/features/tags/feature.js\";\nimport { GetSettingsFeature } from \"~/features/settings/feature.js\";\nimport {\n FileManagerViewWithConfig,\n useFileManagerConfig\n} from \"~/presentation/config/FileManagerViewConfig.js\";\nimport { FolderTree } from \"@webiny/app-aco/presentation/folderTree/FolderTree.js\";\nimport { BottomInfoBar } from \"~/presentation/FileList/components/BottomInfoBar/index.js\";\nimport { BulkActionBar } from \"~/presentation/FileList/components/BulkActions/index.js\";\nimport { FileDropPlaceholder } from \"~/presentation/FileList/components/FileDropPlaceholder/index.js\";\nimport { Empty } from \"~/presentation/FileList/components/Empty/index.js\";\nimport { FileDetailsDrawer } from \"~/presentation/FileDetails/components/FileDetailsDrawer.js\";\nimport { FileGrid } from \"~/presentation/FileList/components/Grid/index.js\";\nimport { FileManagerHeader } from \"~/presentation/FileList/components/Header/FileManagerHeader.js\";\nimport { FileTable } from \"~/presentation/FileList/components/Table/index.js\";\nimport { TagsList } from \"~/presentation/FileList/components/TagsList/index.js\";\nimport { UploadProgress } from \"~/presentation/FileList/components/Upload/index.js\";\nimport { GetSettingsRepository } from \"~/features/settings/abstractions.js\";\nimport { OverlayProvider, useOverlay } from \"./OverlayContext.js\";\n\nimport type { FmFile } from \"~/features/shared/types.js\";\nimport type {\n FileError,\n SelectedFile\n} from \"@webiny/app-admin/presentation/browserFilePicker/index.js\";\nimport { outputFileSelectionError } from \"~/presentation/FileManager/outputFileSelectionError.js\";\nimport type { ScrollPosition } from \"@webiny/admin-ui\";\n\nexport interface FileManagerViewProps {\n overlay?: boolean;\n onChange?: (files: FmFile[]) => void;\n onClose?: () => void;\n multiple?: boolean;\n accept?: string[];\n scope?: string;\n children?: React.ReactNode;\n}\n\nconst t = i18n.ns(\"app-admin/file-manager/file-manager-view\");\n\n// ---------------------------------------------------------------------------\n// Layout — uses original UI components, wired to the presenter.\n// ---------------------------------------------------------------------------\n\nconst FileManagerViewLayout = observer(function FileManagerViewLayout() {\n const { vm, actions } = useFileManagerPresenter();\n const { browser } = useFileManagerConfig();\n const overlay = useOverlay();\n const toast = useToast();\n\n useHotkeys({\n zIndex: 20,\n keys: {\n esc: () => overlay && overlay.onClose()\n }\n });\n\n const container = useContainer();\n const settingsRepository = useMemo(() => container.resolve(GetSettingsRepository), [container]);\n const settings = settingsRepository.settings;\n\n const uploadFiles = async (files: SelectedFile[]) => {\n await actions.upload(files);\n toast.showSuccessToast({ title: \"File upload complete.\" });\n };\n\n const onError = useCallback((errors: FileError[]) => {\n const message = outputFileSelectionError(errors);\n if (message) {\n toast.showWarningToast({ title: message });\n } else {\n toast.showWarningToast({ title: \"Couldn't process selected files.\" });\n console.error(errors);\n }\n }, []);\n\n const loadMoreOnScroll = useCallback(\n debounce(async (scrollFrame: ScrollPosition) => {\n if (scrollFrame.top > 0.8) {\n void actions.loadMore();\n }\n }, 200),\n [vm.list.pagination, actions]\n );\n\n if (!vm.fileModel) {\n return <OverlayLoader text={t`Preparing File Manager...`} />;\n }\n\n const renderList = (browseFiles: BrowserFilePickerRenderProps[\"browseFiles\"]) => {\n if (!vm.list.pagination.loading && vm.list.rows.length === 0) {\n return <Empty isSearchResult={!vm.showFolders} browseFiles={browseFiles} />;\n }\n\n if (vm.viewMode === \"table\") {\n return <FileTable />;\n }\n\n return <FileGrid />;\n };\n\n const content = (\n <BrowserFilePicker\n multiple\n maxSize={settings ? settings.uploadMaxFileSize + \"b\" : \"1TB\"}\n multipleMaxSize={\"1TB\"}\n accept={overlay?.accept ?? []}\n onSuccess={uploadFiles}\n onError={onError}\n >\n {({ getDropZoneProps, browseFiles }) => (\n <>\n <FileDetailsDrawer />\n <SplitView namespace={\"fm/file/list\"}>\n <LeftPanel span={2}>\n <div className={\"flex flex-col h-main-content\"}>\n <div className={\"py-sm px-md\"}>\n <Heading level={5}>{t`File Manager`}</Heading>\n </div>\n <Separator />\n <div className={\"shrink-0 overflow-y-auto max-h-[66vh]\"}>\n <FolderTree\n vm={vm.folders}\n actions={actions.folders}\n folderActions={browser.folder.actions}\n dropConfirmation={browser.folder.dropConfirmation}\n enableActions={true}\n enableCreate={true}\n />\n </div>\n {browser.filterByTags ? (\n <>\n <Separator />\n <div className={\"flex-1 overflow-y-auto min-h-0\"}>\n <TagsList\n loading={false}\n activeTags={\n (vm.list.filters[\"tags\"] as string[]) ?? []\n }\n tags={vm.tags.map(tag => ({\n tag: tag.tag,\n count: tag.count\n }))}\n onActivatedTagsChange={tags => {\n if (tags.length > 0) {\n actions.filter.set(\"tags\", tags);\n } else {\n actions.filter.clear(\"tags\");\n actions.filter.clear(\"tags_rule\");\n }\n }}\n />\n </div>\n </>\n ) : null}\n </div>\n </LeftPanel>\n <RightPanel span={10}>\n <div\n className={\"flex flex-col relative\"}\n style={{ height: \"calc(100vh - 45px\" }}\n >\n <FileManagerHeader browseFiles={browseFiles} />\n <div\n className={\"flex-1\"}\n {...getDropZoneProps({\n onDragEnter: () => actions.setDragging(true),\n onDrop: () => actions.setDragging(false),\n onDragLeave: (e: React.DragEvent) => {\n if (\n !e.relatedTarget ||\n !e.currentTarget.contains(e.relatedTarget as Node)\n ) {\n actions.setDragging(false);\n }\n }\n })}\n data-testid={\"fm-list-wrapper\"}\n >\n {!overlay && <BulkActionBar />}\n <ScrollArea onScroll={loadMoreOnScroll}>\n {renderList(browseFiles)}\n </ScrollArea>\n {vm.dragging && <FileDropPlaceholder />}\n <UploadProgress />\n </div>\n <BottomInfoBar\n accept={overlay?.accept ?? []}\n listing={vm.list.pagination.loadingMore}\n loading={vm.list.pagination.loading}\n totalCount={vm.list.pagination.totalCount}\n currentCount={vm.list.pagination.currentCount}\n />\n </div>\n </RightPanel>\n </SplitView>\n </>\n )}\n </BrowserFilePicker>\n );\n\n if (overlay) {\n return (\n <OverlayLayout variant={\"strong\"} onExited={() => overlay.onClose()}>\n {content}\n </OverlayLayout>\n );\n }\n\n return content;\n});\n\n// ---------------------------------------------------------------------------\n// Inner component that resolves the presenter from the scoped container.\n// ---------------------------------------------------------------------------\n\nconst FileManagerViewInner = observer(\n ({\n overlay = false,\n onChange,\n onClose,\n multiple,\n accept,\n scope,\n children\n }: FileManagerViewProps) => {\n const { presenter } = useFeature(FileManagerPresenterFeature);\n\n const overlayConfig = useMemo(() => {\n if (!overlay || !onChange || !onClose) {\n return null;\n }\n\n const handleFileClick = (file: FmFile) => {\n if (multiple) {\n presenter.actions.selection.toggle(file.id);\n } else {\n onChange([file]);\n }\n };\n\n const confirmSelection = () => {\n const selectedIds = presenter.vm.list.selection.selectedIds;\n const selectedFiles = presenter.vm.list.rows.filter(f => selectedIds.has(f.id));\n if (selectedFiles.length > 0) {\n onChange(selectedFiles);\n }\n };\n\n return {\n onFileClick: handleFileClick,\n confirmSelection,\n onClose,\n accept: accept ?? [],\n multiple: multiple ?? false\n };\n }, [overlay, onChange, onClose, multiple, accept]);\n\n useEffect(() => {\n presenter.init({ scope });\n return () => presenter.dispose();\n }, [presenter, overlay, scope]);\n\n const inner = (\n <DialogsProvider>\n <FileManagerViewWithConfig>\n <FileManagerPresenterProvider presenter={presenter}>\n <FileManagerViewLayout />\n {children}\n </FileManagerPresenterProvider>\n </FileManagerViewWithConfig>\n </DialogsProvider>\n );\n\n if (overlayConfig) {\n return <OverlayProvider config={overlayConfig}>{inner}</OverlayProvider>;\n }\n\n return inner;\n }\n);\n\n// ---------------------------------------------------------------------------\n// FileManagerView — sets up DI container and renders the inner component.\n// ---------------------------------------------------------------------------\n\nexport const FileManagerView = (props: FileManagerViewProps) => {\n const container = useContainer();\n\n const scopedContainer = useMemo(() => {\n const child = container.createChildContainer();\n\n SharedCacheFeature.register(child);\n FoldersFeature.register(child, { type: \"FmFile\" });\n FolderTreePresenterFeature.register(child);\n ListFilesFeature.register(child);\n GetFileFeature.register(child);\n DeleteFileFeature.register(child);\n UpdateFileFeature.register(child);\n FileUploaderFeature.register(child);\n ListTagsFeature.register(child);\n GetSettingsFeature.register(child);\n FileDetailsPresenterFeature.register(child);\n FileManagerPresenterFeature.register(child);\n\n return child;\n }, []);\n\n return (\n <DiContainerProvider container={scopedContainer}>\n <FileManagerViewInner {...props} />\n </DiContainerProvider>\n );\n};\n"],"names":["t","i18n","FileManagerViewLayout","observer","vm","actions","useFileManagerPresenter","browser","useFileManagerConfig","overlay","useOverlay","toast","useToast","useHotkeys","container","useContainer","settingsRepository","useMemo","GetSettingsRepository","settings","uploadFiles","files","onError","useCallback","errors","message","outputFileSelectionError","console","loadMoreOnScroll","debounce","scrollFrame","OverlayLoader","renderList","browseFiles","Empty","FileTable","FileGrid","content","BrowserFilePicker","getDropZoneProps","FileDetailsDrawer","SplitView","LeftPanel","Heading","Separator","FolderTree","TagsList","tag","tags","RightPanel","FileManagerHeader","e","BulkActionBar","ScrollArea","FileDropPlaceholder","UploadProgress","BottomInfoBar","OverlayLayout","FileManagerViewInner","onChange","onClose","multiple","accept","scope","children","presenter","useFeature","FileManagerPresenterFeature","overlayConfig","handleFileClick","file","confirmSelection","selectedIds","selectedFiles","f","useEffect","inner","DialogsProvider","FileManagerViewWithConfig","FileManagerPresenterProvider","OverlayProvider","FileManagerView","props","scopedContainer","child","SharedCacheFeature","FoldersFeature","FolderTreePresenterFeature","ListFilesFeature","GetFileFeature","DeleteFileFeature","UpdateFileFeature","FileUploaderFeature","ListTagsFeature","GetSettingsFeature","FileDetailsPresenterFeature","DiContainerProvider"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { FileError } from "@webiny/app-admin/presentation/browserFilePicker/index.js";
2
+ export declare const outputFileSelectionError: (errors: FileError[]) => string | null;
@@ -4,7 +4,7 @@ const outputFileSelectionError = (errors)=>{
4
4
  let error = errors.find((error)=>"multipleMaxCountExceeded" === error.type);
5
5
  if (error) return `Cannot upload more than ${error.multipleMaxCount} files at once.`;
6
6
  error = errors.find((error)=>"multipleMaxSizeExceeded" === error.type);
7
- if (error) return `Cannot upload more than ${bytes.format(error.multipleMaxSize)} at once.`;
7
+ if (error) return `Cannot upload more than ${bytes.format(error.multipleMaxSize ?? 0)} at once.`;
8
8
  return "Multiple invalid files selected.";
9
9
  }
10
10
  switch(errors[0].type){
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presentation/FileManager/outputFileSelectionError.js","sources":["../../../src/presentation/FileManager/outputFileSelectionError.ts"],"sourcesContent":["import bytes from \"bytes\";\nimport type { FileError } from \"@webiny/app-admin/presentation/browserFilePicker/index.js\";\n\nexport const outputFileSelectionError = (errors: FileError[]): string | null => {\n if (errors.length > 1) {\n let error = errors.find(error => error.type === \"multipleMaxCountExceeded\");\n if (error) {\n return `Cannot upload more than ${error.multipleMaxCount} files at once.`;\n }\n\n error = errors.find(error => error.type === \"multipleMaxSizeExceeded\");\n if (error) {\n return `Cannot upload more than ${bytes.format(error.multipleMaxSize ?? 0)} at once.`;\n }\n\n return \"Multiple invalid files selected.\";\n }\n\n switch (errors[0].type) {\n case \"unsupportedFileType\":\n return \"Unsupported file type.\";\n case \"maxSizeExceeded\":\n return \"Max size exceeded.\";\n case \"multipleMaxCountExceeded\":\n return \"Multiple max files exceeded.\";\n case \"multipleMaxSizeExceeded\":\n return \"Multiple max size exceeded.\";\n case \"multipleNotAllowed\":\n return \"Only one file allowed.\";\n default:\n return null;\n }\n};\n"],"names":["outputFileSelectionError","errors","error","bytes"],"mappings":";AAGO,MAAMA,2BAA2B,CAACC;IACrC,IAAIA,OAAO,MAAM,GAAG,GAAG;QACnB,IAAIC,QAAQD,OAAO,IAAI,CAACC,CAAAA,QAASA,AAAe,+BAAfA,MAAM,IAAI;QAC3C,IAAIA,OACA,OAAO,CAAC,wBAAwB,EAAEA,MAAM,gBAAgB,CAAC,eAAe,CAAC;QAG7EA,QAAQD,OAAO,IAAI,CAACC,CAAAA,QAASA,AAAe,8BAAfA,MAAM,IAAI;QACvC,IAAIA,OACA,OAAO,CAAC,wBAAwB,EAAEC,MAAM,MAAM,CAACD,MAAM,eAAe,IAAI,GAAG,SAAS,CAAC;QAGzF,OAAO;IACX;IAEA,OAAQD,MAAM,CAAC,EAAE,CAAC,IAAI;QAClB,KAAK;YACD,OAAO;QACX,KAAK;YACD,OAAO;QACX,KAAK;YACD,OAAO;QACX,KAAK;YACD,OAAO;QACX,KAAK;YACD,OAAO;QACX;YACI,OAAO;IACf;AACJ"}
@@ -1,19 +0,0 @@
1
- import React from "react";
2
- interface DropZoneProps {
3
- /** Accepted MIME types (e.g. ["image/*", "application/pdf"]). */
4
- accept?: string[];
5
- /** Maximum file size in bytes or human-readable string from Settings. */
6
- maxFileSize?: string;
7
- /** Minimum file size in bytes or human-readable string from Settings. */
8
- minFileSize?: string;
9
- children: React.ReactNode;
10
- }
11
- /**
12
- * Drag-and-drop upload zone that wraps the file list area.
13
- * Reads `vm.dragging` for overlay visibility and passes dropped files
14
- * to `presenter.actions.upload()`.
15
- */
16
- export declare const DropZone: (({ accept, maxFileSize, minFileSize, children }: DropZoneProps) => React.JSX.Element) & {
17
- displayName: string;
18
- };
19
- export {};
@@ -1,96 +0,0 @@
1
- import react, { useCallback, useRef } from "react";
2
- import { observer } from "mobx-react-lite";
3
- import { Text, cn } from "@webiny/admin-ui";
4
- import { i18n } from "@webiny/app/i18n/index.js";
5
- import { useFileManagerPresenter } from "../../FileManagerPresenterProvider.js";
6
- const t = i18n.ns("app-file-manager/presentation/drop-zone");
7
- function parseSizeToBytes(size) {
8
- const num = parseFloat(size);
9
- if (isNaN(num)) return 0;
10
- const lower = size.toLowerCase();
11
- if (lower.endsWith("gb")) return 1024 * num * 1048576;
12
- if (lower.endsWith("mb")) return 1024 * num * 1024;
13
- if (lower.endsWith("kb")) return 1024 * num;
14
- return num;
15
- }
16
- const DropZone_DropZone = observer(function({ accept, maxFileSize, minFileSize, children }) {
17
- const presenter = useFileManagerPresenter();
18
- const { vm, actions } = presenter;
19
- const dragCounterRef = useRef(0);
20
- const filterFiles = useCallback((files)=>files.filter((file)=>{
21
- if (accept && accept.length > 0) {
22
- const accepted = accept.some((pattern)=>{
23
- if (pattern.endsWith("/*")) {
24
- const prefix = pattern.slice(0, -1);
25
- return file.type.startsWith(prefix);
26
- }
27
- return file.type === pattern;
28
- });
29
- if (!accepted) return false;
30
- }
31
- if (maxFileSize) {
32
- const max = parseSizeToBytes(maxFileSize);
33
- if (max > 0 && file.size > max) return false;
34
- }
35
- if (minFileSize) {
36
- const min = parseSizeToBytes(minFileSize);
37
- if (min > 0 && file.size < min) return false;
38
- }
39
- return true;
40
- }), [
41
- accept,
42
- maxFileSize,
43
- minFileSize
44
- ]);
45
- const handleDragEnter = useCallback((e)=>{
46
- e.preventDefault();
47
- e.stopPropagation();
48
- dragCounterRef.current += 1;
49
- }, []);
50
- const handleDragOver = useCallback((e)=>{
51
- e.preventDefault();
52
- e.stopPropagation();
53
- }, []);
54
- const handleDragLeave = useCallback((e)=>{
55
- e.preventDefault();
56
- e.stopPropagation();
57
- dragCounterRef.current -= 1;
58
- }, []);
59
- const handleDrop = useCallback((e)=>{
60
- e.preventDefault();
61
- e.stopPropagation();
62
- dragCounterRef.current = 0;
63
- const droppedFiles = Array.from(e.dataTransfer.files);
64
- if (0 === droppedFiles.length) return;
65
- const validFiles = filterFiles(droppedFiles);
66
- if (validFiles.length > 0) actions.upload(validFiles);
67
- }, [
68
- filterFiles,
69
- actions
70
- ]);
71
- if (!vm.permissions.canCreate) return /*#__PURE__*/ react.createElement(react.Fragment, null, children);
72
- return /*#__PURE__*/ react.createElement("div", {
73
- className: "relative size-full",
74
- onDragEnter: handleDragEnter,
75
- onDragOver: handleDragOver,
76
- onDragLeave: handleDragLeave,
77
- onDrop: handleDrop,
78
- "data-testid": "fm-drop-zone"
79
- }, children, vm.dragging && /*#__PURE__*/ react.createElement("div", {
80
- className: cn([
81
- "absolute inset-0 z-50",
82
- "flex items-center justify-center",
83
- "bg-primary-default/10",
84
- "border-lg border-dashed border-primary-default",
85
- "rounded-lg",
86
- "pointer-events-none"
87
- ]),
88
- "data-testid": "fm-drop-zone-overlay"
89
- }, /*#__PURE__*/ react.createElement(Text, {
90
- size: "lg",
91
- className: "text-primary-default font-semibold"
92
- }, t`Drop files here to upload`)));
93
- });
94
- export { DropZone_DropZone as DropZone };
95
-
96
- //# sourceMappingURL=DropZone.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"presentation/FileList/components/Upload/DropZone.js","sources":["../../../../../src/presentation/FileList/components/Upload/DropZone.tsx"],"sourcesContent":["import React, { useCallback, useRef } from \"react\";\nimport { observer } from \"mobx-react-lite\";\nimport { cn, Text } from \"@webiny/admin-ui\";\nimport { i18n } from \"@webiny/app/i18n/index.js\";\nimport { useFileManagerPresenter } from \"../../FileManagerPresenterProvider.js\";\n\nconst t = i18n.ns(\"app-file-manager/presentation/drop-zone\");\n\n/**\n * Parse a size string like \"26214400\" (bytes) or \"25MB\" into bytes.\n */\nfunction parseSizeToBytes(size: string): number {\n const num = parseFloat(size);\n if (isNaN(num)) {\n return 0;\n }\n const lower = size.toLowerCase();\n if (lower.endsWith(\"gb\")) {\n return num * 1024 * 1024 * 1024;\n }\n if (lower.endsWith(\"mb\")) {\n return num * 1024 * 1024;\n }\n if (lower.endsWith(\"kb\")) {\n return num * 1024;\n }\n // Assume raw bytes.\n return num;\n}\n\ninterface DropZoneProps {\n /** Accepted MIME types (e.g. [\"image/*\", \"application/pdf\"]). */\n accept?: string[];\n /** Maximum file size in bytes or human-readable string from Settings. */\n maxFileSize?: string;\n /** Minimum file size in bytes or human-readable string from Settings. */\n minFileSize?: string;\n children: React.ReactNode;\n}\n\n/**\n * Drag-and-drop upload zone that wraps the file list area.\n * Reads `vm.dragging` for overlay visibility and passes dropped files\n * to `presenter.actions.upload()`.\n */\nexport const DropZone = observer(function DropZone({\n accept,\n maxFileSize,\n minFileSize,\n children\n}: DropZoneProps) {\n const presenter = useFileManagerPresenter();\n const { vm, actions } = presenter;\n const dragCounterRef = useRef(0);\n\n // Filter files by accept list and size limits.\n const filterFiles = useCallback(\n (files: File[]): File[] => {\n return files.filter(file => {\n // Check accept filter.\n if (accept && accept.length > 0) {\n const accepted = accept.some(pattern => {\n if (pattern.endsWith(\"/*\")) {\n // Wildcard match (e.g. \"image/*\").\n const prefix = pattern.slice(0, -1);\n return file.type.startsWith(prefix);\n }\n return file.type === pattern;\n });\n if (!accepted) {\n return false;\n }\n }\n\n // Check max file size.\n if (maxFileSize) {\n const max = parseSizeToBytes(maxFileSize);\n if (max > 0 && file.size > max) {\n return false;\n }\n }\n\n // Check min file size.\n if (minFileSize) {\n const min = parseSizeToBytes(minFileSize);\n if (min > 0 && file.size < min) {\n return false;\n }\n }\n\n return true;\n });\n },\n [accept, maxFileSize, minFileSize]\n );\n\n const handleDragEnter = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n dragCounterRef.current += 1;\n }, []);\n\n const handleDragOver = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n }, []);\n\n const handleDragLeave = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n dragCounterRef.current -= 1;\n }, []);\n\n const handleDrop = useCallback(\n (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n dragCounterRef.current = 0;\n\n const droppedFiles = Array.from(e.dataTransfer.files);\n if (droppedFiles.length === 0) {\n return;\n }\n\n const validFiles = filterFiles(droppedFiles);\n if (validFiles.length > 0) {\n void actions.upload(validFiles);\n }\n },\n [filterFiles, actions]\n );\n\n // Only show the drop zone when the user has create permission.\n if (!vm.permissions.canCreate) {\n return <>{children}</>;\n }\n\n return (\n <div\n className={\"relative size-full\"}\n onDragEnter={handleDragEnter}\n onDragOver={handleDragOver}\n onDragLeave={handleDragLeave}\n onDrop={handleDrop}\n data-testid={\"fm-drop-zone\"}\n >\n {children}\n {/* Drop overlay. */}\n {vm.dragging && (\n <div\n className={cn([\n \"absolute inset-0 z-50\",\n \"flex items-center justify-center\",\n \"bg-primary-default/10\",\n \"border-lg border-dashed border-primary-default\",\n \"rounded-lg\",\n \"pointer-events-none\"\n ])}\n data-testid={\"fm-drop-zone-overlay\"}\n >\n <Text size={\"lg\"} className={\"text-primary-default font-semibold\"}>\n {t`Drop files here to upload`}\n </Text>\n </div>\n )}\n </div>\n );\n});\n"],"names":["t","i18n","parseSizeToBytes","size","num","parseFloat","isNaN","lower","DropZone","observer","accept","maxFileSize","minFileSize","children","presenter","useFileManagerPresenter","vm","actions","dragCounterRef","useRef","filterFiles","useCallback","files","file","accepted","pattern","prefix","max","min","handleDragEnter","e","handleDragOver","handleDragLeave","handleDrop","droppedFiles","Array","validFiles","cn","Text"],"mappings":";;;;;AAMA,MAAMA,IAAIC,KAAK,EAAE,CAAC;AAKlB,SAASC,iBAAiBC,IAAY;IAClC,MAAMC,MAAMC,WAAWF;IACvB,IAAIG,MAAMF,MACN,OAAO;IAEX,MAAMG,QAAQJ,KAAK,WAAW;IAC9B,IAAII,MAAM,QAAQ,CAAC,OACf,OAAOH,AAAM,OAANA,MAAAA;IAEX,IAAIG,MAAM,QAAQ,CAAC,OACf,OAAOH,AAAM,OAANA,MAAa;IAExB,IAAIG,MAAM,QAAQ,CAAC,OACf,OAAOH,AAAM,OAANA;IAGX,OAAOA;AACX;AAiBO,MAAMI,oBAAWC,SAAS,SAAkB,EAC/CC,MAAM,EACNC,WAAW,EACXC,WAAW,EACXC,QAAQ,EACI;IACZ,MAAMC,YAAYC;IAClB,MAAM,EAAEC,EAAE,EAAEC,OAAO,EAAE,GAAGH;IACxB,MAAMI,iBAAiBC,OAAO;IAG9B,MAAMC,cAAcC,YAChB,CAACC,QACUA,MAAM,MAAM,CAACC,CAAAA;YAEhB,IAAIb,UAAUA,OAAO,MAAM,GAAG,GAAG;gBAC7B,MAAMc,WAAWd,OAAO,IAAI,CAACe,CAAAA;oBACzB,IAAIA,QAAQ,QAAQ,CAAC,OAAO;wBAExB,MAAMC,SAASD,QAAQ,KAAK,CAAC,GAAG;wBAChC,OAAOF,KAAK,IAAI,CAAC,UAAU,CAACG;oBAChC;oBACA,OAAOH,KAAK,IAAI,KAAKE;gBACzB;gBACA,IAAI,CAACD,UACD,OAAO;YAEf;YAGA,IAAIb,aAAa;gBACb,MAAMgB,MAAMzB,iBAAiBS;gBAC7B,IAAIgB,MAAM,KAAKJ,KAAK,IAAI,GAAGI,KACvB,OAAO;YAEf;YAGA,IAAIf,aAAa;gBACb,MAAMgB,MAAM1B,iBAAiBU;gBAC7B,IAAIgB,MAAM,KAAKL,KAAK,IAAI,GAAGK,KACvB,OAAO;YAEf;YAEA,OAAO;QACX,IAEJ;QAAClB;QAAQC;QAAaC;KAAY;IAGtC,MAAMiB,kBAAkBR,YAAY,CAACS;QACjCA,EAAE,cAAc;QAChBA,EAAE,eAAe;QACjBZ,eAAe,OAAO,IAAI;IAC9B,GAAG,EAAE;IAEL,MAAMa,iBAAiBV,YAAY,CAACS;QAChCA,EAAE,cAAc;QAChBA,EAAE,eAAe;IACrB,GAAG,EAAE;IAEL,MAAME,kBAAkBX,YAAY,CAACS;QACjCA,EAAE,cAAc;QAChBA,EAAE,eAAe;QACjBZ,eAAe,OAAO,IAAI;IAC9B,GAAG,EAAE;IAEL,MAAMe,aAAaZ,YACf,CAACS;QACGA,EAAE,cAAc;QAChBA,EAAE,eAAe;QACjBZ,eAAe,OAAO,GAAG;QAEzB,MAAMgB,eAAeC,MAAM,IAAI,CAACL,EAAE,YAAY,CAAC,KAAK;QACpD,IAAII,AAAwB,MAAxBA,aAAa,MAAM,EACnB;QAGJ,MAAME,aAAahB,YAAYc;QAC/B,IAAIE,WAAW,MAAM,GAAG,GACfnB,QAAQ,MAAM,CAACmB;IAE5B,GACA;QAAChB;QAAaH;KAAQ;IAI1B,IAAI,CAACD,GAAG,WAAW,CAAC,SAAS,EACzB,OAAO,WAAP,GAAO,0CAAGH;IAGd,OAAO,WAAP,GACI,oBAAC;QACG,WAAW;QACX,aAAagB;QACb,YAAYE;QACZ,aAAaC;QACb,QAAQC;QACR,eAAa;OAEZpB,UAEAG,GAAG,QAAQ,IAAI,WAAJ,GACR,oBAAC;QACG,WAAWqB,GAAG;YACV;YACA;YACA;YACA;YACA;YACA;SACH;QACD,eAAa;qBAEb,oBAACC,MAAIA;QAAC,MAAM;QAAM,WAAW;OACxBtC,CAAC,CAAC,yBAAyB,CAAC;AAMrD"}
@@ -1,3 +0,0 @@
1
- import type { FolderDto } from "@webiny/app-aco";
2
- import type { IFolderTreeNode } from "@webiny/app-aco/presentation/folderTree/abstractions.js";
3
- export declare function toFolderDto(node: IFolderTreeNode): FolderDto;
@@ -1,30 +0,0 @@
1
- const emptyIdentity = {
2
- id: "",
3
- displayName: "",
4
- type: ""
5
- };
6
- function toFolderDto(node) {
7
- return {
8
- id: node.id,
9
- title: node.name,
10
- slug: node.slug,
11
- type: "FmFile",
12
- parentId: node.parentId,
13
- path: "",
14
- permissions: [],
15
- hasNonInheritedPermissions: node.hasNonInheritedPermissions,
16
- canManagePermissions: node.canManagePermissions,
17
- canManageStructure: node.canManageStructure,
18
- canManageContent: true,
19
- createdBy: emptyIdentity,
20
- createdOn: "",
21
- savedBy: emptyIdentity,
22
- savedOn: "",
23
- modifiedBy: null,
24
- modifiedOn: null,
25
- extensions: {}
26
- };
27
- }
28
- export { toFolderDto };
29
-
30
- //# sourceMappingURL=toFolderDto.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"presentation/adapters/toFolderDto.js","sources":["../../../src/presentation/adapters/toFolderDto.ts"],"sourcesContent":["import type { FolderDto } from \"@webiny/app-aco\";\nimport type { IFolderTreeNode } from \"@webiny/app-aco/presentation/folderTree/abstractions.js\";\n\nconst emptyIdentity = { id: \"\", displayName: \"\", type: \"\" };\n\nexport function toFolderDto(node: IFolderTreeNode): FolderDto {\n return {\n id: node.id,\n title: node.name,\n slug: node.slug,\n type: \"FmFile\",\n parentId: node.parentId,\n path: \"\",\n permissions: [],\n hasNonInheritedPermissions: node.hasNonInheritedPermissions,\n canManagePermissions: node.canManagePermissions,\n canManageStructure: node.canManageStructure,\n canManageContent: true,\n createdBy: emptyIdentity,\n createdOn: \"\",\n savedBy: emptyIdentity,\n savedOn: \"\",\n modifiedBy: null,\n modifiedOn: null,\n extensions: {}\n };\n}\n"],"names":["emptyIdentity","toFolderDto","node"],"mappings":"AAGA,MAAMA,gBAAgB;IAAE,IAAI;IAAI,aAAa;IAAI,MAAM;AAAG;AAEnD,SAASC,YAAYC,IAAqB;IAC7C,OAAO;QACH,IAAIA,KAAK,EAAE;QACX,OAAOA,KAAK,IAAI;QAChB,MAAMA,KAAK,IAAI;QACf,MAAM;QACN,UAAUA,KAAK,QAAQ;QACvB,MAAM;QACN,aAAa,EAAE;QACf,4BAA4BA,KAAK,0BAA0B;QAC3D,sBAAsBA,KAAK,oBAAoB;QAC/C,oBAAoBA,KAAK,kBAAkB;QAC3C,kBAAkB;QAClB,WAAWF;QACX,WAAW;QACX,SAASA;QACT,SAAS;QACT,YAAY;QACZ,YAAY;QACZ,YAAY,CAAC;IACjB;AACJ"}
@@ -1,2 +0,0 @@
1
- import type { FileError } from "react-butterfiles";
2
- export declare const outputFileSelectionError: (errors: FileError[]) => string | null;
@@ -1 +0,0 @@
1
- {"version":3,"file":"presentation/config/outputFileSelectionError.js","sources":["../../../src/presentation/config/outputFileSelectionError.ts"],"sourcesContent":["import bytes from \"bytes\";\nimport type { FileError } from \"react-butterfiles\";\n\nexport const outputFileSelectionError = (errors: FileError[]): string | null => {\n if (errors.length > 1) {\n let error = errors.find(error => error.type === \"multipleMaxCountExceeded\");\n if (error) {\n return `Cannot upload more than ${error.multipleMaxCount} files at once.`;\n }\n\n error = errors.find(error => error.type === \"multipleMaxSizeExceeded\");\n if (error) {\n return `Cannot upload more than ${bytes.format(error.multipleMaxSize)} at once.`;\n }\n\n return \"Multiple invalid files selected.\";\n }\n\n switch (errors[0].type) {\n case \"unsupportedFileType\":\n return \"Unsupported file type.\";\n case \"maxSizeExceeded\":\n return \"Max size exceeded.\";\n case \"multipleMaxCountExceeded\":\n return \"Multiple max files exceeded.\";\n case \"multipleMaxSizeExceeded\":\n return \"Multiple max size exceeded.\";\n case \"multipleNotAllowed\":\n return \"Only one file allowed.\";\n default:\n return null;\n }\n};\n"],"names":["outputFileSelectionError","errors","error","bytes"],"mappings":";AAGO,MAAMA,2BAA2B,CAACC;IACrC,IAAIA,OAAO,MAAM,GAAG,GAAG;QACnB,IAAIC,QAAQD,OAAO,IAAI,CAACC,CAAAA,QAASA,AAAe,+BAAfA,MAAM,IAAI;QAC3C,IAAIA,OACA,OAAO,CAAC,wBAAwB,EAAEA,MAAM,gBAAgB,CAAC,eAAe,CAAC;QAG7EA,QAAQD,OAAO,IAAI,CAACC,CAAAA,QAASA,AAAe,8BAAfA,MAAM,IAAI;QACvC,IAAIA,OACA,OAAO,CAAC,wBAAwB,EAAEC,MAAM,MAAM,CAACD,MAAM,eAAe,EAAE,SAAS,CAAC;QAGpF,OAAO;IACX;IAEA,OAAQD,MAAM,CAAC,EAAE,CAAC,IAAI;QAClB,KAAK;YACD,OAAO;QACX,KAAK;YACD,OAAO;QACX,KAAK;YACD,OAAO;QACX,KAAK;YACD,OAAO;QACX,KAAK;YACD,OAAO;QACX;YACI,OAAO;IACf;AACJ"}