@strapi/upload 5.47.1 → 5.48.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/dist/admin/components/EditAssetDialog/EditAssetContent.js +12 -2
  2. package/dist/admin/components/EditAssetDialog/EditAssetContent.js.map +1 -1
  3. package/dist/admin/components/EditAssetDialog/EditAssetContent.mjs +12 -2
  4. package/dist/admin/components/EditAssetDialog/EditAssetContent.mjs.map +1 -1
  5. package/dist/admin/components/UploadAssetDialog/UploadAssetDialog.js +1 -0
  6. package/dist/admin/components/UploadAssetDialog/UploadAssetDialog.js.map +1 -1
  7. package/dist/admin/components/UploadAssetDialog/UploadAssetDialog.mjs +1 -0
  8. package/dist/admin/components/UploadAssetDialog/UploadAssetDialog.mjs.map +1 -1
  9. package/dist/admin/future/components/Drawer.js +7 -8
  10. package/dist/admin/future/components/Drawer.js.map +1 -1
  11. package/dist/admin/future/components/Drawer.mjs +7 -8
  12. package/dist/admin/future/components/Drawer.mjs.map +1 -1
  13. package/dist/admin/future/components/UploadProgressDialog.js +33 -29
  14. package/dist/admin/future/components/UploadProgressDialog.js.map +1 -1
  15. package/dist/admin/future/components/UploadProgressDialog.mjs +36 -32
  16. package/dist/admin/future/components/UploadProgressDialog.mjs.map +1 -1
  17. package/dist/admin/future/pages/Assets/AssetsPage.js +2 -2
  18. package/dist/admin/future/pages/Assets/AssetsPage.js.map +1 -1
  19. package/dist/admin/future/pages/Assets/AssetsPage.mjs +3 -3
  20. package/dist/admin/future/pages/Assets/AssetsPage.mjs.map +1 -1
  21. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js +626 -169
  22. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js.map +1 -1
  23. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs +630 -175
  24. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs.map +1 -1
  25. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetPreview.js +25 -5
  26. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetPreview.js.map +1 -1
  27. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetPreview.mjs +25 -5
  28. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetPreview.mjs.map +1 -1
  29. package/dist/admin/future/services/api.js +124 -200
  30. package/dist/admin/future/services/api.js.map +1 -1
  31. package/dist/admin/future/services/api.mjs +124 -200
  32. package/dist/admin/future/services/api.mjs.map +1 -1
  33. package/dist/admin/future/services/assets.js +57 -1
  34. package/dist/admin/future/services/assets.js.map +1 -1
  35. package/dist/admin/future/services/assets.mjs +56 -2
  36. package/dist/admin/future/services/assets.mjs.map +1 -1
  37. package/dist/admin/future/services/settings.js +18 -0
  38. package/dist/admin/future/services/settings.js.map +1 -0
  39. package/dist/admin/future/services/settings.mjs +16 -0
  40. package/dist/admin/future/services/settings.mjs.map +1 -0
  41. package/dist/admin/future/services/uploadFileViaXHR.js +92 -0
  42. package/dist/admin/future/services/uploadFileViaXHR.js.map +1 -0
  43. package/dist/admin/future/services/uploadFileViaXHR.mjs +88 -0
  44. package/dist/admin/future/services/uploadFileViaXHR.mjs.map +1 -0
  45. package/dist/admin/future/store/uploadProgress.js +32 -26
  46. package/dist/admin/future/store/uploadProgress.js.map +1 -1
  47. package/dist/admin/future/store/uploadProgress.mjs +32 -27
  48. package/dist/admin/future/store/uploadProgress.mjs.map +1 -1
  49. package/dist/admin/future/utils/createRafBatcher.js +42 -0
  50. package/dist/admin/future/utils/createRafBatcher.js.map +1 -0
  51. package/dist/admin/future/utils/createRafBatcher.mjs +40 -0
  52. package/dist/admin/future/utils/createRafBatcher.mjs.map +1 -0
  53. package/dist/admin/future/utils/downloadFile.js +19 -0
  54. package/dist/admin/future/utils/downloadFile.js.map +1 -0
  55. package/dist/admin/future/utils/downloadFile.mjs +17 -0
  56. package/dist/admin/future/utils/downloadFile.mjs.map +1 -0
  57. package/dist/admin/hooks/useAssets.js +5 -3
  58. package/dist/admin/hooks/useAssets.js.map +1 -1
  59. package/dist/admin/hooks/useAssets.mjs +5 -3
  60. package/dist/admin/hooks/useAssets.mjs.map +1 -1
  61. package/dist/admin/src/components/EditAssetDialog/EditAssetContent.d.ts +2 -1
  62. package/dist/admin/src/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.d.ts +15 -1
  63. package/dist/admin/src/future/pages/Assets/components/AssetDetails/AssetPreview.d.ts +4 -1
  64. package/dist/admin/src/future/services/api.d.ts +9 -8
  65. package/dist/admin/src/future/services/assets.d.ts +6 -1
  66. package/dist/admin/src/future/services/uploadFileViaXHR.d.ts +34 -0
  67. package/dist/admin/src/future/store/uploadProgress.d.ts +17 -4
  68. package/dist/admin/src/future/utils/createRafBatcher.d.ts +23 -0
  69. package/dist/admin/src/future/utils/downloadFile.d.ts +6 -0
  70. package/dist/admin/translations/en.json.js +21 -0
  71. package/dist/admin/translations/en.json.js.map +1 -1
  72. package/dist/admin/translations/en.json.mjs +21 -0
  73. package/dist/admin/translations/en.json.mjs.map +1 -1
  74. package/dist/server/controllers/admin-upload.js +69 -118
  75. package/dist/server/controllers/admin-upload.js.map +1 -1
  76. package/dist/server/controllers/admin-upload.mjs +69 -118
  77. package/dist/server/controllers/admin-upload.mjs.map +1 -1
  78. package/dist/server/controllers/content-api.js +12 -0
  79. package/dist/server/controllers/content-api.js.map +1 -1
  80. package/dist/server/controllers/content-api.mjs +12 -0
  81. package/dist/server/controllers/content-api.mjs.map +1 -1
  82. package/dist/server/routes/admin.js +2 -2
  83. package/dist/server/routes/admin.js.map +1 -1
  84. package/dist/server/routes/admin.mjs +2 -2
  85. package/dist/server/routes/admin.mjs.map +1 -1
  86. package/dist/server/routes/content-api.js +15 -0
  87. package/dist/server/routes/content-api.js.map +1 -1
  88. package/dist/server/routes/content-api.mjs +15 -0
  89. package/dist/server/routes/content-api.mjs.map +1 -1
  90. package/dist/server/routes/validation/upload.js +28 -0
  91. package/dist/server/routes/validation/upload.js.map +1 -1
  92. package/dist/server/routes/validation/upload.mjs +28 -0
  93. package/dist/server/routes/validation/upload.mjs.map +1 -1
  94. package/dist/server/services/image-manipulation.js +16 -8
  95. package/dist/server/services/image-manipulation.js.map +1 -1
  96. package/dist/server/services/image-manipulation.mjs +16 -8
  97. package/dist/server/services/image-manipulation.mjs.map +1 -1
  98. package/dist/server/services/upload.js +90 -1
  99. package/dist/server/services/upload.js.map +1 -1
  100. package/dist/server/services/upload.mjs +91 -2
  101. package/dist/server/services/upload.mjs.map +1 -1
  102. package/dist/server/src/controllers/admin-upload.d.ts +6 -8
  103. package/dist/server/src/controllers/admin-upload.d.ts.map +1 -1
  104. package/dist/server/src/controllers/content-api.d.ts +1 -0
  105. package/dist/server/src/controllers/content-api.d.ts.map +1 -1
  106. package/dist/server/src/controllers/index.d.ts +2 -1
  107. package/dist/server/src/controllers/index.d.ts.map +1 -1
  108. package/dist/server/src/index.d.ts +6 -1
  109. package/dist/server/src/index.d.ts.map +1 -1
  110. package/dist/server/src/routes/content-api.d.ts.map +1 -1
  111. package/dist/server/src/routes/validation/upload.d.ts +45 -0
  112. package/dist/server/src/routes/validation/upload.d.ts.map +1 -1
  113. package/dist/server/src/services/image-manipulation.d.ts +5 -0
  114. package/dist/server/src/services/image-manipulation.d.ts.map +1 -1
  115. package/dist/server/src/services/index.d.ts +4 -0
  116. package/dist/server/src/services/index.d.ts.map +1 -1
  117. package/dist/server/src/services/upload.d.ts +5 -0
  118. package/dist/server/src/services/upload.d.ts.map +1 -1
  119. package/dist/server/src/types.d.ts +2 -2
  120. package/dist/server/src/types.d.ts.map +1 -1
  121. package/dist/shared/contracts/files.d.ts +19 -2
  122. package/dist/shared/contracts/files.d.ts.map +1 -1
  123. package/package.json +8 -8
