@strapi/upload 5.51.0 → 5.51.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/dist/admin/future/pages/Assets/AssetsPage.js +198 -129
  2. package/dist/admin/future/pages/Assets/AssetsPage.js.map +1 -1
  3. package/dist/admin/future/pages/Assets/AssetsPage.mjs +199 -130
  4. package/dist/admin/future/pages/Assets/AssetsPage.mjs.map +1 -1
  5. package/dist/admin/future/pages/Assets/components/AssetsGrid.js +158 -19
  6. package/dist/admin/future/pages/Assets/components/AssetsGrid.js.map +1 -1
  7. package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs +159 -20
  8. package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs.map +1 -1
  9. package/dist/admin/future/pages/Assets/components/AssetsTable.js +212 -37
  10. package/dist/admin/future/pages/Assets/components/AssetsTable.js.map +1 -1
  11. package/dist/admin/future/pages/Assets/components/AssetsTable.mjs +213 -38
  12. package/dist/admin/future/pages/Assets/components/AssetsTable.mjs.map +1 -1
  13. package/dist/admin/future/pages/Assets/components/BulkActionsBar.js +252 -0
  14. package/dist/admin/future/pages/Assets/components/BulkActionsBar.js.map +1 -0
  15. package/dist/admin/future/pages/Assets/components/BulkActionsBar.mjs +250 -0
  16. package/dist/admin/future/pages/Assets/components/BulkActionsBar.mjs.map +1 -0
  17. package/dist/admin/future/pages/Assets/components/BulkMoveDialog.js +209 -0
  18. package/dist/admin/future/pages/Assets/components/BulkMoveDialog.js.map +1 -0
  19. package/dist/admin/future/pages/Assets/components/BulkMoveDialog.mjs +207 -0
  20. package/dist/admin/future/pages/Assets/components/BulkMoveDialog.mjs.map +1 -0
  21. package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.js +111 -36
  22. package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.js.map +1 -1
  23. package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.mjs +113 -38
  24. package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.mjs.map +1 -1
  25. package/dist/admin/future/pages/Assets/components/Dnd/DragOverlayChip.js +120 -13
  26. package/dist/admin/future/pages/Assets/components/Dnd/DragOverlayChip.js.map +1 -1
  27. package/dist/admin/future/pages/Assets/components/Dnd/DragOverlayChip.mjs +120 -13
  28. package/dist/admin/future/pages/Assets/components/Dnd/DragOverlayChip.mjs.map +1 -1
  29. package/dist/admin/future/pages/Assets/components/Dnd/buildDragSet.js +71 -0
  30. package/dist/admin/future/pages/Assets/components/Dnd/buildDragSet.js.map +1 -0
  31. package/dist/admin/future/pages/Assets/components/Dnd/buildDragSet.mjs +69 -0
  32. package/dist/admin/future/pages/Assets/components/Dnd/buildDragSet.mjs.map +1 -0
  33. package/dist/admin/future/pages/Assets/components/Dnd/computeValidDropTargets.js +34 -0
  34. package/dist/admin/future/pages/Assets/components/Dnd/computeValidDropTargets.js.map +1 -0
  35. package/dist/admin/future/pages/Assets/components/Dnd/computeValidDropTargets.mjs +32 -0
  36. package/dist/admin/future/pages/Assets/components/Dnd/computeValidDropTargets.mjs.map +1 -0
  37. package/dist/admin/future/pages/Assets/components/Dnd/dndIds.js +15 -0
  38. package/dist/admin/future/pages/Assets/components/Dnd/dndIds.js.map +1 -1
  39. package/dist/admin/future/pages/Assets/components/Dnd/dndIds.mjs +13 -1
  40. package/dist/admin/future/pages/Assets/components/Dnd/dndIds.mjs.map +1 -1
  41. package/dist/admin/future/pages/Assets/components/Dnd/useAssetDnd.js +19 -25
  42. package/dist/admin/future/pages/Assets/components/Dnd/useAssetDnd.js.map +1 -1
  43. package/dist/admin/future/pages/Assets/components/Dnd/useAssetDnd.mjs +19 -25
  44. package/dist/admin/future/pages/Assets/components/Dnd/useAssetDnd.mjs.map +1 -1
  45. package/dist/admin/future/pages/Assets/components/Dnd/useFolderTreeDroppable.js +35 -0
  46. package/dist/admin/future/pages/Assets/components/Dnd/useFolderTreeDroppable.js.map +1 -0
  47. package/dist/admin/future/pages/Assets/components/Dnd/useFolderTreeDroppable.mjs +33 -0
  48. package/dist/admin/future/pages/Assets/components/Dnd/useFolderTreeDroppable.mjs.map +1 -0
  49. package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js +120 -22
  50. package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js.map +1 -1
  51. package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs +121 -23
  52. package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs.map +1 -1
  53. package/dist/admin/future/pages/Assets/components/FolderTree/useSpringLoadedExpand.js +22 -0
  54. package/dist/admin/future/pages/Assets/components/FolderTree/useSpringLoadedExpand.js.map +1 -0
  55. package/dist/admin/future/pages/Assets/components/FolderTree/useSpringLoadedExpand.mjs +19 -0
  56. package/dist/admin/future/pages/Assets/components/FolderTree/useSpringLoadedExpand.mjs.map +1 -0
  57. package/dist/admin/future/pages/Assets/components/SortMenu.js +165 -0
  58. package/dist/admin/future/pages/Assets/components/SortMenu.js.map +1 -0
  59. package/dist/admin/future/pages/Assets/components/SortMenu.mjs +163 -0
  60. package/dist/admin/future/pages/Assets/components/SortMenu.mjs.map +1 -0
  61. package/dist/admin/future/pages/Assets/hooks/useAssetSelection.js +59 -0
  62. package/dist/admin/future/pages/Assets/hooks/useAssetSelection.js.map +1 -0
  63. package/dist/admin/future/pages/Assets/hooks/useAssetSelection.mjs +55 -0
  64. package/dist/admin/future/pages/Assets/hooks/useAssetSelection.mjs.map +1 -0
  65. package/dist/admin/future/pages/Assets/hooks/useListSort.js +124 -0
  66. package/dist/admin/future/pages/Assets/hooks/useListSort.js.map +1 -0
  67. package/dist/admin/future/pages/Assets/hooks/useListSort.mjs +120 -0
  68. package/dist/admin/future/pages/Assets/hooks/useListSort.mjs.map +1 -0
  69. package/dist/admin/future/pages/Assets/utils/listQueryKey.js +29 -0
  70. package/dist/admin/future/pages/Assets/utils/listQueryKey.js.map +1 -0
  71. package/dist/admin/future/pages/Assets/utils/listQueryKey.mjs +27 -0
  72. package/dist/admin/future/pages/Assets/utils/listQueryKey.mjs.map +1 -0
  73. package/dist/admin/future/pages/Assets/utils/mergeMixedList.js +84 -0
  74. package/dist/admin/future/pages/Assets/utils/mergeMixedList.js.map +1 -0
  75. package/dist/admin/future/pages/Assets/utils/mergeMixedList.mjs +81 -0
  76. package/dist/admin/future/pages/Assets/utils/mergeMixedList.mjs.map +1 -0
  77. package/dist/admin/future/pages/Assets/utils/selection.js +104 -0
  78. package/dist/admin/future/pages/Assets/utils/selection.js.map +1 -0
  79. package/dist/admin/future/pages/Assets/utils/selection.mjs +94 -0
  80. package/dist/admin/future/pages/Assets/utils/selection.mjs.map +1 -0
  81. package/dist/admin/future/services/assets.js +33 -1
  82. package/dist/admin/future/services/assets.js.map +1 -1
  83. package/dist/admin/future/services/assets.mjs +33 -2
  84. package/dist/admin/future/services/assets.mjs.map +1 -1
  85. package/dist/admin/future/services/folders.js +3 -3
  86. package/dist/admin/future/services/folders.js.map +1 -1
  87. package/dist/admin/future/services/folders.mjs +3 -3
  88. package/dist/admin/future/services/folders.mjs.map +1 -1
  89. package/dist/admin/future/utils/buildDragSetFromSelection.js +33 -0
  90. package/dist/admin/future/utils/buildDragSetFromSelection.js.map +1 -0
  91. package/dist/admin/future/utils/buildDragSetFromSelection.mjs +31 -0
  92. package/dist/admin/future/utils/buildDragSetFromSelection.mjs.map +1 -0
  93. package/dist/admin/future/utils/canDropItemOnFolder.js +4 -0
  94. package/dist/admin/future/utils/canDropItemOnFolder.js.map +1 -1
  95. package/dist/admin/future/utils/canDropItemOnFolder.mjs +4 -0
  96. package/dist/admin/future/utils/canDropItemOnFolder.mjs.map +1 -1
  97. package/dist/admin/future/utils/flattenFolderStructure.js +28 -0
  98. package/dist/admin/future/utils/flattenFolderStructure.js.map +1 -0
  99. package/dist/admin/future/utils/flattenFolderStructure.mjs +26 -0
  100. package/dist/admin/future/utils/flattenFolderStructure.mjs.map +1 -0
  101. package/dist/admin/future/utils/formatMoveSuccessMessage.js +19 -0
  102. package/dist/admin/future/utils/formatMoveSuccessMessage.js.map +1 -0
  103. package/dist/admin/future/utils/formatMoveSuccessMessage.mjs +17 -0
  104. package/dist/admin/future/utils/formatMoveSuccessMessage.mjs.map +1 -0
  105. package/dist/admin/future/utils/getFolderLabel.js +31 -0
  106. package/dist/admin/future/utils/getFolderLabel.js.map +1 -0
  107. package/dist/admin/future/utils/getFolderLabel.mjs +29 -0
  108. package/dist/admin/future/utils/getFolderLabel.mjs.map +1 -0
  109. package/dist/admin/src/future/pages/Assets/components/AssetsTable.d.ts +7 -1
  110. package/dist/admin/src/future/pages/Assets/components/BulkActionsBar.d.ts +1 -0
  111. package/dist/admin/src/future/pages/Assets/components/BulkMoveDialog.d.ts +13 -0
  112. package/dist/admin/src/future/pages/Assets/components/Dnd/AssetsDndProvider.d.ts +2 -0
  113. package/dist/admin/src/future/pages/Assets/components/Dnd/DragOverlayChip.d.ts +2 -2
  114. package/dist/admin/src/future/pages/Assets/components/Dnd/buildDragSet.d.ts +17 -0
  115. package/dist/admin/src/future/pages/Assets/components/Dnd/computeValidDropTargets.d.ts +7 -0
  116. package/dist/admin/src/future/pages/Assets/components/Dnd/dndIds.d.ts +3 -0
  117. package/dist/admin/src/future/pages/Assets/components/Dnd/useAssetDnd.d.ts +3 -1
  118. package/dist/admin/src/future/pages/Assets/components/Dnd/useFolderTreeDroppable.d.ts +19 -0
  119. package/dist/admin/src/future/pages/Assets/components/FolderTree/useSpringLoadedExpand.d.ts +6 -0
  120. package/dist/admin/src/future/pages/Assets/components/SortMenu.d.ts +17 -0
  121. package/dist/admin/src/future/pages/Assets/hooks/useAssetSelection.d.ts +39 -0
  122. package/dist/admin/src/future/pages/Assets/hooks/useListSort.d.ts +47 -0
  123. package/dist/admin/src/future/pages/Assets/utils/listQueryKey.d.ts +30 -0
  124. package/dist/admin/src/future/pages/Assets/utils/mergeMixedList.d.ts +40 -0
  125. package/dist/admin/src/future/pages/Assets/utils/selection.d.ts +50 -0
  126. package/dist/admin/src/future/services/assets.d.ts +4 -1
  127. package/dist/admin/src/future/services/folders.d.ts +4 -1
  128. package/dist/admin/src/future/types/dnd.d.ts +5 -0
  129. package/dist/admin/src/future/utils/buildDragSetFromSelection.d.ts +11 -0
  130. package/dist/admin/src/future/utils/canDropItemOnFolder.d.ts +1 -1
  131. package/dist/admin/src/future/utils/flattenFolderStructure.d.ts +18 -0
  132. package/dist/admin/src/future/utils/formatMoveSuccessMessage.d.ts +14 -0
  133. package/dist/admin/src/future/utils/getFolderLabel.d.ts +11 -0
  134. package/dist/admin/translations/en.json.js +33 -0
  135. package/dist/admin/translations/en.json.js.map +1 -1
  136. package/dist/admin/translations/en.json.mjs +33 -0
  137. package/dist/admin/translations/en.json.mjs.map +1 -1
  138. package/dist/shared/contracts/folders.d.ts +1 -1
  139. package/package.json +7 -7
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getFolderLabel.mjs","sources":["../../../../admin/src/future/utils/getFolderLabel.ts"],"sourcesContent":["import type { FolderNode } from '../../../../shared/contracts/folders';\n\n/**\n * Leaf display name for a folder id. `null` (root) → the Media Library label.\n * Used by both the DnD success toast and the dialog success toast so the two\n * paths name folders identically. Ancestry paths belong only in the dialog's\n * select options (see `flattenFolderStructure`).\n *\n * `id === null` returns `rootLabel`; an unknown id falls back to `rootLabel`\n * too (defensive — mirrors the dialog's previous `?? rootLabel`).\n */\nexport const getFolderLabel = (\n folderStructure: FolderNode[],\n id: number | null,\n rootLabel: string\n): string => {\n if (id === null) {\n return rootLabel;\n }\n\n const findNode = (nodes: FolderNode[]): FolderNode | null => {\n for (const node of nodes) {\n if (node.id === id) {\n return node;\n }\n\n const found = findNode(node.children ?? []);\n if (found) {\n return found;\n }\n }\n\n return null;\n };\n\n return findNode(folderStructure)?.name ?? rootLabel;\n};\n"],"names":["getFolderLabel","folderStructure","id","rootLabel","findNode","nodes","node","found","children","name"],"mappings":"AAEA;;;;;;;;AAQC,IACM,MAAMA,cAAAA,GAAiB,CAC5BC,iBACAC,EAAAA,EACAC,SAAAA,GAAAA;AAEA,IAAA,IAAID,OAAO,IAAA,EAAM;QACf,OAAOC,SAAAA;AACT,IAAA;AAEA,IAAA,MAAMC,WAAW,CAACC,KAAAA,GAAAA;QAChB,KAAK,MAAMC,QAAQD,KAAAA,CAAO;YACxB,IAAIC,IAAAA,CAAKJ,EAAE,KAAKA,EAAAA,EAAI;gBAClB,OAAOI,IAAAA;AACT,YAAA;AAEA,YAAA,MAAMC,KAAAA,GAAQH,QAAAA,CAASE,IAAAA,CAAKE,QAAQ,IAAI,EAAE,CAAA;AAC1C,YAAA,IAAID,KAAAA,EAAO;gBACT,OAAOA,KAAAA;AACT,YAAA;AACF,QAAA;QAEA,OAAO,IAAA;AACT,IAAA,CAAA;IAEA,OAAOH,QAAAA,CAASH,kBAAkBQ,IAAAA,IAAQN,SAAAA;AAC5C;;;;"}
@@ -1,9 +1,15 @@
1
+ import { type MixedItem } from '../utils/mergeMixedList';
1
2
  import type { File } from '../../../../../../shared/contracts/files';
