@strapi/upload 5.59.0 → 5.60.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/dist/admin/components/AssetPickerDialog/AssetPickerDialog.js +434 -0
  2. package/dist/admin/components/AssetPickerDialog/AssetPickerDialog.js.map +1 -0
  3. package/dist/admin/components/AssetPickerDialog/AssetPickerDialog.mjs +432 -0
  4. package/dist/admin/components/AssetPickerDialog/AssetPickerDialog.mjs.map +1 -0
  5. package/dist/admin/components/AssetPickerDialog/FolderBreadcrumbs.js +91 -0
  6. package/dist/admin/components/AssetPickerDialog/FolderBreadcrumbs.js.map +1 -0
  7. package/dist/admin/components/AssetPickerDialog/FolderBreadcrumbs.mjs +89 -0
  8. package/dist/admin/components/AssetPickerDialog/FolderBreadcrumbs.mjs.map +1 -0
  9. package/dist/admin/components/AssetPickerDialog/PickerSelectionProvider.js +178 -0
  10. package/dist/admin/components/AssetPickerDialog/PickerSelectionProvider.js.map +1 -0
  11. package/dist/admin/components/AssetPickerDialog/PickerSelectionProvider.mjs +175 -0
  12. package/dist/admin/components/AssetPickerDialog/PickerSelectionProvider.mjs.map +1 -0
  13. package/dist/admin/components/AssetPickerDialog/SortableSelection.js +143 -0
  14. package/dist/admin/components/AssetPickerDialog/SortableSelection.js.map +1 -0
  15. package/dist/admin/components/AssetPickerDialog/SortableSelection.mjs +141 -0
  16. package/dist/admin/components/AssetPickerDialog/SortableSelection.mjs.map +1 -0
  17. package/dist/admin/components/AssetPickerDialog/pickerSelection.js +49 -0
  18. package/dist/admin/components/AssetPickerDialog/pickerSelection.js.map +1 -0
  19. package/dist/admin/components/AssetPickerDialog/pickerSelection.mjs +41 -0
  20. package/dist/admin/components/AssetPickerDialog/pickerSelection.mjs.map +1 -0
  21. package/dist/admin/components/MediaLibraryInput/AddAssetMenu.js +4 -3
  22. package/dist/admin/components/MediaLibraryInput/AddAssetMenu.js.map +1 -1
  23. package/dist/admin/components/MediaLibraryInput/AddAssetMenu.mjs +4 -3
  24. package/dist/admin/components/MediaLibraryInput/AddAssetMenu.mjs.map +1 -1
  25. package/dist/admin/components/MediaLibraryInput/AssetCard.js +240 -0
  26. package/dist/admin/components/MediaLibraryInput/AssetCard.js.map +1 -0
  27. package/dist/admin/components/MediaLibraryInput/AssetCard.mjs +237 -0
  28. package/dist/admin/components/MediaLibraryInput/AssetCard.mjs.map +1 -0
  29. package/dist/admin/components/MediaLibraryInput/AssetCarousel.js +161 -0
  30. package/dist/admin/components/MediaLibraryInput/AssetCarousel.js.map +1 -0
  31. package/dist/admin/components/MediaLibraryInput/AssetCarousel.mjs +159 -0
  32. package/dist/admin/components/MediaLibraryInput/AssetCarousel.mjs.map +1 -0
  33. package/dist/admin/components/MediaLibraryInput/AssetDropZone.js +76 -49
  34. package/dist/admin/components/MediaLibraryInput/AssetDropZone.js.map +1 -1
  35. package/dist/admin/components/MediaLibraryInput/AssetDropZone.mjs +77 -50
  36. package/dist/admin/components/MediaLibraryInput/AssetDropZone.mjs.map +1 -1
  37. package/dist/admin/components/MediaLibraryInput/AssetPreview.js +109 -0
  38. package/dist/admin/components/MediaLibraryInput/AssetPreview.js.map +1 -0
  39. package/dist/admin/components/MediaLibraryInput/AssetPreview.mjs +106 -0
  40. package/dist/admin/components/MediaLibraryInput/AssetPreview.mjs.map +1 -0
  41. package/dist/admin/components/MediaLibraryInput/AssetRow.js +146 -79
  42. package/dist/admin/components/MediaLibraryInput/AssetRow.js.map +1 -1
  43. package/dist/admin/components/MediaLibraryInput/AssetRow.mjs +148 -82
  44. package/dist/admin/components/MediaLibraryInput/AssetRow.mjs.map +1 -1
  45. package/dist/admin/components/MediaLibraryInput/FieldControls.js +32 -0
  46. package/dist/admin/components/MediaLibraryInput/FieldControls.js.map +1 -0
  47. package/dist/admin/components/MediaLibraryInput/FieldControls.mjs +29 -0
  48. package/dist/admin/components/MediaLibraryInput/FieldControls.mjs.map +1 -0
  49. package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.js +130 -88
  50. package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.js.map +1 -1
  51. package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.mjs +129 -91
  52. package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.mjs.map +1 -1
  53. package/dist/admin/components/MediaLibraryInput/UploadProgressBar.js +42 -0
  54. package/dist/admin/components/MediaLibraryInput/UploadProgressBar.js.map +1 -0
  55. package/dist/admin/components/MediaLibraryInput/UploadProgressBar.mjs +40 -0
  56. package/dist/admin/components/MediaLibraryInput/UploadProgressBar.mjs.map +1 -0
  57. package/dist/admin/components/MediaLibraryInput/useFieldUploads.js +122 -0
  58. package/dist/admin/components/MediaLibraryInput/useFieldUploads.js.map +1 -0
  59. package/dist/admin/components/MediaLibraryInput/useFieldUploads.mjs +120 -0
  60. package/dist/admin/components/MediaLibraryInput/useFieldUploads.mjs.map +1 -0
  61. package/dist/admin/components/UploadProgressDialog.js +2 -1
  62. package/dist/admin/components/UploadProgressDialog.js.map +1 -1
  63. package/dist/admin/components/UploadProgressDialog.mjs +2 -1
  64. package/dist/admin/components/UploadProgressDialog.mjs.map +1 -1
  65. package/dist/admin/hooks/useMediaLibraryPermissions.js +12 -2
  66. package/dist/admin/hooks/useMediaLibraryPermissions.js.map +1 -1
  67. package/dist/admin/hooks/useMediaLibraryPermissions.mjs +12 -2
  68. package/dist/admin/hooks/useMediaLibraryPermissions.mjs.map +1 -1
  69. package/dist/admin/pages/Assets/AssetsPage.js +13 -302
  70. package/dist/admin/pages/Assets/AssetsPage.js.map +1 -1
  71. package/dist/admin/pages/Assets/AssetsPage.mjs +11 -280
  72. package/dist/admin/pages/Assets/AssetsPage.mjs.map +1 -1
  73. package/dist/admin/pages/Assets/components/AssetsGrid.js +142 -31
  74. package/dist/admin/pages/Assets/components/AssetsGrid.js.map +1 -1
  75. package/dist/admin/pages/Assets/components/AssetsGrid.mjs +145 -34
  76. package/dist/admin/pages/Assets/components/AssetsGrid.mjs.map +1 -1
  77. package/dist/admin/pages/Assets/components/AssetsSearchInput.js +43 -2
  78. package/dist/admin/pages/Assets/components/AssetsSearchInput.js.map +1 -1
  79. package/dist/admin/pages/Assets/components/AssetsSearchInput.mjs +45 -4
  80. package/dist/admin/pages/Assets/components/AssetsSearchInput.mjs.map +1 -1
  81. package/dist/admin/pages/Assets/components/AssetsTable.js +58 -34
  82. package/dist/admin/pages/Assets/components/AssetsTable.js.map +1 -1
  83. package/dist/admin/pages/Assets/components/AssetsTable.mjs +60 -36
  84. package/dist/admin/pages/Assets/components/AssetsTable.mjs.map +1 -1
  85. package/dist/admin/pages/Assets/components/AssetsView.js +145 -0
  86. package/dist/admin/pages/Assets/components/AssetsView.js.map +1 -0
  87. package/dist/admin/pages/Assets/components/AssetsView.mjs +143 -0
  88. package/dist/admin/pages/Assets/components/AssetsView.mjs.map +1 -0
  89. package/dist/admin/pages/Assets/components/BulkActionsBar.mjs +1 -1
  90. package/dist/admin/pages/Assets/components/BusyOverlay.mjs +1 -1
  91. package/dist/admin/pages/Assets/components/Dnd/DragOverlayChip.mjs +1 -1
  92. package/dist/admin/pages/Assets/components/Dnd/ReorderHandle.js +40 -0
  93. package/dist/admin/pages/Assets/components/Dnd/ReorderHandle.js.map +1 -0
  94. package/dist/admin/pages/Assets/components/Dnd/ReorderHandle.mjs +38 -0
  95. package/dist/admin/pages/Assets/components/Dnd/ReorderHandle.mjs.map +1 -0
  96. package/dist/admin/pages/Assets/components/Dnd/assetSortable.js +29 -0
  97. package/dist/admin/pages/Assets/components/Dnd/assetSortable.js.map +1 -0
  98. package/dist/admin/pages/Assets/components/Dnd/assetSortable.mjs +24 -0
  99. package/dist/admin/pages/Assets/components/Dnd/assetSortable.mjs.map +1 -0
  100. package/dist/admin/pages/Assets/components/Dnd/dndIds.js +5 -0
  101. package/dist/admin/pages/Assets/components/Dnd/dndIds.js.map +1 -1
  102. package/dist/admin/pages/Assets/components/Dnd/dndIds.mjs +5 -1
  103. package/dist/admin/pages/Assets/components/Dnd/dndIds.mjs.map +1 -1
  104. package/dist/admin/pages/Assets/components/Dnd/useAssetDnd.js +41 -13
  105. package/dist/admin/pages/Assets/components/Dnd/useAssetDnd.js.map +1 -1
  106. package/dist/admin/pages/Assets/components/Dnd/useAssetDnd.mjs +41 -13
  107. package/dist/admin/pages/Assets/components/Dnd/useAssetDnd.mjs.map +1 -1
  108. package/dist/admin/pages/Assets/components/FilterBadges.mjs +2 -2
  109. package/dist/admin/pages/Assets/components/FilterMenu.mjs +2 -2
  110. package/dist/admin/pages/Assets/components/FolderTree/FolderTree.js +274 -55
  111. package/dist/admin/pages/Assets/components/FolderTree/FolderTree.js.map +1 -1
  112. package/dist/admin/pages/Assets/components/FolderTree/FolderTree.mjs +277 -59
  113. package/dist/admin/pages/Assets/components/FolderTree/FolderTree.mjs.map +1 -1
  114. package/dist/admin/pages/Assets/components/FolderTree/collapsedBranch.js +32 -0
  115. package/dist/admin/pages/Assets/components/FolderTree/collapsedBranch.js.map +1 -0
  116. package/dist/admin/pages/Assets/components/FolderTree/collapsedBranch.mjs +29 -0
  117. package/dist/admin/pages/Assets/components/FolderTree/collapsedBranch.mjs.map +1 -0
  118. package/dist/admin/pages/Assets/components/ViewToggle.js +126 -0
  119. package/dist/admin/pages/Assets/components/ViewToggle.js.map +1 -0
  120. package/dist/admin/pages/Assets/components/ViewToggle.mjs +104 -0
  121. package/dist/admin/pages/Assets/components/ViewToggle.mjs.map +1 -0
  122. package/dist/admin/pages/Assets/hooks/useAssetSearch.js +2 -2
  123. package/dist/admin/pages/Assets/hooks/useAssetSearch.js.map +1 -1
  124. package/dist/admin/pages/Assets/hooks/useAssetSearch.mjs +2 -2
  125. package/dist/admin/pages/Assets/hooks/useAssetSearch.mjs.map +1 -1
  126. package/dist/admin/pages/Assets/hooks/useAssetSelection.js +19 -1
  127. package/dist/admin/pages/Assets/hooks/useAssetSelection.js.map +1 -1
  128. package/dist/admin/pages/Assets/hooks/useAssetSelection.mjs +20 -3
  129. package/dist/admin/pages/Assets/hooks/useAssetSelection.mjs.map +1 -1
  130. package/dist/admin/pages/Assets/hooks/useAssetsList.js +87 -0
  131. package/dist/admin/pages/Assets/hooks/useAssetsList.js.map +1 -0
  132. package/dist/admin/pages/Assets/hooks/useAssetsList.mjs +85 -0
  133. package/dist/admin/pages/Assets/hooks/useAssetsList.mjs.map +1 -0
  134. package/dist/admin/pages/Assets/hooks/useBusyAssets.mjs +1 -1
  135. package/dist/admin/pages/Assets/hooks/useFolderNavigation.js +2 -1
  136. package/dist/admin/pages/Assets/hooks/useFolderNavigation.js.map +1 -1
  137. package/dist/admin/pages/Assets/hooks/useFolderNavigation.mjs +3 -2
  138. package/dist/admin/pages/Assets/hooks/useFolderNavigation.mjs.map +1 -1
  139. package/dist/admin/pages/Assets/hooks/useListFilters.js +2 -1
  140. package/dist/admin/pages/Assets/hooks/useListFilters.js.map +1 -1
  141. package/dist/admin/pages/Assets/hooks/useListFilters.mjs +3 -2
  142. package/dist/admin/pages/Assets/hooks/useListFilters.mjs.map +1 -1
  143. package/dist/admin/pages/Assets/hooks/useListQueryParams.js +80 -0
  144. package/dist/admin/pages/Assets/hooks/useListQueryParams.js.map +1 -0
  145. package/dist/admin/pages/Assets/hooks/useListQueryParams.mjs +77 -0
  146. package/dist/admin/pages/Assets/hooks/useListQueryParams.mjs.map +1 -0
  147. package/dist/admin/pages/Assets/hooks/useListSettings.js +32 -0
  148. package/dist/admin/pages/Assets/hooks/useListSettings.js.map +1 -0
  149. package/dist/admin/pages/Assets/hooks/useListSettings.mjs +29 -0
  150. package/dist/admin/pages/Assets/hooks/useListSettings.mjs.map +1 -0
  151. package/dist/admin/pages/Assets/hooks/useListSort.js +2 -1
  152. package/dist/admin/pages/Assets/hooks/useListSort.js.map +1 -1
  153. package/dist/admin/pages/Assets/hooks/useListSort.mjs +3 -2
  154. package/dist/admin/pages/Assets/hooks/useListSort.mjs.map +1 -1
  155. package/dist/admin/services/api.js +92 -7
  156. package/dist/admin/services/api.js.map +1 -1
  157. package/dist/admin/services/api.mjs +91 -9
  158. package/dist/admin/services/api.mjs.map +1 -1
  159. package/dist/admin/src/components/AssetPickerDialog/AssetPickerDialog.d.ts +19 -0
  160. package/dist/admin/src/components/AssetPickerDialog/FolderBreadcrumbs.d.ts +10 -0
  161. package/dist/admin/src/components/AssetPickerDialog/PickerSelectionProvider.d.ts +28 -0
  162. package/dist/admin/src/components/AssetPickerDialog/SortableSelection.d.ts +12 -0
  163. package/dist/admin/src/components/AssetPickerDialog/pickerSelection.d.ts +26 -0
  164. package/dist/admin/src/components/MediaLibraryInput/AssetCard.d.ts +25 -0
  165. package/dist/admin/src/components/MediaLibraryInput/AssetCarousel.d.ts +16 -0
  166. package/dist/admin/src/components/MediaLibraryInput/AssetDropZone.d.ts +11 -3
  167. package/dist/admin/src/components/MediaLibraryInput/AssetPreview.d.ts +17 -0
  168. package/dist/admin/src/components/MediaLibraryInput/AssetRow.d.ts +13 -3
  169. package/dist/admin/src/components/MediaLibraryInput/FieldControls.d.ts +19 -0
  170. package/dist/admin/src/components/MediaLibraryInput/MediaLibraryInput.d.ts +3 -1
  171. package/dist/admin/src/components/MediaLibraryInput/UploadProgressBar.d.ts +7 -0
  172. package/dist/admin/src/components/MediaLibraryInput/useFieldUploads.d.ts +31 -0
  173. package/dist/admin/src/hooks/useMediaLibraryPermissions.d.ts +2 -0
  174. package/dist/admin/src/pages/Assets/components/AssetsGrid.d.ts +3 -1
  175. package/dist/admin/src/pages/Assets/components/AssetsSearchInput.d.ts +11 -1
  176. package/dist/admin/src/pages/Assets/components/AssetsView.d.ts +29 -0
  177. package/dist/admin/src/pages/Assets/components/Dnd/ReorderHandle.d.ts +12 -0
  178. package/dist/admin/src/pages/Assets/components/Dnd/assetSortable.d.ts +37 -0
  179. package/dist/admin/src/pages/Assets/components/Dnd/dndIds.d.ts +5 -0
  180. package/dist/admin/src/pages/Assets/components/Dnd/useAssetDnd.d.ts +23 -2
  181. package/dist/admin/src/pages/Assets/components/FolderTree/FolderTree.d.ts +1 -0
  182. package/dist/admin/src/pages/Assets/components/FolderTree/collapsedBranch.d.ts +21 -0
  183. package/dist/admin/src/pages/Assets/components/ViewToggle.d.ts +8 -0
  184. package/dist/admin/src/pages/Assets/hooks/useAssetSelection.d.ts +26 -0
  185. package/dist/admin/src/pages/Assets/hooks/useAssetsList.d.ts +30 -0
  186. package/dist/admin/src/pages/Assets/hooks/useListQueryParams.d.ts +27 -0
  187. package/dist/admin/src/pages/Assets/hooks/useListSettings.d.ts +29 -0
  188. package/dist/admin/src/services/api.d.ts +24 -1
  189. package/dist/admin/src/store/uploadProgress.d.ts +14 -1
  190. package/dist/admin/src/utils/findFolderPath.d.ts +6 -0
  191. package/dist/admin/src/utils/isAllowedAssetType.d.ts +14 -0
  192. package/dist/admin/store/uploadProgress.js +30 -3
  193. package/dist/admin/store/uploadProgress.js.map +1 -1
  194. package/dist/admin/store/uploadProgress.mjs +29 -4
  195. package/dist/admin/store/uploadProgress.mjs.map +1 -1
  196. package/dist/admin/translations/en.json.js +20 -0
  197. package/dist/admin/translations/en.json.js.map +1 -1
  198. package/dist/admin/translations/en.json.mjs +20 -0
  199. package/dist/admin/translations/en.json.mjs.map +1 -1
  200. package/dist/admin/utils/findFolderPath.js +26 -0
  201. package/dist/admin/utils/findFolderPath.js.map +1 -0
  202. package/dist/admin/utils/findFolderPath.mjs +24 -0
  203. package/dist/admin/utils/findFolderPath.mjs.map +1 -0
  204. package/dist/admin/utils/isAllowedAssetType.js +33 -0
  205. package/dist/admin/utils/isAllowedAssetType.js.map +1 -0
  206. package/dist/admin/utils/isAllowedAssetType.mjs +31 -0
  207. package/dist/admin/utils/isAllowedAssetType.mjs.map +1 -0
  208. package/dist/server/controllers/admin-settings.js +5 -1
  209. package/dist/server/controllers/admin-settings.js.map +1 -1
  210. package/dist/server/controllers/admin-settings.mjs +5 -1
  211. package/dist/server/controllers/admin-settings.mjs.map +1 -1
  212. package/dist/server/services/image-manipulation.js +2 -2
  213. package/dist/server/services/image-manipulation.js.map +1 -1
  214. package/dist/server/services/image-manipulation.mjs +2 -2
  215. package/dist/server/services/image-manipulation.mjs.map +1 -1
  216. package/dist/server/services/upload.js.map +1 -1
  217. package/dist/server/services/upload.mjs.map +1 -1
  218. package/dist/server/src/controllers/admin-settings.d.ts.map +1 -1
  219. package/dist/server/src/index.d.ts +1 -1
  220. package/dist/server/src/services/extensions/utils.d.ts +11 -11
  221. package/dist/server/src/services/image-manipulation.d.ts +1 -1
  222. package/dist/server/src/services/image-manipulation.d.ts.map +1 -1
  223. package/dist/server/src/services/index.d.ts +1 -1
  224. package/dist/server/src/types.d.ts +63 -12
  225. package/dist/server/src/types.d.ts.map +1 -1
  226. package/package.json +8 -6
  227. package/dist/admin/components/MediaLibraryInput/NoLibraryAccessDialog.js +0 -45
  228. package/dist/admin/components/MediaLibraryInput/NoLibraryAccessDialog.js.map +0 -1
  229. package/dist/admin/components/MediaLibraryInput/NoLibraryAccessDialog.mjs +0 -43
  230. package/dist/admin/components/MediaLibraryInput/NoLibraryAccessDialog.mjs.map +0 -1
  231. package/dist/admin/src/components/MediaLibraryInput/NoLibraryAccessDialog.d.ts +0 -10
