@strapi/upload 5.51.0 → 5.51.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/components/AssetCard/VideoPreview.js +1 -1
- package/dist/admin/components/AssetCard/VideoPreview.js.map +1 -1
- package/dist/admin/components/AssetCard/VideoPreview.mjs +1 -1
- package/dist/admin/components/AssetCard/VideoPreview.mjs.map +1 -1
- package/dist/admin/components/TableList/TableList.js +1 -1
- package/dist/admin/components/TableList/TableList.js.map +1 -1
- package/dist/admin/components/TableList/TableList.mjs +1 -1
- package/dist/admin/components/TableList/TableList.mjs.map +1 -1
- package/dist/admin/components/UploadAssetDialog/AddAssetStep/FromUrlForm.js +21 -4
- package/dist/admin/components/UploadAssetDialog/AddAssetStep/FromUrlForm.js.map +1 -1
- package/dist/admin/components/UploadAssetDialog/AddAssetStep/FromUrlForm.mjs +21 -4
- package/dist/admin/components/UploadAssetDialog/AddAssetStep/FromUrlForm.mjs.map +1 -1
- package/dist/admin/future/components/Drawer.js +3 -1
- package/dist/admin/future/components/Drawer.js.map +1 -1
- package/dist/admin/future/components/Drawer.mjs +3 -1
- package/dist/admin/future/components/Drawer.mjs.map +1 -1
- package/dist/admin/future/components/UploadProgressDialog.js +200 -27
- package/dist/admin/future/components/UploadProgressDialog.js.map +1 -1
- package/dist/admin/future/components/UploadProgressDialog.mjs +203 -30
- package/dist/admin/future/components/UploadProgressDialog.mjs.map +1 -1
- package/dist/admin/future/hooks/useMediaLibraryPermissions.js +35 -0
- package/dist/admin/future/hooks/useMediaLibraryPermissions.js.map +1 -0
- package/dist/admin/future/hooks/useMediaLibraryPermissions.mjs +33 -0
- package/dist/admin/future/hooks/useMediaLibraryPermissions.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/AssetsPage.js +344 -150
- package/dist/admin/future/pages/Assets/AssetsPage.js.map +1 -1
- package/dist/admin/future/pages/Assets/AssetsPage.mjs +343 -149
- package/dist/admin/future/pages/Assets/AssetsPage.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetCropEditor.js +75 -32
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetCropEditor.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetCropEditor.mjs +75 -32
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetCropEditor.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js +46 -19
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs +47 -20
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsGrid.js +161 -19
- package/dist/admin/future/pages/Assets/components/AssetsGrid.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs +162 -20
- package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsSearchInput.js +100 -0
- package/dist/admin/future/pages/Assets/components/AssetsSearchInput.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/AssetsSearchInput.mjs +98 -0
- package/dist/admin/future/pages/Assets/components/AssetsSearchInput.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/components/AssetsTable.js +218 -37
- package/dist/admin/future/pages/Assets/components/AssetsTable.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsTable.mjs +219 -38
- package/dist/admin/future/pages/Assets/components/AssetsTable.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/BulkActionsBar.js +370 -0
- package/dist/admin/future/pages/Assets/components/BulkActionsBar.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/BulkActionsBar.mjs +368 -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/DateRangeCalendar.js +193 -0
- package/dist/admin/future/pages/Assets/components/DateRangeCalendar.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/DateRangeCalendar.mjs +191 -0
- package/dist/admin/future/pages/Assets/components/DateRangeCalendar.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.js +129 -37
- package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.mjs +131 -39
- 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/DropZone/UploadDropZoneContext.js +13 -3
- package/dist/admin/future/pages/Assets/components/DropZone/UploadDropZoneContext.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/DropZone/UploadDropZoneContext.mjs +13 -3
- package/dist/admin/future/pages/Assets/components/DropZone/UploadDropZoneContext.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/EmptyState.js +62 -3
- package/dist/admin/future/pages/Assets/components/EmptyState.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/EmptyState.mjs +62 -4
- package/dist/admin/future/pages/Assets/components/EmptyState.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/FilterBadges.js +408 -0
- package/dist/admin/future/pages/Assets/components/FilterBadges.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/FilterBadges.mjs +406 -0
- package/dist/admin/future/pages/Assets/components/FilterBadges.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/components/FilterMenu.js +273 -0
- package/dist/admin/future/pages/Assets/components/FilterMenu.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/FilterMenu.mjs +267 -0
- package/dist/admin/future/pages/Assets/components/FilterMenu.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js +195 -40
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs +198 -43
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderTree/filterFolderTree.js +33 -0
- package/dist/admin/future/pages/Assets/components/FolderTree/filterFolderTree.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/FolderTree/filterFolderTree.mjs +31 -0
- package/dist/admin/future/pages/Assets/components/FolderTree/filterFolderTree.mjs.map +1 -0
- 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 +154 -0
- package/dist/admin/future/pages/Assets/components/SortMenu.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/SortMenu.mjs +152 -0
- package/dist/admin/future/pages/Assets/components/SortMenu.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/hooks/useAssetSearch.js +40 -0
- package/dist/admin/future/pages/Assets/hooks/useAssetSearch.js.map +1 -0
- package/dist/admin/future/pages/Assets/hooks/useAssetSearch.mjs +38 -0
- package/dist/admin/future/pages/Assets/hooks/useAssetSearch.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.js +75 -0
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.js.map +1 -0
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.mjs +71 -0
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/hooks/useFolderNavigation.js +33 -12
- package/dist/admin/future/pages/Assets/hooks/useFolderNavigation.js.map +1 -1
- package/dist/admin/future/pages/Assets/hooks/useFolderNavigation.mjs +33 -12
- package/dist/admin/future/pages/Assets/hooks/useFolderNavigation.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.js +40 -4
- package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.js.map +1 -1
- package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.mjs +40 -4
- package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/hooks/useListFilters.js +168 -0
- package/dist/admin/future/pages/Assets/hooks/useListFilters.js.map +1 -0
- package/dist/admin/future/pages/Assets/hooks/useListFilters.mjs +162 -0
- package/dist/admin/future/pages/Assets/hooks/useListFilters.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/buildAssetFilters.js +201 -0
- package/dist/admin/future/pages/Assets/utils/buildAssetFilters.js.map +1 -0
- package/dist/admin/future/pages/Assets/utils/buildAssetFilters.mjs +198 -0
- package/dist/admin/future/pages/Assets/utils/buildAssetFilters.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/api.js +163 -28
- package/dist/admin/future/services/api.js.map +1 -1
- package/dist/admin/future/services/api.mjs +163 -30
- package/dist/admin/future/services/api.mjs.map +1 -1
- package/dist/admin/future/services/assets.js +62 -18
- package/dist/admin/future/services/assets.js.map +1 -1
- package/dist/admin/future/services/assets.mjs +62 -19
- package/dist/admin/future/services/assets.mjs.map +1 -1
- package/dist/admin/future/services/folders.js +31 -19
- package/dist/admin/future/services/folders.js.map +1 -1
- package/dist/admin/future/services/folders.mjs +31 -19
- package/dist/admin/future/services/folders.mjs.map +1 -1
- package/dist/admin/future/services/settings.js +10 -3
- package/dist/admin/future/services/settings.js.map +1 -1
- package/dist/admin/future/services/settings.mjs +10 -3
- package/dist/admin/future/services/settings.mjs.map +1 -1
- package/dist/admin/future/store/uploadProgress.js +109 -2
- package/dist/admin/future/store/uploadProgress.js.map +1 -1
- package/dist/admin/future/store/uploadProgress.mjs +105 -3
- package/dist/admin/future/store/uploadProgress.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/future/utils/searchQueryParam.js +11 -0
- package/dist/admin/future/utils/searchQueryParam.js.map +1 -0
- package/dist/admin/future/utils/searchQueryParam.mjs +9 -0
- package/dist/admin/future/utils/searchQueryParam.mjs.map +1 -0
- package/dist/admin/hooks/useSelectionState.js +2 -4
- package/dist/admin/hooks/useSelectionState.js.map +1 -1
- package/dist/admin/hooks/useSelectionState.mjs +2 -4
- package/dist/admin/hooks/useSelectionState.mjs.map +1 -1
- package/dist/admin/shared/constants.js +43 -0
- package/dist/admin/shared/constants.js.map +1 -0
- package/dist/admin/shared/constants.mjs +38 -0
- package/dist/admin/shared/constants.mjs.map +1 -0
- package/dist/admin/src/future/hooks/useMediaLibraryPermissions.d.ts +21 -0
- package/dist/admin/src/future/pages/Assets/components/AssetDetails/AssetCropEditor.d.ts +7 -1
- package/dist/admin/src/future/pages/Assets/components/AssetsSearchInput.d.ts +5 -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 +14 -0
- package/dist/admin/src/future/pages/Assets/components/BulkMoveDialog.d.ts +13 -0
- package/dist/admin/src/future/pages/Assets/components/DateRangeCalendar.d.ts +8 -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/DropZone/UploadDropZoneContext.d.ts +8 -1
- package/dist/admin/src/future/pages/Assets/components/EmptyState.d.ts +18 -1
- package/dist/admin/src/future/pages/Assets/components/FilterBadges.d.ts +6 -0
- package/dist/admin/src/future/pages/Assets/components/FilterMenu.d.ts +22 -0
- package/dist/admin/src/future/pages/Assets/components/FolderTree/FolderTree.d.ts +13 -4
- package/dist/admin/src/future/pages/Assets/components/FolderTree/filterFolderTree.d.ts +16 -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 +23 -0
- package/dist/admin/src/future/pages/Assets/hooks/useAssetSearch.d.ts +12 -0
- package/dist/admin/src/future/pages/Assets/hooks/useAssetSelection.d.ts +46 -0
- package/dist/admin/src/future/pages/Assets/hooks/useInfiniteAssets.d.ts +13 -3
- package/dist/admin/src/future/pages/Assets/hooks/useListFilters.d.ts +69 -0
- package/dist/admin/src/future/pages/Assets/hooks/useListSort.d.ts +47 -0
- package/dist/admin/src/future/pages/Assets/utils/buildAssetFilters.d.ts +46 -0
- package/dist/admin/src/future/pages/Assets/utils/listQueryKey.d.ts +29 -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/api.d.ts +53 -5
- package/dist/admin/src/future/services/assets.d.ts +13 -2
- package/dist/admin/src/future/services/folders.d.ts +7 -1
- package/dist/admin/src/future/services/settings.d.ts +2 -2
- package/dist/admin/src/future/store/uploadProgress.d.ts +83 -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/src/future/utils/searchQueryParam.d.ts +7 -0
- package/dist/admin/src/hooks/useAiAvailability.d.ts +1 -1
- package/dist/admin/src/hooks/useEditAsset.d.ts +4 -4
- package/dist/admin/src/hooks/useEditFolder.d.ts +4 -4
- package/dist/admin/src/hooks/useSettings.d.ts +1 -0
- package/dist/admin/src/hooks/useTracking.d.ts +1 -1
- package/dist/admin/src/hooks/useUpload.d.ts +1 -1
- package/dist/admin/translations/en.json.js +85 -2
- package/dist/admin/translations/en.json.js.map +1 -1
- package/dist/admin/translations/en.json.mjs +85 -2
- package/dist/admin/translations/en.json.mjs.map +1 -1
- package/dist/admin/utils/urlYupSchema.js +33 -9
- package/dist/admin/utils/urlYupSchema.js.map +1 -1
- package/dist/admin/utils/urlYupSchema.mjs +33 -9
- package/dist/admin/utils/urlYupSchema.mjs.map +1 -1
- package/dist/server/config.js +13 -5
- package/dist/server/config.js.map +1 -1
- package/dist/server/config.mjs +13 -5
- package/dist/server/config.mjs.map +1 -1
- package/dist/server/constants.js.map +1 -1
- package/dist/server/constants.mjs.map +1 -1
- package/dist/server/controllers/admin-file.js +30 -0
- package/dist/server/controllers/admin-file.js.map +1 -1
- package/dist/server/controllers/admin-file.mjs +30 -0
- package/dist/server/controllers/admin-file.mjs.map +1 -1
- package/dist/server/controllers/admin-settings.js +20 -2
- package/dist/server/controllers/admin-settings.js.map +1 -1
- package/dist/server/controllers/admin-settings.mjs +21 -3
- package/dist/server/controllers/admin-settings.mjs.map +1 -1
- package/dist/server/controllers/content-api.js +1 -2
- package/dist/server/controllers/content-api.js.map +1 -1
- package/dist/server/controllers/content-api.mjs +2 -2
- package/dist/server/controllers/content-api.mjs.map +1 -1
- package/dist/server/controllers/validation/admin/ai-metadata.js +12 -0
- package/dist/server/controllers/validation/admin/ai-metadata.js.map +1 -0
- package/dist/server/controllers/validation/admin/ai-metadata.mjs +10 -0
- package/dist/server/controllers/validation/admin/ai-metadata.mjs.map +1 -0
- package/dist/server/controllers/validation/admin/settings.js +4 -1
- package/dist/server/controllers/validation/admin/settings.js.map +1 -1
- package/dist/server/controllers/validation/admin/settings.mjs +1 -1
- package/dist/server/controllers/validation/admin/settings.mjs.map +1 -1
- package/dist/server/routes/admin.js +18 -0
- package/dist/server/routes/admin.js.map +1 -1
- package/dist/server/routes/admin.mjs +18 -0
- package/dist/server/routes/admin.mjs.map +1 -1
- package/dist/server/services/ai-metadata.js +108 -11
- package/dist/server/services/ai-metadata.js.map +1 -1
- package/dist/server/services/ai-metadata.mjs +108 -11
- package/dist/server/services/ai-metadata.mjs.map +1 -1
- package/dist/server/services/file.js +86 -13
- package/dist/server/services/file.js.map +1 -1
- package/dist/server/services/file.mjs +87 -14
- package/dist/server/services/file.mjs.map +1 -1
- package/dist/server/services/image-manipulation.js +4 -4
- package/dist/server/services/image-manipulation.js.map +1 -1
- package/dist/server/services/image-manipulation.mjs +4 -4
- package/dist/server/services/image-manipulation.mjs.map +1 -1
- package/dist/server/shared/constants.js +43 -0
- package/dist/server/shared/constants.js.map +1 -0
- package/dist/server/shared/constants.mjs +38 -0
- package/dist/server/shared/constants.mjs.map +1 -0
- package/dist/server/src/config.d.ts +2 -0
- package/dist/server/src/config.d.ts.map +1 -1
- package/dist/server/src/constants.d.ts +2 -1
- package/dist/server/src/constants.d.ts.map +1 -1
- package/dist/server/src/controllers/admin-file.d.ts +10 -0
- package/dist/server/src/controllers/admin-file.d.ts.map +1 -1
- package/dist/server/src/controllers/admin-settings.d.ts.map +1 -1
- package/dist/server/src/controllers/index.d.ts +1 -0
- package/dist/server/src/controllers/index.d.ts.map +1 -1
- package/dist/server/src/controllers/validation/admin/ai-metadata.d.ts +2 -0
- package/dist/server/src/controllers/validation/admin/ai-metadata.d.ts.map +1 -0
- package/dist/server/src/controllers/validation/admin/settings.d.ts +1 -1
- package/dist/server/src/controllers/validation/admin/settings.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +7 -1
- package/dist/server/src/index.d.ts.map +1 -1
- package/dist/server/src/routes/admin.d.ts.map +1 -1
- package/dist/server/src/services/ai-metadata.d.ts +19 -0
- package/dist/server/src/services/ai-metadata.d.ts.map +1 -1
- package/dist/server/src/services/file.d.ts +12 -2
- package/dist/server/src/services/file.d.ts.map +1 -1
- package/dist/server/src/services/index.d.ts +4 -1
- package/dist/server/src/services/index.d.ts.map +1 -1
- package/dist/server/src/types.d.ts +3 -0
- package/dist/server/src/types.d.ts.map +1 -1
- package/dist/shared/constants.d.ts +35 -0
- package/dist/shared/constants.d.ts.map +1 -0
- package/dist/shared/contracts/files.d.ts +25 -0
- package/dist/shared/contracts/files.d.ts.map +1 -1
- package/dist/shared/contracts/folders.d.ts +1 -1
- package/dist/shared/contracts/settings.d.ts +7 -0
- package/package.json +8 -8
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useListSort.mjs","sources":["../../../../../../admin/src/future/pages/Assets/hooks/useListSort.ts"],"sourcesContent":["import { useQueryParams } from '@strapi/admin/strapi-admin';\n\n/**\n * Sort state for the assets list, backed by URL query params so the current\n * ordering is shareable and survives Back/refresh:\n *\n * - `?sort=<rule>` — a single whitelisted rule. Omitted → default (most\n * recent updates).\n * - `?folders=mixed` — folders interleaved with files. Omitted → folders on top.\n *\n * The date rules and the direction rules are mutually exclusive: exactly one\n * rule is active at a time (one checkmark total, like the design mock). Picking\n * an option in one group clears the other; clearing the active option falls\n * back to the default — an unsorted list is not a state the UI offers.\n */\n\nexport const SORT_BY_RULES = {\n oldestUploads: 'createdAt:ASC',\n mostRecentUpdates: 'updatedAt:DESC',\n} as const;\n\nexport const SORT_DIRECTION_RULES = {\n nameAsc: 'name:ASC',\n nameDesc: 'name:DESC',\n sizeAsc: 'size:ASC',\n sizeDesc: 'size:DESC',\n} as const;\n\nexport type SortByKey = keyof typeof SORT_BY_RULES;\nexport type SortDirectionKey = keyof typeof SORT_DIRECTION_RULES;\nexport type FoldersPosition = 'top' | 'mixed';\n\nconst DEFAULT_SORT_BY: SortByKey = 'mostRecentUpdates';\n\nconst SORT_BY_BY_RULE = Object.fromEntries(\n Object.entries(SORT_BY_RULES).map(([key, rule]) => [rule, key])\n) as Record<string, SortByKey>;\n\nconst SORT_DIRECTION_BY_RULE = Object.fromEntries(\n Object.entries(SORT_DIRECTION_RULES).map(([key, rule]) => [rule, key])\n) as Record<string, SortDirectionKey>;\n\ninterface ParsedSort {\n sortBy: SortByKey | null;\n direction: SortDirectionKey | null;\n /** False when the state is the fallback default (no recognized rule in the URL). */\n isExplicit: boolean;\n}\n\n/** Parses `?sort=` — the first recognized rule wins, unknown rules are dropped. */\nconst parseSortParam = (raw: string | undefined): ParsedSort => {\n for (const rule of (raw ?? '').split(',')) {\n if (rule in SORT_BY_BY_RULE) {\n return { sortBy: SORT_BY_BY_RULE[rule], direction: null, isExplicit: true };\n }\n if (rule in SORT_DIRECTION_BY_RULE) {\n return { sortBy: null, direction: SORT_DIRECTION_BY_RULE[rule], isExplicit: true };\n }\n }\n\n return { sortBy: DEFAULT_SORT_BY, direction: null, isExplicit: false };\n};\n\nconst serializeSort = (sortBy: SortByKey | null, direction: SortDirectionKey | null): string => {\n const rules: (string | null)[] = [\n sortBy && SORT_BY_RULES[sortBy],\n direction && SORT_DIRECTION_RULES[direction],\n ];\n\n return rules.filter((rule): rule is string => Boolean(rule)).join(',');\n};\n\nexport interface ListSort {\n sortBy: SortByKey | null;\n direction: SortDirectionKey | null;\n foldersPosition: FoldersPosition;\n /**\n * The active rule for the files query, e.g. `updatedAt:DESC` — always a\n * single rule since the sort groups are mutually exclusive.\n */\n assetsSort: string;\n /**\n * Rule applicable to the folders query. In the default state (no sort in the\n * URL) folders keep their alphabetical order so the band matches the sidebar\n * tree; an explicit user sort applies, except size rules (folders have no\n * `size` column), which fall back to alphabetical.\n */\n foldersSort: string;\n setSortBy: (key: SortByKey | null) => void;\n setDirection: (key: SortDirectionKey | null) => void;\n setFoldersPosition: (position: FoldersPosition) => void;\n}\n\nexport const useListSort = (): ListSort => {\n const [{ query }, setQuery] = useQueryParams<{ sort?: string; folders?: string }>();\n\n const { sortBy, direction, isExplicit } = parseSortParam(query?.sort);\n const foldersPosition: FoldersPosition = query?.folders === 'mixed' ? 'mixed' : 'top';\n\n const writeSort = (nextSortBy: SortByKey | null, nextDirection: SortDirectionKey | null) => {\n // Exactly one active rule: clearing the active one falls back to default.\n if (nextSortBy === null && nextDirection === null) {\n nextSortBy = DEFAULT_SORT_BY;\n }\n\n const serialized = serializeSort(nextSortBy, nextDirection);\n\n if (nextSortBy === DEFAULT_SORT_BY && nextDirection === null) {\n setQuery({ sort: '' }, 'remove');\n } else {\n setQuery({ sort: serialized });\n }\n };\n\n // Groups are mutually exclusive — picking in one clears the other.\n const setSortBy = (key: SortByKey | null) => writeSort(key, null);\n const setDirection = (key: SortDirectionKey | null) => writeSort(null, key);\n\n const setFoldersPosition = (position: FoldersPosition) => {\n if (position === 'mixed') {\n setQuery({ folders: 'mixed' });\n } else {\n setQuery({ folders: '' }, 'remove');\n }\n };\n\n const assetsSort = serializeSort(sortBy, direction);\n const folderRuleCandidates: (string | null)[] = [\n sortBy && SORT_BY_RULES[sortBy],\n direction && !direction.startsWith('size') ? SORT_DIRECTION_RULES[direction] : null,\n ];\n const folderRules = folderRuleCandidates.filter((rule): rule is string => Boolean(rule));\n // Default state keeps folders alphabetical (matches the sidebar tree) — only\n // an explicit user sort reorders the folders band.\n const foldersSort = isExplicit && folderRules.length > 0 ? folderRules.join(',') : 'name:ASC';\n\n return {\n sortBy,\n direction,\n foldersPosition,\n assetsSort,\n foldersSort,\n setSortBy,\n setDirection,\n setFoldersPosition,\n };\n};\n"],"names":["SORT_BY_RULES","oldestUploads","mostRecentUpdates","SORT_DIRECTION_RULES","nameAsc","nameDesc","sizeAsc","sizeDesc","DEFAULT_SORT_BY","SORT_BY_BY_RULE","Object","fromEntries","entries","map","key","rule","SORT_DIRECTION_BY_RULE","parseSortParam","raw","split","sortBy","direction","isExplicit","serializeSort","rules","filter","Boolean","join","useListSort","query","setQuery","useQueryParams","sort","foldersPosition","folders","writeSort","nextSortBy","nextDirection","serialized","setSortBy","setDirection","setFoldersPosition","position","assetsSort","folderRuleCandidates","startsWith","folderRules","foldersSort","length"],"mappings":"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"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const MIME_BY_VALUE = {
|
|
4
|
+
picture: 'image',
|
|
5
|
+
audio: 'audio',
|
|
6
|
+
video: 'video'
|
|
7
|
+
};
|
|
8
|
+
const ALL_MIMES = Object.values(MIME_BY_VALUE);
|
|
9
|
+
const PRESET_DELTAS = {
|
|
10
|
+
'1day': {
|
|
11
|
+
days: 1
|
|
12
|
+
},
|
|
13
|
+
'3days': {
|
|
14
|
+
days: 3
|
|
15
|
+
},
|
|
16
|
+
'1week': {
|
|
17
|
+
days: 7
|
|
18
|
+
},
|
|
19
|
+
'1month': {
|
|
20
|
+
months: 1
|
|
21
|
+
},
|
|
22
|
+
'3months': {
|
|
23
|
+
months: 3
|
|
24
|
+
},
|
|
25
|
+
'6months': {
|
|
26
|
+
months: 6
|
|
27
|
+
},
|
|
28
|
+
'1year': {
|
|
29
|
+
years: 1
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
const subtractPreset = (now, preset)=>{
|
|
33
|
+
const { days = 0, months = 0, years = 0 } = PRESET_DELTAS[preset];
|
|
34
|
+
const result = new Date(now.getTime());
|
|
35
|
+
if (years || months) {
|
|
36
|
+
// JS date setters overflow at month ends (Mar 31 − 1 month → Feb 31 → Mar 3),
|
|
37
|
+
// so move to the 1st first and clamp the day to the target month's length.
|
|
38
|
+
const dayOfMonth = result.getDate();
|
|
39
|
+
result.setDate(1);
|
|
40
|
+
result.setFullYear(result.getFullYear() - years);
|
|
41
|
+
result.setMonth(result.getMonth() - months);
|
|
42
|
+
const daysInTargetMonth = new Date(result.getFullYear(), result.getMonth() + 1, 0).getDate();
|
|
43
|
+
result.setDate(Math.min(dayOfMonth, daysInTargetMonth));
|
|
44
|
+
}
|
|
45
|
+
result.setDate(result.getDate() - days);
|
|
46
|
+
return result;
|
|
47
|
+
};
|
|
48
|
+
const startOfDay = (date)=>{
|
|
49
|
+
const result = new Date(date.getTime());
|
|
50
|
+
result.setHours(0, 0, 0, 0);
|
|
51
|
+
return result;
|
|
52
|
+
};
|
|
53
|
+
const endOfDay = (date)=>{
|
|
54
|
+
const result = new Date(date.getTime());
|
|
55
|
+
result.setHours(23, 59, 59, 999);
|
|
56
|
+
return result;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Parses `YYYY-MM-DD` as a local calendar date — NOT `new Date(value)`, which
|
|
60
|
+
* treats date-only strings as UTC midnight and shifts the day in every
|
|
61
|
+
* timezone west of UTC. Shared by the query builder, the badge labels and the
|
|
62
|
+
* range calendar so all three agree on which day a range endpoint means.
|
|
63
|
+
*/ const parseCalendarDate = (value)=>{
|
|
64
|
+
const [year, month, day] = value.split('-').map(Number);
|
|
65
|
+
return new Date(year, month - 1, day);
|
|
66
|
+
};
|
|
67
|
+
const buildDateClause = (filter, now)=>{
|
|
68
|
+
const { field } = filter;
|
|
69
|
+
if (filter.mode === 'preset') {
|
|
70
|
+
const pivot = subtractPreset(now, filter.preset);
|
|
71
|
+
switch(filter.condition){
|
|
72
|
+
case 'withinLast':
|
|
73
|
+
return {
|
|
74
|
+
[field]: {
|
|
75
|
+
$gte: pivot.toISOString()
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
case 'notWithinLast':
|
|
79
|
+
return {
|
|
80
|
+
[field]: {
|
|
81
|
+
$lt: pivot.toISOString()
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
case 'isExactly':
|
|
85
|
+
return {
|
|
86
|
+
[field]: {
|
|
87
|
+
$gte: startOfDay(pivot).toISOString(),
|
|
88
|
+
$lte: endOfDay(pivot).toISOString()
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const from = startOfDay(parseCalendarDate(filter.from)).toISOString();
|
|
94
|
+
const to = endOfDay(parseCalendarDate(filter.to)).toISOString();
|
|
95
|
+
if (filter.condition === 'is') {
|
|
96
|
+
return {
|
|
97
|
+
[field]: {
|
|
98
|
+
$gte: from,
|
|
99
|
+
$lte: to
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
$or: [
|
|
105
|
+
{
|
|
106
|
+
[field]: {
|
|
107
|
+
$lt: from
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
[field]: {
|
|
112
|
+
$gt: to
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
]
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
const buildMimeClause = (filter)=>{
|
|
119
|
+
const fileValues = filter.values.filter((value)=>value !== 'folder');
|
|
120
|
+
if (fileValues.length === 0) {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
const branches = fileValues.map((value)=>{
|
|
124
|
+
if (value === 'document') {
|
|
125
|
+
// Catch-all: none of the known mime families.
|
|
126
|
+
return {
|
|
127
|
+
$and: ALL_MIMES.map((mime)=>({
|
|
128
|
+
mime: {
|
|
129
|
+
$notContains: mime
|
|
130
|
+
}
|
|
131
|
+
}))
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
mime: {
|
|
136
|
+
$contains: MIME_BY_VALUE[value]
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
});
|
|
140
|
+
if (filter.condition === 'is') {
|
|
141
|
+
return branches.length === 1 ? branches[0] : {
|
|
142
|
+
$or: branches
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
// "is not" = matches none of the selected values: negate each branch, AND them.
|
|
146
|
+
const negated = fileValues.map((value)=>{
|
|
147
|
+
if (value === 'document') {
|
|
148
|
+
// Not a document = is one of the known families.
|
|
149
|
+
return {
|
|
150
|
+
$or: ALL_MIMES.map((mime)=>({
|
|
151
|
+
mime: {
|
|
152
|
+
$contains: mime
|
|
153
|
+
}
|
|
154
|
+
}))
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
mime: {
|
|
159
|
+
$notContains: MIME_BY_VALUE[value]
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
});
|
|
163
|
+
return negated.length === 1 ? negated[0] : {
|
|
164
|
+
$and: negated
|
|
165
|
+
};
|
|
166
|
+
};
|
|
167
|
+
const buildAssetFilters = (filters, now)=>{
|
|
168
|
+
const fileClauses = [];
|
|
169
|
+
const folderClauses = [];
|
|
170
|
+
let showFolders = true;
|
|
171
|
+
let showFiles = true;
|
|
172
|
+
for (const filter of filters){
|
|
173
|
+
if (filter.kind === 'date') {
|
|
174
|
+
const clause = buildDateClause(filter, now);
|
|
175
|
+
fileClauses.push(clause);
|
|
176
|
+
folderClauses.push(clause);
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
const includesFolder = filter.values.includes('folder');
|
|
180
|
+
if (filter.condition === 'is' ? !includesFolder : includesFolder) {
|
|
181
|
+
showFolders = false;
|
|
182
|
+
}
|
|
183
|
+
const mimeClause = buildMimeClause(filter);
|
|
184
|
+
if (mimeClause) {
|
|
185
|
+
fileClauses.push(mimeClause);
|
|
186
|
+
} else if (filter.condition === 'is') {
|
|
187
|
+
// `is [folder]` only — no file can match the badge.
|
|
188
|
+
showFiles = false;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
fileClauses,
|
|
193
|
+
folderClauses,
|
|
194
|
+
showFolders,
|
|
195
|
+
showFiles
|
|
196
|
+
};
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
exports.buildAssetFilters = buildAssetFilters;
|
|
200
|
+
exports.parseCalendarDate = parseCalendarDate;
|
|
201
|
+
//# sourceMappingURL=buildAssetFilters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildAssetFilters.js","sources":["../../../../../../admin/src/future/pages/Assets/utils/buildAssetFilters.ts"],"sourcesContent":["import {\n type DateFilter,\n type DatePreset,\n type ListFilter,\n type TypeFilter,\n type TypeValue,\n} from '../hooks/useListFilters';\n\n/**\n * Translates the URL filter model into Strapi `filters[$and]` entries for the\n * files and folders queries, and decides the structural visibility of both\n * sections.\n *\n * Relative presets resolve against `now` at build time — the URL stays\n * relative (\"within the last week\"), only the outgoing query is absolute.\n *\n * Semantics:\n * - Every badge is one `$and` entry (badges combine with AND, per ticket).\n * - Type: `folder` is not a mime — it acts structurally on the folders\n * section. The remaining values map to mime clauses; `document` is the\n * legacy catch-all (mime contains none of image/audio/video — audio\n * included in the exclusion, fixing the legacy quirk).\n * - Dates apply to files and folders alike (folders have both timestamps).\n * - \"is exactly <preset>\" means the calendar day of `now - delta`.\n * - Ranges are inclusive on both ends (start-of-day .. end-of-day).\n */\n\ntype QueryClause = Record<string, unknown>;\n\nconst MIME_BY_VALUE: Record<Exclude<TypeValue, 'folder' | 'document'>, string> = {\n picture: 'image',\n audio: 'audio',\n video: 'video',\n};\n\nconst ALL_MIMES = Object.values(MIME_BY_VALUE);\n\nconst PRESET_DELTAS: Record<DatePreset, { days?: number; months?: number; years?: number }> = {\n '1day': { days: 1 },\n '3days': { days: 3 },\n '1week': { days: 7 },\n '1month': { months: 1 },\n '3months': { months: 3 },\n '6months': { months: 6 },\n '1year': { years: 1 },\n};\n\nconst subtractPreset = (now: Date, preset: DatePreset): Date => {\n const { days = 0, months = 0, years = 0 } = PRESET_DELTAS[preset];\n const result = new Date(now.getTime());\n\n if (years || months) {\n // JS date setters overflow at month ends (Mar 31 − 1 month → Feb 31 → Mar 3),\n // so move to the 1st first and clamp the day to the target month's length.\n const dayOfMonth = result.getDate();\n result.setDate(1);\n result.setFullYear(result.getFullYear() - years);\n result.setMonth(result.getMonth() - months);\n\n const daysInTargetMonth = new Date(result.getFullYear(), result.getMonth() + 1, 0).getDate();\n result.setDate(Math.min(dayOfMonth, daysInTargetMonth));\n }\n\n result.setDate(result.getDate() - days);\n\n return result;\n};\n\nconst startOfDay = (date: Date): Date => {\n const result = new Date(date.getTime());\n result.setHours(0, 0, 0, 0);\n return result;\n};\n\nconst endOfDay = (date: Date): Date => {\n const result = new Date(date.getTime());\n result.setHours(23, 59, 59, 999);\n return result;\n};\n\n/**\n * Parses `YYYY-MM-DD` as a local calendar date — NOT `new Date(value)`, which\n * treats date-only strings as UTC midnight and shifts the day in every\n * timezone west of UTC. Shared by the query builder, the badge labels and the\n * range calendar so all three agree on which day a range endpoint means.\n */\nexport const parseCalendarDate = (value: string): Date => {\n const [year, month, day] = value.split('-').map(Number);\n return new Date(year, month - 1, day);\n};\n\nconst buildDateClause = (filter: DateFilter, now: Date): QueryClause => {\n const { field } = filter;\n\n if (filter.mode === 'preset') {\n const pivot = subtractPreset(now, filter.preset);\n\n switch (filter.condition) {\n case 'withinLast':\n return { [field]: { $gte: pivot.toISOString() } };\n case 'notWithinLast':\n return { [field]: { $lt: pivot.toISOString() } };\n case 'isExactly':\n return {\n [field]: {\n $gte: startOfDay(pivot).toISOString(),\n $lte: endOfDay(pivot).toISOString(),\n },\n };\n }\n }\n\n const from = startOfDay(parseCalendarDate(filter.from)).toISOString();\n const to = endOfDay(parseCalendarDate(filter.to)).toISOString();\n\n if (filter.condition === 'is') {\n return { [field]: { $gte: from, $lte: to } };\n }\n\n return { $or: [{ [field]: { $lt: from } }, { [field]: { $gt: to } }] };\n};\n\nconst buildMimeClause = (filter: TypeFilter): QueryClause | null => {\n const fileValues = filter.values.filter((value): value is TypeValue => value !== 'folder');\n\n if (fileValues.length === 0) {\n return null;\n }\n\n const branches: QueryClause[] = fileValues.map((value) => {\n if (value === 'document') {\n // Catch-all: none of the known mime families.\n return { $and: ALL_MIMES.map((mime) => ({ mime: { $notContains: mime } })) };\n }\n return { mime: { $contains: MIME_BY_VALUE[value as keyof typeof MIME_BY_VALUE] } };\n });\n\n if (filter.condition === 'is') {\n return branches.length === 1 ? branches[0] : { $or: branches };\n }\n\n // \"is not\" = matches none of the selected values: negate each branch, AND them.\n const negated: QueryClause[] = fileValues.map((value) => {\n if (value === 'document') {\n // Not a document = is one of the known families.\n return { $or: ALL_MIMES.map((mime) => ({ mime: { $contains: mime } })) };\n }\n return { mime: { $notContains: MIME_BY_VALUE[value as keyof typeof MIME_BY_VALUE] } };\n });\n\n return negated.length === 1 ? negated[0] : { $and: negated };\n};\n\nexport interface BuiltFilters {\n /** Extra `$and` entries for the files query. */\n fileClauses: QueryClause[];\n /** Extra `$and` entries for the folders query (dates only). */\n folderClauses: QueryClause[];\n /**\n * Whether the folders section can show at all. A type badge decides it by\n * evaluating \"folder\" like any other value: `is` shows folders only when\n * folder is selected; `is not` hides them only when folder is selected.\n */\n showFolders: boolean;\n /**\n * Whether the files list can show at all — false when an `is` type badge\n * selects only \"folder\" (no file can match).\n */\n showFiles: boolean;\n}\n\nexport const buildAssetFilters = (filters: ListFilter[], now: Date): BuiltFilters => {\n const fileClauses: QueryClause[] = [];\n const folderClauses: QueryClause[] = [];\n let showFolders = true;\n let showFiles = true;\n\n for (const filter of filters) {\n if (filter.kind === 'date') {\n const clause = buildDateClause(filter, now);\n fileClauses.push(clause);\n folderClauses.push(clause);\n continue;\n }\n\n const includesFolder = filter.values.includes('folder');\n if (filter.condition === 'is' ? !includesFolder : includesFolder) {\n showFolders = false;\n }\n\n const mimeClause = buildMimeClause(filter);\n if (mimeClause) {\n fileClauses.push(mimeClause);\n } else if (filter.condition === 'is') {\n // `is [folder]` only — no file can match the badge.\n showFiles = false;\n }\n }\n\n return { fileClauses, folderClauses, showFolders, showFiles };\n};\n"],"names":["MIME_BY_VALUE","picture","audio","video","ALL_MIMES","Object","values","PRESET_DELTAS","days","months","years","subtractPreset","now","preset","result","Date","getTime","dayOfMonth","getDate","setDate","setFullYear","getFullYear","setMonth","getMonth","daysInTargetMonth","Math","min","startOfDay","date","setHours","endOfDay","parseCalendarDate","value","year","month","day","split","map","Number","buildDateClause","filter","field","mode","pivot","condition","$gte","toISOString","$lt","$lte","from","to","$or","$gt","buildMimeClause","fileValues","length","branches","$and","mime","$notContains","$contains","negated","buildAssetFilters","filters","fileClauses","folderClauses","showFolders","showFiles","kind","clause","push","includesFolder","includes","mimeClause"],"mappings":"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"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
const MIME_BY_VALUE = {
|
|
2
|
+
picture: 'image',
|
|
3
|
+
audio: 'audio',
|
|
4
|
+
video: 'video'
|
|
5
|
+
};
|
|
6
|
+
const ALL_MIMES = Object.values(MIME_BY_VALUE);
|
|
7
|
+
const PRESET_DELTAS = {
|
|
8
|
+
'1day': {
|
|
9
|
+
days: 1
|
|
10
|
+
},
|
|
11
|
+
'3days': {
|
|
12
|
+
days: 3
|
|
13
|
+
},
|
|
14
|
+
'1week': {
|
|
15
|
+
days: 7
|
|
16
|
+
},
|
|
17
|
+
'1month': {
|
|
18
|
+
months: 1
|
|
19
|
+
},
|
|
20
|
+
'3months': {
|
|
21
|
+
months: 3
|
|
22
|
+
},
|
|
23
|
+
'6months': {
|
|
24
|
+
months: 6
|
|
25
|
+
},
|
|
26
|
+
'1year': {
|
|
27
|
+
years: 1
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
const subtractPreset = (now, preset)=>{
|
|
31
|
+
const { days = 0, months = 0, years = 0 } = PRESET_DELTAS[preset];
|
|
32
|
+
const result = new Date(now.getTime());
|
|
33
|
+
if (years || months) {
|
|
34
|
+
// JS date setters overflow at month ends (Mar 31 − 1 month → Feb 31 → Mar 3),
|
|
35
|
+
// so move to the 1st first and clamp the day to the target month's length.
|
|
36
|
+
const dayOfMonth = result.getDate();
|
|
37
|
+
result.setDate(1);
|
|
38
|
+
result.setFullYear(result.getFullYear() - years);
|
|
39
|
+
result.setMonth(result.getMonth() - months);
|
|
40
|
+
const daysInTargetMonth = new Date(result.getFullYear(), result.getMonth() + 1, 0).getDate();
|
|
41
|
+
result.setDate(Math.min(dayOfMonth, daysInTargetMonth));
|
|
42
|
+
}
|
|
43
|
+
result.setDate(result.getDate() - days);
|
|
44
|
+
return result;
|
|
45
|
+
};
|
|
46
|
+
const startOfDay = (date)=>{
|
|
47
|
+
const result = new Date(date.getTime());
|
|
48
|
+
result.setHours(0, 0, 0, 0);
|
|
49
|
+
return result;
|
|
50
|
+
};
|
|
51
|
+
const endOfDay = (date)=>{
|
|
52
|
+
const result = new Date(date.getTime());
|
|
53
|
+
result.setHours(23, 59, 59, 999);
|
|
54
|
+
return result;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Parses `YYYY-MM-DD` as a local calendar date — NOT `new Date(value)`, which
|
|
58
|
+
* treats date-only strings as UTC midnight and shifts the day in every
|
|
59
|
+
* timezone west of UTC. Shared by the query builder, the badge labels and the
|
|
60
|
+
* range calendar so all three agree on which day a range endpoint means.
|
|
61
|
+
*/ const parseCalendarDate = (value)=>{
|
|
62
|
+
const [year, month, day] = value.split('-').map(Number);
|
|
63
|
+
return new Date(year, month - 1, day);
|
|
64
|
+
};
|
|
65
|
+
const buildDateClause = (filter, now)=>{
|
|
66
|
+
const { field } = filter;
|
|
67
|
+
if (filter.mode === 'preset') {
|
|
68
|
+
const pivot = subtractPreset(now, filter.preset);
|
|
69
|
+
switch(filter.condition){
|
|
70
|
+
case 'withinLast':
|
|
71
|
+
return {
|
|
72
|
+
[field]: {
|
|
73
|
+
$gte: pivot.toISOString()
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
case 'notWithinLast':
|
|
77
|
+
return {
|
|
78
|
+
[field]: {
|
|
79
|
+
$lt: pivot.toISOString()
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
case 'isExactly':
|
|
83
|
+
return {
|
|
84
|
+
[field]: {
|
|
85
|
+
$gte: startOfDay(pivot).toISOString(),
|
|
86
|
+
$lte: endOfDay(pivot).toISOString()
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const from = startOfDay(parseCalendarDate(filter.from)).toISOString();
|
|
92
|
+
const to = endOfDay(parseCalendarDate(filter.to)).toISOString();
|
|
93
|
+
if (filter.condition === 'is') {
|
|
94
|
+
return {
|
|
95
|
+
[field]: {
|
|
96
|
+
$gte: from,
|
|
97
|
+
$lte: to
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
$or: [
|
|
103
|
+
{
|
|
104
|
+
[field]: {
|
|
105
|
+
$lt: from
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
[field]: {
|
|
110
|
+
$gt: to
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
]
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
const buildMimeClause = (filter)=>{
|
|
117
|
+
const fileValues = filter.values.filter((value)=>value !== 'folder');
|
|
118
|
+
if (fileValues.length === 0) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
const branches = fileValues.map((value)=>{
|
|
122
|
+
if (value === 'document') {
|
|
123
|
+
// Catch-all: none of the known mime families.
|
|
124
|
+
return {
|
|
125
|
+
$and: ALL_MIMES.map((mime)=>({
|
|
126
|
+
mime: {
|
|
127
|
+
$notContains: mime
|
|
128
|
+
}
|
|
129
|
+
}))
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
mime: {
|
|
134
|
+
$contains: MIME_BY_VALUE[value]
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
});
|
|
138
|
+
if (filter.condition === 'is') {
|
|
139
|
+
return branches.length === 1 ? branches[0] : {
|
|
140
|
+
$or: branches
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
// "is not" = matches none of the selected values: negate each branch, AND them.
|
|
144
|
+
const negated = fileValues.map((value)=>{
|
|
145
|
+
if (value === 'document') {
|
|
146
|
+
// Not a document = is one of the known families.
|
|
147
|
+
return {
|
|
148
|
+
$or: ALL_MIMES.map((mime)=>({
|
|
149
|
+
mime: {
|
|
150
|
+
$contains: mime
|
|
151
|
+
}
|
|
152
|
+
}))
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
return {
|
|
156
|
+
mime: {
|
|
157
|
+
$notContains: MIME_BY_VALUE[value]
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
});
|
|
161
|
+
return negated.length === 1 ? negated[0] : {
|
|
162
|
+
$and: negated
|
|
163
|
+
};
|
|
164
|
+
};
|
|
165
|
+
const buildAssetFilters = (filters, now)=>{
|
|
166
|
+
const fileClauses = [];
|
|
167
|
+
const folderClauses = [];
|
|
168
|
+
let showFolders = true;
|
|
169
|
+
let showFiles = true;
|
|
170
|
+
for (const filter of filters){
|
|
171
|
+
if (filter.kind === 'date') {
|
|
172
|
+
const clause = buildDateClause(filter, now);
|
|
173
|
+
fileClauses.push(clause);
|
|
174
|
+
folderClauses.push(clause);
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
const includesFolder = filter.values.includes('folder');
|
|
178
|
+
if (filter.condition === 'is' ? !includesFolder : includesFolder) {
|
|
179
|
+
showFolders = false;
|
|
180
|
+
}
|
|
181
|
+
const mimeClause = buildMimeClause(filter);
|
|
182
|
+
if (mimeClause) {
|
|
183
|
+
fileClauses.push(mimeClause);
|
|
184
|
+
} else if (filter.condition === 'is') {
|
|
185
|
+
// `is [folder]` only — no file can match the badge.
|
|
186
|
+
showFiles = false;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return {
|
|
190
|
+
fileClauses,
|
|
191
|
+
folderClauses,
|
|
192
|
+
showFolders,
|
|
193
|
+
showFiles
|
|
194
|
+
};
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
export { buildAssetFilters, parseCalendarDate };
|
|
198
|
+
//# sourceMappingURL=buildAssetFilters.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildAssetFilters.mjs","sources":["../../../../../../admin/src/future/pages/Assets/utils/buildAssetFilters.ts"],"sourcesContent":["import {\n type DateFilter,\n type DatePreset,\n type ListFilter,\n type TypeFilter,\n type TypeValue,\n} from '../hooks/useListFilters';\n\n/**\n * Translates the URL filter model into Strapi `filters[$and]` entries for the\n * files and folders queries, and decides the structural visibility of both\n * sections.\n *\n * Relative presets resolve against `now` at build time — the URL stays\n * relative (\"within the last week\"), only the outgoing query is absolute.\n *\n * Semantics:\n * - Every badge is one `$and` entry (badges combine with AND, per ticket).\n * - Type: `folder` is not a mime — it acts structurally on the folders\n * section. The remaining values map to mime clauses; `document` is the\n * legacy catch-all (mime contains none of image/audio/video — audio\n * included in the exclusion, fixing the legacy quirk).\n * - Dates apply to files and folders alike (folders have both timestamps).\n * - \"is exactly <preset>\" means the calendar day of `now - delta`.\n * - Ranges are inclusive on both ends (start-of-day .. end-of-day).\n */\n\ntype QueryClause = Record<string, unknown>;\n\nconst MIME_BY_VALUE: Record<Exclude<TypeValue, 'folder' | 'document'>, string> = {\n picture: 'image',\n audio: 'audio',\n video: 'video',\n};\n\nconst ALL_MIMES = Object.values(MIME_BY_VALUE);\n\nconst PRESET_DELTAS: Record<DatePreset, { days?: number; months?: number; years?: number }> = {\n '1day': { days: 1 },\n '3days': { days: 3 },\n '1week': { days: 7 },\n '1month': { months: 1 },\n '3months': { months: 3 },\n '6months': { months: 6 },\n '1year': { years: 1 },\n};\n\nconst subtractPreset = (now: Date, preset: DatePreset): Date => {\n const { days = 0, months = 0, years = 0 } = PRESET_DELTAS[preset];\n const result = new Date(now.getTime());\n\n if (years || months) {\n // JS date setters overflow at month ends (Mar 31 − 1 month → Feb 31 → Mar 3),\n // so move to the 1st first and clamp the day to the target month's length.\n const dayOfMonth = result.getDate();\n result.setDate(1);\n result.setFullYear(result.getFullYear() - years);\n result.setMonth(result.getMonth() - months);\n\n const daysInTargetMonth = new Date(result.getFullYear(), result.getMonth() + 1, 0).getDate();\n result.setDate(Math.min(dayOfMonth, daysInTargetMonth));\n }\n\n result.setDate(result.getDate() - days);\n\n return result;\n};\n\nconst startOfDay = (date: Date): Date => {\n const result = new Date(date.getTime());\n result.setHours(0, 0, 0, 0);\n return result;\n};\n\nconst endOfDay = (date: Date): Date => {\n const result = new Date(date.getTime());\n result.setHours(23, 59, 59, 999);\n return result;\n};\n\n/**\n * Parses `YYYY-MM-DD` as a local calendar date — NOT `new Date(value)`, which\n * treats date-only strings as UTC midnight and shifts the day in every\n * timezone west of UTC. Shared by the query builder, the badge labels and the\n * range calendar so all three agree on which day a range endpoint means.\n */\nexport const parseCalendarDate = (value: string): Date => {\n const [year, month, day] = value.split('-').map(Number);\n return new Date(year, month - 1, day);\n};\n\nconst buildDateClause = (filter: DateFilter, now: Date): QueryClause => {\n const { field } = filter;\n\n if (filter.mode === 'preset') {\n const pivot = subtractPreset(now, filter.preset);\n\n switch (filter.condition) {\n case 'withinLast':\n return { [field]: { $gte: pivot.toISOString() } };\n case 'notWithinLast':\n return { [field]: { $lt: pivot.toISOString() } };\n case 'isExactly':\n return {\n [field]: {\n $gte: startOfDay(pivot).toISOString(),\n $lte: endOfDay(pivot).toISOString(),\n },\n };\n }\n }\n\n const from = startOfDay(parseCalendarDate(filter.from)).toISOString();\n const to = endOfDay(parseCalendarDate(filter.to)).toISOString();\n\n if (filter.condition === 'is') {\n return { [field]: { $gte: from, $lte: to } };\n }\n\n return { $or: [{ [field]: { $lt: from } }, { [field]: { $gt: to } }] };\n};\n\nconst buildMimeClause = (filter: TypeFilter): QueryClause | null => {\n const fileValues = filter.values.filter((value): value is TypeValue => value !== 'folder');\n\n if (fileValues.length === 0) {\n return null;\n }\n\n const branches: QueryClause[] = fileValues.map((value) => {\n if (value === 'document') {\n // Catch-all: none of the known mime families.\n return { $and: ALL_MIMES.map((mime) => ({ mime: { $notContains: mime } })) };\n }\n return { mime: { $contains: MIME_BY_VALUE[value as keyof typeof MIME_BY_VALUE] } };\n });\n\n if (filter.condition === 'is') {\n return branches.length === 1 ? branches[0] : { $or: branches };\n }\n\n // \"is not\" = matches none of the selected values: negate each branch, AND them.\n const negated: QueryClause[] = fileValues.map((value) => {\n if (value === 'document') {\n // Not a document = is one of the known families.\n return { $or: ALL_MIMES.map((mime) => ({ mime: { $contains: mime } })) };\n }\n return { mime: { $notContains: MIME_BY_VALUE[value as keyof typeof MIME_BY_VALUE] } };\n });\n\n return negated.length === 1 ? negated[0] : { $and: negated };\n};\n\nexport interface BuiltFilters {\n /** Extra `$and` entries for the files query. */\n fileClauses: QueryClause[];\n /** Extra `$and` entries for the folders query (dates only). */\n folderClauses: QueryClause[];\n /**\n * Whether the folders section can show at all. A type badge decides it by\n * evaluating \"folder\" like any other value: `is` shows folders only when\n * folder is selected; `is not` hides them only when folder is selected.\n */\n showFolders: boolean;\n /**\n * Whether the files list can show at all — false when an `is` type badge\n * selects only \"folder\" (no file can match).\n */\n showFiles: boolean;\n}\n\nexport const buildAssetFilters = (filters: ListFilter[], now: Date): BuiltFilters => {\n const fileClauses: QueryClause[] = [];\n const folderClauses: QueryClause[] = [];\n let showFolders = true;\n let showFiles = true;\n\n for (const filter of filters) {\n if (filter.kind === 'date') {\n const clause = buildDateClause(filter, now);\n fileClauses.push(clause);\n folderClauses.push(clause);\n continue;\n }\n\n const includesFolder = filter.values.includes('folder');\n if (filter.condition === 'is' ? !includesFolder : includesFolder) {\n showFolders = false;\n }\n\n const mimeClause = buildMimeClause(filter);\n if (mimeClause) {\n fileClauses.push(mimeClause);\n } else if (filter.condition === 'is') {\n // `is [folder]` only — no file can match the badge.\n showFiles = false;\n }\n }\n\n return { fileClauses, folderClauses, showFolders, showFiles };\n};\n"],"names":["MIME_BY_VALUE","picture","audio","video","ALL_MIMES","Object","values","PRESET_DELTAS","days","months","years","subtractPreset","now","preset","result","Date","getTime","dayOfMonth","getDate","setDate","setFullYear","getFullYear","setMonth","getMonth","daysInTargetMonth","Math","min","startOfDay","date","setHours","endOfDay","parseCalendarDate","value","year","month","day","split","map","Number","buildDateClause","filter","field","mode","pivot","condition","$gte","toISOString","$lt","$lte","from","to","$or","$gt","buildMimeClause","fileValues","length","branches","$and","mime","$notContains","$contains","negated","buildAssetFilters","filters","fileClauses","folderClauses","showFolders","showFiles","kind","clause","push","includesFolder","includes","mimeClause"],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Fingerprint for "which asset list the user is looking at".
|
|
5
|
+
*
|
|
6
|
+
* Selection clears when this key changes (see ClearSelectionOnChange in AssetsPage).
|
|
7
|
+
*
|
|
8
|
+
* Hybrid rule
|
|
9
|
+
* - Folder, search, sort, filter changes → new key → selection clears.
|
|
10
|
+
* - Switching table/grid view does NOT change the key — both views render the
|
|
11
|
+
* same list, so the selection survives the toggle.
|
|
12
|
+
* - Infinite scroll (load more) does NOT change any segment → selection persists.
|
|
13
|
+
*
|
|
14
|
+
* Filter uses a stable default until its header control is wired; that follow-up
|
|
15
|
+
* only passes a real value — no selection logic changes needed.
|
|
16
|
+
*/ /**
|
|
17
|
+
* Builds a stable fingerprint for the current asset list query.
|
|
18
|
+
*
|
|
19
|
+
* Selection clears when this key changes. Infinite scroll does not change any
|
|
20
|
+
* segment, so selection persists across load-more.
|
|
21
|
+
*/ const getListQueryKey = ({ folderId, search, sort, filter })=>JSON.stringify({
|
|
22
|
+
folderId,
|
|
23
|
+
search,
|
|
24
|
+
sort,
|
|
25
|
+
filter
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
exports.getListQueryKey = getListQueryKey;
|
|
29
|
+
//# sourceMappingURL=listQueryKey.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"listQueryKey.js","sources":["../../../../../../admin/src/future/pages/Assets/utils/listQueryKey.ts"],"sourcesContent":["/**\n * Fingerprint for \"which asset list the user is looking at\".\n *\n * Selection clears when this key changes (see ClearSelectionOnChange in AssetsPage).\n *\n * Hybrid rule\n * - Folder, search, sort, filter changes → new key → selection clears.\n * - Switching table/grid view does NOT change the key — both views render the\n * same list, so the selection survives the toggle.\n * - Infinite scroll (load more) does NOT change any segment → selection persists.\n *\n * Filter uses a stable default until its header control is wired; that follow-up\n * only passes a real value — no selection logic changes needed.\n */\nexport interface ListQueryKeyInput {\n folderId: number | null;\n search: string;\n /** Composite of asset sort and folder position — both change the render order. */\n sort: string | null;\n /** Null until filter UI ships. */\n filter: string | null;\n}\n\n/**\n * Builds a stable fingerprint for the current asset list query.\n *\n * Selection clears when this key changes. Infinite scroll does not change any\n * segment, so selection persists across load-more.\n */\nexport const getListQueryKey = ({ folderId, search, sort, filter }: ListQueryKeyInput): string =>\n JSON.stringify({ folderId, search, sort, filter });\n"],"names":["getListQueryKey","folderId","search","sort","filter","JSON","stringify"],"mappings":";;AAAA;;;;;;;;;;;;;;;;;;AA4BC,IACM,MAAMA,eAAAA,GAAkB,CAAC,EAAEC,QAAQ,EAAEC,MAAM,EAAEC,IAAI,EAAEC,MAAM,EAAqB,GACnFC,IAAAA,CAAKC,SAAS,CAAC;AAAEL,QAAAA,QAAAA;AAAUC,QAAAA,MAAAA;AAAQC,QAAAA,IAAAA;AAAMC,QAAAA;KAAO;;;;"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fingerprint for "which asset list the user is looking at".
|
|
3
|
+
*
|
|
4
|
+
* Selection clears when this key changes (see ClearSelectionOnChange in AssetsPage).
|
|
5
|
+
*
|
|
6
|
+
* Hybrid rule
|
|
7
|
+
* - Folder, search, sort, filter changes → new key → selection clears.
|
|
8
|
+
* - Switching table/grid view does NOT change the key — both views render the
|
|
9
|
+
* same list, so the selection survives the toggle.
|
|
10
|
+
* - Infinite scroll (load more) does NOT change any segment → selection persists.
|
|
11
|
+
*
|
|
12
|
+
* Filter uses a stable default until its header control is wired; that follow-up
|
|
13
|
+
* only passes a real value — no selection logic changes needed.
|
|
14
|
+
*/ /**
|
|
15
|
+
* Builds a stable fingerprint for the current asset list query.
|
|
16
|
+
*
|
|
17
|
+
* Selection clears when this key changes. Infinite scroll does not change any
|
|
18
|
+
* segment, so selection persists across load-more.
|
|
19
|
+
*/ const getListQueryKey = ({ folderId, search, sort, filter })=>JSON.stringify({
|
|
20
|
+
folderId,
|
|
21
|
+
search,
|
|
22
|
+
sort,
|
|
23
|
+
filter
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
export { getListQueryKey };
|
|
27
|
+
//# sourceMappingURL=listQueryKey.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"listQueryKey.mjs","sources":["../../../../../../admin/src/future/pages/Assets/utils/listQueryKey.ts"],"sourcesContent":["/**\n * Fingerprint for \"which asset list the user is looking at\".\n *\n * Selection clears when this key changes (see ClearSelectionOnChange in AssetsPage).\n *\n * Hybrid rule\n * - Folder, search, sort, filter changes → new key → selection clears.\n * - Switching table/grid view does NOT change the key — both views render the\n * same list, so the selection survives the toggle.\n * - Infinite scroll (load more) does NOT change any segment → selection persists.\n *\n * Filter uses a stable default until its header control is wired; that follow-up\n * only passes a real value — no selection logic changes needed.\n */\nexport interface ListQueryKeyInput {\n folderId: number | null;\n search: string;\n /** Composite of asset sort and folder position — both change the render order. */\n sort: string | null;\n /** Null until filter UI ships. */\n filter: string | null;\n}\n\n/**\n * Builds a stable fingerprint for the current asset list query.\n *\n * Selection clears when this key changes. Infinite scroll does not change any\n * segment, so selection persists across load-more.\n */\nexport const getListQueryKey = ({ folderId, search, sort, filter }: ListQueryKeyInput): string =>\n JSON.stringify({ folderId, search, sort, filter });\n"],"names":["getListQueryKey","folderId","search","sort","filter","JSON","stringify"],"mappings":"AAAA;;;;;;;;;;;;;;;;;;AA4BC,IACM,MAAMA,eAAAA,GAAkB,CAAC,EAAEC,QAAQ,EAAEC,MAAM,EAAEC,IAAI,EAAEC,MAAM,EAAqB,GACnFC,IAAAA,CAAKC,SAAS,CAAC;AAAEL,QAAAA,QAAAA;AAAUC,QAAAA,MAAAA;AAAQC,QAAAA,IAAAA;AAAMC,QAAAA;KAAO;;;;"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const getComparableValue = (record, field)=>{
|
|
4
|
+
switch(field){
|
|
5
|
+
case 'createdAt':
|
|
6
|
+
case 'updatedAt':
|
|
7
|
+
return record[field] ? new Date(record[field]).getTime() : 0;
|
|
8
|
+
case 'size':
|
|
9
|
+
// Folders have no size — they compare as 0 (start of ascending, end of descending).
|
|
10
|
+
return record.size ?? 0;
|
|
11
|
+
case 'name':
|
|
12
|
+
default:
|
|
13
|
+
return (record.name ?? '').toLowerCase();
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Builds a comparator from comma-separated sort rules (`updatedAt:DESC,name:ASC`).
|
|
18
|
+
* Rules apply in order; the first non-equal field decides. Client-side
|
|
19
|
+
* approximation of the server ordering — good enough to slot folders between
|
|
20
|
+
* files that were sorted server-side by the same rules.
|
|
21
|
+
*/ const buildComparator = (sort)=>{
|
|
22
|
+
const rules = sort.split(',').map((rule)=>rule.trim()).filter(Boolean).map((rule)=>{
|
|
23
|
+
const [field, direction] = rule.split(':');
|
|
24
|
+
return {
|
|
25
|
+
field,
|
|
26
|
+
desc: direction?.toUpperCase() === 'DESC'
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
return (a, b)=>{
|
|
30
|
+
for (const { field, desc } of rules){
|
|
31
|
+
const va = getComparableValue(a, field);
|
|
32
|
+
const vb = getComparableValue(b, field);
|
|
33
|
+
let cmp;
|
|
34
|
+
if (typeof va === 'string' || typeof vb === 'string') {
|
|
35
|
+
cmp = String(va) < String(vb) ? -1 : String(va) > String(vb) ? 1 : 0;
|
|
36
|
+
} else {
|
|
37
|
+
cmp = va - vb;
|
|
38
|
+
}
|
|
39
|
+
if (cmp !== 0) {
|
|
40
|
+
return desc ? -cmp : cmp;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return 0;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Interleaves the complete folder list into the (possibly partially loaded)
|
|
48
|
+
* asset stream according to the active sort. Ties order folders first.
|
|
49
|
+
*/ const mergeMixedList = ({ folders, assets, sort, hasNextPage })=>{
|
|
50
|
+
const compare = buildComparator(sort);
|
|
51
|
+
const sortedFolders = [
|
|
52
|
+
...folders
|
|
53
|
+
].sort(compare);
|
|
54
|
+
const lastAsset = assets[assets.length - 1];
|
|
55
|
+
const placeableFolders = !hasNextPage || !lastAsset ? hasNextPage ? [] // nothing loaded yet — wait for the first page
|
|
56
|
+
: sortedFolders : sortedFolders.filter((folder)=>compare(folder, lastAsset) <= 0);
|
|
57
|
+
const items = [];
|
|
58
|
+
let folderIndex = 0;
|
|
59
|
+
for (const asset of assets){
|
|
60
|
+
while(folderIndex < placeableFolders.length && compare(placeableFolders[folderIndex], asset) <= 0){
|
|
61
|
+
items.push({
|
|
62
|
+
kind: 'folder',
|
|
63
|
+
folder: placeableFolders[folderIndex]
|
|
64
|
+
});
|
|
65
|
+
folderIndex += 1;
|
|
66
|
+
}
|
|
67
|
+
items.push({
|
|
68
|
+
kind: 'asset',
|
|
69
|
+
asset
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
while(folderIndex < placeableFolders.length){
|
|
73
|
+
items.push({
|
|
74
|
+
kind: 'folder',
|
|
75
|
+
folder: placeableFolders[folderIndex]
|
|
76
|
+
});
|
|
77
|
+
folderIndex += 1;
|
|
78
|
+
}
|
|
79
|
+
return items;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
exports.buildComparator = buildComparator;
|
|
83
|
+
exports.mergeMixedList = mergeMixedList;
|
|
84
|
+
//# sourceMappingURL=mergeMixedList.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mergeMixedList.js","sources":["../../../../../../admin/src/future/pages/Assets/utils/mergeMixedList.ts"],"sourcesContent":["import type { File } from '../../../../../../shared/contracts/files';\nimport type { Folder } from '../../../../../../shared/contracts/folders';\n\nexport type MixedItem = { kind: 'folder'; folder: Folder } | { kind: 'asset'; asset: File };\n\ntype SortableRecord = {\n name?: string | null;\n createdAt?: string | null;\n updatedAt?: string | null;\n size?: number | null;\n};\n\nconst getComparableValue = (record: SortableRecord, field: string): number | string => {\n switch (field) {\n case 'createdAt':\n case 'updatedAt':\n return record[field] ? new Date(record[field]!).getTime() : 0;\n case 'size':\n // Folders have no size — they compare as 0 (start of ascending, end of descending).\n return record.size ?? 0;\n case 'name':\n default:\n return (record.name ?? '').toLowerCase();\n }\n};\n\n/**\n * Builds a comparator from comma-separated sort rules (`updatedAt:DESC,name:ASC`).\n * Rules apply in order; the first non-equal field decides. Client-side\n * approximation of the server ordering — good enough to slot folders between\n * files that were sorted server-side by the same rules.\n */\nexport const buildComparator = (sort: string) => {\n const rules = sort\n .split(',')\n .map((rule) => rule.trim())\n .filter(Boolean)\n .map((rule) => {\n const [field, direction] = rule.split(':');\n return { field, desc: direction?.toUpperCase() === 'DESC' };\n });\n\n return (a: SortableRecord, b: SortableRecord): number => {\n for (const { field, desc } of rules) {\n const va = getComparableValue(a, field);\n const vb = getComparableValue(b, field);\n\n let cmp: number;\n if (typeof va === 'string' || typeof vb === 'string') {\n cmp = String(va) < String(vb) ? -1 : String(va) > String(vb) ? 1 : 0;\n } else {\n cmp = va - vb;\n }\n\n if (cmp !== 0) {\n return desc ? -cmp : cmp;\n }\n }\n\n return 0;\n };\n};\n\ninterface MergeMixedListParams {\n folders: Folder[];\n assets: File[];\n /** Combined sort rules used for the assets query. */\n sort: string;\n /**\n * More asset pages exist. A folder may only be placed once we know no\n * not-yet-loaded asset sorts before it — i.e. it compares ≤ the last loaded\n * asset. Later pages release the remaining folders progressively.\n */\n hasNextPage: boolean;\n}\n\n/**\n * Interleaves the complete folder list into the (possibly partially loaded)\n * asset stream according to the active sort. Ties order folders first.\n */\nexport const mergeMixedList = ({\n folders,\n assets,\n sort,\n hasNextPage,\n}: MergeMixedListParams): MixedItem[] => {\n const compare = buildComparator(sort);\n\n const sortedFolders = [...folders].sort(compare);\n\n const lastAsset = assets[assets.length - 1];\n const placeableFolders =\n !hasNextPage || !lastAsset\n ? hasNextPage\n ? [] // nothing loaded yet — wait for the first page\n : sortedFolders\n : sortedFolders.filter((folder) => compare(folder, lastAsset) <= 0);\n\n const items: MixedItem[] = [];\n let folderIndex = 0;\n\n for (const asset of assets) {\n while (\n folderIndex < placeableFolders.length &&\n compare(placeableFolders[folderIndex], asset) <= 0\n ) {\n items.push({ kind: 'folder', folder: placeableFolders[folderIndex] });\n folderIndex += 1;\n }\n items.push({ kind: 'asset', asset });\n }\n\n while (folderIndex < placeableFolders.length) {\n items.push({ kind: 'folder', folder: placeableFolders[folderIndex] });\n folderIndex += 1;\n }\n\n return items;\n};\n"],"names":["getComparableValue","record","field","Date","getTime","size","name","toLowerCase","buildComparator","sort","rules","split","map","rule","trim","filter","Boolean","direction","desc","toUpperCase","a","b","va","vb","cmp","String","mergeMixedList","folders","assets","hasNextPage","compare","sortedFolders","lastAsset","length","placeableFolders","folder","items","folderIndex","asset","push","kind"],"mappings":"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"}
|