@strapi/upload 5.58.0 → 5.59.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/components/MediaLibraryInput/AddAssetMenu.js +141 -0
- package/dist/admin/components/MediaLibraryInput/AddAssetMenu.js.map +1 -0
- package/dist/admin/components/MediaLibraryInput/AddAssetMenu.mjs +139 -0
- package/dist/admin/components/MediaLibraryInput/AddAssetMenu.mjs.map +1 -0
- package/dist/admin/components/MediaLibraryInput/AssetDropZone.js +129 -0
- package/dist/admin/components/MediaLibraryInput/AssetDropZone.js.map +1 -0
- package/dist/admin/components/MediaLibraryInput/AssetDropZone.mjs +127 -0
- package/dist/admin/components/MediaLibraryInput/AssetDropZone.mjs.map +1 -0
- package/dist/admin/components/MediaLibraryInput/AssetRow.js +144 -0
- package/dist/admin/components/MediaLibraryInput/AssetRow.js.map +1 -0
- package/dist/admin/components/MediaLibraryInput/AssetRow.mjs +142 -0
- package/dist/admin/components/MediaLibraryInput/AssetRow.mjs.map +1 -0
- package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.js +397 -0
- package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.js.map +1 -0
- package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.mjs +395 -0
- package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.mjs.map +1 -0
- package/dist/admin/components/MediaLibraryInput/NoLibraryAccessDialog.js +45 -0
- package/dist/admin/components/MediaLibraryInput/NoLibraryAccessDialog.js.map +1 -0
- package/dist/admin/components/MediaLibraryInput/NoLibraryAccessDialog.mjs +43 -0
- package/dist/admin/components/MediaLibraryInput/NoLibraryAccessDialog.mjs.map +1 -0
- package/dist/admin/hooks/useAIMetadataAvailability.js +5 -1
- package/dist/admin/hooks/useAIMetadataAvailability.js.map +1 -1
- package/dist/admin/hooks/useAIMetadataAvailability.mjs +5 -1
- package/dist/admin/hooks/useAIMetadataAvailability.mjs.map +1 -1
- package/dist/admin/hooks/useAIMetadataEnabled.js +7 -1
- package/dist/admin/hooks/useAIMetadataEnabled.js.map +1 -1
- package/dist/admin/hooks/useAIMetadataEnabled.mjs +7 -1
- package/dist/admin/hooks/useAIMetadataEnabled.mjs.map +1 -1
- package/dist/admin/hooks/useMediaLibraryPermissions.js +4 -0
- package/dist/admin/hooks/useMediaLibraryPermissions.js.map +1 -1
- package/dist/admin/hooks/useMediaLibraryPermissions.mjs +4 -0
- package/dist/admin/hooks/useMediaLibraryPermissions.mjs.map +1 -1
- package/dist/admin/hooks/useTracking.js +5 -1
- package/dist/admin/hooks/useTracking.js.map +1 -1
- package/dist/admin/hooks/useTracking.mjs +5 -1
- package/dist/admin/hooks/useTracking.mjs.map +1 -1
- package/dist/admin/index.js +7 -2
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +7 -2
- package/dist/admin/index.mjs.map +1 -1
- package/dist/admin/legacy/components/AssetCard/AssetCardBase.js.map +1 -1
- package/dist/admin/legacy/components/AssetCard/AssetCardBase.mjs.map +1 -1
- package/dist/admin/legacy/components/AssetCard/VideoPreview.js +2 -1
- package/dist/admin/legacy/components/AssetCard/VideoPreview.js.map +1 -1
- package/dist/admin/legacy/components/AssetCard/VideoPreview.mjs +2 -1
- package/dist/admin/legacy/components/AssetCard/VideoPreview.mjs.map +1 -1
- package/dist/admin/legacy/components/AssetDialog/AssetDialog.js +3 -1
- package/dist/admin/legacy/components/AssetDialog/AssetDialog.js.map +1 -1
- package/dist/admin/legacy/components/AssetDialog/AssetDialog.mjs +3 -1
- package/dist/admin/legacy/components/AssetDialog/AssetDialog.mjs.map +1 -1
- package/dist/admin/legacy/components/AssetDialog/BrowseStep/BrowseStep.js +3 -1
- package/dist/admin/legacy/components/AssetDialog/BrowseStep/BrowseStep.js.map +1 -1
- package/dist/admin/legacy/components/AssetDialog/BrowseStep/BrowseStep.mjs +3 -1
- package/dist/admin/legacy/components/AssetDialog/BrowseStep/BrowseStep.mjs.map +1 -1
- package/dist/admin/legacy/components/AssetDialog/BrowseStep/Filters.js.map +1 -1
- package/dist/admin/legacy/components/AssetDialog/BrowseStep/Filters.mjs.map +1 -1
- package/dist/admin/legacy/components/AssetGridList/AssetGridList.js +7 -6
- package/dist/admin/legacy/components/AssetGridList/AssetGridList.js.map +1 -1
- package/dist/admin/legacy/components/AssetGridList/AssetGridList.mjs +7 -6
- package/dist/admin/legacy/components/AssetGridList/AssetGridList.mjs.map +1 -1
- package/dist/admin/legacy/components/Breadcrumbs/CrumbSimpleMenuAsync.js +2 -1
- package/dist/admin/legacy/components/Breadcrumbs/CrumbSimpleMenuAsync.js.map +1 -1
- package/dist/admin/legacy/components/Breadcrumbs/CrumbSimpleMenuAsync.mjs +2 -1
- package/dist/admin/legacy/components/Breadcrumbs/CrumbSimpleMenuAsync.mjs.map +1 -1
- package/dist/admin/legacy/components/BulkMoveDialog/BulkMoveDialog.js +2 -1
- package/dist/admin/legacy/components/BulkMoveDialog/BulkMoveDialog.js.map +1 -1
- package/dist/admin/legacy/components/BulkMoveDialog/BulkMoveDialog.mjs +2 -1
- package/dist/admin/legacy/components/BulkMoveDialog/BulkMoveDialog.mjs.map +1 -1
- package/dist/admin/legacy/components/EditAssetDialog/EditAssetContent.js +3 -1
- package/dist/admin/legacy/components/EditAssetDialog/EditAssetContent.js.map +1 -1
- package/dist/admin/legacy/components/EditAssetDialog/EditAssetContent.mjs +3 -1
- package/dist/admin/legacy/components/EditAssetDialog/EditAssetContent.mjs.map +1 -1
- package/dist/admin/legacy/components/FilterList/FilterList.js.map +1 -1
- package/dist/admin/legacy/components/FilterList/FilterList.mjs.map +1 -1
- package/dist/admin/legacy/components/FilterPopover/FilterPopover.js.map +1 -1
- package/dist/admin/legacy/components/FilterPopover/FilterPopover.mjs.map +1 -1
- package/dist/admin/legacy/components/FilterPopover/FilterValueInput.js +2 -1
- package/dist/admin/legacy/components/FilterPopover/FilterValueInput.js.map +1 -1
- package/dist/admin/legacy/components/FilterPopover/FilterValueInput.mjs +2 -1
- package/dist/admin/legacy/components/FilterPopover/FilterValueInput.mjs.map +1 -1
- package/dist/admin/legacy/components/MediaLibraryDialog/MediaLibraryDialog.js +4 -2
- package/dist/admin/legacy/components/MediaLibraryDialog/MediaLibraryDialog.js.map +1 -1
- package/dist/admin/legacy/components/MediaLibraryDialog/MediaLibraryDialog.mjs +4 -2
- package/dist/admin/legacy/components/MediaLibraryDialog/MediaLibraryDialog.mjs.map +1 -1
- package/dist/admin/legacy/components/MediaLibraryInput/MediaLibraryInput.js +2 -1
- package/dist/admin/legacy/components/MediaLibraryInput/MediaLibraryInput.js.map +1 -1
- package/dist/admin/legacy/components/MediaLibraryInput/MediaLibraryInput.mjs +2 -1
- package/dist/admin/legacy/components/MediaLibraryInput/MediaLibraryInput.mjs.map +1 -1
- package/dist/admin/legacy/components/SelectTree/SelectTree.js +3 -1
- package/dist/admin/legacy/components/SelectTree/SelectTree.js.map +1 -1
- package/dist/admin/legacy/components/SelectTree/SelectTree.mjs +3 -1
- package/dist/admin/legacy/components/SelectTree/SelectTree.mjs.map +1 -1
- package/dist/admin/legacy/components/TableList/TableList.js +3 -1
- package/dist/admin/legacy/components/TableList/TableList.js.map +1 -1
- package/dist/admin/legacy/components/TableList/TableList.mjs +3 -1
- package/dist/admin/legacy/components/TableList/TableList.mjs.map +1 -1
- package/dist/admin/legacy/components/TableList/TableRows.js +3 -1
- package/dist/admin/legacy/components/TableList/TableRows.js.map +1 -1
- package/dist/admin/legacy/components/TableList/TableRows.mjs +3 -1
- package/dist/admin/legacy/components/TableList/TableRows.mjs.map +1 -1
- package/dist/admin/legacy/components/UploadAssetDialog/UploadAssetDialog.js +3 -1
- package/dist/admin/legacy/components/UploadAssetDialog/UploadAssetDialog.js.map +1 -1
- package/dist/admin/legacy/components/UploadAssetDialog/UploadAssetDialog.mjs +3 -1
- package/dist/admin/legacy/components/UploadAssetDialog/UploadAssetDialog.mjs.map +1 -1
- package/dist/admin/legacy/pages/App/ConfigureTheView/ConfigureTheView.js.map +1 -1
- package/dist/admin/legacy/pages/App/ConfigureTheView/ConfigureTheView.mjs.map +1 -1
- package/dist/admin/legacy/pages/App/components/BulkActions.js +2 -1
- package/dist/admin/legacy/pages/App/components/BulkActions.js.map +1 -1
- package/dist/admin/legacy/pages/App/components/BulkActions.mjs +2 -1
- package/dist/admin/legacy/pages/App/components/BulkActions.mjs.map +1 -1
- package/dist/admin/legacy/pages/App/components/BulkMoveButton.js +2 -1
- package/dist/admin/legacy/pages/App/components/BulkMoveButton.js.map +1 -1
- package/dist/admin/legacy/pages/App/components/BulkMoveButton.mjs +2 -1
- package/dist/admin/legacy/pages/App/components/BulkMoveButton.mjs.map +1 -1
- package/dist/admin/pages/Assets/components/AssetsGrid.js +2 -1
- package/dist/admin/pages/Assets/components/AssetsGrid.js.map +1 -1
- package/dist/admin/pages/Assets/components/AssetsGrid.mjs +2 -1
- package/dist/admin/pages/Assets/components/AssetsGrid.mjs.map +1 -1
- package/dist/admin/pages/Assets/components/AssetsTable.js +2 -1
- package/dist/admin/pages/Assets/components/AssetsTable.js.map +1 -1
- package/dist/admin/pages/Assets/components/AssetsTable.mjs +2 -1
- package/dist/admin/pages/Assets/components/AssetsTable.mjs.map +1 -1
- package/dist/admin/pages/Assets/components/BulkActionsBar.js +3 -1
- package/dist/admin/pages/Assets/components/BulkActionsBar.js.map +1 -1
- package/dist/admin/pages/Assets/components/BulkActionsBar.mjs +3 -1
- package/dist/admin/pages/Assets/components/BulkActionsBar.mjs.map +1 -1
- package/dist/admin/pages/Assets/components/DateRangeCalendar.js +10 -7
- package/dist/admin/pages/Assets/components/DateRangeCalendar.js.map +1 -1
- package/dist/admin/pages/Assets/components/DateRangeCalendar.mjs +10 -7
- package/dist/admin/pages/Assets/components/DateRangeCalendar.mjs.map +1 -1
- package/dist/admin/pages/Assets/components/DropZone/UploadDropZoneContext.js +4 -2
- package/dist/admin/pages/Assets/components/DropZone/UploadDropZoneContext.js.map +1 -1
- package/dist/admin/pages/Assets/components/DropZone/UploadDropZoneContext.mjs +5 -3
- package/dist/admin/pages/Assets/components/DropZone/UploadDropZoneContext.mjs.map +1 -1
- package/dist/admin/pages/Assets/components/FilterBadges.js +32 -3
- package/dist/admin/pages/Assets/components/FilterBadges.js.map +1 -1
- package/dist/admin/pages/Assets/components/FilterBadges.mjs +33 -4
- package/dist/admin/pages/Assets/components/FilterBadges.mjs.map +1 -1
- package/dist/admin/services/api.js +15 -5
- package/dist/admin/services/api.js.map +1 -1
- package/dist/admin/services/api.mjs +15 -5
- package/dist/admin/services/api.mjs.map +1 -1
- package/dist/admin/src/components/MediaLibraryInput/AddAssetMenu.d.ts +19 -0
- package/dist/admin/src/components/MediaLibraryInput/AssetDropZone.d.ts +13 -0
- package/dist/admin/src/components/MediaLibraryInput/AssetRow.d.ts +15 -0
- package/dist/admin/src/components/MediaLibraryInput/MediaLibraryInput.d.ts +26 -0
- package/dist/admin/src/components/MediaLibraryInput/NoLibraryAccessDialog.d.ts +10 -0
- package/dist/admin/src/hooks/useMediaLibraryPermissions.d.ts +1 -0
- package/dist/admin/src/legacy/components/BulkMoveDialog/BulkMoveDialog.d.ts +1 -1
- package/dist/admin/src/legacy/pages/App/components/BulkActions.d.ts +1 -1
- package/dist/admin/src/services/api.d.ts +6 -0
- package/dist/admin/src/utils/allowedMediaTypes.d.ts +16 -0
- package/dist/admin/translations/ca.json.js +3 -3
- package/dist/admin/translations/ca.json.mjs +3 -3
- package/dist/admin/translations/da.json.js +1 -1
- package/dist/admin/translations/da.json.mjs +1 -1
- package/dist/admin/translations/de.json.js +1 -1
- package/dist/admin/translations/de.json.mjs +1 -1
- package/dist/admin/translations/en.json.js +9 -0
- package/dist/admin/translations/en.json.js.map +1 -1
- package/dist/admin/translations/en.json.mjs +9 -0
- package/dist/admin/translations/en.json.mjs.map +1 -1
- package/dist/admin/translations/es.json.js +1 -1
- package/dist/admin/translations/es.json.mjs +1 -1
- package/dist/admin/translations/sk.json.js +2 -2
- package/dist/admin/translations/sk.json.mjs +2 -2
- package/dist/admin/translations/tr.json.js +2 -2
- package/dist/admin/translations/tr.json.mjs +2 -2
- package/dist/admin/translations/zh-Hans.json.js +1 -1
- package/dist/admin/translations/zh-Hans.json.mjs +1 -1
- package/dist/admin/translations/zh.json.js +2 -2
- package/dist/admin/translations/zh.json.mjs +2 -2
- package/dist/admin/utils/allowedMediaTypes.js +42 -0
- package/dist/admin/utils/allowedMediaTypes.js.map +1 -0
- package/dist/admin/utils/allowedMediaTypes.mjs +39 -0
- package/dist/admin/utils/allowedMediaTypes.mjs.map +1 -0
- package/dist/server/config.js +6 -0
- package/dist/server/config.js.map +1 -1
- package/dist/server/config.mjs +6 -0
- package/dist/server/config.mjs.map +1 -1
- package/dist/server/controllers/validation/admin/upload.js.map +1 -1
- package/dist/server/controllers/validation/admin/upload.mjs.map +1 -1
- package/dist/server/controllers/validation/content-api/upload.js.map +1 -1
- package/dist/server/controllers/validation/content-api/upload.mjs.map +1 -1
- package/dist/server/mcp/ambient-instance.js +7 -5
- package/dist/server/mcp/ambient-instance.js.map +1 -1
- package/dist/server/mcp/ambient-instance.mjs +7 -5
- package/dist/server/mcp/ambient-instance.mjs.map +1 -1
- package/dist/server/mcp/handlers/folder-handlers.js +4 -16
- package/dist/server/mcp/handlers/folder-handlers.js.map +1 -1
- package/dist/server/mcp/handlers/folder-handlers.mjs +5 -17
- package/dist/server/mcp/handlers/folder-handlers.mjs.map +1 -1
- package/dist/server/mcp/handlers/read-handlers.js +6 -14
- package/dist/server/mcp/handlers/read-handlers.js.map +1 -1
- package/dist/server/mcp/handlers/read-handlers.mjs +7 -15
- package/dist/server/mcp/handlers/read-handlers.mjs.map +1 -1
- package/dist/server/mcp/handlers/write-handlers.js +3 -13
- package/dist/server/mcp/handlers/write-handlers.js.map +1 -1
- package/dist/server/mcp/handlers/write-handlers.mjs +3 -13
- package/dist/server/mcp/handlers/write-handlers.mjs.map +1 -1
- package/dist/server/mcp/register-upload-mcp-tools.js +215 -195
- package/dist/server/mcp/register-upload-mcp-tools.js.map +1 -1
- package/dist/server/mcp/register-upload-mcp-tools.mjs +215 -195
- package/dist/server/mcp/register-upload-mcp-tools.mjs.map +1 -1
- package/dist/server/services/image-manipulation.js +33 -14
- package/dist/server/services/image-manipulation.js.map +1 -1
- package/dist/server/services/image-manipulation.mjs +33 -14
- package/dist/server/services/image-manipulation.mjs.map +1 -1
- package/dist/server/src/config.d.ts +3 -0
- package/dist/server/src/config.d.ts.map +1 -1
- package/dist/server/src/controllers/validation/admin/upload.d.ts.map +1 -1
- package/dist/server/src/controllers/validation/content-api/upload.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +3 -0
- package/dist/server/src/index.d.ts.map +1 -1
- package/dist/server/src/mcp/ambient-instance.d.ts +7 -5
- package/dist/server/src/mcp/ambient-instance.d.ts.map +1 -1
- package/dist/server/src/mcp/handlers/folder-handlers.d.ts.map +1 -1
- package/dist/server/src/mcp/handlers/read-handlers.d.ts +3 -2
- package/dist/server/src/mcp/handlers/read-handlers.d.ts.map +1 -1
- package/dist/server/src/mcp/handlers/write-handlers.d.ts.map +1 -1
- package/dist/server/src/mcp/register-upload-mcp-tools.d.ts +9 -14
- package/dist/server/src/mcp/register-upload-mcp-tools.d.ts.map +1 -1
- package/dist/server/src/services/image-manipulation.d.ts.map +1 -1
- package/dist/server/src/types.d.ts +1 -0
- package/dist/server/src/types.d.ts.map +1 -1
- package/package.json +6 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UploadDropZoneContext.js","sources":["../../../../../../admin/src/pages/Assets/components/DropZone/UploadDropZoneContext.tsx"],"sourcesContent":["import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useRef,\n useState,\n type DragEvent,\n type ReactNode,\n} from 'react';\n\nimport { Box } from '@strapi/design-system';\nimport { styled } from 'styled-components';\n\n/* -------------------------------------------------------------------------------------------------\n * Types\n * -----------------------------------------------------------------------------------------------*/\n\ntype DropHandler = (files: File[]) => void | Promise<void>;\n\ninterface UploadDropZoneContextValue {\n isDragging: boolean;\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Context\n * -----------------------------------------------------------------------------------------------*/\n\nconst UploadDropZoneContext = createContext<UploadDropZoneContextValue | null>(null);\n\n/* -------------------------------------------------------------------------------------------------\n * Components\n * -----------------------------------------------------------------------------------------------*/\n\nconst DropZoneWrapper = styled(Box)`\n position: relative;\n display: flex;\n flex-direction: column;\n min-height: 100%;\n`;\n\n/* -------------------------------------------------------------------------------------------------\n * Provider\n * -----------------------------------------------------------------------------------------------*/\n\ninterface UploadDropZoneProps {\n children: ReactNode;\n onDrop?: DropHandler;\n /**\n * When true, the zone never enters the dragging state and never fires\n * `onDrop` — no overlay, no \"drop here\" invitation. Used to hide the whole\n * upload affordance from users without `assets.create`, so they don't drag a\n * file onto an inviting target that then silently discards it.\n */\n disabled?: boolean;\n}\n\nexport const UploadDropZoneProvider = ({\n children,\n onDrop,\n disabled = false,\n}: UploadDropZoneProps) => {\n const [isDragging, setIsDragging] = useState(false);\n const dragCounterRef = useRef(0);\n\n const contextValue
|
|
1
|
+
{"version":3,"file":"UploadDropZoneContext.js","sources":["../../../../../../admin/src/pages/Assets/components/DropZone/UploadDropZoneContext.tsx"],"sourcesContent":["import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type DragEvent,\n type ReactNode,\n} from 'react';\n\nimport { Box } from '@strapi/design-system';\nimport { styled } from 'styled-components';\n\n/* -------------------------------------------------------------------------------------------------\n * Types\n * -----------------------------------------------------------------------------------------------*/\n\ntype DropHandler = (files: File[]) => void | Promise<void>;\n\ninterface UploadDropZoneContextValue {\n isDragging: boolean;\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Context\n * -----------------------------------------------------------------------------------------------*/\n\nconst UploadDropZoneContext = createContext<UploadDropZoneContextValue | null>(null);\n\n/* -------------------------------------------------------------------------------------------------\n * Components\n * -----------------------------------------------------------------------------------------------*/\n\nconst DropZoneWrapper = styled(Box)`\n position: relative;\n display: flex;\n flex-direction: column;\n min-height: 100%;\n`;\n\n/* -------------------------------------------------------------------------------------------------\n * Provider\n * -----------------------------------------------------------------------------------------------*/\n\ninterface UploadDropZoneProps {\n children: ReactNode;\n onDrop?: DropHandler;\n /**\n * When true, the zone never enters the dragging state and never fires\n * `onDrop` — no overlay, no \"drop here\" invitation. Used to hide the whole\n * upload affordance from users without `assets.create`, so they don't drag a\n * file onto an inviting target that then silently discards it.\n */\n disabled?: boolean;\n}\n\nexport const UploadDropZoneProvider = ({\n children,\n onDrop,\n disabled = false,\n}: UploadDropZoneProps) => {\n const [isDragging, setIsDragging] = useState(false);\n const dragCounterRef = useRef(0);\n\n const contextValue = useMemo<UploadDropZoneContextValue>(() => ({ isDragging }), [isDragging]);\n\n useEffect(() => {\n const handleDragEnd = () => {\n setIsDragging(false);\n dragCounterRef.current = 0;\n };\n\n // Handle drag leaving the entire document/window\n const handleDocumentDragLeave = (e: globalThis.DragEvent) => {\n // When relatedTarget is null, we're leaving the document entirely\n if (!e.relatedTarget) {\n setIsDragging(false);\n dragCounterRef.current = 0;\n }\n };\n\n document.addEventListener('dragend', handleDragEnd);\n document.addEventListener('dragleave', handleDocumentDragLeave);\n\n return () => {\n document.removeEventListener('dragend', handleDragEnd);\n document.removeEventListener('dragleave', handleDocumentDragLeave);\n };\n }, []);\n\n const handleDragEnter = useCallback(\n (e: DragEvent<HTMLElement>) => {\n e.preventDefault();\n e.stopPropagation();\n\n // No upload permission → never light up the drop target.\n if (disabled) {\n return;\n }\n\n // Bidirectional guard with AssetsDndProvider — internal item drags must not\n // activate the upload overlay. See AssetsDndProvider.tsx.\n if (!e.dataTransfer.types.includes('Files')) {\n return;\n }\n\n dragCounterRef.current += 1;\n setIsDragging(true);\n },\n [disabled]\n );\n\n const handleDragLeave = useCallback((e: DragEvent<HTMLElement>) => {\n e.preventDefault();\n e.stopPropagation();\n\n dragCounterRef.current -= 1;\n\n // Only set dragging to false if we've left the dropzone completely\n // (counter reaches 0 or negative)\n if (dragCounterRef.current <= 0) {\n setIsDragging(false);\n dragCounterRef.current = 0;\n }\n }, []);\n\n const handleDragOver = useCallback((e: DragEvent<HTMLElement>) => {\n e.preventDefault();\n e.stopPropagation();\n e.dataTransfer.dropEffect = 'copy';\n }, []);\n\n const handleDrop = useCallback(\n (e: DragEvent<HTMLElement>) => {\n e.preventDefault();\n e.stopPropagation();\n setIsDragging(false);\n dragCounterRef.current = 0;\n\n if (disabled) {\n return;\n }\n\n const { files } = e.dataTransfer;\n if (files?.length && onDrop) {\n onDrop(Array.from(files));\n }\n },\n [onDrop, disabled]\n );\n\n return (\n <UploadDropZoneContext.Provider value={contextValue}>\n <DropZoneWrapper\n data-testid=\"assets-dropzone\"\n onDragEnter={handleDragEnter}\n onDragLeave={handleDragLeave}\n onDragOver={handleDragOver}\n onDrop={handleDrop}\n >\n {children}\n </DropZoneWrapper>\n </UploadDropZoneContext.Provider>\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * Hook\n * -----------------------------------------------------------------------------------------------*/\n\nexport const useUploadDropZone = () => {\n const context = useContext(UploadDropZoneContext);\n\n if (!context) {\n throw new Error('useUploadDropZone must be used within UploadDropZone');\n }\n\n return {\n isDragging: context.isDragging,\n };\n};\n"],"names":["UploadDropZoneContext","createContext","DropZoneWrapper","styled","Box","UploadDropZoneProvider","children","onDrop","disabled","isDragging","setIsDragging","useState","dragCounterRef","useRef","contextValue","useMemo","useEffect","handleDragEnd","current","handleDocumentDragLeave","e","relatedTarget","document","addEventListener","removeEventListener","handleDragEnter","useCallback","preventDefault","stopPropagation","dataTransfer","types","includes","handleDragLeave","handleDragOver","dropEffect","handleDrop","files","length","Array","from","_jsx","Provider","value","data-testid","onDragEnter","onDragLeave","onDragOver","useUploadDropZone","context","useContext","Error"],"mappings":";;;;;;;AAyBA;;qGAIA,MAAMA,sCAAwBC,mBAAAA,CAAiD,IAAA,CAAA;AAE/E;;AAEkG,qGAElG,MAAMC,eAAAA,GAAkBC,uBAAAA,CAAOC,gBAAAA,CAAI;;;;;AAKnC,CAAC;AAkBM,MAAMC,sBAAAA,GAAyB,CAAC,EACrCC,QAAQ,EACRC,MAAM,EACNC,QAAAA,GAAW,KAAK,EACI,GAAA;AACpB,IAAA,MAAM,CAACC,UAAAA,EAAYC,aAAAA,CAAc,GAAGC,cAAAA,CAAS,KAAA,CAAA;AAC7C,IAAA,MAAMC,iBAAiBC,YAAAA,CAAO,CAAA,CAAA;IAE9B,MAAMC,YAAAA,GAAeC,aAAAA,CAAoC,KAAO;AAAEN,YAAAA;AAAW,SAAA,CAAA,EAAI;AAACA,QAAAA;AAAW,KAAA,CAAA;IAE7FO,eAAAA,CAAU,IAAA;AACR,QAAA,MAAMC,aAAAA,GAAgB,IAAA;YACpBP,aAAAA,CAAc,KAAA,CAAA;AACdE,YAAAA,cAAAA,CAAeM,OAAO,GAAG,CAAA;AAC3B,QAAA,CAAA;;AAGA,QAAA,MAAMC,0BAA0B,CAACC,CAAAA,GAAAA;;YAE/B,IAAI,CAACA,CAAAA,CAAEC,aAAa,EAAE;gBACpBX,aAAAA,CAAc,KAAA,CAAA;AACdE,gBAAAA,cAAAA,CAAeM,OAAO,GAAG,CAAA;AAC3B,YAAA;AACF,QAAA,CAAA;QAEAI,QAAAA,CAASC,gBAAgB,CAAC,SAAA,EAAWN,aAAAA,CAAAA;QACrCK,QAAAA,CAASC,gBAAgB,CAAC,WAAA,EAAaJ,uBAAAA,CAAAA;QAEvC,OAAO,IAAA;YACLG,QAAAA,CAASE,mBAAmB,CAAC,SAAA,EAAWP,aAAAA,CAAAA;YACxCK,QAAAA,CAASE,mBAAmB,CAAC,WAAA,EAAaL,uBAAAA,CAAAA;AAC5C,QAAA,CAAA;AACF,IAAA,CAAA,EAAG,EAAE,CAAA;IAEL,MAAMM,eAAAA,GAAkBC,kBACtB,CAACN,CAAAA,GAAAA;AACCA,QAAAA,CAAAA,CAAEO,cAAc,EAAA;AAChBP,QAAAA,CAAAA,CAAEQ,eAAe,EAAA;;AAGjB,QAAA,IAAIpB,QAAAA,EAAU;AACZ,YAAA;AACF,QAAA;;;QAIA,IAAI,CAACY,EAAES,YAAY,CAACC,KAAK,CAACC,QAAQ,CAAC,OAAA,CAAA,EAAU;AAC3C,YAAA;AACF,QAAA;AAEAnB,QAAAA,cAAAA,CAAeM,OAAO,IAAI,CAAA;QAC1BR,aAAAA,CAAc,IAAA,CAAA;IAChB,CAAA,EACA;AAACF,QAAAA;AAAS,KAAA,CAAA;IAGZ,MAAMwB,eAAAA,GAAkBN,kBAAY,CAACN,CAAAA,GAAAA;AACnCA,QAAAA,CAAAA,CAAEO,cAAc,EAAA;AAChBP,QAAAA,CAAAA,CAAEQ,eAAe,EAAA;AAEjBhB,QAAAA,cAAAA,CAAeM,OAAO,IAAI,CAAA;;;QAI1B,IAAIN,cAAAA,CAAeM,OAAO,IAAI,CAAA,EAAG;YAC/BR,aAAAA,CAAc,KAAA,CAAA;AACdE,YAAAA,cAAAA,CAAeM,OAAO,GAAG,CAAA;AAC3B,QAAA;AACF,IAAA,CAAA,EAAG,EAAE,CAAA;IAEL,MAAMe,cAAAA,GAAiBP,kBAAY,CAACN,CAAAA,GAAAA;AAClCA,QAAAA,CAAAA,CAAEO,cAAc,EAAA;AAChBP,QAAAA,CAAAA,CAAEQ,eAAe,EAAA;QACjBR,CAAAA,CAAES,YAAY,CAACK,UAAU,GAAG,MAAA;AAC9B,IAAA,CAAA,EAAG,EAAE,CAAA;IAEL,MAAMC,UAAAA,GAAaT,kBACjB,CAACN,CAAAA,GAAAA;AACCA,QAAAA,CAAAA,CAAEO,cAAc,EAAA;AAChBP,QAAAA,CAAAA,CAAEQ,eAAe,EAAA;QACjBlB,aAAAA,CAAc,KAAA,CAAA;AACdE,QAAAA,cAAAA,CAAeM,OAAO,GAAG,CAAA;AAEzB,QAAA,IAAIV,QAAAA,EAAU;AACZ,YAAA;AACF,QAAA;AAEA,QAAA,MAAM,EAAE4B,KAAK,EAAE,GAAGhB,EAAES,YAAY;QAChC,IAAIO,KAAAA,EAAOC,UAAU9B,MAAAA,EAAQ;YAC3BA,MAAAA,CAAO+B,KAAAA,CAAMC,IAAI,CAACH,KAAAA,CAAAA,CAAAA;AACpB,QAAA;IACF,CAAA,EACA;AAAC7B,QAAAA,MAAAA;AAAQC,QAAAA;AAAS,KAAA,CAAA;IAGpB,qBACEgC,cAAA,CAACxC,sBAAsByC,QAAQ,EAAA;QAACC,KAAAA,EAAO5B,YAAAA;AACrC,QAAA,QAAA,gBAAA0B,cAAA,CAACtC,eAAAA,EAAAA;YACCyC,aAAAA,EAAY,iBAAA;YACZC,WAAAA,EAAanB,eAAAA;YACboB,WAAAA,EAAab,eAAAA;YACbc,UAAAA,EAAYb,cAAAA;YACZ1B,MAAAA,EAAQ4B,UAAAA;AAEP7B,YAAAA,QAAAA,EAAAA;;;AAIT;AAEA;;2GAIayC,iBAAAA,GAAoB,IAAA;AAC/B,IAAA,MAAMC,UAAUC,gBAAAA,CAAWjD,qBAAAA,CAAAA;AAE3B,IAAA,IAAI,CAACgD,OAAAA,EAAS;AACZ,QAAA,MAAM,IAAIE,KAAAA,CAAM,sDAAA,CAAA;AAClB,IAAA;IAEA,OAAO;AACLzC,QAAAA,UAAAA,EAAYuC,QAAQvC;AACtB,KAAA;AACF;;;;;"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { useState, useRef, useEffect, useCallback, createContext, useContext } from 'react';
|
|
2
|
+
import { useState, useRef, useMemo, useEffect, useCallback, createContext, useContext } from 'react';
|
|
3
3
|
import { Box } from '@strapi/design-system';
|
|
4
4
|
import { styled } from 'styled-components';
|
|
5
5
|
|
|
@@ -17,9 +17,11 @@ import { styled } from 'styled-components';
|
|
|
17
17
|
const UploadDropZoneProvider = ({ children, onDrop, disabled = false })=>{
|
|
18
18
|
const [isDragging, setIsDragging] = useState(false);
|
|
19
19
|
const dragCounterRef = useRef(0);
|
|
20
|
-
const contextValue = {
|
|
20
|
+
const contextValue = useMemo(()=>({
|
|
21
|
+
isDragging
|
|
22
|
+
}), [
|
|
21
23
|
isDragging
|
|
22
|
-
|
|
24
|
+
]);
|
|
23
25
|
useEffect(()=>{
|
|
24
26
|
const handleDragEnd = ()=>{
|
|
25
27
|
setIsDragging(false);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UploadDropZoneContext.mjs","sources":["../../../../../../admin/src/pages/Assets/components/DropZone/UploadDropZoneContext.tsx"],"sourcesContent":["import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useRef,\n useState,\n type DragEvent,\n type ReactNode,\n} from 'react';\n\nimport { Box } from '@strapi/design-system';\nimport { styled } from 'styled-components';\n\n/* -------------------------------------------------------------------------------------------------\n * Types\n * -----------------------------------------------------------------------------------------------*/\n\ntype DropHandler = (files: File[]) => void | Promise<void>;\n\ninterface UploadDropZoneContextValue {\n isDragging: boolean;\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Context\n * -----------------------------------------------------------------------------------------------*/\n\nconst UploadDropZoneContext = createContext<UploadDropZoneContextValue | null>(null);\n\n/* -------------------------------------------------------------------------------------------------\n * Components\n * -----------------------------------------------------------------------------------------------*/\n\nconst DropZoneWrapper = styled(Box)`\n position: relative;\n display: flex;\n flex-direction: column;\n min-height: 100%;\n`;\n\n/* -------------------------------------------------------------------------------------------------\n * Provider\n * -----------------------------------------------------------------------------------------------*/\n\ninterface UploadDropZoneProps {\n children: ReactNode;\n onDrop?: DropHandler;\n /**\n * When true, the zone never enters the dragging state and never fires\n * `onDrop` — no overlay, no \"drop here\" invitation. Used to hide the whole\n * upload affordance from users without `assets.create`, so they don't drag a\n * file onto an inviting target that then silently discards it.\n */\n disabled?: boolean;\n}\n\nexport const UploadDropZoneProvider = ({\n children,\n onDrop,\n disabled = false,\n}: UploadDropZoneProps) => {\n const [isDragging, setIsDragging] = useState(false);\n const dragCounterRef = useRef(0);\n\n const contextValue
|
|
1
|
+
{"version":3,"file":"UploadDropZoneContext.mjs","sources":["../../../../../../admin/src/pages/Assets/components/DropZone/UploadDropZoneContext.tsx"],"sourcesContent":["import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type DragEvent,\n type ReactNode,\n} from 'react';\n\nimport { Box } from '@strapi/design-system';\nimport { styled } from 'styled-components';\n\n/* -------------------------------------------------------------------------------------------------\n * Types\n * -----------------------------------------------------------------------------------------------*/\n\ntype DropHandler = (files: File[]) => void | Promise<void>;\n\ninterface UploadDropZoneContextValue {\n isDragging: boolean;\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Context\n * -----------------------------------------------------------------------------------------------*/\n\nconst UploadDropZoneContext = createContext<UploadDropZoneContextValue | null>(null);\n\n/* -------------------------------------------------------------------------------------------------\n * Components\n * -----------------------------------------------------------------------------------------------*/\n\nconst DropZoneWrapper = styled(Box)`\n position: relative;\n display: flex;\n flex-direction: column;\n min-height: 100%;\n`;\n\n/* -------------------------------------------------------------------------------------------------\n * Provider\n * -----------------------------------------------------------------------------------------------*/\n\ninterface UploadDropZoneProps {\n children: ReactNode;\n onDrop?: DropHandler;\n /**\n * When true, the zone never enters the dragging state and never fires\n * `onDrop` — no overlay, no \"drop here\" invitation. Used to hide the whole\n * upload affordance from users without `assets.create`, so they don't drag a\n * file onto an inviting target that then silently discards it.\n */\n disabled?: boolean;\n}\n\nexport const UploadDropZoneProvider = ({\n children,\n onDrop,\n disabled = false,\n}: UploadDropZoneProps) => {\n const [isDragging, setIsDragging] = useState(false);\n const dragCounterRef = useRef(0);\n\n const contextValue = useMemo<UploadDropZoneContextValue>(() => ({ isDragging }), [isDragging]);\n\n useEffect(() => {\n const handleDragEnd = () => {\n setIsDragging(false);\n dragCounterRef.current = 0;\n };\n\n // Handle drag leaving the entire document/window\n const handleDocumentDragLeave = (e: globalThis.DragEvent) => {\n // When relatedTarget is null, we're leaving the document entirely\n if (!e.relatedTarget) {\n setIsDragging(false);\n dragCounterRef.current = 0;\n }\n };\n\n document.addEventListener('dragend', handleDragEnd);\n document.addEventListener('dragleave', handleDocumentDragLeave);\n\n return () => {\n document.removeEventListener('dragend', handleDragEnd);\n document.removeEventListener('dragleave', handleDocumentDragLeave);\n };\n }, []);\n\n const handleDragEnter = useCallback(\n (e: DragEvent<HTMLElement>) => {\n e.preventDefault();\n e.stopPropagation();\n\n // No upload permission → never light up the drop target.\n if (disabled) {\n return;\n }\n\n // Bidirectional guard with AssetsDndProvider — internal item drags must not\n // activate the upload overlay. See AssetsDndProvider.tsx.\n if (!e.dataTransfer.types.includes('Files')) {\n return;\n }\n\n dragCounterRef.current += 1;\n setIsDragging(true);\n },\n [disabled]\n );\n\n const handleDragLeave = useCallback((e: DragEvent<HTMLElement>) => {\n e.preventDefault();\n e.stopPropagation();\n\n dragCounterRef.current -= 1;\n\n // Only set dragging to false if we've left the dropzone completely\n // (counter reaches 0 or negative)\n if (dragCounterRef.current <= 0) {\n setIsDragging(false);\n dragCounterRef.current = 0;\n }\n }, []);\n\n const handleDragOver = useCallback((e: DragEvent<HTMLElement>) => {\n e.preventDefault();\n e.stopPropagation();\n e.dataTransfer.dropEffect = 'copy';\n }, []);\n\n const handleDrop = useCallback(\n (e: DragEvent<HTMLElement>) => {\n e.preventDefault();\n e.stopPropagation();\n setIsDragging(false);\n dragCounterRef.current = 0;\n\n if (disabled) {\n return;\n }\n\n const { files } = e.dataTransfer;\n if (files?.length && onDrop) {\n onDrop(Array.from(files));\n }\n },\n [onDrop, disabled]\n );\n\n return (\n <UploadDropZoneContext.Provider value={contextValue}>\n <DropZoneWrapper\n data-testid=\"assets-dropzone\"\n onDragEnter={handleDragEnter}\n onDragLeave={handleDragLeave}\n onDragOver={handleDragOver}\n onDrop={handleDrop}\n >\n {children}\n </DropZoneWrapper>\n </UploadDropZoneContext.Provider>\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * Hook\n * -----------------------------------------------------------------------------------------------*/\n\nexport const useUploadDropZone = () => {\n const context = useContext(UploadDropZoneContext);\n\n if (!context) {\n throw new Error('useUploadDropZone must be used within UploadDropZone');\n }\n\n return {\n isDragging: context.isDragging,\n };\n};\n"],"names":["UploadDropZoneContext","createContext","DropZoneWrapper","styled","Box","UploadDropZoneProvider","children","onDrop","disabled","isDragging","setIsDragging","useState","dragCounterRef","useRef","contextValue","useMemo","useEffect","handleDragEnd","current","handleDocumentDragLeave","e","relatedTarget","document","addEventListener","removeEventListener","handleDragEnter","useCallback","preventDefault","stopPropagation","dataTransfer","types","includes","handleDragLeave","handleDragOver","dropEffect","handleDrop","files","length","Array","from","_jsx","Provider","value","data-testid","onDragEnter","onDragLeave","onDragOver","useUploadDropZone","context","useContext","Error"],"mappings":"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"}
|
|
@@ -397,6 +397,32 @@ const BadgesRoot = styledComponents.styled(designSystem.Flex)`
|
|
|
397
397
|
`;
|
|
398
398
|
const FilterBadges = ({ listFilters, compact = false })=>{
|
|
399
399
|
const { filters, updateFilter, removeFilter } = listFilters;
|
|
400
|
+
/**
|
|
401
|
+
* Stable per-slot keys held in a ref. The ref is written during render, but
|
|
402
|
+
* the bookkeeping depends on the list length rather than on how often render
|
|
403
|
+
* runs, so the second pass of a StrictMode double render sees equal lengths
|
|
404
|
+
* and does nothing. A content-derived key fails twice over here: filters may
|
|
405
|
+
* legitimately repeat, and the key would change while the user edits a badge,
|
|
406
|
+
* remounting the badge under its open popover.
|
|
407
|
+
*/ const filterKeyPrefix = React.useId();
|
|
408
|
+
const nextFilterKey = React.useRef(0);
|
|
409
|
+
const filterKeys = React.useRef([]);
|
|
410
|
+
while(filterKeys.current.length < filters.length){
|
|
411
|
+
filterKeys.current.push(`${filterKeyPrefix}-${nextFilterKey.current}`);
|
|
412
|
+
nextFilterKey.current += 1;
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Keys are truncated from the tail. The `onRemove` closure below splices the
|
|
416
|
+
* removed slot out first, so removal through this component is correct. Any
|
|
417
|
+
* other shrink path (browser back or forward, an external filter reset)
|
|
418
|
+
* shifts the remaining keys and degrades to the index keys this replaced.
|
|
419
|
+
* Known and accepted.
|
|
420
|
+
*/ filterKeys.current.length = filters.length;
|
|
421
|
+
const filtersWithKeys = filters.map((filter, index)=>({
|
|
422
|
+
filter,
|
|
423
|
+
index,
|
|
424
|
+
key: filterKeys.current[index]
|
|
425
|
+
}));
|
|
400
426
|
if (filters.length === 0) {
|
|
401
427
|
return null;
|
|
402
428
|
}
|
|
@@ -405,11 +431,14 @@ const FilterBadges = ({ listFilters, compact = false })=>{
|
|
|
405
431
|
gap: 2,
|
|
406
432
|
wrap: "wrap",
|
|
407
433
|
"data-testid": "filter-badges",
|
|
408
|
-
children:
|
|
434
|
+
children: filtersWithKeys.map(({ filter, index, key })=>/*#__PURE__*/ jsxRuntime.jsx(FilterBadge, {
|
|
409
435
|
filter: filter,
|
|
410
436
|
onChange: (next)=>updateFilter(index, next),
|
|
411
|
-
onRemove: ()=>
|
|
412
|
-
|
|
437
|
+
onRemove: ()=>{
|
|
438
|
+
filterKeys.current.splice(index, 1);
|
|
439
|
+
removeFilter(index);
|
|
440
|
+
}
|
|
441
|
+
}, key))
|
|
413
442
|
});
|
|
414
443
|
};
|
|
415
444
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FilterBadges.js","sources":["../../../../../admin/src/pages/Assets/components/FilterBadges.tsx"],"sourcesContent":["import { useState } from 'react';\n\nimport { Checkbox, Flex, Popover, Typography } from '@strapi/design-system';\nimport { Check, Cross } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { styled } from 'styled-components';\n\nimport { getTranslationKey } from '../../../utils/translations';\nimport {\n DATE_PRESETS,\n TYPE_VALUES,\n type DateFilter,\n type DatePreset,\n type ListFilter,\n type ListFilters,\n type PresetCondition,\n type RangeCondition,\n type TypeCondition,\n type TypeFilter,\n type TypeValue,\n} from '../hooks/useListFilters';\nimport { parseCalendarDate } from '../utils/buildAssetFilters';\n\nimport { DateRangeCalendar } from './DateRangeCalendar';\nimport { DATE_FIELD_LABELS, FILTER_PANEL_WIDTH, PRESET_LABELS, TYPE_LABELS } from './FilterMenu';\n\nimport type { MessageDescriptor } from 'react-intl';\n\n/**\n * Row of applied-filter badges under the toolbar. A badge has three segments —\n * field (static), condition (click → select popover), value (click → type\n * checkboxes / preset list / range calendar) — plus a remove button.\n */\n\nconst BadgePill = styled(Flex)`\n border: 1px solid ${({ theme }) => theme.colors.neutral200};\n border-radius: ${({ theme }) => theme.borderRadius};\n background: ${({ theme }) => theme.colors.neutral0};\n overflow: hidden;\n`;\n\nconst Segment = styled.button<{ $interactive?: boolean }>`\n border: none;\n background: transparent;\n font: inherit;\n padding: ${({ theme }) => `${theme.spaces[2]} ${theme.spaces[3]}`};\n cursor: ${({ $interactive }) => ($interactive ? 'pointer' : 'default')};\n border-right: 1px solid ${({ theme }) => theme.colors.neutral200};\n\n ${({ theme }) => theme.breakpoints.medium} {\n padding: ${({ theme }) => `${theme.spaces[1]} ${theme.spaces[2]}`};\n }\n ${({ $interactive, theme }) =>\n $interactive && `&:hover { background: ${theme.colors.primary100}; }`}\n\n &:focus-visible {\n outline: 2px solid ${({ theme }) => theme.colors.primary600};\n outline-offset: -2px;\n }\n`;\n\n// Non-interactive field segment (first pill cell).\nconst FieldSegment = styled.span`\n display: inline-flex;\n align-items: center;\n padding: ${({ theme }) => `${theme.spaces[1]} ${theme.spaces[2]}`};\n border-right: 1px solid ${({ theme }) => theme.colors.neutral200};\n`;\n\n// Badge popovers mirror the filter-menu panels: same fixed width, same font.\nconst PanelPopoverContent = styled(Popover.Content)`\n width: ${FILTER_PANEL_WIDTH};\n`;\n\n// Option row inside a segment popover — sized like a DS Menu.Item so the badge\n// dropdowns read as the same control family as the filter menu.\nconst OptionButton = styled.button`\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: ${({ theme }) => theme.spaces[4]};\n width: 100%;\n border: none;\n background: transparent;\n font-size: ${({ theme }) => theme.fontSizes[2]};\n line-height: ${({ theme }) => theme.lineHeights[4]};\n font-family: inherit;\n text-align: left;\n padding: ${({ theme }) => `${theme.spaces[2]} ${theme.spaces[4]}`};\n border-radius: ${({ theme }) => theme.borderRadius};\n cursor: pointer;\n color: ${({ theme }) => theme.colors.neutral800};\n\n &:hover {\n background: ${({ theme }) => theme.colors.primary100};\n }\n\n &:focus-visible {\n outline: 2px solid ${({ theme }) => theme.colors.primary600};\n outline-offset: -2px;\n }\n`;\n\nconst RemoveButton = styled.button`\n border: none;\n background: transparent;\n display: inline-flex;\n align-items: center;\n padding: ${({ theme }) => `0 ${theme.spaces[2]}`};\n cursor: pointer;\n color: ${({ theme }) => theme.colors.neutral600};\n\n &:hover {\n color: ${({ theme }) => theme.colors.neutral800};\n }\n\n &:focus-visible {\n outline: 2px solid ${({ theme }) => theme.colors.primary600};\n outline-offset: -2px;\n }\n`;\n\nconst TYPE_CONDITION_LABELS: Record<TypeCondition, MessageDescriptor> = {\n is: { id: getTranslationKey('list.filters.condition.is'), defaultMessage: 'is' },\n isNot: { id: getTranslationKey('list.filters.condition.is-not'), defaultMessage: 'is not' },\n};\n\nconst PRESET_CONDITION_LABELS: Record<PresetCondition, MessageDescriptor> = {\n isExactly: {\n id: getTranslationKey('list.filters.condition.is-exactly'),\n defaultMessage: 'is exactly',\n },\n withinLast: {\n id: getTranslationKey('list.filters.condition.within-last'),\n defaultMessage: 'within the last',\n },\n notWithinLast: {\n id: getTranslationKey('list.filters.condition.not-within-last'),\n defaultMessage: 'not within the last',\n },\n};\n\nconst RANGE_CONDITION_LABELS: Record<RangeCondition, MessageDescriptor> = {\n is: { id: getTranslationKey('list.filters.condition.is'), defaultMessage: 'is' },\n isNot: { id: getTranslationKey('list.filters.condition.is-not'), defaultMessage: 'is not' },\n};\n\n/** A small single-choice popover listing options with a check on the active one. */\ninterface SegmentPopoverProps<T extends string> {\n label: string;\n options: T[];\n active: T;\n getOptionLabel: (option: T) => string;\n onPick: (option: T) => void;\n}\n\nconst SegmentPopover = <T extends string>({\n label,\n options,\n active,\n getOptionLabel,\n onPick,\n}: SegmentPopoverProps<T>) => {\n const [open, setOpen] = useState(false);\n\n return (\n <Popover.Root open={open} onOpenChange={setOpen}>\n <Popover.Trigger>\n <Segment type=\"button\" $interactive>\n <Typography variant=\"pi\" textColor=\"neutral800\">\n {label}\n </Typography>\n </Segment>\n </Popover.Trigger>\n <PanelPopoverContent>\n <Flex direction=\"column\" alignItems=\"stretch\" padding={1}>\n {options.map((option) => (\n <OptionButton\n key={option}\n type=\"button\"\n onClick={() => {\n onPick(option);\n setOpen(false);\n }}\n >\n {getOptionLabel(option)}\n {option === active && <Check aria-hidden width=\"1.6rem\" height=\"1.6rem\" />}\n </OptionButton>\n ))}\n </Flex>\n </PanelPopoverContent>\n </Popover.Root>\n );\n};\n\nconst TypeValuePopover = ({\n filter,\n onChange,\n}: {\n filter: TypeFilter;\n onChange: (next: TypeFilter) => void;\n}) => {\n const { formatMessage } = useIntl();\n const [open, setOpen] = useState(false);\n\n const label = filter.values.map((value) => formatMessage(TYPE_LABELS[value])).join(', ');\n\n const toggleValue = (value: TypeValue) => {\n const nextValues = filter.values.includes(value)\n ? filter.values.filter((v) => v !== value)\n : [...filter.values, value];\n\n // At least one value stays checked — an empty badge is removed via ×, not here.\n if (nextValues.length > 0) {\n onChange({ ...filter, values: nextValues });\n }\n };\n\n return (\n <Popover.Root open={open} onOpenChange={setOpen}>\n <Popover.Trigger>\n <Segment type=\"button\" $interactive>\n <Typography variant=\"pi\" textColor=\"neutral800\">\n {label}\n </Typography>\n </Segment>\n </Popover.Trigger>\n <PanelPopoverContent>\n <Flex direction=\"column\" alignItems=\"flex-start\" padding={3} gap={2}>\n {TYPE_VALUES.map((value) => (\n <Checkbox\n key={value}\n checked={filter.values.includes(value)}\n onCheckedChange={() => toggleValue(value)}\n >\n {formatMessage(TYPE_LABELS[value])}\n </Checkbox>\n ))}\n </Flex>\n </PanelPopoverContent>\n </Popover.Root>\n );\n};\n\nconst DateValuePopover = ({\n filter,\n onChange,\n}: {\n filter: DateFilter;\n onChange: (next: DateFilter) => void;\n}) => {\n const { formatMessage, formatDate } = useIntl();\n const [open, setOpen] = useState(false);\n\n // Parse as LOCAL calendar dates before formatting: react-intl would coerce\n // the raw `YYYY-MM-DD` strings via `new Date(value)` = UTC midnight, showing\n // the previous day in every timezone west of UTC while the query (also\n // local, see buildAssetFilters) filters the day the user actually picked.\n const label =\n filter.mode === 'preset'\n ? formatMessage(PRESET_LABELS[filter.preset])\n : `${formatDate(parseCalendarDate(filter.from), {\n day: '2-digit',\n month: 'short',\n })} - ${formatDate(parseCalendarDate(filter.to), {\n day: '2-digit',\n month: 'short',\n year: 'numeric',\n })}`;\n\n return (\n <Popover.Root open={open} onOpenChange={setOpen}>\n <Popover.Trigger>\n <Segment type=\"button\" $interactive>\n <Typography variant=\"pi\" textColor=\"neutral800\">\n {label}\n </Typography>\n </Segment>\n </Popover.Trigger>\n <PanelPopoverContent>\n {filter.mode === 'preset' ? (\n <Flex direction=\"column\" alignItems=\"stretch\" padding={1}>\n {DATE_PRESETS.map((preset: DatePreset) => (\n <OptionButton\n key={preset}\n type=\"button\"\n onClick={() => {\n onChange({ ...filter, preset });\n setOpen(false);\n }}\n >\n {formatMessage(PRESET_LABELS[preset])}\n {preset === filter.preset && <Check aria-hidden width=\"1.6rem\" height=\"1.6rem\" />}\n </OptionButton>\n ))}\n </Flex>\n ) : (\n <DateRangeCalendar\n from={filter.from}\n to={filter.to}\n onSelect={(from, to) => {\n onChange({ ...filter, from, to });\n setOpen(false);\n }}\n />\n )}\n </PanelPopoverContent>\n </Popover.Root>\n );\n};\n\nconst FilterBadge = ({\n filter,\n onChange,\n onRemove,\n}: {\n filter: ListFilter;\n onChange: (next: ListFilter) => void;\n onRemove: () => void;\n}) => {\n const { formatMessage } = useIntl();\n\n const fieldLabel =\n filter.kind === 'type'\n ? formatMessage({ id: getTranslationKey('list.filters.field.type'), defaultMessage: 'Type' })\n : formatMessage(DATE_FIELD_LABELS[filter.field]);\n\n return (\n <BadgePill alignItems=\"stretch\" data-testid=\"filter-badge\">\n <FieldSegment>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {fieldLabel}\n </Typography>\n </FieldSegment>\n\n {filter.kind === 'type' && (\n <>\n <SegmentPopover\n label={formatMessage(TYPE_CONDITION_LABELS[filter.condition])}\n options={['is', 'isNot'] as TypeCondition[]}\n active={filter.condition}\n getOptionLabel={(option) => formatMessage(TYPE_CONDITION_LABELS[option])}\n onPick={(condition) => onChange({ ...filter, condition })}\n />\n <TypeValuePopover filter={filter} onChange={onChange} />\n </>\n )}\n\n {filter.kind === 'date' && filter.mode === 'preset' && (\n <>\n <SegmentPopover\n label={formatMessage(PRESET_CONDITION_LABELS[filter.condition])}\n options={['isExactly', 'withinLast', 'notWithinLast'] as PresetCondition[]}\n active={filter.condition}\n getOptionLabel={(option) => formatMessage(PRESET_CONDITION_LABELS[option])}\n onPick={(condition) => onChange({ ...filter, condition })}\n />\n <DateValuePopover filter={filter} onChange={onChange} />\n </>\n )}\n\n {filter.kind === 'date' && filter.mode === 'range' && (\n <>\n <SegmentPopover\n label={formatMessage(RANGE_CONDITION_LABELS[filter.condition])}\n options={['is', 'isNot'] as RangeCondition[]}\n active={filter.condition}\n getOptionLabel={(option) => formatMessage(RANGE_CONDITION_LABELS[option])}\n onPick={(condition) => onChange({ ...filter, condition })}\n />\n <DateValuePopover filter={filter} onChange={onChange} />\n </>\n )}\n\n <RemoveButton\n type=\"button\"\n onClick={onRemove}\n aria-label={formatMessage(\n {\n id: getTranslationKey('list.filters.remove'),\n defaultMessage: 'Remove {filter} filter',\n },\n { filter: fieldLabel }\n )}\n >\n <Cross width=\"1.2rem\" height=\"1.2rem\" aria-hidden />\n </RemoveButton>\n </BadgePill>\n );\n};\n\n// Tighten the gap above the badges when the sticky header is in its compact\n// (scrolled) state, matching the header's own shrink.\nconst BadgesRoot = styled(Flex)<{ $compact: boolean }>`\n padding-top: ${({ theme, $compact }) => ($compact ? theme.spaces[1] : theme.spaces[6])};\n transition: padding-top 0.2s ease;\n`;\n\ninterface FilterBadgesProps {\n listFilters: ListFilters;\n /** Sticky header is scrolled/compact — reduce the space above the badges. */\n compact?: boolean;\n}\n\nexport const FilterBadges = ({ listFilters, compact = false }: FilterBadgesProps) => {\n const { filters, updateFilter, removeFilter } = listFilters;\n\n if (filters.length === 0) {\n return null;\n }\n\n return (\n <BadgesRoot $compact={compact} gap={2} wrap=\"wrap\" data-testid=\"filter-badges\">\n {filters.map((filter, index) => (\n <FilterBadge\n // Position is identity: badges are edited/removed by index.\n key={index}\n filter={filter}\n onChange={(next) => updateFilter(index, next)}\n onRemove={() => removeFilter(index)}\n />\n ))}\n </BadgesRoot>\n );\n};\n"],"names":["BadgePill","styled","Flex","theme","colors","neutral200","borderRadius","neutral0","Segment","button","spaces","$interactive","breakpoints","medium","primary100","primary600","FieldSegment","span","PanelPopoverContent","Popover","Content","FILTER_PANEL_WIDTH","OptionButton","fontSizes","lineHeights","neutral800","RemoveButton","neutral600","TYPE_CONDITION_LABELS","is","id","getTranslationKey","defaultMessage","isNot","PRESET_CONDITION_LABELS","isExactly","withinLast","notWithinLast","RANGE_CONDITION_LABELS","SegmentPopover","label","options","active","getOptionLabel","onPick","open","setOpen","useState","_jsxs","Root","onOpenChange","_jsx","Trigger","type","Typography","variant","textColor","direction","alignItems","padding","map","option","onClick","Check","aria-hidden","width","height","TypeValuePopover","filter","onChange","formatMessage","useIntl","values","value","TYPE_LABELS","join","toggleValue","nextValues","includes","v","length","gap","TYPE_VALUES","Checkbox","checked","onCheckedChange","DateValuePopover","formatDate","mode","PRESET_LABELS","preset","parseCalendarDate","from","day","month","to","year","DATE_PRESETS","DateRangeCalendar","onSelect","FilterBadge","onRemove","fieldLabel","kind","DATE_FIELD_LABELS","field","data-testid","_Fragment","condition","aria-label","Cross","BadgesRoot","$compact","FilterBadges","listFilters","compact","filters","updateFilter","removeFilter","wrap","index","next"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FilterBadges.js","sources":["../../../../../admin/src/pages/Assets/components/FilterBadges.tsx"],"sourcesContent":["import { useId, useRef, useState } from 'react';\n\nimport { Checkbox, Flex, Popover, Typography } from '@strapi/design-system';\nimport { Check, Cross } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { styled } from 'styled-components';\n\nimport { getTranslationKey } from '../../../utils/translations';\nimport {\n DATE_PRESETS,\n TYPE_VALUES,\n type DateFilter,\n type DatePreset,\n type ListFilter,\n type ListFilters,\n type PresetCondition,\n type RangeCondition,\n type TypeCondition,\n type TypeFilter,\n type TypeValue,\n} from '../hooks/useListFilters';\nimport { parseCalendarDate } from '../utils/buildAssetFilters';\n\nimport { DateRangeCalendar } from './DateRangeCalendar';\nimport { DATE_FIELD_LABELS, FILTER_PANEL_WIDTH, PRESET_LABELS, TYPE_LABELS } from './FilterMenu';\n\nimport type { MessageDescriptor } from 'react-intl';\n\n/**\n * Row of applied-filter badges under the toolbar. A badge has three segments —\n * field (static), condition (click → select popover), value (click → type\n * checkboxes / preset list / range calendar) — plus a remove button.\n */\n\nconst BadgePill = styled(Flex)`\n border: 1px solid ${({ theme }) => theme.colors.neutral200};\n border-radius: ${({ theme }) => theme.borderRadius};\n background: ${({ theme }) => theme.colors.neutral0};\n overflow: hidden;\n`;\n\nconst Segment = styled.button<{ $interactive?: boolean }>`\n border: none;\n background: transparent;\n font: inherit;\n padding: ${({ theme }) => `${theme.spaces[2]} ${theme.spaces[3]}`};\n cursor: ${({ $interactive }) => ($interactive ? 'pointer' : 'default')};\n border-right: 1px solid ${({ theme }) => theme.colors.neutral200};\n\n ${({ theme }) => theme.breakpoints.medium} {\n padding: ${({ theme }) => `${theme.spaces[1]} ${theme.spaces[2]}`};\n }\n ${({ $interactive, theme }) =>\n $interactive && `&:hover { background: ${theme.colors.primary100}; }`}\n\n &:focus-visible {\n outline: 2px solid ${({ theme }) => theme.colors.primary600};\n outline-offset: -2px;\n }\n`;\n\n// Non-interactive field segment (first pill cell).\nconst FieldSegment = styled.span`\n display: inline-flex;\n align-items: center;\n padding: ${({ theme }) => `${theme.spaces[1]} ${theme.spaces[2]}`};\n border-right: 1px solid ${({ theme }) => theme.colors.neutral200};\n`;\n\n// Badge popovers mirror the filter-menu panels: same fixed width, same font.\nconst PanelPopoverContent = styled(Popover.Content)`\n width: ${FILTER_PANEL_WIDTH};\n`;\n\n// Option row inside a segment popover — sized like a DS Menu.Item so the badge\n// dropdowns read as the same control family as the filter menu.\nconst OptionButton = styled.button`\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: ${({ theme }) => theme.spaces[4]};\n width: 100%;\n border: none;\n background: transparent;\n font-size: ${({ theme }) => theme.fontSizes[2]};\n line-height: ${({ theme }) => theme.lineHeights[4]};\n font-family: inherit;\n text-align: left;\n padding: ${({ theme }) => `${theme.spaces[2]} ${theme.spaces[4]}`};\n border-radius: ${({ theme }) => theme.borderRadius};\n cursor: pointer;\n color: ${({ theme }) => theme.colors.neutral800};\n\n &:hover {\n background: ${({ theme }) => theme.colors.primary100};\n }\n\n &:focus-visible {\n outline: 2px solid ${({ theme }) => theme.colors.primary600};\n outline-offset: -2px;\n }\n`;\n\nconst RemoveButton = styled.button`\n border: none;\n background: transparent;\n display: inline-flex;\n align-items: center;\n padding: ${({ theme }) => `0 ${theme.spaces[2]}`};\n cursor: pointer;\n color: ${({ theme }) => theme.colors.neutral600};\n\n &:hover {\n color: ${({ theme }) => theme.colors.neutral800};\n }\n\n &:focus-visible {\n outline: 2px solid ${({ theme }) => theme.colors.primary600};\n outline-offset: -2px;\n }\n`;\n\nconst TYPE_CONDITION_LABELS: Record<TypeCondition, MessageDescriptor> = {\n is: { id: getTranslationKey('list.filters.condition.is'), defaultMessage: 'is' },\n isNot: { id: getTranslationKey('list.filters.condition.is-not'), defaultMessage: 'is not' },\n};\n\nconst PRESET_CONDITION_LABELS: Record<PresetCondition, MessageDescriptor> = {\n isExactly: {\n id: getTranslationKey('list.filters.condition.is-exactly'),\n defaultMessage: 'is exactly',\n },\n withinLast: {\n id: getTranslationKey('list.filters.condition.within-last'),\n defaultMessage: 'within the last',\n },\n notWithinLast: {\n id: getTranslationKey('list.filters.condition.not-within-last'),\n defaultMessage: 'not within the last',\n },\n};\n\nconst RANGE_CONDITION_LABELS: Record<RangeCondition, MessageDescriptor> = {\n is: { id: getTranslationKey('list.filters.condition.is'), defaultMessage: 'is' },\n isNot: { id: getTranslationKey('list.filters.condition.is-not'), defaultMessage: 'is not' },\n};\n\n/** A small single-choice popover listing options with a check on the active one. */\ninterface SegmentPopoverProps<T extends string> {\n label: string;\n options: T[];\n active: T;\n getOptionLabel: (option: T) => string;\n onPick: (option: T) => void;\n}\n\nconst SegmentPopover = <T extends string>({\n label,\n options,\n active,\n getOptionLabel,\n onPick,\n}: SegmentPopoverProps<T>) => {\n const [open, setOpen] = useState(false);\n\n return (\n <Popover.Root open={open} onOpenChange={setOpen}>\n <Popover.Trigger>\n <Segment type=\"button\" $interactive>\n <Typography variant=\"pi\" textColor=\"neutral800\">\n {label}\n </Typography>\n </Segment>\n </Popover.Trigger>\n <PanelPopoverContent>\n <Flex direction=\"column\" alignItems=\"stretch\" padding={1}>\n {options.map((option) => (\n <OptionButton\n key={option}\n type=\"button\"\n onClick={() => {\n onPick(option);\n setOpen(false);\n }}\n >\n {getOptionLabel(option)}\n {option === active && <Check aria-hidden width=\"1.6rem\" height=\"1.6rem\" />}\n </OptionButton>\n ))}\n </Flex>\n </PanelPopoverContent>\n </Popover.Root>\n );\n};\n\nconst TypeValuePopover = ({\n filter,\n onChange,\n}: {\n filter: TypeFilter;\n onChange: (next: TypeFilter) => void;\n}) => {\n const { formatMessage } = useIntl();\n const [open, setOpen] = useState(false);\n\n const label = filter.values.map((value) => formatMessage(TYPE_LABELS[value])).join(', ');\n\n const toggleValue = (value: TypeValue) => {\n const nextValues = filter.values.includes(value)\n ? filter.values.filter((v) => v !== value)\n : [...filter.values, value];\n\n // At least one value stays checked — an empty badge is removed via ×, not here.\n if (nextValues.length > 0) {\n onChange({ ...filter, values: nextValues });\n }\n };\n\n return (\n <Popover.Root open={open} onOpenChange={setOpen}>\n <Popover.Trigger>\n <Segment type=\"button\" $interactive>\n <Typography variant=\"pi\" textColor=\"neutral800\">\n {label}\n </Typography>\n </Segment>\n </Popover.Trigger>\n <PanelPopoverContent>\n <Flex direction=\"column\" alignItems=\"flex-start\" padding={3} gap={2}>\n {TYPE_VALUES.map((value) => (\n <Checkbox\n key={value}\n checked={filter.values.includes(value)}\n onCheckedChange={() => toggleValue(value)}\n >\n {formatMessage(TYPE_LABELS[value])}\n </Checkbox>\n ))}\n </Flex>\n </PanelPopoverContent>\n </Popover.Root>\n );\n};\n\nconst DateValuePopover = ({\n filter,\n onChange,\n}: {\n filter: DateFilter;\n onChange: (next: DateFilter) => void;\n}) => {\n const { formatMessage, formatDate } = useIntl();\n const [open, setOpen] = useState(false);\n\n // Parse as LOCAL calendar dates before formatting: react-intl would coerce\n // the raw `YYYY-MM-DD` strings via `new Date(value)` = UTC midnight, showing\n // the previous day in every timezone west of UTC while the query (also\n // local, see buildAssetFilters) filters the day the user actually picked.\n const label =\n filter.mode === 'preset'\n ? formatMessage(PRESET_LABELS[filter.preset])\n : `${formatDate(parseCalendarDate(filter.from), {\n day: '2-digit',\n month: 'short',\n })} - ${formatDate(parseCalendarDate(filter.to), {\n day: '2-digit',\n month: 'short',\n year: 'numeric',\n })}`;\n\n return (\n <Popover.Root open={open} onOpenChange={setOpen}>\n <Popover.Trigger>\n <Segment type=\"button\" $interactive>\n <Typography variant=\"pi\" textColor=\"neutral800\">\n {label}\n </Typography>\n </Segment>\n </Popover.Trigger>\n <PanelPopoverContent>\n {filter.mode === 'preset' ? (\n <Flex direction=\"column\" alignItems=\"stretch\" padding={1}>\n {DATE_PRESETS.map((preset: DatePreset) => (\n <OptionButton\n key={preset}\n type=\"button\"\n onClick={() => {\n onChange({ ...filter, preset });\n setOpen(false);\n }}\n >\n {formatMessage(PRESET_LABELS[preset])}\n {preset === filter.preset && <Check aria-hidden width=\"1.6rem\" height=\"1.6rem\" />}\n </OptionButton>\n ))}\n </Flex>\n ) : (\n <DateRangeCalendar\n from={filter.from}\n to={filter.to}\n onSelect={(from, to) => {\n onChange({ ...filter, from, to });\n setOpen(false);\n }}\n />\n )}\n </PanelPopoverContent>\n </Popover.Root>\n );\n};\n\nconst FilterBadge = ({\n filter,\n onChange,\n onRemove,\n}: {\n filter: ListFilter;\n onChange: (next: ListFilter) => void;\n onRemove: () => void;\n}) => {\n const { formatMessage } = useIntl();\n\n const fieldLabel =\n filter.kind === 'type'\n ? formatMessage({ id: getTranslationKey('list.filters.field.type'), defaultMessage: 'Type' })\n : formatMessage(DATE_FIELD_LABELS[filter.field]);\n\n return (\n <BadgePill alignItems=\"stretch\" data-testid=\"filter-badge\">\n <FieldSegment>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {fieldLabel}\n </Typography>\n </FieldSegment>\n\n {filter.kind === 'type' && (\n <>\n <SegmentPopover\n label={formatMessage(TYPE_CONDITION_LABELS[filter.condition])}\n options={['is', 'isNot'] as TypeCondition[]}\n active={filter.condition}\n getOptionLabel={(option) => formatMessage(TYPE_CONDITION_LABELS[option])}\n onPick={(condition) => onChange({ ...filter, condition })}\n />\n <TypeValuePopover filter={filter} onChange={onChange} />\n </>\n )}\n\n {filter.kind === 'date' && filter.mode === 'preset' && (\n <>\n <SegmentPopover\n label={formatMessage(PRESET_CONDITION_LABELS[filter.condition])}\n options={['isExactly', 'withinLast', 'notWithinLast'] as PresetCondition[]}\n active={filter.condition}\n getOptionLabel={(option) => formatMessage(PRESET_CONDITION_LABELS[option])}\n onPick={(condition) => onChange({ ...filter, condition })}\n />\n <DateValuePopover filter={filter} onChange={onChange} />\n </>\n )}\n\n {filter.kind === 'date' && filter.mode === 'range' && (\n <>\n <SegmentPopover\n label={formatMessage(RANGE_CONDITION_LABELS[filter.condition])}\n options={['is', 'isNot'] as RangeCondition[]}\n active={filter.condition}\n getOptionLabel={(option) => formatMessage(RANGE_CONDITION_LABELS[option])}\n onPick={(condition) => onChange({ ...filter, condition })}\n />\n <DateValuePopover filter={filter} onChange={onChange} />\n </>\n )}\n\n <RemoveButton\n type=\"button\"\n onClick={onRemove}\n aria-label={formatMessage(\n {\n id: getTranslationKey('list.filters.remove'),\n defaultMessage: 'Remove {filter} filter',\n },\n { filter: fieldLabel }\n )}\n >\n <Cross width=\"1.2rem\" height=\"1.2rem\" aria-hidden />\n </RemoveButton>\n </BadgePill>\n );\n};\n\n// Tighten the gap above the badges when the sticky header is in its compact\n// (scrolled) state, matching the header's own shrink.\nconst BadgesRoot = styled(Flex)<{ $compact: boolean }>`\n padding-top: ${({ theme, $compact }) => ($compact ? theme.spaces[1] : theme.spaces[6])};\n transition: padding-top 0.2s ease;\n`;\n\ninterface FilterBadgesProps {\n listFilters: ListFilters;\n /** Sticky header is scrolled/compact — reduce the space above the badges. */\n compact?: boolean;\n}\n\nexport const FilterBadges = ({ listFilters, compact = false }: FilterBadgesProps) => {\n const { filters, updateFilter, removeFilter } = listFilters;\n /**\n * Stable per-slot keys held in a ref. The ref is written during render, but\n * the bookkeeping depends on the list length rather than on how often render\n * runs, so the second pass of a StrictMode double render sees equal lengths\n * and does nothing. A content-derived key fails twice over here: filters may\n * legitimately repeat, and the key would change while the user edits a badge,\n * remounting the badge under its open popover.\n */\n const filterKeyPrefix = useId();\n const nextFilterKey = useRef(0);\n const filterKeys = useRef<string[]>([]);\n\n while (filterKeys.current.length < filters.length) {\n filterKeys.current.push(`${filterKeyPrefix}-${nextFilterKey.current}`);\n nextFilterKey.current += 1;\n }\n /**\n * Keys are truncated from the tail. The `onRemove` closure below splices the\n * removed slot out first, so removal through this component is correct. Any\n * other shrink path (browser back or forward, an external filter reset)\n * shifts the remaining keys and degrades to the index keys this replaced.\n * Known and accepted.\n */\n filterKeys.current.length = filters.length;\n\n const filtersWithKeys = filters.map((filter, index) => ({\n filter,\n index,\n key: filterKeys.current[index],\n }));\n\n if (filters.length === 0) {\n return null;\n }\n\n return (\n <BadgesRoot $compact={compact} gap={2} wrap=\"wrap\" data-testid=\"filter-badges\">\n {filtersWithKeys.map(({ filter, index, key }) => (\n <FilterBadge\n key={key}\n filter={filter}\n onChange={(next) => updateFilter(index, next)}\n onRemove={() => {\n filterKeys.current.splice(index, 1);\n removeFilter(index);\n }}\n />\n ))}\n </BadgesRoot>\n );\n};\n"],"names":["BadgePill","styled","Flex","theme","colors","neutral200","borderRadius","neutral0","Segment","button","spaces","$interactive","breakpoints","medium","primary100","primary600","FieldSegment","span","PanelPopoverContent","Popover","Content","FILTER_PANEL_WIDTH","OptionButton","fontSizes","lineHeights","neutral800","RemoveButton","neutral600","TYPE_CONDITION_LABELS","is","id","getTranslationKey","defaultMessage","isNot","PRESET_CONDITION_LABELS","isExactly","withinLast","notWithinLast","RANGE_CONDITION_LABELS","SegmentPopover","label","options","active","getOptionLabel","onPick","open","setOpen","useState","_jsxs","Root","onOpenChange","_jsx","Trigger","type","Typography","variant","textColor","direction","alignItems","padding","map","option","onClick","Check","aria-hidden","width","height","TypeValuePopover","filter","onChange","formatMessage","useIntl","values","value","TYPE_LABELS","join","toggleValue","nextValues","includes","v","length","gap","TYPE_VALUES","Checkbox","checked","onCheckedChange","DateValuePopover","formatDate","mode","PRESET_LABELS","preset","parseCalendarDate","from","day","month","to","year","DATE_PRESETS","DateRangeCalendar","onSelect","FilterBadge","onRemove","fieldLabel","kind","DATE_FIELD_LABELS","field","data-testid","_Fragment","condition","aria-label","Cross","BadgesRoot","$compact","FilterBadges","listFilters","compact","filters","updateFilter","removeFilter","filterKeyPrefix","useId","nextFilterKey","useRef","filterKeys","current","push","filtersWithKeys","index","key","wrap","next","splice"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
|
-
import { useState } from 'react';
|
|
2
|
+
import { useId, useRef, useState } from 'react';
|
|
3
3
|
import { Flex, Typography, Popover, Checkbox } from '@strapi/design-system';
|
|
4
4
|
import { Cross, Check } from '@strapi/icons';
|
|
5
5
|
import { useIntl } from 'react-intl';
|
|
@@ -395,6 +395,32 @@ const BadgesRoot = styled(Flex)`
|
|
|
395
395
|
`;
|
|
396
396
|
const FilterBadges = ({ listFilters, compact = false })=>{
|
|
397
397
|
const { filters, updateFilter, removeFilter } = listFilters;
|
|
398
|
+
/**
|
|
399
|
+
* Stable per-slot keys held in a ref. The ref is written during render, but
|
|
400
|
+
* the bookkeeping depends on the list length rather than on how often render
|
|
401
|
+
* runs, so the second pass of a StrictMode double render sees equal lengths
|
|
402
|
+
* and does nothing. A content-derived key fails twice over here: filters may
|
|
403
|
+
* legitimately repeat, and the key would change while the user edits a badge,
|
|
404
|
+
* remounting the badge under its open popover.
|
|
405
|
+
*/ const filterKeyPrefix = useId();
|
|
406
|
+
const nextFilterKey = useRef(0);
|
|
407
|
+
const filterKeys = useRef([]);
|
|
408
|
+
while(filterKeys.current.length < filters.length){
|
|
409
|
+
filterKeys.current.push(`${filterKeyPrefix}-${nextFilterKey.current}`);
|
|
410
|
+
nextFilterKey.current += 1;
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Keys are truncated from the tail. The `onRemove` closure below splices the
|
|
414
|
+
* removed slot out first, so removal through this component is correct. Any
|
|
415
|
+
* other shrink path (browser back or forward, an external filter reset)
|
|
416
|
+
* shifts the remaining keys and degrades to the index keys this replaced.
|
|
417
|
+
* Known and accepted.
|
|
418
|
+
*/ filterKeys.current.length = filters.length;
|
|
419
|
+
const filtersWithKeys = filters.map((filter, index)=>({
|
|
420
|
+
filter,
|
|
421
|
+
index,
|
|
422
|
+
key: filterKeys.current[index]
|
|
423
|
+
}));
|
|
398
424
|
if (filters.length === 0) {
|
|
399
425
|
return null;
|
|
400
426
|
}
|
|
@@ -403,11 +429,14 @@ const FilterBadges = ({ listFilters, compact = false })=>{
|
|
|
403
429
|
gap: 2,
|
|
404
430
|
wrap: "wrap",
|
|
405
431
|
"data-testid": "filter-badges",
|
|
406
|
-
children:
|
|
432
|
+
children: filtersWithKeys.map(({ filter, index, key })=>/*#__PURE__*/ jsx(FilterBadge, {
|
|
407
433
|
filter: filter,
|
|
408
434
|
onChange: (next)=>updateFilter(index, next),
|
|
409
|
-
onRemove: ()=>
|
|
410
|
-
|
|
435
|
+
onRemove: ()=>{
|
|
436
|
+
filterKeys.current.splice(index, 1);
|
|
437
|
+
removeFilter(index);
|
|
438
|
+
}
|
|
439
|
+
}, key))
|
|
411
440
|
});
|
|
412
441
|
};
|
|
413
442
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FilterBadges.mjs","sources":["../../../../../admin/src/pages/Assets/components/FilterBadges.tsx"],"sourcesContent":["import { useState } from 'react';\n\nimport { Checkbox, Flex, Popover, Typography } from '@strapi/design-system';\nimport { Check, Cross } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { styled } from 'styled-components';\n\nimport { getTranslationKey } from '../../../utils/translations';\nimport {\n DATE_PRESETS,\n TYPE_VALUES,\n type DateFilter,\n type DatePreset,\n type ListFilter,\n type ListFilters,\n type PresetCondition,\n type RangeCondition,\n type TypeCondition,\n type TypeFilter,\n type TypeValue,\n} from '../hooks/useListFilters';\nimport { parseCalendarDate } from '../utils/buildAssetFilters';\n\nimport { DateRangeCalendar } from './DateRangeCalendar';\nimport { DATE_FIELD_LABELS, FILTER_PANEL_WIDTH, PRESET_LABELS, TYPE_LABELS } from './FilterMenu';\n\nimport type { MessageDescriptor } from 'react-intl';\n\n/**\n * Row of applied-filter badges under the toolbar. A badge has three segments —\n * field (static), condition (click → select popover), value (click → type\n * checkboxes / preset list / range calendar) — plus a remove button.\n */\n\nconst BadgePill = styled(Flex)`\n border: 1px solid ${({ theme }) => theme.colors.neutral200};\n border-radius: ${({ theme }) => theme.borderRadius};\n background: ${({ theme }) => theme.colors.neutral0};\n overflow: hidden;\n`;\n\nconst Segment = styled.button<{ $interactive?: boolean }>`\n border: none;\n background: transparent;\n font: inherit;\n padding: ${({ theme }) => `${theme.spaces[2]} ${theme.spaces[3]}`};\n cursor: ${({ $interactive }) => ($interactive ? 'pointer' : 'default')};\n border-right: 1px solid ${({ theme }) => theme.colors.neutral200};\n\n ${({ theme }) => theme.breakpoints.medium} {\n padding: ${({ theme }) => `${theme.spaces[1]} ${theme.spaces[2]}`};\n }\n ${({ $interactive, theme }) =>\n $interactive && `&:hover { background: ${theme.colors.primary100}; }`}\n\n &:focus-visible {\n outline: 2px solid ${({ theme }) => theme.colors.primary600};\n outline-offset: -2px;\n }\n`;\n\n// Non-interactive field segment (first pill cell).\nconst FieldSegment = styled.span`\n display: inline-flex;\n align-items: center;\n padding: ${({ theme }) => `${theme.spaces[1]} ${theme.spaces[2]}`};\n border-right: 1px solid ${({ theme }) => theme.colors.neutral200};\n`;\n\n// Badge popovers mirror the filter-menu panels: same fixed width, same font.\nconst PanelPopoverContent = styled(Popover.Content)`\n width: ${FILTER_PANEL_WIDTH};\n`;\n\n// Option row inside a segment popover — sized like a DS Menu.Item so the badge\n// dropdowns read as the same control family as the filter menu.\nconst OptionButton = styled.button`\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: ${({ theme }) => theme.spaces[4]};\n width: 100%;\n border: none;\n background: transparent;\n font-size: ${({ theme }) => theme.fontSizes[2]};\n line-height: ${({ theme }) => theme.lineHeights[4]};\n font-family: inherit;\n text-align: left;\n padding: ${({ theme }) => `${theme.spaces[2]} ${theme.spaces[4]}`};\n border-radius: ${({ theme }) => theme.borderRadius};\n cursor: pointer;\n color: ${({ theme }) => theme.colors.neutral800};\n\n &:hover {\n background: ${({ theme }) => theme.colors.primary100};\n }\n\n &:focus-visible {\n outline: 2px solid ${({ theme }) => theme.colors.primary600};\n outline-offset: -2px;\n }\n`;\n\nconst RemoveButton = styled.button`\n border: none;\n background: transparent;\n display: inline-flex;\n align-items: center;\n padding: ${({ theme }) => `0 ${theme.spaces[2]}`};\n cursor: pointer;\n color: ${({ theme }) => theme.colors.neutral600};\n\n &:hover {\n color: ${({ theme }) => theme.colors.neutral800};\n }\n\n &:focus-visible {\n outline: 2px solid ${({ theme }) => theme.colors.primary600};\n outline-offset: -2px;\n }\n`;\n\nconst TYPE_CONDITION_LABELS: Record<TypeCondition, MessageDescriptor> = {\n is: { id: getTranslationKey('list.filters.condition.is'), defaultMessage: 'is' },\n isNot: { id: getTranslationKey('list.filters.condition.is-not'), defaultMessage: 'is not' },\n};\n\nconst PRESET_CONDITION_LABELS: Record<PresetCondition, MessageDescriptor> = {\n isExactly: {\n id: getTranslationKey('list.filters.condition.is-exactly'),\n defaultMessage: 'is exactly',\n },\n withinLast: {\n id: getTranslationKey('list.filters.condition.within-last'),\n defaultMessage: 'within the last',\n },\n notWithinLast: {\n id: getTranslationKey('list.filters.condition.not-within-last'),\n defaultMessage: 'not within the last',\n },\n};\n\nconst RANGE_CONDITION_LABELS: Record<RangeCondition, MessageDescriptor> = {\n is: { id: getTranslationKey('list.filters.condition.is'), defaultMessage: 'is' },\n isNot: { id: getTranslationKey('list.filters.condition.is-not'), defaultMessage: 'is not' },\n};\n\n/** A small single-choice popover listing options with a check on the active one. */\ninterface SegmentPopoverProps<T extends string> {\n label: string;\n options: T[];\n active: T;\n getOptionLabel: (option: T) => string;\n onPick: (option: T) => void;\n}\n\nconst SegmentPopover = <T extends string>({\n label,\n options,\n active,\n getOptionLabel,\n onPick,\n}: SegmentPopoverProps<T>) => {\n const [open, setOpen] = useState(false);\n\n return (\n <Popover.Root open={open} onOpenChange={setOpen}>\n <Popover.Trigger>\n <Segment type=\"button\" $interactive>\n <Typography variant=\"pi\" textColor=\"neutral800\">\n {label}\n </Typography>\n </Segment>\n </Popover.Trigger>\n <PanelPopoverContent>\n <Flex direction=\"column\" alignItems=\"stretch\" padding={1}>\n {options.map((option) => (\n <OptionButton\n key={option}\n type=\"button\"\n onClick={() => {\n onPick(option);\n setOpen(false);\n }}\n >\n {getOptionLabel(option)}\n {option === active && <Check aria-hidden width=\"1.6rem\" height=\"1.6rem\" />}\n </OptionButton>\n ))}\n </Flex>\n </PanelPopoverContent>\n </Popover.Root>\n );\n};\n\nconst TypeValuePopover = ({\n filter,\n onChange,\n}: {\n filter: TypeFilter;\n onChange: (next: TypeFilter) => void;\n}) => {\n const { formatMessage } = useIntl();\n const [open, setOpen] = useState(false);\n\n const label = filter.values.map((value) => formatMessage(TYPE_LABELS[value])).join(', ');\n\n const toggleValue = (value: TypeValue) => {\n const nextValues = filter.values.includes(value)\n ? filter.values.filter((v) => v !== value)\n : [...filter.values, value];\n\n // At least one value stays checked — an empty badge is removed via ×, not here.\n if (nextValues.length > 0) {\n onChange({ ...filter, values: nextValues });\n }\n };\n\n return (\n <Popover.Root open={open} onOpenChange={setOpen}>\n <Popover.Trigger>\n <Segment type=\"button\" $interactive>\n <Typography variant=\"pi\" textColor=\"neutral800\">\n {label}\n </Typography>\n </Segment>\n </Popover.Trigger>\n <PanelPopoverContent>\n <Flex direction=\"column\" alignItems=\"flex-start\" padding={3} gap={2}>\n {TYPE_VALUES.map((value) => (\n <Checkbox\n key={value}\n checked={filter.values.includes(value)}\n onCheckedChange={() => toggleValue(value)}\n >\n {formatMessage(TYPE_LABELS[value])}\n </Checkbox>\n ))}\n </Flex>\n </PanelPopoverContent>\n </Popover.Root>\n );\n};\n\nconst DateValuePopover = ({\n filter,\n onChange,\n}: {\n filter: DateFilter;\n onChange: (next: DateFilter) => void;\n}) => {\n const { formatMessage, formatDate } = useIntl();\n const [open, setOpen] = useState(false);\n\n // Parse as LOCAL calendar dates before formatting: react-intl would coerce\n // the raw `YYYY-MM-DD` strings via `new Date(value)` = UTC midnight, showing\n // the previous day in every timezone west of UTC while the query (also\n // local, see buildAssetFilters) filters the day the user actually picked.\n const label =\n filter.mode === 'preset'\n ? formatMessage(PRESET_LABELS[filter.preset])\n : `${formatDate(parseCalendarDate(filter.from), {\n day: '2-digit',\n month: 'short',\n })} - ${formatDate(parseCalendarDate(filter.to), {\n day: '2-digit',\n month: 'short',\n year: 'numeric',\n })}`;\n\n return (\n <Popover.Root open={open} onOpenChange={setOpen}>\n <Popover.Trigger>\n <Segment type=\"button\" $interactive>\n <Typography variant=\"pi\" textColor=\"neutral800\">\n {label}\n </Typography>\n </Segment>\n </Popover.Trigger>\n <PanelPopoverContent>\n {filter.mode === 'preset' ? (\n <Flex direction=\"column\" alignItems=\"stretch\" padding={1}>\n {DATE_PRESETS.map((preset: DatePreset) => (\n <OptionButton\n key={preset}\n type=\"button\"\n onClick={() => {\n onChange({ ...filter, preset });\n setOpen(false);\n }}\n >\n {formatMessage(PRESET_LABELS[preset])}\n {preset === filter.preset && <Check aria-hidden width=\"1.6rem\" height=\"1.6rem\" />}\n </OptionButton>\n ))}\n </Flex>\n ) : (\n <DateRangeCalendar\n from={filter.from}\n to={filter.to}\n onSelect={(from, to) => {\n onChange({ ...filter, from, to });\n setOpen(false);\n }}\n />\n )}\n </PanelPopoverContent>\n </Popover.Root>\n );\n};\n\nconst FilterBadge = ({\n filter,\n onChange,\n onRemove,\n}: {\n filter: ListFilter;\n onChange: (next: ListFilter) => void;\n onRemove: () => void;\n}) => {\n const { formatMessage } = useIntl();\n\n const fieldLabel =\n filter.kind === 'type'\n ? formatMessage({ id: getTranslationKey('list.filters.field.type'), defaultMessage: 'Type' })\n : formatMessage(DATE_FIELD_LABELS[filter.field]);\n\n return (\n <BadgePill alignItems=\"stretch\" data-testid=\"filter-badge\">\n <FieldSegment>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {fieldLabel}\n </Typography>\n </FieldSegment>\n\n {filter.kind === 'type' && (\n <>\n <SegmentPopover\n label={formatMessage(TYPE_CONDITION_LABELS[filter.condition])}\n options={['is', 'isNot'] as TypeCondition[]}\n active={filter.condition}\n getOptionLabel={(option) => formatMessage(TYPE_CONDITION_LABELS[option])}\n onPick={(condition) => onChange({ ...filter, condition })}\n />\n <TypeValuePopover filter={filter} onChange={onChange} />\n </>\n )}\n\n {filter.kind === 'date' && filter.mode === 'preset' && (\n <>\n <SegmentPopover\n label={formatMessage(PRESET_CONDITION_LABELS[filter.condition])}\n options={['isExactly', 'withinLast', 'notWithinLast'] as PresetCondition[]}\n active={filter.condition}\n getOptionLabel={(option) => formatMessage(PRESET_CONDITION_LABELS[option])}\n onPick={(condition) => onChange({ ...filter, condition })}\n />\n <DateValuePopover filter={filter} onChange={onChange} />\n </>\n )}\n\n {filter.kind === 'date' && filter.mode === 'range' && (\n <>\n <SegmentPopover\n label={formatMessage(RANGE_CONDITION_LABELS[filter.condition])}\n options={['is', 'isNot'] as RangeCondition[]}\n active={filter.condition}\n getOptionLabel={(option) => formatMessage(RANGE_CONDITION_LABELS[option])}\n onPick={(condition) => onChange({ ...filter, condition })}\n />\n <DateValuePopover filter={filter} onChange={onChange} />\n </>\n )}\n\n <RemoveButton\n type=\"button\"\n onClick={onRemove}\n aria-label={formatMessage(\n {\n id: getTranslationKey('list.filters.remove'),\n defaultMessage: 'Remove {filter} filter',\n },\n { filter: fieldLabel }\n )}\n >\n <Cross width=\"1.2rem\" height=\"1.2rem\" aria-hidden />\n </RemoveButton>\n </BadgePill>\n );\n};\n\n// Tighten the gap above the badges when the sticky header is in its compact\n// (scrolled) state, matching the header's own shrink.\nconst BadgesRoot = styled(Flex)<{ $compact: boolean }>`\n padding-top: ${({ theme, $compact }) => ($compact ? theme.spaces[1] : theme.spaces[6])};\n transition: padding-top 0.2s ease;\n`;\n\ninterface FilterBadgesProps {\n listFilters: ListFilters;\n /** Sticky header is scrolled/compact — reduce the space above the badges. */\n compact?: boolean;\n}\n\nexport const FilterBadges = ({ listFilters, compact = false }: FilterBadgesProps) => {\n const { filters, updateFilter, removeFilter } = listFilters;\n\n if (filters.length === 0) {\n return null;\n }\n\n return (\n <BadgesRoot $compact={compact} gap={2} wrap=\"wrap\" data-testid=\"filter-badges\">\n {filters.map((filter, index) => (\n <FilterBadge\n // Position is identity: badges are edited/removed by index.\n key={index}\n filter={filter}\n onChange={(next) => updateFilter(index, next)}\n onRemove={() => removeFilter(index)}\n />\n ))}\n </BadgesRoot>\n );\n};\n"],"names":["BadgePill","styled","Flex","theme","colors","neutral200","borderRadius","neutral0","Segment","button","spaces","$interactive","breakpoints","medium","primary100","primary600","FieldSegment","span","PanelPopoverContent","Popover","Content","FILTER_PANEL_WIDTH","OptionButton","fontSizes","lineHeights","neutral800","RemoveButton","neutral600","TYPE_CONDITION_LABELS","is","id","getTranslationKey","defaultMessage","isNot","PRESET_CONDITION_LABELS","isExactly","withinLast","notWithinLast","RANGE_CONDITION_LABELS","SegmentPopover","label","options","active","getOptionLabel","onPick","open","setOpen","useState","_jsxs","Root","onOpenChange","_jsx","Trigger","type","Typography","variant","textColor","direction","alignItems","padding","map","option","onClick","Check","aria-hidden","width","height","TypeValuePopover","filter","onChange","formatMessage","useIntl","values","value","TYPE_LABELS","join","toggleValue","nextValues","includes","v","length","gap","TYPE_VALUES","Checkbox","checked","onCheckedChange","DateValuePopover","formatDate","mode","PRESET_LABELS","preset","parseCalendarDate","from","day","month","to","year","DATE_PRESETS","DateRangeCalendar","onSelect","FilterBadge","onRemove","fieldLabel","kind","DATE_FIELD_LABELS","field","data-testid","_Fragment","condition","aria-label","Cross","BadgesRoot","$compact","FilterBadges","listFilters","compact","filters","updateFilter","removeFilter","wrap","index","next"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FilterBadges.mjs","sources":["../../../../../admin/src/pages/Assets/components/FilterBadges.tsx"],"sourcesContent":["import { useId, useRef, useState } from 'react';\n\nimport { Checkbox, Flex, Popover, Typography } from '@strapi/design-system';\nimport { Check, Cross } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { styled } from 'styled-components';\n\nimport { getTranslationKey } from '../../../utils/translations';\nimport {\n DATE_PRESETS,\n TYPE_VALUES,\n type DateFilter,\n type DatePreset,\n type ListFilter,\n type ListFilters,\n type PresetCondition,\n type RangeCondition,\n type TypeCondition,\n type TypeFilter,\n type TypeValue,\n} from '../hooks/useListFilters';\nimport { parseCalendarDate } from '../utils/buildAssetFilters';\n\nimport { DateRangeCalendar } from './DateRangeCalendar';\nimport { DATE_FIELD_LABELS, FILTER_PANEL_WIDTH, PRESET_LABELS, TYPE_LABELS } from './FilterMenu';\n\nimport type { MessageDescriptor } from 'react-intl';\n\n/**\n * Row of applied-filter badges under the toolbar. A badge has three segments —\n * field (static), condition (click → select popover), value (click → type\n * checkboxes / preset list / range calendar) — plus a remove button.\n */\n\nconst BadgePill = styled(Flex)`\n border: 1px solid ${({ theme }) => theme.colors.neutral200};\n border-radius: ${({ theme }) => theme.borderRadius};\n background: ${({ theme }) => theme.colors.neutral0};\n overflow: hidden;\n`;\n\nconst Segment = styled.button<{ $interactive?: boolean }>`\n border: none;\n background: transparent;\n font: inherit;\n padding: ${({ theme }) => `${theme.spaces[2]} ${theme.spaces[3]}`};\n cursor: ${({ $interactive }) => ($interactive ? 'pointer' : 'default')};\n border-right: 1px solid ${({ theme }) => theme.colors.neutral200};\n\n ${({ theme }) => theme.breakpoints.medium} {\n padding: ${({ theme }) => `${theme.spaces[1]} ${theme.spaces[2]}`};\n }\n ${({ $interactive, theme }) =>\n $interactive && `&:hover { background: ${theme.colors.primary100}; }`}\n\n &:focus-visible {\n outline: 2px solid ${({ theme }) => theme.colors.primary600};\n outline-offset: -2px;\n }\n`;\n\n// Non-interactive field segment (first pill cell).\nconst FieldSegment = styled.span`\n display: inline-flex;\n align-items: center;\n padding: ${({ theme }) => `${theme.spaces[1]} ${theme.spaces[2]}`};\n border-right: 1px solid ${({ theme }) => theme.colors.neutral200};\n`;\n\n// Badge popovers mirror the filter-menu panels: same fixed width, same font.\nconst PanelPopoverContent = styled(Popover.Content)`\n width: ${FILTER_PANEL_WIDTH};\n`;\n\n// Option row inside a segment popover — sized like a DS Menu.Item so the badge\n// dropdowns read as the same control family as the filter menu.\nconst OptionButton = styled.button`\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: ${({ theme }) => theme.spaces[4]};\n width: 100%;\n border: none;\n background: transparent;\n font-size: ${({ theme }) => theme.fontSizes[2]};\n line-height: ${({ theme }) => theme.lineHeights[4]};\n font-family: inherit;\n text-align: left;\n padding: ${({ theme }) => `${theme.spaces[2]} ${theme.spaces[4]}`};\n border-radius: ${({ theme }) => theme.borderRadius};\n cursor: pointer;\n color: ${({ theme }) => theme.colors.neutral800};\n\n &:hover {\n background: ${({ theme }) => theme.colors.primary100};\n }\n\n &:focus-visible {\n outline: 2px solid ${({ theme }) => theme.colors.primary600};\n outline-offset: -2px;\n }\n`;\n\nconst RemoveButton = styled.button`\n border: none;\n background: transparent;\n display: inline-flex;\n align-items: center;\n padding: ${({ theme }) => `0 ${theme.spaces[2]}`};\n cursor: pointer;\n color: ${({ theme }) => theme.colors.neutral600};\n\n &:hover {\n color: ${({ theme }) => theme.colors.neutral800};\n }\n\n &:focus-visible {\n outline: 2px solid ${({ theme }) => theme.colors.primary600};\n outline-offset: -2px;\n }\n`;\n\nconst TYPE_CONDITION_LABELS: Record<TypeCondition, MessageDescriptor> = {\n is: { id: getTranslationKey('list.filters.condition.is'), defaultMessage: 'is' },\n isNot: { id: getTranslationKey('list.filters.condition.is-not'), defaultMessage: 'is not' },\n};\n\nconst PRESET_CONDITION_LABELS: Record<PresetCondition, MessageDescriptor> = {\n isExactly: {\n id: getTranslationKey('list.filters.condition.is-exactly'),\n defaultMessage: 'is exactly',\n },\n withinLast: {\n id: getTranslationKey('list.filters.condition.within-last'),\n defaultMessage: 'within the last',\n },\n notWithinLast: {\n id: getTranslationKey('list.filters.condition.not-within-last'),\n defaultMessage: 'not within the last',\n },\n};\n\nconst RANGE_CONDITION_LABELS: Record<RangeCondition, MessageDescriptor> = {\n is: { id: getTranslationKey('list.filters.condition.is'), defaultMessage: 'is' },\n isNot: { id: getTranslationKey('list.filters.condition.is-not'), defaultMessage: 'is not' },\n};\n\n/** A small single-choice popover listing options with a check on the active one. */\ninterface SegmentPopoverProps<T extends string> {\n label: string;\n options: T[];\n active: T;\n getOptionLabel: (option: T) => string;\n onPick: (option: T) => void;\n}\n\nconst SegmentPopover = <T extends string>({\n label,\n options,\n active,\n getOptionLabel,\n onPick,\n}: SegmentPopoverProps<T>) => {\n const [open, setOpen] = useState(false);\n\n return (\n <Popover.Root open={open} onOpenChange={setOpen}>\n <Popover.Trigger>\n <Segment type=\"button\" $interactive>\n <Typography variant=\"pi\" textColor=\"neutral800\">\n {label}\n </Typography>\n </Segment>\n </Popover.Trigger>\n <PanelPopoverContent>\n <Flex direction=\"column\" alignItems=\"stretch\" padding={1}>\n {options.map((option) => (\n <OptionButton\n key={option}\n type=\"button\"\n onClick={() => {\n onPick(option);\n setOpen(false);\n }}\n >\n {getOptionLabel(option)}\n {option === active && <Check aria-hidden width=\"1.6rem\" height=\"1.6rem\" />}\n </OptionButton>\n ))}\n </Flex>\n </PanelPopoverContent>\n </Popover.Root>\n );\n};\n\nconst TypeValuePopover = ({\n filter,\n onChange,\n}: {\n filter: TypeFilter;\n onChange: (next: TypeFilter) => void;\n}) => {\n const { formatMessage } = useIntl();\n const [open, setOpen] = useState(false);\n\n const label = filter.values.map((value) => formatMessage(TYPE_LABELS[value])).join(', ');\n\n const toggleValue = (value: TypeValue) => {\n const nextValues = filter.values.includes(value)\n ? filter.values.filter((v) => v !== value)\n : [...filter.values, value];\n\n // At least one value stays checked — an empty badge is removed via ×, not here.\n if (nextValues.length > 0) {\n onChange({ ...filter, values: nextValues });\n }\n };\n\n return (\n <Popover.Root open={open} onOpenChange={setOpen}>\n <Popover.Trigger>\n <Segment type=\"button\" $interactive>\n <Typography variant=\"pi\" textColor=\"neutral800\">\n {label}\n </Typography>\n </Segment>\n </Popover.Trigger>\n <PanelPopoverContent>\n <Flex direction=\"column\" alignItems=\"flex-start\" padding={3} gap={2}>\n {TYPE_VALUES.map((value) => (\n <Checkbox\n key={value}\n checked={filter.values.includes(value)}\n onCheckedChange={() => toggleValue(value)}\n >\n {formatMessage(TYPE_LABELS[value])}\n </Checkbox>\n ))}\n </Flex>\n </PanelPopoverContent>\n </Popover.Root>\n );\n};\n\nconst DateValuePopover = ({\n filter,\n onChange,\n}: {\n filter: DateFilter;\n onChange: (next: DateFilter) => void;\n}) => {\n const { formatMessage, formatDate } = useIntl();\n const [open, setOpen] = useState(false);\n\n // Parse as LOCAL calendar dates before formatting: react-intl would coerce\n // the raw `YYYY-MM-DD` strings via `new Date(value)` = UTC midnight, showing\n // the previous day in every timezone west of UTC while the query (also\n // local, see buildAssetFilters) filters the day the user actually picked.\n const label =\n filter.mode === 'preset'\n ? formatMessage(PRESET_LABELS[filter.preset])\n : `${formatDate(parseCalendarDate(filter.from), {\n day: '2-digit',\n month: 'short',\n })} - ${formatDate(parseCalendarDate(filter.to), {\n day: '2-digit',\n month: 'short',\n year: 'numeric',\n })}`;\n\n return (\n <Popover.Root open={open} onOpenChange={setOpen}>\n <Popover.Trigger>\n <Segment type=\"button\" $interactive>\n <Typography variant=\"pi\" textColor=\"neutral800\">\n {label}\n </Typography>\n </Segment>\n </Popover.Trigger>\n <PanelPopoverContent>\n {filter.mode === 'preset' ? (\n <Flex direction=\"column\" alignItems=\"stretch\" padding={1}>\n {DATE_PRESETS.map((preset: DatePreset) => (\n <OptionButton\n key={preset}\n type=\"button\"\n onClick={() => {\n onChange({ ...filter, preset });\n setOpen(false);\n }}\n >\n {formatMessage(PRESET_LABELS[preset])}\n {preset === filter.preset && <Check aria-hidden width=\"1.6rem\" height=\"1.6rem\" />}\n </OptionButton>\n ))}\n </Flex>\n ) : (\n <DateRangeCalendar\n from={filter.from}\n to={filter.to}\n onSelect={(from, to) => {\n onChange({ ...filter, from, to });\n setOpen(false);\n }}\n />\n )}\n </PanelPopoverContent>\n </Popover.Root>\n );\n};\n\nconst FilterBadge = ({\n filter,\n onChange,\n onRemove,\n}: {\n filter: ListFilter;\n onChange: (next: ListFilter) => void;\n onRemove: () => void;\n}) => {\n const { formatMessage } = useIntl();\n\n const fieldLabel =\n filter.kind === 'type'\n ? formatMessage({ id: getTranslationKey('list.filters.field.type'), defaultMessage: 'Type' })\n : formatMessage(DATE_FIELD_LABELS[filter.field]);\n\n return (\n <BadgePill alignItems=\"stretch\" data-testid=\"filter-badge\">\n <FieldSegment>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {fieldLabel}\n </Typography>\n </FieldSegment>\n\n {filter.kind === 'type' && (\n <>\n <SegmentPopover\n label={formatMessage(TYPE_CONDITION_LABELS[filter.condition])}\n options={['is', 'isNot'] as TypeCondition[]}\n active={filter.condition}\n getOptionLabel={(option) => formatMessage(TYPE_CONDITION_LABELS[option])}\n onPick={(condition) => onChange({ ...filter, condition })}\n />\n <TypeValuePopover filter={filter} onChange={onChange} />\n </>\n )}\n\n {filter.kind === 'date' && filter.mode === 'preset' && (\n <>\n <SegmentPopover\n label={formatMessage(PRESET_CONDITION_LABELS[filter.condition])}\n options={['isExactly', 'withinLast', 'notWithinLast'] as PresetCondition[]}\n active={filter.condition}\n getOptionLabel={(option) => formatMessage(PRESET_CONDITION_LABELS[option])}\n onPick={(condition) => onChange({ ...filter, condition })}\n />\n <DateValuePopover filter={filter} onChange={onChange} />\n </>\n )}\n\n {filter.kind === 'date' && filter.mode === 'range' && (\n <>\n <SegmentPopover\n label={formatMessage(RANGE_CONDITION_LABELS[filter.condition])}\n options={['is', 'isNot'] as RangeCondition[]}\n active={filter.condition}\n getOptionLabel={(option) => formatMessage(RANGE_CONDITION_LABELS[option])}\n onPick={(condition) => onChange({ ...filter, condition })}\n />\n <DateValuePopover filter={filter} onChange={onChange} />\n </>\n )}\n\n <RemoveButton\n type=\"button\"\n onClick={onRemove}\n aria-label={formatMessage(\n {\n id: getTranslationKey('list.filters.remove'),\n defaultMessage: 'Remove {filter} filter',\n },\n { filter: fieldLabel }\n )}\n >\n <Cross width=\"1.2rem\" height=\"1.2rem\" aria-hidden />\n </RemoveButton>\n </BadgePill>\n );\n};\n\n// Tighten the gap above the badges when the sticky header is in its compact\n// (scrolled) state, matching the header's own shrink.\nconst BadgesRoot = styled(Flex)<{ $compact: boolean }>`\n padding-top: ${({ theme, $compact }) => ($compact ? theme.spaces[1] : theme.spaces[6])};\n transition: padding-top 0.2s ease;\n`;\n\ninterface FilterBadgesProps {\n listFilters: ListFilters;\n /** Sticky header is scrolled/compact — reduce the space above the badges. */\n compact?: boolean;\n}\n\nexport const FilterBadges = ({ listFilters, compact = false }: FilterBadgesProps) => {\n const { filters, updateFilter, removeFilter } = listFilters;\n /**\n * Stable per-slot keys held in a ref. The ref is written during render, but\n * the bookkeeping depends on the list length rather than on how often render\n * runs, so the second pass of a StrictMode double render sees equal lengths\n * and does nothing. A content-derived key fails twice over here: filters may\n * legitimately repeat, and the key would change while the user edits a badge,\n * remounting the badge under its open popover.\n */\n const filterKeyPrefix = useId();\n const nextFilterKey = useRef(0);\n const filterKeys = useRef<string[]>([]);\n\n while (filterKeys.current.length < filters.length) {\n filterKeys.current.push(`${filterKeyPrefix}-${nextFilterKey.current}`);\n nextFilterKey.current += 1;\n }\n /**\n * Keys are truncated from the tail. The `onRemove` closure below splices the\n * removed slot out first, so removal through this component is correct. Any\n * other shrink path (browser back or forward, an external filter reset)\n * shifts the remaining keys and degrades to the index keys this replaced.\n * Known and accepted.\n */\n filterKeys.current.length = filters.length;\n\n const filtersWithKeys = filters.map((filter, index) => ({\n filter,\n index,\n key: filterKeys.current[index],\n }));\n\n if (filters.length === 0) {\n return null;\n }\n\n return (\n <BadgesRoot $compact={compact} gap={2} wrap=\"wrap\" data-testid=\"filter-badges\">\n {filtersWithKeys.map(({ filter, index, key }) => (\n <FilterBadge\n key={key}\n filter={filter}\n onChange={(next) => updateFilter(index, next)}\n onRemove={() => {\n filterKeys.current.splice(index, 1);\n removeFilter(index);\n }}\n />\n ))}\n </BadgesRoot>\n );\n};\n"],"names":["BadgePill","styled","Flex","theme","colors","neutral200","borderRadius","neutral0","Segment","button","spaces","$interactive","breakpoints","medium","primary100","primary600","FieldSegment","span","PanelPopoverContent","Popover","Content","FILTER_PANEL_WIDTH","OptionButton","fontSizes","lineHeights","neutral800","RemoveButton","neutral600","TYPE_CONDITION_LABELS","is","id","getTranslationKey","defaultMessage","isNot","PRESET_CONDITION_LABELS","isExactly","withinLast","notWithinLast","RANGE_CONDITION_LABELS","SegmentPopover","label","options","active","getOptionLabel","onPick","open","setOpen","useState","_jsxs","Root","onOpenChange","_jsx","Trigger","type","Typography","variant","textColor","direction","alignItems","padding","map","option","onClick","Check","aria-hidden","width","height","TypeValuePopover","filter","onChange","formatMessage","useIntl","values","value","TYPE_LABELS","join","toggleValue","nextValues","includes","v","length","gap","TYPE_VALUES","Checkbox","checked","onCheckedChange","DateValuePopover","formatDate","mode","PRESET_LABELS","preset","parseCalendarDate","from","day","month","to","year","DATE_PRESETS","DateRangeCalendar","onSelect","FilterBadge","onRemove","fieldLabel","kind","DATE_FIELD_LABELS","field","data-testid","_Fragment","condition","aria-label","Cross","BadgesRoot","$compact","FilterBadges","listFilters","compact","filters","updateFilter","removeFilter","filterKeyPrefix","useId","nextFilterKey","useRef","filterKeys","current","push","filtersWithKeys","index","key","wrap","next","splice"],"mappings":"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"}
|
|
@@ -166,6 +166,7 @@ const trackPoolRun = (uploadId, run)=>{
|
|
|
166
166
|
uploadId,
|
|
167
167
|
completedAt: Date.now()
|
|
168
168
|
}));
|
|
169
|
+
entry.onUploaded?.(file);
|
|
169
170
|
// Not awaited: overlaps with the next file's upload and can't fail the batch.
|
|
170
171
|
maybeGenerateMetadata({
|
|
171
172
|
file,
|
|
@@ -231,7 +232,8 @@ const trackPoolRun = (uploadId, run)=>{
|
|
|
231
232
|
const earlier = previous?.data ?? [];
|
|
232
233
|
if (abortController.signal.aborted) {
|
|
233
234
|
return {
|
|
234
|
-
data: earlier
|
|
235
|
+
data: earlier,
|
|
236
|
+
own: []
|
|
235
237
|
};
|
|
236
238
|
}
|
|
237
239
|
registerAbortController(uploadId, abortController);
|
|
@@ -248,11 +250,18 @@ const trackPoolRun = (uploadId, run)=>{
|
|
|
248
250
|
data: [
|
|
249
251
|
...earlier,
|
|
250
252
|
...result.data ?? []
|
|
251
|
-
]
|
|
253
|
+
],
|
|
254
|
+
own: result.data ?? []
|
|
252
255
|
});
|
|
253
256
|
});
|
|
254
257
|
trackPoolRun(uploadId, run);
|
|
255
|
-
|
|
258
|
+
// The chained value keeps every file in the batch, because the next merged leg
|
|
259
|
+
// reads it as its own `earlier`. The caller gets only what it handed in: a
|
|
260
|
+
// consumer that attaches the result — the Content Manager field — would
|
|
261
|
+
// otherwise re-attach the files the earlier drop already added.
|
|
262
|
+
return run.then((result)=>result.error ? result : {
|
|
263
|
+
data: result.own ?? result.data
|
|
264
|
+
});
|
|
256
265
|
};
|
|
257
266
|
/* -------------------------------------------------------------------------------------------------
|
|
258
267
|
* URL upload flow (SSE) — kept as-is for this iteration
|
|
@@ -431,7 +440,7 @@ const uploadApi = strapiAdmin.adminApi.enhanceEndpoints({
|
|
|
431
440
|
* pool of `concurrency` parallel requests (default 1 = sequential). Real
|
|
432
441
|
* per-file byte progress comes from `XHR.upload.onprogress`.
|
|
433
442
|
*/ uploadFiles: builder.mutation({
|
|
434
|
-
queryFn: async ({ formData, totalFiles, concurrency = 1, generateAiMetadata }, { dispatch, getState })=>{
|
|
443
|
+
queryFn: async ({ formData, totalFiles, concurrency = 1, generateAiMetadata, onFileUploaded }, { dispatch, getState })=>{
|
|
435
444
|
const token = getState().admin_app?.token;
|
|
436
445
|
// Extract the original files and their per-file fileInfo from the combined FormData.
|
|
437
446
|
const files = formData.getAll('files');
|
|
@@ -444,7 +453,8 @@ const uploadApi = strapiAdmin.adminApi.enhanceEndpoints({
|
|
|
444
453
|
caption: null,
|
|
445
454
|
alternativeText: null,
|
|
446
455
|
folder: null
|
|
447
|
-
}
|
|
456
|
+
},
|
|
457
|
+
onUploaded: onFileUploaded
|
|
448
458
|
}));
|
|
449
459
|
const fileNames = entries.map((entry)=>entry.fileInfo.name ?? entry.file.name);
|
|
450
460
|
const fileSizes = entries.map((entry)=>entry.file.size);
|