@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,43 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Constants shared by the upload server and the admin panel.
|
|
5
|
+
*
|
|
6
|
+
* The server stays authoritative — it validates and rejects — but the admin
|
|
7
|
+
* needs the same values to disable actions up front rather than letting the
|
|
8
|
+
* user discover a limit through a failed request.
|
|
9
|
+
*/ /**
|
|
10
|
+
* Image formats the AI metadata provider can read.
|
|
11
|
+
*
|
|
12
|
+
* Anything outside this list (non-images, but also exotic image formats like
|
|
13
|
+
* SVG or TIFF) is reported as `skipped` instead of being sent.
|
|
14
|
+
*
|
|
15
|
+
* @see https://ai.google.dev/gemini-api/docs/image-understanding
|
|
16
|
+
*/ const AI_METADATA_SUPPORTED_IMAGE_TYPES = [
|
|
17
|
+
'image/png',
|
|
18
|
+
'image/jpeg',
|
|
19
|
+
'image/webp',
|
|
20
|
+
'image/heic',
|
|
21
|
+
'image/heif'
|
|
22
|
+
];
|
|
23
|
+
/**
|
|
24
|
+
* Whether the AI metadata provider can generate metadata for this mime type.
|
|
25
|
+
*/ const isAIMetadataSupportedMime = (mime)=>AI_METADATA_SUPPORTED_IMAGE_TYPES.includes(mime);
|
|
26
|
+
/**
|
|
27
|
+
* Number of images sent to the AI server per request when generating metadata
|
|
28
|
+
* for an explicit selection. Matches the URL cap of the bulk URL upload flow.
|
|
29
|
+
*/ const AI_METADATA_CHUNK_SIZE = 20;
|
|
30
|
+
/**
|
|
31
|
+
* Upper bound on a single synchronous AI metadata request.
|
|
32
|
+
*
|
|
33
|
+
* The selection is processed in sequential chunks inside one HTTP request, so
|
|
34
|
+
* an unbounded selection means an unbounded request — long past most proxy and
|
|
35
|
+
* load balancer timeouts, with no way for the client to learn what was written.
|
|
36
|
+
* Rejecting with a 400 lets the UI ask for a smaller selection instead.
|
|
37
|
+
*/ const AI_METADATA_MAX_FILES = AI_METADATA_CHUNK_SIZE * 2;
|
|
38
|
+
|
|
39
|
+
exports.AI_METADATA_CHUNK_SIZE = AI_METADATA_CHUNK_SIZE;
|
|
40
|
+
exports.AI_METADATA_MAX_FILES = AI_METADATA_MAX_FILES;
|
|
41
|
+
exports.AI_METADATA_SUPPORTED_IMAGE_TYPES = AI_METADATA_SUPPORTED_IMAGE_TYPES;
|
|
42
|
+
exports.isAIMetadataSupportedMime = isAIMetadataSupportedMime;
|
|
43
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sources":["../../../shared/constants.ts"],"sourcesContent":["/**\n * Constants shared by the upload server and the admin panel.\n *\n * The server stays authoritative — it validates and rejects — but the admin\n * needs the same values to disable actions up front rather than letting the\n * user discover a limit through a failed request.\n */\n\n/**\n * Image formats the AI metadata provider can read.\n *\n * Anything outside this list (non-images, but also exotic image formats like\n * SVG or TIFF) is reported as `skipped` instead of being sent.\n *\n * @see https://ai.google.dev/gemini-api/docs/image-understanding\n */\nexport const AI_METADATA_SUPPORTED_IMAGE_TYPES = [\n 'image/png',\n 'image/jpeg',\n 'image/webp',\n 'image/heic',\n 'image/heif',\n] as const;\n\nexport type AIMetadataSupportedImageType = (typeof AI_METADATA_SUPPORTED_IMAGE_TYPES)[number];\n\n/**\n * Whether the AI metadata provider can generate metadata for this mime type.\n */\nexport const isAIMetadataSupportedMime = (mime?: string | null): boolean =>\n AI_METADATA_SUPPORTED_IMAGE_TYPES.includes(mime as AIMetadataSupportedImageType);\n\n/**\n * Number of images sent to the AI server per request when generating metadata\n * for an explicit selection. Matches the URL cap of the bulk URL upload flow.\n */\nexport const AI_METADATA_CHUNK_SIZE = 20;\n\n/**\n * Upper bound on a single synchronous AI metadata request.\n *\n * The selection is processed in sequential chunks inside one HTTP request, so\n * an unbounded selection means an unbounded request — long past most proxy and\n * load balancer timeouts, with no way for the client to learn what was written.\n * Rejecting with a 400 lets the UI ask for a smaller selection instead.\n */\nexport const AI_METADATA_MAX_FILES = AI_METADATA_CHUNK_SIZE * 2;\n"],"names":["AI_METADATA_SUPPORTED_IMAGE_TYPES","isAIMetadataSupportedMime","mime","includes","AI_METADATA_CHUNK_SIZE","AI_METADATA_MAX_FILES"],"mappings":";;AAAA;;;;;;;;;;;;;UAgBaA,iCAAAA,GAAoC;AAC/C,IAAA,WAAA;AACA,IAAA,YAAA;AACA,IAAA,YAAA;AACA,IAAA,YAAA;AACA,IAAA;;AAKF;;UAGaC,yBAAAA,GAA4B,CAACC,OACxCF,iCAAAA,CAAkCG,QAAQ,CAACD,IAAAA;AAE7C;;;IAIO,MAAME,sBAAAA,GAAyB;AAEtC;;;;;;;AAOC,IACM,MAAMC,qBAAAA,GAAwBD,sBAAAA,GAAyB;;;;;;;"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constants shared by the upload server and the admin panel.
|
|
3
|
+
*
|
|
4
|
+
* The server stays authoritative — it validates and rejects — but the admin
|
|
5
|
+
* needs the same values to disable actions up front rather than letting the
|
|
6
|
+
* user discover a limit through a failed request.
|
|
7
|
+
*/ /**
|
|
8
|
+
* Image formats the AI metadata provider can read.
|
|
9
|
+
*
|
|
10
|
+
* Anything outside this list (non-images, but also exotic image formats like
|
|
11
|
+
* SVG or TIFF) is reported as `skipped` instead of being sent.
|
|
12
|
+
*
|
|
13
|
+
* @see https://ai.google.dev/gemini-api/docs/image-understanding
|
|
14
|
+
*/ const AI_METADATA_SUPPORTED_IMAGE_TYPES = [
|
|
15
|
+
'image/png',
|
|
16
|
+
'image/jpeg',
|
|
17
|
+
'image/webp',
|
|
18
|
+
'image/heic',
|
|
19
|
+
'image/heif'
|
|
20
|
+
];
|
|
21
|
+
/**
|
|
22
|
+
* Whether the AI metadata provider can generate metadata for this mime type.
|
|
23
|
+
*/ const isAIMetadataSupportedMime = (mime)=>AI_METADATA_SUPPORTED_IMAGE_TYPES.includes(mime);
|
|
24
|
+
/**
|
|
25
|
+
* Number of images sent to the AI server per request when generating metadata
|
|
26
|
+
* for an explicit selection. Matches the URL cap of the bulk URL upload flow.
|
|
27
|
+
*/ const AI_METADATA_CHUNK_SIZE = 20;
|
|
28
|
+
/**
|
|
29
|
+
* Upper bound on a single synchronous AI metadata request.
|
|
30
|
+
*
|
|
31
|
+
* The selection is processed in sequential chunks inside one HTTP request, so
|
|
32
|
+
* an unbounded selection means an unbounded request — long past most proxy and
|
|
33
|
+
* load balancer timeouts, with no way for the client to learn what was written.
|
|
34
|
+
* Rejecting with a 400 lets the UI ask for a smaller selection instead.
|
|
35
|
+
*/ const AI_METADATA_MAX_FILES = AI_METADATA_CHUNK_SIZE * 2;
|
|
36
|
+
|
|
37
|
+
export { AI_METADATA_CHUNK_SIZE, AI_METADATA_MAX_FILES, AI_METADATA_SUPPORTED_IMAGE_TYPES, isAIMetadataSupportedMime };
|
|
38
|
+
//# sourceMappingURL=constants.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.mjs","sources":["../../../shared/constants.ts"],"sourcesContent":["/**\n * Constants shared by the upload server and the admin panel.\n *\n * The server stays authoritative — it validates and rejects — but the admin\n * needs the same values to disable actions up front rather than letting the\n * user discover a limit through a failed request.\n */\n\n/**\n * Image formats the AI metadata provider can read.\n *\n * Anything outside this list (non-images, but also exotic image formats like\n * SVG or TIFF) is reported as `skipped` instead of being sent.\n *\n * @see https://ai.google.dev/gemini-api/docs/image-understanding\n */\nexport const AI_METADATA_SUPPORTED_IMAGE_TYPES = [\n 'image/png',\n 'image/jpeg',\n 'image/webp',\n 'image/heic',\n 'image/heif',\n] as const;\n\nexport type AIMetadataSupportedImageType = (typeof AI_METADATA_SUPPORTED_IMAGE_TYPES)[number];\n\n/**\n * Whether the AI metadata provider can generate metadata for this mime type.\n */\nexport const isAIMetadataSupportedMime = (mime?: string | null): boolean =>\n AI_METADATA_SUPPORTED_IMAGE_TYPES.includes(mime as AIMetadataSupportedImageType);\n\n/**\n * Number of images sent to the AI server per request when generating metadata\n * for an explicit selection. Matches the URL cap of the bulk URL upload flow.\n */\nexport const AI_METADATA_CHUNK_SIZE = 20;\n\n/**\n * Upper bound on a single synchronous AI metadata request.\n *\n * The selection is processed in sequential chunks inside one HTTP request, so\n * an unbounded selection means an unbounded request — long past most proxy and\n * load balancer timeouts, with no way for the client to learn what was written.\n * Rejecting with a 400 lets the UI ask for a smaller selection instead.\n */\nexport const AI_METADATA_MAX_FILES = AI_METADATA_CHUNK_SIZE * 2;\n"],"names":["AI_METADATA_SUPPORTED_IMAGE_TYPES","isAIMetadataSupportedMime","mime","includes","AI_METADATA_CHUNK_SIZE","AI_METADATA_MAX_FILES"],"mappings":"AAAA;;;;;;;;;;;;;UAgBaA,iCAAAA,GAAoC;AAC/C,IAAA,WAAA;AACA,IAAA,YAAA;AACA,IAAA,YAAA;AACA,IAAA,YAAA;AACA,IAAA;;AAKF;;UAGaC,yBAAAA,GAA4B,CAACC,OACxCF,iCAAAA,CAAkCG,QAAQ,CAACD,IAAAA;AAE7C;;;IAIO,MAAME,sBAAAA,GAAyB;AAEtC;;;;;;;AAOC,IACM,MAAMC,qBAAAA,GAAwBD,sBAAAA,GAAyB;;;;"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RBAC gate for the future Media Library UI. Mirrors the legacy hook of the
|
|
3
|
+
* same name: the server already enforces every action route-side (assets and
|
|
4
|
+
* folder operations share the asset permissions — folder create requires
|
|
5
|
+
* `assets.create`, folder rename/move/delete require `assets.update`); this
|
|
6
|
+
* hook is what keeps the UI honest so users don't discover a missing
|
|
7
|
+
* permission through a 403.
|
|
8
|
+
*
|
|
9
|
+
* - `canCreate` — upload (files, from URL) and New folder
|
|
10
|
+
* - `canUpdate` — edit details, replace, crop, move (dnd + bulk), delete
|
|
11
|
+
* (single + bulk), AI metadata — the `assets.update` action covers
|
|
12
|
+
* "Update (crop, details, replace) + delete" by definition
|
|
13
|
+
* - `canDownload` / `canCopyLink` — the matching drawer actions
|
|
14
|
+
*/
|
|
15
|
+
export declare const useMediaLibraryPermissions: () => {
|
|
16
|
+
isLoading: boolean;
|
|
17
|
+
canCreate: boolean;
|
|
18
|
+
canUpdate: boolean;
|
|
19
|
+
canDownload: boolean;
|
|
20
|
+
canCopyLink: boolean;
|
|
21
|
+
};
|
|
@@ -5,6 +5,12 @@ interface AssetCropEditorProps {
|
|
|
5
5
|
onClose: () => void;
|
|
6
6
|
onApply: (file: globalThis.File, focalPoint: FocalPoint) => void;
|
|
7
7
|
onSaveAsCopy: (file: globalThis.File, focalPoint: FocalPoint) => void;
|
|
8
|
+
/**
|
|
9
|
+
* "Save as copy" creates a new asset (`assets.create`), a different permission
|
|
10
|
+
* from cropping in place (`assets.update`). Hidden when the user lacks it, so
|
|
11
|
+
* an update-only role can't trigger a 403.
|
|
12
|
+
*/
|
|
13
|
+
canSaveAsCopy: boolean;
|
|
8
14
|
}
|
|
9
|
-
export declare const AssetCropEditor: ({ asset, isBusy, onClose, onApply, onSaveAsCopy, }: AssetCropEditorProps) => import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
export declare const AssetCropEditor: ({ asset, isBusy, onClose, onApply, onSaveAsCopy, canSaveAsCopy, }: AssetCropEditorProps) => import("react/jsx-runtime").JSX.Element;
|
|
10
16
|
export {};
|
|
@@ -1,9 +1,15 @@
|
|
|
1
|
+
import { type MixedItem } from '../utils/mergeMixedList';
|
|
1
2
|
import type { File } from '../../../../../../shared/contracts/files';
|
|
2
3
|
import type { Folder } from '../../../../../../shared/contracts/folders';
|
|
3
4
|
interface AssetsTableProps {
|
|
4
5
|
assets: File[];
|
|
5
6
|
folders?: Folder[];
|
|
7
|
+
/**
|
|
8
|
+
* When set ("Folders: Mixed with files"), rows render in this interleaved
|
|
9
|
+
* order instead of folders-first. Range selection follows the same order.
|
|
10
|
+
*/
|
|
11
|
+
mixedItems?: MixedItem[] | null;
|
|
6
12
|
onAssetItemClick: (assetId: number) => void;
|
|
7
13
|
}
|
|
8
|
-
export declare const AssetsTable: ({ assets, folders, onAssetItemClick }: AssetsTableProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
14
|
+
export declare const AssetsTable: ({ assets, folders, mixedItems, onAssetItemClick, }: AssetsTableProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
9
15
|
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { File } from '../../../../../../shared/contracts/files';
|
|
2
|
+
interface BulkActionsBarProps {
|
|
3
|
+
/**
|
|
4
|
+
* The assets currently rendered in the list, used to resolve the mime types
|
|
5
|
+
* of the selection — the bar needs them to know which selected assets the AI
|
|
6
|
+
* provider can actually read.
|
|
7
|
+
*
|
|
8
|
+
* Selection is page-scoped and cleared whenever the list identity changes, so
|
|
9
|
+
* every selected asset id is guaranteed to appear here.
|
|
10
|
+
*/
|
|
11
|
+
assets?: File[];
|
|
12
|
+
}
|
|
13
|
+
export declare const BulkActionsBar: ({ assets }: BulkActionsBarProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
interface BulkMoveDialogProps {
|
|
2
|
+
open: boolean;
|
|
3
|
+
onClose: () => void;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* "Move elements to" modal for the bulk actions bar. Moves the current
|
|
7
|
+
* selection (assets and/or folders) into the picked destination folder via
|
|
8
|
+
* `POST /upload/actions/bulk-move`. The mutation invalidates the asset list,
|
|
9
|
+
* folder list and the sidebar folder-structure, so both panes refresh on
|
|
10
|
+
* success. On failure the modal stays open so the user can retry or cancel.
|
|
11
|
+
*/
|
|
12
|
+
export declare const BulkMoveDialog: ({ open, onClose }: BulkMoveDialogProps) => import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
interface DateRangeCalendarProps {
|
|
2
|
+
/** `YYYY-MM-DD`, both set when editing an existing range badge. */
|
|
3
|
+
from?: string;
|
|
4
|
+
to?: string;
|
|
5
|
+
onSelect: (from: string, to: string) => void;
|
|
6
|
+
}
|
|
7
|
+
export declare const DateRangeCalendar: ({ from, to, onSelect }: DateRangeCalendarProps) => import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export {};
|
|
@@ -2,6 +2,8 @@ import { type ReactNode } from 'react';
|
|
|
2
2
|
interface AssetsDndContextValue {
|
|
3
3
|
isInternalDragActive: boolean;
|
|
4
4
|
isMovePending: boolean;
|
|
5
|
+
/** O(1) lookup of whether the current drag set may drop on this destination. */
|
|
6
|
+
isValidDropTarget: (targetFolderId: number | null) => boolean;
|
|
5
7
|
}
|
|
6
8
|
export declare const useAssetsDnd: () => AssetsDndContextValue;
|
|
7
9
|
export declare const useAssetsDndOptional: () => AssetsDndContextValue | null;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { DragItemData } from '../../../../types/dnd';
|
|
2
2
|
interface DragOverlayChipProps {
|
|
3
|
-
|
|
3
|
+
items: DragItemData[];
|
|
4
4
|
}
|
|
5
|
-
export declare const DragOverlayChip: ({
|
|
5
|
+
export declare const DragOverlayChip: ({ items }: DragOverlayChipProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
6
6
|
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ItemKey } from '../../utils/selection';
|
|
2
|
+
import type { DragItemData } from '../../../../types/dnd';
|
|
3
|
+
export interface DragSet {
|
|
4
|
+
items: DragItemData[];
|
|
5
|
+
/** True when the active item was already selected — membership is the full selection. */
|
|
6
|
+
fromSelection: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Derive the drag payload once at drag start.
|
|
10
|
+
*
|
|
11
|
+
* - Dragging a selected item moves the complete current selection.
|
|
12
|
+
* - Dragging an unselected item moves only that item.
|
|
13
|
+
*
|
|
14
|
+
* Selection is page-scoped to the current folder, so every item is stamped with
|
|
15
|
+
* `currentFolderId` as its location for move validation.
|
|
16
|
+
*/
|
|
17
|
+
export declare const buildDragSet: (activeData: DragItemData, selectedKeys: Set<ItemKey> | undefined, currentFolderId: number | null) => DragSet;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { FolderNode } from '../../../../../../../shared/contracts/folders';
|
|
2
|
+
import type { DragItemData } from '../../../../types/dnd';
|
|
3
|
+
/**
|
|
4
|
+
* Evaluate destination validity once for the full drag set. Callers look up
|
|
5
|
+
* targets in O(1) via {@link Set.has} — `null` represents the Home/root drop.
|
|
6
|
+
*/
|
|
7
|
+
export declare const computeValidDropTargets: (items: DragItemData[], folderStructure: FolderNode[]) => Set<number | null>;
|
|
@@ -2,3 +2,6 @@ export declare const toFileDraggableId: (id: number) => `file:${number}`;
|
|
|
2
2
|
export declare const toFolderDraggableId: (id: number) => `folder:${number}`;
|
|
3
3
|
export declare const toFolderTargetId: (id: number) => `folder-target:${number}`;
|
|
4
4
|
export declare const parseFolderTargetId: (dndId: string | number) => number | null;
|
|
5
|
+
export declare const toFolderTreeTargetId: (id: number) => `folder-tree-target:${number}`;
|
|
6
|
+
export declare const HOME_TREE_TARGET_ID: "folder-tree-target:home";
|
|
7
|
+
export declare const parseFolderTreeTargetId: (dndId: string | number) => number | "root" | null;
|
|
@@ -2,7 +2,9 @@ import type { DragFolderData } from '../../../../types/dnd';
|
|
|
2
2
|
export declare const useFileDraggable: (asset: {
|
|
3
3
|
id: number;
|
|
4
4
|
name: string;
|
|
5
|
-
folder?: number | string |
|
|
5
|
+
folder?: number | string | {
|
|
6
|
+
id?: number;
|
|
7
|
+
} | null;
|
|
6
8
|
}) => {
|
|
7
9
|
active: import("@dnd-kit/core").Active | null;
|
|
8
10
|
activatorEvent: Event | null;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const useFolderTreeDroppable: (target: {
|
|
2
|
+
id: number;
|
|
3
|
+
name: string;
|
|
4
|
+
} | {
|
|
5
|
+
id: null;
|
|
6
|
+
name: string;
|
|
7
|
+
}) => {
|
|
8
|
+
droppable: {
|
|
9
|
+
active: import("@dnd-kit/core").Active | null;
|
|
10
|
+
rect: import("react").MutableRefObject<import("@dnd-kit/core").ClientRect | null>;
|
|
11
|
+
isOver: boolean;
|
|
12
|
+
node: import("react").MutableRefObject<HTMLElement | null>;
|
|
13
|
+
over: import("@dnd-kit/core").Over | null;
|
|
14
|
+
setNodeRef: (element: HTMLElement | null) => void;
|
|
15
|
+
};
|
|
16
|
+
isOver: boolean;
|
|
17
|
+
showValidDropHighlight: boolean;
|
|
18
|
+
showInvalidDropCursor: boolean;
|
|
19
|
+
};
|
|
@@ -3,8 +3,15 @@ type DropHandler = (files: File[]) => void | Promise<void>;
|
|
|
3
3
|
interface UploadDropZoneProps {
|
|
4
4
|
children: ReactNode;
|
|
5
5
|
onDrop?: DropHandler;
|
|
6
|
+
/**
|
|
7
|
+
* When true, the zone never enters the dragging state and never fires
|
|
8
|
+
* `onDrop` — no overlay, no "drop here" invitation. Used to hide the whole
|
|
9
|
+
* upload affordance from users without `assets.create`, so they don't drag a
|
|
10
|
+
* file onto an inviting target that then silently discards it.
|
|
11
|
+
*/
|
|
12
|
+
disabled?: boolean;
|
|
6
13
|
}
|
|
7
|
-
export declare const UploadDropZoneProvider: ({ children, onDrop }: UploadDropZoneProps) => import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export declare const UploadDropZoneProvider: ({ children, onDrop, disabled, }: UploadDropZoneProps) => import("react/jsx-runtime").JSX.Element;
|
|
8
15
|
export declare const useUploadDropZone: () => {
|
|
9
16
|
isDragging: boolean;
|
|
10
17
|
};
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
interface EmptyStateProps {
|
|
2
2
|
onAddAssets: () => void;
|
|
3
|
+
/**
|
|
4
|
+
* RBAC gate — without `assets.create` the "Add assets" CTA is hidden.
|
|
5
|
+
* Required (not defaulted) so a permission gate can't silently regress to
|
|
6
|
+
* permissive when a future call site forgets to pass it.
|
|
7
|
+
*/
|
|
8
|
+
canAddAssets: boolean;
|
|
9
|
+
searchQuery?: string;
|
|
10
|
+
onClearSearch?: () => void;
|
|
3
11
|
}
|
|
4
12
|
/**
|
|
5
13
|
* Empty state for the assets list (both views) when the current folder holds
|
|
@@ -7,5 +15,14 @@ interface EmptyStateProps {
|
|
|
7
15
|
* as New > File upload; drag-and-drop upload keeps working since the page-wide
|
|
8
16
|
* drop zone wraps this component.
|
|
9
17
|
*/
|
|
10
|
-
export declare const EmptyState: ({ onAddAssets }: EmptyStateProps) => import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
export declare const EmptyState: ({ onAddAssets, canAddAssets, searchQuery, onClearSearch, }: EmptyStateProps) => import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
interface FilteredEmptyStateProps {
|
|
20
|
+
onClearFilters: () => void;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Empty state when active filters match nothing (including contradictory
|
|
24
|
+
* badges — allowed by design). Distinct from the no-content state: the library
|
|
25
|
+
* has items, the filters exclude them all.
|
|
26
|
+
*/
|
|
27
|
+
export declare const FilteredEmptyState: ({ onClearFilters }: FilteredEmptyStateProps) => import("react/jsx-runtime").JSX.Element;
|
|
11
28
|
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type DateField, type DatePreset, type ListFilters, type TypeValue } from '../hooks/useListFilters';
|
|
2
|
+
import type { MessageDescriptor } from 'react-intl';
|
|
3
|
+
export declare const TYPE_LABELS: Record<TypeValue, MessageDescriptor>;
|
|
4
|
+
export declare const PRESET_LABELS: Record<DatePreset, MessageDescriptor>;
|
|
5
|
+
export declare const DATE_FIELD_LABELS: Record<DateField, MessageDescriptor>;
|
|
6
|
+
/** Every panel of the filter tree shares this fixed width (design). */
|
|
7
|
+
export declare const FILTER_PANEL_WIDTH = "24.2rem";
|
|
8
|
+
interface FilterMenuProps {
|
|
9
|
+
listFilters: ListFilters;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Toolbar "Filter" dropdown. Picking anything ADDS a badge (editing happens on
|
|
13
|
+
* the badge itself, see FilterBadges):
|
|
14
|
+
*
|
|
15
|
+
* - Type → keep-open checkbox list; the badge is created/updated live with the
|
|
16
|
+
* checked set (`is` by default, condition editable on the badge).
|
|
17
|
+
* - Creation date / Last modified → preset list (single pick, `within the
|
|
18
|
+
* last` by default) + "Select date range" (creation date only) opening the
|
|
19
|
+
* range calendar; a completed range adds an `is` range badge.
|
|
20
|
+
*/
|
|
21
|
+
export declare const FilterMenu: ({ listFilters }: FilterMenuProps) => import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
export {};
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
interface FolderTreeProps {
|
|
2
2
|
currentFolderId: number | null;
|
|
3
|
+
/**
|
|
4
|
+
* Set to `false` while a global asset search is active: the results span the
|
|
5
|
+
* whole library, so highlighting one folder would misrepresent them.
|
|
6
|
+
* */
|
|
7
|
+
showActiveFolder?: boolean;
|
|
3
8
|
onSelectFolder: (folderId: number | null) => void;
|
|
4
9
|
}
|
|
5
10
|
/**
|
|
@@ -7,13 +12,17 @@ interface FolderTreeProps {
|
|
|
7
12
|
* and renders:
|
|
8
13
|
*
|
|
9
14
|
* 1. A "Media library" title
|
|
10
|
-
* 2. A
|
|
11
|
-
* 3. A "
|
|
12
|
-
* 4.
|
|
15
|
+
* 2. A filter input that prunes the tree to matching destinations
|
|
16
|
+
* 3. A "Home" entry that clears the folder query param
|
|
17
|
+
* 4. A "FOLDERS" section header
|
|
18
|
+
* 5. The folder tree itself
|
|
19
|
+
*
|
|
20
|
+
* The filter is purely local: it never touches the URL and never affects the
|
|
21
|
+
* asset list, which has its own independent search in the content toolbar.
|
|
13
22
|
*
|
|
14
23
|
* Presentational with respect to routing — navigation is delegated to the parent
|
|
15
24
|
* via `onSelectFolder` so the URL stays the single source of truth (see
|
|
16
25
|
* `useFolderNavigation`).
|
|
17
26
|
*/
|
|
18
|
-
export declare const FolderTree: ({ currentFolderId, onSelectFolder }: FolderTreeProps) => import("react/jsx-runtime").JSX.Element;
|
|
27
|
+
export declare const FolderTree: ({ currentFolderId, showActiveFolder, onSelectFolder, }: FolderTreeProps) => import("react/jsx-runtime").JSX.Element;
|
|
19
28
|
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { FolderNode } from '../../../../../../../shared/contracts/folders';
|
|
2
|
+
interface FilterFolderTreeResult {
|
|
3
|
+
nodes: FolderNode[];
|
|
4
|
+
/**
|
|
5
|
+
* Ancestors of a match, which have to be expanded for the match to be
|
|
6
|
+
* reachable.
|
|
7
|
+
*/
|
|
8
|
+
expandedIds: number[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Prunes the folder tree to nodes that match, or that have a matching
|
|
12
|
+
* descendant, so a match deep in the hierarchy stays reachable with its ancestor
|
|
13
|
+
* chain intact.
|
|
14
|
+
*/
|
|
15
|
+
export declare const filterFolderTree: (nodes: FolderNode[], matches: (name: string) => boolean) => FilterFolderTreeResult;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type ListSort } from '../hooks/useListSort';
|
|
2
|
+
interface SortMenuProps {
|
|
3
|
+
sort: ListSort;
|
|
4
|
+
/**
|
|
5
|
+
* The grid view forces folders on top (mixing folder cards with asset cards
|
|
6
|
+
* is not supported there), so it hides the Folders group entirely.
|
|
7
|
+
*/
|
|
8
|
+
showFoldersGroup?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Toolbar "Sort" dropdown: single-select sections (Sort / Folders). Picking an
|
|
12
|
+
* option keeps the menu open (`onSelect` preventDefault) so several facets can
|
|
13
|
+
* be tuned in one visit; clicking a checked facet clears it (the hook
|
|
14
|
+
* guarantees at least one sort rule stays active).
|
|
15
|
+
*
|
|
16
|
+
* Each section is single-select, so its items are radios: the checkmark icon is
|
|
17
|
+
* decorative, and `aria-checked` is what assistive tech reads. The DS `Menu`
|
|
18
|
+
* exposes no `RadioItem`, but `Menu.Item` forwards extra props onto the element
|
|
19
|
+
* it renders through Radix's `asChild`, where they take precedence over Radix's
|
|
20
|
+
* own `role="menuitem"`.
|
|
21
|
+
*/
|
|
22
|
+
export declare const SortMenu: ({ sort, showFoldersGroup }: SortMenuProps) => import("react/jsx-runtime").JSX.Element;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads and writes the global asset search term held in `?_q=`.
|
|
3
|
+
*
|
|
4
|
+
* Debouncing is the input component's job (see `AssetsSearchInput`) — this hook
|
|
5
|
+
* is a thin URL accessor so every consumer reads the same source of truth.
|
|
6
|
+
*/
|
|
7
|
+
export declare const useAssetSearch: () => {
|
|
8
|
+
searchQuery: string;
|
|
9
|
+
isSearching: boolean;
|
|
10
|
+
setSearchQuery: (value: string) => void;
|
|
11
|
+
clearSearch: () => void;
|
|
12
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import { type ItemKey } from '../utils/selection';
|
|
3
|
+
/**
|
|
4
|
+
* Ephemeral, view-state-only multi-select for the future Media Library. Selection
|
|
5
|
+
* is page-scoped and reset on folder navigation or sort/filter changes (the
|
|
6
|
+
* table/grid toggle keeps it — same list, different presentation).
|
|
7
|
+
*
|
|
8
|
+
* The actual computation lives in `../utils/selection.ts` (pure + unit-tested);
|
|
9
|
+
* this hook is a thin React wrapper. Assets and folders share one mechanism —
|
|
10
|
+
* items are tracked as namespaced keys (`asset:1` / `folder:1`) so toggle, range
|
|
11
|
+
* and select-all behave the same for both. Range / select-all receive the
|
|
12
|
+
* ordered key array from the caller (the view owns the rendered order), keeping
|
|
13
|
+
* the context data-source-agnostic.
|
|
14
|
+
*/
|
|
15
|
+
export interface AssetSelection {
|
|
16
|
+
/** Every selected item key (assets and folders), render-order agnostic. */
|
|
17
|
+
selectedKeys: Set<ItemKey>;
|
|
18
|
+
/** Selected asset ids, derived from {@link selectedKeys}. */
|
|
19
|
+
selectedIds: Set<number>;
|
|
20
|
+
/** Selected folder ids, derived from {@link selectedKeys}. */
|
|
21
|
+
selectedFolderIds: Set<number>;
|
|
22
|
+
anchorKey: ItemKey | null;
|
|
23
|
+
isSelected: (key: ItemKey) => boolean;
|
|
24
|
+
/** Additive toggle (Cmd/Ctrl+click, item checkbox). */
|
|
25
|
+
toggle: (key: ItemKey) => void;
|
|
26
|
+
/** Shift+click — selects the contiguous range from the anchor to the target. */
|
|
27
|
+
selectRange: (orderedKeys: ItemKey[], targetKey: ItemKey) => void;
|
|
28
|
+
/** Header checkbox — selects every rendered item (folders and assets). */
|
|
29
|
+
selectAll: (orderedKeys: ItemKey[]) => void;
|
|
30
|
+
/** Close button / folder navigation / list-identity changes. */
|
|
31
|
+
clear: () => void;
|
|
32
|
+
}
|
|
33
|
+
interface AssetSelectionProviderProps {
|
|
34
|
+
children: ReactNode;
|
|
35
|
+
/**
|
|
36
|
+
* When true, selection is inert: every mutator is a no-op and nothing ever
|
|
37
|
+
* reads as selected. Every bulk action is gated on `assets.update`, so a user
|
|
38
|
+
* without it has nothing to select for — the views also hide the checkboxes,
|
|
39
|
+
* and this makes the remaining paths (click-to-select, Space key) do nothing.
|
|
40
|
+
*/
|
|
41
|
+
disabled?: boolean;
|
|
42
|
+
}
|
|
43
|
+
export declare const AssetSelectionProvider: ({ children, disabled, }: AssetSelectionProviderProps) => import("react").FunctionComponentElement<import("react").ProviderProps<AssetSelection | null>>;
|
|
44
|
+
export declare const useAssetSelection: () => AssetSelection;
|
|
45
|
+
export declare const useAssetSelectionOptional: () => AssetSelection | null;
|
|
46
|
+
export {};
|
|
@@ -1,12 +1,22 @@
|
|
|
1
|
-
import type { File } from '../../../../../../shared/contracts/files';
|
|
1
|
+
import type { File, Pagination } from '../../../../../../shared/contracts/files';
|
|
2
2
|
declare const PAGE_SIZE = 20;
|
|
3
3
|
interface UseInfiniteAssetsOptions {
|
|
4
4
|
folder?: number | null;
|
|
5
5
|
sort?: string;
|
|
6
|
+
search?: string;
|
|
7
|
+
/** Extra `filters[$and]` entries for the files query. */
|
|
8
|
+
filters?: Record<string, unknown>[];
|
|
9
|
+
/**
|
|
10
|
+
* Stable fingerprint of `filters` — a change resets the accumulated pages
|
|
11
|
+
* (the array identity itself changes every render).
|
|
12
|
+
*/
|
|
13
|
+
filtersKey?: string;
|
|
14
|
+
/** Structural switch: an `is [folder]`-only type badge means no file can match. */
|
|
15
|
+
enabled?: boolean;
|
|
6
16
|
}
|
|
7
|
-
declare const useInfiniteAssets: ({ folder, sort }?: UseInfiniteAssetsOptions) => {
|
|
17
|
+
declare const useInfiniteAssets: ({ folder, sort, search, filters, filtersKey, enabled, }?: UseInfiniteAssetsOptions) => {
|
|
8
18
|
assets: File[];
|
|
9
|
-
pagination:
|
|
19
|
+
pagination: Pagination | undefined;
|
|
10
20
|
isLoading: boolean;
|
|
11
21
|
isFetchingMore: boolean;
|
|
12
22
|
hasNextPage: boolean;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filter state for the assets list, backed by a single `?filters=` query param
|
|
3
|
+
* so the applied filters are shareable and survive Back/refresh.
|
|
4
|
+
*
|
|
5
|
+
* Serialized grammar — badges separated by `;`, one badge is
|
|
6
|
+
* `<field>:<condition>:<value>`:
|
|
7
|
+
*
|
|
8
|
+
* - `type:is:picture,audio` / `type:not:folder`
|
|
9
|
+
* - `created:within:1week` / `updated:notwithin:3months` / `created:exact:1day`
|
|
10
|
+
* - `created:rangeis:2024-01-01..2024-04-07` / `created:rangenot:...`
|
|
11
|
+
*
|
|
12
|
+
* Relative presets stay relative in the URL on purpose: the badge label
|
|
13
|
+
* ("1 week ago") remains truthful forever and a shared link means "within the
|
|
14
|
+
* last week from whenever it is opened". Resolution to absolute timestamps
|
|
15
|
+
* happens at query-build time (see utils/buildAssetFilters.ts).
|
|
16
|
+
*
|
|
17
|
+
* Several badges for the same field are allowed, even contradictory ones —
|
|
18
|
+
* everything is combined with AND; contradictions simply produce the filtered
|
|
19
|
+
* empty state.
|
|
20
|
+
*/
|
|
21
|
+
export declare const TYPE_VALUES: readonly ["folder", "picture", "audio", "video", "document"];
|
|
22
|
+
export type TypeValue = (typeof TYPE_VALUES)[number];
|
|
23
|
+
export declare const DATE_PRESETS: readonly ["1day", "3days", "1week", "1month", "3months", "6months", "1year"];
|
|
24
|
+
export type DatePreset = (typeof DATE_PRESETS)[number];
|
|
25
|
+
export type TypeCondition = 'is' | 'isNot';
|
|
26
|
+
export type PresetCondition = 'isExactly' | 'withinLast' | 'notWithinLast';
|
|
27
|
+
export type RangeCondition = 'is' | 'isNot';
|
|
28
|
+
export type DateField = 'createdAt' | 'updatedAt';
|
|
29
|
+
export interface TypeFilter {
|
|
30
|
+
kind: 'type';
|
|
31
|
+
condition: TypeCondition;
|
|
32
|
+
values: TypeValue[];
|
|
33
|
+
}
|
|
34
|
+
export interface DatePresetFilter {
|
|
35
|
+
kind: 'date';
|
|
36
|
+
field: DateField;
|
|
37
|
+
mode: 'preset';
|
|
38
|
+
condition: PresetCondition;
|
|
39
|
+
preset: DatePreset;
|
|
40
|
+
}
|
|
41
|
+
export interface DateRangeFilter {
|
|
42
|
+
kind: 'date';
|
|
43
|
+
field: DateField;
|
|
44
|
+
mode: 'range';
|
|
45
|
+
condition: RangeCondition;
|
|
46
|
+
/** Calendar dates, `YYYY-MM-DD`, inclusive on both ends. */
|
|
47
|
+
from: string;
|
|
48
|
+
to: string;
|
|
49
|
+
}
|
|
50
|
+
export type DateFilter = DatePresetFilter | DateRangeFilter;
|
|
51
|
+
export type ListFilter = TypeFilter | DateFilter;
|
|
52
|
+
/**
|
|
53
|
+
* `unknown` on purpose: the query string is user-editable, and qs parses
|
|
54
|
+
* shapes like `?filters[]=a&filters[]=b` into arrays — the guard is what
|
|
55
|
+
* makes the caller's `?filters=` type an assertion rather than a crash.
|
|
56
|
+
*/
|
|
57
|
+
export declare const parseFiltersParam: (raw: unknown) => ListFilter[];
|
|
58
|
+
export declare const serializeFilters: (filters: ListFilter[]) => string;
|
|
59
|
+
export interface ListFilters {
|
|
60
|
+
filters: ListFilter[];
|
|
61
|
+
/** Serialized form — stable fingerprint for list-identity (selection reset). */
|
|
62
|
+
serialized: string;
|
|
63
|
+
addFilter: (filter: ListFilter) => void;
|
|
64
|
+
/** Replaces the badge at `index` (condition or value edited in place). */
|
|
65
|
+
updateFilter: (index: number, filter: ListFilter) => void;
|
|
66
|
+
removeFilter: (index: number) => void;
|
|
67
|
+
clearFilters: () => void;
|
|
68
|
+
}
|
|
69
|
+
export declare const useListFilters: () => ListFilters;
|