@strapi/upload 5.51.0 → 5.51.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/pages/Assets/AssetsPage.js +198 -129
- package/dist/admin/future/pages/Assets/AssetsPage.js.map +1 -1
- package/dist/admin/future/pages/Assets/AssetsPage.mjs +199 -130
- package/dist/admin/future/pages/Assets/AssetsPage.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsGrid.js +158 -19
- package/dist/admin/future/pages/Assets/components/AssetsGrid.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs +159 -20
- package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsTable.js +212 -37
- package/dist/admin/future/pages/Assets/components/AssetsTable.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsTable.mjs +213 -38
- package/dist/admin/future/pages/Assets/components/AssetsTable.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/BulkActionsBar.js +252 -0
- package/dist/admin/future/pages/Assets/components/BulkActionsBar.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/BulkActionsBar.mjs +250 -0
- package/dist/admin/future/pages/Assets/components/BulkActionsBar.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/components/BulkMoveDialog.js +209 -0
- package/dist/admin/future/pages/Assets/components/BulkMoveDialog.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/BulkMoveDialog.mjs +207 -0
- package/dist/admin/future/pages/Assets/components/BulkMoveDialog.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.js +111 -36
- package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.mjs +113 -38
- package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/Dnd/DragOverlayChip.js +120 -13
- package/dist/admin/future/pages/Assets/components/Dnd/DragOverlayChip.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/Dnd/DragOverlayChip.mjs +120 -13
- package/dist/admin/future/pages/Assets/components/Dnd/DragOverlayChip.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/Dnd/buildDragSet.js +71 -0
- package/dist/admin/future/pages/Assets/components/Dnd/buildDragSet.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/Dnd/buildDragSet.mjs +69 -0
- package/dist/admin/future/pages/Assets/components/Dnd/buildDragSet.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/components/Dnd/computeValidDropTargets.js +34 -0
- package/dist/admin/future/pages/Assets/components/Dnd/computeValidDropTargets.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/Dnd/computeValidDropTargets.mjs +32 -0
- package/dist/admin/future/pages/Assets/components/Dnd/computeValidDropTargets.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/components/Dnd/dndIds.js +15 -0
- package/dist/admin/future/pages/Assets/components/Dnd/dndIds.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/Dnd/dndIds.mjs +13 -1
- package/dist/admin/future/pages/Assets/components/Dnd/dndIds.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/Dnd/useAssetDnd.js +19 -25
- package/dist/admin/future/pages/Assets/components/Dnd/useAssetDnd.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/Dnd/useAssetDnd.mjs +19 -25
- package/dist/admin/future/pages/Assets/components/Dnd/useAssetDnd.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/Dnd/useFolderTreeDroppable.js +35 -0
- package/dist/admin/future/pages/Assets/components/Dnd/useFolderTreeDroppable.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/Dnd/useFolderTreeDroppable.mjs +33 -0
- package/dist/admin/future/pages/Assets/components/Dnd/useFolderTreeDroppable.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js +120 -22
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs +121 -23
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderTree/useSpringLoadedExpand.js +22 -0
- package/dist/admin/future/pages/Assets/components/FolderTree/useSpringLoadedExpand.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/FolderTree/useSpringLoadedExpand.mjs +19 -0
- package/dist/admin/future/pages/Assets/components/FolderTree/useSpringLoadedExpand.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/components/SortMenu.js +165 -0
- package/dist/admin/future/pages/Assets/components/SortMenu.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/SortMenu.mjs +163 -0
- package/dist/admin/future/pages/Assets/components/SortMenu.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.js +59 -0
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.js.map +1 -0
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.mjs +55 -0
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/hooks/useListSort.js +124 -0
- package/dist/admin/future/pages/Assets/hooks/useListSort.js.map +1 -0
- package/dist/admin/future/pages/Assets/hooks/useListSort.mjs +120 -0
- package/dist/admin/future/pages/Assets/hooks/useListSort.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/utils/listQueryKey.js +29 -0
- package/dist/admin/future/pages/Assets/utils/listQueryKey.js.map +1 -0
- package/dist/admin/future/pages/Assets/utils/listQueryKey.mjs +27 -0
- package/dist/admin/future/pages/Assets/utils/listQueryKey.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/utils/mergeMixedList.js +84 -0
- package/dist/admin/future/pages/Assets/utils/mergeMixedList.js.map +1 -0
- package/dist/admin/future/pages/Assets/utils/mergeMixedList.mjs +81 -0
- package/dist/admin/future/pages/Assets/utils/mergeMixedList.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/utils/selection.js +104 -0
- package/dist/admin/future/pages/Assets/utils/selection.js.map +1 -0
- package/dist/admin/future/pages/Assets/utils/selection.mjs +94 -0
- package/dist/admin/future/pages/Assets/utils/selection.mjs.map +1 -0
- package/dist/admin/future/services/assets.js +33 -1
- package/dist/admin/future/services/assets.js.map +1 -1
- package/dist/admin/future/services/assets.mjs +33 -2
- package/dist/admin/future/services/assets.mjs.map +1 -1
- package/dist/admin/future/services/folders.js +3 -3
- package/dist/admin/future/services/folders.js.map +1 -1
- package/dist/admin/future/services/folders.mjs +3 -3
- package/dist/admin/future/services/folders.mjs.map +1 -1
- package/dist/admin/future/utils/buildDragSetFromSelection.js +33 -0
- package/dist/admin/future/utils/buildDragSetFromSelection.js.map +1 -0
- package/dist/admin/future/utils/buildDragSetFromSelection.mjs +31 -0
- package/dist/admin/future/utils/buildDragSetFromSelection.mjs.map +1 -0
- package/dist/admin/future/utils/canDropItemOnFolder.js +4 -0
- package/dist/admin/future/utils/canDropItemOnFolder.js.map +1 -1
- package/dist/admin/future/utils/canDropItemOnFolder.mjs +4 -0
- package/dist/admin/future/utils/canDropItemOnFolder.mjs.map +1 -1
- package/dist/admin/future/utils/flattenFolderStructure.js +28 -0
- package/dist/admin/future/utils/flattenFolderStructure.js.map +1 -0
- package/dist/admin/future/utils/flattenFolderStructure.mjs +26 -0
- package/dist/admin/future/utils/flattenFolderStructure.mjs.map +1 -0
- package/dist/admin/future/utils/formatMoveSuccessMessage.js +19 -0
- package/dist/admin/future/utils/formatMoveSuccessMessage.js.map +1 -0
- package/dist/admin/future/utils/formatMoveSuccessMessage.mjs +17 -0
- package/dist/admin/future/utils/formatMoveSuccessMessage.mjs.map +1 -0
- package/dist/admin/future/utils/getFolderLabel.js +31 -0
- package/dist/admin/future/utils/getFolderLabel.js.map +1 -0
- package/dist/admin/future/utils/getFolderLabel.mjs +29 -0
- package/dist/admin/future/utils/getFolderLabel.mjs.map +1 -0
- package/dist/admin/src/future/pages/Assets/components/AssetsTable.d.ts +7 -1
- package/dist/admin/src/future/pages/Assets/components/BulkActionsBar.d.ts +1 -0
- package/dist/admin/src/future/pages/Assets/components/BulkMoveDialog.d.ts +13 -0
- package/dist/admin/src/future/pages/Assets/components/Dnd/AssetsDndProvider.d.ts +2 -0
- package/dist/admin/src/future/pages/Assets/components/Dnd/DragOverlayChip.d.ts +2 -2
- package/dist/admin/src/future/pages/Assets/components/Dnd/buildDragSet.d.ts +17 -0
- package/dist/admin/src/future/pages/Assets/components/Dnd/computeValidDropTargets.d.ts +7 -0
- package/dist/admin/src/future/pages/Assets/components/Dnd/dndIds.d.ts +3 -0
- package/dist/admin/src/future/pages/Assets/components/Dnd/useAssetDnd.d.ts +3 -1
- package/dist/admin/src/future/pages/Assets/components/Dnd/useFolderTreeDroppable.d.ts +19 -0
- package/dist/admin/src/future/pages/Assets/components/FolderTree/useSpringLoadedExpand.d.ts +6 -0
- package/dist/admin/src/future/pages/Assets/components/SortMenu.d.ts +17 -0
- package/dist/admin/src/future/pages/Assets/hooks/useAssetSelection.d.ts +39 -0
- package/dist/admin/src/future/pages/Assets/hooks/useListSort.d.ts +47 -0
- package/dist/admin/src/future/pages/Assets/utils/listQueryKey.d.ts +30 -0
- package/dist/admin/src/future/pages/Assets/utils/mergeMixedList.d.ts +40 -0
- package/dist/admin/src/future/pages/Assets/utils/selection.d.ts +50 -0
- package/dist/admin/src/future/services/assets.d.ts +4 -1
- package/dist/admin/src/future/services/folders.d.ts +4 -1
- package/dist/admin/src/future/types/dnd.d.ts +5 -0
- package/dist/admin/src/future/utils/buildDragSetFromSelection.d.ts +11 -0
- package/dist/admin/src/future/utils/canDropItemOnFolder.d.ts +1 -1
- package/dist/admin/src/future/utils/flattenFolderStructure.d.ts +18 -0
- package/dist/admin/src/future/utils/formatMoveSuccessMessage.d.ts +14 -0
- package/dist/admin/src/future/utils/getFolderLabel.d.ts +11 -0
- package/dist/admin/translations/en.json.js +33 -0
- package/dist/admin/translations/en.json.js.map +1 -1
- package/dist/admin/translations/en.json.mjs +33 -0
- package/dist/admin/translations/en.json.mjs.map +1 -1
- package/dist/shared/contracts/folders.d.ts +1 -1
- package/package.json +7 -7
|
@@ -151,10 +151,41 @@ const assetsApi = uploadApi.injectEndpoints({
|
|
|
151
151
|
id: 'LIST'
|
|
152
152
|
}
|
|
153
153
|
]
|
|
154
|
+
}),
|
|
155
|
+
/**
|
|
156
|
+
* Permanently delete several assets and/or folders in one request. Same
|
|
157
|
+
* endpoint as the legacy bulk remove (`POST /upload/actions/bulk-delete`,
|
|
158
|
+
* handled by `admin-folder-file.deleteMany`) so server behaviour is
|
|
159
|
+
* unchanged — folder deletion cascades to everything inside.
|
|
160
|
+
*/ bulkDeleteItems: builder.mutation({
|
|
161
|
+
query: ({ fileIds, folderIds })=>({
|
|
162
|
+
url: '/upload/actions/bulk-delete',
|
|
163
|
+
method: 'POST',
|
|
164
|
+
data: {
|
|
165
|
+
fileIds,
|
|
166
|
+
folderIds
|
|
167
|
+
}
|
|
168
|
+
}),
|
|
169
|
+
invalidatesTags: [
|
|
170
|
+
{
|
|
171
|
+
type: 'Asset',
|
|
172
|
+
id: 'LIST'
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
type: 'Folder',
|
|
176
|
+
id: 'LIST'
|
|
177
|
+
},
|
|
178
|
+
// The sidebar FolderTree reads /upload/folder-structure, which carries
|
|
179
|
+
// its own tag — without it, deleted folders linger in the tree.
|
|
180
|
+
{
|
|
181
|
+
type: 'Folder',
|
|
182
|
+
id: 'STRUCTURE'
|
|
183
|
+
}
|
|
184
|
+
]
|
|
154
185
|
})
|
|
155
186
|
})
|
|
156
187
|
});
|
|
157
|
-
const { useGetAssetsQuery, useGetAssetQuery, useUpdateAssetMutation, useReplaceAssetMutation, useDeleteAssetMutation } = assetsApi;
|
|
188
|
+
const { useGetAssetsQuery, useGetAssetQuery, useUpdateAssetMutation, useReplaceAssetMutation, useDeleteAssetMutation, useBulkDeleteItemsMutation } = assetsApi;
|
|
158
189
|
|
|
159
|
-
export { useDeleteAssetMutation, useGetAssetQuery, useGetAssetsQuery, useReplaceAssetMutation, useUpdateAssetMutation };
|
|
190
|
+
export { useBulkDeleteItemsMutation, useDeleteAssetMutation, useGetAssetQuery, useGetAssetsQuery, useReplaceAssetMutation, useUpdateAssetMutation };
|
|
160
191
|
//# sourceMappingURL=assets.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assets.mjs","sources":["../../../../admin/src/future/services/assets.ts"],"sourcesContent":["import { uploadApi } from './api';\n\nimport type {\n GetFiles,\n File,\n Pagination,\n UploadFileInfo,\n AssetWithPopulatedCreatedBy,\n} from '../../../../shared/contracts/files';\n\ninterface GetAssetsParams {\n page?: number;\n pageSize?: number;\n folder?: number | null;\n sort?: string;\n}\n\ninterface GetAssetsResponse {\n results: File[];\n pagination: Pagination;\n}\n\ninterface UpdateAssetArgs {\n id: number;\n fileInfo: Partial<UploadFileInfo>;\n}\n\ninterface ReplaceAssetArgs {\n id: number;\n // `File` is shadowed in this module by the asset-file contract type; the\n // global browser File is what we need for FormData.\n file: globalThis.File;\n fileInfo?: Partial<UploadFileInfo>;\n}\n\nconst assetsApi = uploadApi.injectEndpoints({\n endpoints: (builder) => ({\n getAssets: builder.query<GetAssetsResponse, GetAssetsParams | void>({\n query: (params = {}) => {\n const { folder, ...rest } = params as GetAssetsParams;\n\n const queryParams: Record<string, unknown> = { ...rest };\n\n if (folder != null) {\n queryParams['filters'] = {\n $and: [{ folder: { id: folder } }],\n };\n } else {\n queryParams['filters'] = {\n $and: [{ folder: { id: { $null: true } } }],\n };\n }\n\n return {\n url: '/upload/files',\n method: 'GET',\n config: { params: queryParams },\n };\n },\n transformResponse: (response: GetFiles.Response['data']) => response,\n providesTags: (result) =>\n result\n ? [\n ...result.results.map(({ id }) => ({ type: 'Asset' as const, id })),\n { type: 'Asset', id: 'LIST' },\n ]\n : [{ type: 'Asset', id: 'LIST' }],\n }),\n getAsset: builder.query<AssetWithPopulatedCreatedBy, number>({\n query: (id) => ({\n url: `/upload/files/${id}`,\n method: 'GET',\n }),\n providesTags: (_result, _error, id) => [{ type: 'Asset' as const, id }],\n }),\n /**\n * Update the editable metadata of an existing asset.\n * Hits the legacy `POST /upload?id=<id>` endpoint which dispatches to\n * `admin-upload.updateFileInfo`.\n */\n updateAsset: builder.mutation<AssetWithPopulatedCreatedBy, UpdateAssetArgs>({\n query: ({ id, fileInfo }) => {\n const formData = new FormData();\n formData.append('fileInfo', JSON.stringify(fileInfo));\n\n return {\n url: '/upload',\n method: 'POST',\n data: formData,\n config: { params: { id } },\n };\n },\n invalidatesTags: (_result, _error, { id }) => [\n { type: 'Asset' as const, id },\n { type: 'Asset' as const, id: 'LIST' },\n ],\n }),\n /**\n * Replace the binary content of an existing asset.\n * Hits `POST /upload?id=<id>` with a multipart body — the controller\n * dispatches to `admin-upload.replaceFile` when a `files` part is present.\n * Uses the standard axios baseQuery (no streaming) since we only ever\n * replace one file at a time and don't need per-byte progress here.\n */\n replaceAsset: builder.mutation<AssetWithPopulatedCreatedBy, ReplaceAssetArgs>({\n query: ({ id, file, fileInfo }) => {\n const formData = new FormData();\n formData.append('files', file);\n if (fileInfo) {\n formData.append('fileInfo', JSON.stringify(fileInfo));\n }\n return {\n url: '/upload',\n method: 'POST',\n data: formData,\n config: { params: { id } },\n };\n },\n invalidatesTags: (_result, _error, { id }) => [\n { type: 'Asset' as const, id },\n { type: 'Asset' as const, id: 'LIST' },\n ],\n }),\n /**\n * Permanently delete an asset by id. Hits the same endpoint as the legacy\n * `useRemoveAsset` hook so server behaviour is unchanged.\n */\n deleteAsset: builder.mutation<unknown, number>({\n query: (id) => ({\n url: `/upload/files/${id}`,\n method: 'DELETE',\n }),\n invalidatesTags: (_result, _error, id) => [\n { type: 'Asset' as const, id },\n { type: 'Asset' as const, id: 'LIST' },\n ],\n }),\n }),\n});\n\nexport const {\n useGetAssetsQuery,\n useGetAssetQuery,\n useUpdateAssetMutation,\n useReplaceAssetMutation,\n useDeleteAssetMutation,\n} = assetsApi;\n"],"names":["assetsApi","uploadApi","injectEndpoints","endpoints","builder","getAssets","query","params","folder","rest","queryParams","$and","id","$null","url","method","config","transformResponse","response","providesTags","result","results","map","type","getAsset","_result","_error","updateAsset","mutation","fileInfo","formData","FormData","append","JSON","stringify","data","invalidatesTags","replaceAsset","file","deleteAsset","useGetAssetsQuery","useGetAssetQuery","useUpdateAssetMutation","useReplaceAssetMutation","useDeleteAssetMutation"],"mappings":"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
|
|
1
|
+
{"version":3,"file":"assets.mjs","sources":["../../../../admin/src/future/services/assets.ts"],"sourcesContent":["import { uploadApi } from './api';\n\nimport type {\n GetFiles,\n File,\n Pagination,\n UploadFileInfo,\n AssetWithPopulatedCreatedBy,\n} from '../../../../shared/contracts/files';\n\ninterface GetAssetsParams {\n page?: number;\n pageSize?: number;\n folder?: number | null;\n sort?: string;\n}\n\ninterface GetAssetsResponse {\n results: File[];\n pagination: Pagination;\n}\n\ninterface UpdateAssetArgs {\n id: number;\n fileInfo: Partial<UploadFileInfo>;\n}\n\ninterface ReplaceAssetArgs {\n id: number;\n // `File` is shadowed in this module by the asset-file contract type; the\n // global browser File is what we need for FormData.\n file: globalThis.File;\n fileInfo?: Partial<UploadFileInfo>;\n}\n\nconst assetsApi = uploadApi.injectEndpoints({\n endpoints: (builder) => ({\n getAssets: builder.query<GetAssetsResponse, GetAssetsParams | void>({\n query: (params = {}) => {\n const { folder, ...rest } = params as GetAssetsParams;\n\n const queryParams: Record<string, unknown> = { ...rest };\n\n if (folder != null) {\n queryParams['filters'] = {\n $and: [{ folder: { id: folder } }],\n };\n } else {\n queryParams['filters'] = {\n $and: [{ folder: { id: { $null: true } } }],\n };\n }\n\n return {\n url: '/upload/files',\n method: 'GET',\n config: { params: queryParams },\n };\n },\n transformResponse: (response: GetFiles.Response['data']) => response,\n providesTags: (result) =>\n result\n ? [\n ...result.results.map(({ id }) => ({ type: 'Asset' as const, id })),\n { type: 'Asset', id: 'LIST' },\n ]\n : [{ type: 'Asset', id: 'LIST' }],\n }),\n getAsset: builder.query<AssetWithPopulatedCreatedBy, number>({\n query: (id) => ({\n url: `/upload/files/${id}`,\n method: 'GET',\n }),\n providesTags: (_result, _error, id) => [{ type: 'Asset' as const, id }],\n }),\n /**\n * Update the editable metadata of an existing asset.\n * Hits the legacy `POST /upload?id=<id>` endpoint which dispatches to\n * `admin-upload.updateFileInfo`.\n */\n updateAsset: builder.mutation<AssetWithPopulatedCreatedBy, UpdateAssetArgs>({\n query: ({ id, fileInfo }) => {\n const formData = new FormData();\n formData.append('fileInfo', JSON.stringify(fileInfo));\n\n return {\n url: '/upload',\n method: 'POST',\n data: formData,\n config: { params: { id } },\n };\n },\n invalidatesTags: (_result, _error, { id }) => [\n { type: 'Asset' as const, id },\n { type: 'Asset' as const, id: 'LIST' },\n ],\n }),\n /**\n * Replace the binary content of an existing asset.\n * Hits `POST /upload?id=<id>` with a multipart body — the controller\n * dispatches to `admin-upload.replaceFile` when a `files` part is present.\n * Uses the standard axios baseQuery (no streaming) since we only ever\n * replace one file at a time and don't need per-byte progress here.\n */\n replaceAsset: builder.mutation<AssetWithPopulatedCreatedBy, ReplaceAssetArgs>({\n query: ({ id, file, fileInfo }) => {\n const formData = new FormData();\n formData.append('files', file);\n if (fileInfo) {\n formData.append('fileInfo', JSON.stringify(fileInfo));\n }\n return {\n url: '/upload',\n method: 'POST',\n data: formData,\n config: { params: { id } },\n };\n },\n invalidatesTags: (_result, _error, { id }) => [\n { type: 'Asset' as const, id },\n { type: 'Asset' as const, id: 'LIST' },\n ],\n }),\n /**\n * Permanently delete an asset by id. Hits the same endpoint as the legacy\n * `useRemoveAsset` hook so server behaviour is unchanged.\n */\n deleteAsset: builder.mutation<unknown, number>({\n query: (id) => ({\n url: `/upload/files/${id}`,\n method: 'DELETE',\n }),\n invalidatesTags: (_result, _error, id) => [\n { type: 'Asset' as const, id },\n { type: 'Asset' as const, id: 'LIST' },\n ],\n }),\n /**\n * Permanently delete several assets and/or folders in one request. Same\n * endpoint as the legacy bulk remove (`POST /upload/actions/bulk-delete`,\n * handled by `admin-folder-file.deleteMany`) so server behaviour is\n * unchanged — folder deletion cascades to everything inside.\n */\n bulkDeleteItems: builder.mutation<unknown, { fileIds: number[]; folderIds: number[] }>({\n query: ({ fileIds, folderIds }) => ({\n url: '/upload/actions/bulk-delete',\n method: 'POST',\n data: { fileIds, folderIds },\n }),\n invalidatesTags: [\n { type: 'Asset' as const, id: 'LIST' },\n { type: 'Folder' as const, id: 'LIST' },\n // The sidebar FolderTree reads /upload/folder-structure, which carries\n // its own tag — without it, deleted folders linger in the tree.\n { type: 'Folder' as const, id: 'STRUCTURE' },\n ],\n }),\n }),\n});\n\nexport const {\n useGetAssetsQuery,\n useGetAssetQuery,\n useUpdateAssetMutation,\n useReplaceAssetMutation,\n useDeleteAssetMutation,\n useBulkDeleteItemsMutation,\n} = assetsApi;\n"],"names":["assetsApi","uploadApi","injectEndpoints","endpoints","builder","getAssets","query","params","folder","rest","queryParams","$and","id","$null","url","method","config","transformResponse","response","providesTags","result","results","map","type","getAsset","_result","_error","updateAsset","mutation","fileInfo","formData","FormData","append","JSON","stringify","data","invalidatesTags","replaceAsset","file","deleteAsset","bulkDeleteItems","fileIds","folderIds","useGetAssetsQuery","useGetAssetQuery","useUpdateAssetMutation","useReplaceAssetMutation","useDeleteAssetMutation","useBulkDeleteItemsMutation"],"mappings":"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"}
|
|
@@ -8,10 +8,10 @@ const foldersApi = api.uploadApi.injectEndpoints({
|
|
|
8
8
|
endpoints: (builder)=>({
|
|
9
9
|
getFolders: builder.query({
|
|
10
10
|
query: (params = {})=>{
|
|
11
|
-
const { parentId } = params;
|
|
11
|
+
const { parentId, sort } = params;
|
|
12
12
|
const queryParams = {
|
|
13
|
-
//
|
|
14
|
-
sort: 'name:ASC'
|
|
13
|
+
// Default matches sidebar FolderTree order (server getStructure uses sortBy('name')).
|
|
14
|
+
sort: sort ?? 'name:ASC'
|
|
15
15
|
};
|
|
16
16
|
if (parentId != null) {
|
|
17
17
|
queryParams['filters'] = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"folders.js","sources":["../../../../admin/src/future/services/folders.ts"],"sourcesContent":["import { uploadApi } from './api';\n\nimport type {\n Folder,\n FolderNode,\n CreateFolders,\n GetFolder,\n GetFolders,\n GetFolderStructure,\n BulkMoveFolders,\n} from '../../../../shared/contracts/folders';\n\nexport type FolderWithCounts = Omit<Folder, 'children' | 'files'> & {\n children?: { count: number };\n files?: { count: number };\n};\n\ninterface GetFoldersParams {\n parentId?: number | null;\n}\n\ninterface BulkMoveParams {\n fileIds?: number[];\n folderIds?: number[];\n destinationFolderId: number;\n}\n\ntype DataEnvelope<T> = {\n data: T;\n};\n\nconst isDataEnvelope = <T>(response: T | DataEnvelope<T>): response is DataEnvelope<T> =>\n typeof response === 'object' && response !== null && 'data' in response;\n\nconst unwrapData = <T>(response: T | DataEnvelope<T>): T =>\n isDataEnvelope(response) ? response.data : response;\n\nconst foldersApi = uploadApi.injectEndpoints({\n endpoints: (builder) => ({\n getFolders: builder.query<Folder[], GetFoldersParams | void>({\n query: (params = {}) => {\n const { parentId } = params as GetFoldersParams;\n\n const queryParams: Record<string, unknown> = {\n // Match sidebar FolderTree order (server getStructure uses sortBy('name')).\n sort: 'name:ASC',\n };\n\n if (parentId != null) {\n queryParams['filters'] = {\n $and: [{ parent: { id: parentId } }],\n };\n } else {\n queryParams['filters'] = {\n $and: [{ parent: { id: { $null: true } } }],\n };\n }\n\n return {\n url: '/upload/folders',\n method: 'GET',\n config: { params: queryParams },\n };\n },\n transformResponse: (response: GetFolders.Response['data']) =>\n unwrapData<GetFolders.Response['data']>(response),\n providesTags: (results) => {\n if (results) {\n return [\n ...results.map(({ id }) => ({ type: 'Folder' as const, id })),\n { type: 'Folder', id: 'LIST' },\n ];\n }\n return [{ type: 'Folder', id: 'LIST' }];\n },\n }),\n createFolder: builder.mutation<CreateFolders.Response['data'], CreateFolders.Request['body']>({\n query: (body) => ({\n url: '/upload/folders',\n method: 'POST',\n data: body,\n }),\n transformResponse: (response: CreateFolders.Response) => response.data,\n invalidatesTags: [\n { type: 'Folder', id: 'LIST' },\n { type: 'Folder', id: 'STRUCTURE' },\n ],\n }),\n /**\n * Hierarchical folder tree used by the FolderTree sidebar. Returned as a\n * single nested array — the server walks the folders table once and\n * assembles parent/child relationships.\n *\n * TODO: filter results like `admin-folder.find` for folder-scoped roles\n * (v1 returns all folders; relies on global `plugin::upload.read`).\n */\n getFolderStructure: builder.query<FolderNode[], void>({\n query: () => ({\n url: '/upload/folder-structure',\n method: 'GET',\n }),\n // TODO: align GetFolderStructure contract with the real /upload/folder-structure\n // envelope and drop this defensive unwrap (data[] vs { data: [] }).\n transformResponse: (response: GetFolderStructure.Response['data']) =>\n ((response as unknown as { data: FolderNode[] })?.data ??\n (response as unknown as FolderNode[]) ??\n []) as FolderNode[],\n providesTags: [{ type: 'Folder', id: 'STRUCTURE' }],\n }),\n /**\n * Flat list of every folder, used to populate the \"Location\" select in the\n * asset details drawer. No parent filter — we want the entire tree in one\n * query so the select can render any destination folder.\n */\n getAllFolders: builder.query<Folder[], void>({\n query: () => ({\n url: '/upload/folders',\n method: 'GET',\n }),\n transformResponse: (response: GetFolders.Response['data']) =>\n unwrapData<GetFolders.Response['data']>(response ?? []),\n providesTags: (results) => {\n if (results) {\n return [\n ...results.map(({ id }) => ({ type: 'Folder' as const, id })),\n { type: 'Folder' as const, id: 'LIST' },\n ];\n }\n return [{ type: 'Folder' as const, id: 'LIST' }];\n },\n }),\n getFolder: builder.query<FolderWithCounts, { id: number }>({\n query: ({ id }) => ({\n url: `/upload/folders/${id}`,\n method: 'GET',\n config: {\n params: {\n populate: {\n parent: {\n populate: {\n parent: '*',\n },\n },\n children: { count: true },\n files: { count: true },\n },\n },\n },\n }),\n transformResponse: (response: GetFolder.Response) =>\n response.data as unknown as FolderWithCounts,\n providesTags: (_result, _error, { id }) => [{ type: 'Folder', id }],\n }),\n bulkMove: builder.mutation<BulkMoveFolders.Response['data'], BulkMoveParams>({\n query: ({ fileIds = [], folderIds = [], destinationFolderId }) => ({\n url: '/upload/actions/bulk-move',\n method: 'POST',\n data: { fileIds, folderIds, destinationFolderId },\n }),\n transformResponse: (response: BulkMoveFolders.Response) => response.data,\n invalidatesTags: [\n { type: 'Asset', id: 'LIST' },\n { type: 'Folder', id: 'LIST' },\n { type: 'Folder', id: 'STRUCTURE' },\n ],\n }),\n }),\n});\n\nexport const {\n useCreateFolderMutation,\n useGetFoldersQuery,\n useGetFolderQuery,\n useGetAllFoldersQuery,\n useGetFolderStructureQuery,\n useBulkMoveMutation,\n} = foldersApi;\n"],"names":["isDataEnvelope","response","unwrapData","data","foldersApi","uploadApi","injectEndpoints","endpoints","builder","getFolders","query","params","parentId","queryParams","sort","$and","parent","id","$null","url","method","config","transformResponse","providesTags","results","map","type","createFolder","mutation","body","invalidatesTags","getFolderStructure","getAllFolders","getFolder","populate","children","count","files","_result","_error","bulkMove","fileIds","folderIds","destinationFolderId","useCreateFolderMutation","useGetFoldersQuery","useGetFolderQuery","useGetAllFoldersQuery","useGetFolderStructureQuery","useBulkMoveMutation"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"folders.js","sources":["../../../../admin/src/future/services/folders.ts"],"sourcesContent":["import { uploadApi } from './api';\n\nimport type {\n Folder,\n FolderNode,\n CreateFolders,\n GetFolder,\n GetFolders,\n GetFolderStructure,\n BulkMoveFolders,\n} from '../../../../shared/contracts/folders';\n\nexport type FolderWithCounts = Omit<Folder, 'children' | 'files'> & {\n children?: { count: number };\n files?: { count: number };\n};\n\ninterface GetFoldersParams {\n parentId?: number | null;\n /** Comma-separated rules, e.g. `updatedAt:DESC,name:ASC`. Defaults to alphabetical. */\n sort?: string;\n}\n\ninterface BulkMoveParams {\n fileIds?: number[];\n folderIds?: number[];\n /** `null` moves the items to the root of the Media Library. */\n destinationFolderId: number | null;\n}\n\ntype DataEnvelope<T> = {\n data: T;\n};\n\nconst isDataEnvelope = <T>(response: T | DataEnvelope<T>): response is DataEnvelope<T> =>\n typeof response === 'object' && response !== null && 'data' in response;\n\nconst unwrapData = <T>(response: T | DataEnvelope<T>): T =>\n isDataEnvelope(response) ? response.data : response;\n\nconst foldersApi = uploadApi.injectEndpoints({\n endpoints: (builder) => ({\n getFolders: builder.query<Folder[], GetFoldersParams | void>({\n query: (params = {}) => {\n const { parentId, sort } = params as GetFoldersParams;\n\n const queryParams: Record<string, unknown> = {\n // Default matches sidebar FolderTree order (server getStructure uses sortBy('name')).\n sort: sort ?? 'name:ASC',\n };\n\n if (parentId != null) {\n queryParams['filters'] = {\n $and: [{ parent: { id: parentId } }],\n };\n } else {\n queryParams['filters'] = {\n $and: [{ parent: { id: { $null: true } } }],\n };\n }\n\n return {\n url: '/upload/folders',\n method: 'GET',\n config: { params: queryParams },\n };\n },\n transformResponse: (response: GetFolders.Response['data']) =>\n unwrapData<GetFolders.Response['data']>(response),\n providesTags: (results) => {\n if (results) {\n return [\n ...results.map(({ id }) => ({ type: 'Folder' as const, id })),\n { type: 'Folder', id: 'LIST' },\n ];\n }\n return [{ type: 'Folder', id: 'LIST' }];\n },\n }),\n createFolder: builder.mutation<CreateFolders.Response['data'], CreateFolders.Request['body']>({\n query: (body) => ({\n url: '/upload/folders',\n method: 'POST',\n data: body,\n }),\n transformResponse: (response: CreateFolders.Response) => response.data,\n invalidatesTags: [\n { type: 'Folder', id: 'LIST' },\n { type: 'Folder', id: 'STRUCTURE' },\n ],\n }),\n /**\n * Hierarchical folder tree used by the FolderTree sidebar. Returned as a\n * single nested array — the server walks the folders table once and\n * assembles parent/child relationships.\n *\n * TODO: filter results like `admin-folder.find` for folder-scoped roles\n * (v1 returns all folders; relies on global `plugin::upload.read`).\n */\n getFolderStructure: builder.query<FolderNode[], void>({\n query: () => ({\n url: '/upload/folder-structure',\n method: 'GET',\n }),\n // TODO: align GetFolderStructure contract with the real /upload/folder-structure\n // envelope and drop this defensive unwrap (data[] vs { data: [] }).\n transformResponse: (response: GetFolderStructure.Response['data']) =>\n ((response as unknown as { data: FolderNode[] })?.data ??\n (response as unknown as FolderNode[]) ??\n []) as FolderNode[],\n providesTags: [{ type: 'Folder', id: 'STRUCTURE' }],\n }),\n /**\n * Flat list of every folder, used to populate the \"Location\" select in the\n * asset details drawer. No parent filter — we want the entire tree in one\n * query so the select can render any destination folder.\n */\n getAllFolders: builder.query<Folder[], void>({\n query: () => ({\n url: '/upload/folders',\n method: 'GET',\n }),\n transformResponse: (response: GetFolders.Response['data']) =>\n unwrapData<GetFolders.Response['data']>(response ?? []),\n providesTags: (results) => {\n if (results) {\n return [\n ...results.map(({ id }) => ({ type: 'Folder' as const, id })),\n { type: 'Folder' as const, id: 'LIST' },\n ];\n }\n return [{ type: 'Folder' as const, id: 'LIST' }];\n },\n }),\n getFolder: builder.query<FolderWithCounts, { id: number }>({\n query: ({ id }) => ({\n url: `/upload/folders/${id}`,\n method: 'GET',\n config: {\n params: {\n populate: {\n parent: {\n populate: {\n parent: '*',\n },\n },\n children: { count: true },\n files: { count: true },\n },\n },\n },\n }),\n transformResponse: (response: GetFolder.Response) =>\n response.data as unknown as FolderWithCounts,\n providesTags: (_result, _error, { id }) => [{ type: 'Folder', id }],\n }),\n bulkMove: builder.mutation<BulkMoveFolders.Response['data'], BulkMoveParams>({\n query: ({ fileIds = [], folderIds = [], destinationFolderId }) => ({\n url: '/upload/actions/bulk-move',\n method: 'POST',\n data: { fileIds, folderIds, destinationFolderId },\n }),\n transformResponse: (response: BulkMoveFolders.Response) => response.data,\n invalidatesTags: [\n { type: 'Asset', id: 'LIST' },\n { type: 'Folder', id: 'LIST' },\n { type: 'Folder', id: 'STRUCTURE' },\n ],\n }),\n }),\n});\n\nexport const {\n useCreateFolderMutation,\n useGetFoldersQuery,\n useGetFolderQuery,\n useGetAllFoldersQuery,\n useGetFolderStructureQuery,\n useBulkMoveMutation,\n} = foldersApi;\n"],"names":["isDataEnvelope","response","unwrapData","data","foldersApi","uploadApi","injectEndpoints","endpoints","builder","getFolders","query","params","parentId","sort","queryParams","$and","parent","id","$null","url","method","config","transformResponse","providesTags","results","map","type","createFolder","mutation","body","invalidatesTags","getFolderStructure","getAllFolders","getFolder","populate","children","count","files","_result","_error","bulkMove","fileIds","folderIds","destinationFolderId","useCreateFolderMutation","useGetFoldersQuery","useGetFolderQuery","useGetAllFoldersQuery","useGetFolderStructureQuery","useBulkMoveMutation"],"mappings":";;;;AAkCA,MAAMA,cAAAA,GAAiB,CAAIC,QAAAA,GACzB,OAAOA,aAAa,QAAA,IAAYA,QAAAA,KAAa,QAAQ,MAAA,IAAUA,QAAAA;AAEjE,MAAMC,aAAa,CAAID,QAAAA,GACrBD,eAAeC,QAAAA,CAAAA,GAAYA,QAAAA,CAASE,IAAI,GAAGF,QAAAA;AAE7C,MAAMG,UAAAA,GAAaC,aAAAA,CAAUC,eAAe,CAAC;IAC3CC,SAAAA,EAAW,CAACC,WAAa;YACvBC,UAAAA,EAAYD,OAAAA,CAAQE,KAAK,CAAoC;gBAC3DA,KAAAA,EAAO,CAACC,MAAAA,GAAS,EAAE,GAAA;AACjB,oBAAA,MAAM,EAAEC,QAAQ,EAAEC,IAAI,EAAE,GAAGF,MAAAA;AAE3B,oBAAA,MAAMG,WAAAA,GAAuC;;AAE3CD,wBAAAA,IAAAA,EAAMA,IAAAA,IAAQ;AAChB,qBAAA;AAEA,oBAAA,IAAID,YAAY,IAAA,EAAM;wBACpBE,WAAW,CAAC,UAAU,GAAG;4BACvBC,IAAAA,EAAM;AAAC,gCAAA;oCAAEC,MAAAA,EAAQ;wCAAEC,EAAAA,EAAIL;AAAS;AAAE;AAAE;AACtC,yBAAA;oBACF,CAAA,MAAO;wBACLE,WAAW,CAAC,UAAU,GAAG;4BACvBC,IAAAA,EAAM;AAAC,gCAAA;oCAAEC,MAAAA,EAAQ;wCAAEC,EAAAA,EAAI;4CAAEC,KAAAA,EAAO;AAAK;AAAE;AAAE;AAAE;AAC7C,yBAAA;AACF,oBAAA;oBAEA,OAAO;wBACLC,GAAAA,EAAK,iBAAA;wBACLC,MAAAA,EAAQ,KAAA;wBACRC,MAAAA,EAAQ;4BAAEV,MAAAA,EAAQG;AAAY;AAChC,qBAAA;AACF,gBAAA,CAAA;gBACAQ,iBAAAA,EAAmB,CAACrB,WAClBC,UAAAA,CAAwCD,QAAAA,CAAAA;AAC1CsB,gBAAAA,YAAAA,EAAc,CAACC,OAAAA,GAAAA;AACb,oBAAA,IAAIA,OAAAA,EAAS;wBACX,OAAO;AACFA,4BAAAA,GAAAA,OAAAA,CAAQC,GAAG,CAAC,CAAC,EAAER,EAAE,EAAE,IAAM;oCAAES,IAAAA,EAAM,QAAA;AAAmBT,oCAAAA;iCAAG,CAAA,CAAA;AAC1D,4BAAA;gCAAES,IAAAA,EAAM,QAAA;gCAAUT,EAAAA,EAAI;AAAO;AAC9B,yBAAA;AACH,oBAAA;oBACA,OAAO;AAAC,wBAAA;4BAAES,IAAAA,EAAM,QAAA;4BAAUT,EAAAA,EAAI;AAAO;AAAE,qBAAA;AACzC,gBAAA;AACF,aAAA,CAAA;YACAU,YAAAA,EAAcnB,OAAAA,CAAQoB,QAAQ,CAAgE;gBAC5FlB,KAAAA,EAAO,CAACmB,QAAU;wBAChBV,GAAAA,EAAK,iBAAA;wBACLC,MAAAA,EAAQ,MAAA;wBACRjB,IAAAA,EAAM0B;qBACR,CAAA;gBACAP,iBAAAA,EAAmB,CAACrB,QAAAA,GAAqCA,QAAAA,CAASE,IAAI;gBACtE2B,eAAAA,EAAiB;AACf,oBAAA;wBAAEJ,IAAAA,EAAM,QAAA;wBAAUT,EAAAA,EAAI;AAAO,qBAAA;AAC7B,oBAAA;wBAAES,IAAAA,EAAM,QAAA;wBAAUT,EAAAA,EAAI;AAAY;AACnC;AACH,aAAA,CAAA;AACA;;;;;;;QAQAc,kBAAAA,EAAoBvB,OAAAA,CAAQE,KAAK,CAAqB;AACpDA,gBAAAA,KAAAA,EAAO,KAAO;wBACZS,GAAAA,EAAK,0BAAA;wBACLC,MAAAA,EAAQ;qBACV,CAAA;;;AAGAE,gBAAAA,iBAAAA,EAAmB,CAACrB,QAAAA,GAChBA,QAAAA,EAAgDE,IAAAA,IAC/CF,YACD,EAAE;gBACNsB,YAAAA,EAAc;AAAC,oBAAA;wBAAEG,IAAAA,EAAM,QAAA;wBAAUT,EAAAA,EAAI;AAAY;AAAE;AACrD,aAAA,CAAA;AACA;;;;QAKAe,aAAAA,EAAexB,OAAAA,CAAQE,KAAK,CAAiB;AAC3CA,gBAAAA,KAAAA,EAAO,KAAO;wBACZS,GAAAA,EAAK,iBAAA;wBACLC,MAAAA,EAAQ;qBACV,CAAA;AACAE,gBAAAA,iBAAAA,EAAmB,CAACrB,QAAAA,GAClBC,UAAAA,CAAwCD,QAAAA,IAAY,EAAE,CAAA;AACxDsB,gBAAAA,YAAAA,EAAc,CAACC,OAAAA,GAAAA;AACb,oBAAA,IAAIA,OAAAA,EAAS;wBACX,OAAO;AACFA,4BAAAA,GAAAA,OAAAA,CAAQC,GAAG,CAAC,CAAC,EAAER,EAAE,EAAE,IAAM;oCAAES,IAAAA,EAAM,QAAA;AAAmBT,oCAAAA;iCAAG,CAAA,CAAA;AAC1D,4BAAA;gCAAES,IAAAA,EAAM,QAAA;gCAAmBT,EAAAA,EAAI;AAAO;AACvC,yBAAA;AACH,oBAAA;oBACA,OAAO;AAAC,wBAAA;4BAAES,IAAAA,EAAM,QAAA;4BAAmBT,EAAAA,EAAI;AAAO;AAAE,qBAAA;AAClD,gBAAA;AACF,aAAA,CAAA;YACAgB,SAAAA,EAAWzB,OAAAA,CAAQE,KAAK,CAAmC;AACzDA,gBAAAA,KAAAA,EAAO,CAAC,EAAEO,EAAE,EAAE,IAAM;wBAClBE,GAAAA,EAAK,CAAC,gBAAgB,EAAEF,EAAAA,CAAAA,CAAI;wBAC5BG,MAAAA,EAAQ,KAAA;wBACRC,MAAAA,EAAQ;4BACNV,MAAAA,EAAQ;gCACNuB,QAAAA,EAAU;oCACRlB,MAAAA,EAAQ;wCACNkB,QAAAA,EAAU;4CACRlB,MAAAA,EAAQ;AACV;AACF,qCAAA;oCACAmB,QAAAA,EAAU;wCAAEC,KAAAA,EAAO;AAAK,qCAAA;oCACxBC,KAAAA,EAAO;wCAAED,KAAAA,EAAO;AAAK;AACvB;AACF;AACF;qBACF,CAAA;gBACAd,iBAAAA,EAAmB,CAACrB,QAAAA,GAClBA,QAAAA,CAASE,IAAI;AACfoB,gBAAAA,YAAAA,EAAc,CAACe,OAAAA,EAASC,MAAAA,EAAQ,EAAEtB,EAAE,EAAE,GAAK;AAAC,wBAAA;4BAAES,IAAAA,EAAM,QAAA;AAAUT,4BAAAA;AAAG;AAAE;AACrE,aAAA,CAAA;YACAuB,QAAAA,EAAUhC,OAAAA,CAAQoB,QAAQ,CAAmD;gBAC3ElB,KAAAA,EAAO,CAAC,EAAE+B,OAAAA,GAAU,EAAE,EAAEC,SAAAA,GAAY,EAAE,EAAEC,mBAAmB,EAAE,IAAM;wBACjExB,GAAAA,EAAK,2BAAA;wBACLC,MAAAA,EAAQ,MAAA;wBACRjB,IAAAA,EAAM;AAAEsC,4BAAAA,OAAAA;AAASC,4BAAAA,SAAAA;AAAWC,4BAAAA;AAAoB;qBAClD,CAAA;gBACArB,iBAAAA,EAAmB,CAACrB,QAAAA,GAAuCA,QAAAA,CAASE,IAAI;gBACxE2B,eAAAA,EAAiB;AACf,oBAAA;wBAAEJ,IAAAA,EAAM,OAAA;wBAAST,EAAAA,EAAI;AAAO,qBAAA;AAC5B,oBAAA;wBAAES,IAAAA,EAAM,QAAA;wBAAUT,EAAAA,EAAI;AAAO,qBAAA;AAC7B,oBAAA;wBAAES,IAAAA,EAAM,QAAA;wBAAUT,EAAAA,EAAI;AAAY;AACnC;AACH,aAAA;SACF;AACF,CAAA,CAAA;AAEO,MAAM,EACX2B,uBAAuB,EACvBC,kBAAkB,EAClBC,iBAAiB,EACjBC,qBAAqB,EACrBC,0BAA0B,EAC1BC,mBAAmB,EACpB,GAAG7C;;;;;;;;;"}
|
|
@@ -6,10 +6,10 @@ const foldersApi = uploadApi.injectEndpoints({
|
|
|
6
6
|
endpoints: (builder)=>({
|
|
7
7
|
getFolders: builder.query({
|
|
8
8
|
query: (params = {})=>{
|
|
9
|
-
const { parentId } = params;
|
|
9
|
+
const { parentId, sort } = params;
|
|
10
10
|
const queryParams = {
|
|
11
|
-
//
|
|
12
|
-
sort: 'name:ASC'
|
|
11
|
+
// Default matches sidebar FolderTree order (server getStructure uses sortBy('name')).
|
|
12
|
+
sort: sort ?? 'name:ASC'
|
|
13
13
|
};
|
|
14
14
|
if (parentId != null) {
|
|
15
15
|
queryParams['filters'] = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"folders.mjs","sources":["../../../../admin/src/future/services/folders.ts"],"sourcesContent":["import { uploadApi } from './api';\n\nimport type {\n Folder,\n FolderNode,\n CreateFolders,\n GetFolder,\n GetFolders,\n GetFolderStructure,\n BulkMoveFolders,\n} from '../../../../shared/contracts/folders';\n\nexport type FolderWithCounts = Omit<Folder, 'children' | 'files'> & {\n children?: { count: number };\n files?: { count: number };\n};\n\ninterface GetFoldersParams {\n parentId?: number | null;\n}\n\ninterface BulkMoveParams {\n fileIds?: number[];\n folderIds?: number[];\n destinationFolderId: number;\n}\n\ntype DataEnvelope<T> = {\n data: T;\n};\n\nconst isDataEnvelope = <T>(response: T | DataEnvelope<T>): response is DataEnvelope<T> =>\n typeof response === 'object' && response !== null && 'data' in response;\n\nconst unwrapData = <T>(response: T | DataEnvelope<T>): T =>\n isDataEnvelope(response) ? response.data : response;\n\nconst foldersApi = uploadApi.injectEndpoints({\n endpoints: (builder) => ({\n getFolders: builder.query<Folder[], GetFoldersParams | void>({\n query: (params = {}) => {\n const { parentId } = params as GetFoldersParams;\n\n const queryParams: Record<string, unknown> = {\n // Match sidebar FolderTree order (server getStructure uses sortBy('name')).\n sort: 'name:ASC',\n };\n\n if (parentId != null) {\n queryParams['filters'] = {\n $and: [{ parent: { id: parentId } }],\n };\n } else {\n queryParams['filters'] = {\n $and: [{ parent: { id: { $null: true } } }],\n };\n }\n\n return {\n url: '/upload/folders',\n method: 'GET',\n config: { params: queryParams },\n };\n },\n transformResponse: (response: GetFolders.Response['data']) =>\n unwrapData<GetFolders.Response['data']>(response),\n providesTags: (results) => {\n if (results) {\n return [\n ...results.map(({ id }) => ({ type: 'Folder' as const, id })),\n { type: 'Folder', id: 'LIST' },\n ];\n }\n return [{ type: 'Folder', id: 'LIST' }];\n },\n }),\n createFolder: builder.mutation<CreateFolders.Response['data'], CreateFolders.Request['body']>({\n query: (body) => ({\n url: '/upload/folders',\n method: 'POST',\n data: body,\n }),\n transformResponse: (response: CreateFolders.Response) => response.data,\n invalidatesTags: [\n { type: 'Folder', id: 'LIST' },\n { type: 'Folder', id: 'STRUCTURE' },\n ],\n }),\n /**\n * Hierarchical folder tree used by the FolderTree sidebar. Returned as a\n * single nested array — the server walks the folders table once and\n * assembles parent/child relationships.\n *\n * TODO: filter results like `admin-folder.find` for folder-scoped roles\n * (v1 returns all folders; relies on global `plugin::upload.read`).\n */\n getFolderStructure: builder.query<FolderNode[], void>({\n query: () => ({\n url: '/upload/folder-structure',\n method: 'GET',\n }),\n // TODO: align GetFolderStructure contract with the real /upload/folder-structure\n // envelope and drop this defensive unwrap (data[] vs { data: [] }).\n transformResponse: (response: GetFolderStructure.Response['data']) =>\n ((response as unknown as { data: FolderNode[] })?.data ??\n (response as unknown as FolderNode[]) ??\n []) as FolderNode[],\n providesTags: [{ type: 'Folder', id: 'STRUCTURE' }],\n }),\n /**\n * Flat list of every folder, used to populate the \"Location\" select in the\n * asset details drawer. No parent filter — we want the entire tree in one\n * query so the select can render any destination folder.\n */\n getAllFolders: builder.query<Folder[], void>({\n query: () => ({\n url: '/upload/folders',\n method: 'GET',\n }),\n transformResponse: (response: GetFolders.Response['data']) =>\n unwrapData<GetFolders.Response['data']>(response ?? []),\n providesTags: (results) => {\n if (results) {\n return [\n ...results.map(({ id }) => ({ type: 'Folder' as const, id })),\n { type: 'Folder' as const, id: 'LIST' },\n ];\n }\n return [{ type: 'Folder' as const, id: 'LIST' }];\n },\n }),\n getFolder: builder.query<FolderWithCounts, { id: number }>({\n query: ({ id }) => ({\n url: `/upload/folders/${id}`,\n method: 'GET',\n config: {\n params: {\n populate: {\n parent: {\n populate: {\n parent: '*',\n },\n },\n children: { count: true },\n files: { count: true },\n },\n },\n },\n }),\n transformResponse: (response: GetFolder.Response) =>\n response.data as unknown as FolderWithCounts,\n providesTags: (_result, _error, { id }) => [{ type: 'Folder', id }],\n }),\n bulkMove: builder.mutation<BulkMoveFolders.Response['data'], BulkMoveParams>({\n query: ({ fileIds = [], folderIds = [], destinationFolderId }) => ({\n url: '/upload/actions/bulk-move',\n method: 'POST',\n data: { fileIds, folderIds, destinationFolderId },\n }),\n transformResponse: (response: BulkMoveFolders.Response) => response.data,\n invalidatesTags: [\n { type: 'Asset', id: 'LIST' },\n { type: 'Folder', id: 'LIST' },\n { type: 'Folder', id: 'STRUCTURE' },\n ],\n }),\n }),\n});\n\nexport const {\n useCreateFolderMutation,\n useGetFoldersQuery,\n useGetFolderQuery,\n useGetAllFoldersQuery,\n useGetFolderStructureQuery,\n useBulkMoveMutation,\n} = foldersApi;\n"],"names":["isDataEnvelope","response","unwrapData","data","foldersApi","uploadApi","injectEndpoints","endpoints","builder","getFolders","query","params","parentId","queryParams","sort","$and","parent","id","$null","url","method","config","transformResponse","providesTags","results","map","type","createFolder","mutation","body","invalidatesTags","getFolderStructure","getAllFolders","getFolder","populate","children","count","files","_result","_error","bulkMove","fileIds","folderIds","destinationFolderId","useCreateFolderMutation","useGetFoldersQuery","useGetFolderQuery","useGetAllFoldersQuery","useGetFolderStructureQuery","useBulkMoveMutation"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"folders.mjs","sources":["../../../../admin/src/future/services/folders.ts"],"sourcesContent":["import { uploadApi } from './api';\n\nimport type {\n Folder,\n FolderNode,\n CreateFolders,\n GetFolder,\n GetFolders,\n GetFolderStructure,\n BulkMoveFolders,\n} from '../../../../shared/contracts/folders';\n\nexport type FolderWithCounts = Omit<Folder, 'children' | 'files'> & {\n children?: { count: number };\n files?: { count: number };\n};\n\ninterface GetFoldersParams {\n parentId?: number | null;\n /** Comma-separated rules, e.g. `updatedAt:DESC,name:ASC`. Defaults to alphabetical. */\n sort?: string;\n}\n\ninterface BulkMoveParams {\n fileIds?: number[];\n folderIds?: number[];\n /** `null` moves the items to the root of the Media Library. */\n destinationFolderId: number | null;\n}\n\ntype DataEnvelope<T> = {\n data: T;\n};\n\nconst isDataEnvelope = <T>(response: T | DataEnvelope<T>): response is DataEnvelope<T> =>\n typeof response === 'object' && response !== null && 'data' in response;\n\nconst unwrapData = <T>(response: T | DataEnvelope<T>): T =>\n isDataEnvelope(response) ? response.data : response;\n\nconst foldersApi = uploadApi.injectEndpoints({\n endpoints: (builder) => ({\n getFolders: builder.query<Folder[], GetFoldersParams | void>({\n query: (params = {}) => {\n const { parentId, sort } = params as GetFoldersParams;\n\n const queryParams: Record<string, unknown> = {\n // Default matches sidebar FolderTree order (server getStructure uses sortBy('name')).\n sort: sort ?? 'name:ASC',\n };\n\n if (parentId != null) {\n queryParams['filters'] = {\n $and: [{ parent: { id: parentId } }],\n };\n } else {\n queryParams['filters'] = {\n $and: [{ parent: { id: { $null: true } } }],\n };\n }\n\n return {\n url: '/upload/folders',\n method: 'GET',\n config: { params: queryParams },\n };\n },\n transformResponse: (response: GetFolders.Response['data']) =>\n unwrapData<GetFolders.Response['data']>(response),\n providesTags: (results) => {\n if (results) {\n return [\n ...results.map(({ id }) => ({ type: 'Folder' as const, id })),\n { type: 'Folder', id: 'LIST' },\n ];\n }\n return [{ type: 'Folder', id: 'LIST' }];\n },\n }),\n createFolder: builder.mutation<CreateFolders.Response['data'], CreateFolders.Request['body']>({\n query: (body) => ({\n url: '/upload/folders',\n method: 'POST',\n data: body,\n }),\n transformResponse: (response: CreateFolders.Response) => response.data,\n invalidatesTags: [\n { type: 'Folder', id: 'LIST' },\n { type: 'Folder', id: 'STRUCTURE' },\n ],\n }),\n /**\n * Hierarchical folder tree used by the FolderTree sidebar. Returned as a\n * single nested array — the server walks the folders table once and\n * assembles parent/child relationships.\n *\n * TODO: filter results like `admin-folder.find` for folder-scoped roles\n * (v1 returns all folders; relies on global `plugin::upload.read`).\n */\n getFolderStructure: builder.query<FolderNode[], void>({\n query: () => ({\n url: '/upload/folder-structure',\n method: 'GET',\n }),\n // TODO: align GetFolderStructure contract with the real /upload/folder-structure\n // envelope and drop this defensive unwrap (data[] vs { data: [] }).\n transformResponse: (response: GetFolderStructure.Response['data']) =>\n ((response as unknown as { data: FolderNode[] })?.data ??\n (response as unknown as FolderNode[]) ??\n []) as FolderNode[],\n providesTags: [{ type: 'Folder', id: 'STRUCTURE' }],\n }),\n /**\n * Flat list of every folder, used to populate the \"Location\" select in the\n * asset details drawer. No parent filter — we want the entire tree in one\n * query so the select can render any destination folder.\n */\n getAllFolders: builder.query<Folder[], void>({\n query: () => ({\n url: '/upload/folders',\n method: 'GET',\n }),\n transformResponse: (response: GetFolders.Response['data']) =>\n unwrapData<GetFolders.Response['data']>(response ?? []),\n providesTags: (results) => {\n if (results) {\n return [\n ...results.map(({ id }) => ({ type: 'Folder' as const, id })),\n { type: 'Folder' as const, id: 'LIST' },\n ];\n }\n return [{ type: 'Folder' as const, id: 'LIST' }];\n },\n }),\n getFolder: builder.query<FolderWithCounts, { id: number }>({\n query: ({ id }) => ({\n url: `/upload/folders/${id}`,\n method: 'GET',\n config: {\n params: {\n populate: {\n parent: {\n populate: {\n parent: '*',\n },\n },\n children: { count: true },\n files: { count: true },\n },\n },\n },\n }),\n transformResponse: (response: GetFolder.Response) =>\n response.data as unknown as FolderWithCounts,\n providesTags: (_result, _error, { id }) => [{ type: 'Folder', id }],\n }),\n bulkMove: builder.mutation<BulkMoveFolders.Response['data'], BulkMoveParams>({\n query: ({ fileIds = [], folderIds = [], destinationFolderId }) => ({\n url: '/upload/actions/bulk-move',\n method: 'POST',\n data: { fileIds, folderIds, destinationFolderId },\n }),\n transformResponse: (response: BulkMoveFolders.Response) => response.data,\n invalidatesTags: [\n { type: 'Asset', id: 'LIST' },\n { type: 'Folder', id: 'LIST' },\n { type: 'Folder', id: 'STRUCTURE' },\n ],\n }),\n }),\n});\n\nexport const {\n useCreateFolderMutation,\n useGetFoldersQuery,\n useGetFolderQuery,\n useGetAllFoldersQuery,\n useGetFolderStructureQuery,\n useBulkMoveMutation,\n} = foldersApi;\n"],"names":["isDataEnvelope","response","unwrapData","data","foldersApi","uploadApi","injectEndpoints","endpoints","builder","getFolders","query","params","parentId","sort","queryParams","$and","parent","id","$null","url","method","config","transformResponse","providesTags","results","map","type","createFolder","mutation","body","invalidatesTags","getFolderStructure","getAllFolders","getFolder","populate","children","count","files","_result","_error","bulkMove","fileIds","folderIds","destinationFolderId","useCreateFolderMutation","useGetFoldersQuery","useGetFolderQuery","useGetAllFoldersQuery","useGetFolderStructureQuery","useBulkMoveMutation"],"mappings":";;AAkCA,MAAMA,cAAAA,GAAiB,CAAIC,QAAAA,GACzB,OAAOA,aAAa,QAAA,IAAYA,QAAAA,KAAa,QAAQ,MAAA,IAAUA,QAAAA;AAEjE,MAAMC,aAAa,CAAID,QAAAA,GACrBD,eAAeC,QAAAA,CAAAA,GAAYA,QAAAA,CAASE,IAAI,GAAGF,QAAAA;AAE7C,MAAMG,UAAAA,GAAaC,SAAAA,CAAUC,eAAe,CAAC;IAC3CC,SAAAA,EAAW,CAACC,WAAa;YACvBC,UAAAA,EAAYD,OAAAA,CAAQE,KAAK,CAAoC;gBAC3DA,KAAAA,EAAO,CAACC,MAAAA,GAAS,EAAE,GAAA;AACjB,oBAAA,MAAM,EAAEC,QAAQ,EAAEC,IAAI,EAAE,GAAGF,MAAAA;AAE3B,oBAAA,MAAMG,WAAAA,GAAuC;;AAE3CD,wBAAAA,IAAAA,EAAMA,IAAAA,IAAQ;AAChB,qBAAA;AAEA,oBAAA,IAAID,YAAY,IAAA,EAAM;wBACpBE,WAAW,CAAC,UAAU,GAAG;4BACvBC,IAAAA,EAAM;AAAC,gCAAA;oCAAEC,MAAAA,EAAQ;wCAAEC,EAAAA,EAAIL;AAAS;AAAE;AAAE;AACtC,yBAAA;oBACF,CAAA,MAAO;wBACLE,WAAW,CAAC,UAAU,GAAG;4BACvBC,IAAAA,EAAM;AAAC,gCAAA;oCAAEC,MAAAA,EAAQ;wCAAEC,EAAAA,EAAI;4CAAEC,KAAAA,EAAO;AAAK;AAAE;AAAE;AAAE;AAC7C,yBAAA;AACF,oBAAA;oBAEA,OAAO;wBACLC,GAAAA,EAAK,iBAAA;wBACLC,MAAAA,EAAQ,KAAA;wBACRC,MAAAA,EAAQ;4BAAEV,MAAAA,EAAQG;AAAY;AAChC,qBAAA;AACF,gBAAA,CAAA;gBACAQ,iBAAAA,EAAmB,CAACrB,WAClBC,UAAAA,CAAwCD,QAAAA,CAAAA;AAC1CsB,gBAAAA,YAAAA,EAAc,CAACC,OAAAA,GAAAA;AACb,oBAAA,IAAIA,OAAAA,EAAS;wBACX,OAAO;AACFA,4BAAAA,GAAAA,OAAAA,CAAQC,GAAG,CAAC,CAAC,EAAER,EAAE,EAAE,IAAM;oCAAES,IAAAA,EAAM,QAAA;AAAmBT,oCAAAA;iCAAG,CAAA,CAAA;AAC1D,4BAAA;gCAAES,IAAAA,EAAM,QAAA;gCAAUT,EAAAA,EAAI;AAAO;AAC9B,yBAAA;AACH,oBAAA;oBACA,OAAO;AAAC,wBAAA;4BAAES,IAAAA,EAAM,QAAA;4BAAUT,EAAAA,EAAI;AAAO;AAAE,qBAAA;AACzC,gBAAA;AACF,aAAA,CAAA;YACAU,YAAAA,EAAcnB,OAAAA,CAAQoB,QAAQ,CAAgE;gBAC5FlB,KAAAA,EAAO,CAACmB,QAAU;wBAChBV,GAAAA,EAAK,iBAAA;wBACLC,MAAAA,EAAQ,MAAA;wBACRjB,IAAAA,EAAM0B;qBACR,CAAA;gBACAP,iBAAAA,EAAmB,CAACrB,QAAAA,GAAqCA,QAAAA,CAASE,IAAI;gBACtE2B,eAAAA,EAAiB;AACf,oBAAA;wBAAEJ,IAAAA,EAAM,QAAA;wBAAUT,EAAAA,EAAI;AAAO,qBAAA;AAC7B,oBAAA;wBAAES,IAAAA,EAAM,QAAA;wBAAUT,EAAAA,EAAI;AAAY;AACnC;AACH,aAAA,CAAA;AACA;;;;;;;QAQAc,kBAAAA,EAAoBvB,OAAAA,CAAQE,KAAK,CAAqB;AACpDA,gBAAAA,KAAAA,EAAO,KAAO;wBACZS,GAAAA,EAAK,0BAAA;wBACLC,MAAAA,EAAQ;qBACV,CAAA;;;AAGAE,gBAAAA,iBAAAA,EAAmB,CAACrB,QAAAA,GAChBA,QAAAA,EAAgDE,IAAAA,IAC/CF,YACD,EAAE;gBACNsB,YAAAA,EAAc;AAAC,oBAAA;wBAAEG,IAAAA,EAAM,QAAA;wBAAUT,EAAAA,EAAI;AAAY;AAAE;AACrD,aAAA,CAAA;AACA;;;;QAKAe,aAAAA,EAAexB,OAAAA,CAAQE,KAAK,CAAiB;AAC3CA,gBAAAA,KAAAA,EAAO,KAAO;wBACZS,GAAAA,EAAK,iBAAA;wBACLC,MAAAA,EAAQ;qBACV,CAAA;AACAE,gBAAAA,iBAAAA,EAAmB,CAACrB,QAAAA,GAClBC,UAAAA,CAAwCD,QAAAA,IAAY,EAAE,CAAA;AACxDsB,gBAAAA,YAAAA,EAAc,CAACC,OAAAA,GAAAA;AACb,oBAAA,IAAIA,OAAAA,EAAS;wBACX,OAAO;AACFA,4BAAAA,GAAAA,OAAAA,CAAQC,GAAG,CAAC,CAAC,EAAER,EAAE,EAAE,IAAM;oCAAES,IAAAA,EAAM,QAAA;AAAmBT,oCAAAA;iCAAG,CAAA,CAAA;AAC1D,4BAAA;gCAAES,IAAAA,EAAM,QAAA;gCAAmBT,EAAAA,EAAI;AAAO;AACvC,yBAAA;AACH,oBAAA;oBACA,OAAO;AAAC,wBAAA;4BAAES,IAAAA,EAAM,QAAA;4BAAmBT,EAAAA,EAAI;AAAO;AAAE,qBAAA;AAClD,gBAAA;AACF,aAAA,CAAA;YACAgB,SAAAA,EAAWzB,OAAAA,CAAQE,KAAK,CAAmC;AACzDA,gBAAAA,KAAAA,EAAO,CAAC,EAAEO,EAAE,EAAE,IAAM;wBAClBE,GAAAA,EAAK,CAAC,gBAAgB,EAAEF,EAAAA,CAAAA,CAAI;wBAC5BG,MAAAA,EAAQ,KAAA;wBACRC,MAAAA,EAAQ;4BACNV,MAAAA,EAAQ;gCACNuB,QAAAA,EAAU;oCACRlB,MAAAA,EAAQ;wCACNkB,QAAAA,EAAU;4CACRlB,MAAAA,EAAQ;AACV;AACF,qCAAA;oCACAmB,QAAAA,EAAU;wCAAEC,KAAAA,EAAO;AAAK,qCAAA;oCACxBC,KAAAA,EAAO;wCAAED,KAAAA,EAAO;AAAK;AACvB;AACF;AACF;qBACF,CAAA;gBACAd,iBAAAA,EAAmB,CAACrB,QAAAA,GAClBA,QAAAA,CAASE,IAAI;AACfoB,gBAAAA,YAAAA,EAAc,CAACe,OAAAA,EAASC,MAAAA,EAAQ,EAAEtB,EAAE,EAAE,GAAK;AAAC,wBAAA;4BAAES,IAAAA,EAAM,QAAA;AAAUT,4BAAAA;AAAG;AAAE;AACrE,aAAA,CAAA;YACAuB,QAAAA,EAAUhC,OAAAA,CAAQoB,QAAQ,CAAmD;gBAC3ElB,KAAAA,EAAO,CAAC,EAAE+B,OAAAA,GAAU,EAAE,EAAEC,SAAAA,GAAY,EAAE,EAAEC,mBAAmB,EAAE,IAAM;wBACjExB,GAAAA,EAAK,2BAAA;wBACLC,MAAAA,EAAQ,MAAA;wBACRjB,IAAAA,EAAM;AAAEsC,4BAAAA,OAAAA;AAASC,4BAAAA,SAAAA;AAAWC,4BAAAA;AAAoB;qBAClD,CAAA;gBACArB,iBAAAA,EAAmB,CAACrB,QAAAA,GAAuCA,QAAAA,CAASE,IAAI;gBACxE2B,eAAAA,EAAiB;AACf,oBAAA;wBAAEJ,IAAAA,EAAM,OAAA;wBAAST,EAAAA,EAAI;AAAO,qBAAA;AAC5B,oBAAA;wBAAES,IAAAA,EAAM,QAAA;wBAAUT,EAAAA,EAAI;AAAO,qBAAA;AAC7B,oBAAA;wBAAES,IAAAA,EAAM,QAAA;wBAAUT,EAAAA,EAAI;AAAY;AACnC;AACH,aAAA;SACF;AACF,CAAA,CAAA;AAEO,MAAM,EACX2B,uBAAuB,EACvBC,kBAAkB,EAClBC,iBAAiB,EACjBC,qBAAqB,EACrBC,0BAA0B,EAC1BC,mBAAmB,EACpB,GAAG7C;;;;"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Reconstruct the drag set from a bulk-actions selection so the dialog can feed
|
|
5
|
+
* the exact same `DragItemData[]` into `computeValidDropTargets` / the canonical
|
|
6
|
+
* `canDropItemOnFolder` predicate that pointer drag uses.
|
|
7
|
+
*
|
|
8
|
+
* Selection is page-scoped to the current folder, so every selected item shares
|
|
9
|
+
* `currentFolderId` as its location (files → `folderId`, folders → `parentId`).
|
|
10
|
+
* Names are irrelevant to drop validation, so they are left empty.
|
|
11
|
+
*/ const buildDragSetFromSelection = (selectedIds, selectedFolderIds, currentFolderId)=>{
|
|
12
|
+
const items = [];
|
|
13
|
+
selectedIds.forEach((id)=>{
|
|
14
|
+
items.push({
|
|
15
|
+
kind: 'file',
|
|
16
|
+
id,
|
|
17
|
+
name: '',
|
|
18
|
+
folderId: currentFolderId
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
selectedFolderIds.forEach((id)=>{
|
|
22
|
+
items.push({
|
|
23
|
+
kind: 'folder',
|
|
24
|
+
id,
|
|
25
|
+
name: '',
|
|
26
|
+
parentId: currentFolderId
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
return items;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
exports.buildDragSetFromSelection = buildDragSetFromSelection;
|
|
33
|
+
//# sourceMappingURL=buildDragSetFromSelection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildDragSetFromSelection.js","sources":["../../../../admin/src/future/utils/buildDragSetFromSelection.ts"],"sourcesContent":["import type { DragItemData } from '../types/dnd';\n\n/**\n * Reconstruct the drag set from a bulk-actions selection so the dialog can feed\n * the exact same `DragItemData[]` into `computeValidDropTargets` / the canonical\n * `canDropItemOnFolder` predicate that pointer drag uses.\n *\n * Selection is page-scoped to the current folder, so every selected item shares\n * `currentFolderId` as its location (files → `folderId`, folders → `parentId`).\n * Names are irrelevant to drop validation, so they are left empty.\n */\nexport const buildDragSetFromSelection = (\n selectedIds: ReadonlySet<number>,\n selectedFolderIds: ReadonlySet<number>,\n currentFolderId: number | null\n): DragItemData[] => {\n const items: DragItemData[] = [];\n\n selectedIds.forEach((id) => {\n items.push({ kind: 'file', id, name: '', folderId: currentFolderId });\n });\n\n selectedFolderIds.forEach((id) => {\n items.push({ kind: 'folder', id, name: '', parentId: currentFolderId });\n });\n\n return items;\n};\n"],"names":["buildDragSetFromSelection","selectedIds","selectedFolderIds","currentFolderId","items","forEach","id","push","kind","name","folderId","parentId"],"mappings":";;AAEA;;;;;;;;AAQC,IACM,MAAMA,yBAAAA,GAA4B,CACvCC,aACAC,iBAAAA,EACAC,eAAAA,GAAAA;AAEA,IAAA,MAAMC,QAAwB,EAAE;IAEhCH,WAAAA,CAAYI,OAAO,CAAC,CAACC,EAAAA,GAAAA;AACnBF,QAAAA,KAAAA,CAAMG,IAAI,CAAC;YAAEC,IAAAA,EAAM,MAAA;AAAQF,YAAAA,EAAAA;YAAIG,IAAAA,EAAM,EAAA;YAAIC,QAAAA,EAAUP;AAAgB,SAAA,CAAA;AACrE,IAAA,CAAA,CAAA;IAEAD,iBAAAA,CAAkBG,OAAO,CAAC,CAACC,EAAAA,GAAAA;AACzBF,QAAAA,KAAAA,CAAMG,IAAI,CAAC;YAAEC,IAAAA,EAAM,QAAA;AAAUF,YAAAA,EAAAA;YAAIG,IAAAA,EAAM,EAAA;YAAIE,QAAAA,EAAUR;AAAgB,SAAA,CAAA;AACvE,IAAA,CAAA,CAAA;IAEA,OAAOC,KAAAA;AACT;;;;"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reconstruct the drag set from a bulk-actions selection so the dialog can feed
|
|
3
|
+
* the exact same `DragItemData[]` into `computeValidDropTargets` / the canonical
|
|
4
|
+
* `canDropItemOnFolder` predicate that pointer drag uses.
|
|
5
|
+
*
|
|
6
|
+
* Selection is page-scoped to the current folder, so every selected item shares
|
|
7
|
+
* `currentFolderId` as its location (files → `folderId`, folders → `parentId`).
|
|
8
|
+
* Names are irrelevant to drop validation, so they are left empty.
|
|
9
|
+
*/ const buildDragSetFromSelection = (selectedIds, selectedFolderIds, currentFolderId)=>{
|
|
10
|
+
const items = [];
|
|
11
|
+
selectedIds.forEach((id)=>{
|
|
12
|
+
items.push({
|
|
13
|
+
kind: 'file',
|
|
14
|
+
id,
|
|
15
|
+
name: '',
|
|
16
|
+
folderId: currentFolderId
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
selectedFolderIds.forEach((id)=>{
|
|
20
|
+
items.push({
|
|
21
|
+
kind: 'folder',
|
|
22
|
+
id,
|
|
23
|
+
name: '',
|
|
24
|
+
parentId: currentFolderId
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
return items;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export { buildDragSetFromSelection };
|
|
31
|
+
//# sourceMappingURL=buildDragSetFromSelection.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildDragSetFromSelection.mjs","sources":["../../../../admin/src/future/utils/buildDragSetFromSelection.ts"],"sourcesContent":["import type { DragItemData } from '../types/dnd';\n\n/**\n * Reconstruct the drag set from a bulk-actions selection so the dialog can feed\n * the exact same `DragItemData[]` into `computeValidDropTargets` / the canonical\n * `canDropItemOnFolder` predicate that pointer drag uses.\n *\n * Selection is page-scoped to the current folder, so every selected item shares\n * `currentFolderId` as its location (files → `folderId`, folders → `parentId`).\n * Names are irrelevant to drop validation, so they are left empty.\n */\nexport const buildDragSetFromSelection = (\n selectedIds: ReadonlySet<number>,\n selectedFolderIds: ReadonlySet<number>,\n currentFolderId: number | null\n): DragItemData[] => {\n const items: DragItemData[] = [];\n\n selectedIds.forEach((id) => {\n items.push({ kind: 'file', id, name: '', folderId: currentFolderId });\n });\n\n selectedFolderIds.forEach((id) => {\n items.push({ kind: 'folder', id, name: '', parentId: currentFolderId });\n });\n\n return items;\n};\n"],"names":["buildDragSetFromSelection","selectedIds","selectedFolderIds","currentFolderId","items","forEach","id","push","kind","name","folderId","parentId"],"mappings":"AAEA;;;;;;;;AAQC,IACM,MAAMA,yBAAAA,GAA4B,CACvCC,aACAC,iBAAAA,EACAC,eAAAA,GAAAA;AAEA,IAAA,MAAMC,QAAwB,EAAE;IAEhCH,WAAAA,CAAYI,OAAO,CAAC,CAACC,EAAAA,GAAAA;AACnBF,QAAAA,KAAAA,CAAMG,IAAI,CAAC;YAAEC,IAAAA,EAAM,MAAA;AAAQF,YAAAA,EAAAA;YAAIG,IAAAA,EAAM,EAAA;YAAIC,QAAAA,EAAUP;AAAgB,SAAA,CAAA;AACrE,IAAA,CAAA,CAAA;IAEAD,iBAAAA,CAAkBG,OAAO,CAAC,CAACC,EAAAA,GAAAA;AACzBF,QAAAA,KAAAA,CAAMG,IAAI,CAAC;YAAEC,IAAAA,EAAM,QAAA;AAAUF,YAAAA,EAAAA;YAAIG,IAAAA,EAAM,EAAA;YAAIE,QAAAA,EAAUR;AAAgB,SAAA,CAAA;AACvE,IAAA,CAAA,CAAA;IAEA,OAAOC,KAAAA;AACT;;;;"}
|
|
@@ -35,10 +35,14 @@ const isFolderDescendantOf = (folderStructure, ancestorId, candidateId)=>{
|
|
|
35
35
|
}
|
|
36
36
|
return collectDescendantIds(ancestorNode).has(candidateId);
|
|
37
37
|
};
|
|
38
|
+
const isItemAtRoot = (item)=>item.kind === 'file' ? item.folderId == null : item.parentId == null;
|
|
38
39
|
const canDropItemOnFolder = ({ items, targetFolderId, folderStructure })=>{
|
|
39
40
|
if (items.length === 0) {
|
|
40
41
|
return false;
|
|
41
42
|
}
|
|
43
|
+
if (targetFolderId === null) {
|
|
44
|
+
return items.some((item)=>!isItemAtRoot(item));
|
|
45
|
+
}
|
|
42
46
|
const draggedFolderIds = new Set(items.filter((item)=>item.kind === 'folder').map((item)=>item.id));
|
|
43
47
|
if (draggedFolderIds.has(targetFolderId)) {
|
|
44
48
|
return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canDropItemOnFolder.js","sources":["../../../../admin/src/future/utils/canDropItemOnFolder.ts"],"sourcesContent":["import type { FolderNode } from '../../../../shared/contracts/folders';\nimport type { DragItemData } from '../types/dnd';\n\n// TODO: permission-aware droppables — server validates in v1.\n\nexport interface CanDropItemOnFolderParams {\n items: DragItemData[];\n targetFolderId: number;\n folderStructure: FolderNode[];\n}\n\nconst findNode = (nodes: FolderNode[], id: number): FolderNode | null => {\n for (const node of nodes) {\n if (node.id === id) {\n return node;\n }\n\n const found = findNode(node.children, id);\n if (found) {\n return found;\n }\n }\n\n return null;\n};\n\nconst collectDescendantIds = (node: FolderNode): Set<number> => {\n const ids = new Set<number>();\n\n const walk = (current: FolderNode) => {\n for (const child of current.children) {\n if (child.id != null) {\n ids.add(child.id);\n }\n walk(child);\n }\n };\n\n walk(node);\n return ids;\n};\n\nexport const isFolderDescendantOf = (\n folderStructure: FolderNode[],\n ancestorId: number,\n candidateId: number\n): boolean => {\n if (ancestorId === candidateId) {\n return true;\n }\n\n const ancestorNode = findNode(folderStructure, ancestorId);\n if (!ancestorNode) {\n return false;\n }\n\n return collectDescendantIds(ancestorNode).has(candidateId);\n};\n\nexport const canDropItemOnFolder = ({\n items,\n targetFolderId,\n folderStructure,\n}: CanDropItemOnFolderParams): boolean => {\n if (items.length === 0) {\n return false;\n }\n\n const draggedFolderIds = new Set(\n items\n .filter((item): item is Extract<DragItemData, { kind: 'folder' }> => item.kind === 'folder')\n .map((item) => item.id)\n );\n\n if (draggedFolderIds.has(targetFolderId)) {\n return false;\n }\n\n for (const folderId of draggedFolderIds) {\n if (isFolderDescendantOf(folderStructure, folderId, targetFolderId)) {\n return false;\n }\n }\n\n for (const item of items) {\n if (item.kind === 'file' && item.folderId === targetFolderId) {\n return false;\n }\n\n if (item.kind === 'folder' && item.parentId === targetFolderId) {\n return false;\n }\n }\n\n return true;\n};\n"],"names":["findNode","nodes","id","node","found","children","collectDescendantIds","ids","Set","walk","current","child","add","isFolderDescendantOf","folderStructure","ancestorId","candidateId","ancestorNode","has","
|
|
1
|
+
{"version":3,"file":"canDropItemOnFolder.js","sources":["../../../../admin/src/future/utils/canDropItemOnFolder.ts"],"sourcesContent":["import type { FolderNode } from '../../../../shared/contracts/folders';\nimport type { DragItemData } from '../types/dnd';\n\n// TODO: permission-aware droppables — server validates in v1.\n\nexport interface CanDropItemOnFolderParams {\n items: DragItemData[];\n targetFolderId: number | null;\n folderStructure: FolderNode[];\n}\n\nconst findNode = (nodes: FolderNode[], id: number): FolderNode | null => {\n for (const node of nodes) {\n if (node.id === id) {\n return node;\n }\n\n const found = findNode(node.children, id);\n if (found) {\n return found;\n }\n }\n\n return null;\n};\n\nconst collectDescendantIds = (node: FolderNode): Set<number> => {\n const ids = new Set<number>();\n\n const walk = (current: FolderNode) => {\n for (const child of current.children) {\n if (child.id != null) {\n ids.add(child.id);\n }\n walk(child);\n }\n };\n\n walk(node);\n return ids;\n};\n\nexport const isFolderDescendantOf = (\n folderStructure: FolderNode[],\n ancestorId: number,\n candidateId: number\n): boolean => {\n if (ancestorId === candidateId) {\n return true;\n }\n\n const ancestorNode = findNode(folderStructure, ancestorId);\n if (!ancestorNode) {\n return false;\n }\n\n return collectDescendantIds(ancestorNode).has(candidateId);\n};\n\nconst isItemAtRoot = (item: DragItemData): boolean =>\n item.kind === 'file' ? item.folderId == null : item.parentId == null;\n\nexport const canDropItemOnFolder = ({\n items,\n targetFolderId,\n folderStructure,\n}: CanDropItemOnFolderParams): boolean => {\n if (items.length === 0) {\n return false;\n }\n\n if (targetFolderId === null) {\n return items.some((item) => !isItemAtRoot(item));\n }\n\n const draggedFolderIds = new Set(\n items\n .filter((item): item is Extract<DragItemData, { kind: 'folder' }> => item.kind === 'folder')\n .map((item) => item.id)\n );\n\n if (draggedFolderIds.has(targetFolderId)) {\n return false;\n }\n\n for (const folderId of draggedFolderIds) {\n if (isFolderDescendantOf(folderStructure, folderId, targetFolderId)) {\n return false;\n }\n }\n\n for (const item of items) {\n if (item.kind === 'file' && item.folderId === targetFolderId) {\n return false;\n }\n\n if (item.kind === 'folder' && item.parentId === targetFolderId) {\n return false;\n }\n }\n\n return true;\n};\n"],"names":["findNode","nodes","id","node","found","children","collectDescendantIds","ids","Set","walk","current","child","add","isFolderDescendantOf","folderStructure","ancestorId","candidateId","ancestorNode","has","isItemAtRoot","item","kind","folderId","parentId","canDropItemOnFolder","items","targetFolderId","length","some","draggedFolderIds","filter","map"],"mappings":"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"}
|
|
@@ -33,10 +33,14 @@ const isFolderDescendantOf = (folderStructure, ancestorId, candidateId)=>{
|
|
|
33
33
|
}
|
|
34
34
|
return collectDescendantIds(ancestorNode).has(candidateId);
|
|
35
35
|
};
|
|
36
|
+
const isItemAtRoot = (item)=>item.kind === 'file' ? item.folderId == null : item.parentId == null;
|
|
36
37
|
const canDropItemOnFolder = ({ items, targetFolderId, folderStructure })=>{
|
|
37
38
|
if (items.length === 0) {
|
|
38
39
|
return false;
|
|
39
40
|
}
|
|
41
|
+
if (targetFolderId === null) {
|
|
42
|
+
return items.some((item)=>!isItemAtRoot(item));
|
|
43
|
+
}
|
|
40
44
|
const draggedFolderIds = new Set(items.filter((item)=>item.kind === 'folder').map((item)=>item.id));
|
|
41
45
|
if (draggedFolderIds.has(targetFolderId)) {
|
|
42
46
|
return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canDropItemOnFolder.mjs","sources":["../../../../admin/src/future/utils/canDropItemOnFolder.ts"],"sourcesContent":["import type { FolderNode } from '../../../../shared/contracts/folders';\nimport type { DragItemData } from '../types/dnd';\n\n// TODO: permission-aware droppables — server validates in v1.\n\nexport interface CanDropItemOnFolderParams {\n items: DragItemData[];\n targetFolderId: number;\n folderStructure: FolderNode[];\n}\n\nconst findNode = (nodes: FolderNode[], id: number): FolderNode | null => {\n for (const node of nodes) {\n if (node.id === id) {\n return node;\n }\n\n const found = findNode(node.children, id);\n if (found) {\n return found;\n }\n }\n\n return null;\n};\n\nconst collectDescendantIds = (node: FolderNode): Set<number> => {\n const ids = new Set<number>();\n\n const walk = (current: FolderNode) => {\n for (const child of current.children) {\n if (child.id != null) {\n ids.add(child.id);\n }\n walk(child);\n }\n };\n\n walk(node);\n return ids;\n};\n\nexport const isFolderDescendantOf = (\n folderStructure: FolderNode[],\n ancestorId: number,\n candidateId: number\n): boolean => {\n if (ancestorId === candidateId) {\n return true;\n }\n\n const ancestorNode = findNode(folderStructure, ancestorId);\n if (!ancestorNode) {\n return false;\n }\n\n return collectDescendantIds(ancestorNode).has(candidateId);\n};\n\nexport const canDropItemOnFolder = ({\n items,\n targetFolderId,\n folderStructure,\n}: CanDropItemOnFolderParams): boolean => {\n if (items.length === 0) {\n return false;\n }\n\n const draggedFolderIds = new Set(\n items\n .filter((item): item is Extract<DragItemData, { kind: 'folder' }> => item.kind === 'folder')\n .map((item) => item.id)\n );\n\n if (draggedFolderIds.has(targetFolderId)) {\n return false;\n }\n\n for (const folderId of draggedFolderIds) {\n if (isFolderDescendantOf(folderStructure, folderId, targetFolderId)) {\n return false;\n }\n }\n\n for (const item of items) {\n if (item.kind === 'file' && item.folderId === targetFolderId) {\n return false;\n }\n\n if (item.kind === 'folder' && item.parentId === targetFolderId) {\n return false;\n }\n }\n\n return true;\n};\n"],"names":["findNode","nodes","id","node","found","children","collectDescendantIds","ids","Set","walk","current","child","add","isFolderDescendantOf","folderStructure","ancestorId","candidateId","ancestorNode","has","
|
|
1
|
+
{"version":3,"file":"canDropItemOnFolder.mjs","sources":["../../../../admin/src/future/utils/canDropItemOnFolder.ts"],"sourcesContent":["import type { FolderNode } from '../../../../shared/contracts/folders';\nimport type { DragItemData } from '../types/dnd';\n\n// TODO: permission-aware droppables — server validates in v1.\n\nexport interface CanDropItemOnFolderParams {\n items: DragItemData[];\n targetFolderId: number | null;\n folderStructure: FolderNode[];\n}\n\nconst findNode = (nodes: FolderNode[], id: number): FolderNode | null => {\n for (const node of nodes) {\n if (node.id === id) {\n return node;\n }\n\n const found = findNode(node.children, id);\n if (found) {\n return found;\n }\n }\n\n return null;\n};\n\nconst collectDescendantIds = (node: FolderNode): Set<number> => {\n const ids = new Set<number>();\n\n const walk = (current: FolderNode) => {\n for (const child of current.children) {\n if (child.id != null) {\n ids.add(child.id);\n }\n walk(child);\n }\n };\n\n walk(node);\n return ids;\n};\n\nexport const isFolderDescendantOf = (\n folderStructure: FolderNode[],\n ancestorId: number,\n candidateId: number\n): boolean => {\n if (ancestorId === candidateId) {\n return true;\n }\n\n const ancestorNode = findNode(folderStructure, ancestorId);\n if (!ancestorNode) {\n return false;\n }\n\n return collectDescendantIds(ancestorNode).has(candidateId);\n};\n\nconst isItemAtRoot = (item: DragItemData): boolean =>\n item.kind === 'file' ? item.folderId == null : item.parentId == null;\n\nexport const canDropItemOnFolder = ({\n items,\n targetFolderId,\n folderStructure,\n}: CanDropItemOnFolderParams): boolean => {\n if (items.length === 0) {\n return false;\n }\n\n if (targetFolderId === null) {\n return items.some((item) => !isItemAtRoot(item));\n }\n\n const draggedFolderIds = new Set(\n items\n .filter((item): item is Extract<DragItemData, { kind: 'folder' }> => item.kind === 'folder')\n .map((item) => item.id)\n );\n\n if (draggedFolderIds.has(targetFolderId)) {\n return false;\n }\n\n for (const folderId of draggedFolderIds) {\n if (isFolderDescendantOf(folderStructure, folderId, targetFolderId)) {\n return false;\n }\n }\n\n for (const item of items) {\n if (item.kind === 'file' && item.folderId === targetFolderId) {\n return false;\n }\n\n if (item.kind === 'folder' && item.parentId === targetFolderId) {\n return false;\n }\n }\n\n return true;\n};\n"],"names":["findNode","nodes","id","node","found","children","collectDescendantIds","ids","Set","walk","current","child","add","isFolderDescendantOf","folderStructure","ancestorId","candidateId","ancestorNode","has","isItemAtRoot","item","kind","folderId","parentId","canDropItemOnFolder","items","targetFolderId","length","some","draggedFolderIds","filter","map"],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Flattens the nested folder structure (`/upload/folder-structure`) into a
|
|
5
|
+
* depth-first list of `{ id, label }` options where the label carries the full
|
|
6
|
+
* ancestry path. Used by destination selects so folders sharing a name stay
|
|
7
|
+
* distinguishable ("About / Images" vs "Tech / Images"), with children listed
|
|
8
|
+
* right under their parent.
|
|
9
|
+
*
|
|
10
|
+
* `excludeSubtreeIds` prunes a folder *and everything below it* in the same
|
|
11
|
+
* single pass — used to drop the selected folders (and their descendants) from
|
|
12
|
+
* bulk-move destinations without re-walking the tree per option.
|
|
13
|
+
*/ const flattenFolderStructure = (nodes, excludeSubtreeIds = new Set(), parentLabel = '')=>nodes.flatMap((node)=>{
|
|
14
|
+
if (node.id == null || excludeSubtreeIds.has(node.id)) {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
const label = parentLabel ? `${parentLabel} / ${node.name ?? ''}` : node.name ?? '';
|
|
18
|
+
return [
|
|
19
|
+
{
|
|
20
|
+
id: node.id,
|
|
21
|
+
label
|
|
22
|
+
},
|
|
23
|
+
...flattenFolderStructure(node.children ?? [], excludeSubtreeIds, label)
|
|
24
|
+
];
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
exports.flattenFolderStructure = flattenFolderStructure;
|
|
28
|
+
//# sourceMappingURL=flattenFolderStructure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flattenFolderStructure.js","sources":["../../../../admin/src/future/utils/flattenFolderStructure.ts"],"sourcesContent":["import type { FolderNode } from '../../../../shared/contracts/folders';\n\nexport interface FlatFolderOption {\n id: number;\n /** Full ancestry label, e.g. \"About / Images\". */\n label: string;\n}\n\n/**\n * Flattens the nested folder structure (`/upload/folder-structure`) into a\n * depth-first list of `{ id, label }` options where the label carries the full\n * ancestry path. Used by destination selects so folders sharing a name stay\n * distinguishable (\"About / Images\" vs \"Tech / Images\"), with children listed\n * right under their parent.\n *\n * `excludeSubtreeIds` prunes a folder *and everything below it* in the same\n * single pass — used to drop the selected folders (and their descendants) from\n * bulk-move destinations without re-walking the tree per option.\n */\nexport const flattenFolderStructure = (\n nodes: FolderNode[],\n excludeSubtreeIds: ReadonlySet<number> = new Set(),\n parentLabel = ''\n): FlatFolderOption[] =>\n nodes.flatMap((node) => {\n if (node.id == null || excludeSubtreeIds.has(node.id)) {\n return [];\n }\n\n const label = parentLabel ? `${parentLabel} / ${node.name ?? ''}` : (node.name ?? '');\n\n return [\n { id: node.id, label },\n ...flattenFolderStructure(node.children ?? [], excludeSubtreeIds, label),\n ];\n });\n"],"names":["flattenFolderStructure","nodes","excludeSubtreeIds","Set","parentLabel","flatMap","node","id","has","label","name","children"],"mappings":";;AAQA;;;;;;;;;;AAUC,IACM,MAAMA,sBAAAA,GAAyB,CACpCC,OACAC,iBAAAA,GAAyC,IAAIC,GAAAA,EAAK,EAClDC,cAAc,EAAE,GAEhBH,KAAAA,CAAMI,OAAO,CAAC,CAACC,IAAAA,GAAAA;QACb,IAAIA,IAAAA,CAAKC,EAAE,IAAI,IAAA,IAAQL,kBAAkBM,GAAG,CAACF,IAAAA,CAAKC,EAAE,CAAA,EAAG;AACrD,YAAA,OAAO,EAAE;AACX,QAAA;AAEA,QAAA,MAAME,KAAAA,GAAQL,WAAAA,GAAc,CAAA,EAAGA,WAAAA,CAAY,GAAG,EAAEE,IAAAA,CAAKI,IAAI,IAAI,EAAA,CAAA,CAAI,GAAIJ,IAAAA,CAAKI,IAAI,IAAI,EAAA;QAElF,OAAO;AACL,YAAA;AAAEH,gBAAAA,EAAAA,EAAID,KAAKC,EAAE;AAAEE,gBAAAA;AAAM,aAAA;AAClBT,YAAAA,GAAAA,sBAAAA,CAAuBM,IAAAA,CAAKK,QAAQ,IAAI,EAAE,EAAET,iBAAAA,EAAmBO,KAAAA;AACnE,SAAA;IACH,CAAA;;;;"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flattens the nested folder structure (`/upload/folder-structure`) into a
|
|
3
|
+
* depth-first list of `{ id, label }` options where the label carries the full
|
|
4
|
+
* ancestry path. Used by destination selects so folders sharing a name stay
|
|
5
|
+
* distinguishable ("About / Images" vs "Tech / Images"), with children listed
|
|
6
|
+
* right under their parent.
|
|
7
|
+
*
|
|
8
|
+
* `excludeSubtreeIds` prunes a folder *and everything below it* in the same
|
|
9
|
+
* single pass — used to drop the selected folders (and their descendants) from
|
|
10
|
+
* bulk-move destinations without re-walking the tree per option.
|
|
11
|
+
*/ const flattenFolderStructure = (nodes, excludeSubtreeIds = new Set(), parentLabel = '')=>nodes.flatMap((node)=>{
|
|
12
|
+
if (node.id == null || excludeSubtreeIds.has(node.id)) {
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
const label = parentLabel ? `${parentLabel} / ${node.name ?? ''}` : node.name ?? '';
|
|
16
|
+
return [
|
|
17
|
+
{
|
|
18
|
+
id: node.id,
|
|
19
|
+
label
|
|
20
|
+
},
|
|
21
|
+
...flattenFolderStructure(node.children ?? [], excludeSubtreeIds, label)
|
|
22
|
+
];
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export { flattenFolderStructure };
|
|
26
|
+
//# sourceMappingURL=flattenFolderStructure.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flattenFolderStructure.mjs","sources":["../../../../admin/src/future/utils/flattenFolderStructure.ts"],"sourcesContent":["import type { FolderNode } from '../../../../shared/contracts/folders';\n\nexport interface FlatFolderOption {\n id: number;\n /** Full ancestry label, e.g. \"About / Images\". */\n label: string;\n}\n\n/**\n * Flattens the nested folder structure (`/upload/folder-structure`) into a\n * depth-first list of `{ id, label }` options where the label carries the full\n * ancestry path. Used by destination selects so folders sharing a name stay\n * distinguishable (\"About / Images\" vs \"Tech / Images\"), with children listed\n * right under their parent.\n *\n * `excludeSubtreeIds` prunes a folder *and everything below it* in the same\n * single pass — used to drop the selected folders (and their descendants) from\n * bulk-move destinations without re-walking the tree per option.\n */\nexport const flattenFolderStructure = (\n nodes: FolderNode[],\n excludeSubtreeIds: ReadonlySet<number> = new Set(),\n parentLabel = ''\n): FlatFolderOption[] =>\n nodes.flatMap((node) => {\n if (node.id == null || excludeSubtreeIds.has(node.id)) {\n return [];\n }\n\n const label = parentLabel ? `${parentLabel} / ${node.name ?? ''}` : (node.name ?? '');\n\n return [\n { id: node.id, label },\n ...flattenFolderStructure(node.children ?? [], excludeSubtreeIds, label),\n ];\n });\n"],"names":["flattenFolderStructure","nodes","excludeSubtreeIds","Set","parentLabel","flatMap","node","id","has","label","name","children"],"mappings":"AAQA;;;;;;;;;;AAUC,IACM,MAAMA,sBAAAA,GAAyB,CACpCC,OACAC,iBAAAA,GAAyC,IAAIC,GAAAA,EAAK,EAClDC,cAAc,EAAE,GAEhBH,KAAAA,CAAMI,OAAO,CAAC,CAACC,IAAAA,GAAAA;QACb,IAAIA,IAAAA,CAAKC,EAAE,IAAI,IAAA,IAAQL,kBAAkBM,GAAG,CAACF,IAAAA,CAAKC,EAAE,CAAA,EAAG;AACrD,YAAA,OAAO,EAAE;AACX,QAAA;AAEA,QAAA,MAAME,KAAAA,GAAQL,WAAAA,GAAc,CAAA,EAAGA,WAAAA,CAAY,GAAG,EAAEE,IAAAA,CAAKI,IAAI,IAAI,EAAA,CAAA,CAAI,GAAIJ,IAAAA,CAAKI,IAAI,IAAI,EAAA;QAElF,OAAO;AACL,YAAA;AAAEH,gBAAAA,EAAAA,EAAID,KAAKC,EAAE;AAAEE,gBAAAA;AAAM,aAAA;AAClBT,YAAAA,GAAAA,sBAAAA,CAAuBM,IAAAA,CAAKK,QAAQ,IAAI,EAAE,EAAET,iBAAAA,EAAmBO,KAAAA;AACnE,SAAA;IACH,CAAA;;;;"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var translations = require('./translations.js');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Single source of truth for the bulk-move success wording. Both the DnD drop
|
|
7
|
+
* and the BulkMoveDialog format the toast (and DnD live-region announcement)
|
|
8
|
+
* through here so the two paths stay identical for the same move.
|
|
9
|
+
*/ const formatMoveSuccessMessage = ({ formatMessage, count, source, destination })=>formatMessage({
|
|
10
|
+
id: translations.getTranslationKey('list.bulk-actions.move.success'),
|
|
11
|
+
defaultMessage: '{count, plural, =1 {# element has} other {# elements have}} been moved from {source} to {destination}'
|
|
12
|
+
}, {
|
|
13
|
+
count,
|
|
14
|
+
source,
|
|
15
|
+
destination
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
exports.formatMoveSuccessMessage = formatMoveSuccessMessage;
|
|
19
|
+
//# sourceMappingURL=formatMoveSuccessMessage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatMoveSuccessMessage.js","sources":["../../../../admin/src/future/utils/formatMoveSuccessMessage.ts"],"sourcesContent":["import { getTranslationKey } from './translations';\n\nimport type { IntlShape } from 'react-intl';\n\ninterface FormatMoveSuccessArgs {\n formatMessage: IntlShape['formatMessage'];\n count: number;\n source: string;\n destination: string;\n}\n\n/**\n * Single source of truth for the bulk-move success wording. Both the DnD drop\n * and the BulkMoveDialog format the toast (and DnD live-region announcement)\n * through here so the two paths stay identical for the same move.\n */\nexport const formatMoveSuccessMessage = ({\n formatMessage,\n count,\n source,\n destination,\n}: FormatMoveSuccessArgs): string =>\n formatMessage(\n {\n id: getTranslationKey('list.bulk-actions.move.success'),\n defaultMessage:\n '{count, plural, =1 {# element has} other {# elements have}} been moved from {source} to {destination}',\n },\n { count, source, destination }\n );\n"],"names":["formatMoveSuccessMessage","formatMessage","count","source","destination","id","getTranslationKey","defaultMessage"],"mappings":";;;;AAWA;;;;AAIC,IACM,MAAMA,wBAAAA,GAA2B,CAAC,EACvCC,aAAa,EACbC,KAAK,EACLC,MAAM,EACNC,WAAW,EACW,GACtBH,aAAAA,CACE;AACEI,QAAAA,EAAAA,EAAIC,8BAAAA,CAAkB,gCAAA,CAAA;QACtBC,cAAAA,EACE;KACJ,EACA;AAAEL,QAAAA,KAAAA;AAAOC,QAAAA,MAAAA;AAAQC,QAAAA;KAAY;;;;"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { getTranslationKey } from './translations.mjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Single source of truth for the bulk-move success wording. Both the DnD drop
|
|
5
|
+
* and the BulkMoveDialog format the toast (and DnD live-region announcement)
|
|
6
|
+
* through here so the two paths stay identical for the same move.
|
|
7
|
+
*/ const formatMoveSuccessMessage = ({ formatMessage, count, source, destination })=>formatMessage({
|
|
8
|
+
id: getTranslationKey('list.bulk-actions.move.success'),
|
|
9
|
+
defaultMessage: '{count, plural, =1 {# element has} other {# elements have}} been moved from {source} to {destination}'
|
|
10
|
+
}, {
|
|
11
|
+
count,
|
|
12
|
+
source,
|
|
13
|
+
destination
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export { formatMoveSuccessMessage };
|
|
17
|
+
//# sourceMappingURL=formatMoveSuccessMessage.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatMoveSuccessMessage.mjs","sources":["../../../../admin/src/future/utils/formatMoveSuccessMessage.ts"],"sourcesContent":["import { getTranslationKey } from './translations';\n\nimport type { IntlShape } from 'react-intl';\n\ninterface FormatMoveSuccessArgs {\n formatMessage: IntlShape['formatMessage'];\n count: number;\n source: string;\n destination: string;\n}\n\n/**\n * Single source of truth for the bulk-move success wording. Both the DnD drop\n * and the BulkMoveDialog format the toast (and DnD live-region announcement)\n * through here so the two paths stay identical for the same move.\n */\nexport const formatMoveSuccessMessage = ({\n formatMessage,\n count,\n source,\n destination,\n}: FormatMoveSuccessArgs): string =>\n formatMessage(\n {\n id: getTranslationKey('list.bulk-actions.move.success'),\n defaultMessage:\n '{count, plural, =1 {# element has} other {# elements have}} been moved from {source} to {destination}',\n },\n { count, source, destination }\n );\n"],"names":["formatMoveSuccessMessage","formatMessage","count","source","destination","id","getTranslationKey","defaultMessage"],"mappings":";;AAWA;;;;AAIC,IACM,MAAMA,wBAAAA,GAA2B,CAAC,EACvCC,aAAa,EACbC,KAAK,EACLC,MAAM,EACNC,WAAW,EACW,GACtBH,aAAAA,CACE;AACEI,QAAAA,EAAAA,EAAIC,iBAAAA,CAAkB,gCAAA,CAAA;QACtBC,cAAAA,EACE;KACJ,EACA;AAAEL,QAAAA,KAAAA;AAAOC,QAAAA,MAAAA;AAAQC,QAAAA;KAAY;;;;"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Leaf display name for a folder id. `null` (root) → the Media Library label.
|
|
5
|
+
* Used by both the DnD success toast and the dialog success toast so the two
|
|
6
|
+
* paths name folders identically. Ancestry paths belong only in the dialog's
|
|
7
|
+
* select options (see `flattenFolderStructure`).
|
|
8
|
+
*
|
|
9
|
+
* `id === null` returns `rootLabel`; an unknown id falls back to `rootLabel`
|
|
10
|
+
* too (defensive — mirrors the dialog's previous `?? rootLabel`).
|
|
11
|
+
*/ const getFolderLabel = (folderStructure, id, rootLabel)=>{
|
|
12
|
+
if (id === null) {
|
|
13
|
+
return rootLabel;
|
|
14
|
+
}
|
|
15
|
+
const findNode = (nodes)=>{
|
|
16
|
+
for (const node of nodes){
|
|
17
|
+
if (node.id === id) {
|
|
18
|
+
return node;
|
|
19
|
+
}
|
|
20
|
+
const found = findNode(node.children ?? []);
|
|
21
|
+
if (found) {
|
|
22
|
+
return found;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
};
|
|
27
|
+
return findNode(folderStructure)?.name ?? rootLabel;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
exports.getFolderLabel = getFolderLabel;
|
|
31
|
+
//# sourceMappingURL=getFolderLabel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getFolderLabel.js","sources":["../../../../admin/src/future/utils/getFolderLabel.ts"],"sourcesContent":["import type { FolderNode } from '../../../../shared/contracts/folders';\n\n/**\n * Leaf display name for a folder id. `null` (root) → the Media Library label.\n * Used by both the DnD success toast and the dialog success toast so the two\n * paths name folders identically. Ancestry paths belong only in the dialog's\n * select options (see `flattenFolderStructure`).\n *\n * `id === null` returns `rootLabel`; an unknown id falls back to `rootLabel`\n * too (defensive — mirrors the dialog's previous `?? rootLabel`).\n */\nexport const getFolderLabel = (\n folderStructure: FolderNode[],\n id: number | null,\n rootLabel: string\n): string => {\n if (id === null) {\n return rootLabel;\n }\n\n const findNode = (nodes: FolderNode[]): FolderNode | null => {\n for (const node of nodes) {\n if (node.id === id) {\n return node;\n }\n\n const found = findNode(node.children ?? []);\n if (found) {\n return found;\n }\n }\n\n return null;\n };\n\n return findNode(folderStructure)?.name ?? rootLabel;\n};\n"],"names":["getFolderLabel","folderStructure","id","rootLabel","findNode","nodes","node","found","children","name"],"mappings":";;AAEA;;;;;;;;AAQC,IACM,MAAMA,cAAAA,GAAiB,CAC5BC,iBACAC,EAAAA,EACAC,SAAAA,GAAAA;AAEA,IAAA,IAAID,OAAO,IAAA,EAAM;QACf,OAAOC,SAAAA;AACT,IAAA;AAEA,IAAA,MAAMC,WAAW,CAACC,KAAAA,GAAAA;QAChB,KAAK,MAAMC,QAAQD,KAAAA,CAAO;YACxB,IAAIC,IAAAA,CAAKJ,EAAE,KAAKA,EAAAA,EAAI;gBAClB,OAAOI,IAAAA;AACT,YAAA;AAEA,YAAA,MAAMC,KAAAA,GAAQH,QAAAA,CAASE,IAAAA,CAAKE,QAAQ,IAAI,EAAE,CAAA;AAC1C,YAAA,IAAID,KAAAA,EAAO;gBACT,OAAOA,KAAAA;AACT,YAAA;AACF,QAAA;QAEA,OAAO,IAAA;AACT,IAAA,CAAA;IAEA,OAAOH,QAAAA,CAASH,kBAAkBQ,IAAAA,IAAQN,SAAAA;AAC5C;;;;"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Leaf display name for a folder id. `null` (root) → the Media Library label.
|
|
3
|
+
* Used by both the DnD success toast and the dialog success toast so the two
|
|
4
|
+
* paths name folders identically. Ancestry paths belong only in the dialog's
|
|
5
|
+
* select options (see `flattenFolderStructure`).
|
|
6
|
+
*
|
|
7
|
+
* `id === null` returns `rootLabel`; an unknown id falls back to `rootLabel`
|
|
8
|
+
* too (defensive — mirrors the dialog's previous `?? rootLabel`).
|
|
9
|
+
*/ const getFolderLabel = (folderStructure, id, rootLabel)=>{
|
|
10
|
+
if (id === null) {
|
|
11
|
+
return rootLabel;
|
|
12
|
+
}
|
|
13
|
+
const findNode = (nodes)=>{
|
|
14
|
+
for (const node of nodes){
|
|
15
|
+
if (node.id === id) {
|
|
16
|
+
return node;
|
|
17
|
+
}
|
|
18
|
+
const found = findNode(node.children ?? []);
|
|
19
|
+
if (found) {
|
|
20
|
+
return found;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
};
|
|
25
|
+
return findNode(folderStructure)?.name ?? rootLabel;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export { getFolderLabel };
|
|
29
|
+
//# sourceMappingURL=getFolderLabel.mjs.map
|