2
3
  import type { Folder } from '../../../../../../shared/contracts/folders';
3
4
  interface AssetsTableProps {
4
5
  assets: File[];
5
6
  folders?: Folder[];
7
+ /**
8
+ * When set ("Folders: Mixed with files"), rows render in this interleaved
9
+ * order instead of folders-first. Range selection follows the same order.
10
+ */
11
+ mixedItems?: MixedItem[] | null;
6
12
  onAssetItemClick: (assetId: number) => void;
7
13
  }
8
- export declare const AssetsTable: ({ assets, folders, onAssetItemClick }: AssetsTableProps) => import("react/jsx-runtime").JSX.Element | null;
14
+ export declare const AssetsTable: ({ assets, folders, mixedItems, onAssetItemClick, }: AssetsTableProps) => import("react/jsx-runtime").JSX.Element | null;
9
15
  export {};
@@ -0,0 +1 @@
1
+ export declare const BulkActionsBar: () => import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,13 @@
1
+ interface BulkMoveDialogProps {
2
+ open: boolean;
3
+ onClose: () => void;
4
+ }
5
+ /**
6
+ * "Move elements to" modal for the bulk actions bar. Moves the current
7
+ * selection (assets and/or folders) into the picked destination folder via
8
+ * `POST /upload/actions/bulk-move`. The mutation invalidates the asset list,
9
+ * folder list and the sidebar folder-structure, so both panes refresh on
10
+ * success. On failure the modal stays open so the user can retry or cancel.
11
+ */
12
+ export declare const BulkMoveDialog: ({ open, onClose }: BulkMoveDialogProps) => import("react/jsx-runtime").JSX.Element;
13
+ export {};
@@ -2,6 +2,8 @@ import { type ReactNode } from 'react';
2
2
  interface AssetsDndContextValue {
3
3
  isInternalDragActive: boolean;
4
4
  isMovePending: boolean;
5
+ /** O(1) lookup of whether the current drag set may drop on this destination. */
6
+ isValidDropTarget: (targetFolderId: number | null) => boolean;
5
7
  }
