@strapi/upload 5.51.2 → 5.52.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/future/App.js +3 -3
- package/dist/admin/future/App.js.map +1 -1
- package/dist/admin/future/App.mjs +4 -4
- package/dist/admin/future/App.mjs.map +1 -1
- package/dist/admin/future/components/BetaNotice.js +72 -0
- package/dist/admin/future/components/BetaNotice.js.map +1 -0
- package/dist/admin/future/components/BetaNotice.mjs +70 -0
- package/dist/admin/future/components/BetaNotice.mjs.map +1 -0
- package/dist/admin/future/components/Drawer.js +16 -3
- package/dist/admin/future/components/Drawer.js.map +1 -1
- package/dist/admin/future/components/Drawer.mjs +16 -3
- package/dist/admin/future/components/Drawer.mjs.map +1 -1
- package/dist/admin/future/components/TruncatedText.js +76 -0
- package/dist/admin/future/components/TruncatedText.js.map +1 -0
- package/dist/admin/future/components/TruncatedText.mjs +74 -0
- package/dist/admin/future/components/TruncatedText.mjs.map +1 -0
- package/dist/admin/future/hooks/useAIMetadataEnabled.js +39 -0
- package/dist/admin/future/hooks/useAIMetadataEnabled.js.map +1 -0
- package/dist/admin/future/hooks/useAIMetadataEnabled.mjs +37 -0
- package/dist/admin/future/hooks/useAIMetadataEnabled.mjs.map +1 -0
- package/dist/admin/future/hooks/useTracking.js +57 -0
- package/dist/admin/future/hooks/useTracking.js.map +1 -0
- package/dist/admin/future/hooks/useTracking.mjs +53 -0
- package/dist/admin/future/hooks/useTracking.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/AssetsPage.js +328 -139
- package/dist/admin/future/pages/Assets/AssetsPage.js.map +1 -1
- package/dist/admin/future/pages/Assets/AssetsPage.mjs +332 -143
- package/dist/admin/future/pages/Assets/AssetsPage.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/ActionsMenuContent.js +46 -0
- package/dist/admin/future/pages/Assets/components/ActionsMenuContent.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/ActionsMenuContent.mjs +44 -0
- package/dist/admin/future/pages/Assets/components/ActionsMenuContent.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/components/AssetActionsMenu.js +328 -0
- package/dist/admin/future/pages/Assets/components/AssetActionsMenu.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/AssetActionsMenu.mjs +326 -0
- package/dist/admin/future/pages/Assets/components/AssetActionsMenu.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetCropEditor.js +35 -14
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetCropEditor.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetCropEditor.mjs +35 -14
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetCropEditor.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js +74 -53
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs +74 -54
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsGrid.js +92 -28
- package/dist/admin/future/pages/Assets/components/AssetsGrid.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs +94 -30
- package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsSearchInput.js +26 -4
- package/dist/admin/future/pages/Assets/components/AssetsSearchInput.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsSearchInput.mjs +27 -5
- package/dist/admin/future/pages/Assets/components/AssetsSearchInput.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsTable.js +172 -60
- package/dist/admin/future/pages/Assets/components/AssetsTable.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsTable.mjs +175 -63
- package/dist/admin/future/pages/Assets/components/AssetsTable.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/BulkActionsBar.js +64 -132
- package/dist/admin/future/pages/Assets/components/BulkActionsBar.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/BulkActionsBar.mjs +64 -132
- package/dist/admin/future/pages/Assets/components/BulkActionsBar.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/BulkMoveDialog.js +123 -76
- package/dist/admin/future/pages/Assets/components/BulkMoveDialog.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/BulkMoveDialog.mjs +126 -79
- package/dist/admin/future/pages/Assets/components/BulkMoveDialog.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/BusyOverlay.js +36 -0
- package/dist/admin/future/pages/Assets/components/BusyOverlay.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/BusyOverlay.mjs +34 -0
- package/dist/admin/future/pages/Assets/components/BusyOverlay.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/components/DeleteItemsDialog.js +131 -0
- package/dist/admin/future/pages/Assets/components/DeleteItemsDialog.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/DeleteItemsDialog.mjs +129 -0
- package/dist/admin/future/pages/Assets/components/DeleteItemsDialog.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.js +27 -17
- package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.mjs +28 -18
- package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/Dnd/buildDragSet.js +28 -31
- package/dist/admin/future/pages/Assets/components/Dnd/buildDragSet.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/Dnd/buildDragSet.mjs +28 -31
- package/dist/admin/future/pages/Assets/components/Dnd/buildDragSet.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/Dnd/useAssetDnd.js +10 -15
- package/dist/admin/future/pages/Assets/components/Dnd/useAssetDnd.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/Dnd/useAssetDnd.mjs +10 -15
- package/dist/admin/future/pages/Assets/components/Dnd/useAssetDnd.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/FilterBadges.js +13 -4
- package/dist/admin/future/pages/Assets/components/FilterBadges.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/FilterBadges.mjs +13 -4
- package/dist/admin/future/pages/Assets/components/FilterBadges.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/FilterMenu.js +259 -63
- package/dist/admin/future/pages/Assets/components/FilterMenu.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/FilterMenu.mjs +262 -66
- package/dist/admin/future/pages/Assets/components/FilterMenu.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderActionsMenu.js +146 -0
- package/dist/admin/future/pages/Assets/components/FolderActionsMenu.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/FolderActionsMenu.mjs +144 -0
- package/dist/admin/future/pages/Assets/components/FolderActionsMenu.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/components/{CreateFolderDialog.js → FolderFormDialog.js} +62 -16
- package/dist/admin/future/pages/Assets/components/FolderFormDialog.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/{CreateFolderDialog.mjs → FolderFormDialog.mjs} +64 -18
- package/dist/admin/future/pages/Assets/components/FolderFormDialog.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js +132 -229
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs +135 -232
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/SortMenu.js +14 -0
- package/dist/admin/future/pages/Assets/components/SortMenu.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/SortMenu.mjs +14 -0
- package/dist/admin/future/pages/Assets/components/SortMenu.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.js +5 -0
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.js.map +1 -1
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.mjs +6 -1
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/hooks/useBusyAssets.js +47 -0
- package/dist/admin/future/pages/Assets/hooks/useBusyAssets.js.map +1 -0
- package/dist/admin/future/pages/Assets/hooks/useBusyAssets.mjs +44 -0
- package/dist/admin/future/pages/Assets/hooks/useBusyAssets.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.js +203 -62
- package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.js.map +1 -1
- package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.mjs +204 -63
- package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/hooks/useInfiniteScrollSentinel.js +75 -0
- package/dist/admin/future/pages/Assets/hooks/useInfiniteScrollSentinel.js.map +1 -0
- package/dist/admin/future/pages/Assets/hooks/useInfiniteScrollSentinel.mjs +73 -0
- package/dist/admin/future/pages/Assets/hooks/useInfiniteScrollSentinel.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/utils/selection.js +17 -0
- package/dist/admin/future/pages/Assets/utils/selection.js.map +1 -1
- package/dist/admin/future/pages/Assets/utils/selection.mjs +17 -1
- package/dist/admin/future/pages/Assets/utils/selection.mjs.map +1 -1
- package/dist/admin/future/services/api.js +31 -8
- package/dist/admin/future/services/api.js.map +1 -1
- package/dist/admin/future/services/api.mjs +31 -8
- package/dist/admin/future/services/api.mjs.map +1 -1
- package/dist/admin/future/services/assets.js +22 -23
- package/dist/admin/future/services/assets.js.map +1 -1
- package/dist/admin/future/services/assets.mjs +22 -23
- package/dist/admin/future/services/assets.mjs.map +1 -1
- package/dist/admin/future/services/folders.js +37 -2
- package/dist/admin/future/services/folders.js.map +1 -1
- package/dist/admin/future/services/folders.mjs +37 -3
- package/dist/admin/future/services/folders.mjs.map +1 -1
- package/dist/admin/future/utils/buildDragSetFromSelection.js +7 -5
- package/dist/admin/future/utils/buildDragSetFromSelection.js.map +1 -1
- package/dist/admin/future/utils/buildDragSetFromSelection.mjs +7 -5
- package/dist/admin/future/utils/buildDragSetFromSelection.mjs.map +1 -1
- package/dist/admin/future/utils/formatMoveSuccessMessage.js +12 -1
- package/dist/admin/future/utils/formatMoveSuccessMessage.js.map +1 -1
- package/dist/admin/future/utils/formatMoveSuccessMessage.mjs +12 -1
- package/dist/admin/future/utils/formatMoveSuccessMessage.mjs.map +1 -1
- package/dist/admin/future/utils/getRelationId.js +24 -0
- package/dist/admin/future/utils/getRelationId.js.map +1 -0
- package/dist/admin/future/utils/getRelationId.mjs +22 -0
- package/dist/admin/future/utils/getRelationId.mjs.map +1 -0
- package/dist/admin/future/utils/isEventFromWithin.js +14 -0
- package/dist/admin/future/utils/isEventFromWithin.js.map +1 -0
- package/dist/admin/future/utils/isEventFromWithin.mjs +12 -0
- package/dist/admin/future/utils/isEventFromWithin.mjs.map +1 -0
- package/dist/admin/future/utils/itemLocations.js +40 -0
- package/dist/admin/future/utils/itemLocations.js.map +1 -0
- package/dist/admin/future/utils/itemLocations.mjs +36 -0
- package/dist/admin/future/utils/itemLocations.mjs.map +1 -0
- package/dist/admin/future/utils/itemSource.js +36 -0
- package/dist/admin/future/utils/itemSource.js.map +1 -0
- package/dist/admin/future/utils/itemSource.mjs +32 -0
- package/dist/admin/future/utils/itemSource.mjs.map +1 -0
- package/dist/admin/hooks/useAIMetadataJob.js +1 -1
- package/dist/admin/hooks/useAIMetadataJob.js.map +1 -1
- package/dist/admin/hooks/useAIMetadataJob.mjs +1 -1
- package/dist/admin/hooks/useAIMetadataJob.mjs.map +1 -1
- package/dist/admin/index.js +11 -17
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +12 -18
- package/dist/admin/index.mjs.map +1 -1
- package/dist/admin/pages/SettingsPage/SettingsPage.js +2 -2
- package/dist/admin/pages/SettingsPage/SettingsPage.js.map +1 -1
- package/dist/admin/pages/SettingsPage/SettingsPage.mjs +2 -2
- package/dist/admin/pages/SettingsPage/SettingsPage.mjs.map +1 -1
- package/dist/admin/src/future/App.d.ts +1 -1
- package/dist/admin/src/future/components/BetaNotice.d.ts +11 -0
- package/dist/admin/src/future/components/Drawer.d.ts +5 -1
- package/dist/admin/src/future/components/TruncatedText.d.ts +32 -0
- package/dist/admin/src/future/hooks/useAIMetadataEnabled.d.ts +26 -0
- package/dist/admin/src/future/hooks/useTracking.d.ts +29 -0
- package/dist/admin/src/future/pages/Assets/components/ActionsMenuContent.d.ts +33 -0
- package/dist/admin/src/future/pages/Assets/components/AssetActionsMenu.d.ts +26 -0
- package/dist/admin/src/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.d.ts +16 -0
- package/dist/admin/src/future/pages/Assets/components/BulkActionsBar.d.ts +8 -1
- package/dist/admin/src/future/pages/Assets/components/BulkMoveDialog.d.ts +17 -6
- package/dist/admin/src/future/pages/Assets/components/BusyOverlay.d.ts +9 -0
- package/dist/admin/src/future/pages/Assets/components/DeleteItemsDialog.d.ts +27 -0
- package/dist/admin/src/future/pages/Assets/components/Dnd/AssetsDndProvider.d.ts +8 -1
- package/dist/admin/src/future/pages/Assets/components/Dnd/buildDragSet.d.ts +18 -3
- package/dist/admin/src/future/pages/Assets/components/Dnd/useAssetDnd.d.ts +2 -1
- package/dist/admin/src/future/pages/Assets/components/FilterBadges.d.ts +3 -1
- package/dist/admin/src/future/pages/Assets/components/FilterMenu.d.ts +4 -0
- package/dist/admin/src/future/pages/Assets/components/FolderActionsMenu.d.ts +21 -0
- package/dist/admin/src/future/pages/Assets/components/FolderFormDialog.d.ts +16 -0
- package/dist/admin/src/future/pages/Assets/hooks/useAssetSelection.d.ts +2 -0
- package/dist/admin/src/future/pages/Assets/hooks/useBusyAssets.d.ts +38 -0
- package/dist/admin/src/future/pages/Assets/hooks/useInfiniteAssets.d.ts +20 -6
- package/dist/admin/src/future/pages/Assets/hooks/useInfiniteScrollSentinel.d.ts +41 -0
- package/dist/admin/src/future/pages/Assets/utils/selection.d.ts +10 -0
- package/dist/admin/src/future/services/api.d.ts +6 -7
- package/dist/admin/src/future/services/folders.d.ts +6 -1
- package/dist/admin/src/future/utils/buildDragSetFromSelection.d.ts +4 -3
- package/dist/admin/src/future/utils/formatMoveSuccessMessage.d.ts +7 -1
- package/dist/admin/src/future/utils/getRelationId.d.ts +11 -0
- package/dist/admin/src/future/utils/isEventFromWithin.d.ts +11 -0
- package/dist/admin/src/future/utils/itemLocations.d.ts +31 -0
- package/dist/admin/src/future/utils/itemSource.d.ts +22 -0
- package/dist/admin/translations/en.json.js +25 -4
- package/dist/admin/translations/en.json.js.map +1 -1
- package/dist/admin/translations/en.json.mjs +25 -4
- package/dist/admin/translations/en.json.mjs.map +1 -1
- package/dist/server/controllers/admin-file.js +27 -9
- package/dist/server/controllers/admin-file.js.map +1 -1
- package/dist/server/controllers/admin-file.mjs +27 -9
- package/dist/server/controllers/admin-file.mjs.map +1 -1
- package/dist/server/controllers/admin-upload.js +24 -8
- package/dist/server/controllers/admin-upload.js.map +1 -1
- package/dist/server/controllers/admin-upload.mjs +24 -8
- package/dist/server/controllers/admin-upload.mjs.map +1 -1
- package/dist/server/routes/admin.js +41 -21
- package/dist/server/routes/admin.js.map +1 -1
- package/dist/server/routes/admin.mjs +41 -21
- package/dist/server/routes/admin.mjs.map +1 -1
- package/dist/server/services/ai-metadata.js.map +1 -1
- package/dist/server/services/ai-metadata.mjs.map +1 -1
- package/dist/server/services/image-manipulation.js.map +1 -1
- package/dist/server/services/image-manipulation.mjs.map +1 -1
- package/dist/server/src/controllers/admin-file.d.ts +29 -8
- package/dist/server/src/controllers/admin-file.d.ts.map +1 -1
- package/dist/server/src/controllers/admin-upload.d.ts +20 -4
- package/dist/server/src/controllers/admin-upload.d.ts.map +1 -1
- package/dist/server/src/controllers/index.d.ts +4 -4
- package/dist/server/src/index.d.ts +4 -4
- package/dist/server/src/routes/admin.d.ts.map +1 -1
- package/dist/server/src/services/ai-metadata.d.ts +2 -2
- package/dist/server/src/services/ai-metadata.d.ts.map +1 -1
- package/dist/server/src/services/image-manipulation.d.ts +0 -5
- package/dist/server/src/services/image-manipulation.d.ts.map +1 -1
- package/dist/shared/contracts/ai-metadata-jobs.d.ts +10 -32
- package/dist/shared/contracts/ai-metadata-jobs.d.ts.map +1 -1
- package/dist/shared/contracts/files.d.ts +10 -10
- package/dist/shared/contracts/files.d.ts.map +1 -1
- package/package.json +9 -9
- package/dist/admin/future/pages/Assets/components/CreateFolderDialog.js.map +0 -1
- package/dist/admin/future/pages/Assets/components/CreateFolderDialog.mjs.map +0 -1
- package/dist/admin/future/pages/Assets/components/FolderTree/filterFolderTree.js +0 -33
- package/dist/admin/future/pages/Assets/components/FolderTree/filterFolderTree.js.map +0 -1
- package/dist/admin/future/pages/Assets/components/FolderTree/filterFolderTree.mjs +0 -31
- package/dist/admin/future/pages/Assets/components/FolderTree/filterFolderTree.mjs.map +0 -1
- package/dist/admin/src/future/pages/Assets/components/CreateFolderDialog.d.ts +0 -8
- package/dist/admin/src/future/pages/Assets/components/FolderTree/filterFolderTree.d.ts +0 -16
|
@@ -37,6 +37,22 @@ const createEmptySelection = ()=>({
|
|
|
37
37
|
anchorKey: key
|
|
38
38
|
};
|
|
39
39
|
};
|
|
40
|
+
/**
|
|
41
|
+
* Subtractive counterpart to {@link toggleSelection} — removes a key without the
|
|
42
|
+
* add-if-absent ambiguity, leaving the rest of the selection alone. Used when a
|
|
43
|
+
* single-item affordance (a row's "..." menu) makes exactly one key stale.
|
|
44
|
+
*
|
|
45
|
+
* Idempotent: removing a key that was never selected is a no-op. The anchor is
|
|
46
|
+
* dropped only when it is the removed key, so a Shift+click range built around
|
|
47
|
+
* other rows survives.
|
|
48
|
+
*/ const deselect = (state, key)=>{
|
|
49
|
+
const selectedKeys = new Set(state.selectedKeys);
|
|
50
|
+
selectedKeys.delete(key);
|
|
51
|
+
return {
|
|
52
|
+
selectedKeys,
|
|
53
|
+
anchorKey: state.anchorKey === key ? null : state.anchorKey
|
|
54
|
+
};
|
|
55
|
+
};
|
|
40
56
|
/**
|
|
41
57
|
* Shift+click — selects the contiguous range between the current anchor and the
|
|
42
58
|
* target in render order, replacing the current selection. The anchor stays put.
|
|
@@ -90,5 +106,5 @@ const clearSelection = ()=>createEmptySelection();
|
|
|
90
106
|
};
|
|
91
107
|
};
|
|
92
108
|
|
|
93
|
-
export { assetKey, clearSelection, createEmptySelection, folderKey, getIdsOfKind, getSelectAllState, selectAll, selectRange, toggleSelection };
|
|
109
|
+
export { assetKey, clearSelection, createEmptySelection, deselect, folderKey, getIdsOfKind, getSelectAllState, selectAll, selectRange, toggleSelection };
|
|
94
110
|
//# sourceMappingURL=selection.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selection.mjs","sources":["../../../../../../admin/src/future/pages/Assets/utils/selection.ts"],"sourcesContent":["/**\n * Pure, view-agnostic selection logic for the future Media Library multi-select.\n *\n * Selection covers both assets and folders. Since their numeric ids live in\n * different tables (and can collide), items are tracked as namespaced keys\n * (`asset:1` / `folder:1`). Views build their rendered order as a key array so\n * range / select-all work across the folder and asset sections seamlessly.\n */\n\nexport type SelectableKind = 'asset' | 'folder';\n\nexport type ItemKey = `${SelectableKind}:${number}`;\n\nexport const assetKey = (id: number): ItemKey => `asset:${id}`;\n\nexport const folderKey = (id: number): ItemKey => `folder:${id}`;\n\n/** Extracts the numeric ids of one kind from a set of item keys. */\nexport const getIdsOfKind = (keys: Set<ItemKey>, kind: SelectableKind): Set<number> => {\n const ids = new Set<number>();\n\n keys.forEach((key) => {\n const [keyKind, id] = key.split(':');\n if (keyKind === kind) {\n ids.add(Number(id));\n }\n });\n\n return ids;\n};\n\nexport interface SelectionState {\n /** Currently selected item keys (assets and folders). */\n selectedKeys: Set<ItemKey>;\n /** Anchor used as the start of a Shift+click range. */\n anchorKey: ItemKey | null;\n}\n\nexport const createEmptySelection = (): SelectionState => ({\n selectedKeys: new Set<ItemKey>(),\n anchorKey: null,\n});\n\n/**\n * Additive toggle — adds the key if absent, removes it otherwise, without\n * touching the rest of the selection. Used by the item checkbox and Cmd/Ctrl+click.\n * The toggled key becomes the new anchor.\n */\nexport const toggleSelection = (state: SelectionState, key: ItemKey): SelectionState => {\n const selectedKeys = new Set(state.selectedKeys);\n\n if (selectedKeys.has(key)) {\n selectedKeys.delete(key);\n } else {\n selectedKeys.add(key);\n }\n\n return { selectedKeys, anchorKey: key };\n};\n\n/**\n * Shift+click — selects the contiguous range between the current anchor and the\n * target in render order, replacing the current selection. The anchor stays put.\n *\n * Falls back to a single selection when there is no usable anchor (e.g. first\n * click was a Shift+click, or the anchor is no longer in the list).\n */\nexport const selectRange = (\n state: SelectionState,\n orderedKeys: ItemKey[],\n targetKey: ItemKey\n): SelectionState => {\n const targetIndex = orderedKeys.indexOf(targetKey);\n\n if (targetIndex === -1) {\n return state;\n }\n\n const anchorIndex = state.anchorKey === null ? -1 : orderedKeys.indexOf(state.anchorKey);\n\n if (anchorIndex === -1) {\n return { selectedKeys: new Set<ItemKey>([targetKey]), anchorKey: targetKey };\n }\n\n const start = Math.min(anchorIndex, targetIndex);\n const end = Math.max(anchorIndex, targetIndex);\n\n return {\n selectedKeys: new Set(orderedKeys.slice(start, end + 1)),\n anchorKey: state.anchorKey,\n };\n};\n\n/**\n * Select-all — selects every key in the provided ordered array. Used by the header\n * checkbox when not everything is already selected.\n */\nexport const selectAll = (orderedKeys: ItemKey[]): SelectionState => ({\n selectedKeys: new Set(orderedKeys),\n anchorKey: orderedKeys.length > 0 ? orderedKeys[orderedKeys.length - 1] : null,\n});\n\nexport const clearSelection = (): SelectionState => createEmptySelection();\n\nexport interface SelectAllState {\n allSelected: boolean;\n isIndeterminate: boolean;\n}\n\n/**\n * Derives the header checkbox state: everything selected, some (indeterminate),\n * or none. Only considers the currently-rendered items (orderedKeys).\n */\nexport const getSelectAllState = (\n selectedKeys: Set<ItemKey>,\n orderedKeys: ItemKey[]\n): SelectAllState => {\n if (orderedKeys.length === 0) {\n return { allSelected: false, isIndeterminate: false };\n }\n\n const selectedCount = orderedKeys.reduce(\n (count, key) => (selectedKeys.has(key) ? count + 1 : count),\n 0\n );\n const allSelected = selectedCount === orderedKeys.length;\n\n return {\n allSelected,\n isIndeterminate: selectedCount > 0 && !allSelected,\n };\n};\n"],"names":["assetKey","id","folderKey","getIdsOfKind","keys","kind","ids","Set","forEach","key","keyKind","split","add","Number","createEmptySelection","selectedKeys","anchorKey","toggleSelection","state","has","delete","selectRange","orderedKeys","targetKey","targetIndex","indexOf","anchorIndex","start","Math","min","end","max","slice","selectAll","length","clearSelection","getSelectAllState","allSelected","isIndeterminate","selectedCount","reduce","count"],"mappings":"AAAA;;;;;;;UAaaA,QAAAA,GAAW,CAACC,KAAwB,CAAC,MAAM,EAAEA,EAAAA,CAAAA;AAEnD,MAAMC,YAAY,CAACD,EAAAA,GAAwB,CAAC,OAAO,EAAEA;AAE5D,qEACO,MAAME,YAAAA,GAAe,CAACC,IAAAA,EAAoBC,IAAAA,GAAAA;AAC/C,IAAA,MAAMC,MAAM,IAAIC,GAAAA,EAAAA;IAEhBH,IAAAA,CAAKI,OAAO,CAAC,CAACC,GAAAA,GAAAA;AACZ,QAAA,MAAM,CAACC,OAAAA,EAAST,EAAAA,CAAG,GAAGQ,GAAAA,CAAIE,KAAK,CAAC,GAAA,CAAA;AAChC,QAAA,IAAID,YAAYL,IAAAA,EAAM;YACpBC,GAAAA,CAAIM,GAAG,CAACC,MAAAA,CAAOZ,EAAAA,CAAAA,CAAAA;AACjB,QAAA;AACF,IAAA,CAAA,CAAA;IAEA,OAAOK,GAAAA;AACT;AASO,MAAMQ,oBAAAA,GAAuB,KAAuB;AACzDC,QAAAA,YAAAA,EAAc,IAAIR,GAAAA,EAAAA;QAClBS,SAAAA,EAAW;AACb,KAAA;AAEA;;;;AAIC,IACM,MAAMC,eAAAA,GAAkB,CAACC,KAAAA,EAAuBT,GAAAA,GAAAA;AACrD,IAAA,MAAMM,YAAAA,GAAe,IAAIR,GAAAA,CAAIW,KAAAA,CAAMH,YAAY,CAAA;IAE/C,IAAIA,YAAAA,CAAaI,GAAG,CAACV,GAAAA,CAAAA,EAAM;AACzBM,QAAAA,YAAAA,CAAaK,MAAM,CAACX,GAAAA,CAAAA;IACtB,CAAA,MAAO;AACLM,QAAAA,YAAAA,CAAaH,GAAG,CAACH,GAAAA,CAAAA;AACnB,IAAA;IAEA,OAAO;AAAEM,QAAAA,YAAAA;QAAcC,SAAAA,EAAWP;AAAI,KAAA;AACxC;AAEA;;;;;;AAMC,IACM,
|
|
1
|
+
{"version":3,"file":"selection.mjs","sources":["../../../../../../admin/src/future/pages/Assets/utils/selection.ts"],"sourcesContent":["/**\n * Pure, view-agnostic selection logic for the future Media Library multi-select.\n *\n * Selection covers both assets and folders. Since their numeric ids live in\n * different tables (and can collide), items are tracked as namespaced keys\n * (`asset:1` / `folder:1`). Views build their rendered order as a key array so\n * range / select-all work across the folder and asset sections seamlessly.\n */\n\nexport type SelectableKind = 'asset' | 'folder';\n\nexport type ItemKey = `${SelectableKind}:${number}`;\n\nexport const assetKey = (id: number): ItemKey => `asset:${id}`;\n\nexport const folderKey = (id: number): ItemKey => `folder:${id}`;\n\n/** Extracts the numeric ids of one kind from a set of item keys. */\nexport const getIdsOfKind = (keys: Set<ItemKey>, kind: SelectableKind): Set<number> => {\n const ids = new Set<number>();\n\n keys.forEach((key) => {\n const [keyKind, id] = key.split(':');\n if (keyKind === kind) {\n ids.add(Number(id));\n }\n });\n\n return ids;\n};\n\nexport interface SelectionState {\n /** Currently selected item keys (assets and folders). */\n selectedKeys: Set<ItemKey>;\n /** Anchor used as the start of a Shift+click range. */\n anchorKey: ItemKey | null;\n}\n\nexport const createEmptySelection = (): SelectionState => ({\n selectedKeys: new Set<ItemKey>(),\n anchorKey: null,\n});\n\n/**\n * Additive toggle — adds the key if absent, removes it otherwise, without\n * touching the rest of the selection. Used by the item checkbox and Cmd/Ctrl+click.\n * The toggled key becomes the new anchor.\n */\nexport const toggleSelection = (state: SelectionState, key: ItemKey): SelectionState => {\n const selectedKeys = new Set(state.selectedKeys);\n\n if (selectedKeys.has(key)) {\n selectedKeys.delete(key);\n } else {\n selectedKeys.add(key);\n }\n\n return { selectedKeys, anchorKey: key };\n};\n\n/**\n * Subtractive counterpart to {@link toggleSelection} — removes a key without the\n * add-if-absent ambiguity, leaving the rest of the selection alone. Used when a\n * single-item affordance (a row's \"...\" menu) makes exactly one key stale.\n *\n * Idempotent: removing a key that was never selected is a no-op. The anchor is\n * dropped only when it is the removed key, so a Shift+click range built around\n * other rows survives.\n */\nexport const deselect = (state: SelectionState, key: ItemKey): SelectionState => {\n const selectedKeys = new Set(state.selectedKeys);\n selectedKeys.delete(key);\n\n return {\n selectedKeys,\n anchorKey: state.anchorKey === key ? null : state.anchorKey,\n };\n};\n\n/**\n * Shift+click — selects the contiguous range between the current anchor and the\n * target in render order, replacing the current selection. The anchor stays put.\n *\n * Falls back to a single selection when there is no usable anchor (e.g. first\n * click was a Shift+click, or the anchor is no longer in the list).\n */\nexport const selectRange = (\n state: SelectionState,\n orderedKeys: ItemKey[],\n targetKey: ItemKey\n): SelectionState => {\n const targetIndex = orderedKeys.indexOf(targetKey);\n\n if (targetIndex === -1) {\n return state;\n }\n\n const anchorIndex = state.anchorKey === null ? -1 : orderedKeys.indexOf(state.anchorKey);\n\n if (anchorIndex === -1) {\n return { selectedKeys: new Set<ItemKey>([targetKey]), anchorKey: targetKey };\n }\n\n const start = Math.min(anchorIndex, targetIndex);\n const end = Math.max(anchorIndex, targetIndex);\n\n return {\n selectedKeys: new Set(orderedKeys.slice(start, end + 1)),\n anchorKey: state.anchorKey,\n };\n};\n\n/**\n * Select-all — selects every key in the provided ordered array. Used by the header\n * checkbox when not everything is already selected.\n */\nexport const selectAll = (orderedKeys: ItemKey[]): SelectionState => ({\n selectedKeys: new Set(orderedKeys),\n anchorKey: orderedKeys.length > 0 ? orderedKeys[orderedKeys.length - 1] : null,\n});\n\nexport const clearSelection = (): SelectionState => createEmptySelection();\n\nexport interface SelectAllState {\n allSelected: boolean;\n isIndeterminate: boolean;\n}\n\n/**\n * Derives the header checkbox state: everything selected, some (indeterminate),\n * or none. Only considers the currently-rendered items (orderedKeys).\n */\nexport const getSelectAllState = (\n selectedKeys: Set<ItemKey>,\n orderedKeys: ItemKey[]\n): SelectAllState => {\n if (orderedKeys.length === 0) {\n return { allSelected: false, isIndeterminate: false };\n }\n\n const selectedCount = orderedKeys.reduce(\n (count, key) => (selectedKeys.has(key) ? count + 1 : count),\n 0\n );\n const allSelected = selectedCount === orderedKeys.length;\n\n return {\n allSelected,\n isIndeterminate: selectedCount > 0 && !allSelected,\n };\n};\n"],"names":["assetKey","id","folderKey","getIdsOfKind","keys","kind","ids","Set","forEach","key","keyKind","split","add","Number","createEmptySelection","selectedKeys","anchorKey","toggleSelection","state","has","delete","deselect","selectRange","orderedKeys","targetKey","targetIndex","indexOf","anchorIndex","start","Math","min","end","max","slice","selectAll","length","clearSelection","getSelectAllState","allSelected","isIndeterminate","selectedCount","reduce","count"],"mappings":"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"}
|
|
@@ -99,7 +99,7 @@ const unregisterAbortController = (uploadId)=>{
|
|
|
99
99
|
* "complete" or "error". Each file is wrapped in its own try/catch so one failure
|
|
100
100
|
* does not stop the batch. An abort stops the loop without starting further files.
|
|
101
101
|
*/ const runUploadPool = async ({ entries, indices, token, uploadId, abortController, dispatch, concurrency = 1, generateAiMetadata })=>{
|
|
102
|
-
const url = `${window.strapi.backendURL}/upload/
|
|
102
|
+
const url = `${window.strapi.backendURL}/upload/files`;
|
|
103
103
|
const uploaded = [];
|
|
104
104
|
// Shared queue: each worker shifts the next index when it frees up, so N
|
|
105
105
|
// files are in flight at any moment (not N-sized waves). With concurrency 1
|
|
@@ -227,7 +227,7 @@ const unregisterAbortController = (uploadId)=>{
|
|
|
227
227
|
if (token) {
|
|
228
228
|
headers.Authorization = `Bearer ${token}`;
|
|
229
229
|
}
|
|
230
|
-
return fetch(`${backendURL}/upload/
|
|
230
|
+
return fetch(`${backendURL}/upload/actions/upload-from-urls`, {
|
|
231
231
|
method: 'POST',
|
|
232
232
|
headers,
|
|
233
233
|
body: JSON.stringify({
|
|
@@ -336,10 +336,9 @@ const uploadApi = strapiAdmin.adminApi.enhanceEndpoints({
|
|
|
336
336
|
}).injectEndpoints({
|
|
337
337
|
endpoints: (builder)=>({
|
|
338
338
|
/**
|
|
339
|
-
* Upload files to `/upload/
|
|
340
|
-
*
|
|
341
|
-
*
|
|
342
|
-
* `XHR.upload.onprogress`.
|
|
339
|
+
* Upload files to `/upload/files`, one request per file, through a worker
|
|
340
|
+
* pool of `concurrency` parallel requests (default 1 = sequential). Real
|
|
341
|
+
* per-file byte progress comes from `XHR.upload.onprogress`.
|
|
343
342
|
*/ uploadFiles: builder.mutation({
|
|
344
343
|
queryFn: async ({ formData, totalFiles, concurrency = 1, generateAiMetadata }, { dispatch, getState })=>{
|
|
345
344
|
const token = getState().admin_app?.token;
|
|
@@ -382,10 +381,16 @@ const uploadApi = strapiAdmin.adminApi.enhanceEndpoints({
|
|
|
382
381
|
generateAiMetadata
|
|
383
382
|
});
|
|
384
383
|
},
|
|
384
|
+
// `Folder, LIST` refreshes the folder header count, which changes when
|
|
385
|
+
// files are added to it.
|
|
385
386
|
invalidatesTags: [
|
|
386
387
|
{
|
|
387
388
|
type: 'Asset',
|
|
388
389
|
id: 'LIST'
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
type: 'Folder',
|
|
393
|
+
id: 'LIST'
|
|
389
394
|
}
|
|
390
395
|
]
|
|
391
396
|
}),
|
|
@@ -398,7 +403,7 @@ const uploadApi = strapiAdmin.adminApi.enhanceEndpoints({
|
|
|
398
403
|
*/ uploadFileSilently: builder.mutation({
|
|
399
404
|
queryFn: async ({ file, fileInfo }, { getState })=>{
|
|
400
405
|
const token = getState().admin_app?.token;
|
|
401
|
-
const url = `${window.strapi.backendURL}/upload/
|
|
406
|
+
const url = `${window.strapi.backendURL}/upload/files`;
|
|
402
407
|
const formData = new FormData();
|
|
403
408
|
formData.append('files', file);
|
|
404
409
|
formData.append('fileInfo', JSON.stringify(fileInfo));
|
|
@@ -417,10 +422,16 @@ const uploadApi = strapiAdmin.adminApi.enhanceEndpoints({
|
|
|
417
422
|
};
|
|
418
423
|
}
|
|
419
424
|
},
|
|
425
|
+
// `Folder, LIST` refreshes the folder header count, which changes when
|
|
426
|
+
// files are added to it.
|
|
420
427
|
invalidatesTags: [
|
|
421
428
|
{
|
|
422
429
|
type: 'Asset',
|
|
423
430
|
id: 'LIST'
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
type: 'Folder',
|
|
434
|
+
id: 'LIST'
|
|
424
435
|
}
|
|
425
436
|
]
|
|
426
437
|
}),
|
|
@@ -467,10 +478,16 @@ const uploadApi = strapiAdmin.adminApi.enhanceEndpoints({
|
|
|
467
478
|
generateAiMetadata: batch.generateAiMetadata
|
|
468
479
|
});
|
|
469
480
|
},
|
|
481
|
+
// `Folder, LIST` refreshes the folder header count, which changes when
|
|
482
|
+
// files are added to it.
|
|
470
483
|
invalidatesTags: [
|
|
471
484
|
{
|
|
472
485
|
type: 'Asset',
|
|
473
486
|
id: 'LIST'
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
type: 'Folder',
|
|
490
|
+
id: 'LIST'
|
|
474
491
|
}
|
|
475
492
|
]
|
|
476
493
|
}),
|
|
@@ -565,10 +582,16 @@ const uploadApi = strapiAdmin.adminApi.enhanceEndpoints({
|
|
|
565
582
|
};
|
|
566
583
|
}
|
|
567
584
|
},
|
|
585
|
+
// `Folder, LIST` refreshes the folder header count, which changes when
|
|
586
|
+
// files are added to it.
|
|
568
587
|
invalidatesTags: [
|
|
569
588
|
{
|
|
570
589
|
type: 'Asset',
|
|
571
590
|
id: 'LIST'
|
|
591
|
+
},
|
|
592
|
+
{
|
|
593
|
+
type: 'Folder',
|
|
594
|
+
id: 'LIST'
|
|
572
595
|
}
|
|
573
596
|
]
|
|
574
597
|
}),
|
|
@@ -584,7 +607,7 @@ const uploadApi = strapiAdmin.adminApi.enhanceEndpoints({
|
|
|
584
607
|
* Re-exported from `assets.ts` for the components that consume the hook.
|
|
585
608
|
*/ generateAiMetadata: builder.mutation({
|
|
586
609
|
query: ({ fileIds })=>({
|
|
587
|
-
url: '/upload/
|
|
610
|
+
url: '/upload/actions/generate-ai-metadata',
|
|
588
611
|
method: 'POST',
|
|
589
612
|
data: {
|
|
590
613
|
fileIds
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sources":["../../../../admin/src/future/services/api.ts"],"sourcesContent":["import { Dispatch } from '@reduxjs/toolkit';\nimport { adminApi } from '@strapi/admin/strapi-admin';\n\nimport {\n openUploadProgress,\n setFileUploading,\n setFileProgress,\n setFileComplete,\n setFileError,\n setFileMetadataGenerating,\n setFileMetadataResult,\n setUploadFailed,\n retryCancelledFiles,\n} from '../store/uploadProgress';\nimport { createRafBatcher } from '../utils/createRafBatcher';\nimport { getFilenameFromUrl } from '../utils/files';\n\nimport { uploadFileViaXHR, UploadAbortedError } from './uploadFileViaXHR';\n\nimport type {\n CreateFilesStream,\n CreateFilesStreamEvents,\n File as UploadedFile,\n UnstableGenerateAIMetadata,\n UploadFileInfo,\n} from '../../../../shared/contracts/files';\nimport type { FileMetadataResultStatus } from '../store/uploadProgress';\n\ninterface UploadFilesArgs {\n formData: FormData;\n totalFiles: number;\n /**\n * How many files to upload in parallel — the `concurrentUploadRequests`\n * settings value. Defaults to 1 (sequential).\n */\n concurrency?: number;\n /** Whether AI metadata generation is enabled (EE AI available + `settings.aiMetadata`). */\n generateAiMetadata: boolean;\n}\n\ninterface UploadFromUrlsArgs {\n urls: string[];\n folderId: number | null;\n generateAiMetadata: boolean;\n}\n\ninterface RootState {\n admin_app: {\n token?: string | null;\n };\n uploadProgress: {\n uploadId: number;\n files: Array<{\n index: number;\n name: string;\n size: number;\n status: 'pending' | 'uploading' | 'complete' | 'error' | 'cancelled';\n }>;\n };\n}\n\n/**\n * A single file plus the `fileInfo` it was queued with.\n * Retained in {@link uploadRegistry} so cancelled files can be retried without\n * the user re-selecting them. `File`/`AbortController` are non-serializable, so\n * they live here rather than in Redux.\n */\ninterface UploadEntry {\n file: File;\n fileInfo: UploadFileInfo;\n}\n\n/**\n * Everything a batch needs to be replayed on retry: the original entries plus the\n * flags it was started with (AI-metadata and upload concurrency). These live here\n * rather than in Redux because `retryCancelledFiles` takes no args and the page\n * that owns `useAIAvailability` / the settings value is not involved in the retry.\n */\ninterface UploadBatch {\n entries: UploadEntry[];\n generateAiMetadata: boolean;\n concurrency: number;\n}\n\n/**\n * Stores the original upload batch (keyed by uploadId) to enable retry.\n */\nconst uploadRegistry = new Map<number, UploadBatch>();\n\nconst registerUploadEntries = (\n uploadId: number,\n entries: UploadEntry[],\n generateAiMetadata: boolean,\n concurrency: number\n) => {\n uploadRegistry.set(uploadId, { entries, generateAiMetadata, concurrency });\n};\n\nconst getUploadEntries = (uploadId: number): UploadBatch | undefined => {\n return uploadRegistry.get(uploadId);\n};\n\n/**\n * Manages abort controllers for in-flight uploads.\n *\n * Design decision: Uses a Map to track uploads by their unique uploadId.\n * Redux state cannot store function references (abort controllers), RTK Query's\n * signal is only accessible within the queryFn, and the upload is triggered in\n * AssetsPage but cancelled from UploadProgressDialog.\n */\nconst abortControllers = new Map<number, AbortController>();\n\nconst registerAbortController = (uploadId: number, controller: AbortController) => {\n abortControllers.set(uploadId, controller);\n};\n\nconst unregisterAbortController = (uploadId: number) => {\n abortControllers.delete(uploadId);\n};\n\n/**\n * Aborts an upload by its uploadId.\n * Called from the UploadProgressDialog when the user clicks cancel or close.\n */\nexport const abortUpload = (uploadId: number) => {\n const controller = abortControllers.get(uploadId);\n if (controller) {\n controller.abort();\n unregisterAbortController(uploadId);\n }\n};\n\n/**\n * Error shape returned by upload operations.\n * Matches RTK Query's expected return type for queryFn.\n */\ninterface UploadError {\n name: 'UnknownError';\n message: string;\n status?: number;\n}\n\n/**\n * The store's dispatch also accepts thunks, which is what RTK Query's\n * `endpoint.initiate(...)` returns — the plain `Dispatch` action type can't express that.\n */\ntype AppDispatch = Dispatch &\n (<T>(thunk: T) => T extends (...args: never[]) => infer R ? R : never);\n\ntype UploadPoolResult =\n | { data: UploadedFile[]; error?: undefined }\n | { error: UploadError; data?: undefined };\n\n/** Maps a server per-file outcome onto the row's terminal metadata status. */\nconst METADATA_STATUS_BY_RESULT: Record<\n UnstableGenerateAIMetadata.FileStatus,\n FileMetadataResultStatus\n> = {\n success: 'generated',\n skipped: 'skipped',\n error: 'failed',\n};\n\n/**\n * Kicks off AI metadata generation for a freshly uploaded file.\n *\n * Deliberately fire-and-forget — the caller must NOT await it:\n * - generation for file N overlaps the upload of file N+1;\n * - a generation failure can never affect the upload result (the upload already\n * succeeded), which is why the promise is fully swallowed here.\n *\n * Every uploaded file is sent, including non-images: the server already classifies\n * them (`ai-metadata.generateForFiles` returns `skipped` for anything whose mime\n * isn't `image/*`) and duplicating that rule here would let the two drift apart.\n * The upshot is that a non-image now reports \"Metadata generation skipped\" rather\n * than silently showing no metadata state at all.\n */\nexport const maybeGenerateMetadata = ({\n file,\n index,\n uploadId,\n enabled,\n dispatch,\n}: {\n file: UploadedFile;\n index: number;\n uploadId: number;\n enabled: boolean;\n dispatch: Dispatch;\n}): void => {\n if (!enabled || typeof file.id !== 'number') {\n return;\n }\n\n dispatch(setFileMetadataGenerating({ index, uploadId }));\n\n // `uploadApi` is declared below but only read at call time, long after the module\n // has finished evaluating.\n const promise = (dispatch as AppDispatch)(\n uploadApi.endpoints.generateAiMetadata.initiate({ fileIds: [file.id] })\n );\n\n promise\n .unwrap()\n .then((results) => {\n const result = results?.find((r) => r.id === file.id) ?? results?.[0];\n dispatch(\n setFileMetadataResult({\n index,\n uploadId,\n status: result ? METADATA_STATUS_BY_RESULT[result.status] : 'failed',\n })\n );\n })\n .catch(() => {\n dispatch(setFileMetadataResult({ index, uploadId, status: 'failed' }));\n });\n};\n\n/**\n * Uploads the given entry indices one at a time through the single-file endpoint.\n *\n * For each file: dispatches \"uploading\", wires `XHR.upload.onprogress` through a\n * per-frame batcher to `setFileProgress`, awaits the XHR, then dispatches\n * \"complete\" or \"error\". Each file is wrapped in its own try/catch so one failure\n * does not stop the batch. An abort stops the loop without starting further files.\n */\nconst runUploadPool = async ({\n entries,\n indices,\n token,\n uploadId,\n abortController,\n dispatch,\n concurrency = 1,\n generateAiMetadata,\n}: {\n entries: UploadEntry[];\n indices: number[];\n token: string | null | undefined;\n uploadId: number;\n abortController: AbortController;\n dispatch: Dispatch;\n /** Parallel workers pulling from the queue. 1 (the default) = sequential. */\n concurrency?: number;\n generateAiMetadata: boolean;\n}): Promise<UploadPoolResult> => {\n const url = `${window.strapi.backendURL}/upload/unstable/upload-file`;\n const uploaded: UploadedFile[] = [];\n\n // Shared queue: each worker shifts the next index when it frees up, so N\n // files are in flight at any moment (not N-sized waves). With concurrency 1\n // this degenerates to the original strictly sequential loop.\n const queue = [...indices];\n\n const uploadOne = async (index: number) => {\n const entry = entries[index];\n if (!entry) {\n return;\n }\n\n const fileName = entry.fileInfo?.name ?? entry.file.name;\n\n dispatch(setFileUploading({ name: fileName, index, size: entry.file.size }));\n\n const formData = new FormData();\n formData.append('files', entry.file);\n formData.append('fileInfo', JSON.stringify(entry.fileInfo));\n\n // Coalesce high-frequency progress events into one dispatch per frame.\n const batcher = createRafBatcher<number>((bytes) => {\n dispatch(setFileProgress({ index, bytes }));\n });\n\n try {\n const file = await uploadFileViaXHR(url, token, formData, abortController.signal, (bytes) =>\n batcher.schedule(bytes)\n );\n batcher.cancel();\n uploaded.push(file);\n dispatch(setFileComplete({ index, file }));\n\n // Not awaited: overlaps with the next file's upload and can't fail the batch.\n maybeGenerateMetadata({\n file,\n index,\n uploadId,\n enabled: generateAiMetadata,\n dispatch,\n });\n } catch (err) {\n batcher.cancel();\n\n if (err instanceof UploadAbortedError) {\n // Batch was cancelled — the worker loop checks the signal and stops.\n // cancelUpload (dispatched from the dialog) marks the remaining rows.\n return;\n }\n\n const message = err instanceof Error ? err.message : 'Upload failed';\n dispatch(setFileError({ index, name: fileName, message }));\n }\n };\n\n // Guard non-finite/invalid values (NaN, Infinity, <1): `Math.floor(NaN)`\n // would propagate through Math.max to `Array.from({ length: NaN })` = zero\n // workers, silently uploading nothing. Anything invalid falls back to 1.\n const requested = Number.isFinite(concurrency) ? Math.floor(concurrency) : 1;\n const workerCount = Math.min(Math.max(1, requested), queue.length);\n\n const worker = async () => {\n while (queue.length > 0) {\n if (abortController.signal.aborted) {\n break;\n }\n\n const index = queue.shift();\n if (index === undefined) {\n break;\n }\n\n // eslint-disable-next-line no-await-in-loop\n await uploadOne(index);\n }\n };\n\n await Promise.all(Array.from({ length: workerCount }, () => worker()));\n\n unregisterAbortController(uploadId);\n\n return { data: uploaded };\n};\n\n/* -------------------------------------------------------------------------------------------------\n * URL upload flow (SSE) — kept as-is for this iteration\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * Parses a raw SSE text chunk into event/data pairs.\n *\n * SSE format:\n * event: <eventName>\\n\n * data: <json>\\n\n * \\n\n */\nconst parseSSEEvents = (chunk: string): Array<{ event: string; data: string }> => {\n const events: Array<{ event: string; data: string }> = [];\n const blocks = chunk.split('\\n\\n').filter(Boolean);\n\n for (const block of blocks) {\n let event = '';\n let data = '';\n\n for (const line of block.split('\\n')) {\n if (line.startsWith('event: ')) {\n event = line.slice(7);\n } else if (line.startsWith('data: ')) {\n data = line.slice(6);\n }\n }\n\n if (event && data) {\n events.push({ event, data });\n }\n }\n\n return events;\n};\n\n/**\n * Makes a streaming upload-from-URLs request to the server.\n * Sends URLs as JSON body instead of FormData.\n */\nconst fetchUrlUploadStream = async ({\n token,\n urls,\n folderId,\n signal,\n}: {\n token: string | null | undefined;\n urls: string[];\n folderId: number | null;\n signal: AbortSignal;\n}): Promise<Response> => {\n const backendURL = window.strapi.backendURL;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n if (token) {\n headers.Authorization = `Bearer ${token}`;\n }\n\n return fetch(`${backendURL}/upload/unstable/stream-from-urls`, {\n method: 'POST',\n headers,\n body: JSON.stringify({ urls, folderId }),\n signal,\n });\n};\n\n/**\n * Processes an SSE stream from the URL upload endpoint.\n * Dispatches Redux actions for each file event and returns the final result.\n */\nconst processSSEStream = async ({\n response,\n dispatch,\n uploadId,\n generateAiMetadata,\n}: {\n response: Response;\n dispatch: Dispatch;\n uploadId: number;\n generateAiMetadata: boolean;\n}): Promise<CreateFilesStream.Response | null> => {\n const reader = response.body!.getReader();\n const decoder = new TextDecoder();\n let streamResult: CreateFilesStream.Response | null = null;\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) {\n break;\n }\n\n buffer += decoder.decode(value, { stream: true });\n\n // Process complete SSE events from the buffer\n const lastDoubleNewline = buffer.lastIndexOf('\\n\\n');\n if (lastDoubleNewline === -1) {\n // No complete events yet, keep buffering\n // eslint-disable-next-line no-continue\n continue;\n }\n\n const completePart = buffer.slice(0, lastDoubleNewline + 2);\n buffer = buffer.slice(lastDoubleNewline + 2);\n\n const events = parseSSEEvents(completePart);\n\n for (const { event, data } of events) {\n const parsed = JSON.parse(data);\n const index = parsed.index as number;\n\n switch (event) {\n case 'file:fetching': {\n // URL is being fetched server-side - mark as uploading (processing)\n dispatch(setFileUploading({ name: parsed.url as string, index, size: 0 }));\n break;\n }\n case 'file:uploading': {\n const payload = parsed as CreateFilesStreamEvents.FileUploadingEvent;\n dispatch(setFileUploading({ name: payload.name, index, size: payload.size }));\n break;\n }\n case 'file:complete': {\n const payload = parsed as CreateFilesStreamEvents.FileCompleteEvent;\n dispatch(setFileComplete({ index, file: payload.file }));\n\n // Same fire-and-forget semantics as the file flow.\n maybeGenerateMetadata({\n file: payload.file,\n index,\n uploadId,\n enabled: generateAiMetadata,\n dispatch,\n });\n break;\n }\n case 'file:error': {\n const payload = parsed as CreateFilesStreamEvents.FileErrorEvent;\n dispatch(setFileError({ index, name: payload.name, message: payload.message }));\n break;\n }\n case 'stream:complete': {\n const payload = parsed as CreateFilesStreamEvents.StreamCompleteEvent;\n streamResult = {\n data: payload.data,\n errors: payload.errors,\n };\n break;\n }\n default:\n console.error(`[SSE Upload] unknown event: ${event}`, parsed);\n }\n }\n }\n\n return streamResult;\n};\n\nconst uploadApi = adminApi\n .enhanceEndpoints({\n addTagTypes: ['Asset', 'Folder'],\n })\n .injectEndpoints({\n endpoints: (builder) => ({\n /**\n * Upload files to `/upload/unstable/upload-file`, one request per file,\n * through a worker pool of `concurrency` parallel requests (default 1 =\n * sequential). Real per-file byte progress comes from\n * `XHR.upload.onprogress`.\n */\n uploadFiles: builder.mutation<UploadedFile[], UploadFilesArgs>({\n queryFn: async (\n { formData, totalFiles, concurrency = 1, generateAiMetadata },\n { dispatch, getState }\n ) => {\n const token = (getState() as RootState).admin_app?.token;\n\n // Extract the original files and their per-file fileInfo from the combined FormData.\n const files = formData.getAll('files') as File[];\n const fileInfoJson = formData.get('fileInfo') as string;\n const fileInfoArray = JSON.parse(fileInfoJson) as UploadFileInfo[];\n\n const entries: UploadEntry[] = files.map((file, index) => ({\n file,\n fileInfo: fileInfoArray[index] ?? {\n name: file.name,\n caption: null,\n alternativeText: null,\n folder: null,\n },\n }));\n\n const fileNames = entries.map((entry) => entry.fileInfo.name ?? entry.file.name);\n const fileSizes = entries.map((entry) => entry.file.size);\n\n // Open the progress dialog\n dispatch(openUploadProgress({ totalFiles, fileNames, fileSizes }));\n\n // Get the uploadId from state after dispatching\n const uploadId = (getState() as RootState).uploadProgress.uploadId;\n\n // Store original entries for retry functionality\n registerUploadEntries(uploadId, entries, generateAiMetadata, concurrency);\n\n // One AbortController per batch\n const abortController = new AbortController();\n registerAbortController(uploadId, abortController);\n\n return runUploadPool({\n entries,\n indices: entries.map((_, index) => index),\n token,\n uploadId,\n abortController,\n dispatch,\n concurrency,\n generateAiMetadata,\n });\n },\n invalidatesTags: [{ type: 'Asset', id: 'LIST' }],\n }),\n\n /**\n * Upload a single, already-prepared file WITHOUT opening the global\n * upload-progress dialog. For flows that create one asset programmatically\n * (e.g. crop → \"Save as copy\"), where the bulk-upload progress UI is\n * inappropriate. Same endpoint as `uploadFiles`, minus the progress/retry\n * machinery.\n */\n uploadFileSilently: builder.mutation<UploadedFile, UploadEntry>({\n queryFn: async ({ file, fileInfo }, { getState }) => {\n const token = (getState() as RootState).admin_app?.token;\n const url = `${window.strapi.backendURL}/upload/unstable/upload-file`;\n\n const formData = new FormData();\n formData.append('files', file);\n formData.append('fileInfo', JSON.stringify(fileInfo));\n\n try {\n const uploaded = await uploadFileViaXHR(\n url,\n token,\n formData,\n new AbortController().signal,\n () => {}\n );\n return { data: uploaded };\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Upload failed';\n return { error: { name: 'UnknownError', message } };\n }\n },\n invalidatesTags: [{ type: 'Asset', id: 'LIST' }],\n }),\n\n /**\n * Retry uploading cancelled files.\n * Maps cancelled rows back to their original entries and re-runs only those\n * through the same upload pool with a fresh AbortController.\n */\n retryCancelledFiles: builder.mutation<UploadedFile[], void>({\n queryFn: async (_arg, { dispatch, getState }) => {\n const { uploadId, files: stateFiles } = (getState() as RootState).uploadProgress;\n const token = (getState() as RootState).admin_app?.token;\n\n const cancelledIndices = stateFiles\n .filter((f) => f.status === 'cancelled')\n .map((f) => f.index);\n\n if (cancelledIndices.length === 0) {\n return { error: { name: 'UnknownError', message: 'No cancelled files to retry' } };\n }\n\n const batch = getUploadEntries(uploadId);\n if (!batch) {\n return { error: { name: 'UnknownError', message: 'Original files not found' } };\n }\n\n // Reset cancelled files back to pending\n dispatch(retryCancelledFiles());\n\n // Fresh AbortController for the retry run\n const abortController = new AbortController();\n registerAbortController(uploadId, abortController);\n\n return runUploadPool({\n entries: batch.entries,\n indices: cancelledIndices,\n token,\n uploadId,\n abortController,\n dispatch,\n // Replay the retried rows with the flags the batch was started with.\n concurrency: batch.concurrency,\n generateAiMetadata: batch.generateAiMetadata,\n });\n },\n invalidatesTags: [{ type: 'Asset', id: 'LIST' }],\n }),\n\n /**\n * Upload files from URLs.\n * Sends URLs to the server which fetches and uploads them (SSE flow, unchanged).\n */\n uploadFromUrls: builder.mutation<CreateFilesStream.Response, UploadFromUrlsArgs>({\n queryFn: async ({ urls, folderId, generateAiMetadata }, { dispatch, getState }) => {\n const token = (getState() as RootState).admin_app?.token;\n\n // Extract filenames from URLs for the progress dialog\n const fileNames = urls.map((url) => getFilenameFromUrl(url));\n\n // Open progress dialog with all URLs as pending files\n dispatch(\n openUploadProgress({\n totalFiles: urls.length,\n fileNames,\n })\n );\n\n // Get the uploadId from state after dispatching\n const uploadId = (getState() as RootState).uploadProgress.uploadId;\n\n // Create abort controller for this upload\n const abortController = new AbortController();\n registerAbortController(uploadId, abortController);\n\n try {\n // Send URLs to server for fetching and uploading\n const response = await fetchUrlUploadStream({\n token,\n urls,\n folderId,\n signal: abortController.signal,\n });\n\n if (!response.ok || !response.body) {\n unregisterAbortController(uploadId);\n\n let errorMessage = 'Upload request failed';\n try {\n const errorData = await response.json();\n if (errorData.error?.message) {\n errorMessage = errorData.error.message;\n } else if (errorData.message) {\n errorMessage = errorData.message;\n }\n } catch {\n errorMessage = `Upload failed with status ${response.status}`;\n }\n\n dispatch(setUploadFailed({ message: errorMessage }));\n\n return {\n error: {\n name: 'UnknownError' as const,\n message: errorMessage,\n status: response.status,\n },\n };\n }\n\n // Process SSE stream from server\n const streamResult = await processSSEStream({\n response,\n dispatch,\n uploadId,\n generateAiMetadata,\n });\n\n unregisterAbortController(uploadId);\n\n if (streamResult && streamResult.data.length > 0) {\n return { data: streamResult };\n }\n\n return { data: { data: [], errors: [] } };\n } catch (err) {\n unregisterAbortController(uploadId);\n\n if (err instanceof DOMException && err.name === 'AbortError') {\n return { error: { name: 'UnknownError' as const, message: 'Upload cancelled' } };\n }\n\n const errorMessage = err instanceof Error ? err.message : 'Network error occurred';\n dispatch(setUploadFailed({ message: errorMessage }));\n\n return {\n error: {\n name: 'UnknownError' as const,\n message: errorMessage,\n },\n };\n }\n },\n invalidatesTags: [{ type: 'Asset', id: 'LIST' }],\n }),\n\n /**\n * Generate AI metadata (alt text + caption) for the given assets.\n * Synchronous: resolves once every file has been processed and reports the\n * outcome per file, so non-images and individual failures don't fail the\n * whole batch. Existing alt text and captions are never overwritten.\n *\n * Lives here rather than in `assets.ts` because the upload flows dispatch it\n * directly via `initiate()` after each file completes, and `assets.ts` already\n * imports from this module — defining it there would be a circular import.\n * Re-exported from `assets.ts` for the components that consume the hook.\n */\n generateAiMetadata: builder.mutation<\n UnstableGenerateAIMetadata.Response['data'],\n { fileIds: number[] }\n >({\n query: ({ fileIds }) => ({\n url: '/upload/unstable/generate-ai-metadata',\n method: 'POST',\n data: { fileIds },\n }),\n transformResponse: (response: { data: UnstableGenerateAIMetadata.Response['data'] }) =>\n response.data,\n invalidatesTags: (_result, _error, { fileIds }) => [\n ...fileIds.map((id) => ({ type: 'Asset' as const, id })),\n { type: 'Asset' as const, id: 'LIST' },\n ],\n }),\n }),\n });\n\nexport const {\n useUploadFilesMutation,\n useUploadFileSilentlyMutation,\n useRetryCancelledFilesMutation,\n useUploadFromUrlsMutation,\n useGenerateAiMetadataMutation,\n} = uploadApi;\nexport { uploadApi };\n"],"names":["uploadRegistry","Map","registerUploadEntries","uploadId","entries","generateAiMetadata","concurrency","set","getUploadEntries","get","abortControllers","registerAbortController","controller","unregisterAbortController","delete","abortUpload","abort","METADATA_STATUS_BY_RESULT","success","skipped","error","maybeGenerateMetadata","file","index","enabled","dispatch","id","setFileMetadataGenerating","promise","uploadApi","endpoints","initiate","fileIds","unwrap","then","results","result","find","r","setFileMetadataResult","status","catch","runUploadPool","indices","token","abortController","url","window","strapi","backendURL","uploaded","queue","uploadOne","entry","fileName","fileInfo","name","setFileUploading","size","formData","FormData","append","JSON","stringify","batcher","createRafBatcher","bytes","setFileProgress","uploadFileViaXHR","signal","schedule","cancel","push","setFileComplete","err","UploadAbortedError","message","Error","setFileError","requested","Number","isFinite","Math","floor","workerCount","min","max","length","worker","aborted","shift","undefined","Promise","all","Array","from","data","parseSSEEvents","chunk","events","blocks","split","filter","Boolean","block","event","line","startsWith","slice","fetchUrlUploadStream","urls","folderId","headers","Authorization","fetch","method","body","processSSEStream","response","reader","getReader","decoder","TextDecoder","streamResult","buffer","done","value","read","decode","stream","lastDoubleNewline","lastIndexOf","completePart","parsed","parse","payload","errors","console","adminApi","enhanceEndpoints","addTagTypes","injectEndpoints","builder","uploadFiles","mutation","queryFn","totalFiles","getState","admin_app","files","getAll","fileInfoJson","fileInfoArray","map","caption","alternativeText","folder","fileNames","fileSizes","openUploadProgress","uploadProgress","AbortController","_","invalidatesTags","type","uploadFileSilently","retryCancelledFiles","_arg","stateFiles","cancelledIndices","f","batch","uploadFromUrls","getFilenameFromUrl","ok","errorMessage","errorData","json","setUploadFailed","DOMException","query","transformResponse","_result","_error","useUploadFilesMutation","useUploadFileSilentlyMutation","useRetryCancelledFilesMutation","useUploadFromUrlsMutation","useGenerateAiMetadataMutation"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"api.js","sources":["../../../../admin/src/future/services/api.ts"],"sourcesContent":["import { Dispatch } from '@reduxjs/toolkit';\nimport { adminApi } from '@strapi/admin/strapi-admin';\n\nimport {\n openUploadProgress,\n setFileUploading,\n setFileProgress,\n setFileComplete,\n setFileError,\n setFileMetadataGenerating,\n setFileMetadataResult,\n setUploadFailed,\n retryCancelledFiles,\n} from '../store/uploadProgress';\nimport { createRafBatcher } from '../utils/createRafBatcher';\nimport { getFilenameFromUrl } from '../utils/files';\n\nimport { uploadFileViaXHR, UploadAbortedError } from './uploadFileViaXHR';\n\nimport type {\n CreateFilesStream,\n CreateFilesStreamEvents,\n File as UploadedFile,\n GenerateAIMetadata,\n UploadFileInfo,\n} from '../../../../shared/contracts/files';\nimport type { FileMetadataResultStatus } from '../store/uploadProgress';\n\ninterface UploadFilesArgs {\n formData: FormData;\n totalFiles: number;\n /**\n * How many files to upload in parallel — the `concurrentUploadRequests`\n * settings value. Defaults to 1 (sequential).\n */\n concurrency?: number;\n /** Whether AI metadata generation is enabled (EE AI available + `settings.aiMetadata`). */\n generateAiMetadata: boolean;\n}\n\ninterface UploadFromUrlsArgs {\n urls: string[];\n folderId: number | null;\n generateAiMetadata: boolean;\n}\n\ninterface RootState {\n admin_app: {\n token?: string | null;\n };\n uploadProgress: {\n uploadId: number;\n files: Array<{\n index: number;\n name: string;\n size: number;\n status: 'pending' | 'uploading' | 'complete' | 'error' | 'cancelled';\n }>;\n };\n}\n\n/**\n * A single file plus the `fileInfo` it was queued with.\n * Retained in {@link uploadRegistry} so cancelled files can be retried without\n * the user re-selecting them. `File`/`AbortController` are non-serializable, so\n * they live here rather than in Redux.\n */\ninterface UploadEntry {\n file: File;\n fileInfo: UploadFileInfo;\n}\n\n/**\n * Everything a batch needs to be replayed on retry: the original entries plus the\n * flags it was started with (AI-metadata and upload concurrency). These live here\n * rather than in Redux because `retryCancelledFiles` takes no args and the page\n * that owns `useAIAvailability` / the settings value is not involved in the retry.\n */\ninterface UploadBatch {\n entries: UploadEntry[];\n generateAiMetadata: boolean;\n concurrency: number;\n}\n\n/**\n * Stores the original upload batch (keyed by uploadId) to enable retry.\n */\nconst uploadRegistry = new Map<number, UploadBatch>();\n\nconst registerUploadEntries = (\n uploadId: number,\n entries: UploadEntry[],\n generateAiMetadata: boolean,\n concurrency: number\n) => {\n uploadRegistry.set(uploadId, { entries, generateAiMetadata, concurrency });\n};\n\nconst getUploadEntries = (uploadId: number): UploadBatch | undefined => {\n return uploadRegistry.get(uploadId);\n};\n\n/**\n * Manages abort controllers for in-flight uploads.\n *\n * Design decision: Uses a Map to track uploads by their unique uploadId.\n * Redux state cannot store function references (abort controllers), RTK Query's\n * signal is only accessible within the queryFn, and the upload is triggered in\n * AssetsPage but cancelled from UploadProgressDialog.\n */\nconst abortControllers = new Map<number, AbortController>();\n\nconst registerAbortController = (uploadId: number, controller: AbortController) => {\n abortControllers.set(uploadId, controller);\n};\n\nconst unregisterAbortController = (uploadId: number) => {\n abortControllers.delete(uploadId);\n};\n\n/**\n * Aborts an upload by its uploadId.\n * Called from the UploadProgressDialog when the user clicks cancel or close.\n */\nexport const abortUpload = (uploadId: number) => {\n const controller = abortControllers.get(uploadId);\n if (controller) {\n controller.abort();\n unregisterAbortController(uploadId);\n }\n};\n\n/**\n * Error shape returned by upload operations.\n * Matches RTK Query's expected return type for queryFn.\n */\ninterface UploadError {\n name: 'UnknownError';\n message: string;\n status?: number;\n}\n\n/**\n * The store's dispatch also accepts thunks, which is what RTK Query's\n * `endpoint.initiate(...)` returns — the plain `Dispatch` action type can't express that.\n */\ntype AppDispatch = Dispatch &\n (<T>(thunk: T) => T extends (...args: never[]) => infer R ? R : never);\n\ntype UploadPoolResult =\n | { data: UploadedFile[]; error?: undefined }\n | { error: UploadError; data?: undefined };\n\n/** Maps a server per-file outcome onto the row's terminal metadata status. */\nconst METADATA_STATUS_BY_RESULT: Record<GenerateAIMetadata.FileStatus, FileMetadataResultStatus> = {\n success: 'generated',\n skipped: 'skipped',\n error: 'failed',\n};\n\n/**\n * Kicks off AI metadata generation for a freshly uploaded file.\n *\n * Deliberately fire-and-forget — the caller must NOT await it:\n * - generation for file N overlaps the upload of file N+1;\n * - a generation failure can never affect the upload result (the upload already\n * succeeded), which is why the promise is fully swallowed here.\n *\n * Every uploaded file is sent, including non-images: the server already classifies\n * them (`ai-metadata.generateForFiles` returns `skipped` for anything whose mime\n * isn't `image/*`) and duplicating that rule here would let the two drift apart.\n * The upshot is that a non-image now reports \"Metadata generation skipped\" rather\n * than silently showing no metadata state at all.\n */\nexport const maybeGenerateMetadata = ({\n file,\n index,\n uploadId,\n enabled,\n dispatch,\n}: {\n file: UploadedFile;\n index: number;\n uploadId: number;\n enabled: boolean;\n dispatch: Dispatch;\n}): void => {\n if (!enabled || typeof file.id !== 'number') {\n return;\n }\n\n dispatch(setFileMetadataGenerating({ index, uploadId }));\n\n // `uploadApi` is declared below but only read at call time, long after the module\n // has finished evaluating.\n const promise = (dispatch as AppDispatch)(\n uploadApi.endpoints.generateAiMetadata.initiate({ fileIds: [file.id] })\n );\n\n promise\n .unwrap()\n .then((results) => {\n const result = results?.find((r) => r.id === file.id) ?? results?.[0];\n dispatch(\n setFileMetadataResult({\n index,\n uploadId,\n status: result ? METADATA_STATUS_BY_RESULT[result.status] : 'failed',\n })\n );\n })\n .catch(() => {\n dispatch(setFileMetadataResult({ index, uploadId, status: 'failed' }));\n });\n};\n\n/**\n * Uploads the given entry indices one at a time through the single-file endpoint.\n *\n * For each file: dispatches \"uploading\", wires `XHR.upload.onprogress` through a\n * per-frame batcher to `setFileProgress`, awaits the XHR, then dispatches\n * \"complete\" or \"error\". Each file is wrapped in its own try/catch so one failure\n * does not stop the batch. An abort stops the loop without starting further files.\n */\nconst runUploadPool = async ({\n entries,\n indices,\n token,\n uploadId,\n abortController,\n dispatch,\n concurrency = 1,\n generateAiMetadata,\n}: {\n entries: UploadEntry[];\n indices: number[];\n token: string | null | undefined;\n uploadId: number;\n abortController: AbortController;\n dispatch: Dispatch;\n /** Parallel workers pulling from the queue. 1 (the default) = sequential. */\n concurrency?: number;\n generateAiMetadata: boolean;\n}): Promise<UploadPoolResult> => {\n const url = `${window.strapi.backendURL}/upload/files`;\n const uploaded: UploadedFile[] = [];\n\n // Shared queue: each worker shifts the next index when it frees up, so N\n // files are in flight at any moment (not N-sized waves). With concurrency 1\n // this degenerates to the original strictly sequential loop.\n const queue = [...indices];\n\n const uploadOne = async (index: number) => {\n const entry = entries[index];\n if (!entry) {\n return;\n }\n\n const fileName = entry.fileInfo?.name ?? entry.file.name;\n\n dispatch(setFileUploading({ name: fileName, index, size: entry.file.size }));\n\n const formData = new FormData();\n formData.append('files', entry.file);\n formData.append('fileInfo', JSON.stringify(entry.fileInfo));\n\n // Coalesce high-frequency progress events into one dispatch per frame.\n const batcher = createRafBatcher<number>((bytes) => {\n dispatch(setFileProgress({ index, bytes }));\n });\n\n try {\n const file = await uploadFileViaXHR(url, token, formData, abortController.signal, (bytes) =>\n batcher.schedule(bytes)\n );\n batcher.cancel();\n uploaded.push(file);\n dispatch(setFileComplete({ index, file }));\n\n // Not awaited: overlaps with the next file's upload and can't fail the batch.\n maybeGenerateMetadata({\n file,\n index,\n uploadId,\n enabled: generateAiMetadata,\n dispatch,\n });\n } catch (err) {\n batcher.cancel();\n\n if (err instanceof UploadAbortedError) {\n // Batch was cancelled — the worker loop checks the signal and stops.\n // cancelUpload (dispatched from the dialog) marks the remaining rows.\n return;\n }\n\n const message = err instanceof Error ? err.message : 'Upload failed';\n dispatch(setFileError({ index, name: fileName, message }));\n }\n };\n\n // Guard non-finite/invalid values (NaN, Infinity, <1): `Math.floor(NaN)`\n // would propagate through Math.max to `Array.from({ length: NaN })` = zero\n // workers, silently uploading nothing. Anything invalid falls back to 1.\n const requested = Number.isFinite(concurrency) ? Math.floor(concurrency) : 1;\n const workerCount = Math.min(Math.max(1, requested), queue.length);\n\n const worker = async () => {\n while (queue.length > 0) {\n if (abortController.signal.aborted) {\n break;\n }\n\n const index = queue.shift();\n if (index === undefined) {\n break;\n }\n\n // eslint-disable-next-line no-await-in-loop\n await uploadOne(index);\n }\n };\n\n await Promise.all(Array.from({ length: workerCount }, () => worker()));\n\n unregisterAbortController(uploadId);\n\n return { data: uploaded };\n};\n\n/* -------------------------------------------------------------------------------------------------\n * URL upload flow (SSE) — kept as-is for this iteration\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * Parses a raw SSE text chunk into event/data pairs.\n *\n * SSE format:\n * event: <eventName>\\n\n * data: <json>\\n\n * \\n\n */\nconst parseSSEEvents = (chunk: string): Array<{ event: string; data: string }> => {\n const events: Array<{ event: string; data: string }> = [];\n const blocks = chunk.split('\\n\\n').filter(Boolean);\n\n for (const block of blocks) {\n let event = '';\n let data = '';\n\n for (const line of block.split('\\n')) {\n if (line.startsWith('event: ')) {\n event = line.slice(7);\n } else if (line.startsWith('data: ')) {\n data = line.slice(6);\n }\n }\n\n if (event && data) {\n events.push({ event, data });\n }\n }\n\n return events;\n};\n\n/**\n * Makes a streaming upload-from-URLs request to the server.\n * Sends URLs as JSON body instead of FormData.\n */\nconst fetchUrlUploadStream = async ({\n token,\n urls,\n folderId,\n signal,\n}: {\n token: string | null | undefined;\n urls: string[];\n folderId: number | null;\n signal: AbortSignal;\n}): Promise<Response> => {\n const backendURL = window.strapi.backendURL;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n if (token) {\n headers.Authorization = `Bearer ${token}`;\n }\n\n return fetch(`${backendURL}/upload/actions/upload-from-urls`, {\n method: 'POST',\n headers,\n body: JSON.stringify({ urls, folderId }),\n signal,\n });\n};\n\n/**\n * Processes an SSE stream from the URL upload endpoint.\n * Dispatches Redux actions for each file event and returns the final result.\n */\nconst processSSEStream = async ({\n response,\n dispatch,\n uploadId,\n generateAiMetadata,\n}: {\n response: Response;\n dispatch: Dispatch;\n uploadId: number;\n generateAiMetadata: boolean;\n}): Promise<CreateFilesStream.Response | null> => {\n const reader = response.body!.getReader();\n const decoder = new TextDecoder();\n let streamResult: CreateFilesStream.Response | null = null;\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) {\n break;\n }\n\n buffer += decoder.decode(value, { stream: true });\n\n // Process complete SSE events from the buffer\n const lastDoubleNewline = buffer.lastIndexOf('\\n\\n');\n if (lastDoubleNewline === -1) {\n // No complete events yet, keep buffering\n // eslint-disable-next-line no-continue\n continue;\n }\n\n const completePart = buffer.slice(0, lastDoubleNewline + 2);\n buffer = buffer.slice(lastDoubleNewline + 2);\n\n const events = parseSSEEvents(completePart);\n\n for (const { event, data } of events) {\n const parsed = JSON.parse(data);\n const index = parsed.index as number;\n\n switch (event) {\n case 'file:fetching': {\n // URL is being fetched server-side - mark as uploading (processing)\n dispatch(setFileUploading({ name: parsed.url as string, index, size: 0 }));\n break;\n }\n case 'file:uploading': {\n const payload = parsed as CreateFilesStreamEvents.FileUploadingEvent;\n dispatch(setFileUploading({ name: payload.name, index, size: payload.size }));\n break;\n }\n case 'file:complete': {\n const payload = parsed as CreateFilesStreamEvents.FileCompleteEvent;\n dispatch(setFileComplete({ index, file: payload.file }));\n\n // Same fire-and-forget semantics as the file flow.\n maybeGenerateMetadata({\n file: payload.file,\n index,\n uploadId,\n enabled: generateAiMetadata,\n dispatch,\n });\n break;\n }\n case 'file:error': {\n const payload = parsed as CreateFilesStreamEvents.FileErrorEvent;\n dispatch(setFileError({ index, name: payload.name, message: payload.message }));\n break;\n }\n case 'stream:complete': {\n const payload = parsed as CreateFilesStreamEvents.StreamCompleteEvent;\n streamResult = {\n data: payload.data,\n errors: payload.errors,\n };\n break;\n }\n default:\n console.error(`[SSE Upload] unknown event: ${event}`, parsed);\n }\n }\n }\n\n return streamResult;\n};\n\nconst uploadApi = adminApi\n .enhanceEndpoints({\n addTagTypes: ['Asset', 'Folder'],\n })\n .injectEndpoints({\n endpoints: (builder) => ({\n /**\n * Upload files to `/upload/files`, one request per file, through a worker\n * pool of `concurrency` parallel requests (default 1 = sequential). Real\n * per-file byte progress comes from `XHR.upload.onprogress`.\n */\n uploadFiles: builder.mutation<UploadedFile[], UploadFilesArgs>({\n queryFn: async (\n { formData, totalFiles, concurrency = 1, generateAiMetadata },\n { dispatch, getState }\n ) => {\n const token = (getState() as RootState).admin_app?.token;\n\n // Extract the original files and their per-file fileInfo from the combined FormData.\n const files = formData.getAll('files') as File[];\n const fileInfoJson = formData.get('fileInfo') as string;\n const fileInfoArray = JSON.parse(fileInfoJson) as UploadFileInfo[];\n\n const entries: UploadEntry[] = files.map((file, index) => ({\n file,\n fileInfo: fileInfoArray[index] ?? {\n name: file.name,\n caption: null,\n alternativeText: null,\n folder: null,\n },\n }));\n\n const fileNames = entries.map((entry) => entry.fileInfo.name ?? entry.file.name);\n const fileSizes = entries.map((entry) => entry.file.size);\n\n // Open the progress dialog\n dispatch(openUploadProgress({ totalFiles, fileNames, fileSizes }));\n\n // Get the uploadId from state after dispatching\n const uploadId = (getState() as RootState).uploadProgress.uploadId;\n\n // Store original entries for retry functionality\n registerUploadEntries(uploadId, entries, generateAiMetadata, concurrency);\n\n // One AbortController per batch\n const abortController = new AbortController();\n registerAbortController(uploadId, abortController);\n\n return runUploadPool({\n entries,\n indices: entries.map((_, index) => index),\n token,\n uploadId,\n abortController,\n dispatch,\n concurrency,\n generateAiMetadata,\n });\n },\n // `Folder, LIST` refreshes the folder header count, which changes when\n // files are added to it.\n invalidatesTags: [\n { type: 'Asset', id: 'LIST' },\n { type: 'Folder', id: 'LIST' },\n ],\n }),\n\n /**\n * Upload a single, already-prepared file WITHOUT opening the global\n * upload-progress dialog. For flows that create one asset programmatically\n * (e.g. crop → \"Save as copy\"), where the bulk-upload progress UI is\n * inappropriate. Same endpoint as `uploadFiles`, minus the progress/retry\n * machinery.\n */\n uploadFileSilently: builder.mutation<UploadedFile, UploadEntry>({\n queryFn: async ({ file, fileInfo }, { getState }) => {\n const token = (getState() as RootState).admin_app?.token;\n const url = `${window.strapi.backendURL}/upload/files`;\n\n const formData = new FormData();\n formData.append('files', file);\n formData.append('fileInfo', JSON.stringify(fileInfo));\n\n try {\n const uploaded = await uploadFileViaXHR(\n url,\n token,\n formData,\n new AbortController().signal,\n () => {}\n );\n return { data: uploaded };\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Upload failed';\n return { error: { name: 'UnknownError', message } };\n }\n },\n // `Folder, LIST` refreshes the folder header count, which changes when\n // files are added to it.\n invalidatesTags: [\n { type: 'Asset', id: 'LIST' },\n { type: 'Folder', id: 'LIST' },\n ],\n }),\n\n /**\n * Retry uploading cancelled files.\n * Maps cancelled rows back to their original entries and re-runs only those\n * through the same upload pool with a fresh AbortController.\n */\n retryCancelledFiles: builder.mutation<UploadedFile[], void>({\n queryFn: async (_arg, { dispatch, getState }) => {\n const { uploadId, files: stateFiles } = (getState() as RootState).uploadProgress;\n const token = (getState() as RootState).admin_app?.token;\n\n const cancelledIndices = stateFiles\n .filter((f) => f.status === 'cancelled')\n .map((f) => f.index);\n\n if (cancelledIndices.length === 0) {\n return { error: { name: 'UnknownError', message: 'No cancelled files to retry' } };\n }\n\n const batch = getUploadEntries(uploadId);\n if (!batch) {\n return { error: { name: 'UnknownError', message: 'Original files not found' } };\n }\n\n // Reset cancelled files back to pending\n dispatch(retryCancelledFiles());\n\n // Fresh AbortController for the retry run\n const abortController = new AbortController();\n registerAbortController(uploadId, abortController);\n\n return runUploadPool({\n entries: batch.entries,\n indices: cancelledIndices,\n token,\n uploadId,\n abortController,\n dispatch,\n // Replay the retried rows with the flags the batch was started with.\n concurrency: batch.concurrency,\n generateAiMetadata: batch.generateAiMetadata,\n });\n },\n // `Folder, LIST` refreshes the folder header count, which changes when\n // files are added to it.\n invalidatesTags: [\n { type: 'Asset', id: 'LIST' },\n { type: 'Folder', id: 'LIST' },\n ],\n }),\n\n /**\n * Upload files from URLs.\n * Sends URLs to the server which fetches and uploads them (SSE flow, unchanged).\n */\n uploadFromUrls: builder.mutation<CreateFilesStream.Response, UploadFromUrlsArgs>({\n queryFn: async ({ urls, folderId, generateAiMetadata }, { dispatch, getState }) => {\n const token = (getState() as RootState).admin_app?.token;\n\n // Extract filenames from URLs for the progress dialog\n const fileNames = urls.map((url) => getFilenameFromUrl(url));\n\n // Open progress dialog with all URLs as pending files\n dispatch(\n openUploadProgress({\n totalFiles: urls.length,\n fileNames,\n })\n );\n\n // Get the uploadId from state after dispatching\n const uploadId = (getState() as RootState).uploadProgress.uploadId;\n\n // Create abort controller for this upload\n const abortController = new AbortController();\n registerAbortController(uploadId, abortController);\n\n try {\n // Send URLs to server for fetching and uploading\n const response = await fetchUrlUploadStream({\n token,\n urls,\n folderId,\n signal: abortController.signal,\n });\n\n if (!response.ok || !response.body) {\n unregisterAbortController(uploadId);\n\n let errorMessage = 'Upload request failed';\n try {\n const errorData = await response.json();\n if (errorData.error?.message) {\n errorMessage = errorData.error.message;\n } else if (errorData.message) {\n errorMessage = errorData.message;\n }\n } catch {\n errorMessage = `Upload failed with status ${response.status}`;\n }\n\n dispatch(setUploadFailed({ message: errorMessage }));\n\n return {\n error: {\n name: 'UnknownError' as const,\n message: errorMessage,\n status: response.status,\n },\n };\n }\n\n // Process SSE stream from server\n const streamResult = await processSSEStream({\n response,\n dispatch,\n uploadId,\n generateAiMetadata,\n });\n\n unregisterAbortController(uploadId);\n\n if (streamResult && streamResult.data.length > 0) {\n return { data: streamResult };\n }\n\n return { data: { data: [], errors: [] } };\n } catch (err) {\n unregisterAbortController(uploadId);\n\n if (err instanceof DOMException && err.name === 'AbortError') {\n return { error: { name: 'UnknownError' as const, message: 'Upload cancelled' } };\n }\n\n const errorMessage = err instanceof Error ? err.message : 'Network error occurred';\n dispatch(setUploadFailed({ message: errorMessage }));\n\n return {\n error: {\n name: 'UnknownError' as const,\n message: errorMessage,\n },\n };\n }\n },\n // `Folder, LIST` refreshes the folder header count, which changes when\n // files are added to it.\n invalidatesTags: [\n { type: 'Asset', id: 'LIST' },\n { type: 'Folder', id: 'LIST' },\n ],\n }),\n\n /**\n * Generate AI metadata (alt text + caption) for the given assets.\n * Synchronous: resolves once every file has been processed and reports the\n * outcome per file, so non-images and individual failures don't fail the\n * whole batch. Existing alt text and captions are never overwritten.\n *\n * Lives here rather than in `assets.ts` because the upload flows dispatch it\n * directly via `initiate()` after each file completes, and `assets.ts` already\n * imports from this module — defining it there would be a circular import.\n * Re-exported from `assets.ts` for the components that consume the hook.\n */\n generateAiMetadata: builder.mutation<\n GenerateAIMetadata.Response['data'],\n { fileIds: number[] }\n >({\n query: ({ fileIds }) => ({\n url: '/upload/actions/generate-ai-metadata',\n method: 'POST',\n data: { fileIds },\n }),\n transformResponse: (response: { data: GenerateAIMetadata.Response['data'] }) =>\n response.data,\n invalidatesTags: (_result, _error, { fileIds }) => [\n ...fileIds.map((id) => ({ type: 'Asset' as const, id })),\n { type: 'Asset' as const, id: 'LIST' },\n ],\n }),\n }),\n });\n\nexport const {\n useUploadFilesMutation,\n useUploadFileSilentlyMutation,\n useRetryCancelledFilesMutation,\n useUploadFromUrlsMutation,\n useGenerateAiMetadataMutation,\n} = uploadApi;\nexport { uploadApi };\n"],"names":["uploadRegistry","Map","registerUploadEntries","uploadId","entries","generateAiMetadata","concurrency","set","getUploadEntries","get","abortControllers","registerAbortController","controller","unregisterAbortController","delete","abortUpload","abort","METADATA_STATUS_BY_RESULT","success","skipped","error","maybeGenerateMetadata","file","index","enabled","dispatch","id","setFileMetadataGenerating","promise","uploadApi","endpoints","initiate","fileIds","unwrap","then","results","result","find","r","setFileMetadataResult","status","catch","runUploadPool","indices","token","abortController","url","window","strapi","backendURL","uploaded","queue","uploadOne","entry","fileName","fileInfo","name","setFileUploading","size","formData","FormData","append","JSON","stringify","batcher","createRafBatcher","bytes","setFileProgress","uploadFileViaXHR","signal","schedule","cancel","push","setFileComplete","err","UploadAbortedError","message","Error","setFileError","requested","Number","isFinite","Math","floor","workerCount","min","max","length","worker","aborted","shift","undefined","Promise","all","Array","from","data","parseSSEEvents","chunk","events","blocks","split","filter","Boolean","block","event","line","startsWith","slice","fetchUrlUploadStream","urls","folderId","headers","Authorization","fetch","method","body","processSSEStream","response","reader","getReader","decoder","TextDecoder","streamResult","buffer","done","value","read","decode","stream","lastDoubleNewline","lastIndexOf","completePart","parsed","parse","payload","errors","console","adminApi","enhanceEndpoints","addTagTypes","injectEndpoints","builder","uploadFiles","mutation","queryFn","totalFiles","getState","admin_app","files","getAll","fileInfoJson","fileInfoArray","map","caption","alternativeText","folder","fileNames","fileSizes","openUploadProgress","uploadProgress","AbortController","_","invalidatesTags","type","uploadFileSilently","retryCancelledFiles","_arg","stateFiles","cancelledIndices","f","batch","uploadFromUrls","getFilenameFromUrl","ok","errorMessage","errorData","json","setUploadFailed","DOMException","query","transformResponse","_result","_error","useUploadFilesMutation","useUploadFileSilentlyMutation","useRetryCancelledFilesMutation","useUploadFromUrlsMutation","useGenerateAiMetadataMutation"],"mappings":"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"}
|
|
@@ -97,7 +97,7 @@ const unregisterAbortController = (uploadId)=>{
|
|
|
97
97
|
* "complete" or "error". Each file is wrapped in its own try/catch so one failure
|
|
98
98
|
* does not stop the batch. An abort stops the loop without starting further files.
|
|
99
99
|
*/ const runUploadPool = async ({ entries, indices, token, uploadId, abortController, dispatch, concurrency = 1, generateAiMetadata })=>{
|
|
100
|
-
const url = `${window.strapi.backendURL}/upload/
|
|
100
|
+
const url = `${window.strapi.backendURL}/upload/files`;
|
|
101
101
|
const uploaded = [];
|
|
102
102
|
// Shared queue: each worker shifts the next index when it frees up, so N
|
|
103
103
|
// files are in flight at any moment (not N-sized waves). With concurrency 1
|
|
@@ -225,7 +225,7 @@ const unregisterAbortController = (uploadId)=>{
|
|
|
225
225
|
if (token) {
|
|
226
226
|
headers.Authorization = `Bearer ${token}`;
|
|
227
227
|
}
|
|
228
|
-
return fetch(`${backendURL}/upload/
|
|
228
|
+
return fetch(`${backendURL}/upload/actions/upload-from-urls`, {
|
|
229
229
|
method: 'POST',
|
|
230
230
|
headers,
|
|
231
231
|
body: JSON.stringify({
|
|
@@ -334,10 +334,9 @@ const uploadApi = adminApi.enhanceEndpoints({
|
|
|
334
334
|
}).injectEndpoints({
|
|
335
335
|
endpoints: (builder)=>({
|
|
336
336
|
/**
|
|
337
|
-
* Upload files to `/upload/
|
|
338
|
-
*
|
|
339
|
-
*
|
|
340
|
-
* `XHR.upload.onprogress`.
|
|
337
|
+
* Upload files to `/upload/files`, one request per file, through a worker
|
|
338
|
+
* pool of `concurrency` parallel requests (default 1 = sequential). Real
|
|
339
|
+
* per-file byte progress comes from `XHR.upload.onprogress`.
|
|
341
340
|
*/ uploadFiles: builder.mutation({
|
|
342
341
|
queryFn: async ({ formData, totalFiles, concurrency = 1, generateAiMetadata }, { dispatch, getState })=>{
|
|
343
342
|
const token = getState().admin_app?.token;
|
|
@@ -380,10 +379,16 @@ const uploadApi = adminApi.enhanceEndpoints({
|
|
|
380
379
|
generateAiMetadata
|
|
381
380
|
});
|
|
382
381
|
},
|
|
382
|
+
// `Folder, LIST` refreshes the folder header count, which changes when
|
|
383
|
+
// files are added to it.
|
|
383
384
|
invalidatesTags: [
|
|
384
385
|
{
|
|
385
386
|
type: 'Asset',
|
|
386
387
|
id: 'LIST'
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
type: 'Folder',
|
|
391
|
+
id: 'LIST'
|
|
387
392
|
}
|
|
388
393
|
]
|
|
389
394
|
}),
|
|
@@ -396,7 +401,7 @@ const uploadApi = adminApi.enhanceEndpoints({
|
|
|
396
401
|
*/ uploadFileSilently: builder.mutation({
|
|
397
402
|
queryFn: async ({ file, fileInfo }, { getState })=>{
|
|
398
403
|
const token = getState().admin_app?.token;
|
|
399
|
-
const url = `${window.strapi.backendURL}/upload/
|
|
404
|
+
const url = `${window.strapi.backendURL}/upload/files`;
|
|
400
405
|
const formData = new FormData();
|
|
401
406
|
formData.append('files', file);
|
|
402
407
|
formData.append('fileInfo', JSON.stringify(fileInfo));
|
|
@@ -415,10 +420,16 @@ const uploadApi = adminApi.enhanceEndpoints({
|
|
|
415
420
|
};
|
|
416
421
|
}
|
|
417
422
|
},
|
|
423
|
+
// `Folder, LIST` refreshes the folder header count, which changes when
|
|
424
|
+
// files are added to it.
|
|
418
425
|
invalidatesTags: [
|
|
419
426
|
{
|
|
420
427
|
type: 'Asset',
|
|
421
428
|
id: 'LIST'
|
|
429
|
+
},
|
|
430
|
+
{
|
|
431
|
+
type: 'Folder',
|
|
432
|
+
id: 'LIST'
|
|
422
433
|
}
|
|
423
434
|
]
|
|
424
435
|
}),
|
|
@@ -465,10 +476,16 @@ const uploadApi = adminApi.enhanceEndpoints({
|
|
|
465
476
|
generateAiMetadata: batch.generateAiMetadata
|
|
466
477
|
});
|
|
467
478
|
},
|
|
479
|
+
// `Folder, LIST` refreshes the folder header count, which changes when
|
|
480
|
+
// files are added to it.
|
|
468
481
|
invalidatesTags: [
|
|
469
482
|
{
|
|
470
483
|
type: 'Asset',
|
|
471
484
|
id: 'LIST'
|
|
485
|
+
},
|
|
486
|
+
{
|
|
487
|
+
type: 'Folder',
|
|
488
|
+
id: 'LIST'
|
|
472
489
|
}
|
|
473
490
|
]
|
|
474
491
|
}),
|
|
@@ -563,10 +580,16 @@ const uploadApi = adminApi.enhanceEndpoints({
|
|
|
563
580
|
};
|
|
564
581
|
}
|
|
565
582
|
},
|
|
583
|
+
// `Folder, LIST` refreshes the folder header count, which changes when
|
|
584
|
+
// files are added to it.
|
|
566
585
|
invalidatesTags: [
|
|
567
586
|
{
|
|
568
587
|
type: 'Asset',
|
|
569
588
|
id: 'LIST'
|
|
589
|
+
},
|
|
590
|
+
{
|
|
591
|
+
type: 'Folder',
|
|
592
|
+
id: 'LIST'
|
|
570
593
|
}
|
|
571
594
|
]
|
|
572
595
|
}),
|
|
@@ -582,7 +605,7 @@ const uploadApi = adminApi.enhanceEndpoints({
|
|
|
582
605
|
* Re-exported from `assets.ts` for the components that consume the hook.
|
|
583
606
|
*/ generateAiMetadata: builder.mutation({
|
|
584
607
|
query: ({ fileIds })=>({
|
|
585
|
-
url: '/upload/
|
|
608
|
+
url: '/upload/actions/generate-ai-metadata',
|
|
586
609
|
method: 'POST',
|
|
587
610
|
data: {
|
|
588
611
|
fileIds
|