@@ -1 +1 @@
1
- {"version":3,"file":"uploadProgress.js","sources":["../../../../admin/src/future/store/uploadProgress.ts"],"sourcesContent":["import { createSlice, type PayloadAction } from '@reduxjs/toolkit';\n\nimport type { File } from '../../../../shared/contracts/files';\n\nexport interface FileUploadError {\n name: string;\n message: string;\n}\n\nexport type FileProgressStatus = 'pending' | 'uploading' | 'complete' | 'error' | 'cancelled';\n\nexport interface FileProgress {\n name: string;\n index: number;\n status: FileProgressStatus;\n size: number;\n file?: File;\n error?: string;\n}\n\nexport interface UploadProgressState {\n isVisible: boolean;\n isMinimized: boolean;\n progress: number;\n totalFiles: number;\n files: FileProgress[];\n errors: FileUploadError[];\n uploadId: number;\n}\n\nexport interface RootState {\n uploadProgress: UploadProgressState;\n}\n\nconst initialState: UploadProgressState = {\n isVisible: false,\n isMinimized: false,\n progress: 0,\n totalFiles: 0,\n files: [],\n errors: [],\n uploadId: 0,\n};\n\nconst computeProgress = (files: FileProgress[]): number => {\n if (files.length === 0) return 0;\n const totalSize = files.reduce((sum, f) => sum + f.size, 0);\n if (totalSize === 0) {\n // Fallback to count-based if sizes are unknown\n const completed = files.filter(\n (f) => f.status === 'complete' || f.status === 'error' || f.status === 'cancelled'\n ).length;\n return Math.round((completed / files.length) * 100);\n }\n const completedSize = files\n .filter((f) => f.status === 'complete' || f.status === 'error' || f.status === 'cancelled')\n .reduce((sum, f) => sum + f.size, 0);\n return Math.round((completedSize / totalSize) * 100);\n};\n\nconst uploadProgressSlice = createSlice({\n name: 'uploadProgress',\n initialState,\n reducers: {\n openUploadProgress(\n state,\n action: PayloadAction<{\n totalFiles: number;\n fileNames: string[];\n fileSizes?: number[];\n }>\n ) {\n state.isVisible = true;\n state.isMinimized = false;\n state.progress = 0;\n\n // Create pending files for upload\n const pendingFiles: FileProgress[] = action.payload.fileNames.map((name, index) => ({\n name,\n index,\n status: 'pending' as FileProgressStatus,\n size: action.payload.fileSizes?.[index] ?? 0,\n }));\n\n state.files = pendingFiles;\n state.totalFiles = action.payload.totalFiles;\n state.errors = [];\n state.uploadId += 1;\n },\n setFileUploading(\n state,\n action: PayloadAction<{ name: string; index: number; total: number; size: number }>\n ) {\n const { index, size } = action.payload;\n if (state.files[index]) {\n state.files[index].status = 'uploading';\n state.files[index].size = size;\n }\n },\n setFileComplete(state, action: PayloadAction<{ index: number; file: File }>) {\n const { index, file } = action.payload;\n if (state.files[index]) {\n state.files[index].status = 'complete';\n state.files[index].file = file;\n }\n state.progress = computeProgress(state.files);\n },\n setFileError(state, action: PayloadAction<{ index: number; name: string; message: string }>) {\n const { index, name, message } = action.payload;\n if (state.files[index]) {\n state.files[index].status = 'error';\n state.files[index].error = message;\n }\n state.errors = [...state.errors, { name, message }];\n state.progress = computeProgress(state.files);\n },\n updateProgress(state, action: PayloadAction<number>) {\n state.progress = action.payload;\n },\n addUploadErrors(state, action: PayloadAction<FileUploadError[]>) {\n state.errors = [...state.errors, ...action.payload];\n },\n closeUploadProgress(state) {\n state.isVisible = false;\n state.isMinimized = false;\n state.progress = 0;\n state.totalFiles = 0;\n state.files = [];\n state.errors = [];\n },\n toggleMinimize(state) {\n state.isMinimized = !state.isMinimized;\n },\n cancelUpload(state) {\n // Mark all pending and uploading files as cancelled\n state.files = state.files.map((file) => {\n if (file.status === 'pending' || file.status === 'uploading') {\n return { ...file, status: 'cancelled' as FileProgressStatus };\n }\n return file;\n });\n state.progress = computeProgress(state.files);\n },\n setUploadFailed(state, action: PayloadAction<{ message: string }>) {\n // Mark all pending and uploading files as errored when a catastrophic failure occurs\n state.files = state.files.map((file) => {\n if (file.status === 'pending' || file.status === 'uploading') {\n return {\n ...file,\n status: 'error' as FileProgressStatus,\n error: action.payload.message,\n };\n }\n return file;\n });\n state.progress = 100;\n state.errors = [...state.errors, { name: 'Upload Error', message: action.payload.message }];\n },\n retryCancelledFiles(state) {\n // Reset all cancelled files back to pending for retry\n state.files = state.files.map((file) => {\n if (file.status === 'cancelled') {\n return {\n ...file,\n status: 'pending' as FileProgressStatus,\n };\n }\n return file;\n });\n state.progress = computeProgress(state.files);\n },\n },\n});\n\nexport const {\n openUploadProgress,\n setFileUploading,\n setFileComplete,\n setFileError,\n updateProgress,\n addUploadErrors,\n closeUploadProgress,\n toggleMinimize,\n cancelUpload,\n setUploadFailed,\n retryCancelledFiles,\n} = uploadProgressSlice.actions;\n\nexport const uploadProgressReducer = uploadProgressSlice.reducer;\n"],"names":["initialState","isVisible","isMinimized","progress","totalFiles","files","errors","uploadId","computeProgress","length","totalSize","reduce","sum","f","size","completed","filter","status","Math","round","completedSize","uploadProgressSlice","createSlice","name","reducers","openUploadProgress","state","action","pendingFiles","payload","fileNames","map","index","fileSizes","setFileUploading","setFileComplete","file","setFileError","message","error","updateProgress","addUploadErrors","closeUploadProgress","toggleMinimize","cancelUpload","setUploadFailed","retryCancelledFiles","actions","uploadProgressReducer","reducer"],"mappings":"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"}
1
+ {"version":3,"file":"uploadProgress.js","sources":["../../../../admin/src/future/store/uploadProgress.ts"],"sourcesContent":["import { createSelector, createSlice, type PayloadAction } from '@reduxjs/toolkit';\n\nimport type { File } from '../../../../shared/contracts/files';\n\nexport interface FileUploadError {\n name: string;\n message: string;\n}\n\nexport type FileProgressStatus = 'pending' | 'uploading' | 'complete' | 'error' | 'cancelled';\n\nexport interface FileProgress {\n name: string;\n index: number;\n status: FileProgressStatus;\n size: number;\n uploadedBytes: number;\n file?: File;\n error?: string;\n}\n\nexport interface UploadProgressState {\n isVisible: boolean;\n isMinimized: boolean;\n totalFiles: number;\n files: FileProgress[];\n errors: FileUploadError[];\n uploadId: number;\n}\n\nexport interface RootState {\n uploadProgress: UploadProgressState;\n}\n\nconst initialState: UploadProgressState = {\n isVisible: false,\n isMinimized: false,\n totalFiles: 0,\n files: [],\n errors: [],\n uploadId: 0,\n};\n\nconst uploadProgressSlice = createSlice({\n name: 'uploadProgress',\n initialState,\n reducers: {\n openUploadProgress(\n state,\n action: PayloadAction<{\n totalFiles: number;\n fileNames: string[];\n fileSizes?: number[];\n }>\n ) {\n state.isVisible = true;\n state.isMinimized = false;\n\n // Create pending files for upload\n const pendingFiles: FileProgress[] = action.payload.fileNames.map((name, index) => ({\n name,\n index,\n status: 'pending' as FileProgressStatus,\n size: action.payload.fileSizes?.[index] ?? 0,\n uploadedBytes: 0,\n }));\n\n state.files = pendingFiles;\n state.totalFiles = action.payload.totalFiles;\n state.errors = [];\n state.uploadId += 1;\n },\n setFileUploading(state, action: PayloadAction<{ name: string; index: number; size: number }>) {\n const { index, size } = action.payload;\n if (state.files[index]) {\n state.files[index].status = 'uploading';\n state.files[index].size = size;\n }\n },\n setFileProgress(state, action: PayloadAction<{ index: number; bytes: number }>) {\n const { index, bytes } = action.payload;\n const file = state.files[index];\n if (file) {\n // Clamp to the known file size so the aggregate can never exceed 100%.\n file.uploadedBytes = Math.min(bytes, file.size);\n }\n },\n setFileComplete(state, action: PayloadAction<{ index: number; file: File }>) {\n const { index, file } = action.payload;\n if (state.files[index]) {\n state.files[index].status = 'complete';\n state.files[index].file = file;\n // Reflect completion in the aggregate even if the final progress event was throttled.\n state.files[index].uploadedBytes = state.files[index].size;\n }\n },\n setFileError(state, action: PayloadAction<{ index: number; name: string; message: string }>) {\n const { index, name, message } = action.payload;\n if (state.files[index]) {\n state.files[index].status = 'error';\n state.files[index].error = message;\n }\n state.errors = [...state.errors, { name, message }];\n },\n addUploadErrors(state, action: PayloadAction<FileUploadError[]>) {\n state.errors = [...state.errors, ...action.payload];\n },\n closeUploadProgress(state) {\n state.isVisible = false;\n state.isMinimized = false;\n state.totalFiles = 0;\n state.files = [];\n state.errors = [];\n },\n toggleMinimize(state) {\n state.isMinimized = !state.isMinimized;\n },\n cancelUpload(state) {\n // Mark all pending and uploading files as cancelled\n state.files = state.files.map((file) => {\n if (file.status === 'pending' || file.status === 'uploading') {\n return { ...file, status: 'cancelled' as FileProgressStatus };\n }\n return file;\n });\n },\n setUploadFailed(state, action: PayloadAction<{ message: string }>) {\n // Mark all pending and uploading files as errored when a catastrophic failure occurs\n state.files = state.files.map((file) => {\n if (file.status === 'pending' || file.status === 'uploading') {\n return {\n ...file,\n status: 'error' as FileProgressStatus,\n error: action.payload.message,\n };\n }\n return file;\n });\n state.errors = [...state.errors, { name: 'Upload Error', message: action.payload.message }];\n },\n retryCancelledFiles(state) {\n // Reset all cancelled files back to pending for retry\n state.files = state.files.map((file) => {\n if (file.status === 'cancelled') {\n return {\n ...file,\n status: 'pending' as FileProgressStatus,\n uploadedBytes: 0,\n };\n }\n return file;\n });\n },\n },\n});\n\n/**\n * Byte-weighted aggregate progress across the whole batch: `sum(uploadedBytes) / sum(size)`.\n *\n * Falls back to count-based progress (settled files / total files) when all sizes are\n * zero — e.g. URL-flow rows where the file size is unknown up front.\n */\nexport const selectAggregateProgress = createSelector(\n (state: RootState) => state.uploadProgress.files,\n (files): number => {\n if (files.length === 0) return 0;\n\n const totalSize = files.reduce((sum, f) => sum + f.size, 0);\n\n if (totalSize === 0) {\n const settled = files.filter(\n (f) => f.status === 'complete' || f.status === 'error' || f.status === 'cancelled'\n ).length;\n return Math.round((settled / files.length) * 100);\n }\n\n const uploadedBytes = files.reduce((sum, f) => sum + f.uploadedBytes, 0);\n return Math.round((uploadedBytes / totalSize) * 100);\n }\n);\n\nexport const {\n openUploadProgress,\n setFileUploading,\n setFileProgress,\n setFileComplete,\n setFileError,\n addUploadErrors,\n closeUploadProgress,\n toggleMinimize,\n cancelUpload,\n setUploadFailed,\n retryCancelledFiles,\n} = uploadProgressSlice.actions;\n\nexport const uploadProgressReducer = uploadProgressSlice.reducer;\n"],"names":["initialState","isVisible","isMinimized","totalFiles","files","errors","uploadId","uploadProgressSlice","createSlice","name","reducers","openUploadProgress","state","action","pendingFiles","payload","fileNames","map","index","status","size","fileSizes","uploadedBytes","setFileUploading","setFileProgress","bytes","file","Math","min","setFileComplete","setFileError","message","error","addUploadErrors","closeUploadProgress","toggleMinimize","cancelUpload","setUploadFailed","retryCancelledFiles","selectAggregateProgress","createSelector","uploadProgress","length","totalSize","reduce","sum","f","settled","filter","round","actions","uploadProgressReducer","reducer"],"mappings":"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"}
@@ -1,25 +1,13 @@
1
- import { createSlice } from '@reduxjs/toolkit';
1
+ import { createSlice, createSelector } from '@reduxjs/toolkit';
2
2
 