6
8
  export declare const useAssetsDnd: () => AssetsDndContextValue;
7
9
  export declare const useAssetsDndOptional: () => AssetsDndContextValue | null;
@@ -1,6 +1,6 @@
1
1
  import type { DragItemData } from '../../../../types/dnd';
2
2
  interface DragOverlayChipProps {
3
- item: DragItemData;
3
+ items: DragItemData[];
4
4
  }
5
- export declare const DragOverlayChip: ({ item }: DragOverlayChipProps) => import("react/jsx-runtime").JSX.Element;
5
+ export declare const DragOverlayChip: ({ items }: DragOverlayChipProps) => import("react/jsx-runtime").JSX.Element | null;
6
6
  export {};
@@ -0,0 +1,17 @@
1
+ import { type ItemKey } from '../../utils/selection';
2
+ import type { DragItemData } from '../../../../types/dnd';
3
+ export interface DragSet {
4
+ items: DragItemData[];
5
+ /** True when the active item was already selected — membership is the full selection. */
6
+ fromSelection: boolean;
7
+ }
8
+ /**
9
+ * Derive the drag payload once at drag start.
10
+ *
11
+ * - Dragging a selected item moves the complete current selection.
12
+ * - Dragging an unselected item moves only that item.
13
+ *
14
+ * Selection is page-scoped to the current folder, so every item is stamped with
15
+ * `currentFolderId` as its location for move validation.
16
+ */
17
+ export declare const buildDragSet: (activeData: DragItemData, selectedKeys: Set<ItemKey> | undefined, currentFolderId: number | null) => DragSet;
@@ -0,0 +1,7 @@
1
+ import type { FolderNode } from '../../../../../../../shared/contracts/folders';
2
+ import type { DragItemData } from '../../../../types/dnd';
3
+ /**
4
+ * Evaluate destination validity once for the full drag set. Callers look up
5
+ * targets in O(1) via {@link Set.has} — `null` represents the Home/root drop.
6
+ */
7
+ export declare const computeValidDropTargets: (items: DragItemData[], folderStructure: FolderNode[]) => Set<number | null>;
@@ -2,3 +2,6 @@ export declare const toFileDraggableId: (id: number) => `file:${number}`;
2
2
  export declare const toFolderDraggableId: (id: number) => `folder:${number}`;