@@ -0,0 +1,122 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+ var reactRedux = require('react-redux');
5
+ var api = require('../../services/api.js');
6
+ var hooks = require('../../store/hooks.js');
7
+ var uploadProgress = require('../../store/uploadProgress.js');
8
+
9
+ const NO_ROWS = [];
10
+ const getKey = (uploadId, index)=>`${uploadId}:${index}`;
11
+ const toProgress = ({ status, size, uploadedBytes })=>{
12
+ if (status === 'pending') {
13
+ return 0;
14
+ }
15
+ return size > 0 ? Math.round(uploadedBytes / size * 100) : null;
16
+ };
17
+ /**
18
+ * The uploads a field started, read from the shared progress store so the field
19
+ * and the progress dialog always agree.
20
+ *
21
+ * The store only holds the latest batch, and closing the dialog empties it. Rows
22
+ * are therefore remembered here once seen: a failed upload stays on the field
23
+ * until the user retries or removes it, whatever happened to the dialog. A row
24
+ * that vanished while still in flight was cancelled along with its batch.
25
+ *
26
+ * Completed rows leave the list. Attaching them to the field is the upload's
27
+ * `onFileUploaded`, which outlives the input.
28
+ */ const useFieldUploads = (owner)=>{
29
+ const dispatch = hooks.useTypedDispatch();
30
+ const [retryUploadFile] = api.useRetryUploadFileMutation();
31
+ // The plugin registers the slice in `register()`; a host that has not has no
32
+ // uploads to show.
33
+ const currentUploadId = hooks.useTypedSelector((state)=>state.uploadProgress?.uploadId ?? 0);
34
+ const ownedRows = hooks.useTypedSelector((state)=>(state.uploadProgress?.files ?? NO_ROWS).filter((file)=>file.owner === owner), reactRedux.shallowEqual);
35
+ const trackedRef = React.useRef(new Map());
36
+ const [dismissed, setDismissed] = React.useState(()=>new Set());
37
+ const tracked = trackedRef.current;
38
+ const liveKeys = new Set();
39
+ ownedRows.forEach((row)=>{
40
+ const key = getKey(currentUploadId, row.index);
41
+ liveKeys.add(key);
42
+ tracked.set(key, {
43
+ uploadId: currentUploadId,
44
+ row
45
+ });
46
+ });
47
+ tracked.forEach((entry, key)=>{
48
+ const isInFlight = entry.row.status === 'pending' || entry.row.status === 'uploading';
49
+ if (!liveKeys.has(key) && isInFlight) {
50
+ tracked.set(key, {
51
+ ...entry,
52
+ row: {
53
+ ...entry.row,
54
+ status: 'cancelled'
55
+ }
56
+ });
57
+ }
58
+ });
59
+ const uploads = [];
60
+ tracked.forEach(({ uploadId, row }, key)=>{
61
+ const isInFlight = row.status === 'pending' || row.status === 'uploading';
62
+ const isFailed = row.status === 'error' && !dismissed.has(key);
63
+ if (!isInFlight && !isFailed) {
64
+ return;
65
+ }
66
+ uploads.push({
67
+ key,
68
+ uploadId,
69
+ index: row.index,
70
+ name: row.name,
71
+ status: isInFlight ? 'uploading' : 'failed',
72
+ progress: isInFlight ? toProgress(row) : null,
73
+ sourceFile: api.getUploadSourceFile(uploadId, row.index),
74
+ isInStore: liveKeys.has(key)
75
+ });
76
+ });
77
+ const dismiss = React.useCallback((key)=>{
78
+ setDismissed((previous)=>new Set(previous).add(key));
79
+ }, []);
80
+ const cancel = React.useCallback(({ uploadId, index })=>{
81
+ api.abortUploadFile(uploadId, index);
82
+ dispatch(uploadProgress.cancelFile({
83
+ uploadId,
84
+ index
85
+ }));
86
+ }, [
87
+ dispatch
88
+ ]);
89
+ /**
90
+ * Retries in place while the row is still in the store. Once the store has
91
+ * moved on to another batch, the row can only be replayed as a new upload,
92
+ * which `reupload` does with the file the user picked.
93
+ */ const retry = React.useCallback(async (upload, reupload)=>{
94
+ if (upload.isInStore) {
95
+ try {
96
+ await retryUploadFile({
97
+ uploadId: upload.uploadId,
98
+ index: upload.index
99
+ }).unwrap();
100
+ } catch {
101
+ // The row reports the failure itself.
102
+ }
103
+ return;
104
+ }
105
+ if (upload.sourceFile) {
106
+ dismiss(upload.key);
107
+ reupload(upload.sourceFile);
108
+ }
109
+ }, [
110
+ dismiss,
111
+ retryUploadFile
112
+ ]);
113
+ return {
114
+ uploads,
115
+ cancel,
116
+ retry,
117
+ dismiss
118
+ };
119
+ };
120
+
121
+ exports.useFieldUploads = useFieldUploads;
122
+ //# sourceMappingURL=useFieldUploads.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFieldUploads.js","sources":["../../../../admin/src/components/MediaLibraryInput/useFieldUploads.ts"],"sourcesContent":["import { useCallback, useRef, useState } from 'react';\n\nimport { shallowEqual } from 'react-redux';\n\nimport {\n abortUploadFile,\n getUploadSourceFile,\n useRetryUploadFileMutation,\n} from '../../services/api';\nimport { useTypedDispatch, useTypedSelector } from '../../store/hooks';\nimport { cancelFile, type FileProgress } from '../../store/uploadProgress';\n\nexport interface FieldUpload {\n key: string;\n uploadId: number;\n index: number;\n name: string;\n status: 'uploading' | 'failed';\n /** 0–100, or `null` while the size is unknown. */\n progress: number | null;\n /** The file the user picked, for the preview. Gone once the page reloads. */\n sourceFile?: globalThis.File;\n /** Whether the progress store still holds the row, i.e. it can be retried in place. */\n isInStore: boolean;\n}\n\ninterface TrackedRow {\n uploadId: number;\n row: FileProgress;\n}\n\nconst NO_ROWS: FileProgress[] = [];\n\nconst getKey = (uploadId: number, index: number) => `${uploadId}:${index}`;\n\nconst toProgress = ({ status, size, uploadedBytes }: FileProgress) => {\n if (status === 'pending') {\n return 0;\n }\n\n return size > 0 ? Math.round((uploadedBytes / size) * 100) : null;\n};\n\n/**\n * The uploads a field started, read from the shared progress store so the field\n * and the progress dialog always agree.\n *\n * The store only holds the latest batch, and closing the dialog empties it. Rows\n * are therefore remembered here once seen: a failed upload stays on the field\n * until the user retries or removes it, whatever happened to the dialog. A row\n * that vanished while still in flight was cancelled along with its batch.\n *\n * Completed rows leave the list. Attaching them to the field is the upload's\n * `onFileUploaded`, which outlives the input.\n */\nexport const useFieldUploads = (owner: string) => {\n const dispatch = useTypedDispatch();\n const [retryUploadFile] = useRetryUploadFileMutation();\n\n // The plugin registers the slice in `register()`; a host that has not has no\n // uploads to show.\n const currentUploadId = useTypedSelector((state) => state.uploadProgress?.uploadId ?? 0);\n const ownedRows = useTypedSelector(\n (state) => (state.uploadProgress?.files ?? NO_ROWS).filter((file) => file.owner === owner),\n shallowEqual\n );\n\n const trackedRef = useRef(new Map<string, TrackedRow>());\n const [dismissed, setDismissed] = useState<ReadonlySet<string>>(() => new Set());\n\n const tracked = trackedRef.current;\n const liveKeys = new Set<string>();\n\n ownedRows.forEach((row) => {\n const key = getKey(currentUploadId, row.index);\n liveKeys.add(key);\n tracked.set(key, { uploadId: currentUploadId, row });\n });\n\n tracked.forEach((entry, key) => {\n const isInFlight = entry.row.status === 'pending' || entry.row.status === 'uploading';\n\n if (!liveKeys.has(key) && isInFlight) {\n tracked.set(key, { ...entry, row: { ...entry.row, status: 'cancelled' } });\n }\n });\n\n const uploads: FieldUpload[] = [];\n\n tracked.forEach(({ uploadId, row }, key) => {\n const isInFlight = row.status === 'pending' || row.status === 'uploading';\n const isFailed = row.status === 'error' && !dismissed.has(key);\n\n if (!isInFlight && !isFailed) {\n return;\n }\n\n uploads.push({\n key,\n uploadId,\n index: row.index,\n name: row.name,\n status: isInFlight ? 'uploading' : 'failed',\n progress: isInFlight ? toProgress(row) : null,\n sourceFile: getUploadSourceFile(uploadId, row.index),\n isInStore: liveKeys.has(key),\n });\n });\n\n const dismiss = useCallback((key: string) => {\n setDismissed((previous) => new Set(previous).add(key));\n }, []);\n\n const cancel = useCallback(\n ({ uploadId, index }: FieldUpload) => {\n abortUploadFile(uploadId, index);\n dispatch(cancelFile({ uploadId, index }));\n },\n [dispatch]\n );\n\n /**\n * Retries in place while the row is still in the store. Once the store has\n * moved on to another batch, the row can only be replayed as a new upload,\n * which `reupload` does with the file the user picked.\n */\n const retry = useCallback(\n async (upload: FieldUpload, reupload: (file: globalThis.File) => void) => {\n if (upload.isInStore) {\n try {\n await retryUploadFile({ uploadId: upload.uploadId, index: upload.index }).unwrap();\n } catch {\n // The row reports the failure itself.\n }\n return;\n }\n\n if (upload.sourceFile) {\n dismiss(upload.key);\n reupload(upload.sourceFile);\n }\n },\n [dismiss, retryUploadFile]\n );\n\n return { uploads, cancel, retry, dismiss };\n};\n"],"names":["NO_ROWS","getKey","uploadId","index","toProgress","status","size","uploadedBytes","Math","round","useFieldUploads","owner","dispatch","useTypedDispatch","retryUploadFile","useRetryUploadFileMutation","currentUploadId","useTypedSelector","state","uploadProgress","ownedRows","files","filter","file","shallowEqual","trackedRef","useRef","Map","dismissed","setDismissed","useState","Set","tracked","current","liveKeys","forEach","row","key","add","set","entry","isInFlight","has","uploads","isFailed","push","name","progress","sourceFile","getUploadSourceFile","isInStore","dismiss","useCallback","previous","cancel","abortUploadFile","cancelFile","retry","upload","reupload","unwrap"],"mappings":"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"}
@@ -0,0 +1,120 @@
1
+ import { useRef, useState, useCallback } from 'react';
2
+ import { shallowEqual } from 'react-redux';
3
+ import { useRetryUploadFileMutation, getUploadSourceFile, abortUploadFile } from '../../services/api.mjs';
4
+ import { useTypedDispatch, useTypedSelector } from '../../store/hooks.mjs';
5
+ import { cancelFile } from '../../store/uploadProgress.mjs';
6
+
7
+ const NO_ROWS = [];
8
+ const getKey = (uploadId, index)=>`${uploadId}:${index}`;
9
+ const toProgress = ({ status, size, uploadedBytes })=>{
10
+ if (status === 'pending') {
11
+ return 0;
12
+ }
13
+ return size > 0 ? Math.round(uploadedBytes / size * 100) : null;
14
+ };
15
+ /**
16
+ * The uploads a field started, read from the shared progress store so the field
17
+ * and the progress dialog always agree.
18
+ *
19
+ * The store only holds the latest batch, and closing the dialog empties it. Rows
20
+ * are therefore remembered here once seen: a failed upload stays on the field
21
+ * until the user retries or removes it, whatever happened to the dialog. A row
22
+ * that vanished while still in flight was cancelled along with its batch.
23
+ *
24
+ * Completed rows leave the list. Attaching them to the field is the upload's
25
+ * `onFileUploaded`, which outlives the input.
26
+ */ const useFieldUploads = (owner)=>{
27
+ const dispatch = useTypedDispatch();
28
+ const [retryUploadFile] = useRetryUploadFileMutation();
29
+ // The plugin registers the slice in `register()`; a host that has not has no
30
+ // uploads to show.
31
+ const currentUploadId = useTypedSelector((state)=>state.uploadProgress?.uploadId ?? 0);
32
+ const ownedRows = useTypedSelector((state)=>(state.uploadProgress?.files ?? NO_ROWS).filter((file)=>file.owner === owner), shallowEqual);
33
+ const trackedRef = useRef(new Map());
34
+ const [dismissed, setDismissed] = useState(()=>new Set());
35
+ const tracked = trackedRef.current;
36
+ const liveKeys = new Set();
37
+ ownedRows.forEach((row)=>{
38
+ const key = getKey(currentUploadId, row.index);
39
+ liveKeys.add(key);
40
+ tracked.set(key, {
41
+ uploadId: currentUploadId,
42
+ row
43
+ });
44
+ });
45
+ tracked.forEach((entry, key)=>{
46
+ const isInFlight = entry.row.status === 'pending' || entry.row.status === 'uploading';
47
+ if (!liveKeys.has(key) && isInFlight) {
48
+ tracked.set(key, {
49
+ ...entry,
50
+ row: {
51
+ ...entry.row,
52
+ status: 'cancelled'
53
+ }
54
+ });
55
+ }
56
+ });
57
+ const uploads = [];
58
+ tracked.forEach(({ uploadId, row }, key)=>{
59
+ const isInFlight = row.status === 'pending' || row.status === 'uploading';
60
+ const isFailed = row.status === 'error' && !dismissed.has(key);
61
+ if (!isInFlight && !isFailed) {
62
+ return;
63
+ }
64
+ uploads.push({
65
+ key,
66
+ uploadId,
67
+ index: row.index,
68
+ name: row.name,
69
+ status: isInFlight ? 'uploading' : 'failed',
70
+ progress: isInFlight ? toProgress(row) : null,
71
+ sourceFile: getUploadSourceFile(uploadId, row.index),
72
+ isInStore: liveKeys.has(key)
73
+ });
74
+ });
75
+ const dismiss = useCallback((key)=>{
76
+ setDismissed((previous)=>new Set(previous).add(key));
77
+ }, []);
78
+ const cancel = useCallback(({ uploadId, index })=>{
79
+ abortUploadFile(uploadId, index);
80
+ dispatch(cancelFile({
81
+ uploadId,
82
+ index
83
+ }));
84
+ }, [
85
+ dispatch
86
+ ]);
87
+ /**
88
+ * Retries in place while the row is still in the store. Once the store has
89
+ * moved on to another batch, the row can only be replayed as a new upload,
90
+ * which `reupload` does with the file the user picked.
91
+ */ const retry = useCallback(async (upload, reupload)=>{
92
+ if (upload.isInStore) {
93
+ try {
94
+ await retryUploadFile({
95
+ uploadId: upload.uploadId,
96
+ index: upload.index
97
+ }).unwrap();
98
+ } catch {
99
+ // The row reports the failure itself.
100
+ }
101
+ return;
102
+ }
103
+ if (upload.sourceFile) {
104
+ dismiss(upload.key);
105
+ reupload(upload.sourceFile);
106
+ }
107
+ }, [
108
+ dismiss,
109
+ retryUploadFile
110
+ ]);
111
+ return {
112
+ uploads,
113
+ cancel,
114
+ retry,
115
+ dismiss
116
+ };
117
+ };
118
+
119
+ export { useFieldUploads };
120
+ //# sourceMappingURL=useFieldUploads.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFieldUploads.mjs","sources":["../../../../admin/src/components/MediaLibraryInput/useFieldUploads.ts"],"sourcesContent":["import { useCallback, useRef, useState } from 'react';\n\nimport { shallowEqual } from 'react-redux';\n\nimport {\n abortUploadFile,\n getUploadSourceFile,\n useRetryUploadFileMutation,\n} from '../../services/api';\nimport { useTypedDispatch, useTypedSelector } from '../../store/hooks';\nimport { cancelFile, type FileProgress } from '../../store/uploadProgress';\n\nexport interface FieldUpload {\n key: string;\n uploadId: number;\n index: number;\n name: string;\n status: 'uploading' | 'failed';\n /** 0–100, or `null` while the size is unknown. */\n progress: number | null;\n /** The file the user picked, for the preview. Gone once the page reloads. */\n sourceFile?: globalThis.File;\n /** Whether the progress store still holds the row, i.e. it can be retried in place. */\n isInStore: boolean;\n}\n\ninterface TrackedRow {\n uploadId: number;\n row: FileProgress;\n}\n\nconst NO_ROWS: FileProgress[] = [];\n\nconst getKey = (uploadId: number, index: number) => `${uploadId}:${index}`;\n\nconst toProgress = ({ status, size, uploadedBytes }: FileProgress) => {\n if (status === 'pending') {\n return 0;\n }\n\n return size > 0 ? Math.round((uploadedBytes / size) * 100) : null;\n};\n\n/**\n * The uploads a field started, read from the shared progress store so the field\n * and the progress dialog always agree.\n *\n * The store only holds the latest batch, and closing the dialog empties it. Rows\n * are therefore remembered here once seen: a failed upload stays on the field\n * until the user retries or removes it, whatever happened to the dialog. A row\n * that vanished while still in flight was cancelled along with its batch.\n *\n * Completed rows leave the list. Attaching them to the field is the upload's\n * `onFileUploaded`, which outlives the input.\n */\nexport const useFieldUploads = (owner: string) => {\n const dispatch = useTypedDispatch();\n const [retryUploadFile] = useRetryUploadFileMutation();\n\n // The plugin registers the slice in `register()`; a host that has not has no\n // uploads to show.\n const currentUploadId = useTypedSelector((state) => state.uploadProgress?.uploadId ?? 0);\n const ownedRows = useTypedSelector(\n (state) => (state.uploadProgress?.files ?? NO_ROWS).filter((file) => file.owner === owner),\n shallowEqual\n );\n\n const trackedRef = useRef(new Map<string, TrackedRow>());\n const [dismissed, setDismissed] = useState<ReadonlySet<string>>(() => new Set());\n\n const tracked = trackedRef.current;\n const liveKeys = new Set<string>();\n\n ownedRows.forEach((row) => {\n const key = getKey(currentUploadId, row.index);\n liveKeys.add(key);\n tracked.set(key, { uploadId: currentUploadId, row });\n });\n\n tracked.forEach((entry, key) => {\n const isInFlight = entry.row.status === 'pending' || entry.row.status === 'uploading';\n\n if (!liveKeys.has(key) && isInFlight) {\n tracked.set(key, { ...entry, row: { ...entry.row, status: 'cancelled' } });\n }\n });\n\n const uploads: FieldUpload[] = [];\n\n tracked.forEach(({ uploadId, row }, key) => {\n const isInFlight = row.status === 'pending' || row.status === 'uploading';\n const isFailed = row.status === 'error' && !dismissed.has(key);\n\n if (!isInFlight && !isFailed) {\n return;\n }\n\n uploads.push({\n key,\n uploadId,\n index: row.index,\n name: row.name,\n status: isInFlight ? 'uploading' : 'failed',\n progress: isInFlight ? toProgress(row) : null,\n sourceFile: getUploadSourceFile(uploadId, row.index),\n isInStore: liveKeys.has(key),\n });\n });\n\n const dismiss = useCallback((key: string) => {\n setDismissed((previous) => new Set(previous).add(key));\n }, []);\n\n const cancel = useCallback(\n ({ uploadId, index }: FieldUpload) => {\n abortUploadFile(uploadId, index);\n dispatch(cancelFile({ uploadId, index }));\n },\n [dispatch]\n );\n\n /**\n * Retries in place while the row is still in the store. Once the store has\n * moved on to another batch, the row can only be replayed as a new upload,\n * which `reupload` does with the file the user picked.\n */\n const retry = useCallback(\n async (upload: FieldUpload, reupload: (file: globalThis.File) => void) => {\n if (upload.isInStore) {\n try {\n await retryUploadFile({ uploadId: upload.uploadId, index: upload.index }).unwrap();\n } catch {\n // The row reports the failure itself.\n }\n return;\n }\n\n if (upload.sourceFile) {\n dismiss(upload.key);\n reupload(upload.sourceFile);\n }\n },\n [dismiss, retryUploadFile]\n );\n\n return { uploads, cancel, retry, dismiss };\n};\n"],"names":["NO_ROWS","getKey","uploadId","index","toProgress","status","size","uploadedBytes","Math","round","useFieldUploads","owner","dispatch","useTypedDispatch","retryUploadFile","useRetryUploadFileMutation","currentUploadId","useTypedSelector","state","uploadProgress","ownedRows","files","filter","file","shallowEqual","trackedRef","useRef","Map","dismissed","setDismissed","useState","Set","tracked","current","liveKeys","forEach","row","key","add","set","entry","isInFlight","has","uploads","isFailed","push","name","progress","sourceFile","getUploadSourceFile","isInStore","dismiss","useCallback","previous","cancel","abortUploadFile","cancelFile","retry","upload","reupload","unwrap"],"mappings":"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"}
@@ -263,7 +263,8 @@ const DialogHeader = ({ handleClose })=>{
263
263
  const status = (()=>{
264
264
  if (isAllErrored) return 'error';
265
265
  if (isSuccess) return 'success';
266
- if (hasCancelledFiles) return 'canceled';
266
+ // A single file can be cancelled while the rest of the batch keeps going.
267
+ if (hasCancelledFiles && isComplete) return 'canceled';
267
268
  return 'uploading';
268
269
  })();
269
270
  const handleCancel = ()=>{
@@ -1 +1 @@
1
- {"version":3,"file":"UploadProgressDialog.js","sources":["../../../admin/src/components/UploadProgressDialog.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { Flex, IconButton, TextButton, Typography } from '@strapi/design-system';\nimport {\n ArrowsCounterClockwise,\n Check,\n CheckCircle,\n ChevronDown,\n Clock,\n Cross,\n CrossCircle,\n Information,\n MinusCircle,\n Sparkle,\n Upload,\n WarningCircle,\n} from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { keyframes, styled } from 'styled-components';\n\nimport { abortUpload, useRetryCancelledFilesMutation } from '../services/api';\nimport { useTypedDispatch, useTypedSelector } from '../store/hooks';\nimport {\n closeUploadProgress,\n toggleMinimize,\n cancelUpload,\n selectAggregateProgress,\n selectReportsByteProgress,\n selectCountBasedProgress,\n selectMetadataProgress,\n selectIsGeneratingMetadata,\n selectMetadataOutcome,\n} from '../store/uploadProgress';\nimport { getTranslationKey } from '../utils/translations';\n\nimport { Drawer } from './Drawer';\nimport { TruncatedText } from './TruncatedText';\n\nimport type { FileMetadataStatus, FileProgress, FileProgressStatus } from '../store/uploadProgress';\nimport type { MessageDescriptor } from 'react-intl';\n\n/* -------------------------------------------------------------------------------------------------\n * DialogHeader\n * -----------------------------------------------------------------------------------------------*/\n\nconst HeaderStatusMessage = ({\n title,\n subtitle,\n metadataSubtitle,\n}: {\n title: string;\n subtitle?: string;\n metadataSubtitle?: string;\n}) => {\n return (\n <Flex\n direction=\"column\"\n alignItems=\"flex-start\"\n paddingLeft={2}\n paddingRight={2}\n paddingTop={1}\n paddingBottom={1}\n >\n <Drawer.Title>\n <Typography variant=\"omega\">{title}</Typography>\n </Drawer.Title>\n <Drawer.Description>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {subtitle}\n </Typography>\n </Drawer.Description>\n {metadataSubtitle && (\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {metadataSubtitle}\n </Typography>\n )}\n </Flex>\n );\n};\n\nconst HeaderStatusIcon = styled(Flex)`\n align-self: stretch;\n padding: ${({ theme }) => theme.spaces[3]};\n border-radius: ${({ theme }) => `${theme.borderRadius} 0 0 ${theme.borderRadius}`};\n\n > svg {\n height: 24px;\n width: 24px;\n }\n`;\n\nconst HeaderStatusWrapper = styled(Flex)`\n align-items: center;\n`;\n\ntype HeaderStatusProps = {\n status: 'uploading' | 'success' | 'error' | 'canceled';\n /** Byte-weighted progress, or `null` for a batch that reports no bytes (the URL flow). */\n progress: number | null;\n totalFiles: number;\n successfulCount: number;\n errorCount: number;\n /**\n * Count-based metadata progress, or `null` when no row entered the metadata phase.\n * Shown as an extra subtitle while generation is still in flight.\n */\n metadataProgress: number | null;\n /** Whether any row is still generating — drives whether the subtitle shows at all. */\n isGeneratingMetadata: boolean;\n /**\n * Terminal per-outcome counts, or `null` while the phase is unfinished or was never\n * entered. Replaces the in-flight subtitle once generation settles.\n */\n metadataOutcome: { generated: number; skipped: number; failed: number } | null;\n};\n\nconst HeaderStatus = ({\n status,\n progress,\n totalFiles,\n successfulCount,\n errorCount,\n metadataProgress,\n isGeneratingMetadata,\n metadataOutcome,\n}: HeaderStatusProps) => {\n const { formatMessage } = useIntl();\n\n // Completion is upload-driven, so the terminal header can appear while metadata is\n // still generating — the subtitle keeps ticking underneath until it settles.\n //\n // Gated on work actually being in flight rather than on `progress < 100`: in a\n // sequential batch the percentage touches 100% between files, which would blink the\n // subtitle out and back in on every upload.\n //\n // Once the phase settles the line is not dropped but replaced with the outcome, so the\n // header keeps confirming what happened instead of silently losing the message.\n const metadataSubtitle = (() => {\n if (metadataProgress !== null && isGeneratingMetadata) {\n return formatMessage(\n {\n id: getTranslationKey('upload.progress.generatingMetadata.withCount'),\n defaultMessage: 'Generating metadata with AI ({percentage}%)',\n },\n { percentage: metadataProgress }\n );\n }\n\n if (metadataOutcome === null) {\n return undefined;\n }\n\n // Only `generated` rows had metadata written, so only they can be reported as a\n // success. With none, there is nothing to confirm — an all-skipped batch of\n // non-images would otherwise read as \"generated on 0 files\". Per-row sublines\n // already spell out skipped and failed outcomes.\n if (metadataOutcome.generated === 0) {\n return undefined;\n }\n\n if (metadataOutcome.failed > 0) {\n return formatMessage(\n {\n id: getTranslationKey('upload.progress.metadataGenerated.withFailures'),\n defaultMessage: '{generatedCount} generated, {failedCount} failed',\n },\n { generatedCount: metadataOutcome.generated, failedCount: metadataOutcome.failed }\n );\n }\n\n return formatMessage(\n {\n id: getTranslationKey('upload.progress.metadataGenerated.withCount'),\n defaultMessage:\n '{count, plural, one {Metadata successfully generated on # file} other {Metadata successfully generated on # files}}',\n },\n { count: metadataOutcome.generated }\n );\n })();\n\n if (status === 'error') {\n return (\n <HeaderStatusWrapper>\n <HeaderStatusIcon background=\"danger200\">\n <Cross fill=\"danger700\" />\n </HeaderStatusIcon>\n <HeaderStatusMessage\n title={formatMessage({\n id: getTranslationKey('upload.progress.failed'),\n defaultMessage: 'Upload failed',\n })}\n subtitle={formatMessage({\n id: getTranslationKey('upload.progress.failed.subtitle'),\n defaultMessage: 'Please try to upload files again',\n })}\n />\n </HeaderStatusWrapper>\n );\n }\n\n if (status === 'success') {\n const subtitle =\n errorCount > 0\n ? formatMessage(\n {\n id: getTranslationKey('upload.progress.success.subtitle.withErrors'),\n defaultMessage: '{successCount} uploaded, {errorCount} failed',\n },\n { successCount: successfulCount, errorCount }\n )\n : formatMessage(\n {\n id: getTranslationKey('upload.progress.success.subtitle'),\n defaultMessage: '{count} files uploaded successfully',\n },\n { count: successfulCount }\n );\n\n return (\n <HeaderStatusWrapper>\n <HeaderStatusIcon background=\"success200\">\n <Check fill=\"success700\" />\n </HeaderStatusIcon>\n <HeaderStatusMessage\n title={formatMessage({\n id: getTranslationKey('upload.progress.success'),\n defaultMessage: 'Upload successful!',\n })}\n subtitle={subtitle}\n metadataSubtitle={metadataSubtitle}\n />\n </HeaderStatusWrapper>\n );\n }\n\n if (status === 'canceled') {\n return (\n <HeaderStatusWrapper>\n <HeaderStatusIcon background=\"neutral200\">\n <MinusCircle fill=\"neutral700\" />\n </HeaderStatusIcon>\n <HeaderStatusMessage\n title={formatMessage({\n id: getTranslationKey('upload.progress.canceled'),\n defaultMessage: 'Upload canceled',\n })}\n subtitle={formatMessage({\n id: getTranslationKey('upload.progress.canceled.subtitle'),\n defaultMessage: 'Some files were not uploaded',\n })}\n metadataSubtitle={metadataSubtitle}\n />\n </HeaderStatusWrapper>\n );\n }\n\n if (status === 'uploading') {\n // Two separate strings so a locale can position (or omit) the percentage itself.\n const title =\n progress === null\n ? formatMessage(\n {\n id: getTranslationKey('upload.progress.uploading.indeterminate'),\n defaultMessage: 'Uploading {total, plural, one {# item} other {# items}}',\n },\n { total: totalFiles }\n )\n : formatMessage(\n {\n id: getTranslationKey('upload.progress.uploading.withCount'),\n defaultMessage:\n 'Uploading {total, plural, one {# item} other {# items}} ({percentage}%)',\n },\n {\n total: totalFiles,\n percentage: Math.round(progress),\n }\n );\n\n return (\n <HeaderStatusWrapper>\n <HeaderStatusIcon background=\"primary200\">\n <Upload fill=\"primary700\" />\n </HeaderStatusIcon>\n <HeaderStatusMessage title={title} metadataSubtitle={metadataSubtitle} />\n </HeaderStatusWrapper>\n );\n }\n\n return null;\n};\n\nconst HeaderIconButton = styled(IconButton)`\n &:hover {\n background: transparent;\n }\n`;\n\nconst ChevronWrapper = styled.span<{ $isMinimized: boolean }>`\n display: flex;\n transition: transform 0.5s ease-in-out;\n transform: ${({ $isMinimized }) => ($isMinimized ? 'rotate(180deg)' : 'rotate(0deg)')};\n`;\n\nconst HEADER_COLOR_MAP = {\n uploading: { background: 'primary100' },\n canceled: { background: 'neutral100' },\n success: { background: 'success100' },\n error: { background: 'danger100' },\n} as const;\n\nconst DialogHeader = ({ handleClose }: { handleClose: () => void }) => {\n const { formatMessage } = useIntl();\n\n const { isMinimized, files, uploadId, totalFiles } = useTypedSelector(\n (state) => state.uploadProgress\n );\n const aggregateProgress = useTypedSelector(selectAggregateProgress);\n const reportsByteProgress = useTypedSelector(selectReportsByteProgress);\n const countBasedProgress = useTypedSelector(selectCountBasedProgress);\n // Byte-weighted when the flow streams bytes (direct-file), else count-based (settled/total).\n // Both return `null` for an indeterminate header when there's nothing to show yet.\n const progress = reportsByteProgress ? aggregateProgress : countBasedProgress;\n const metadataProgress = useTypedSelector(selectMetadataProgress);\n const isGeneratingMetadata = useTypedSelector(selectIsGeneratingMetadata);\n const metadataOutcome = useTypedSelector(selectMetadataOutcome);\n const dispatch = useTypedDispatch();\n const [retryCancelledFiles] = useRetryCancelledFilesMutation();\n\n // The batch is complete once every file has reached a terminal state. Byte-weighted\n // progress can't be used here because errored/cancelled rows never reach 100%.\n const isComplete =\n files.length > 0 &&\n files.every((f) => f.status === 'complete' || f.status === 'error' || f.status === 'cancelled');\n const isAllUploaded = isComplete;\n const isAllErrored = isComplete && files.every((f) => f.status === 'error');\n const hasCancelledFiles = files.some((f) => f.status === 'cancelled');\n const successfulCount = files.filter((f) => f.status === 'complete').length;\n const errorCount = files.filter((f) => f.status === 'error').length;\n // Success includes partial success (some files succeeded, even if some failed)\n const isSuccess = isComplete && successfulCount > 0 && !hasCancelledFiles;\n const status = ((): HeaderStatusProps['status'] => {\n if (isAllErrored) return 'error';\n if (isSuccess) return 'success';\n if (hasCancelledFiles) return 'canceled';\n\n return 'uploading';\n })();\n\n const handleCancel = () => {\n abortUpload(uploadId);\n dispatch(cancelUpload());\n };\n\n const handleRetry = async () => {\n try {\n await retryCancelledFiles().unwrap();\n } catch {\n // Error is already dispatched to store from the API queryFn\n }\n };\n\n const handleToggleMinimize = () => {\n dispatch(toggleMinimize());\n };\n\n return (\n <Flex\n background={HEADER_COLOR_MAP[status].background}\n justifyContent=\"space-between\"\n margin={1}\n hasRadius\n >\n <HeaderStatus\n status={status}\n progress={progress}\n totalFiles={totalFiles}\n successfulCount={successfulCount}\n errorCount={errorCount}\n metadataProgress={metadataProgress}\n isGeneratingMetadata={isGeneratingMetadata}\n metadataOutcome={metadataOutcome}\n />\n <Flex gap={1}>\n {!isAllUploaded && (\n <TextButton onClick={handleCancel} fontWeight=\"bold\">\n {formatMessage({\n id: getTranslationKey('upload.progress.cancel'),\n defaultMessage: 'Cancel all',\n })}\n </TextButton>\n )}\n {hasCancelledFiles && (\n <TextButton onClick={handleRetry} fontWeight=\"bold\">\n {formatMessage({\n id: getTranslationKey('upload.progress.retry'),\n defaultMessage: 'Retry',\n })}\n </TextButton>\n )}\n <HeaderIconButton\n onClick={handleToggleMinimize}\n label={formatMessage({\n id: getTranslationKey(\n isMinimized ? 'upload.progress.maximize' : 'upload.progress.minimize'\n ),\n defaultMessage: isMinimized ? 'Maximize' : 'Minimize',\n })}\n variant=\"ghost\"\n >\n <ChevronWrapper $isMinimized={isMinimized}>\n <ChevronDown />\n </ChevronWrapper>\n </HeaderIconButton>\n {isComplete && (\n <Drawer.CloseButton\n onClose={handleClose}\n label={formatMessage({\n id: getTranslationKey('upload.progress.close'),\n defaultMessage: 'Close',\n })}\n />\n )}\n </Flex>\n </Flex>\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * UploadProgressDialog\n * -----------------------------------------------------------------------------------------------*/\n\nconst ProgressTrack = styled.div`\n width: 100%;\n height: ${({ theme }) => theme.spaces[1]};\n background-color: ${({ theme }) => theme.colors.neutral200};\n border-radius: 4px;\n overflow: hidden;\n`;\n\nconst ProgressIndicator = styled.div<{ $percent: number }>`\n height: 100%;\n width: ${({ $percent }) => $percent}%;\n background-color: ${({ theme }) => theme.colors.primary700};\n border-radius: 4px;\n transition: width 0.15s linear;\n`;\n\nconst DeterminateBar = ({ percent }: { percent: number }) => {\n const clamped = Math.min(100, Math.max(0, Math.round(percent)));\n return (\n <ProgressTrack role=\"progressbar\" aria-valuemin={0} aria-valuemax={100} aria-valuenow={clamped}>\n <ProgressIndicator $percent={clamped} />\n </ProgressTrack>\n );\n};\n\nconst INDETERMINATE_INDICATOR_WIDTH = 40;\n\n/**\n * `translateX` percentages resolve against the *indicator's* own width, not the track's.\n * So -100% is exactly \"fully off the left edge\" regardless of the width above, and the\n * end offset converts a full track width into those same own-width units. Both ends sit\n * flush off-track, which keeps entry and exit symmetric — a smaller start offset would\n * make the bar pop in already partly visible.\n */\nconst indeterminateSlide = keyframes`\n from {\n transform: translateX(-100%);\n }\n to {\n transform: translateX(${(100 / INDETERMINATE_INDICATOR_WIDTH) * 100}%);\n }\n`;\n\nconst IndeterminateIndicator = styled.div`\n height: 100%;\n width: ${INDETERMINATE_INDICATOR_WIDTH}%;\n background-color: ${({ theme }) => theme.colors.primary700};\n border-radius: 4px;\n /* Linear, not an eased curve: the DS easings decelerate to a stop, which on a loop\n reads as a stall at the wrap point. Constant speed is what makes it read as a sweep. */\n animation: ${indeterminateSlide} 1.2s linear infinite;\n\n /* A perpetually moving bar is a vestibular trigger; fall back to a static track fill. */\n @media (prefers-reduced-motion: reduce) {\n animation: none;\n width: 100%;\n opacity: 0.5;\n }\n`;\n\n/**\n * Progress bar for work whose completion fraction is genuinely unknowable, rather\n * than merely unknown-yet: the AI metadata endpoint answers in one go, and the URL\n * flow can't report bytes until the server has fetched the file and knows its size.\n *\n * Deliberately omits `aria-valuenow` — that absence is precisely how ARIA conveys\n * an indeterminate progressbar, so assistive tech announces \"busy\" instead of \"0%\".\n */\nconst IndeterminateBar = () => {\n return (\n <ProgressTrack role=\"progressbar\" aria-valuemin={0} aria-valuemax={100}>\n <IndeterminateIndicator />\n </ProgressTrack>\n );\n};\n\n/**\n * Without a floor of zero the row is as wide as its longest filename, which\n * pushes past the panel and gives the dialog a second, horizontal scrollbar\n * instead of truncating.\n *\n * The floor belongs to the name alone: the icon carries its size in SVG\n * attributes, which flex is free to override, so letting it shrink squashes it\n * against a long name instead of truncating the name.\n */\nconst FileRowName = styled(Flex)`\n min-width: 0;\n\n > :first-child {\n flex-shrink: 0;\n }\n\n > :last-child {\n min-width: 0;\n }\n`;\n\nconst FileRow = ({\n icon,\n fileName,\n children,\n}: {\n icon: React.ReactNode;\n fileName: string;\n children: React.ReactNode;\n}) => {\n return (\n <Flex direction=\"column\" alignItems=\"stretch\" justifyContent=\"center\" gap={1} width=\"100%\">\n <FileRowName gap={2}>\n {icon}\n <TruncatedText variant=\"omega\" fontWeight=\"semiBold\">\n {fileName}\n </TruncatedText>\n </FileRowName>\n {children}\n </Flex>\n );\n};\n\n/**\n * Icon + subline for a successfully uploaded row, keyed by its metadata phase.\n * `'none'` covers rows that never entered the phase — AI metadata disabled — and\n * renders exactly as before this feature existed. Non-images do enter the phase and\n * land on `skipped`.\n *\n * `skipped` uses a neutral `Information` icon, deliberately distinct from\n * generated/failed/cancelled — skipping is an expected outcome for a non-image, not a\n * problem to flag.\n */\nconst COMPLETED_ROW_PRESENTATION: Record<\n FileMetadataStatus | 'none',\n { icon: React.ReactNode; message: MessageDescriptor }\n> = {\n none: {\n icon: <CheckCircle fill=\"success500\" />,\n message: {\n id: getTranslationKey('upload.progress.file.uploaded'),\n defaultMessage: 'Uploaded',\n },\n },\n generating: {\n icon: <Sparkle fill=\"primary600\" />,\n message: {\n id: getTranslationKey('upload.progress.file.generatingMetadata'),\n defaultMessage: 'Uploaded • Generating metadata…',\n },\n },\n generated: {\n icon: <CheckCircle fill=\"success500\" />,\n message: {\n id: getTranslationKey('upload.progress.file.metadataGenerated'),\n defaultMessage: 'Uploaded • Metadata generated',\n },\n },\n skipped: {\n icon: <Information fill=\"neutral500\" />,\n message: {\n id: getTranslationKey('upload.progress.file.metadataSkipped'),\n defaultMessage: 'Upload complete • Metadata generation skipped',\n },\n },\n failed: {\n icon: <WarningCircle fill=\"warning500\" />,\n message: {\n id: getTranslationKey('upload.progress.file.metadataFailed'),\n defaultMessage: 'Upload complete • Metadata generation failed',\n },\n },\n};\n\nconst FileRowRenderer = ({ file }: { file: FileProgress }) => {\n const { formatMessage } = useIntl();\n const isError = file.status === 'error';\n const isCurrentFile = file.status === 'uploading';\n const isCompleted = file.status === 'complete';\n const isCancelled = file.status === 'cancelled';\n const isQueued = file.status === 'pending';\n\n if (isQueued) {\n // No bar: there is nothing to report yet, and an indeterminate bar would read\n // as \"in progress\" on a file the pool has not picked up.\n return (\n <FileRow icon={<Clock fill=\"neutral600\" />} fileName={file.name}>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {formatMessage({\n id: getTranslationKey('upload.progress.file.queued'),\n defaultMessage: 'Queued',\n })}\n </Typography>\n </FileRow>\n );\n }\n\n if (isCurrentFile) {\n // Determinate only once bytes are actually being reported — a known `size` is not\n // enough. Both flows can report bytes, but neither always does:\n // - the direct-file flow streams real byte counts from XHR;\n // - the URL flow streams `file:progress` SSE frames while the server fetches the\n // remote file, but only when the remote sent a usable Content-Length. Without one\n // there is no denominator, nothing is dispatched, and `uploadedBytes` stays 0.\n // Keying off `size` alone froze such rows at a determinate 0% for the entire upload;\n // keying off reported bytes keeps them animating until there is a fraction to show.\n // Back to indeterminate once every byte is in: the server is still working (the URL\n // flow's provider upload, the direct flow awaiting its response), not stuck at 100%.\n const hasReportedProgress =\n file.size > 0 && file.uploadedBytes > 0 && file.uploadedBytes < file.size;\n\n return (\n <FileRow icon={<ArrowsCounterClockwise fill=\"secondary600\" />} fileName={file.name}>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {formatMessage({\n id: getTranslationKey('upload.progress.file.uploading'),\n defaultMessage: 'Uploading...',\n })}\n </Typography>\n {hasReportedProgress ? (\n <DeterminateBar percent={(file.uploadedBytes / file.size) * 100} />\n ) : (\n <IndeterminateBar />\n )}\n </FileRow>\n );\n }\n\n if (isError) {\n return (\n <FileRow icon={<CrossCircle fill=\"danger500\" />} fileName={file.name}>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {file.error\n ? /**\n * The server may return a machine-readable code (e.g. `FileTooBig` from the\n * body middleware) or an already human-readable sentence (e.g. the upload\n * plugin's size-limit message). Translate the former, fall back to the latter.\n */\n formatMessage({\n id: getTranslationKey(`apiError.${file.error}`),\n defaultMessage: file.error,\n })\n : formatMessage({\n id: getTranslationKey('upload.generic-error'),\n defaultMessage: 'An error occurred while uploading the file.',\n })}\n </Typography>\n </FileRow>\n );\n }\n\n if (isCancelled) {\n return (\n <FileRow icon={<MinusCircle fill=\"neutral600\" />} fileName={file.name}>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {formatMessage({\n id: getTranslationKey('upload.progress.file.canceled'),\n defaultMessage: 'Canceled',\n })}\n </Typography>\n </FileRow>\n );\n }\n\n if (isCompleted) {\n // The upload succeeded; the metadata phase (if any) drives both the icon and the\n // subline from here on — a metadata failure shows a warning, not an upload error.\n const { icon, message } = COMPLETED_ROW_PRESENTATION[file.metadataStatus ?? 'none'];\n\n return (\n <FileRow icon={icon} fileName={file.name}>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {formatMessage(message)}\n </Typography>\n {/* Generation has no intermediate progress to report, so the bar stays indeterminate. */}\n {file.metadataStatus === 'generating' && <IndeterminateBar />}\n </FileRow>\n );\n }\n\n return null;\n};\n\nconst CompletedFilesList = styled(Flex)`\n flex-direction: column;\n gap: ${({ theme }) => theme.spaces[2]};\n width: 100%;\n`;\n\nexport const UploadProgressDialog = () => {\n const dispatch = useTypedDispatch();\n const { isVisible, isMinimized, files } = useTypedSelector((state) => state.uploadProgress);\n\n // With concurrent uploads several files are `uploading` at once — render every\n // in-flight row, not just the first (a `find` here dated to the strictly\n // sequential era and hid all but the lowest-index worker's row).\n const uploadingFiles = files.filter((f) => f.status === 'uploading');\n // Everything the pool has not reached yet. Listed in queue order, which is the\n // order `files` is already in, so a row's position tells the user where it sits.\n const queuedFiles = files.filter((f) => f.status === 'pending');\n const completedFiles = files\n .filter((f) => f.status === 'complete' || f.status === 'error' || f.status === 'cancelled')\n .sort((a, b) => {\n // Sort priority: error > cancelled > complete\n const priority: Record<FileProgressStatus, number> = {\n error: 0,\n cancelled: 1,\n complete: 2,\n uploading: 3,\n pending: 4,\n };\n return priority[a.status] - priority[b.status];\n });\n\n const handleClose = () => {\n dispatch(closeUploadProgress());\n };\n\n return (\n <Drawer.Root isVisible={isVisible} onClose={handleClose}>\n <Drawer.Body animationDirection=\"up\" width=\"41.6rem\" maxHeight=\"34.2rem\">\n <DialogHeader handleClose={handleClose} />\n <Drawer.ScrollableContent isContentExpanded={!isMinimized}>\n <Flex\n direction=\"column\"\n alignItems=\"stretch\"\n gap={4}\n paddingTop={4}\n paddingBottom={4}\n paddingLeft={4}\n paddingRight={4}\n >\n {uploadingFiles.map((file) => (\n <FileRowRenderer key={file.index} file={file} />\n ))}\n\n {queuedFiles.map((file) => (\n <FileRowRenderer key={file.index} file={file} />\n ))}\n\n {completedFiles.length > 0 && (\n <CompletedFilesList>\n {completedFiles.map((file) => (\n <FileRowRenderer key={file.index} file={file} />\n ))}\n </CompletedFilesList>\n )}\n </Flex>\n </Drawer.ScrollableContent>\n </Drawer.Body>\n </Drawer.Root>\n );\n};\n"],"names":["HeaderStatusMessage","title","subtitle","metadataSubtitle","_jsxs","Flex","direction","alignItems","paddingLeft","paddingRight","paddingTop","paddingBottom","_jsx","Drawer","Title","Typography","variant","Description","textColor","HeaderStatusIcon","styled","theme","spaces","borderRadius","HeaderStatusWrapper","HeaderStatus","status","progress","totalFiles","successfulCount","errorCount","metadataProgress","isGeneratingMetadata","metadataOutcome","formatMessage","useIntl","id","getTranslationKey","defaultMessage","percentage","undefined","generated","failed","generatedCount","failedCount","count","background","Cross","fill","successCount","Check","MinusCircle","total","Math","round","Upload","HeaderIconButton","IconButton","ChevronWrapper","span","$isMinimized","HEADER_COLOR_MAP","uploading","canceled","success","error","DialogHeader","handleClose","isMinimized","files","uploadId","useTypedSelector","state","uploadProgress","aggregateProgress","selectAggregateProgress","reportsByteProgress","selectReportsByteProgress","countBasedProgress","selectCountBasedProgress","selectMetadataProgress","selectIsGeneratingMetadata","selectMetadataOutcome","dispatch","useTypedDispatch","retryCancelledFiles","useRetryCancelledFilesMutation","isComplete","length","every","f","isAllUploaded","isAllErrored","hasCancelledFiles","some","filter","isSuccess","handleCancel","abortUpload","cancelUpload","handleRetry","unwrap","handleToggleMinimize","toggleMinimize","justifyContent","margin","hasRadius","gap","TextButton","onClick","fontWeight","label","ChevronDown","CloseButton","onClose","ProgressTrack","div","colors","neutral200","ProgressIndicator","$percent","primary700","DeterminateBar","percent","clamped","min","max","role","aria-valuemin","aria-valuemax","aria-valuenow","INDETERMINATE_INDICATOR_WIDTH","indeterminateSlide","keyframes","IndeterminateIndicator","IndeterminateBar","FileRowName","FileRow","icon","fileName","children","width","TruncatedText","COMPLETED_ROW_PRESENTATION","none","CheckCircle","message","generating","Sparkle","skipped","Information","WarningCircle","FileRowRenderer","file","isError","isCurrentFile","isCompleted","isCancelled","isQueued","Clock","name","hasReportedProgress","size","uploadedBytes","ArrowsCounterClockwise","CrossCircle","metadataStatus","CompletedFilesList","UploadProgressDialog","isVisible","uploadingFiles","queuedFiles","completedFiles","sort","a","b","priority","cancelled","complete","pending","closeUploadProgress","Root","Body","animationDirection","maxHeight","ScrollableContent","isContentExpanded","map","index"],"mappings":"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"}
1
+ {"version":3,"file":"UploadProgressDialog.js","sources":["../../../admin/src/components/UploadProgressDialog.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { Flex, IconButton, TextButton, Typography } from '@strapi/design-system';\nimport {\n ArrowsCounterClockwise,\n Check,\n CheckCircle,\n ChevronDown,\n Clock,\n Cross,\n CrossCircle,\n Information,\n MinusCircle,\n Sparkle,\n Upload,\n WarningCircle,\n} from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { keyframes, styled } from 'styled-components';\n\nimport { abortUpload, useRetryCancelledFilesMutation } from '../services/api';\nimport { useTypedDispatch, useTypedSelector } from '../store/hooks';\nimport {\n closeUploadProgress,\n toggleMinimize,\n cancelUpload,\n selectAggregateProgress,\n selectReportsByteProgress,\n selectCountBasedProgress,\n selectMetadataProgress,\n selectIsGeneratingMetadata,\n selectMetadataOutcome,\n} from '../store/uploadProgress';\nimport { getTranslationKey } from '../utils/translations';\n\nimport { Drawer } from './Drawer';\nimport { TruncatedText } from './TruncatedText';\n\nimport type { FileMetadataStatus, FileProgress, FileProgressStatus } from '../store/uploadProgress';\nimport type { MessageDescriptor } from 'react-intl';\n\n/* -------------------------------------------------------------------------------------------------\n * DialogHeader\n * -----------------------------------------------------------------------------------------------*/\n\nconst HeaderStatusMessage = ({\n title,\n subtitle,\n metadataSubtitle,\n}: {\n title: string;\n subtitle?: string;\n metadataSubtitle?: string;\n}) => {\n return (\n <Flex\n direction=\"column\"\n alignItems=\"flex-start\"\n paddingLeft={2}\n paddingRight={2}\n paddingTop={1}\n paddingBottom={1}\n >\n <Drawer.Title>\n <Typography variant=\"omega\">{title}</Typography>\n </Drawer.Title>\n <Drawer.Description>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {subtitle}\n </Typography>\n </Drawer.Description>\n {metadataSubtitle && (\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {metadataSubtitle}\n </Typography>\n )}\n </Flex>\n );\n};\n\nconst HeaderStatusIcon = styled(Flex)`\n align-self: stretch;\n padding: ${({ theme }) => theme.spaces[3]};\n border-radius: ${({ theme }) => `${theme.borderRadius} 0 0 ${theme.borderRadius}`};\n\n > svg {\n height: 24px;\n width: 24px;\n }\n`;\n\nconst HeaderStatusWrapper = styled(Flex)`\n align-items: center;\n`;\n\ntype HeaderStatusProps = {\n status: 'uploading' | 'success' | 'error' | 'canceled';\n /** Byte-weighted progress, or `null` for a batch that reports no bytes (the URL flow). */\n progress: number | null;\n totalFiles: number;\n successfulCount: number;\n errorCount: number;\n /**\n * Count-based metadata progress, or `null` when no row entered the metadata phase.\n * Shown as an extra subtitle while generation is still in flight.\n */\n metadataProgress: number | null;\n /** Whether any row is still generating — drives whether the subtitle shows at all. */\n isGeneratingMetadata: boolean;\n /**\n * Terminal per-outcome counts, or `null` while the phase is unfinished or was never\n * entered. Replaces the in-flight subtitle once generation settles.\n */\n metadataOutcome: { generated: number; skipped: number; failed: number } | null;\n};\n\nconst HeaderStatus = ({\n status,\n progress,\n totalFiles,\n successfulCount,\n errorCount,\n metadataProgress,\n isGeneratingMetadata,\n metadataOutcome,\n}: HeaderStatusProps) => {\n const { formatMessage } = useIntl();\n\n // Completion is upload-driven, so the terminal header can appear while metadata is\n // still generating — the subtitle keeps ticking underneath until it settles.\n //\n // Gated on work actually being in flight rather than on `progress < 100`: in a\n // sequential batch the percentage touches 100% between files, which would blink the\n // subtitle out and back in on every upload.\n //\n // Once the phase settles the line is not dropped but replaced with the outcome, so the\n // header keeps confirming what happened instead of silently losing the message.\n const metadataSubtitle = (() => {\n if (metadataProgress !== null && isGeneratingMetadata) {\n return formatMessage(\n {\n id: getTranslationKey('upload.progress.generatingMetadata.withCount'),\n defaultMessage: 'Generating metadata with AI ({percentage}%)',\n },\n { percentage: metadataProgress }\n );\n }\n\n if (metadataOutcome === null) {\n return undefined;\n }\n\n // Only `generated` rows had metadata written, so only they can be reported as a\n // success. With none, there is nothing to confirm — an all-skipped batch of\n // non-images would otherwise read as \"generated on 0 files\". Per-row sublines\n // already spell out skipped and failed outcomes.\n if (metadataOutcome.generated === 0) {\n return undefined;\n }\n\n if (metadataOutcome.failed > 0) {\n return formatMessage(\n {\n id: getTranslationKey('upload.progress.metadataGenerated.withFailures'),\n defaultMessage: '{generatedCount} generated, {failedCount} failed',\n },\n { generatedCount: metadataOutcome.generated, failedCount: metadataOutcome.failed }\n );\n }\n\n return formatMessage(\n {\n id: getTranslationKey('upload.progress.metadataGenerated.withCount'),\n defaultMessage:\n '{count, plural, one {Metadata successfully generated on # file} other {Metadata successfully generated on # files}}',\n },\n { count: metadataOutcome.generated }\n );\n })();\n\n if (status === 'error') {\n return (\n <HeaderStatusWrapper>\n <HeaderStatusIcon background=\"danger200\">\n <Cross fill=\"danger700\" />\n </HeaderStatusIcon>\n <HeaderStatusMessage\n title={formatMessage({\n id: getTranslationKey('upload.progress.failed'),\n defaultMessage: 'Upload failed',\n })}\n subtitle={formatMessage({\n id: getTranslationKey('upload.progress.failed.subtitle'),\n defaultMessage: 'Please try to upload files again',\n })}\n />\n </HeaderStatusWrapper>\n );\n }\n\n if (status === 'success') {\n const subtitle =\n errorCount > 0\n ? formatMessage(\n {\n id: getTranslationKey('upload.progress.success.subtitle.withErrors'),\n defaultMessage: '{successCount} uploaded, {errorCount} failed',\n },\n { successCount: successfulCount, errorCount }\n )\n : formatMessage(\n {\n id: getTranslationKey('upload.progress.success.subtitle'),\n defaultMessage: '{count} files uploaded successfully',\n },\n { count: successfulCount }\n );\n\n return (\n <HeaderStatusWrapper>\n <HeaderStatusIcon background=\"success200\">\n <Check fill=\"success700\" />\n </HeaderStatusIcon>\n <HeaderStatusMessage\n title={formatMessage({\n id: getTranslationKey('upload.progress.success'),\n defaultMessage: 'Upload successful!',\n })}\n subtitle={subtitle}\n metadataSubtitle={metadataSubtitle}\n />\n </HeaderStatusWrapper>\n );\n }\n\n if (status === 'canceled') {\n return (\n <HeaderStatusWrapper>\n <HeaderStatusIcon background=\"neutral200\">\n <MinusCircle fill=\"neutral700\" />\n </HeaderStatusIcon>\n <HeaderStatusMessage\n title={formatMessage({\n id: getTranslationKey('upload.progress.canceled'),\n defaultMessage: 'Upload canceled',\n })}\n subtitle={formatMessage({\n id: getTranslationKey('upload.progress.canceled.subtitle'),\n defaultMessage: 'Some files were not uploaded',\n })}\n metadataSubtitle={metadataSubtitle}\n />\n </HeaderStatusWrapper>\n );\n }\n\n if (status === 'uploading') {\n // Two separate strings so a locale can position (or omit) the percentage itself.\n const title =\n progress === null\n ? formatMessage(\n {\n id: getTranslationKey('upload.progress.uploading.indeterminate'),\n defaultMessage: 'Uploading {total, plural, one {# item} other {# items}}',\n },\n { total: totalFiles }\n )\n : formatMessage(\n {\n id: getTranslationKey('upload.progress.uploading.withCount'),\n defaultMessage:\n 'Uploading {total, plural, one {# item} other {# items}} ({percentage}%)',\n },\n {\n total: totalFiles,\n percentage: Math.round(progress),\n }\n );\n\n return (\n <HeaderStatusWrapper>\n <HeaderStatusIcon background=\"primary200\">\n <Upload fill=\"primary700\" />\n </HeaderStatusIcon>\n <HeaderStatusMessage title={title} metadataSubtitle={metadataSubtitle} />\n </HeaderStatusWrapper>\n );\n }\n\n return null;\n};\n\nconst HeaderIconButton = styled(IconButton)`\n &:hover {\n background: transparent;\n }\n`;\n\nconst ChevronWrapper = styled.span<{ $isMinimized: boolean }>`\n display: flex;\n transition: transform 0.5s ease-in-out;\n transform: ${({ $isMinimized }) => ($isMinimized ? 'rotate(180deg)' : 'rotate(0deg)')};\n`;\n\nconst HEADER_COLOR_MAP = {\n uploading: { background: 'primary100' },\n canceled: { background: 'neutral100' },\n success: { background: 'success100' },\n error: { background: 'danger100' },\n} as const;\n\nconst DialogHeader = ({ handleClose }: { handleClose: () => void }) => {\n const { formatMessage } = useIntl();\n\n const { isMinimized, files, uploadId, totalFiles } = useTypedSelector(\n (state) => state.uploadProgress\n );\n const aggregateProgress = useTypedSelector(selectAggregateProgress);\n const reportsByteProgress = useTypedSelector(selectReportsByteProgress);\n const countBasedProgress = useTypedSelector(selectCountBasedProgress);\n // Byte-weighted when the flow streams bytes (direct-file), else count-based (settled/total).\n // Both return `null` for an indeterminate header when there's nothing to show yet.\n const progress = reportsByteProgress ? aggregateProgress : countBasedProgress;\n const metadataProgress = useTypedSelector(selectMetadataProgress);\n const isGeneratingMetadata = useTypedSelector(selectIsGeneratingMetadata);\n const metadataOutcome = useTypedSelector(selectMetadataOutcome);\n const dispatch = useTypedDispatch();\n const [retryCancelledFiles] = useRetryCancelledFilesMutation();\n\n // The batch is complete once every file has reached a terminal state. Byte-weighted\n // progress can't be used here because errored/cancelled rows never reach 100%.\n const isComplete =\n files.length > 0 &&\n files.every((f) => f.status === 'complete' || f.status === 'error' || f.status === 'cancelled');\n const isAllUploaded = isComplete;\n const isAllErrored = isComplete && files.every((f) => f.status === 'error');\n const hasCancelledFiles = files.some((f) => f.status === 'cancelled');\n const successfulCount = files.filter((f) => f.status === 'complete').length;\n const errorCount = files.filter((f) => f.status === 'error').length;\n // Success includes partial success (some files succeeded, even if some failed)\n const isSuccess = isComplete && successfulCount > 0 && !hasCancelledFiles;\n const status = ((): HeaderStatusProps['status'] => {\n if (isAllErrored) return 'error';\n if (isSuccess) return 'success';\n // A single file can be cancelled while the rest of the batch keeps going.\n if (hasCancelledFiles && isComplete) return 'canceled';\n\n return 'uploading';\n })();\n\n const handleCancel = () => {\n abortUpload(uploadId);\n dispatch(cancelUpload());\n };\n\n const handleRetry = async () => {\n try {\n await retryCancelledFiles().unwrap();\n } catch {\n // Error is already dispatched to store from the API queryFn\n }\n };\n\n const handleToggleMinimize = () => {\n dispatch(toggleMinimize());\n };\n\n return (\n <Flex\n background={HEADER_COLOR_MAP[status].background}\n justifyContent=\"space-between\"\n margin={1}\n hasRadius\n >\n <HeaderStatus\n status={status}\n progress={progress}\n totalFiles={totalFiles}\n successfulCount={successfulCount}\n errorCount={errorCount}\n metadataProgress={metadataProgress}\n isGeneratingMetadata={isGeneratingMetadata}\n metadataOutcome={metadataOutcome}\n />\n <Flex gap={1}>\n {!isAllUploaded && (\n <TextButton onClick={handleCancel} fontWeight=\"bold\">\n {formatMessage({\n id: getTranslationKey('upload.progress.cancel'),\n defaultMessage: 'Cancel all',\n })}\n </TextButton>\n )}\n {hasCancelledFiles && (\n <TextButton onClick={handleRetry} fontWeight=\"bold\">\n {formatMessage({\n id: getTranslationKey('upload.progress.retry'),\n defaultMessage: 'Retry',\n })}\n </TextButton>\n )}\n <HeaderIconButton\n onClick={handleToggleMinimize}\n label={formatMessage({\n id: getTranslationKey(\n isMinimized ? 'upload.progress.maximize' : 'upload.progress.minimize'\n ),\n defaultMessage: isMinimized ? 'Maximize' : 'Minimize',\n })}\n variant=\"ghost\"\n >\n <ChevronWrapper $isMinimized={isMinimized}>\n <ChevronDown />\n </ChevronWrapper>\n </HeaderIconButton>\n {isComplete && (\n <Drawer.CloseButton\n onClose={handleClose}\n label={formatMessage({\n id: getTranslationKey('upload.progress.close'),\n defaultMessage: 'Close',\n })}\n />\n )}\n </Flex>\n </Flex>\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * UploadProgressDialog\n * -----------------------------------------------------------------------------------------------*/\n\nconst ProgressTrack = styled.div`\n width: 100%;\n height: ${({ theme }) => theme.spaces[1]};\n background-color: ${({ theme }) => theme.colors.neutral200};\n border-radius: 4px;\n overflow: hidden;\n`;\n\nconst ProgressIndicator = styled.div<{ $percent: number }>`\n height: 100%;\n width: ${({ $percent }) => $percent}%;\n background-color: ${({ theme }) => theme.colors.primary700};\n border-radius: 4px;\n transition: width 0.15s linear;\n`;\n\nconst DeterminateBar = ({ percent }: { percent: number }) => {\n const clamped = Math.min(100, Math.max(0, Math.round(percent)));\n return (\n <ProgressTrack role=\"progressbar\" aria-valuemin={0} aria-valuemax={100} aria-valuenow={clamped}>\n <ProgressIndicator $percent={clamped} />\n </ProgressTrack>\n );\n};\n\nconst INDETERMINATE_INDICATOR_WIDTH = 40;\n\n/**\n * `translateX` percentages resolve against the *indicator's* own width, not the track's.\n * So -100% is exactly \"fully off the left edge\" regardless of the width above, and the\n * end offset converts a full track width into those same own-width units. Both ends sit\n * flush off-track, which keeps entry and exit symmetric — a smaller start offset would\n * make the bar pop in already partly visible.\n */\nconst indeterminateSlide = keyframes`\n from {\n transform: translateX(-100%);\n }\n to {\n transform: translateX(${(100 / INDETERMINATE_INDICATOR_WIDTH) * 100}%);\n }\n`;\n\nconst IndeterminateIndicator = styled.div`\n height: 100%;\n width: ${INDETERMINATE_INDICATOR_WIDTH}%;\n background-color: ${({ theme }) => theme.colors.primary700};\n border-radius: 4px;\n /* Linear, not an eased curve: the DS easings decelerate to a stop, which on a loop\n reads as a stall at the wrap point. Constant speed is what makes it read as a sweep. */\n animation: ${indeterminateSlide} 1.2s linear infinite;\n\n /* A perpetually moving bar is a vestibular trigger; fall back to a static track fill. */\n @media (prefers-reduced-motion: reduce) {\n animation: none;\n width: 100%;\n opacity: 0.5;\n }\n`;\n\n/**\n * Progress bar for work whose completion fraction is genuinely unknowable, rather\n * than merely unknown-yet: the AI metadata endpoint answers in one go, and the URL\n * flow can't report bytes until the server has fetched the file and knows its size.\n *\n * Deliberately omits `aria-valuenow` — that absence is precisely how ARIA conveys\n * an indeterminate progressbar, so assistive tech announces \"busy\" instead of \"0%\".\n */\nconst IndeterminateBar = () => {\n return (\n <ProgressTrack role=\"progressbar\" aria-valuemin={0} aria-valuemax={100}>\n <IndeterminateIndicator />\n </ProgressTrack>\n );\n};\n\n/**\n * Without a floor of zero the row is as wide as its longest filename, which\n * pushes past the panel and gives the dialog a second, horizontal scrollbar\n * instead of truncating.\n *\n * The floor belongs to the name alone: the icon carries its size in SVG\n * attributes, which flex is free to override, so letting it shrink squashes it\n * against a long name instead of truncating the name.\n */\nconst FileRowName = styled(Flex)`\n min-width: 0;\n\n > :first-child {\n flex-shrink: 0;\n }\n\n > :last-child {\n min-width: 0;\n }\n`;\n\nconst FileRow = ({\n icon,\n fileName,\n children,\n}: {\n icon: React.ReactNode;\n fileName: string;\n children: React.ReactNode;\n}) => {\n return (\n <Flex direction=\"column\" alignItems=\"stretch\" justifyContent=\"center\" gap={1} width=\"100%\">\n <FileRowName gap={2}>\n {icon}\n <TruncatedText variant=\"omega\" fontWeight=\"semiBold\">\n {fileName}\n </TruncatedText>\n </FileRowName>\n {children}\n </Flex>\n );\n};\n\n/**\n * Icon + subline for a successfully uploaded row, keyed by its metadata phase.\n * `'none'` covers rows that never entered the phase — AI metadata disabled — and\n * renders exactly as before this feature existed. Non-images do enter the phase and\n * land on `skipped`.\n *\n * `skipped` uses a neutral `Information` icon, deliberately distinct from\n * generated/failed/cancelled — skipping is an expected outcome for a non-image, not a\n * problem to flag.\n */\nconst COMPLETED_ROW_PRESENTATION: Record<\n FileMetadataStatus | 'none',\n { icon: React.ReactNode; message: MessageDescriptor }\n> = {\n none: {\n icon: <CheckCircle fill=\"success500\" />,\n message: {\n id: getTranslationKey('upload.progress.file.uploaded'),\n defaultMessage: 'Uploaded',\n },\n },\n generating: {\n icon: <Sparkle fill=\"primary600\" />,\n message: {\n id: getTranslationKey('upload.progress.file.generatingMetadata'),\n defaultMessage: 'Uploaded • Generating metadata…',\n },\n },\n generated: {\n icon: <CheckCircle fill=\"success500\" />,\n message: {\n id: getTranslationKey('upload.progress.file.metadataGenerated'),\n defaultMessage: 'Uploaded • Metadata generated',\n },\n },\n skipped: {\n icon: <Information fill=\"neutral500\" />,\n message: {\n id: getTranslationKey('upload.progress.file.metadataSkipped'),\n defaultMessage: 'Upload complete • Metadata generation skipped',\n },\n },\n failed: {\n icon: <WarningCircle fill=\"warning500\" />,\n message: {\n id: getTranslationKey('upload.progress.file.metadataFailed'),\n defaultMessage: 'Upload complete • Metadata generation failed',\n },\n },\n};\n\nconst FileRowRenderer = ({ file }: { file: FileProgress }) => {\n const { formatMessage } = useIntl();\n const isError = file.status === 'error';\n const isCurrentFile = file.status === 'uploading';\n const isCompleted = file.status === 'complete';\n const isCancelled = file.status === 'cancelled';\n const isQueued = file.status === 'pending';\n\n if (isQueued) {\n // No bar: there is nothing to report yet, and an indeterminate bar would read\n // as \"in progress\" on a file the pool has not picked up.\n return (\n <FileRow icon={<Clock fill=\"neutral600\" />} fileName={file.name}>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {formatMessage({\n id: getTranslationKey('upload.progress.file.queued'),\n defaultMessage: 'Queued',\n })}\n </Typography>\n </FileRow>\n );\n }\n\n if (isCurrentFile) {\n // Determinate only once bytes are actually being reported — a known `size` is not\n // enough. Both flows can report bytes, but neither always does:\n // - the direct-file flow streams real byte counts from XHR;\n // - the URL flow streams `file:progress` SSE frames while the server fetches the\n // remote file, but only when the remote sent a usable Content-Length. Without one\n // there is no denominator, nothing is dispatched, and `uploadedBytes` stays 0.\n // Keying off `size` alone froze such rows at a determinate 0% for the entire upload;\n // keying off reported bytes keeps them animating until there is a fraction to show.\n // Back to indeterminate once every byte is in: the server is still working (the URL\n // flow's provider upload, the direct flow awaiting its response), not stuck at 100%.\n const hasReportedProgress =\n file.size > 0 && file.uploadedBytes > 0 && file.uploadedBytes < file.size;\n\n return (\n <FileRow icon={<ArrowsCounterClockwise fill=\"secondary600\" />} fileName={file.name}>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {formatMessage({\n id: getTranslationKey('upload.progress.file.uploading'),\n defaultMessage: 'Uploading...',\n })}\n </Typography>\n {hasReportedProgress ? (\n <DeterminateBar percent={(file.uploadedBytes / file.size) * 100} />\n ) : (\n <IndeterminateBar />\n )}\n </FileRow>\n );\n }\n\n if (isError) {\n return (\n <FileRow icon={<CrossCircle fill=\"danger500\" />} fileName={file.name}>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {file.error\n ? /**\n * The server may return a machine-readable code (e.g. `FileTooBig` from the\n * body middleware) or an already human-readable sentence (e.g. the upload\n * plugin's size-limit message). Translate the former, fall back to the latter.\n */\n formatMessage({\n id: getTranslationKey(`apiError.${file.error}`),\n defaultMessage: file.error,\n })\n : formatMessage({\n id: getTranslationKey('upload.generic-error'),\n defaultMessage: 'An error occurred while uploading the file.',\n })}\n </Typography>\n </FileRow>\n );\n }\n\n if (isCancelled) {\n return (\n <FileRow icon={<MinusCircle fill=\"neutral600\" />} fileName={file.name}>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {formatMessage({\n id: getTranslationKey('upload.progress.file.canceled'),\n defaultMessage: 'Canceled',\n })}\n </Typography>\n </FileRow>\n );\n }\n\n if (isCompleted) {\n // The upload succeeded; the metadata phase (if any) drives both the icon and the\n // subline from here on — a metadata failure shows a warning, not an upload error.\n const { icon, message } = COMPLETED_ROW_PRESENTATION[file.metadataStatus ?? 'none'];\n\n return (\n <FileRow icon={icon} fileName={file.name}>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {formatMessage(message)}\n </Typography>\n {/* Generation has no intermediate progress to report, so the bar stays indeterminate. */}\n {file.metadataStatus === 'generating' && <IndeterminateBar />}\n </FileRow>\n );\n }\n\n return null;\n};\n\nconst CompletedFilesList = styled(Flex)`\n flex-direction: column;\n gap: ${({ theme }) => theme.spaces[2]};\n width: 100%;\n`;\n\nexport const UploadProgressDialog = () => {\n const dispatch = useTypedDispatch();\n const { isVisible, isMinimized, files } = useTypedSelector((state) => state.uploadProgress);\n\n // With concurrent uploads several files are `uploading` at once — render every\n // in-flight row, not just the first (a `find` here dated to the strictly\n // sequential era and hid all but the lowest-index worker's row).\n const uploadingFiles = files.filter((f) => f.status === 'uploading');\n // Everything the pool has not reached yet. Listed in queue order, which is the\n // order `files` is already in, so a row's position tells the user where it sits.\n const queuedFiles = files.filter((f) => f.status === 'pending');\n const completedFiles = files\n .filter((f) => f.status === 'complete' || f.status === 'error' || f.status === 'cancelled')\n .sort((a, b) => {\n // Sort priority: error > cancelled > complete\n const priority: Record<FileProgressStatus, number> = {\n error: 0,\n cancelled: 1,\n complete: 2,\n uploading: 3,\n pending: 4,\n };\n return priority[a.status] - priority[b.status];\n });\n\n const handleClose = () => {\n dispatch(closeUploadProgress());\n };\n\n return (\n <Drawer.Root isVisible={isVisible} onClose={handleClose}>\n <Drawer.Body animationDirection=\"up\" width=\"41.6rem\" maxHeight=\"34.2rem\">\n <DialogHeader handleClose={handleClose} />\n <Drawer.ScrollableContent isContentExpanded={!isMinimized}>\n <Flex\n direction=\"column\"\n alignItems=\"stretch\"\n gap={4}\n paddingTop={4}\n paddingBottom={4}\n paddingLeft={4}\n paddingRight={4}\n >\n {uploadingFiles.map((file) => (\n <FileRowRenderer key={file.index} file={file} />\n ))}\n\n {queuedFiles.map((file) => (\n <FileRowRenderer key={file.index} file={file} />\n ))}\n\n {completedFiles.length > 0 && (\n <CompletedFilesList>\n {completedFiles.map((file) => (\n <FileRowRenderer key={file.index} file={file} />\n ))}\n </CompletedFilesList>\n )}\n </Flex>\n </Drawer.ScrollableContent>\n </Drawer.Body>\n </Drawer.Root>\n );\n};\n"],"names":["HeaderStatusMessage","title","subtitle","metadataSubtitle","_jsxs","Flex","direction","alignItems","paddingLeft","paddingRight","paddingTop","paddingBottom","_jsx","Drawer","Title","Typography","variant","Description","textColor","HeaderStatusIcon","styled","theme","spaces","borderRadius","HeaderStatusWrapper","HeaderStatus","status","progress","totalFiles","successfulCount","errorCount","metadataProgress","isGeneratingMetadata","metadataOutcome","formatMessage","useIntl","id","getTranslationKey","defaultMessage","percentage","undefined","generated","failed","generatedCount","failedCount","count","background","Cross","fill","successCount","Check","MinusCircle","total","Math","round","Upload","HeaderIconButton","IconButton","ChevronWrapper","span","$isMinimized","HEADER_COLOR_MAP","uploading","canceled","success","error","DialogHeader","handleClose","isMinimized","files","uploadId","useTypedSelector","state","uploadProgress","aggregateProgress","selectAggregateProgress","reportsByteProgress","selectReportsByteProgress","countBasedProgress","selectCountBasedProgress","selectMetadataProgress","selectIsGeneratingMetadata","selectMetadataOutcome","dispatch","useTypedDispatch","retryCancelledFiles","useRetryCancelledFilesMutation","isComplete","length","every","f","isAllUploaded","isAllErrored","hasCancelledFiles","some","filter","isSuccess","handleCancel","abortUpload","cancelUpload","handleRetry","unwrap","handleToggleMinimize","toggleMinimize","justifyContent","margin","hasRadius","gap","TextButton","onClick","fontWeight","label","ChevronDown","CloseButton","onClose","ProgressTrack","div","colors","neutral200","ProgressIndicator","$percent","primary700","DeterminateBar","percent","clamped","min","max","role","aria-valuemin","aria-valuemax","aria-valuenow","INDETERMINATE_INDICATOR_WIDTH","indeterminateSlide","keyframes","IndeterminateIndicator","IndeterminateBar","FileRowName","FileRow","icon","fileName","children","width","TruncatedText","COMPLETED_ROW_PRESENTATION","none","CheckCircle","message","generating","Sparkle","skipped","Information","WarningCircle","FileRowRenderer","file","isError","isCurrentFile","isCompleted","isCancelled","isQueued","Clock","name","hasReportedProgress","size","uploadedBytes","ArrowsCounterClockwise","CrossCircle","metadataStatus","CompletedFilesList","UploadProgressDialog","isVisible","uploadingFiles","queuedFiles","completedFiles","sort","a","b","priority","cancelled","complete","pending","closeUploadProgress","Root","Body","animationDirection","maxHeight","ScrollableContent","isContentExpanded","map","index"],"mappings":"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"}
@@ -261,7 +261,8 @@ const DialogHeader = ({ handleClose })=>{
261
261
  const status = (()=>{
262
262
  if (isAllErrored) return 'error';
263
263
  if (isSuccess) return 'success';
264
- if (hasCancelledFiles) return 'canceled';
264
+ // A single file can be cancelled while the rest of the batch keeps going.
265
+ if (hasCancelledFiles && isComplete) return 'canceled';
265
266
  return 'uploading';
266
267
  })();
267
268
  const handleCancel = ()=>{