3
3
  const initialState = {
4
4
  isVisible: false,
5
5
  isMinimized: false,
6
- progress: 0,
7
6
  totalFiles: 0,
8
7
  files: [],
9
8
  errors: [],
10
9
  uploadId: 0
11
10
  };
12
- const computeProgress = (files)=>{
13
- if (files.length === 0) return 0;
14
- const totalSize = files.reduce((sum, f)=>sum + f.size, 0);
15
- if (totalSize === 0) {
16
- // Fallback to count-based if sizes are unknown
17
- const completed = files.filter((f)=>f.status === 'complete' || f.status === 'error' || f.status === 'cancelled').length;
18
- return Math.round(completed / files.length * 100);
19
- }
20
- const completedSize = files.filter((f)=>f.status === 'complete' || f.status === 'error' || f.status === 'cancelled').reduce((sum, f)=>sum + f.size, 0);
21
- return Math.round(completedSize / totalSize * 100);
22
- };
23
11
  const uploadProgressSlice = createSlice({
24
12
  name: 'uploadProgress',
25
13
  initialState,
@@ -27,13 +15,13 @@ const uploadProgressSlice = createSlice({
27
15
  openUploadProgress (state, action) {
28
16
  state.isVisible = true;
29
17
  state.isMinimized = false;
30
- state.progress = 0;
31
18
  // Create pending files for upload
32
19
  const pendingFiles = action.payload.fileNames.map((name, index)=>({
33
20
  name,
34
21
  index,
35
22
  status: 'pending',
36
- size: action.payload.fileSizes?.[index] ?? 0
23
+ size: action.payload.fileSizes?.[index] ?? 0,
24
+ uploadedBytes: 0
37
25
  }));
38
26
  state.files = pendingFiles;
39
27
  state.totalFiles = action.payload.totalFiles;
@@ -47,13 +35,22 @@ const uploadProgressSlice = createSlice({
47
35
  state.files[index].size = size;
48
36
  }
49
37
  },
38
+ setFileProgress (state, action) {
39
+ const { index, bytes } = action.payload;
40
+ const file = state.files[index];
41
+ if (file) {
42
+ // Clamp to the known file size so the aggregate can never exceed 100%.
43
+ file.uploadedBytes = Math.min(bytes, file.size);
44
+ }
45
+ },
50
46
  setFileComplete (state, action) {
51
47
  const { index, file } = action.payload;
52
48
  if (state.files[index]) {
53
49
  state.files[index].status = 'complete';
54
50
  state.files[index].file = file;
51
+ // Reflect completion in the aggregate even if the final progress event was throttled.
52
+ state.files[index].uploadedBytes = state.files[index].size;
55
53
  }
56
- state.progress = computeProgress(state.files);
57
54
  },
58
55
  setFileError (state, action) {
59
56
  const { index, name, message } = action.payload;
@@ -68,10 +65,6 @@ const uploadProgressSlice = createSlice({
68
65
  message
69
66
  }
70
67
  ];
71
- state.progress = computeProgress(state.files);
72
- },
73
- updateProgress (state, action) {
74
- state.progress = action.payload;
75
68
  },
76
69
  addUploadErrors (state, action) {
77
70
  state.errors = [
@@ -82,7 +75,6 @@ const uploadProgressSlice = createSlice({
82
75
  closeUploadProgress (state) {
83
76
  state.isVisible = false;
84
77
  state.isMinimized = false;
85
- state.progress = 0;
86
78
  state.totalFiles = 0;
87
79
  state.files = [];
88
80
  state.errors = [];
@@ -101,7 +93,6 @@ const uploadProgressSlice = createSlice({
101
93
  }
102
94
  return file;
103
95
  });
104
- state.progress = computeProgress(state.files);
105
96
  },
106
97
  setUploadFailed (state, action) {
107
98
  // Mark all pending and uploading files as errored when a catastrophic failure occurs
@@ -115,7 +106,6 @@ const uploadProgressSlice = createSlice({
115
106
  }
116
107
  return file;
117
108
  });
118
- state.progress = 100;
119
109
  state.errors = [
120
110
  ...state.errors,
121
111
  {
@@ -130,17 +120,32 @@ const uploadProgressSlice = createSlice({
130
120
  if (file.status === 'cancelled') {
131
121
  return {
132
122
  ...file,
133
- status: 'pending'
123
+ status: 'pending',
124
+ uploadedBytes: 0
134
125
  };
135
126
  }
136
127
  return file;
137
128
  });
138
- state.progress = computeProgress(state.files);
139
129
  }
140
130
  }
141
131
  });
142
- const { openUploadProgress, setFileUploading, setFileComplete, setFileError, updateProgress, addUploadErrors, closeUploadProgress, toggleMinimize, cancelUpload, setUploadFailed, retryCancelledFiles } = uploadProgressSlice.actions;
132
+ /**
133
+ * Byte-weighted aggregate progress across the whole batch: `sum(uploadedBytes) / sum(size)`.
134
+ *
135
+ * Falls back to count-based progress (settled files / total files) when all sizes are
136
+ * zero — e.g. URL-flow rows where the file size is unknown up front.
137
+ */ const selectAggregateProgress = createSelector((state)=>state.uploadProgress.files, (files)=>{
138
+ if (files.length === 0) return 0;
139
+ const totalSize = files.reduce((sum, f)=>sum + f.size, 0);
140
+ if (totalSize === 0) {
141
+ const settled = files.filter((f)=>f.status === 'complete' || f.status === 'error' || f.status === 'cancelled').length;
142
+ return Math.round(settled / files.length * 100);
143
+ }
144
+ const uploadedBytes = files.reduce((sum, f)=>sum + f.uploadedBytes, 0);
145
+ return Math.round(uploadedBytes / totalSize * 100);
146
+ });
147
+ const { openUploadProgress, setFileUploading, setFileProgress, setFileComplete, setFileError, addUploadErrors, closeUploadProgress, toggleMinimize, cancelUpload, setUploadFailed, retryCancelledFiles } = uploadProgressSlice.actions;
143
148
  const uploadProgressReducer = uploadProgressSlice.reducer;
144
149
 
145
- export { addUploadErrors, cancelUpload, closeUploadProgress, openUploadProgress, retryCancelledFiles, setFileComplete, setFileError, setFileUploading, setUploadFailed, toggleMinimize, updateProgress, uploadProgressReducer };
150
+ export { addUploadErrors, cancelUpload, closeUploadProgress, openUploadProgress, retryCancelledFiles, selectAggregateProgress, setFileComplete, setFileError, setFileProgress, setFileUploading, setUploadFailed, toggleMinimize, uploadProgressReducer };
146
151
  //# sourceMappingURL=uploadProgress.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"uploadProgress.mjs","sources":["../../../../admin/src/future/store/uploadProgress.ts"],"sourcesContent":["import { createSlice, type PayloadAction } from '@reduxjs/toolkit';\n\nimport type { File } from '../../../../shared/contracts/files';\n\nexport interface FileUploadError {\n name: string;\n message: string;\n}\n\nexport type FileProgressStatus = 'pending' | 'uploading' | 'complete' | 'error' | 'cancelled';\n\nexport interface FileProgress {\n name: string;\n index: number;\n status: FileProgressStatus;\n size: number;\n file?: File;\n error?: string;\n}\n\nexport interface UploadProgressState {\n isVisible: boolean;\n isMinimized: boolean;\n progress: number;\n totalFiles: number;\n files: FileProgress[];\n errors: FileUploadError[];\n uploadId: number;\n}\n\nexport interface RootState {\n uploadProgress: UploadProgressState;\n}\n\nconst initialState: UploadProgressState = {\n isVisible: false,\n isMinimized: false,\n progress: 0,\n totalFiles: 0,\n files: [],\n errors: [],\n uploadId: 0,\n};\n\nconst computeProgress = (files: FileProgress[]): number => {\n if (files.length === 0) return 0;\n const totalSize = files.reduce((sum, f) => sum + f.size, 0);\n if (totalSize === 0) {\n // Fallback to count-based if sizes are unknown\n const completed = files.filter(\n (f) => f.status === 'complete' || f.status === 'error' || f.status === 'cancelled'\n ).length;\n return Math.round((completed / files.length) * 100);\n }\n const completedSize = files\n .filter((f) => f.status === 'complete' || f.status === 'error' || f.status === 'cancelled')\n .reduce((sum, f) => sum + f.size, 0);\n return Math.round((completedSize / totalSize) * 100);\n};\n\nconst uploadProgressSlice = createSlice({\n name: 'uploadProgress',\n initialState,\n reducers: {\n openUploadProgress(\n state,\n action: PayloadAction<{\n totalFiles: number;\n fileNames: string[];\n fileSizes?: number[];\n }>\n ) {\n state.isVisible = true;\n state.isMinimized = false;\n state.progress = 0;\n\n // Create pending files for upload\n const pendingFiles: FileProgress[] = action.payload.fileNames.map((name, index) => ({\n name,\n index,\n status: 'pending' as FileProgressStatus,\n size: action.payload.fileSizes?.[index] ?? 0,\n }));\n\n state.files = pendingFiles;\n state.totalFiles = action.payload.totalFiles;\n state.errors = [];\n state.uploadId += 1;\n },\n setFileUploading(\n state,\n action: PayloadAction<{ name: string; index: number; total: number; size: number }>\n ) {\n const { index, size } = action.payload;\n if (state.files[index]) {\n state.files[index].status = 'uploading';\n state.files[index].size = size;\n }\n },\n setFileComplete(state, action: PayloadAction<{ index: number; file: File }>) {\n const { index, file } = action.payload;\n if (state.files[index]) {\n state.files[index].status = 'complete';\n state.files[index].file = file;\n }\n state.progress = computeProgress(state.files);\n },\n setFileError(state, action: PayloadAction<{ index: number; name: string; message: string }>) {\n const { index, name, message } = action.payload;\n if (state.files[index]) {\n state.files[index].status = 'error';\n state.files[index].error = message;\n }\n state.errors = [...state.errors, { name, message }];\n state.progress = computeProgress(state.files);\n },\n updateProgress(state, action: PayloadAction<number>) {\n state.progress = action.payload;\n },\n addUploadErrors(state, action: PayloadAction<FileUploadError[]>) {\n state.errors = [...state.errors, ...action.payload];\n },\n closeUploadProgress(state) {\n state.isVisible = false;\n state.isMinimized = false;\n state.progress = 0;\n state.totalFiles = 0;\n state.files = [];\n state.errors = [];\n },\n toggleMinimize(state) {\n state.isMinimized = !state.isMinimized;\n },\n cancelUpload(state) {\n // Mark all pending and uploading files as cancelled\n state.files = state.files.map((file) => {\n if (file.status === 'pending' || file.status === 'uploading') {\n return { ...file, status: 'cancelled' as FileProgressStatus };\n }\n return file;\n });\n state.progress = computeProgress(state.files);\n },\n setUploadFailed(state, action: PayloadAction<{ message: string }>) {\n // Mark all pending and uploading files as errored when a catastrophic failure occurs\n state.files = state.files.map((file) => {\n if (file.status === 'pending' || file.status === 'uploading') {\n return {\n ...file,\n status: 'error' as FileProgressStatus,\n error: action.payload.message,\n };\n }\n return file;\n });\n state.progress = 100;\n state.errors = [...state.errors, { name: 'Upload Error', message: action.payload.message }];\n },\n retryCancelledFiles(state) {\n // Reset all cancelled files back to pending for retry\n state.files = state.files.map((file) => {\n if (file.status === 'cancelled') {\n return {\n ...file,\n status: 'pending' as FileProgressStatus,\n };\n }\n return file;\n });\n state.progress = computeProgress(state.files);\n },\n },\n});\n\nexport const {\n openUploadProgress,\n setFileUploading,\n setFileComplete,\n setFileError,\n updateProgress,\n addUploadErrors,\n closeUploadProgress,\n toggleMinimize,\n cancelUpload,\n setUploadFailed,\n retryCancelledFiles,\n} = uploadProgressSlice.actions;\n\nexport const uploadProgressReducer = uploadProgressSlice.reducer;\n"],"names":["initialState","isVisible","isMinimized","progress","totalFiles","files","errors","uploadId","computeProgress","length","totalSize","reduce","sum","f","size","completed","filter","status","Math","round","completedSize","uploadProgressSlice","createSlice","name","reducers","openUploadProgress","state","action","pendingFiles","payload","fileNames","map","index","fileSizes","setFileUploading","setFileComplete","file","setFileError","message","error","updateProgress","addUploadErrors","closeUploadProgress","toggleMinimize","cancelUpload","setUploadFailed","retryCancelledFiles","actions","uploadProgressReducer","reducer"],"mappings":"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"}
1
+ {"version":3,"file":"uploadProgress.mjs","sources":["../../../../admin/src/future/store/uploadProgress.ts"],"sourcesContent":["import { createSelector, createSlice, type PayloadAction } from '@reduxjs/toolkit';\n\nimport type { File } from '../../../../shared/contracts/files';\n\nexport interface FileUploadError {\n name: string;\n message: string;\n}\n\nexport type FileProgressStatus = 'pending' | 'uploading' | 'complete' | 'error' | 'cancelled';\n\nexport interface FileProgress {\n name: string;\n index: number;\n status: FileProgressStatus;\n size: number;\n uploadedBytes: number;\n file?: File;\n error?: string;\n}\n\nexport interface UploadProgressState {\n isVisible: boolean;\n isMinimized: boolean;\n totalFiles: number;\n files: FileProgress[];\n errors: FileUploadError[];\n uploadId: number;\n}\n\nexport interface RootState {\n uploadProgress: UploadProgressState;\n}\n\nconst initialState: UploadProgressState = {\n isVisible: false,\n isMinimized: false,\n totalFiles: 0,\n files: [],\n errors: [],\n uploadId: 0,\n};\n\nconst uploadProgressSlice = createSlice({\n name: 'uploadProgress',\n initialState,\n reducers: {\n openUploadProgress(\n state,\n action: PayloadAction<{\n totalFiles: number;\n fileNames: string[];\n fileSizes?: number[];\n }>\n ) {\n state.isVisible = true;\n state.isMinimized = false;\n\n // Create pending files for upload\n const pendingFiles: FileProgress[] = action.payload.fileNames.map((name, index) => ({\n name,\n index,\n status: 'pending' as FileProgressStatus,\n size: action.payload.fileSizes?.[index] ?? 0,\n uploadedBytes: 0,\n }));\n\n state.files = pendingFiles;\n state.totalFiles = action.payload.totalFiles;\n state.errors = [];\n state.uploadId += 1;\n },\n setFileUploading(state, action: PayloadAction<{ name: string; index: number; size: number }>) {\n const { index, size } = action.payload;\n if (state.files[index]) {\n state.files[index].status = 'uploading';\n state.files[index].size = size;\n }\n },\n setFileProgress(state, action: PayloadAction<{ index: number; bytes: number }>) {\n const { index, bytes } = action.payload;\n const file = state.files[index];\n if (file) {\n // Clamp to the known file size so the aggregate can never exceed 100%.\n file.uploadedBytes = Math.min(bytes, file.size);\n }\n },\n setFileComplete(state, action: PayloadAction<{ index: number; file: File }>) {\n const { index, file } = action.payload;\n if (state.files[index]) {\n state.files[index].status = 'complete';\n state.files[index].file = file;\n // Reflect completion in the aggregate even if the final progress event was throttled.\n state.files[index].uploadedBytes = state.files[index].size;\n }\n },\n setFileError(state, action: PayloadAction<{ index: number; name: string; message: string }>) {\n const { index, name, message } = action.payload;\n if (state.files[index]) {\n state.files[index].status = 'error';\n state.files[index].error = message;\n }\n state.errors = [...state.errors, { name, message }];\n },\n addUploadErrors(state, action: PayloadAction<FileUploadError[]>) {\n state.errors = [...state.errors, ...action.payload];\n },\n closeUploadProgress(state) {\n state.isVisible = false;\n state.isMinimized = false;\n state.totalFiles = 0;\n state.files = [];\n state.errors = [];\n },\n toggleMinimize(state) {\n state.isMinimized = !state.isMinimized;\n },\n cancelUpload(state) {\n // Mark all pending and uploading files as cancelled\n state.files = state.files.map((file) => {\n if (file.status === 'pending' || file.status === 'uploading') {\n return { ...file, status: 'cancelled' as FileProgressStatus };\n }\n return file;\n });\n },\n setUploadFailed(state, action: PayloadAction<{ message: string }>) {\n // Mark all pending and uploading files as errored when a catastrophic failure occurs\n state.files = state.files.map((file) => {\n if (file.status === 'pending' || file.status === 'uploading') {\n return {\n ...file,\n status: 'error' as FileProgressStatus,\n error: action.payload.message,\n };\n }\n return file;\n });\n state.errors = [...state.errors, { name: 'Upload Error', message: action.payload.message }];\n },\n retryCancelledFiles(state) {\n // Reset all cancelled files back to pending for retry\n state.files = state.files.map((file) => {\n if (file.status === 'cancelled') {\n return {\n ...file,\n status: 'pending' as FileProgressStatus,\n uploadedBytes: 0,\n };\n }\n return file;\n });\n },\n },\n});\n\n/**\n * Byte-weighted aggregate progress across the whole batch: `sum(uploadedBytes) / sum(size)`.\n *\n * Falls back to count-based progress (settled files / total files) when all sizes are\n * zero — e.g. URL-flow rows where the file size is unknown up front.\n */\nexport const selectAggregateProgress = createSelector(\n (state: RootState) => state.uploadProgress.files,\n (files): number => {\n if (files.length === 0) return 0;\n\n const totalSize = files.reduce((sum, f) => sum + f.size, 0);\n\n if (totalSize === 0) {\n const settled = files.filter(\n (f) => f.status === 'complete' || f.status === 'error' || f.status === 'cancelled'\n ).length;\n return Math.round((settled / files.length) * 100);\n }\n\n const uploadedBytes = files.reduce((sum, f) => sum + f.uploadedBytes, 0);\n return Math.round((uploadedBytes / totalSize) * 100);\n }\n);\n\nexport const {\n openUploadProgress,\n setFileUploading,\n setFileProgress,\n setFileComplete,\n setFileError,\n addUploadErrors,\n closeUploadProgress,\n toggleMinimize,\n cancelUpload,\n setUploadFailed,\n retryCancelledFiles,\n} = uploadProgressSlice.actions;\n\nexport const uploadProgressReducer = uploadProgressSlice.reducer;\n"],"names":["initialState","isVisible","isMinimized","totalFiles","files","errors","uploadId","uploadProgressSlice","createSlice","name","reducers","openUploadProgress","state","action","pendingFiles","payload","fileNames","map","index","status","size","fileSizes","uploadedBytes","setFileUploading","setFileProgress","bytes","file","Math","min","setFileComplete","setFileError","message","error","addUploadErrors","closeUploadProgress","toggleMinimize","cancelUpload","setUploadFailed","retryCancelledFiles","selectAggregateProgress","createSelector","uploadProgress","length","totalSize","reduce","sum","f","settled","filter","round","actions","uploadProgressReducer","reducer"],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Coalesces high-frequency values into at most one flush per animation frame.
5
+ *
6
+ * `XHR.upload.onprogress` can fire many times per second on a fast connection.
7
+ * Dispatching each one to Redux would flood the store, so the orchestrator routes
8
+ * progress through a batcher: many `schedule(value)` calls within a single frame
9
+ * collapse into one `flush(latestValue)` callback.
10
+ *
11
+ * @param flush - Invoked once per frame with the most recent scheduled value.
12
+ */ const createRafBatcher = (flush)=>{
13
+ let frame = null;
14
+ let latest;
15
+ const run = ()=>{
16
+ frame = null;
17
+ flush(latest);
18
+ };
19
+ return {
20
+ /**
21
+ * Records the latest value and ensures a flush is scheduled for the next frame.
22
+ * Repeated calls within the same frame overwrite the value without scheduling
23
+ * additional frames.
24
+ */ schedule (value) {
25
+ latest = value;
26
+ if (frame === null) {
27
+ frame = requestAnimationFrame(run);
28
+ }
29
+ },
30
+ /**
31
+ * Cancels any pending flush so a value scheduled this frame will not fire.
32
+ */ cancel () {
33
+ if (frame !== null) {
34
+ cancelAnimationFrame(frame);
35
+ frame = null;
36
+ }
37
+ }
38
+ };
39
+ };
40
+
41
+ exports.createRafBatcher = createRafBatcher;
42
+ //# sourceMappingURL=createRafBatcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createRafBatcher.js","sources":["../../../../admin/src/future/utils/createRafBatcher.ts"],"sourcesContent":["/**\n * Coalesces high-frequency values into at most one flush per animation frame.\n *\n * `XHR.upload.onprogress` can fire many times per second on a fast connection.\n * Dispatching each one to Redux would flood the store, so the orchestrator routes\n * progress through a batcher: many `schedule(value)` calls within a single frame\n * collapse into one `flush(latestValue)` callback.\n *\n * @param flush - Invoked once per frame with the most recent scheduled value.\n */\nexport const createRafBatcher = <T>(flush: (value: T) => void) => {\n let frame: number | null = null;\n let latest: T;\n\n const run = () => {\n frame = null;\n flush(latest);\n };\n\n return {\n /**\n * Records the latest value and ensures a flush is scheduled for the next frame.\n * Repeated calls within the same frame overwrite the value without scheduling\n * additional frames.\n */\n schedule(value: T) {\n latest = value;\n if (frame === null) {\n frame = requestAnimationFrame(run);\n }\n },\n /**\n * Cancels any pending flush so a value scheduled this frame will not fire.\n */\n cancel() {\n if (frame !== null) {\n cancelAnimationFrame(frame);\n frame = null;\n }\n },\n };\n};\n\nexport type RafBatcher<T> = ReturnType<typeof createRafBatcher<T>>;\n"],"names":["createRafBatcher","flush","frame","latest","run","schedule","value","requestAnimationFrame","cancel","cancelAnimationFrame"],"mappings":";;AAAA;;;;;;;;;IAUO,MAAMA,gBAAAA,GAAmB,CAAIC,KAAAA,GAAAA;AAClC,IAAA,IAAIC,KAAAA,GAAuB,IAAA;IAC3B,IAAIC,MAAAA;AAEJ,IAAA,MAAMC,GAAAA,GAAM,IAAA;QACVF,KAAAA,GAAQ,IAAA;QACRD,KAAAA,CAAME,MAAAA,CAAAA;AACR,IAAA,CAAA;IAEA,OAAO;AACL;;;;AAIC,QACDE,UAASC,KAAQ,EAAA;YACfH,MAAAA,GAASG,KAAAA;AACT,YAAA,IAAIJ,UAAU,IAAA,EAAM;AAClBA,gBAAAA,KAAAA,GAAQK,qBAAAA,CAAsBH,GAAAA,CAAAA;AAChC,YAAA;AACF,QAAA,CAAA;AACA;;QAGAI,MAAAA,CAAAA,GAAAA;AACE,YAAA,IAAIN,UAAU,IAAA,EAAM;gBAClBO,oBAAAA,CAAqBP,KAAAA,CAAAA;gBACrBA,KAAAA,GAAQ,IAAA;AACV,YAAA;AACF,QAAA;AACF,KAAA;AACF;;;;"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Coalesces high-frequency values into at most one flush per animation frame.
3
+ *
4
+ * `XHR.upload.onprogress` can fire many times per second on a fast connection.
5
+ * Dispatching each one to Redux would flood the store, so the orchestrator routes
6
+ * progress through a batcher: many `schedule(value)` calls within a single frame
7
+ * collapse into one `flush(latestValue)` callback.
8
+ *
9
+ * @param flush - Invoked once per frame with the most recent scheduled value.
10
+ */ const createRafBatcher = (flush)=>{
11
+ let frame = null;
12
+ let latest;
13
+ const run = ()=>{
14
+ frame = null;
15
+ flush(latest);
16
+ };
17
+ return {
18
+ /**
19
+ * Records the latest value and ensures a flush is scheduled for the next frame.
20
+ * Repeated calls within the same frame overwrite the value without scheduling
21
+ * additional frames.
22
+ */ schedule (value) {
23
+ latest = value;
24
+ if (frame === null) {
25
+ frame = requestAnimationFrame(run);
26
+ }
27
+ },
28
+ /**
29
+ * Cancels any pending flush so a value scheduled this frame will not fire.
30
+ */ cancel () {
31
+ if (frame !== null) {
32
+ cancelAnimationFrame(frame);
33
+ frame = null;
34
+ }
35
+ }
36
+ };
37
+ };
38
+
39
+ export { createRafBatcher };
40
+ //# sourceMappingURL=createRafBatcher.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createRafBatcher.mjs","sources":["../../../../admin/src/future/utils/createRafBatcher.ts"],"sourcesContent":["/**\n * Coalesces high-frequency values into at most one flush per animation frame.\n *\n * `XHR.upload.onprogress` can fire many times per second on a fast connection.\n * Dispatching each one to Redux would flood the store, so the orchestrator routes\n * progress through a batcher: many `schedule(value)` calls within a single frame\n * collapse into one `flush(latestValue)` callback.\n *\n * @param flush - Invoked once per frame with the most recent scheduled value.\n */\nexport const createRafBatcher = <T>(flush: (value: T) => void) => {\n let frame: number | null = null;\n let latest: T;\n\n const run = () => {\n frame = null;\n flush(latest);\n };\n\n return {\n /**\n * Records the latest value and ensures a flush is scheduled for the next frame.\n * Repeated calls within the same frame overwrite the value without scheduling\n * additional frames.\n */\n schedule(value: T) {\n latest = value;\n if (frame === null) {\n frame = requestAnimationFrame(run);\n }\n },\n /**\n * Cancels any pending flush so a value scheduled this frame will not fire.\n */\n cancel() {\n if (frame !== null) {\n cancelAnimationFrame(frame);\n frame = null;\n }\n },\n };\n};\n\nexport type RafBatcher<T> = ReturnType<typeof createRafBatcher<T>>;\n"],"names":["createRafBatcher","flush","frame","latest","run","schedule","value","requestAnimationFrame","cancel","cancelAnimationFrame"],"mappings":"AAAA;;;;;;;;;IAUO,MAAMA,gBAAAA,GAAmB,CAAIC,KAAAA,GAAAA;AAClC,IAAA,IAAIC,KAAAA,GAAuB,IAAA;IAC3B,IAAIC,MAAAA;AAEJ,IAAA,MAAMC,GAAAA,GAAM,IAAA;QACVF,KAAAA,GAAQ,IAAA;QACRD,KAAAA,CAAME,MAAAA,CAAAA;AACR,IAAA,CAAA;IAEA,OAAO;AACL;;;;AAIC,QACDE,UAASC,KAAQ,EAAA;YACfH,MAAAA,GAASG,KAAAA;AACT,YAAA,IAAIJ,UAAU,IAAA,EAAM;AAClBA,gBAAAA,KAAAA,GAAQK,qBAAAA,CAAsBH,GAAAA,CAAAA;AAChC,YAAA;AACF,QAAA,CAAA;AACA;;QAGAI,MAAAA,CAAAA,GAAAA;AACE,YAAA,IAAIN,UAAU,IAAA,EAAM;gBAClBO,oBAAAA,CAAqBP,KAAAA,CAAAA;gBACrBA,KAAAA,GAAQ,IAAA;AACV,YAAA;AACF,QAAA;AACF,KAAA;AACF;;;;"}
@@ -0,0 +1,19 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Fetch a file at `url` and trigger a browser download with the given filename.
5
+ * Goes via a blob + temporary anchor so we honour the `download` attribute
6
+ * even when the file is served same-origin without `Content-Disposition`.
7
+ */ const downloadFile = async (url, fileName)=>{
8
+ const response = await fetch(url);
9
+ const blob = await response.blob();
10
+ const objectUrl = window.URL.createObjectURL(blob);
11
+ const anchor = document.createElement('a');
12
+ anchor.href = objectUrl;
13
+ anchor.setAttribute('download', fileName);
14
+ anchor.click();
15
+ window.URL.revokeObjectURL(objectUrl);
16
+ };
17
+
18
+ exports.downloadFile = downloadFile;
19
+ //# sourceMappingURL=downloadFile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"downloadFile.js","sources":["../../../../admin/src/future/utils/downloadFile.ts"],"sourcesContent":["/**\n * Fetch a file at `url` and trigger a browser download with the given filename.\n * Goes via a blob + temporary anchor so we honour the `download` attribute\n * even when the file is served same-origin without `Content-Disposition`.\n */\nexport const downloadFile = async (url: string, fileName: string) => {\n const response = await fetch(url);\n const blob = await response.blob();\n const objectUrl = window.URL.createObjectURL(blob);\n const anchor = document.createElement('a');\n anchor.href = objectUrl;\n anchor.setAttribute('download', fileName);\n anchor.click();\n window.URL.revokeObjectURL(objectUrl);\n};\n"],"names":["downloadFile","url","fileName","response","fetch","blob","objectUrl","window","URL","createObjectURL","anchor","document","createElement","href","setAttribute","click","revokeObjectURL"],"mappings":";;AAAA;;;;AAIC,IACM,MAAMA,YAAAA,GAAe,OAAOC,GAAAA,EAAaC,QAAAA,GAAAA;IAC9C,MAAMC,QAAAA,GAAW,MAAMC,KAAAA,CAAMH,GAAAA,CAAAA;IAC7B,MAAMI,IAAAA,GAAO,MAAMF,QAAAA,CAASE,IAAI,EAAA;AAChC,IAAA,MAAMC,SAAAA,GAAYC,MAAAA,CAAOC,GAAG,CAACC,eAAe,CAACJ,IAAAA,CAAAA;IAC7C,MAAMK,MAAAA,GAASC,QAAAA,CAASC,aAAa,CAAC,GAAA,CAAA;AACtCF,IAAAA,MAAAA,CAAOG,IAAI,GAAGP,SAAAA;IACdI,MAAAA,CAAOI,YAAY,CAAC,UAAA,EAAYZ,QAAAA,CAAAA;AAChCQ,IAAAA,MAAAA,CAAOK,KAAK,EAAA;IACZR,MAAAA,CAAOC,GAAG,CAACQ,eAAe,CAACV,SAAAA,CAAAA;AAC7B;;;;"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Fetch a file at `url` and trigger a browser download with the given filename.
3
+ * Goes via a blob + temporary anchor so we honour the `download` attribute
4
+ * even when the file is served same-origin without `Content-Disposition`.
5
+ */ const downloadFile = async (url, fileName)=>{
6
+ const response = await fetch(url);
7
+ const blob = await response.blob();
8
+ const objectUrl = window.URL.createObjectURL(blob);
9
+ const anchor = document.createElement('a');
10
+ anchor.href = objectUrl;
11
+ anchor.setAttribute('download', fileName);
12
+ anchor.click();
13
+ window.URL.revokeObjectURL(objectUrl);
14
+ };
15
+
16
+ export { downloadFile };
17
+ //# sourceMappingURL=downloadFile.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"downloadFile.mjs","sources":["../../../../admin/src/future/utils/downloadFile.ts"],"sourcesContent":["/**\n * Fetch a file at `url` and trigger a browser download with the given filename.\n * Goes via a blob + temporary anchor so we honour the `download` attribute\n * even when the file is served same-origin without `Content-Disposition`.\n */\nexport const downloadFile = async (url: string, fileName: string) => {\n const response = await fetch(url);\n const blob = await response.blob();\n const objectUrl = window.URL.createObjectURL(blob);\n const anchor = document.createElement('a');\n anchor.href = objectUrl;\n anchor.setAttribute('download', fileName);\n anchor.click();\n window.URL.revokeObjectURL(objectUrl);\n};\n"],"names":["downloadFile","url","fileName","response","fetch","blob","objectUrl","window","URL","createObjectURL","anchor","document","createElement","href","setAttribute","click","revokeObjectURL"],"mappings":"AAAA;;;;AAIC,IACM,MAAMA,YAAAA,GAAe,OAAOC,GAAAA,EAAaC,QAAAA,GAAAA;IAC9C,MAAMC,QAAAA,GAAW,MAAMC,KAAAA,CAAMH,GAAAA,CAAAA;IAC7B,MAAMI,IAAAA,GAAO,MAAMF,QAAAA,CAASE,IAAI,EAAA;AAChC,IAAA,MAAMC,SAAAA,GAAYC,MAAAA,CAAOC,GAAG,CAACC,eAAe,CAACJ,IAAAA,CAAAA;IAC7C,MAAMK,MAAAA,GAASC,QAAAA,CAASC,aAAa,CAAC,GAAA,CAAA;AACtCF,IAAAA,MAAAA,CAAOG,IAAI,GAAGP,SAAAA;IACdI,MAAAA,CAAOI,YAAY,CAAC,UAAA,EAAYZ,QAAAA,CAAAA;AAChCQ,IAAAA,MAAAA,CAAOK,KAAK,EAAA;IACZR,MAAAA,CAAOC,GAAG,CAACQ,eAAe,CAACV,SAAAA,CAAAA;AAC7B;;;;"}
@@ -31,7 +31,7 @@ const useAssets = ({ skipWhen = false, query = {} } = {})=>{
31
31
  const { toggleNotification } = strapiAdmin.useNotification();
32
32
  const { notifyStatus } = designSystem.useNotifyAT();
33
33
  const { get } = strapiAdmin.useFetchClient();
34
- const { folderPath, _q, ...paramsExceptFolderAndQ } = query;
34
+ const { folder, folderPath: _folderPath, _q, ...paramsExceptFolderAndQ } = query;
35
35
  let params;
36
36
  if (_q) {
37
37
  params = {
@@ -45,8 +45,10 @@ const useAssets = ({ skipWhen = false, query = {} } = {})=>{
45
45
  $and: [
46
46
  ...paramsExceptFolderAndQ?.filters?.$and ?? [],
47
47
  {
48
- folderPath: {
49
- $eq: folderPath ?? '/'
48
+ folder: {
49
+ id: folder ?? {
50
+ $null: true
51
+ }
50
52
  }
51
53
  }
52
54
  ]
@@ -1 +1 @@
1
- {"version":3,"file":"useAssets.js","sources":["../../../admin/src/hooks/useAssets.ts"],"sourcesContent":["import * as React from 'react';\n\nimport { useNotification, useFetchClient } from '@strapi/admin/strapi-admin';\nimport { useNotifyAT } from '@strapi/design-system';\nimport { useIntl } from 'react-intl';\nimport { useQuery } from 'react-query';\n\nimport { Query, GetFiles } from '../../../shared/contracts/files';\nimport { pluginId } from '../pluginId';\n\ninterface UseAssetsOptions {\n skipWhen?: boolean;\n query?: Query;\n}\n\nexport const useAssets = ({ skipWhen = false, query = {} }: UseAssetsOptions = {}) => {\n const { formatMessage } = useIntl();\n const { toggleNotification } = useNotification();\n const { notifyStatus } = useNotifyAT();\n const { get } = useFetchClient();\n const { folderPath, _q, ...paramsExceptFolderAndQ } = query;\n\n let params: Query;\n\n if (_q) {\n params = {\n ...paramsExceptFolderAndQ,\n _q: encodeURIComponent(_q),\n };\n } else {\n params = {\n ...paramsExceptFolderAndQ,\n filters: {\n $and: [\n ...(paramsExceptFolderAndQ?.filters?.$and ?? []),\n {\n folderPath: { $eq: folderPath ?? '/' },\n },\n ],\n },\n };\n }\n\n const { data, error, isLoading } = useQuery<\n GetFiles.Response['data'],\n GetFiles.Response['error']\n >(\n [pluginId, 'assets', params],\n async () => {\n const { data } = await get('/upload/files', { params });\n\n return data;\n },\n {\n enabled: !skipWhen,\n staleTime: 0,\n cacheTime: 0,\n select(data) {\n if (data?.results && Array.isArray(data.results)) {\n return {\n ...data,\n results: data.results\n /**\n * Filter out assets that don't have a name.\n * So we don't try to render them as assets\n * and get errors.\n */\n .filter((asset) => asset.name)\n .map((asset) => ({\n ...asset,\n /**\n * Mime and ext cannot be null in the front-end because\n * we expect them to be strings and use the `includes` method.\n */\n mime: asset.mime ?? '',\n ext: asset.ext ?? '',\n })),\n };\n }\n\n return data;\n },\n }\n );\n\n React.useEffect(() => {\n if (data) {\n notifyStatus(\n formatMessage({\n id: 'list.asset.at.finished',\n defaultMessage: 'The assets have finished loading.',\n })\n );\n }\n }, [data, formatMessage, notifyStatus]);\n\n React.useEffect(() => {\n if (error) {\n toggleNotification({\n type: 'danger',\n message: formatMessage({ id: 'notification.error' }),\n });\n }\n }, [error, formatMessage, toggleNotification]);\n\n return { data, error, isLoading };\n};\n"],"names":["useAssets","skipWhen","query","formatMessage","useIntl","toggleNotification","useNotification","notifyStatus","useNotifyAT","get","useFetchClient","folderPath","_q","paramsExceptFolderAndQ","params","encodeURIComponent","filters","$and","$eq","data","error","isLoading","useQuery","pluginId","enabled","staleTime","cacheTime","select","results","Array","isArray","filter","asset","name","map","mime","ext","React","useEffect","id","defaultMessage","type","message"],"mappings":"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"}
1
+ {"version":3,"file":"useAssets.js","sources":["../../../admin/src/hooks/useAssets.ts"],"sourcesContent":["import * as React from 'react';\n\nimport { useNotification, useFetchClient } from '@strapi/admin/strapi-admin';\nimport { useNotifyAT } from '@strapi/design-system';\nimport { useIntl } from 'react-intl';\nimport { useQuery } from 'react-query';\n\nimport { Query, GetFiles } from '../../../shared/contracts/files';\nimport { pluginId } from '../pluginId';\n\ninterface UseAssetsOptions {\n skipWhen?: boolean;\n query?: Query;\n}\n\nexport const useAssets = ({ skipWhen = false, query = {} }: UseAssetsOptions = {}) => {\n const { formatMessage } = useIntl();\n const { toggleNotification } = useNotification();\n const { notifyStatus } = useNotifyAT();\n const { get } = useFetchClient();\n const { folder, folderPath: _folderPath, _q, ...paramsExceptFolderAndQ } = query;\n\n let params: Query;\n\n if (_q) {\n params = {\n ...paramsExceptFolderAndQ,\n _q: encodeURIComponent(_q),\n };\n } else {\n params = {\n ...paramsExceptFolderAndQ,\n filters: {\n $and: [\n ...(paramsExceptFolderAndQ?.filters?.$and ?? []),\n {\n folder: {\n id: folder ?? {\n $null: true,\n },\n },\n },\n ],\n },\n };\n }\n\n const { data, error, isLoading } = useQuery<\n GetFiles.Response['data'],\n GetFiles.Response['error']\n >(\n [pluginId, 'assets', params],\n async () => {\n const { data } = await get('/upload/files', { params });\n\n return data;\n },\n {\n enabled: !skipWhen,\n staleTime: 0,\n cacheTime: 0,\n select(data) {\n if (data?.results && Array.isArray(data.results)) {\n return {\n ...data,\n results: data.results\n /**\n * Filter out assets that don't have a name.\n * So we don't try to render them as assets\n * and get errors.\n */\n .filter((asset) => asset.name)\n .map((asset) => ({\n ...asset,\n /**\n * Mime and ext cannot be null in the front-end because\n * we expect them to be strings and use the `includes` method.\n */\n mime: asset.mime ?? '',\n ext: asset.ext ?? '',\n })),\n };\n }\n\n return data;\n },\n }\n );\n\n React.useEffect(() => {\n if (data) {\n notifyStatus(\n formatMessage({\n id: 'list.asset.at.finished',\n defaultMessage: 'The assets have finished loading.',\n })\n );\n }\n }, [data, formatMessage, notifyStatus]);\n\n React.useEffect(() => {\n if (error) {\n toggleNotification({\n type: 'danger',\n message: formatMessage({ id: 'notification.error' }),\n });\n }\n }, [error, formatMessage, toggleNotification]);\n\n return { data, error, isLoading };\n};\n"],"names":["useAssets","skipWhen","query","formatMessage","useIntl","toggleNotification","useNotification","notifyStatus","useNotifyAT","get","useFetchClient","folder","folderPath","_folderPath","_q","paramsExceptFolderAndQ","params","encodeURIComponent","filters","$and","id","$null","data","error","isLoading","useQuery","pluginId","enabled","staleTime","cacheTime","select","results","Array","isArray","filter","asset","name","map","mime","ext","React","useEffect","defaultMessage","type","message"],"mappings":"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"}
@@ -10,7 +10,7 @@ const useAssets = ({ skipWhen = false, query = {} } = {})=>{
10
10
  const { toggleNotification } = useNotification();
11
11
  const { notifyStatus } = useNotifyAT();
12
12
  const { get } = useFetchClient();
13
- const { folderPath, _q, ...paramsExceptFolderAndQ } = query;
13
+ const { folder, folderPath: _folderPath, _q, ...paramsExceptFolderAndQ } = query;
14
14
  let params;
15
15
  if (_q) {
16
16
  params = {
@@ -24,8 +24,10 @@ const useAssets = ({ skipWhen = false, query = {} } = {})=>{
24
24
  $and: [
25
25
  ...paramsExceptFolderAndQ?.filters?.$and ?? [],
26
26
  {
27
- folderPath: {
28
- $eq: folderPath ?? '/'
27
+ folder: {
28
+ id: folder ?? {
29
+ $null: true
30
+ }
29
31
  }
30
32
  }
31
33
  ]
@@ -1 +1 @@
1
- {"version":3,"file":"useAssets.mjs","sources":["../../../admin/src/hooks/useAssets.ts"],"sourcesContent":["import * as React from 'react';\n\nimport { useNotification, useFetchClient } from '@strapi/admin/strapi-admin';\nimport { useNotifyAT } from '@strapi/design-system';\nimport { useIntl } from 'react-intl';\nimport { useQuery } from 'react-query';\n\nimport { Query, GetFiles } from '../../../shared/contracts/files';\nimport { pluginId } from '../pluginId';\n\ninterface UseAssetsOptions {\n skipWhen?: boolean;\n query?: Query;\n}\n\nexport const useAssets = ({ skipWhen = false, query = {} }: UseAssetsOptions = {}) => {\n const { formatMessage } = useIntl();\n const { toggleNotification } = useNotification();\n const { notifyStatus } = useNotifyAT();\n const { get } = useFetchClient();\n const { folderPath, _q, ...paramsExceptFolderAndQ } = query;\n\n let params: Query;\n\n if (_q) {\n params = {\n ...paramsExceptFolderAndQ,\n _q: encodeURIComponent(_q),\n };\n } else {\n params = {\n ...paramsExceptFolderAndQ,\n filters: {\n $and: [\n ...(paramsExceptFolderAndQ?.filters?.$and ?? []),\n {\n folderPath: { $eq: folderPath ?? '/' },\n },\n ],\n },\n };\n }\n\n const { data, error, isLoading } = useQuery<\n GetFiles.Response['data'],\n GetFiles.Response['error']\n >(\n [pluginId, 'assets', params],\n async () => {\n const { data } = await get('/upload/files', { params });\n\n return data;\n },\n {\n enabled: !skipWhen,\n staleTime: 0,\n cacheTime: 0,\n select(data) {\n if (data?.results && Array.isArray(data.results)) {\n return {\n ...data,\n results: data.results\n /**\n * Filter out assets that don't have a name.\n * So we don't try to render them as assets\n * and get errors.\n */\n .filter((asset) => asset.name)\n .map((asset) => ({\n ...asset,\n /**\n * Mime and ext cannot be null in the front-end because\n * we expect them to be strings and use the `includes` method.\n */\n mime: asset.mime ?? '',\n ext: asset.ext ?? '',\n })),\n };\n }\n\n return data;\n },\n }\n );\n\n React.useEffect(() => {\n if (data) {\n notifyStatus(\n formatMessage({\n id: 'list.asset.at.finished',\n defaultMessage: 'The assets have finished loading.',\n })\n );\n }\n }, [data, formatMessage, notifyStatus]);\n\n React.useEffect(() => {\n if (error) {\n toggleNotification({\n type: 'danger',\n message: formatMessage({ id: 'notification.error' }),\n });\n }\n }, [error, formatMessage, toggleNotification]);\n\n return { data, error, isLoading };\n};\n"],"names":["useAssets","skipWhen","query","formatMessage","useIntl","toggleNotification","useNotification","notifyStatus","useNotifyAT","get","useFetchClient","folderPath","_q","paramsExceptFolderAndQ","params","encodeURIComponent","filters","$and","$eq","data","error","isLoading","useQuery","pluginId","enabled","staleTime","cacheTime","select","results","Array","isArray","filter","asset","name","map","mime","ext","React","useEffect","id","defaultMessage","type","message"],"mappings":"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"}
1
+ {"version":3,"file":"useAssets.mjs","sources":["../../../admin/src/hooks/useAssets.ts"],"sourcesContent":["import * as React from 'react';\n\nimport { useNotification, useFetchClient } from '@strapi/admin/strapi-admin';\nimport { useNotifyAT } from '@strapi/design-system';\nimport { useIntl } from 'react-intl';\nimport { useQuery } from 'react-query';\n\nimport { Query, GetFiles } from '../../../shared/contracts/files';\nimport { pluginId } from '../pluginId';\n\ninterface UseAssetsOptions {\n skipWhen?: boolean;\n query?: Query;\n}\n\nexport const useAssets = ({ skipWhen = false, query = {} }: UseAssetsOptions = {}) => {\n const { formatMessage } = useIntl();\n const { toggleNotification } = useNotification();\n const { notifyStatus } = useNotifyAT();\n const { get } = useFetchClient();\n const { folder, folderPath: _folderPath, _q, ...paramsExceptFolderAndQ } = query;\n\n let params: Query;\n\n if (_q) {\n params = {\n ...paramsExceptFolderAndQ,\n _q: encodeURIComponent(_q),\n };\n } else {\n params = {\n ...paramsExceptFolderAndQ,\n filters: {\n $and: [\n ...(paramsExceptFolderAndQ?.filters?.$and ?? []),\n {\n folder: {\n id: folder ?? {\n $null: true,\n },\n },\n },\n ],\n },\n };\n }\n\n const { data, error, isLoading } = useQuery<\n GetFiles.Response['data'],\n GetFiles.Response['error']\n >(\n [pluginId, 'assets', params],\n async () => {\n const { data } = await get('/upload/files', { params });\n\n return data;\n },\n {\n enabled: !skipWhen,\n staleTime: 0,\n cacheTime: 0,\n select(data) {\n if (data?.results && Array.isArray(data.results)) {\n return {\n ...data,\n results: data.results\n /**\n * Filter out assets that don't have a name.\n * So we don't try to render them as assets\n * and get errors.\n */\n .filter((asset) => asset.name)\n .map((asset) => ({\n ...asset,\n /**\n * Mime and ext cannot be null in the front-end because\n * we expect them to be strings and use the `includes` method.\n */\n mime: asset.mime ?? '',\n ext: asset.ext ?? '',\n })),\n };\n }\n\n return data;\n },\n }\n );\n\n React.useEffect(() => {\n if (data) {\n notifyStatus(\n formatMessage({\n id: 'list.asset.at.finished',\n defaultMessage: 'The assets have finished loading.',\n })\n );\n }\n }, [data, formatMessage, notifyStatus]);\n\n React.useEffect(() => {\n if (error) {\n toggleNotification({\n type: 'danger',\n message: formatMessage({ id: 'notification.error' }),\n });\n }\n }, [error, formatMessage, toggleNotification]);\n\n return { data, error, isLoading };\n};\n"],"names":["useAssets","skipWhen","query","formatMessage","useIntl","toggleNotification","useNotification","notifyStatus","useNotifyAT","get","useFetchClient","folder","folderPath","_folderPath","_q","paramsExceptFolderAndQ","params","encodeURIComponent","filters","$and","id","$null","data","error","isLoading","useQuery","pluginId","enabled","staleTime","cacheTime","select","results","Array","isArray","filter","asset","name","map","mime","ext","React","useEffect","defaultMessage","type","message"],"mappings":"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"}
@@ -8,6 +8,7 @@ export interface Asset extends Omit<FileDefinition, 'folder'> {
8
8
  }
9
9
  interface EditAssetContentProps {
10
10
  asset?: Asset;
11
+ initialFolderId?: string | number | null;
11
12
  canUpdate?: boolean;
12
13
  canCopyLink?: boolean;
13
14
  canDownload?: boolean;
@@ -16,7 +17,7 @@ interface EditAssetContentProps {
16
17
  omitFields?: ('caption' | 'alternativeText')[];
17
18
  omitActions?: 'replace'[];
18
19
  }
19
- export declare const EditAssetContent: ({ onClose, asset, canUpdate, canCopyLink, canDownload, trackedLocation, omitFields, omitActions, }: EditAssetContentProps) => import("react/jsx-runtime").JSX.Element;
20
+ export declare const EditAssetContent: ({ onClose, asset, initialFolderId, canUpdate, canCopyLink, canDownload, trackedLocation, omitFields, omitActions, }: EditAssetContentProps) => import("react/jsx-runtime").JSX.Element;
20
21
  interface EditAssetDialogProps {
21
22
  asset: Asset;
22
23
  canUpdate?: boolean;
@@ -1,5 +1,18 @@
1
1
  import * as React from 'react';
2
2
  import type { AssetWithPopulatedCreatedBy } from '../../../../../../../shared/contracts/files';
3
+ interface DrawerToast {
4
+ type: 'success' | 'danger';
5
+ message: string;
6
+ }
7
+ type DrawerNotify = (toast: DrawerToast) => void;
8
+ export declare const DrawerNotifyContext: React.Context<DrawerNotify | null>;
9
+ interface AssetOperations {
10
+ replaceAsset: (file: globalThis.File) => Promise<void>;
11
+ deleteAsset: () => Promise<void>;
12
+ isReplacing: boolean;
13
+ isDeleting: boolean;
14
+ }
15
+ export declare const AssetOperationsContext: React.Context<AssetOperations | null>;
3
16
  export declare const useAssetDetailsParam: () => {
4
17
  assetId: number | null;
5
18
  isVisible: boolean;
@@ -10,7 +23,8 @@ export declare const useAssetDetailsParam: () => {
10
23
  };
11
24
  interface AssetDetailsProps {
12
25
  asset: AssetWithPopulatedCreatedBy;
26
+ closeDetails: () => void;
13
27
  }
14
- export declare const AssetDetails: ({ asset }: AssetDetailsProps) => import("react/jsx-runtime").JSX.Element;
28
+ export declare const AssetDetails: ({ asset, closeDetails }: AssetDetailsProps) => import("react/jsx-runtime").JSX.Element;
15
29
  export declare const AssetDetailsDrawer: () => import("react/jsx-runtime").JSX.Element | null;
16
30
  export {};
@@ -1,6 +1,9 @@
1
+ import * as React from 'react';
1
2
  import type { File, AssetWithPopulatedCreatedBy } from '../../../../../../../shared/contracts/files';
2
3
  interface AssetPreviewProps {
3
4
  asset: File | AssetWithPopulatedCreatedBy;
5
+ actions?: React.ReactNode;
6
+ isLoading?: boolean;
4
7
  }
5
- export declare const AssetPreview: ({ asset }: AssetPreviewProps) => import("react/jsx-runtime").JSX.Element;
8
+ export declare const AssetPreview: ({ asset, actions, isLoading }: AssetPreviewProps) => import("react/jsx-runtime").JSX.Element;
6
9
  export {};