3
3
  export declare const toFolderTargetId: (id: number) => `folder-target:${number}`;
4
4
  export declare const parseFolderTargetId: (dndId: string | number) => number | null;
5
+ export declare const toFolderTreeTargetId: (id: number) => `folder-tree-target:${number}`;
6
+ export declare const HOME_TREE_TARGET_ID: "folder-tree-target:home";
7
+ export declare const parseFolderTreeTargetId: (dndId: string | number) => number | "root" | null;
@@ -2,7 +2,9 @@ import type { DragFolderData } from '../../../../types/dnd';
2
2
  export declare const useFileDraggable: (asset: {
3
3
  id: number;
4
4
  name: string;
5
- folder?: number | string | null;
5
+ folder?: number | string | {
6
+ id?: number;
7
+ } | null;
6
8
  }) => {
7
9
  active: import("@dnd-kit/core").Active | null;
8
10
  activatorEvent: Event | null;
@@ -0,0 +1,19 @@
1
+ export declare const useFolderTreeDroppable: (target: {
2
+ id: number;
3
+ name: string;
4
+ } | {
5
+ id: null;
6
+ name: string;
7
+ }) => {
8
+ droppable: {
9
+ active: import("@dnd-kit/core").Active | null;
10
+ rect: import("react").MutableRefObject<import("@dnd-kit/core").ClientRect | null>;
11
+ isOver: boolean;
12
+ node: import("react").MutableRefObject<HTMLElement | null>;
13
+ over: import("@dnd-kit/core").Over | null;
14
+ setNodeRef: (element: HTMLElement | null) => void;
15
+ };
16
+ isOver: boolean;
17
+ showValidDropHighlight: boolean;
18
+ showInvalidDropCursor: boolean;
19
+ };
@@ -0,0 +1,6 @@
1
+ export declare const SPRING_LOAD_DELAY_MS = 600;
2
+ export declare const useSpringLoadedExpand: ({ isOver, canExpand, onExpand, }: {
3
+ isOver: boolean;
4
+ canExpand: boolean;
5
+ onExpand: () => void;
6
+ }) => void;
@@ -0,0 +1,17 @@
1
+ import { type ListSort } from '../hooks/useListSort';
2
+ interface SortMenuProps {
3
+ sort: ListSort;
4
+ /**
5
+ * The grid view forces folders on top (mixing folder cards with asset cards
6
+ * is not supported there), so it hides the Folders group entirely.
7
+ */
8
+ showFoldersGroup?: boolean;
9
+ }
10
+ /**
11
+ * Toolbar "Sort" dropdown: single-select sections (Sort / Folders). Picking an
12
+ * option keeps the menu open (`onSelect` preventDefault) so several facets can
13
+ * be tuned in one visit; clicking a checked facet clears it (the hook
14
+ * guarantees at least one sort rule stays active).
15
+ */
16
+ export declare const SortMenu: ({ sort, showFoldersGroup }: SortMenuProps) => import("react/jsx-runtime").JSX.Element;
17
+ export {};
@@ -0,0 +1,39 @@
1
+ import { type ReactNode } from 'react';
2
+ import { type ItemKey } from '../utils/selection';
3
+ /**
4
+ * Ephemeral, view-state-only multi-select for the future Media Library. Selection
5
+ * is page-scoped and reset on folder navigation or sort/filter changes (the
6
+ * table/grid toggle keeps it — same list, different presentation).
7
+ *
8
+ * The actual computation lives in `../utils/selection.ts` (pure + unit-tested);
9
+ * this hook is a thin React wrapper. Assets and folders share one mechanism —
10
+ * items are tracked as namespaced keys (`asset:1` / `folder:1`) so toggle, range
11
+ * and select-all behave the same for both. Range / select-all receive the
12
+ * ordered key array from the caller (the view owns the rendered order), keeping
13
+ * the context data-source-agnostic.
14
+ */
15
+ export interface AssetSelection {
16
+ /** Every selected item key (assets and folders), render-order agnostic. */
17
+ selectedKeys: Set<ItemKey>;
18
+ /** Selected asset ids, derived from {@link selectedKeys}. */
19
+ selectedIds: Set<number>;
20
+ /** Selected folder ids, derived from {@link selectedKeys}. */
21
+ selectedFolderIds: Set<number>;
22
+ anchorKey: ItemKey | null;
23
+ isSelected: (key: ItemKey) => boolean;
24
+ /** Additive toggle (Cmd/Ctrl+click, item checkbox). */
25
+ toggle: (key: ItemKey) => void;
26
+ /** Shift+click — selects the contiguous range from the anchor to the target. */
27
+ selectRange: (orderedKeys: ItemKey[], targetKey: ItemKey) => void;
28
+ /** Header checkbox — selects every rendered item (folders and assets). */
29
+ selectAll: (orderedKeys: ItemKey[]) => void;
30
+ /** Close button / folder navigation / list-identity changes. */
31
+ clear: () => void;
32
+ }
33
+ interface AssetSelectionProviderProps {
34
+ children: ReactNode;
35
+ }
36
+ export declare const AssetSelectionProvider: ({ children }: AssetSelectionProviderProps) => import("react").FunctionComponentElement<import("react").ProviderProps<AssetSelection | null>>;
37
+ export declare const useAssetSelection: () => AssetSelection;
38
+ export declare const useAssetSelectionOptional: () => AssetSelection | null;
39
+ export {};
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Sort state for the assets list, backed by URL query params so the current
3
+ * ordering is shareable and survives Back/refresh:
4
+ *
5
+ * - `?sort=<rule>` — a single whitelisted rule. Omitted → default (most
6
+ * recent updates).
7
+ * - `?folders=mixed` — folders interleaved with files. Omitted → folders on top.
8
+ *
9
+ * The date rules and the direction rules are mutually exclusive: exactly one
10
+ * rule is active at a time (one checkmark total, like the design mock). Picking
11
+ * an option in one group clears the other; clearing the active option falls
12
+ * back to the default — an unsorted list is not a state the UI offers.
13
+ */
14
+ export declare const SORT_BY_RULES: {
15
+ readonly oldestUploads: "createdAt:ASC";
16
+ readonly mostRecentUpdates: "updatedAt:DESC";
17
+ };
18
+ export declare const SORT_DIRECTION_RULES: {
19
+ readonly nameAsc: "name:ASC";
20
+ readonly nameDesc: "name:DESC";
21
+ readonly sizeAsc: "size:ASC";
22
+ readonly sizeDesc: "size:DESC";
23
+ };
24
+ export type SortByKey = keyof typeof SORT_BY_RULES;
25
+ export type SortDirectionKey = keyof typeof SORT_DIRECTION_RULES;
26
+ export type FoldersPosition = 'top' | 'mixed';
27
+ export interface ListSort {
28
+ sortBy: SortByKey | null;
29
+ direction: SortDirectionKey | null;
30
+ foldersPosition: FoldersPosition;
31
+ /**
32
+ * The active rule for the files query, e.g. `updatedAt:DESC` — always a
33
+ * single rule since the sort groups are mutually exclusive.
34
+ */
35
+ assetsSort: string;
36
+ /**
37
+ * Rule applicable to the folders query. In the default state (no sort in the
38
+ * URL) folders keep their alphabetical order so the band matches the sidebar
39
+ * tree; an explicit user sort applies, except size rules (folders have no
40
+ * `size` column), which fall back to alphabetical.
41
+ */
42
+ foldersSort: string;
43
+ setSortBy: (key: SortByKey | null) => void;
44
+ setDirection: (key: SortDirectionKey | null) => void;
45
+ setFoldersPosition: (position: FoldersPosition) => void;
46
+ }
47
+ export declare const useListSort: () => ListSort;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Fingerprint for "which asset list the user is looking at".
3
+ *
4
+ * Selection clears when this key changes (see ClearSelectionOnChange in AssetsPage).
5
+ *
6
+ * Hybrid rule
7
+ * - Folder, search, sort, filter changes → new key → selection clears.
8
+ * - Switching table/grid view does NOT change the key — both views render the
9
+ * same list, so the selection survives the toggle.
10
+ * - Infinite scroll (load more) does NOT change any segment → selection persists.
11
+ *
12
+ * Search/filter use stable defaults until their header controls are wired;
13
+ * follow-up PRs only pass real values — no selection logic changes needed.
14
+ */
15
+ export interface ListQueryKeyInput {
16
+ folderId: number | null;
17
+ /** Empty string until search UI ships. */
18
+ search: string;
19
+ /** Null until sort UI ships. */
20
+ sort: string | null;
21
+ /** Null until filter UI ships. */
22
+ filter: string | null;
23
+ }
24
+ /**
25
+ * Builds a stable fingerprint for the current asset list query.
26
+ *
27
+ * Selection clears when this key changes. Infinite scroll does not change any
28
+ * segment, so selection persists across load-more.
29
+ */
30
+ export declare const getListQueryKey: ({ folderId, search, sort, filter }: ListQueryKeyInput) => string;
@@ -0,0 +1,40 @@
1
+ import type { File } from '../../../../../../shared/contracts/files';
2
+ import type { Folder } from '../../../../../../shared/contracts/folders';
3
+ export type MixedItem = {
4
+ kind: 'folder';
5
+ folder: Folder;
6
+ } | {
7
+ kind: 'asset';
8
+ asset: File;
9
+ };
10
+ type SortableRecord = {
11
+ name?: string | null;
12
+ createdAt?: string | null;
13
+ updatedAt?: string | null;
14
+ size?: number | null;
15
+ };
16
+ /**
17
+ * Builds a comparator from comma-separated sort rules (`updatedAt:DESC,name:ASC`).
18
+ * Rules apply in order; the first non-equal field decides. Client-side
19
+ * approximation of the server ordering — good enough to slot folders between
20
+ * files that were sorted server-side by the same rules.
21
+ */
22
+ export declare const buildComparator: (sort: string) => (a: SortableRecord, b: SortableRecord) => number;
23
+ interface MergeMixedListParams {
24
+ folders: Folder[];
25
+ assets: File[];
26
+ /** Combined sort rules used for the assets query. */
27
+ sort: string;
28
+ /**
29
+ * More asset pages exist. A folder may only be placed once we know no
30
+ * not-yet-loaded asset sorts before it — i.e. it compares ≤ the last loaded
31
+ * asset. Later pages release the remaining folders progressively.
32
+ */
33
+ hasNextPage: boolean;
34
+ }
35
+ /**
36
+ * Interleaves the complete folder list into the (possibly partially loaded)
37
+ * asset stream according to the active sort. Ties order folders first.
38
+ */
39
+ export declare const mergeMixedList: ({ folders, assets, sort, hasNextPage, }: MergeMixedListParams) => MixedItem[];
40
+ export {};
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Pure, view-agnostic selection logic for the future Media Library multi-select.
3
+ *
4
+ * Selection covers both assets and folders. Since their numeric ids live in
5
+ * different tables (and can collide), items are tracked as namespaced keys
6
+ * (`asset:1` / `folder:1`). Views build their rendered order as a key array so
7
+ * range / select-all work across the folder and asset sections seamlessly.
8
+ */
9
+ export type SelectableKind = 'asset' | 'folder';
10
+ export type ItemKey = `${SelectableKind}:${number}`;
11
+ export declare const assetKey: (id: number) => ItemKey;
12
+ export declare const folderKey: (id: number) => ItemKey;
13
+ /** Extracts the numeric ids of one kind from a set of item keys. */
14
+ export declare const getIdsOfKind: (keys: Set<ItemKey>, kind: SelectableKind) => Set<number>;
15
+ export interface SelectionState {
16
+ /** Currently selected item keys (assets and folders). */
17
+ selectedKeys: Set<ItemKey>;
18
+ /** Anchor used as the start of a Shift+click range. */
19
+ anchorKey: ItemKey | null;
20
+ }
21
+ export declare const createEmptySelection: () => SelectionState;
22
+ /**
23
+ * Additive toggle — adds the key if absent, removes it otherwise, without
24
+ * touching the rest of the selection. Used by the item checkbox and Cmd/Ctrl+click.
25
+ * The toggled key becomes the new anchor.
26
+ */
27
+ export declare const toggleSelection: (state: SelectionState, key: ItemKey) => SelectionState;
28
+ /**
29
+ * Shift+click — selects the contiguous range between the current anchor and the
30
+ * target in render order, replacing the current selection. The anchor stays put.
31
+ *
32
+ * Falls back to a single selection when there is no usable anchor (e.g. first
33
+ * click was a Shift+click, or the anchor is no longer in the list).
34
+ */
35
+ export declare const selectRange: (state: SelectionState, orderedKeys: ItemKey[], targetKey: ItemKey) => SelectionState;
36
+ /**
37
+ * Select-all — selects every key in the provided ordered array. Used by the header
38
+ * checkbox when not everything is already selected.
39
+ */
40
+ export declare const selectAll: (orderedKeys: ItemKey[]) => SelectionState;
41
+ export declare const clearSelection: () => SelectionState;
42
+ export interface SelectAllState {
43
+ allSelected: boolean;
44
+ isIndeterminate: boolean;
45
+ }
46
+ /**
47
+ * Derives the header checkbox state: everything selected, some (indeterminate),
48
+ * or none. Only considers the currently-rendered items (orderedKeys).
49
+ */
50
+ export declare const getSelectAllState: (selectedKeys: Set<ItemKey>, orderedKeys: ItemKey[]) => SelectAllState;
@@ -18,5 +18,8 @@ interface ReplaceAssetArgs {
18
18
  file: globalThis.File;
19
19
  fileInfo?: Partial<UploadFileInfo>;
20
20
  }
21
- export declare const useGetAssetsQuery: import("@reduxjs/toolkit/dist/query/react/buildHooks").UseQuery<import("@reduxjs/toolkit/query").QueryDefinition<void | GetAssetsParams, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError | import("@reduxjs/toolkit").SerializedError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AiUsage" | "AiFeatureConfig" | "Asset" | "Folder", GetAssetsResponse, "adminApi">>, useGetAssetQuery: import("@reduxjs/toolkit/dist/query/react/buildHooks").UseQuery<import("@reduxjs/toolkit/query").QueryDefinition<number, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError | import("@reduxjs/toolkit").SerializedError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AiUsage" | "AiFeatureConfig" | "Asset" | "Folder", AssetWithPopulatedCreatedBy, "adminApi">>, useUpdateAssetMutation: import("@reduxjs/toolkit/dist/query/react/buildHooks").UseMutation<import("@reduxjs/toolkit/query").MutationDefinition<UpdateAssetArgs, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError | import("@reduxjs/toolkit").SerializedError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AiUsage" | "AiFeatureConfig" | "Asset" | "Folder", AssetWithPopulatedCreatedBy, "adminApi">>, useReplaceAssetMutation: import("@reduxjs/toolkit/dist/query/react/buildHooks").UseMutation<import("@reduxjs/toolkit/query").MutationDefinition<ReplaceAssetArgs, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError | import("@reduxjs/toolkit").SerializedError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AiUsage" | "AiFeatureConfig" | "Asset" | "Folder", AssetWithPopulatedCreatedBy, "adminApi">>, useDeleteAssetMutation: import("@reduxjs/toolkit/dist/query/react/buildHooks").UseMutation<import("@reduxjs/toolkit/query").MutationDefinition<number, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError | import("@reduxjs/toolkit").SerializedError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AiUsage" | "AiFeatureConfig" | "Asset" | "Folder", unknown, "adminApi">>;
21
+ export declare const useGetAssetsQuery: import("@reduxjs/toolkit/dist/query/react/buildHooks").UseQuery<import("@reduxjs/toolkit/query").QueryDefinition<void | GetAssetsParams, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError | import("@reduxjs/toolkit").SerializedError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AiUsage" | "AiFeatureConfig" | "Asset" | "Folder", GetAssetsResponse, "adminApi">>, useGetAssetQuery: import("@reduxjs/toolkit/dist/query/react/buildHooks").UseQuery<import("@reduxjs/toolkit/query").QueryDefinition<number, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError | import("@reduxjs/toolkit").SerializedError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AiUsage" | "AiFeatureConfig" | "Asset" | "Folder", AssetWithPopulatedCreatedBy, "adminApi">>, useUpdateAssetMutation: import("@reduxjs/toolkit/dist/query/react/buildHooks").UseMutation<import("@reduxjs/toolkit/query").MutationDefinition<UpdateAssetArgs, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError | import("@reduxjs/toolkit").SerializedError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AiUsage" | "AiFeatureConfig" | "Asset" | "Folder", AssetWithPopulatedCreatedBy, "adminApi">>, useReplaceAssetMutation: import("@reduxjs/toolkit/dist/query/react/buildHooks").UseMutation<import("@reduxjs/toolkit/query").MutationDefinition<ReplaceAssetArgs, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError | import("@reduxjs/toolkit").SerializedError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AiUsage" | "AiFeatureConfig" | "Asset" | "Folder", AssetWithPopulatedCreatedBy, "adminApi">>, useDeleteAssetMutation: import("@reduxjs/toolkit/dist/query/react/buildHooks").UseMutation<import("@reduxjs/toolkit/query").MutationDefinition<number, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError | import("@reduxjs/toolkit").SerializedError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AiUsage" | "AiFeatureConfig" | "Asset" | "Folder", unknown, "adminApi">>, useBulkDeleteItemsMutation: import("@reduxjs/toolkit/dist/query/react/buildHooks").UseMutation<import("@reduxjs/toolkit/query").MutationDefinition<{
22
+ fileIds: number[];
23
+ folderIds: number[];
24
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError | import("@reduxjs/toolkit").SerializedError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AiUsage" | "AiFeatureConfig" | "Asset" | "Folder", unknown, "adminApi">>;
22
25
  export {};
@@ -9,11 +9,14 @@ export type FolderWithCounts = Omit<Folder, 'children' | 'files'> & {
9
9
  };
10
10
  interface GetFoldersParams {
11
11
  parentId?: number | null;
12
+ /** Comma-separated rules, e.g. `updatedAt:DESC,name:ASC`. Defaults to alphabetical. */
13
+ sort?: string;
12
14
  }
13
15
  interface BulkMoveParams {
14
16
  fileIds?: number[];
15
17
  folderIds?: number[];
16
- destinationFolderId: number;
18
+ /** `null` moves the items to the root of the Media Library. */
19
+ destinationFolderId: number | null;
17
20
  }
18
21
  export declare const useCreateFolderMutation: import("@reduxjs/toolkit/dist/query/react/buildHooks").UseMutation<import("@reduxjs/toolkit/query").MutationDefinition<Pick<Folder, "name" | "parent">, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError | import("@reduxjs/toolkit").SerializedError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AiUsage" | "AiFeatureConfig" | "Asset" | "Folder", Folder, "adminApi">>, useGetFoldersQuery: import("@reduxjs/toolkit/dist/query/react/buildHooks").UseQuery<import("@reduxjs/toolkit/query").QueryDefinition<void | GetFoldersParams, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@strapi/admin/strapi-admin").QueryArguments, unknown, import("@strapi/admin/strapi-admin").BaseQueryError | import("@reduxjs/toolkit").SerializedError, {}, {}>, "GuidedTourMeta" | "HomepageKeyStatistics" | "AiUsage" | "AiFeatureConfig" | "Asset" | "Folder", Folder[], "adminApi">>, useGetFolderQuery: import("@reduxjs/toolkit/dist/query/react/buildHooks").UseQuery<import("@reduxjs/toolkit/query").QueryDefinition<{
19
22
  id: number;
@@ -16,6 +16,11 @@ export interface FolderTargetData {
16
16
  id: number;
17
17
  name: string;
18
18
  }
19
+ export interface FolderTreeTargetData {
20
+ kind: 'folder-tree-target';
21
+ id: number | null;
22
+ name: string;
23
+ }
19
24
  export interface BulkMovePayload {
20
25
  fileIds: number[];
21
26
  folderIds: number[];
@@ -0,0 +1,11 @@
1
+ import type { DragItemData } from '../types/dnd';
2
+ /**
3
+ * Reconstruct the drag set from a bulk-actions selection so the dialog can feed
4
+ * the exact same `DragItemData[]` into `computeValidDropTargets` / the canonical
5
+ * `canDropItemOnFolder` predicate that pointer drag uses.
6
+ *
7
+ * Selection is page-scoped to the current folder, so every selected item shares
8
+ * `currentFolderId` as its location (files → `folderId`, folders → `parentId`).
9
+ * Names are irrelevant to drop validation, so they are left empty.
10
+ */
11
+ export declare const buildDragSetFromSelection: (selectedIds: ReadonlySet<number>, selectedFolderIds: ReadonlySet<number>, currentFolderId: number | null) => DragItemData[];
@@ -2,7 +2,7 @@ import type { FolderNode } from '../../../../shared/contracts/folders';
2
2
  import type { DragItemData } from '../types/dnd';
3
3
  export interface CanDropItemOnFolderParams {
4
4
  items: DragItemData[];
5
- targetFolderId: number;
5
+ targetFolderId: number | null;
6
6
  folderStructure: FolderNode[];
7
7
  }
8
8
  export declare const isFolderDescendantOf: (folderStructure: FolderNode[], ancestorId: number, candidateId: number) => boolean;
@@ -0,0 +1,18 @@
1
+ import type { FolderNode } from '../../../../shared/contracts/folders';
2
+ export interface FlatFolderOption {
3
+ id: number;
4
+ /** Full ancestry label, e.g. "About / Images". */
5
+ label: string;
6
+ }
7
+ /**
8
+ * Flattens the nested folder structure (`/upload/folder-structure`) into a
9
+ * depth-first list of `{ id, label }` options where the label carries the full
10
+ * ancestry path. Used by destination selects so folders sharing a name stay
11
+ * distinguishable ("About / Images" vs "Tech / Images"), with children listed
12
+ * right under their parent.
13
+ *
14
+ * `excludeSubtreeIds` prunes a folder *and everything below it* in the same
15
+ * single pass — used to drop the selected folders (and their descendants) from
16
+ * bulk-move destinations without re-walking the tree per option.
17
+ */
18
+ export declare const flattenFolderStructure: (nodes: FolderNode[], excludeSubtreeIds?: ReadonlySet<number>, parentLabel?: string) => FlatFolderOption[];
@@ -0,0 +1,14 @@
1
+ import type { IntlShape } from 'react-intl';
2
+ interface FormatMoveSuccessArgs {
3
+ formatMessage: IntlShape['formatMessage'];
4
+ count: number;
5
+ source: string;
6
+ destination: string;
7
+ }
8
+ /**
9
+ * Single source of truth for the bulk-move success wording. Both the DnD drop
10
+ * and the BulkMoveDialog format the toast (and DnD live-region announcement)
11
+ * through here so the two paths stay identical for the same move.
12
+ */
13
+ export declare const formatMoveSuccessMessage: ({ formatMessage, count, source, destination, }: FormatMoveSuccessArgs) => string;
14
+ export {};
@@ -0,0 +1,11 @@
1
+ import type { FolderNode } from '../../../../shared/contracts/folders';
2
+ /**
3
+ * Leaf display name for a folder id. `null` (root) → the Media Library label.
4
+ * Used by both the DnD success toast and the dialog success toast so the two
5
+ * paths name folders identically. Ancestry paths belong only in the dialog's
6
+ * select options (see `flattenFolderStructure`).
7
+ *
8
+ * `id === null` returns `rootLabel`; an unknown id falls back to `rootLabel`
9
+ * too (defensive — mirrors the dialog's previous `?? rootLabel`).
10
+ */
11
+ export declare const getFolderLabel: (folderStructure: FolderNode[], id: number | null, rootLabel: string) => string;
@@ -162,6 +162,18 @@ var en = {
162
162
  "list.empty.title": "No assets yet",
163
163
  "list.empty.description": "Get started by uploading assets or creating a folder.",
164
164
  "list.empty.add-assets": "Add assets",
165
+ "list.sort.trigger": "Sort: {active}",
166
+ "list.sort.section": "Sort",
167
+ "list.sort.oldest-uploads": "Oldest uploads",
168
+ "list.sort.most-recent-updates": "Most recent updates",
169
+ "list.sort.name-asc": "A to Z",
170
+ "list.sort.name-desc": "Z to A",
171
+ "list.sort.size-asc": "File size ascending",
172
+ "list.sort.size-desc": "File size descending",
173
+ "list.sort.folders": "Folders",
174
+ "list.sort.folders-on-top": "On top",
175
+ "list.sort.folders-mixed": "Mixed with files",
176
+ "list.sort.active": "(active)",
165
177
  "list.assets.loading-more": "Loading more assets...",
166
178
  "list.assets.loading-asset": "Loading the preview for the media: {path}",
167
179
  "list.assets.not-supported-content": "No preview available",
@@ -203,6 +215,8 @@ var en = {
203
215
  "dnd.announce.invalid-drop": "Cannot move item to this folder.",
204
216
  "dnd.announce.move-failure": "Move failed. {message}",
205
217
  "dnd.announce.cancel": "Drag cancelled.",
218
+ "dnd.overlay.folders": "{count, plural, one {# folder} other {# folders}}",
219
+ "dnd.overlay.files": "{count, plural, one {# file} other {# files}}",
206
220
  "modal.selected-list.sub-header-subtitle": "Drag & drop to reorder the assets in the field",
207
221
  "modal.upload-list.footer.button": "Upload {number, plural, one {# asset} other {# assets}} to the library",
208
222
  "modal.upload-list.sub-header-subtitle": "Manage the assets before adding them to the Media Library",
@@ -258,7 +272,26 @@ var en = {
258
272
  "list.table.header.creationDate": "Creation Date",
259
273
  "list.table.header.lastModified": "Last Modified",
260
274
  "list.table.header.sort": "Sort on {label}",
275
+ "list.table.header.select-all": "Select all",
276
+ "list.table.row.select": "Select {name}",
261
277
  "list.table.content.empty-label": "This field is empty",
278
+ "list.bulk-actions.label": "Bulk actions",
279
+ "list.bulk-actions.selected-count": "{count, plural, =1 {# item selected} other {# items selected}}",
280
+ "list.bulk-actions.clear": "Clear selection",
281
+ "list.bulk-actions.create-metadata": "Create metadata",
282
+ "list.bulk-actions.move": "Move",
283
+ "list.bulk-actions.move.title": "Move elements to",
284
+ "list.bulk-actions.move.location": "Location",
285
+ "list.bulk-actions.move.submit": "Move",
286
+ "list.bulk-actions.move.success": "{count, plural, =1 {# element has} other {# elements have}} been moved from {source} to {destination}",
287
+ "list.bulk-actions.move.error": "An error occurred while moving the items.",
288
+ "list.bulk-actions.delete": "Delete",
289
+ "list.bulk-actions.delete.confirm.title": "Delete {count, plural, =1 {# item} other {# items}}?",
290
+ "list.bulk-actions.delete.confirm.description.are-you-sure": "Are you sure you want to delete the selected items?",
291
+ "list.bulk-actions.delete.confirm.description.cant-be-undone": "This action can’t be undone. Deleting a folder also removes everything inside it, and any linked content will break – media asset containers will appear empty.",
292
+ "list.bulk-actions.delete.success": "{count, plural, =1 {# item has been deleted} other {# items have been deleted}}",
293
+ "list.bulk-actions.delete.error": "An error occurred while deleting the items.",
294
+ "list.bulk-actions.create-metadata-not-available": "Generate metadata isn't available yet",
262
295
  "tabs.title": "How do you want to upload your assets?",
263
296
  "window.confirm.close-modal.file": "Are you sure? Your changes will be lost.",
264
297
  "window.confirm.close-modal.files": "Are you sure? You have some files that have not been uploaded yet.",
@@ -1 +1 @@
1
- {"version":3,"file":"en.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"en.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -160,6 +160,18 @@ var en = {
160
160
  "list.empty.title": "No assets yet",
161
161
  "list.empty.description": "Get started by uploading assets or creating a folder.",
162
162
  "list.empty.add-assets": "Add assets",
163
+ "list.sort.trigger": "Sort: {active}",
164
+ "list.sort.section": "Sort",
165
+ "list.sort.oldest-uploads": "Oldest uploads",
166
+ "list.sort.most-recent-updates": "Most recent updates",
167
+ "list.sort.name-asc": "A to Z",
168
+ "list.sort.name-desc": "Z to A",
169
+ "list.sort.size-asc": "File size ascending",
170
+ "list.sort.size-desc": "File size descending",
171
+ "list.sort.folders": "Folders",
172
+ "list.sort.folders-on-top": "On top",
173
+ "list.sort.folders-mixed": "Mixed with files",
174
+ "list.sort.active": "(active)",
163
175
  "list.assets.loading-more": "Loading more assets...",
164
176
  "list.assets.loading-asset": "Loading the preview for the media: {path}",
165
177
  "list.assets.not-supported-content": "No preview available",
@@ -201,6 +213,8 @@ var en = {
201
213
  "dnd.announce.invalid-drop": "Cannot move item to this folder.",
202
214
  "dnd.announce.move-failure": "Move failed. {message}",
203
215
  "dnd.announce.cancel": "Drag cancelled.",
216
+ "dnd.overlay.folders": "{count, plural, one {# folder} other {# folders}}",
217
+ "dnd.overlay.files": "{count, plural, one {# file} other {# files}}",
204
218
  "modal.selected-list.sub-header-subtitle": "Drag & drop to reorder the assets in the field",
205
219
  "modal.upload-list.footer.button": "Upload {number, plural, one {# asset} other {# assets}} to the library",
206
220
  "modal.upload-list.sub-header-subtitle": "Manage the assets before adding them to the Media Library",
@@ -256,7 +270,26 @@ var en = {
256
270
  "list.table.header.creationDate": "Creation Date",
257
271
  "list.table.header.lastModified": "Last Modified",
258
272
  "list.table.header.sort": "Sort on {label}",
273
+ "list.table.header.select-all": "Select all",
274
+ "list.table.row.select": "Select {name}",
259
275
  "list.table.content.empty-label": "This field is empty",
276
+ "list.bulk-actions.label": "Bulk actions",
277
+ "list.bulk-actions.selected-count": "{count, plural, =1 {# item selected} other {# items selected}}",
278
+ "list.bulk-actions.clear": "Clear selection",
279
+ "list.bulk-actions.create-metadata": "Create metadata",
280
+ "list.bulk-actions.move": "Move",
281
+ "list.bulk-actions.move.title": "Move elements to",
282
+ "list.bulk-actions.move.location": "Location",
283
+ "list.bulk-actions.move.submit": "Move",
284
+ "list.bulk-actions.move.success": "{count, plural, =1 {# element has} other {# elements have}} been moved from {source} to {destination}",
285
+ "list.bulk-actions.move.error": "An error occurred while moving the items.",
286
+ "list.bulk-actions.delete": "Delete",
287
+ "list.bulk-actions.delete.confirm.title": "Delete {count, plural, =1 {# item} other {# items}}?",
288
+ "list.bulk-actions.delete.confirm.description.are-you-sure": "Are you sure you want to delete the selected items?",
289
+ "list.bulk-actions.delete.confirm.description.cant-be-undone": "This action can’t be undone. Deleting a folder also removes everything inside it, and any linked content will break – media asset containers will appear empty.",
290
+ "list.bulk-actions.delete.success": "{count, plural, =1 {# item has been deleted} other {# items have been deleted}}",
291
+ "list.bulk-actions.delete.error": "An error occurred while deleting the items.",
292
+ "list.bulk-actions.create-metadata-not-available": "Generate metadata isn't available yet",
260
293
  "tabs.title": "How do you want to upload your assets?",
261
294
  "window.confirm.close-modal.file": "Are you sure? Your changes will be lost.",
262
295
  "window.confirm.close-modal.files": "Are you sure? You have some files that have not been uploaded yet.",
@@ -1 +1 @@
1
- {"version":3,"file":"en.json.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"en.json.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}