@strapi/upload 5.59.0 → 5.60.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.
Files changed (231) hide show
  1. package/dist/admin/components/AssetPickerDialog/AssetPickerDialog.js +434 -0
  2. package/dist/admin/components/AssetPickerDialog/AssetPickerDialog.js.map +1 -0
  3. package/dist/admin/components/AssetPickerDialog/AssetPickerDialog.mjs +432 -0
  4. package/dist/admin/components/AssetPickerDialog/AssetPickerDialog.mjs.map +1 -0
  5. package/dist/admin/components/AssetPickerDialog/FolderBreadcrumbs.js +91 -0
  6. package/dist/admin/components/AssetPickerDialog/FolderBreadcrumbs.js.map +1 -0
  7. package/dist/admin/components/AssetPickerDialog/FolderBreadcrumbs.mjs +89 -0
  8. package/dist/admin/components/AssetPickerDialog/FolderBreadcrumbs.mjs.map +1 -0
  9. package/dist/admin/components/AssetPickerDialog/PickerSelectionProvider.js +178 -0
  10. package/dist/admin/components/AssetPickerDialog/PickerSelectionProvider.js.map +1 -0
  11. package/dist/admin/components/AssetPickerDialog/PickerSelectionProvider.mjs +175 -0
  12. package/dist/admin/components/AssetPickerDialog/PickerSelectionProvider.mjs.map +1 -0
  13. package/dist/admin/components/AssetPickerDialog/SortableSelection.js +143 -0
  14. package/dist/admin/components/AssetPickerDialog/SortableSelection.js.map +1 -0
  15. package/dist/admin/components/AssetPickerDialog/SortableSelection.mjs +141 -0
  16. package/dist/admin/components/AssetPickerDialog/SortableSelection.mjs.map +1 -0
  17. package/dist/admin/components/AssetPickerDialog/pickerSelection.js +49 -0
  18. package/dist/admin/components/AssetPickerDialog/pickerSelection.js.map +1 -0
  19. package/dist/admin/components/AssetPickerDialog/pickerSelection.mjs +41 -0
  20. package/dist/admin/components/AssetPickerDialog/pickerSelection.mjs.map +1 -0
  21. package/dist/admin/components/MediaLibraryInput/AddAssetMenu.js +4 -3
  22. package/dist/admin/components/MediaLibraryInput/AddAssetMenu.js.map +1 -1
  23. package/dist/admin/components/MediaLibraryInput/AddAssetMenu.mjs +4 -3
  24. package/dist/admin/components/MediaLibraryInput/AddAssetMenu.mjs.map +1 -1
  25. package/dist/admin/components/MediaLibraryInput/AssetCard.js +240 -0
  26. package/dist/admin/components/MediaLibraryInput/AssetCard.js.map +1 -0
  27. package/dist/admin/components/MediaLibraryInput/AssetCard.mjs +237 -0
  28. package/dist/admin/components/MediaLibraryInput/AssetCard.mjs.map +1 -0
  29. package/dist/admin/components/MediaLibraryInput/AssetCarousel.js +161 -0
  30. package/dist/admin/components/MediaLibraryInput/AssetCarousel.js.map +1 -0
  31. package/dist/admin/components/MediaLibraryInput/AssetCarousel.mjs +159 -0
  32. package/dist/admin/components/MediaLibraryInput/AssetCarousel.mjs.map +1 -0
  33. package/dist/admin/components/MediaLibraryInput/AssetDropZone.js +76 -49
  34. package/dist/admin/components/MediaLibraryInput/AssetDropZone.js.map +1 -1
  35. package/dist/admin/components/MediaLibraryInput/AssetDropZone.mjs +77 -50
  36. package/dist/admin/components/MediaLibraryInput/AssetDropZone.mjs.map +1 -1
  37. package/dist/admin/components/MediaLibraryInput/AssetPreview.js +109 -0
  38. package/dist/admin/components/MediaLibraryInput/AssetPreview.js.map +1 -0
  39. package/dist/admin/components/MediaLibraryInput/AssetPreview.mjs +106 -0
  40. package/dist/admin/components/MediaLibraryInput/AssetPreview.mjs.map +1 -0
  41. package/dist/admin/components/MediaLibraryInput/AssetRow.js +146 -79
  42. package/dist/admin/components/MediaLibraryInput/AssetRow.js.map +1 -1
  43. package/dist/admin/components/MediaLibraryInput/AssetRow.mjs +148 -82
  44. package/dist/admin/components/MediaLibraryInput/AssetRow.mjs.map +1 -1
  45. package/dist/admin/components/MediaLibraryInput/FieldControls.js +32 -0
  46. package/dist/admin/components/MediaLibraryInput/FieldControls.js.map +1 -0
  47. package/dist/admin/components/MediaLibraryInput/FieldControls.mjs +29 -0
  48. package/dist/admin/components/MediaLibraryInput/FieldControls.mjs.map +1 -0
  49. package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.js +130 -88
  50. package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.js.map +1 -1
  51. package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.mjs +129 -91
  52. package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.mjs.map +1 -1
  53. package/dist/admin/components/MediaLibraryInput/UploadProgressBar.js +42 -0
  54. package/dist/admin/components/MediaLibraryInput/UploadProgressBar.js.map +1 -0
  55. package/dist/admin/components/MediaLibraryInput/UploadProgressBar.mjs +40 -0
  56. package/dist/admin/components/MediaLibraryInput/UploadProgressBar.mjs.map +1 -0
  57. package/dist/admin/components/MediaLibraryInput/useFieldUploads.js +122 -0
  58. package/dist/admin/components/MediaLibraryInput/useFieldUploads.js.map +1 -0
  59. package/dist/admin/components/MediaLibraryInput/useFieldUploads.mjs +120 -0
  60. package/dist/admin/components/MediaLibraryInput/useFieldUploads.mjs.map +1 -0
  61. package/dist/admin/components/UploadProgressDialog.js +2 -1
  62. package/dist/admin/components/UploadProgressDialog.js.map +1 -1
  63. package/dist/admin/components/UploadProgressDialog.mjs +2 -1
  64. package/dist/admin/components/UploadProgressDialog.mjs.map +1 -1
  65. package/dist/admin/hooks/useMediaLibraryPermissions.js +12 -2
  66. package/dist/admin/hooks/useMediaLibraryPermissions.js.map +1 -1
  67. package/dist/admin/hooks/useMediaLibraryPermissions.mjs +12 -2
  68. package/dist/admin/hooks/useMediaLibraryPermissions.mjs.map +1 -1
  69. package/dist/admin/pages/Assets/AssetsPage.js +13 -302
  70. package/dist/admin/pages/Assets/AssetsPage.js.map +1 -1
  71. package/dist/admin/pages/Assets/AssetsPage.mjs +11 -280
  72. package/dist/admin/pages/Assets/AssetsPage.mjs.map +1 -1
  73. package/dist/admin/pages/Assets/components/AssetsGrid.js +142 -31
  74. package/dist/admin/pages/Assets/components/AssetsGrid.js.map +1 -1
  75. package/dist/admin/pages/Assets/components/AssetsGrid.mjs +145 -34
  76. package/dist/admin/pages/Assets/components/AssetsGrid.mjs.map +1 -1
  77. package/dist/admin/pages/Assets/components/AssetsSearchInput.js +43 -2
  78. package/dist/admin/pages/Assets/components/AssetsSearchInput.js.map +1 -1
  79. package/dist/admin/pages/Assets/components/AssetsSearchInput.mjs +45 -4
  80. package/dist/admin/pages/Assets/components/AssetsSearchInput.mjs.map +1 -1
  81. package/dist/admin/pages/Assets/components/AssetsTable.js +58 -34
  82. package/dist/admin/pages/Assets/components/AssetsTable.js.map +1 -1
  83. package/dist/admin/pages/Assets/components/AssetsTable.mjs +60 -36
  84. package/dist/admin/pages/Assets/components/AssetsTable.mjs.map +1 -1
  85. package/dist/admin/pages/Assets/components/AssetsView.js +145 -0
  86. package/dist/admin/pages/Assets/components/AssetsView.js.map +1 -0
  87. package/dist/admin/pages/Assets/components/AssetsView.mjs +143 -0
  88. package/dist/admin/pages/Assets/components/AssetsView.mjs.map +1 -0
  89. package/dist/admin/pages/Assets/components/BulkActionsBar.mjs +1 -1
  90. package/dist/admin/pages/Assets/components/BusyOverlay.mjs +1 -1
  91. package/dist/admin/pages/Assets/components/Dnd/DragOverlayChip.mjs +1 -1
  92. package/dist/admin/pages/Assets/components/Dnd/ReorderHandle.js +40 -0
  93. package/dist/admin/pages/Assets/components/Dnd/ReorderHandle.js.map +1 -0
  94. package/dist/admin/pages/Assets/components/Dnd/ReorderHandle.mjs +38 -0
  95. package/dist/admin/pages/Assets/components/Dnd/ReorderHandle.mjs.map +1 -0
  96. package/dist/admin/pages/Assets/components/Dnd/assetSortable.js +29 -0
  97. package/dist/admin/pages/Assets/components/Dnd/assetSortable.js.map +1 -0
  98. package/dist/admin/pages/Assets/components/Dnd/assetSortable.mjs +24 -0
  99. package/dist/admin/pages/Assets/components/Dnd/assetSortable.mjs.map +1 -0
  100. package/dist/admin/pages/Assets/components/Dnd/dndIds.js +5 -0
  101. package/dist/admin/pages/Assets/components/Dnd/dndIds.js.map +1 -1
  102. package/dist/admin/pages/Assets/components/Dnd/dndIds.mjs +5 -1
  103. package/dist/admin/pages/Assets/components/Dnd/dndIds.mjs.map +1 -1
  104. package/dist/admin/pages/Assets/components/Dnd/useAssetDnd.js +41 -13
  105. package/dist/admin/pages/Assets/components/Dnd/useAssetDnd.js.map +1 -1
  106. package/dist/admin/pages/Assets/components/Dnd/useAssetDnd.mjs +41 -13
  107. package/dist/admin/pages/Assets/components/Dnd/useAssetDnd.mjs.map +1 -1
  108. package/dist/admin/pages/Assets/components/FilterBadges.mjs +2 -2
  109. package/dist/admin/pages/Assets/components/FilterMenu.mjs +2 -2
  110. package/dist/admin/pages/Assets/components/FolderTree/FolderTree.js +274 -55
  111. package/dist/admin/pages/Assets/components/FolderTree/FolderTree.js.map +1 -1
  112. package/dist/admin/pages/Assets/components/FolderTree/FolderTree.mjs +277 -59
  113. package/dist/admin/pages/Assets/components/FolderTree/FolderTree.mjs.map +1 -1
  114. package/dist/admin/pages/Assets/components/FolderTree/collapsedBranch.js +32 -0
  115. package/dist/admin/pages/Assets/components/FolderTree/collapsedBranch.js.map +1 -0
  116. package/dist/admin/pages/Assets/components/FolderTree/collapsedBranch.mjs +29 -0
  117. package/dist/admin/pages/Assets/components/FolderTree/collapsedBranch.mjs.map +1 -0
  118. package/dist/admin/pages/Assets/components/ViewToggle.js +126 -0
  119. package/dist/admin/pages/Assets/components/ViewToggle.js.map +1 -0
  120. package/dist/admin/pages/Assets/components/ViewToggle.mjs +104 -0
  121. package/dist/admin/pages/Assets/components/ViewToggle.mjs.map +1 -0
  122. package/dist/admin/pages/Assets/hooks/useAssetSearch.js +2 -2
  123. package/dist/admin/pages/Assets/hooks/useAssetSearch.js.map +1 -1
  124. package/dist/admin/pages/Assets/hooks/useAssetSearch.mjs +2 -2
  125. package/dist/admin/pages/Assets/hooks/useAssetSearch.mjs.map +1 -1
  126. package/dist/admin/pages/Assets/hooks/useAssetSelection.js +19 -1
  127. package/dist/admin/pages/Assets/hooks/useAssetSelection.js.map +1 -1
  128. package/dist/admin/pages/Assets/hooks/useAssetSelection.mjs +20 -3
  129. package/dist/admin/pages/Assets/hooks/useAssetSelection.mjs.map +1 -1
  130. package/dist/admin/pages/Assets/hooks/useAssetsList.js +87 -0
  131. package/dist/admin/pages/Assets/hooks/useAssetsList.js.map +1 -0
  132. package/dist/admin/pages/Assets/hooks/useAssetsList.mjs +85 -0
  133. package/dist/admin/pages/Assets/hooks/useAssetsList.mjs.map +1 -0
  134. package/dist/admin/pages/Assets/hooks/useBusyAssets.mjs +1 -1
  135. package/dist/admin/pages/Assets/hooks/useFolderNavigation.js +2 -1
  136. package/dist/admin/pages/Assets/hooks/useFolderNavigation.js.map +1 -1
  137. package/dist/admin/pages/Assets/hooks/useFolderNavigation.mjs +3 -2
  138. package/dist/admin/pages/Assets/hooks/useFolderNavigation.mjs.map +1 -1
  139. package/dist/admin/pages/Assets/hooks/useListFilters.js +2 -1
  140. package/dist/admin/pages/Assets/hooks/useListFilters.js.map +1 -1
  141. package/dist/admin/pages/Assets/hooks/useListFilters.mjs +3 -2
  142. package/dist/admin/pages/Assets/hooks/useListFilters.mjs.map +1 -1
  143. package/dist/admin/pages/Assets/hooks/useListQueryParams.js +80 -0
  144. package/dist/admin/pages/Assets/hooks/useListQueryParams.js.map +1 -0
  145. package/dist/admin/pages/Assets/hooks/useListQueryParams.mjs +77 -0
  146. package/dist/admin/pages/Assets/hooks/useListQueryParams.mjs.map +1 -0
  147. package/dist/admin/pages/Assets/hooks/useListSettings.js +32 -0
  148. package/dist/admin/pages/Assets/hooks/useListSettings.js.map +1 -0
  149. package/dist/admin/pages/Assets/hooks/useListSettings.mjs +29 -0
  150. package/dist/admin/pages/Assets/hooks/useListSettings.mjs.map +1 -0
  151. package/dist/admin/pages/Assets/hooks/useListSort.js +2 -1
  152. package/dist/admin/pages/Assets/hooks/useListSort.js.map +1 -1
  153. package/dist/admin/pages/Assets/hooks/useListSort.mjs +3 -2
  154. package/dist/admin/pages/Assets/hooks/useListSort.mjs.map +1 -1
  155. package/dist/admin/services/api.js +92 -7
  156. package/dist/admin/services/api.js.map +1 -1
  157. package/dist/admin/services/api.mjs +91 -9
  158. package/dist/admin/services/api.mjs.map +1 -1
  159. package/dist/admin/src/components/AssetPickerDialog/AssetPickerDialog.d.ts +19 -0
  160. package/dist/admin/src/components/AssetPickerDialog/FolderBreadcrumbs.d.ts +10 -0
  161. package/dist/admin/src/components/AssetPickerDialog/PickerSelectionProvider.d.ts +28 -0
  162. package/dist/admin/src/components/AssetPickerDialog/SortableSelection.d.ts +12 -0
  163. package/dist/admin/src/components/AssetPickerDialog/pickerSelection.d.ts +26 -0
  164. package/dist/admin/src/components/MediaLibraryInput/AssetCard.d.ts +25 -0
  165. package/dist/admin/src/components/MediaLibraryInput/AssetCarousel.d.ts +16 -0
  166. package/dist/admin/src/components/MediaLibraryInput/AssetDropZone.d.ts +11 -3
  167. package/dist/admin/src/components/MediaLibraryInput/AssetPreview.d.ts +17 -0
  168. package/dist/admin/src/components/MediaLibraryInput/AssetRow.d.ts +13 -3
  169. package/dist/admin/src/components/MediaLibraryInput/FieldControls.d.ts +19 -0
  170. package/dist/admin/src/components/MediaLibraryInput/MediaLibraryInput.d.ts +3 -1
  171. package/dist/admin/src/components/MediaLibraryInput/UploadProgressBar.d.ts +7 -0
  172. package/dist/admin/src/components/MediaLibraryInput/useFieldUploads.d.ts +31 -0
  173. package/dist/admin/src/hooks/useMediaLibraryPermissions.d.ts +2 -0
  174. package/dist/admin/src/pages/Assets/components/AssetsGrid.d.ts +3 -1
  175. package/dist/admin/src/pages/Assets/components/AssetsSearchInput.d.ts +11 -1
  176. package/dist/admin/src/pages/Assets/components/AssetsView.d.ts +29 -0
  177. package/dist/admin/src/pages/Assets/components/Dnd/ReorderHandle.d.ts +12 -0
  178. package/dist/admin/src/pages/Assets/components/Dnd/assetSortable.d.ts +37 -0
  179. package/dist/admin/src/pages/Assets/components/Dnd/dndIds.d.ts +5 -0
  180. package/dist/admin/src/pages/Assets/components/Dnd/useAssetDnd.d.ts +23 -2
  181. package/dist/admin/src/pages/Assets/components/FolderTree/FolderTree.d.ts +1 -0
  182. package/dist/admin/src/pages/Assets/components/FolderTree/collapsedBranch.d.ts +21 -0
  183. package/dist/admin/src/pages/Assets/components/ViewToggle.d.ts +8 -0
  184. package/dist/admin/src/pages/Assets/hooks/useAssetSelection.d.ts +26 -0
  185. package/dist/admin/src/pages/Assets/hooks/useAssetsList.d.ts +30 -0
  186. package/dist/admin/src/pages/Assets/hooks/useListQueryParams.d.ts +27 -0
  187. package/dist/admin/src/pages/Assets/hooks/useListSettings.d.ts +29 -0
  188. package/dist/admin/src/services/api.d.ts +24 -1
  189. package/dist/admin/src/store/uploadProgress.d.ts +14 -1
  190. package/dist/admin/src/utils/findFolderPath.d.ts +6 -0
  191. package/dist/admin/src/utils/isAllowedAssetType.d.ts +14 -0
  192. package/dist/admin/store/uploadProgress.js +30 -3
  193. package/dist/admin/store/uploadProgress.js.map +1 -1
  194. package/dist/admin/store/uploadProgress.mjs +29 -4
  195. package/dist/admin/store/uploadProgress.mjs.map +1 -1
  196. package/dist/admin/translations/en.json.js +20 -0
  197. package/dist/admin/translations/en.json.js.map +1 -1
  198. package/dist/admin/translations/en.json.mjs +20 -0
  199. package/dist/admin/translations/en.json.mjs.map +1 -1
  200. package/dist/admin/utils/findFolderPath.js +26 -0
  201. package/dist/admin/utils/findFolderPath.js.map +1 -0
  202. package/dist/admin/utils/findFolderPath.mjs +24 -0
  203. package/dist/admin/utils/findFolderPath.mjs.map +1 -0
  204. package/dist/admin/utils/isAllowedAssetType.js +33 -0
  205. package/dist/admin/utils/isAllowedAssetType.js.map +1 -0
  206. package/dist/admin/utils/isAllowedAssetType.mjs +31 -0
  207. package/dist/admin/utils/isAllowedAssetType.mjs.map +1 -0
  208. package/dist/server/controllers/admin-settings.js +5 -1
  209. package/dist/server/controllers/admin-settings.js.map +1 -1
  210. package/dist/server/controllers/admin-settings.mjs +5 -1
  211. package/dist/server/controllers/admin-settings.mjs.map +1 -1
  212. package/dist/server/services/image-manipulation.js +2 -2
  213. package/dist/server/services/image-manipulation.js.map +1 -1
  214. package/dist/server/services/image-manipulation.mjs +2 -2
  215. package/dist/server/services/image-manipulation.mjs.map +1 -1
  216. package/dist/server/services/upload.js.map +1 -1
  217. package/dist/server/services/upload.mjs.map +1 -1
  218. package/dist/server/src/controllers/admin-settings.d.ts.map +1 -1
  219. package/dist/server/src/index.d.ts +1 -1
  220. package/dist/server/src/services/extensions/utils.d.ts +11 -11
  221. package/dist/server/src/services/image-manipulation.d.ts +1 -1
  222. package/dist/server/src/services/image-manipulation.d.ts.map +1 -1
  223. package/dist/server/src/services/index.d.ts +1 -1
  224. package/dist/server/src/types.d.ts +63 -12
  225. package/dist/server/src/types.d.ts.map +1 -1
  226. package/package.json +8 -6
  227. package/dist/admin/components/MediaLibraryInput/NoLibraryAccessDialog.js +0 -45
  228. package/dist/admin/components/MediaLibraryInput/NoLibraryAccessDialog.js.map +0 -1
  229. package/dist/admin/components/MediaLibraryInput/NoLibraryAccessDialog.mjs +0 -43
  230. package/dist/admin/components/MediaLibraryInput/NoLibraryAccessDialog.mjs.map +0 -1
  231. package/dist/admin/src/components/MediaLibraryInput/NoLibraryAccessDialog.d.ts +0 -10
@@ -1,6 +1,6 @@
1
1
  import { useCallback } from 'react';
2
- import { useQueryParams } from '@strapi/admin/strapi-admin';
3
2
  import { encodeSearchQuery } from '../../../utils/searchQueryParam.mjs';
3
+ import { useListQueryParams } from './useListQueryParams.mjs';
4
4
 
5
5
  /**
6
6
  * Reads and writes the global asset search term held in `?_q=`.
@@ -8,7 +8,7 @@ import { encodeSearchQuery } from '../../../utils/searchQueryParam.mjs';
8
8
  * Debouncing is the input component's job (see `AssetsSearchInput`) — this hook
9
9
  * is a thin URL accessor so every consumer reads the same source of truth.
10
10
  */ const useAssetSearch = ()=>{
11
- const [{ query }, setQuery] = useQueryParams();
11
+ const [{ query }, setQuery] = useListQueryParams();
12
12
  const searchQuery = query?._q ?? '';
13
13
  const setSearchQuery = useCallback((value)=>{
14
14
  if (value) {
@@ -1 +1 @@
1
- {"version":3,"file":"useAssetSearch.mjs","sources":["../../../../../admin/src/pages/Assets/hooks/useAssetSearch.ts"],"sourcesContent":["import { useCallback } from 'react';\n\nimport { useQueryParams } from '@strapi/admin/strapi-admin';\n\nimport { encodeSearchQuery } from '../../../utils/searchQueryParam';\n\n/**\n * Reads and writes the global asset search term held in `?_q=`.\n *\n * Debouncing is the input component's job (see `AssetsSearchInput`) — this hook\n * is a thin URL accessor so every consumer reads the same source of truth.\n */\nexport const useAssetSearch = () => {\n const [{ query }, setQuery] = useQueryParams<{ _q?: string }>();\n\n const searchQuery = query?._q ?? '';\n\n const setSearchQuery = useCallback(\n (value: string) => {\n if (value) {\n setQuery({ _q: encodeSearchQuery(value) }, 'push', true);\n } else {\n setQuery({ _q: '' }, 'remove', true);\n }\n },\n [setQuery]\n );\n\n const clearSearch = useCallback(() => setSearchQuery(''), [setSearchQuery]);\n\n return {\n searchQuery,\n isSearching: searchQuery !== '',\n setSearchQuery,\n clearSearch,\n };\n};\n"],"names":["useAssetSearch","query","setQuery","useQueryParams","searchQuery","_q","setSearchQuery","useCallback","value","encodeSearchQuery","clearSearch","isSearching"],"mappings":";;;;AAMA;;;;;UAMaA,cAAAA,GAAiB,IAAA;AAC5B,IAAA,MAAM,CAAC,EAAEC,KAAK,EAAE,EAAEC,SAAS,GAAGC,cAAAA,EAAAA;IAE9B,MAAMC,WAAAA,GAAcH,OAAOI,EAAAA,IAAM,EAAA;IAEjC,MAAMC,cAAAA,GAAiBC,YACrB,CAACC,KAAAA,GAAAA;AACC,QAAA,IAAIA,KAAAA,EAAO;YACTN,QAAAA,CAAS;AAAEG,gBAAAA,EAAAA,EAAII,iBAAAA,CAAkBD,KAAAA;AAAO,aAAA,EAAG,MAAA,EAAQ,IAAA,CAAA;QACrD,CAAA,MAAO;YACLN,QAAAA,CAAS;gBAAEG,EAAAA,EAAI;AAAG,aAAA,EAAG,QAAA,EAAU,IAAA,CAAA;AACjC,QAAA;IACF,CAAA,EACA;AAACH,QAAAA;AAAS,KAAA,CAAA;AAGZ,IAAA,MAAMQ,WAAAA,GAAcH,WAAAA,CAAY,IAAMD,cAAAA,CAAe,EAAA,CAAA,EAAK;AAACA,QAAAA;AAAe,KAAA,CAAA;IAE1E,OAAO;AACLF,QAAAA,WAAAA;AACAO,QAAAA,WAAAA,EAAaP,WAAAA,KAAgB,EAAA;AAC7BE,QAAAA,cAAAA;AACAI,QAAAA;AACF,KAAA;AACF;;;;"}
1
+ {"version":3,"file":"useAssetSearch.mjs","sources":["../../../../../admin/src/pages/Assets/hooks/useAssetSearch.ts"],"sourcesContent":["import { useCallback } from 'react';\n\nimport { encodeSearchQuery } from '../../../utils/searchQueryParam';\n\nimport { useListQueryParams } from './useListQueryParams';\n\n/**\n * Reads and writes the global asset search term held in `?_q=`.\n *\n * Debouncing is the input component's job (see `AssetsSearchInput`) — this hook\n * is a thin URL accessor so every consumer reads the same source of truth.\n */\nexport const useAssetSearch = () => {\n const [{ query }, setQuery] = useListQueryParams<{ _q?: string }>();\n\n const searchQuery = query?._q ?? '';\n\n const setSearchQuery = useCallback(\n (value: string) => {\n if (value) {\n setQuery({ _q: encodeSearchQuery(value) }, 'push', true);\n } else {\n setQuery({ _q: '' }, 'remove', true);\n }\n },\n [setQuery]\n );\n\n const clearSearch = useCallback(() => setSearchQuery(''), [setSearchQuery]);\n\n return {\n searchQuery,\n isSearching: searchQuery !== '',\n setSearchQuery,\n clearSearch,\n };\n};\n"],"names":["useAssetSearch","query","setQuery","useListQueryParams","searchQuery","_q","setSearchQuery","useCallback","value","encodeSearchQuery","clearSearch","isSearching"],"mappings":";;;;AAMA;;;;;UAMaA,cAAAA,GAAiB,IAAA;AAC5B,IAAA,MAAM,CAAC,EAAEC,KAAK,EAAE,EAAEC,SAAS,GAAGC,kBAAAA,EAAAA;IAE9B,MAAMC,WAAAA,GAAcH,OAAOI,EAAAA,IAAM,EAAA;IAEjC,MAAMC,cAAAA,GAAiBC,YACrB,CAACC,KAAAA,GAAAA;AACC,QAAA,IAAIA,KAAAA,EAAO;YACTN,QAAAA,CAAS;AAAEG,gBAAAA,EAAAA,EAAII,iBAAAA,CAAkBD,KAAAA;AAAO,aAAA,EAAG,MAAA,EAAQ,IAAA,CAAA;QACrD,CAAA,MAAO;YACLN,QAAAA,CAAS;gBAAEG,EAAAA,EAAI;AAAG,aAAA,EAAG,QAAA,EAAU,IAAA,CAAA;AACjC,QAAA;IACF,CAAA,EACA;AAACH,QAAAA;AAAS,KAAA,CAAA;AAGZ,IAAA,MAAMQ,WAAAA,GAAcH,WAAAA,CAAY,IAAMD,cAAAA,CAAe,EAAA,CAAA,EAAK;AAACA,QAAAA;AAAe,KAAA,CAAA;IAE1E,OAAO;AACLF,QAAAA,WAAAA;AACAO,QAAAA,WAAAA,EAAaP,WAAAA,KAAgB,EAAA;AAC7BE,QAAAA,cAAAA;AACAI,QAAAA;AACF,KAAA;AACF;;;;"}
@@ -1,11 +1,19 @@
1
1
  'use strict';
2
2
 
3
3
  var React = require('react');
4
+ var useMediaLibraryPermissions = require('../../../hooks/useMediaLibraryPermissions.js');
4
5
  var selection = require('../utils/selection.js');
5
6
 
6
- const AssetSelectionContext = React.createContext(null);
7
+ /**
8
+ * Exported so a host with its own selection rules (the Content Manager asset
9
+ * picker) can feed the same views a different implementation.
10
+ */ const AssetSelectionContext = React.createContext(null);
7
11
  const AssetSelectionProvider = ({ children, disabled = false })=>{
8
12
  const [state, setState] = React.useState(selection.createEmptySelection);
13
+ // Every bulk action needs `assets.update`: without it the views show no
14
+ // checkboxes, whatever the host passes as `disabled`.
15
+ const { canUpdate } = useMediaLibraryPermissions.useMediaLibraryPermissions();
16
+ const isEnabled = !disabled && canUpdate;
9
17
  const isSelected = React.useCallback((key)=>!disabled && state.selectedKeys.has(key), [
10
18
  disabled,
11
19
  state.selectedKeys
@@ -46,7 +54,13 @@ const AssetSelectionProvider = ({ children, disabled = false })=>{
46
54
  const selectedFolderIds = React.useMemo(()=>selection.getIdsOfKind(state.selectedKeys, 'folder'), [
47
55
  state.selectedKeys
48
56
  ]);
57
+ const getSelectability = React.useCallback(()=>isEnabled ? 'enabled' : 'hidden', [
58
+ isEnabled
59
+ ]);
49
60
  const value = React.useMemo(()=>({
61
+ isEnabled,
62
+ canSelectAll: true,
63
+ getSelectability,
50
64
  selectedKeys: state.selectedKeys,
51
65
  selectedIds,
52
66
  selectedFolderIds,
@@ -57,8 +71,11 @@ const AssetSelectionProvider = ({ children, disabled = false })=>{
57
71
  selectAll,
58
72
  selectOnly,
59
73
  deselect,
74
+ deselectAll: clear,
60
75
  clear
61
76
  }), [
77
+ isEnabled,
78
+ getSelectability,
62
79
  state.selectedKeys,
63
80
  selectedIds,
64
81
  selectedFolderIds,
@@ -84,6 +101,7 @@ const useAssetSelection = ()=>{
84
101
  };
85
102
  const useAssetSelectionOptional = ()=>React.useContext(AssetSelectionContext);
86
103
 
104
+ exports.AssetSelectionContext = AssetSelectionContext;
87
105
  exports.AssetSelectionProvider = AssetSelectionProvider;
88
106
  exports.useAssetSelection = useAssetSelection;
89
107
  exports.useAssetSelectionOptional = useAssetSelectionOptional;
@@ -1 +1 @@
1
- {"version":3,"file":"useAssetSelection.js","sources":["../../../../../admin/src/pages/Assets/hooks/useAssetSelection.ts"],"sourcesContent":["import {\n createContext,\n createElement,\n useCallback,\n useContext,\n useMemo,\n useState,\n type ReactNode,\n} from 'react';\n\nimport {\n clearSelection,\n createEmptySelection,\n deselect as deselectState,\n getIdsOfKind,\n selectAll as selectAllState,\n selectRange as selectRangeState,\n toggleSelection,\n type ItemKey,\n type SelectionState,\n} from '../utils/selection';\n\n/**\n * Ephemeral, view-state-only multi-select for the future Media Library. Selection\n * is page-scoped and reset on folder navigation or sort/filter changes (the\n * table/grid toggle keeps it — same list, different presentation).\n *\n * The actual computation lives in `../utils/selection.ts` (pure + unit-tested);\n * this hook is a thin React wrapper. Assets and folders share one mechanism —\n * items are tracked as namespaced keys (`asset:1` / `folder:1`) so toggle, range\n * and select-all behave the same for both. Range / select-all receive the\n * ordered key array from the caller (the view owns the rendered order), keeping\n * the context data-source-agnostic.\n */\nexport interface AssetSelection {\n /** Every selected item key (assets and folders), render-order agnostic. */\n selectedKeys: Set<ItemKey>;\n /** Selected asset ids, derived from {@link selectedKeys}. */\n selectedIds: Set<number>;\n /** Selected folder ids, derived from {@link selectedKeys}. */\n selectedFolderIds: Set<number>;\n anchorKey: ItemKey | null;\n isSelected: (key: ItemKey) => boolean;\n /** Additive toggle (Cmd/Ctrl+click, item checkbox). */\n toggle: (key: ItemKey) => void;\n /** Shift+click — selects the contiguous range from the anchor to the target. */\n selectRange: (orderedKeys: ItemKey[], targetKey: ItemKey) => void;\n /** Header checkbox — selects every rendered item (folders and assets). */\n selectAll: (orderedKeys: ItemKey[]) => void;\n /**\n * Replaces the selection with this one key, as a right-click on an unselected\n * item does: what the menu then acts on is what the user can see is selected.\n */\n selectOnly: (key: ItemKey) => void;\n /** Row-level \"...\" menu — drops one key when its item leaves the list (move, delete). */\n deselect: (key: ItemKey) => void;\n /** Close button / folder navigation / list-identity changes. */\n clear: () => void;\n}\n\nconst AssetSelectionContext = createContext<AssetSelection | null>(null);\n\ninterface AssetSelectionProviderProps {\n children: ReactNode;\n /**\n * When true, selection is inert: every mutator is a no-op and nothing ever\n * reads as selected. Every bulk action is gated on `assets.update`, so a user\n * without it has nothing to select for — the views also hide the checkboxes,\n * and this makes the remaining paths (click-to-select, Space key) do nothing.\n */\n disabled?: boolean;\n}\n\nexport const AssetSelectionProvider = ({\n children,\n disabled = false,\n}: AssetSelectionProviderProps) => {\n const [state, setState] = useState<SelectionState>(createEmptySelection);\n\n const isSelected = useCallback(\n (key: ItemKey) => !disabled && state.selectedKeys.has(key),\n [disabled, state.selectedKeys]\n );\n\n const toggle = useCallback(\n (key: ItemKey) => {\n if (disabled) return;\n setState((prev) => toggleSelection(prev, key));\n },\n [disabled]\n );\n\n const selectRange = useCallback(\n (orderedKeys: ItemKey[], targetKey: ItemKey) => {\n if (disabled) return;\n setState((prev) => selectRangeState(prev, orderedKeys, targetKey));\n },\n [disabled]\n );\n\n const selectAll = useCallback(\n (orderedKeys: ItemKey[]) => {\n if (disabled) return;\n setState(selectAllState(orderedKeys));\n },\n [disabled]\n );\n\n const selectOnly = useCallback(\n (key: ItemKey) => {\n if (disabled) return;\n setState(selectAllState([key]));\n },\n [disabled]\n );\n\n // No `disabled` guard, like `clear`: this only ever shrinks the selection, and a\n // disabled provider has nothing in it (every additive path is guarded).\n const deselect = useCallback((key: ItemKey) => setState((prev) => deselectState(prev, key)), []);\n\n const clear = useCallback(() => setState(clearSelection()), []);\n\n const selectedIds = useMemo(\n () => getIdsOfKind(state.selectedKeys, 'asset'),\n [state.selectedKeys]\n );\n const selectedFolderIds = useMemo(\n () => getIdsOfKind(state.selectedKeys, 'folder'),\n [state.selectedKeys]\n );\n\n const value = useMemo<AssetSelection>(\n () => ({\n selectedKeys: state.selectedKeys,\n selectedIds,\n selectedFolderIds,\n anchorKey: state.anchorKey,\n isSelected,\n toggle,\n selectRange,\n selectAll,\n selectOnly,\n deselect,\n clear,\n }),\n [\n state.selectedKeys,\n selectedIds,\n selectedFolderIds,\n state.anchorKey,\n isSelected,\n toggle,\n selectRange,\n selectAll,\n selectOnly,\n deselect,\n clear,\n ]\n );\n\n return createElement(AssetSelectionContext.Provider, { value }, children);\n};\n\nexport const useAssetSelection = () => {\n const context = useContext(AssetSelectionContext);\n\n if (!context) {\n throw new Error('useAssetSelection must be used within an AssetSelectionProvider');\n }\n\n return context;\n};\n\nexport const useAssetSelectionOptional = () => useContext(AssetSelectionContext);\n"],"names":["AssetSelectionContext","createContext","AssetSelectionProvider","children","disabled","state","setState","useState","createEmptySelection","isSelected","useCallback","key","selectedKeys","has","toggle","prev","toggleSelection","selectRange","orderedKeys","targetKey","selectRangeState","selectAll","selectAllState","selectOnly","deselect","deselectState","clear","clearSelection","selectedIds","useMemo","getIdsOfKind","selectedFolderIds","value","anchorKey","createElement","Provider","useAssetSelection","context","useContext","Error","useAssetSelectionOptional"],"mappings":"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"}
1
+ {"version":3,"file":"useAssetSelection.js","sources":["../../../../../admin/src/pages/Assets/hooks/useAssetSelection.ts"],"sourcesContent":["import {\n createContext,\n createElement,\n useCallback,\n useContext,\n useMemo,\n useState,\n type ReactNode,\n} from 'react';\n\nimport { useMediaLibraryPermissions } from '../../../hooks/useMediaLibraryPermissions';\nimport {\n clearSelection,\n createEmptySelection,\n deselect as deselectState,\n getIdsOfKind,\n selectAll as selectAllState,\n selectRange as selectRangeState,\n toggleSelection,\n type ItemKey,\n type SelectionState,\n} from '../utils/selection';\n\n/**\n * Ephemeral, view-state-only multi-select for the future Media Library. Selection\n * is page-scoped and reset on folder navigation or sort/filter changes (the\n * table/grid toggle keeps it — same list, different presentation).\n *\n * The actual computation lives in `../utils/selection.ts` (pure + unit-tested);\n * this hook is a thin React wrapper. Assets and folders share one mechanism —\n * items are tracked as namespaced keys (`asset:1` / `folder:1`) so toggle, range\n * and select-all behave the same for both. Range / select-all receive the\n * ordered key array from the caller (the view owns the rendered order), keeping\n * the context data-source-agnostic.\n */\n/**\n * How an item takes part in selection: `enabled` shows a working checkbox,\n * `disabled` shows it greyed out (the item cannot be chosen here), `hidden`\n * shows none (the item is not something this selection is about).\n */\nexport type Selectability = 'enabled' | 'disabled' | 'hidden';\n\nexport interface AssetSelection {\n /**\n * Whether selection is on at all. Views show the checkbox column and\n * select-all only when it is.\n */\n isEnabled: boolean;\n /** Whether the table offers a select-all header (not on a single-value picker). */\n canSelectAll: boolean;\n getSelectability: (key: ItemKey) => Selectability;\n /** Every selected item key (assets and folders), render-order agnostic. */\n selectedKeys: Set<ItemKey>;\n /** Selected asset ids, derived from {@link selectedKeys}. */\n selectedIds: Set<number>;\n /** Selected folder ids, derived from {@link selectedKeys}. */\n selectedFolderIds: Set<number>;\n anchorKey: ItemKey | null;\n isSelected: (key: ItemKey) => boolean;\n /** Additive toggle (Cmd/Ctrl+click, item checkbox). */\n toggle: (key: ItemKey) => void;\n /** Shift+click — selects the contiguous range from the anchor to the target. */\n selectRange: (orderedKeys: ItemKey[], targetKey: ItemKey) => void;\n /** Header checkbox — selects every rendered item (folders and assets). */\n selectAll: (orderedKeys: ItemKey[]) => void;\n /**\n * Replaces the selection with this one key, as a right-click on an unselected\n * item does: what the menu then acts on is what the user can see is selected.\n */\n selectOnly: (key: ItemKey) => void;\n /** Row-level \"...\" menu — drops one key when its item leaves the list (move, delete). */\n deselect: (key: ItemKey) => void;\n /**\n * Header checkbox, when everything it covers is selected. The host decides how\n * far that reaches: the Media Library page clears the whole selection, because\n * it can still hold keys that left the list without being deselected (moved or\n * deleted from the details drawer). The picker drops only these keys.\n */\n deselectAll: (orderedKeys: ItemKey[]) => void;\n /** Close button / folder navigation / list-identity changes. */\n clear: () => void;\n}\n\n/**\n * Exported so a host with its own selection rules (the Content Manager asset\n * picker) can feed the same views a different implementation.\n */\nexport const AssetSelectionContext = createContext<AssetSelection | null>(null);\n\ninterface AssetSelectionProviderProps {\n children: ReactNode;\n /**\n * When true, selection is inert: every mutator is a no-op and nothing ever\n * reads as selected. Every bulk action is gated on `assets.update`, so a user\n * without it has nothing to select for — the views also hide the checkboxes,\n * and this makes the remaining paths (click-to-select, Space key) do nothing.\n */\n disabled?: boolean;\n}\n\nexport const AssetSelectionProvider = ({\n children,\n disabled = false,\n}: AssetSelectionProviderProps) => {\n const [state, setState] = useState<SelectionState>(createEmptySelection);\n // Every bulk action needs `assets.update`: without it the views show no\n // checkboxes, whatever the host passes as `disabled`.\n const { canUpdate } = useMediaLibraryPermissions();\n const isEnabled = !disabled && canUpdate;\n\n const isSelected = useCallback(\n (key: ItemKey) => !disabled && state.selectedKeys.has(key),\n [disabled, state.selectedKeys]\n );\n\n const toggle = useCallback(\n (key: ItemKey) => {\n if (disabled) return;\n setState((prev) => toggleSelection(prev, key));\n },\n [disabled]\n );\n\n const selectRange = useCallback(\n (orderedKeys: ItemKey[], targetKey: ItemKey) => {\n if (disabled) return;\n setState((prev) => selectRangeState(prev, orderedKeys, targetKey));\n },\n [disabled]\n );\n\n const selectAll = useCallback(\n (orderedKeys: ItemKey[]) => {\n if (disabled) return;\n setState(selectAllState(orderedKeys));\n },\n [disabled]\n );\n\n const selectOnly = useCallback(\n (key: ItemKey) => {\n if (disabled) return;\n setState(selectAllState([key]));\n },\n [disabled]\n );\n\n // No `disabled` guard, like `clear`: this only ever shrinks the selection, and a\n // disabled provider has nothing in it (every additive path is guarded).\n const deselect = useCallback((key: ItemKey) => setState((prev) => deselectState(prev, key)), []);\n\n const clear = useCallback(() => setState(clearSelection()), []);\n\n const selectedIds = useMemo(\n () => getIdsOfKind(state.selectedKeys, 'asset'),\n [state.selectedKeys]\n );\n const selectedFolderIds = useMemo(\n () => getIdsOfKind(state.selectedKeys, 'folder'),\n [state.selectedKeys]\n );\n\n const getSelectability = useCallback(\n (): Selectability => (isEnabled ? 'enabled' : 'hidden'),\n [isEnabled]\n );\n\n const value = useMemo<AssetSelection>(\n () => ({\n isEnabled,\n canSelectAll: true,\n getSelectability,\n selectedKeys: state.selectedKeys,\n selectedIds,\n selectedFolderIds,\n anchorKey: state.anchorKey,\n isSelected,\n toggle,\n selectRange,\n selectAll,\n selectOnly,\n deselect,\n deselectAll: clear,\n clear,\n }),\n [\n isEnabled,\n getSelectability,\n state.selectedKeys,\n selectedIds,\n selectedFolderIds,\n state.anchorKey,\n isSelected,\n toggle,\n selectRange,\n selectAll,\n selectOnly,\n deselect,\n clear,\n ]\n );\n\n return createElement(AssetSelectionContext.Provider, { value }, children);\n};\n\nexport const useAssetSelection = () => {\n const context = useContext(AssetSelectionContext);\n\n if (!context) {\n throw new Error('useAssetSelection must be used within an AssetSelectionProvider');\n }\n\n return context;\n};\n\nexport const useAssetSelectionOptional = () => useContext(AssetSelectionContext);\n"],"names":["AssetSelectionContext","createContext","AssetSelectionProvider","children","disabled","state","setState","useState","createEmptySelection","canUpdate","useMediaLibraryPermissions","isEnabled","isSelected","useCallback","key","selectedKeys","has","toggle","prev","toggleSelection","selectRange","orderedKeys","targetKey","selectRangeState","selectAll","selectAllState","selectOnly","deselect","deselectState","clear","clearSelection","selectedIds","useMemo","getIdsOfKind","selectedFolderIds","getSelectability","value","canSelectAll","anchorKey","deselectAll","createElement","Provider","useAssetSelection","context","useContext","Error","useAssetSelectionOptional"],"mappings":"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"}
@@ -1,9 +1,17 @@
1
- import { useState, useCallback, useMemo, createElement, createContext, useContext } from 'react';
1
+ import { createContext, useState, useCallback, useMemo, createElement, useContext } from 'react';
2
+ import { useMediaLibraryPermissions } from '../../../hooks/useMediaLibraryPermissions.mjs';
2
3
  import { createEmptySelection, toggleSelection, selectRange, selectAll, deselect, clearSelection, getIdsOfKind } from '../utils/selection.mjs';
3
4
 
4
- const AssetSelectionContext = createContext(null);
5
+ /**
6
+ * Exported so a host with its own selection rules (the Content Manager asset
7
+ * picker) can feed the same views a different implementation.
8
+ */ const AssetSelectionContext = createContext(null);
5
9
  const AssetSelectionProvider = ({ children, disabled = false })=>{
6
10
  const [state, setState] = useState(createEmptySelection);
11
+ // Every bulk action needs `assets.update`: without it the views show no
12
+ // checkboxes, whatever the host passes as `disabled`.
13
+ const { canUpdate } = useMediaLibraryPermissions();
14
+ const isEnabled = !disabled && canUpdate;
7
15
  const isSelected = useCallback((key)=>!disabled && state.selectedKeys.has(key), [
8
16
  disabled,
9
17
  state.selectedKeys
@@ -44,7 +52,13 @@ const AssetSelectionProvider = ({ children, disabled = false })=>{
44
52
  const selectedFolderIds = useMemo(()=>getIdsOfKind(state.selectedKeys, 'folder'), [
45
53
  state.selectedKeys
46
54
  ]);
55
+ const getSelectability = useCallback(()=>isEnabled ? 'enabled' : 'hidden', [
56
+ isEnabled
57
+ ]);
47
58
  const value = useMemo(()=>({
59
+ isEnabled,
60
+ canSelectAll: true,
61
+ getSelectability,
48
62
  selectedKeys: state.selectedKeys,
49
63
  selectedIds,
50
64
  selectedFolderIds,
@@ -55,8 +69,11 @@ const AssetSelectionProvider = ({ children, disabled = false })=>{
55
69
  selectAll: selectAll$1,
56
70
  selectOnly,
57
71
  deselect: deselect$1,
72
+ deselectAll: clear,
58
73
  clear
59
74
  }), [
75
+ isEnabled,
76
+ getSelectability,
60
77
  state.selectedKeys,
61
78
  selectedIds,
62
79
  selectedFolderIds,
@@ -82,5 +99,5 @@ const useAssetSelection = ()=>{
82
99
  };
83
100
  const useAssetSelectionOptional = ()=>useContext(AssetSelectionContext);
84
101
 
85
- export { AssetSelectionProvider, useAssetSelection, useAssetSelectionOptional };
102
+ export { AssetSelectionContext, AssetSelectionProvider, useAssetSelection, useAssetSelectionOptional };
86
103
  //# sourceMappingURL=useAssetSelection.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"useAssetSelection.mjs","sources":["../../../../../admin/src/pages/Assets/hooks/useAssetSelection.ts"],"sourcesContent":["import {\n createContext,\n createElement,\n useCallback,\n useContext,\n useMemo,\n useState,\n type ReactNode,\n} from 'react';\n\nimport {\n clearSelection,\n createEmptySelection,\n deselect as deselectState,\n getIdsOfKind,\n selectAll as selectAllState,\n selectRange as selectRangeState,\n toggleSelection,\n type ItemKey,\n type SelectionState,\n} from '../utils/selection';\n\n/**\n * Ephemeral, view-state-only multi-select for the future Media Library. Selection\n * is page-scoped and reset on folder navigation or sort/filter changes (the\n * table/grid toggle keeps it — same list, different presentation).\n *\n * The actual computation lives in `../utils/selection.ts` (pure + unit-tested);\n * this hook is a thin React wrapper. Assets and folders share one mechanism —\n * items are tracked as namespaced keys (`asset:1` / `folder:1`) so toggle, range\n * and select-all behave the same for both. Range / select-all receive the\n * ordered key array from the caller (the view owns the rendered order), keeping\n * the context data-source-agnostic.\n */\nexport interface AssetSelection {\n /** Every selected item key (assets and folders), render-order agnostic. */\n selectedKeys: Set<ItemKey>;\n /** Selected asset ids, derived from {@link selectedKeys}. */\n selectedIds: Set<number>;\n /** Selected folder ids, derived from {@link selectedKeys}. */\n selectedFolderIds: Set<number>;\n anchorKey: ItemKey | null;\n isSelected: (key: ItemKey) => boolean;\n /** Additive toggle (Cmd/Ctrl+click, item checkbox). */\n toggle: (key: ItemKey) => void;\n /** Shift+click — selects the contiguous range from the anchor to the target. */\n selectRange: (orderedKeys: ItemKey[], targetKey: ItemKey) => void;\n /** Header checkbox — selects every rendered item (folders and assets). */\n selectAll: (orderedKeys: ItemKey[]) => void;\n /**\n * Replaces the selection with this one key, as a right-click on an unselected\n * item does: what the menu then acts on is what the user can see is selected.\n */\n selectOnly: (key: ItemKey) => void;\n /** Row-level \"...\" menu — drops one key when its item leaves the list (move, delete). */\n deselect: (key: ItemKey) => void;\n /** Close button / folder navigation / list-identity changes. */\n clear: () => void;\n}\n\nconst AssetSelectionContext = createContext<AssetSelection | null>(null);\n\ninterface AssetSelectionProviderProps {\n children: ReactNode;\n /**\n * When true, selection is inert: every mutator is a no-op and nothing ever\n * reads as selected. Every bulk action is gated on `assets.update`, so a user\n * without it has nothing to select for — the views also hide the checkboxes,\n * and this makes the remaining paths (click-to-select, Space key) do nothing.\n */\n disabled?: boolean;\n}\n\nexport const AssetSelectionProvider = ({\n children,\n disabled = false,\n}: AssetSelectionProviderProps) => {\n const [state, setState] = useState<SelectionState>(createEmptySelection);\n\n const isSelected = useCallback(\n (key: ItemKey) => !disabled && state.selectedKeys.has(key),\n [disabled, state.selectedKeys]\n );\n\n const toggle = useCallback(\n (key: ItemKey) => {\n if (disabled) return;\n setState((prev) => toggleSelection(prev, key));\n },\n [disabled]\n );\n\n const selectRange = useCallback(\n (orderedKeys: ItemKey[], targetKey: ItemKey) => {\n if (disabled) return;\n setState((prev) => selectRangeState(prev, orderedKeys, targetKey));\n },\n [disabled]\n );\n\n const selectAll = useCallback(\n (orderedKeys: ItemKey[]) => {\n if (disabled) return;\n setState(selectAllState(orderedKeys));\n },\n [disabled]\n );\n\n const selectOnly = useCallback(\n (key: ItemKey) => {\n if (disabled) return;\n setState(selectAllState([key]));\n },\n [disabled]\n );\n\n // No `disabled` guard, like `clear`: this only ever shrinks the selection, and a\n // disabled provider has nothing in it (every additive path is guarded).\n const deselect = useCallback((key: ItemKey) => setState((prev) => deselectState(prev, key)), []);\n\n const clear = useCallback(() => setState(clearSelection()), []);\n\n const selectedIds = useMemo(\n () => getIdsOfKind(state.selectedKeys, 'asset'),\n [state.selectedKeys]\n );\n const selectedFolderIds = useMemo(\n () => getIdsOfKind(state.selectedKeys, 'folder'),\n [state.selectedKeys]\n );\n\n const value = useMemo<AssetSelection>(\n () => ({\n selectedKeys: state.selectedKeys,\n selectedIds,\n selectedFolderIds,\n anchorKey: state.anchorKey,\n isSelected,\n toggle,\n selectRange,\n selectAll,\n selectOnly,\n deselect,\n clear,\n }),\n [\n state.selectedKeys,\n selectedIds,\n selectedFolderIds,\n state.anchorKey,\n isSelected,\n toggle,\n selectRange,\n selectAll,\n selectOnly,\n deselect,\n clear,\n ]\n );\n\n return createElement(AssetSelectionContext.Provider, { value }, children);\n};\n\nexport const useAssetSelection = () => {\n const context = useContext(AssetSelectionContext);\n\n if (!context) {\n throw new Error('useAssetSelection must be used within an AssetSelectionProvider');\n }\n\n return context;\n};\n\nexport const useAssetSelectionOptional = () => useContext(AssetSelectionContext);\n"],"names":["AssetSelectionContext","createContext","AssetSelectionProvider","children","disabled","state","setState","useState","createEmptySelection","isSelected","useCallback","key","selectedKeys","has","toggle","prev","toggleSelection","selectRange","orderedKeys","targetKey","selectRangeState","selectAll","selectAllState","selectOnly","deselect","deselectState","clear","clearSelection","selectedIds","useMemo","getIdsOfKind","selectedFolderIds","value","anchorKey","createElement","Provider","useAssetSelection","context","useContext","Error","useAssetSelectionOptional"],"mappings":"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"}
1
+ {"version":3,"file":"useAssetSelection.mjs","sources":["../../../../../admin/src/pages/Assets/hooks/useAssetSelection.ts"],"sourcesContent":["import {\n createContext,\n createElement,\n useCallback,\n useContext,\n useMemo,\n useState,\n type ReactNode,\n} from 'react';\n\nimport { useMediaLibraryPermissions } from '../../../hooks/useMediaLibraryPermissions';\nimport {\n clearSelection,\n createEmptySelection,\n deselect as deselectState,\n getIdsOfKind,\n selectAll as selectAllState,\n selectRange as selectRangeState,\n toggleSelection,\n type ItemKey,\n type SelectionState,\n} from '../utils/selection';\n\n/**\n * Ephemeral, view-state-only multi-select for the future Media Library. Selection\n * is page-scoped and reset on folder navigation or sort/filter changes (the\n * table/grid toggle keeps it — same list, different presentation).\n *\n * The actual computation lives in `../utils/selection.ts` (pure + unit-tested);\n * this hook is a thin React wrapper. Assets and folders share one mechanism —\n * items are tracked as namespaced keys (`asset:1` / `folder:1`) so toggle, range\n * and select-all behave the same for both. Range / select-all receive the\n * ordered key array from the caller (the view owns the rendered order), keeping\n * the context data-source-agnostic.\n */\n/**\n * How an item takes part in selection: `enabled` shows a working checkbox,\n * `disabled` shows it greyed out (the item cannot be chosen here), `hidden`\n * shows none (the item is not something this selection is about).\n */\nexport type Selectability = 'enabled' | 'disabled' | 'hidden';\n\nexport interface AssetSelection {\n /**\n * Whether selection is on at all. Views show the checkbox column and\n * select-all only when it is.\n */\n isEnabled: boolean;\n /** Whether the table offers a select-all header (not on a single-value picker). */\n canSelectAll: boolean;\n getSelectability: (key: ItemKey) => Selectability;\n /** Every selected item key (assets and folders), render-order agnostic. */\n selectedKeys: Set<ItemKey>;\n /** Selected asset ids, derived from {@link selectedKeys}. */\n selectedIds: Set<number>;\n /** Selected folder ids, derived from {@link selectedKeys}. */\n selectedFolderIds: Set<number>;\n anchorKey: ItemKey | null;\n isSelected: (key: ItemKey) => boolean;\n /** Additive toggle (Cmd/Ctrl+click, item checkbox). */\n toggle: (key: ItemKey) => void;\n /** Shift+click — selects the contiguous range from the anchor to the target. */\n selectRange: (orderedKeys: ItemKey[], targetKey: ItemKey) => void;\n /** Header checkbox — selects every rendered item (folders and assets). */\n selectAll: (orderedKeys: ItemKey[]) => void;\n /**\n * Replaces the selection with this one key, as a right-click on an unselected\n * item does: what the menu then acts on is what the user can see is selected.\n */\n selectOnly: (key: ItemKey) => void;\n /** Row-level \"...\" menu — drops one key when its item leaves the list (move, delete). */\n deselect: (key: ItemKey) => void;\n /**\n * Header checkbox, when everything it covers is selected. The host decides how\n * far that reaches: the Media Library page clears the whole selection, because\n * it can still hold keys that left the list without being deselected (moved or\n * deleted from the details drawer). The picker drops only these keys.\n */\n deselectAll: (orderedKeys: ItemKey[]) => void;\n /** Close button / folder navigation / list-identity changes. */\n clear: () => void;\n}\n\n/**\n * Exported so a host with its own selection rules (the Content Manager asset\n * picker) can feed the same views a different implementation.\n */\nexport const AssetSelectionContext = createContext<AssetSelection | null>(null);\n\ninterface AssetSelectionProviderProps {\n children: ReactNode;\n /**\n * When true, selection is inert: every mutator is a no-op and nothing ever\n * reads as selected. Every bulk action is gated on `assets.update`, so a user\n * without it has nothing to select for — the views also hide the checkboxes,\n * and this makes the remaining paths (click-to-select, Space key) do nothing.\n */\n disabled?: boolean;\n}\n\nexport const AssetSelectionProvider = ({\n children,\n disabled = false,\n}: AssetSelectionProviderProps) => {\n const [state, setState] = useState<SelectionState>(createEmptySelection);\n // Every bulk action needs `assets.update`: without it the views show no\n // checkboxes, whatever the host passes as `disabled`.\n const { canUpdate } = useMediaLibraryPermissions();\n const isEnabled = !disabled && canUpdate;\n\n const isSelected = useCallback(\n (key: ItemKey) => !disabled && state.selectedKeys.has(key),\n [disabled, state.selectedKeys]\n );\n\n const toggle = useCallback(\n (key: ItemKey) => {\n if (disabled) return;\n setState((prev) => toggleSelection(prev, key));\n },\n [disabled]\n );\n\n const selectRange = useCallback(\n (orderedKeys: ItemKey[], targetKey: ItemKey) => {\n if (disabled) return;\n setState((prev) => selectRangeState(prev, orderedKeys, targetKey));\n },\n [disabled]\n );\n\n const selectAll = useCallback(\n (orderedKeys: ItemKey[]) => {\n if (disabled) return;\n setState(selectAllState(orderedKeys));\n },\n [disabled]\n );\n\n const selectOnly = useCallback(\n (key: ItemKey) => {\n if (disabled) return;\n setState(selectAllState([key]));\n },\n [disabled]\n );\n\n // No `disabled` guard, like `clear`: this only ever shrinks the selection, and a\n // disabled provider has nothing in it (every additive path is guarded).\n const deselect = useCallback((key: ItemKey) => setState((prev) => deselectState(prev, key)), []);\n\n const clear = useCallback(() => setState(clearSelection()), []);\n\n const selectedIds = useMemo(\n () => getIdsOfKind(state.selectedKeys, 'asset'),\n [state.selectedKeys]\n );\n const selectedFolderIds = useMemo(\n () => getIdsOfKind(state.selectedKeys, 'folder'),\n [state.selectedKeys]\n );\n\n const getSelectability = useCallback(\n (): Selectability => (isEnabled ? 'enabled' : 'hidden'),\n [isEnabled]\n );\n\n const value = useMemo<AssetSelection>(\n () => ({\n isEnabled,\n canSelectAll: true,\n getSelectability,\n selectedKeys: state.selectedKeys,\n selectedIds,\n selectedFolderIds,\n anchorKey: state.anchorKey,\n isSelected,\n toggle,\n selectRange,\n selectAll,\n selectOnly,\n deselect,\n deselectAll: clear,\n clear,\n }),\n [\n isEnabled,\n getSelectability,\n state.selectedKeys,\n selectedIds,\n selectedFolderIds,\n state.anchorKey,\n isSelected,\n toggle,\n selectRange,\n selectAll,\n selectOnly,\n deselect,\n clear,\n ]\n );\n\n return createElement(AssetSelectionContext.Provider, { value }, children);\n};\n\nexport const useAssetSelection = () => {\n const context = useContext(AssetSelectionContext);\n\n if (!context) {\n throw new Error('useAssetSelection must be used within an AssetSelectionProvider');\n }\n\n return context;\n};\n\nexport const useAssetSelectionOptional = () => useContext(AssetSelectionContext);\n"],"names":["AssetSelectionContext","createContext","AssetSelectionProvider","children","disabled","state","setState","useState","createEmptySelection","canUpdate","useMediaLibraryPermissions","isEnabled","isSelected","useCallback","key","selectedKeys","has","toggle","prev","toggleSelection","selectRange","orderedKeys","targetKey","selectRangeState","selectAll","selectAllState","selectOnly","deselect","deselectState","clear","clearSelection","selectedIds","useMemo","getIdsOfKind","selectedFolderIds","getSelectability","value","canSelectAll","anchorKey","deselectAll","createElement","Provider","useAssetSelection","context","useContext","Error","useAssetSelectionOptional"],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+ var folders = require('../../../services/folders.js');
5
+ var buildAssetFilters = require('../utils/buildAssetFilters.js');
6
+ var useAssetSearch = require('./useAssetSearch.js');
7
+ var useFolderNavigation = require('./useFolderNavigation.js');
8
+ var useInfiniteAssets = require('./useInfiniteAssets.js');
9
+ var useListFilters = require('./useListFilters.js');
10
+ var useListSort = require('./useListSort.js');
11
+
12
+ /**
13
+ * The list behind the Media Library page and the Content Manager asset picker:
14
+ * the current folder, search, sort and filters, and the folders and assets they
15
+ * select. Where that query state lives (URL or memory) is decided by
16
+ * `ListQueryStateProvider`, not here.
17
+ */ const useAssetsList = ()=>{
18
+ const folderNavigation = useFolderNavigation.useFolderNavigation();
19
+ const { currentFolderId, navigateToRoot } = folderNavigation;
20
+ // Deleted or missing folders (404) need a fetch — handled here, not in
21
+ // `useFolderNavigation` (which only strips malformed ?folder= values).
22
+ const { error: currentFolderError } = folders.useGetFolderQuery({
23
+ id: currentFolderId
24
+ }, {
25
+ skip: currentFolderId === null
26
+ });
27
+ React.useEffect(()=>{
28
+ if (currentFolderError?.name === 'NotFoundError') {
29
+ navigateToRoot();
30
+ }
31
+ }, [
32
+ currentFolderError,
33
+ navigateToRoot
34
+ ]);
35
+ const assetSearch = useAssetSearch.useAssetSearch();
36
+ const { searchQuery } = assetSearch;
37
+ const listSort = useListSort.useListSort();
38
+ const listFilters = useListFilters.useListFilters();
39
+ // Resolve relative presets against "now" only when the filters change —
40
+ // keeps the query args (and RTK cache keys) stable between renders.
41
+ const builtFilters = React.useMemo(()=>buildAssetFilters.buildAssetFilters(listFilters.filters, new Date()), // eslint-disable-next-line react-hooks/exhaustive-deps -- serialized is the value identity of filters
42
+ [
43
+ listFilters.serialized
44
+ ]);
45
+ const { assets, subscribers, pagination, isLoading: isLoadingAssets, isFetchingMore, hasNextPage, fetchNextPage, error: assetsError } = useInfiniteAssets.useInfiniteAssets({
46
+ // The real folder is passed even while searching: the service drops the folder
47
+ // filter when `search` is set, so results are still global. List filters
48
+ // compose with both modes.
49
+ folder: currentFolderId,
50
+ search: searchQuery || undefined,
51
+ sort: listSort.assetsSort,
52
+ filters: builtFilters.fileClauses,
53
+ enabled: builtFilters.showFiles
54
+ });
55
+ const { data: fetchedFolders = [], isLoading: isLoadingFolders } = folders.useGetFoldersQuery({
56
+ parentId: currentFolderId,
57
+ search: searchQuery || undefined,
58
+ sort: listSort.foldersSort,
59
+ filters: builtFilters.folderClauses
60
+ }, {
61
+ skip: !builtFilters.showFolders
62
+ });
63
+ // A type badge can exclude folders structurally (e.g. "Type is Picture").
64
+ const folders$1 = React.useMemo(()=>builtFilters.showFolders ? fetchedFolders : [], [
65
+ builtFilters.showFolders,
66
+ fetchedFolders
67
+ ]);
68
+ return {
69
+ ...folderNavigation,
70
+ ...assetSearch,
71
+ listSort,
72
+ listFilters,
73
+ assets,
74
+ subscribers,
75
+ pagination,
76
+ isLoadingAssets,
77
+ isFetchingMore,
78
+ hasNextPage,
79
+ fetchNextPage,
80
+ assetsError,
81
+ folders: folders$1,
82
+ isLoadingFolders
83
+ };
84
+ };
85
+
86
+ exports.useAssetsList = useAssetsList;
87
+ //# sourceMappingURL=useAssetsList.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAssetsList.js","sources":["../../../../../admin/src/pages/Assets/hooks/useAssetsList.ts"],"sourcesContent":["import { useEffect, useMemo } from 'react';\n\nimport { useGetFolderQuery, useGetFoldersQuery } from '../../../services/folders';\nimport { buildAssetFilters } from '../utils/buildAssetFilters';\n\nimport { useAssetSearch } from './useAssetSearch';\nimport { useFolderNavigation } from './useFolderNavigation';\nimport { useInfiniteAssets } from './useInfiniteAssets';\nimport { useListFilters } from './useListFilters';\nimport { useListSort } from './useListSort';\n\n/**\n * The list behind the Media Library page and the Content Manager asset picker:\n * the current folder, search, sort and filters, and the folders and assets they\n * select. Where that query state lives (URL or memory) is decided by\n * `ListQueryStateProvider`, not here.\n */\nexport const useAssetsList = () => {\n const folderNavigation = useFolderNavigation();\n const { currentFolderId, navigateToRoot } = folderNavigation;\n\n // Deleted or missing folders (404) need a fetch — handled here, not in\n // `useFolderNavigation` (which only strips malformed ?folder= values).\n const { error: currentFolderError } = useGetFolderQuery(\n { id: currentFolderId! },\n { skip: currentFolderId === null }\n );\n\n useEffect(() => {\n if (currentFolderError?.name === 'NotFoundError') {\n navigateToRoot();\n }\n }, [currentFolderError, navigateToRoot]);\n\n const assetSearch = useAssetSearch();\n const { searchQuery } = assetSearch;\n const listSort = useListSort();\n const listFilters = useListFilters();\n\n // Resolve relative presets against \"now\" only when the filters change —\n // keeps the query args (and RTK cache keys) stable between renders.\n const builtFilters = useMemo(\n () => buildAssetFilters(listFilters.filters, new Date()),\n // eslint-disable-next-line react-hooks/exhaustive-deps -- serialized is the value identity of filters\n [listFilters.serialized]\n );\n\n const {\n assets,\n subscribers,\n pagination,\n isLoading: isLoadingAssets,\n isFetchingMore,\n hasNextPage,\n fetchNextPage,\n error: assetsError,\n } = useInfiniteAssets({\n // The real folder is passed even while searching: the service drops the folder\n // filter when `search` is set, so results are still global. List filters\n // compose with both modes.\n folder: currentFolderId,\n search: searchQuery || undefined,\n sort: listSort.assetsSort,\n filters: builtFilters.fileClauses,\n enabled: builtFilters.showFiles,\n });\n\n const { data: fetchedFolders = [], isLoading: isLoadingFolders } = useGetFoldersQuery(\n {\n parentId: currentFolderId,\n search: searchQuery || undefined,\n sort: listSort.foldersSort,\n filters: builtFilters.folderClauses,\n },\n { skip: !builtFilters.showFolders }\n );\n // A type badge can exclude folders structurally (e.g. \"Type is Picture\").\n const folders = useMemo(\n () => (builtFilters.showFolders ? fetchedFolders : []),\n [builtFilters.showFolders, fetchedFolders]\n );\n\n return {\n ...folderNavigation,\n ...assetSearch,\n listSort,\n listFilters,\n assets,\n subscribers,\n pagination,\n isLoadingAssets,\n isFetchingMore,\n hasNextPage,\n fetchNextPage,\n assetsError,\n folders,\n isLoadingFolders,\n };\n};\n"],"names":["useAssetsList","folderNavigation","useFolderNavigation","currentFolderId","navigateToRoot","error","currentFolderError","useGetFolderQuery","id","skip","useEffect","name","assetSearch","useAssetSearch","searchQuery","listSort","useListSort","listFilters","useListFilters","builtFilters","useMemo","buildAssetFilters","filters","Date","serialized","assets","subscribers","pagination","isLoading","isLoadingAssets","isFetchingMore","hasNextPage","fetchNextPage","assetsError","useInfiniteAssets","folder","search","undefined","sort","assetsSort","fileClauses","enabled","showFiles","data","fetchedFolders","isLoadingFolders","useGetFoldersQuery","parentId","foldersSort","folderClauses","showFolders","folders"],"mappings":";;;;;;;;;;;AAWA;;;;;UAMaA,aAAAA,GAAgB,IAAA;AAC3B,IAAA,MAAMC,gBAAAA,GAAmBC,uCAAAA,EAAAA;AACzB,IAAA,MAAM,EAAEC,eAAe,EAAEC,cAAc,EAAE,GAAGH,gBAAAA;;;AAI5C,IAAA,MAAM,EAAEI,KAAAA,EAAOC,kBAAkB,EAAE,GAAGC,yBAAAA,CACpC;QAAEC,EAAAA,EAAIL;KAAiB,EACvB;AAAEM,QAAAA,IAAAA,EAAMN,eAAAA,KAAoB;AAAK,KAAA,CAAA;IAGnCO,eAAAA,CAAU,IAAA;QACR,IAAIJ,kBAAAA,EAAoBK,SAAS,eAAA,EAAiB;AAChDP,YAAAA,cAAAA,EAAAA;AACF,QAAA;IACF,CAAA,EAAG;AAACE,QAAAA,kBAAAA;AAAoBF,QAAAA;AAAe,KAAA,CAAA;AAEvC,IAAA,MAAMQ,WAAAA,GAAcC,6BAAAA,EAAAA;IACpB,MAAM,EAAEC,WAAW,EAAE,GAAGF,WAAAA;AACxB,IAAA,MAAMG,QAAAA,GAAWC,uBAAAA,EAAAA;AACjB,IAAA,MAAMC,WAAAA,GAAcC,6BAAAA,EAAAA;;;IAIpB,MAAMC,YAAAA,GAAeC,cACnB,IAAMC,mCAAAA,CAAkBJ,YAAYK,OAAO,EAAE,IAAIC,IAAAA,EAAAA,CAAAA;AAEjD,IAAA;AAACN,QAAAA,WAAAA,CAAYO;AAAW,KAAA,CAAA;IAG1B,MAAM,EACJC,MAAM,EACNC,WAAW,EACXC,UAAU,EACVC,WAAWC,eAAe,EAC1BC,cAAc,EACdC,WAAW,EACXC,aAAa,EACb3B,OAAO4B,WAAW,EACnB,GAAGC,mCAAAA,CAAkB;;;;QAIpBC,MAAAA,EAAQhC,eAAAA;AACRiC,QAAAA,MAAAA,EAAQtB,WAAAA,IAAeuB,SAAAA;AACvBC,QAAAA,IAAAA,EAAMvB,SAASwB,UAAU;AACzBjB,QAAAA,OAAAA,EAASH,aAAaqB,WAAW;AACjCC,QAAAA,OAAAA,EAAStB,aAAauB;AACxB,KAAA,CAAA;IAEA,MAAM,EAAEC,MAAMC,cAAAA,GAAiB,EAAE,EAAEhB,SAAAA,EAAWiB,gBAAgB,EAAE,GAAGC,0BAAAA,CACjE;QACEC,QAAAA,EAAU5C,eAAAA;AACViC,QAAAA,MAAAA,EAAQtB,WAAAA,IAAeuB,SAAAA;AACvBC,QAAAA,IAAAA,EAAMvB,SAASiC,WAAW;AAC1B1B,QAAAA,OAAAA,EAASH,aAAa8B;KACxB,EACA;QAAExC,IAAAA,EAAM,CAACU,aAAa+B;AAAY,KAAA,CAAA;;IAGpC,MAAMC,SAAAA,GAAU/B,cACd,IAAOD,YAAAA,CAAa+B,WAAW,GAAGN,cAAAA,GAAiB,EAAE,EACrD;AAACzB,QAAAA,YAAAA,CAAa+B,WAAW;AAAEN,QAAAA;AAAe,KAAA,CAAA;IAG5C,OAAO;AACL,QAAA,GAAG3C,gBAAgB;AACnB,QAAA,GAAGW,WAAW;AACdG,QAAAA,QAAAA;AACAE,QAAAA,WAAAA;AACAQ,QAAAA,MAAAA;AACAC,QAAAA,WAAAA;AACAC,QAAAA,UAAAA;AACAE,QAAAA,eAAAA;AACAC,QAAAA,cAAAA;AACAC,QAAAA,WAAAA;AACAC,QAAAA,aAAAA;AACAC,QAAAA,WAAAA;AACAkB,iBAAAA,SAAAA;AACAN,QAAAA;AACF,KAAA;AACF;;;;"}
@@ -0,0 +1,85 @@
1
+ import { useEffect, useMemo } from 'react';
2
+ import { useGetFolderQuery, useGetFoldersQuery } from '../../../services/folders.mjs';
3
+ import { buildAssetFilters } from '../utils/buildAssetFilters.mjs';
4
+ import { useAssetSearch } from './useAssetSearch.mjs';
5
+ import { useFolderNavigation } from './useFolderNavigation.mjs';
6
+ import { useInfiniteAssets } from './useInfiniteAssets.mjs';
7
+ import { useListFilters } from './useListFilters.mjs';
8
+ import { useListSort } from './useListSort.mjs';
9
+
10
+ /**
11
+ * The list behind the Media Library page and the Content Manager asset picker:
12
+ * the current folder, search, sort and filters, and the folders and assets they
13
+ * select. Where that query state lives (URL or memory) is decided by
14
+ * `ListQueryStateProvider`, not here.
15
+ */ const useAssetsList = ()=>{
16
+ const folderNavigation = useFolderNavigation();
17
+ const { currentFolderId, navigateToRoot } = folderNavigation;
18
+ // Deleted or missing folders (404) need a fetch — handled here, not in
19
+ // `useFolderNavigation` (which only strips malformed ?folder= values).
20
+ const { error: currentFolderError } = useGetFolderQuery({
21
+ id: currentFolderId
22
+ }, {
23
+ skip: currentFolderId === null
24
+ });
25
+ useEffect(()=>{
26
+ if (currentFolderError?.name === 'NotFoundError') {
27
+ navigateToRoot();
28
+ }
29
+ }, [
30
+ currentFolderError,
31
+ navigateToRoot
32
+ ]);
33
+ const assetSearch = useAssetSearch();
34
+ const { searchQuery } = assetSearch;
35
+ const listSort = useListSort();
36
+ const listFilters = useListFilters();
37
+ // Resolve relative presets against "now" only when the filters change —
38
+ // keeps the query args (and RTK cache keys) stable between renders.
39
+ const builtFilters = useMemo(()=>buildAssetFilters(listFilters.filters, new Date()), // eslint-disable-next-line react-hooks/exhaustive-deps -- serialized is the value identity of filters
40
+ [
41
+ listFilters.serialized
42
+ ]);
43
+ const { assets, subscribers, pagination, isLoading: isLoadingAssets, isFetchingMore, hasNextPage, fetchNextPage, error: assetsError } = useInfiniteAssets({
44
+ // The real folder is passed even while searching: the service drops the folder
45
+ // filter when `search` is set, so results are still global. List filters
46
+ // compose with both modes.
47
+ folder: currentFolderId,
48
+ search: searchQuery || undefined,
49
+ sort: listSort.assetsSort,
50
+ filters: builtFilters.fileClauses,
51
+ enabled: builtFilters.showFiles
52
+ });
53
+ const { data: fetchedFolders = [], isLoading: isLoadingFolders } = useGetFoldersQuery({
54
+ parentId: currentFolderId,
55
+ search: searchQuery || undefined,
56
+ sort: listSort.foldersSort,
57
+ filters: builtFilters.folderClauses
58
+ }, {
59
+ skip: !builtFilters.showFolders
60
+ });
61
+ // A type badge can exclude folders structurally (e.g. "Type is Picture").
62
+ const folders = useMemo(()=>builtFilters.showFolders ? fetchedFolders : [], [
63
+ builtFilters.showFolders,
64
+ fetchedFolders
65
+ ]);
66
+ return {
67
+ ...folderNavigation,
68
+ ...assetSearch,
69
+ listSort,
70
+ listFilters,
71
+ assets,
72
+ subscribers,
73
+ pagination,
74
+ isLoadingAssets,
75
+ isFetchingMore,
76
+ hasNextPage,
77
+ fetchNextPage,
78
+ assetsError,
79
+ folders,
80
+ isLoadingFolders
81
+ };
82
+ };
83
+
84
+ export { useAssetsList };
85
+ //# sourceMappingURL=useAssetsList.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAssetsList.mjs","sources":["../../../../../admin/src/pages/Assets/hooks/useAssetsList.ts"],"sourcesContent":["import { useEffect, useMemo } from 'react';\n\nimport { useGetFolderQuery, useGetFoldersQuery } from '../../../services/folders';\nimport { buildAssetFilters } from '../utils/buildAssetFilters';\n\nimport { useAssetSearch } from './useAssetSearch';\nimport { useFolderNavigation } from './useFolderNavigation';\nimport { useInfiniteAssets } from './useInfiniteAssets';\nimport { useListFilters } from './useListFilters';\nimport { useListSort } from './useListSort';\n\n/**\n * The list behind the Media Library page and the Content Manager asset picker:\n * the current folder, search, sort and filters, and the folders and assets they\n * select. Where that query state lives (URL or memory) is decided by\n * `ListQueryStateProvider`, not here.\n */\nexport const useAssetsList = () => {\n const folderNavigation = useFolderNavigation();\n const { currentFolderId, navigateToRoot } = folderNavigation;\n\n // Deleted or missing folders (404) need a fetch — handled here, not in\n // `useFolderNavigation` (which only strips malformed ?folder= values).\n const { error: currentFolderError } = useGetFolderQuery(\n { id: currentFolderId! },\n { skip: currentFolderId === null }\n );\n\n useEffect(() => {\n if (currentFolderError?.name === 'NotFoundError') {\n navigateToRoot();\n }\n }, [currentFolderError, navigateToRoot]);\n\n const assetSearch = useAssetSearch();\n const { searchQuery } = assetSearch;\n const listSort = useListSort();\n const listFilters = useListFilters();\n\n // Resolve relative presets against \"now\" only when the filters change —\n // keeps the query args (and RTK cache keys) stable between renders.\n const builtFilters = useMemo(\n () => buildAssetFilters(listFilters.filters, new Date()),\n // eslint-disable-next-line react-hooks/exhaustive-deps -- serialized is the value identity of filters\n [listFilters.serialized]\n );\n\n const {\n assets,\n subscribers,\n pagination,\n isLoading: isLoadingAssets,\n isFetchingMore,\n hasNextPage,\n fetchNextPage,\n error: assetsError,\n } = useInfiniteAssets({\n // The real folder is passed even while searching: the service drops the folder\n // filter when `search` is set, so results are still global. List filters\n // compose with both modes.\n folder: currentFolderId,\n search: searchQuery || undefined,\n sort: listSort.assetsSort,\n filters: builtFilters.fileClauses,\n enabled: builtFilters.showFiles,\n });\n\n const { data: fetchedFolders = [], isLoading: isLoadingFolders } = useGetFoldersQuery(\n {\n parentId: currentFolderId,\n search: searchQuery || undefined,\n sort: listSort.foldersSort,\n filters: builtFilters.folderClauses,\n },\n { skip: !builtFilters.showFolders }\n );\n // A type badge can exclude folders structurally (e.g. \"Type is Picture\").\n const folders = useMemo(\n () => (builtFilters.showFolders ? fetchedFolders : []),\n [builtFilters.showFolders, fetchedFolders]\n );\n\n return {\n ...folderNavigation,\n ...assetSearch,\n listSort,\n listFilters,\n assets,\n subscribers,\n pagination,\n isLoadingAssets,\n isFetchingMore,\n hasNextPage,\n fetchNextPage,\n assetsError,\n folders,\n isLoadingFolders,\n };\n};\n"],"names":["useAssetsList","folderNavigation","useFolderNavigation","currentFolderId","navigateToRoot","error","currentFolderError","useGetFolderQuery","id","skip","useEffect","name","assetSearch","useAssetSearch","searchQuery","listSort","useListSort","listFilters","useListFilters","builtFilters","useMemo","buildAssetFilters","filters","Date","serialized","assets","subscribers","pagination","isLoading","isLoadingAssets","isFetchingMore","hasNextPage","fetchNextPage","assetsError","useInfiniteAssets","folder","search","undefined","sort","assetsSort","fileClauses","enabled","showFiles","data","fetchedFolders","isLoadingFolders","useGetFoldersQuery","parentId","foldersSort","folderClauses","showFolders","folders"],"mappings":";;;;;;;;;AAWA;;;;;UAMaA,aAAAA,GAAgB,IAAA;AAC3B,IAAA,MAAMC,gBAAAA,GAAmBC,mBAAAA,EAAAA;AACzB,IAAA,MAAM,EAAEC,eAAe,EAAEC,cAAc,EAAE,GAAGH,gBAAAA;;;AAI5C,IAAA,MAAM,EAAEI,KAAAA,EAAOC,kBAAkB,EAAE,GAAGC,iBAAAA,CACpC;QAAEC,EAAAA,EAAIL;KAAiB,EACvB;AAAEM,QAAAA,IAAAA,EAAMN,eAAAA,KAAoB;AAAK,KAAA,CAAA;IAGnCO,SAAAA,CAAU,IAAA;QACR,IAAIJ,kBAAAA,EAAoBK,SAAS,eAAA,EAAiB;AAChDP,YAAAA,cAAAA,EAAAA;AACF,QAAA;IACF,CAAA,EAAG;AAACE,QAAAA,kBAAAA;AAAoBF,QAAAA;AAAe,KAAA,CAAA;AAEvC,IAAA,MAAMQ,WAAAA,GAAcC,cAAAA,EAAAA;IACpB,MAAM,EAAEC,WAAW,EAAE,GAAGF,WAAAA;AACxB,IAAA,MAAMG,QAAAA,GAAWC,WAAAA,EAAAA;AACjB,IAAA,MAAMC,WAAAA,GAAcC,cAAAA,EAAAA;;;IAIpB,MAAMC,YAAAA,GAAeC,QACnB,IAAMC,iBAAAA,CAAkBJ,YAAYK,OAAO,EAAE,IAAIC,IAAAA,EAAAA,CAAAA;AAEjD,IAAA;AAACN,QAAAA,WAAAA,CAAYO;AAAW,KAAA,CAAA;IAG1B,MAAM,EACJC,MAAM,EACNC,WAAW,EACXC,UAAU,EACVC,WAAWC,eAAe,EAC1BC,cAAc,EACdC,WAAW,EACXC,aAAa,EACb3B,OAAO4B,WAAW,EACnB,GAAGC,iBAAAA,CAAkB;;;;QAIpBC,MAAAA,EAAQhC,eAAAA;AACRiC,QAAAA,MAAAA,EAAQtB,WAAAA,IAAeuB,SAAAA;AACvBC,QAAAA,IAAAA,EAAMvB,SAASwB,UAAU;AACzBjB,QAAAA,OAAAA,EAASH,aAAaqB,WAAW;AACjCC,QAAAA,OAAAA,EAAStB,aAAauB;AACxB,KAAA,CAAA;IAEA,MAAM,EAAEC,MAAMC,cAAAA,GAAiB,EAAE,EAAEhB,SAAAA,EAAWiB,gBAAgB,EAAE,GAAGC,kBAAAA,CACjE;QACEC,QAAAA,EAAU5C,eAAAA;AACViC,QAAAA,MAAAA,EAAQtB,WAAAA,IAAeuB,SAAAA;AACvBC,QAAAA,IAAAA,EAAMvB,SAASiC,WAAW;AAC1B1B,QAAAA,OAAAA,EAASH,aAAa8B;KACxB,EACA;QAAExC,IAAAA,EAAM,CAACU,aAAa+B;AAAY,KAAA,CAAA;;IAGpC,MAAMC,OAAAA,GAAU/B,QACd,IAAOD,YAAAA,CAAa+B,WAAW,GAAGN,cAAAA,GAAiB,EAAE,EACrD;AAACzB,QAAAA,YAAAA,CAAa+B,WAAW;AAAEN,QAAAA;AAAe,KAAA,CAAA;IAG5C,OAAO;AACL,QAAA,GAAG3C,gBAAgB;AACnB,QAAA,GAAGW,WAAW;AACdG,QAAAA,QAAAA;AACAE,QAAAA,WAAAA;AACAQ,QAAAA,MAAAA;AACAC,QAAAA,WAAAA;AACAC,QAAAA,UAAAA;AACAE,QAAAA,eAAAA;AACAC,QAAAA,cAAAA;AACAC,QAAAA,WAAAA;AACAC,QAAAA,aAAAA;AACAC,QAAAA,WAAAA;AACAkB,QAAAA,OAAAA;AACAN,QAAAA;AACF,KAAA;AACF;;;;"}
@@ -1,4 +1,4 @@
1
- import { useState, useCallback, useMemo, createElement, createContext, useContext } from 'react';
1
+ import { createContext, useState, useCallback, useMemo, createElement, useContext } from 'react';
2
2
 
3
3
  const BusyAssetsContext = createContext(null);
4
4
  const BusyAssetsProvider = ({ children })=>{
@@ -2,6 +2,7 @@
2
2
 
3
3
  var React = require('react');
4
4
  var strapiAdmin = require('@strapi/admin/strapi-admin');
5
+ var useListQueryParams = require('./useListQueryParams.js');
5
6
 
6
7
  const parseFolderIdFromQuery = (folder)=>{
7
8
  if (!folder) {
@@ -11,7 +12,7 @@ const parseFolderIdFromQuery = (folder)=>{
11
12
  return Number.isFinite(id) ? id : null;
12
13
  };
13
14
  const useFolderNavigation = ()=>{
14
- const [{ query }, setQuery] = strapiAdmin.useQueryParams();
15
+ const [{ query }, setQuery] = useListQueryParams.useListQueryParams();
15
16
  const currentFolderId = parseFolderIdFromQuery(query?.folder);
16
17
  /**
17
18
  * Asset search is global, so keeping `_q` after a folder navigation would show
@@ -1 +1 @@
1
- {"version":3,"file":"useFolderNavigation.js","sources":["../../../../../admin/src/pages/Assets/hooks/useFolderNavigation.ts"],"sourcesContent":["import { useCallback, useEffect } from 'react';\n\nimport { useQueryParams, withEncodedUserParams } from '@strapi/admin/strapi-admin';\n\nimport type { Folder } from '../../../../../shared/contracts/folders';\n\nconst parseFolderIdFromQuery = (folder: string | undefined): number | null => {\n if (!folder) {\n return null;\n }\n\n const id = Number(folder);\n\n return Number.isFinite(id) ? id : null;\n};\n\ninterface FolderNavigationQuery {\n folder?: string;\n _q?: string;\n}\n\nexport const useFolderNavigation = () => {\n const [{ query }, setQuery] = useQueryParams<FolderNavigationQuery>();\n\n const currentFolderId = parseFolderIdFromQuery(query?.folder);\n\n /**\n * Asset search is global, so keeping `_q` after a folder navigation would show\n * byte-identical results and make the navigation look broken. Clearing it here\n * — rather than at each call site — means no caller can forget.\n */\n const navigateToFolder = useCallback(\n (folder: Folder) => {\n setQuery({ folder: String(folder.id), _q: undefined });\n },\n [setQuery]\n );\n\n /**\n * Move to the Media Library root by removing the `folder` query param, and the\n * search term with it. `setQuery(_, 'remove')` deletes the keys present on the\n * first argument (values are ignored) in one navigation, so any other query\n * state (pagination, the details drawer, etc.) is preserved.\n */\n const navigateToRoot = useCallback(() => {\n setQuery({ folder: '', _q: '' }, 'remove');\n }, [setQuery]);\n\n /**\n * Strips a `?folder=` value we can't parse.\n */\n const stripFolderParam = useCallback(() => {\n setQuery(withEncodedUserParams(query, { folder: undefined }));\n }, [query, setQuery]);\n\n // Malformed ?folder= values (e.g. abc) parse as null; strip the param from the URL.\n // Deleted/missing folders (404) are handled in AssetsPage — that needs a fetch.\n useEffect(() => {\n if (query?.folder && currentFolderId === null) {\n stripFolderParam();\n }\n }, [query?.folder, currentFolderId, stripFolderParam]);\n\n /**\n * Convenience for the FolderTree sidebar: a single entry point that handles\n * both \"go home\" and \"go to folder X\" without forcing the caller to know\n * whether to call navigateToFolder or navigateToRoot.\n */\n const navigateToFolderId = useCallback(\n (folderId: number | null) => {\n if (folderId == null) {\n navigateToRoot();\n } else {\n setQuery({ folder: String(folderId), _q: undefined });\n }\n },\n [navigateToRoot, setQuery]\n );\n\n return {\n currentFolderId,\n navigateToFolder,\n navigateToRoot,\n navigateToFolderId,\n };\n};\n"],"names":["parseFolderIdFromQuery","folder","id","Number","isFinite","useFolderNavigation","query","setQuery","useQueryParams","currentFolderId","navigateToFolder","useCallback","String","_q","undefined","navigateToRoot","stripFolderParam","withEncodedUserParams","useEffect","navigateToFolderId","folderId"],"mappings":";;;;;AAMA,MAAMA,yBAAyB,CAACC,MAAAA,GAAAA;AAC9B,IAAA,IAAI,CAACA,MAAAA,EAAQ;QACX,OAAO,IAAA;AACT,IAAA;AAEA,IAAA,MAAMC,KAAKC,MAAAA,CAAOF,MAAAA,CAAAA;AAElB,IAAA,OAAOE,MAAAA,CAAOC,QAAQ,CAACF,EAAAA,CAAAA,GAAMA,EAAAA,GAAK,IAAA;AACpC,CAAA;MAOaG,mBAAAA,GAAsB,IAAA;AACjC,IAAA,MAAM,CAAC,EAAEC,KAAK,EAAE,EAAEC,SAAS,GAAGC,0BAAAA,EAAAA;IAE9B,MAAMC,eAAAA,GAAkBT,uBAAuBM,KAAAA,EAAOL,MAAAA,CAAAA;AAEtD;;;;MAKA,MAAMS,gBAAAA,GAAmBC,iBAAAA,CACvB,CAACV,MAAAA,GAAAA;QACCM,QAAAA,CAAS;YAAEN,MAAAA,EAAQW,MAAAA,CAAOX,OAAOC,EAAE,CAAA;YAAGW,EAAAA,EAAIC;AAAU,SAAA,CAAA;IACtD,CAAA,EACA;AAACP,QAAAA;AAAS,KAAA,CAAA;AAGZ;;;;;MAMA,MAAMQ,iBAAiBJ,iBAAAA,CAAY,IAAA;QACjCJ,QAAAA,CAAS;YAAEN,MAAAA,EAAQ,EAAA;YAAIY,EAAAA,EAAI;SAAG,EAAG,QAAA,CAAA;IACnC,CAAA,EAAG;AAACN,QAAAA;AAAS,KAAA,CAAA;AAEb;;MAGA,MAAMS,mBAAmBL,iBAAAA,CAAY,IAAA;AACnCJ,QAAAA,QAAAA,CAASU,kCAAsBX,KAAAA,EAAO;YAAEL,MAAAA,EAAQa;AAAU,SAAA,CAAA,CAAA;IAC5D,CAAA,EAAG;AAACR,QAAAA,KAAAA;AAAOC,QAAAA;AAAS,KAAA,CAAA;;;IAIpBW,eAAAA,CAAU,IAAA;QACR,IAAIZ,KAAAA,EAAOL,MAAAA,IAAUQ,eAAAA,KAAoB,IAAA,EAAM;AAC7CO,YAAAA,gBAAAA,EAAAA;AACF,QAAA;IACF,CAAA,EAAG;QAACV,KAAAA,EAAOL,MAAAA;AAAQQ,QAAAA,eAAAA;AAAiBO,QAAAA;AAAiB,KAAA,CAAA;AAErD;;;;MAKA,MAAMG,kBAAAA,GAAqBR,iBAAAA,CACzB,CAACS,QAAAA,GAAAA;AACC,QAAA,IAAIA,YAAY,IAAA,EAAM;AACpBL,YAAAA,cAAAA,EAAAA;QACF,CAAA,MAAO;YACLR,QAAAA,CAAS;AAAEN,gBAAAA,MAAAA,EAAQW,MAAAA,CAAOQ,QAAAA,CAAAA;gBAAWP,EAAAA,EAAIC;AAAU,aAAA,CAAA;AACrD,QAAA;IACF,CAAA,EACA;AAACC,QAAAA,cAAAA;AAAgBR,QAAAA;AAAS,KAAA,CAAA;IAG5B,OAAO;AACLE,QAAAA,eAAAA;AACAC,QAAAA,gBAAAA;AACAK,QAAAA,cAAAA;AACAI,QAAAA;AACF,KAAA;AACF;;;;"}
1
+ {"version":3,"file":"useFolderNavigation.js","sources":["../../../../../admin/src/pages/Assets/hooks/useFolderNavigation.ts"],"sourcesContent":["import { useCallback, useEffect } from 'react';\n\nimport { withEncodedUserParams } from '@strapi/admin/strapi-admin';\n\nimport { useListQueryParams } from './useListQueryParams';\n\nimport type { Folder } from '../../../../../shared/contracts/folders';\n\nconst parseFolderIdFromQuery = (folder: string | undefined): number | null => {\n if (!folder) {\n return null;\n }\n\n const id = Number(folder);\n\n return Number.isFinite(id) ? id : null;\n};\n\ninterface FolderNavigationQuery {\n folder?: string;\n _q?: string;\n}\n\nexport const useFolderNavigation = () => {\n const [{ query }, setQuery] = useListQueryParams<FolderNavigationQuery>();\n\n const currentFolderId = parseFolderIdFromQuery(query?.folder);\n\n /**\n * Asset search is global, so keeping `_q` after a folder navigation would show\n * byte-identical results and make the navigation look broken. Clearing it here\n * — rather than at each call site — means no caller can forget.\n */\n const navigateToFolder = useCallback(\n (folder: Folder) => {\n setQuery({ folder: String(folder.id), _q: undefined });\n },\n [setQuery]\n );\n\n /**\n * Move to the Media Library root by removing the `folder` query param, and the\n * search term with it. `setQuery(_, 'remove')` deletes the keys present on the\n * first argument (values are ignored) in one navigation, so any other query\n * state (pagination, the details drawer, etc.) is preserved.\n */\n const navigateToRoot = useCallback(() => {\n setQuery({ folder: '', _q: '' }, 'remove');\n }, [setQuery]);\n\n /**\n * Strips a `?folder=` value we can't parse.\n */\n const stripFolderParam = useCallback(() => {\n setQuery(withEncodedUserParams(query, { folder: undefined }));\n }, [query, setQuery]);\n\n // Malformed ?folder= values (e.g. abc) parse as null; strip the param from the URL.\n // Deleted/missing folders (404) are handled in AssetsPage — that needs a fetch.\n useEffect(() => {\n if (query?.folder && currentFolderId === null) {\n stripFolderParam();\n }\n }, [query?.folder, currentFolderId, stripFolderParam]);\n\n /**\n * Convenience for the FolderTree sidebar: a single entry point that handles\n * both \"go home\" and \"go to folder X\" without forcing the caller to know\n * whether to call navigateToFolder or navigateToRoot.\n */\n const navigateToFolderId = useCallback(\n (folderId: number | null) => {\n if (folderId == null) {\n navigateToRoot();\n } else {\n setQuery({ folder: String(folderId), _q: undefined });\n }\n },\n [navigateToRoot, setQuery]\n );\n\n return {\n currentFolderId,\n navigateToFolder,\n navigateToRoot,\n navigateToFolderId,\n };\n};\n"],"names":["parseFolderIdFromQuery","folder","id","Number","isFinite","useFolderNavigation","query","setQuery","useListQueryParams","currentFolderId","navigateToFolder","useCallback","String","_q","undefined","navigateToRoot","stripFolderParam","withEncodedUserParams","useEffect","navigateToFolderId","folderId"],"mappings":";;;;;;AAQA,MAAMA,yBAAyB,CAACC,MAAAA,GAAAA;AAC9B,IAAA,IAAI,CAACA,MAAAA,EAAQ;QACX,OAAO,IAAA;AACT,IAAA;AAEA,IAAA,MAAMC,KAAKC,MAAAA,CAAOF,MAAAA,CAAAA;AAElB,IAAA,OAAOE,MAAAA,CAAOC,QAAQ,CAACF,EAAAA,CAAAA,GAAMA,EAAAA,GAAK,IAAA;AACpC,CAAA;MAOaG,mBAAAA,GAAsB,IAAA;AACjC,IAAA,MAAM,CAAC,EAAEC,KAAK,EAAE,EAAEC,SAAS,GAAGC,qCAAAA,EAAAA;IAE9B,MAAMC,eAAAA,GAAkBT,uBAAuBM,KAAAA,EAAOL,MAAAA,CAAAA;AAEtD;;;;MAKA,MAAMS,gBAAAA,GAAmBC,iBAAAA,CACvB,CAACV,MAAAA,GAAAA;QACCM,QAAAA,CAAS;YAAEN,MAAAA,EAAQW,MAAAA,CAAOX,OAAOC,EAAE,CAAA;YAAGW,EAAAA,EAAIC;AAAU,SAAA,CAAA;IACtD,CAAA,EACA;AAACP,QAAAA;AAAS,KAAA,CAAA;AAGZ;;;;;MAMA,MAAMQ,iBAAiBJ,iBAAAA,CAAY,IAAA;QACjCJ,QAAAA,CAAS;YAAEN,MAAAA,EAAQ,EAAA;YAAIY,EAAAA,EAAI;SAAG,EAAG,QAAA,CAAA;IACnC,CAAA,EAAG;AAACN,QAAAA;AAAS,KAAA,CAAA;AAEb;;MAGA,MAAMS,mBAAmBL,iBAAAA,CAAY,IAAA;AACnCJ,QAAAA,QAAAA,CAASU,kCAAsBX,KAAAA,EAAO;YAAEL,MAAAA,EAAQa;AAAU,SAAA,CAAA,CAAA;IAC5D,CAAA,EAAG;AAACR,QAAAA,KAAAA;AAAOC,QAAAA;AAAS,KAAA,CAAA;;;IAIpBW,eAAAA,CAAU,IAAA;QACR,IAAIZ,KAAAA,EAAOL,MAAAA,IAAUQ,eAAAA,KAAoB,IAAA,EAAM;AAC7CO,YAAAA,gBAAAA,EAAAA;AACF,QAAA;IACF,CAAA,EAAG;QAACV,KAAAA,EAAOL,MAAAA;AAAQQ,QAAAA,eAAAA;AAAiBO,QAAAA;AAAiB,KAAA,CAAA;AAErD;;;;MAKA,MAAMG,kBAAAA,GAAqBR,iBAAAA,CACzB,CAACS,QAAAA,GAAAA;AACC,QAAA,IAAIA,YAAY,IAAA,EAAM;AACpBL,YAAAA,cAAAA,EAAAA;QACF,CAAA,MAAO;YACLR,QAAAA,CAAS;AAAEN,gBAAAA,MAAAA,EAAQW,MAAAA,CAAOQ,QAAAA,CAAAA;gBAAWP,EAAAA,EAAIC;AAAU,aAAA,CAAA;AACrD,QAAA;IACF,CAAA,EACA;AAACC,QAAAA,cAAAA;AAAgBR,QAAAA;AAAS,KAAA,CAAA;IAG5B,OAAO;AACLE,QAAAA,eAAAA;AACAC,QAAAA,gBAAAA;AACAK,QAAAA,cAAAA;AACAI,QAAAA;AACF,KAAA;AACF;;;;"}
@@ -1,5 +1,6 @@
1
1
  import { useCallback, useEffect } from 'react';
2
- import { useQueryParams, withEncodedUserParams } from '@strapi/admin/strapi-admin';
2
+ import { withEncodedUserParams } from '@strapi/admin/strapi-admin';
3
+ import { useListQueryParams } from './useListQueryParams.mjs';
3
4
 
4
5
  const parseFolderIdFromQuery = (folder)=>{
5
6
  if (!folder) {
@@ -9,7 +10,7 @@ const parseFolderIdFromQuery = (folder)=>{
9
10
  return Number.isFinite(id) ? id : null;
10
11
  };
11
12
  const useFolderNavigation = ()=>{
12
- const [{ query }, setQuery] = useQueryParams();
13
+ const [{ query }, setQuery] = useListQueryParams();
13
14
  const currentFolderId = parseFolderIdFromQuery(query?.folder);
14
15
  /**
15
16
  * Asset search is global, so keeping `_q` after a folder navigation would show
@@ -1 +1 @@
1
- {"version":3,"file":"useFolderNavigation.mjs","sources":["../../../../../admin/src/pages/Assets/hooks/useFolderNavigation.ts"],"sourcesContent":["import { useCallback, useEffect } from 'react';\n\nimport { useQueryParams, withEncodedUserParams } from '@strapi/admin/strapi-admin';\n\nimport type { Folder } from '../../../../../shared/contracts/folders';\n\nconst parseFolderIdFromQuery = (folder: string | undefined): number | null => {\n if (!folder) {\n return null;\n }\n\n const id = Number(folder);\n\n return Number.isFinite(id) ? id : null;\n};\n\ninterface FolderNavigationQuery {\n folder?: string;\n _q?: string;\n}\n\nexport const useFolderNavigation = () => {\n const [{ query }, setQuery] = useQueryParams<FolderNavigationQuery>();\n\n const currentFolderId = parseFolderIdFromQuery(query?.folder);\n\n /**\n * Asset search is global, so keeping `_q` after a folder navigation would show\n * byte-identical results and make the navigation look broken. Clearing it here\n * — rather than at each call site — means no caller can forget.\n */\n const navigateToFolder = useCallback(\n (folder: Folder) => {\n setQuery({ folder: String(folder.id), _q: undefined });\n },\n [setQuery]\n );\n\n /**\n * Move to the Media Library root by removing the `folder` query param, and the\n * search term with it. `setQuery(_, 'remove')` deletes the keys present on the\n * first argument (values are ignored) in one navigation, so any other query\n * state (pagination, the details drawer, etc.) is preserved.\n */\n const navigateToRoot = useCallback(() => {\n setQuery({ folder: '', _q: '' }, 'remove');\n }, [setQuery]);\n\n /**\n * Strips a `?folder=` value we can't parse.\n */\n const stripFolderParam = useCallback(() => {\n setQuery(withEncodedUserParams(query, { folder: undefined }));\n }, [query, setQuery]);\n\n // Malformed ?folder= values (e.g. abc) parse as null; strip the param from the URL.\n // Deleted/missing folders (404) are handled in AssetsPage — that needs a fetch.\n useEffect(() => {\n if (query?.folder && currentFolderId === null) {\n stripFolderParam();\n }\n }, [query?.folder, currentFolderId, stripFolderParam]);\n\n /**\n * Convenience for the FolderTree sidebar: a single entry point that handles\n * both \"go home\" and \"go to folder X\" without forcing the caller to know\n * whether to call navigateToFolder or navigateToRoot.\n */\n const navigateToFolderId = useCallback(\n (folderId: number | null) => {\n if (folderId == null) {\n navigateToRoot();\n } else {\n setQuery({ folder: String(folderId), _q: undefined });\n }\n },\n [navigateToRoot, setQuery]\n );\n\n return {\n currentFolderId,\n navigateToFolder,\n navigateToRoot,\n navigateToFolderId,\n };\n};\n"],"names":["parseFolderIdFromQuery","folder","id","Number","isFinite","useFolderNavigation","query","setQuery","useQueryParams","currentFolderId","navigateToFolder","useCallback","String","_q","undefined","navigateToRoot","stripFolderParam","withEncodedUserParams","useEffect","navigateToFolderId","folderId"],"mappings":";;;AAMA,MAAMA,yBAAyB,CAACC,MAAAA,GAAAA;AAC9B,IAAA,IAAI,CAACA,MAAAA,EAAQ;QACX,OAAO,IAAA;AACT,IAAA;AAEA,IAAA,MAAMC,KAAKC,MAAAA,CAAOF,MAAAA,CAAAA;AAElB,IAAA,OAAOE,MAAAA,CAAOC,QAAQ,CAACF,EAAAA,CAAAA,GAAMA,EAAAA,GAAK,IAAA;AACpC,CAAA;MAOaG,mBAAAA,GAAsB,IAAA;AACjC,IAAA,MAAM,CAAC,EAAEC,KAAK,EAAE,EAAEC,SAAS,GAAGC,cAAAA,EAAAA;IAE9B,MAAMC,eAAAA,GAAkBT,uBAAuBM,KAAAA,EAAOL,MAAAA,CAAAA;AAEtD;;;;MAKA,MAAMS,gBAAAA,GAAmBC,WAAAA,CACvB,CAACV,MAAAA,GAAAA;QACCM,QAAAA,CAAS;YAAEN,MAAAA,EAAQW,MAAAA,CAAOX,OAAOC,EAAE,CAAA;YAAGW,EAAAA,EAAIC;AAAU,SAAA,CAAA;IACtD,CAAA,EACA;AAACP,QAAAA;AAAS,KAAA,CAAA;AAGZ;;;;;MAMA,MAAMQ,iBAAiBJ,WAAAA,CAAY,IAAA;QACjCJ,QAAAA,CAAS;YAAEN,MAAAA,EAAQ,EAAA;YAAIY,EAAAA,EAAI;SAAG,EAAG,QAAA,CAAA;IACnC,CAAA,EAAG;AAACN,QAAAA;AAAS,KAAA,CAAA;AAEb;;MAGA,MAAMS,mBAAmBL,WAAAA,CAAY,IAAA;AACnCJ,QAAAA,QAAAA,CAASU,sBAAsBX,KAAAA,EAAO;YAAEL,MAAAA,EAAQa;AAAU,SAAA,CAAA,CAAA;IAC5D,CAAA,EAAG;AAACR,QAAAA,KAAAA;AAAOC,QAAAA;AAAS,KAAA,CAAA;;;IAIpBW,SAAAA,CAAU,IAAA;QACR,IAAIZ,KAAAA,EAAOL,MAAAA,IAAUQ,eAAAA,KAAoB,IAAA,EAAM;AAC7CO,YAAAA,gBAAAA,EAAAA;AACF,QAAA;IACF,CAAA,EAAG;QAACV,KAAAA,EAAOL,MAAAA;AAAQQ,QAAAA,eAAAA;AAAiBO,QAAAA;AAAiB,KAAA,CAAA;AAErD;;;;MAKA,MAAMG,kBAAAA,GAAqBR,WAAAA,CACzB,CAACS,QAAAA,GAAAA;AACC,QAAA,IAAIA,YAAY,IAAA,EAAM;AACpBL,YAAAA,cAAAA,EAAAA;QACF,CAAA,MAAO;YACLR,QAAAA,CAAS;AAAEN,gBAAAA,MAAAA,EAAQW,MAAAA,CAAOQ,QAAAA,CAAAA;gBAAWP,EAAAA,EAAIC;AAAU,aAAA,CAAA;AACrD,QAAA;IACF,CAAA,EACA;AAACC,QAAAA,cAAAA;AAAgBR,QAAAA;AAAS,KAAA,CAAA;IAG5B,OAAO;AACLE,QAAAA,eAAAA;AACAC,QAAAA,gBAAAA;AACAK,QAAAA,cAAAA;AACAI,QAAAA;AACF,KAAA;AACF;;;;"}
1
+ {"version":3,"file":"useFolderNavigation.mjs","sources":["../../../../../admin/src/pages/Assets/hooks/useFolderNavigation.ts"],"sourcesContent":["import { useCallback, useEffect } from 'react';\n\nimport { withEncodedUserParams } from '@strapi/admin/strapi-admin';\n\nimport { useListQueryParams } from './useListQueryParams';\n\nimport type { Folder } from '../../../../../shared/contracts/folders';\n\nconst parseFolderIdFromQuery = (folder: string | undefined): number | null => {\n if (!folder) {\n return null;\n }\n\n const id = Number(folder);\n\n return Number.isFinite(id) ? id : null;\n};\n\ninterface FolderNavigationQuery {\n folder?: string;\n _q?: string;\n}\n\nexport const useFolderNavigation = () => {\n const [{ query }, setQuery] = useListQueryParams<FolderNavigationQuery>();\n\n const currentFolderId = parseFolderIdFromQuery(query?.folder);\n\n /**\n * Asset search is global, so keeping `_q` after a folder navigation would show\n * byte-identical results and make the navigation look broken. Clearing it here\n * — rather than at each call site — means no caller can forget.\n */\n const navigateToFolder = useCallback(\n (folder: Folder) => {\n setQuery({ folder: String(folder.id), _q: undefined });\n },\n [setQuery]\n );\n\n /**\n * Move to the Media Library root by removing the `folder` query param, and the\n * search term with it. `setQuery(_, 'remove')` deletes the keys present on the\n * first argument (values are ignored) in one navigation, so any other query\n * state (pagination, the details drawer, etc.) is preserved.\n */\n const navigateToRoot = useCallback(() => {\n setQuery({ folder: '', _q: '' }, 'remove');\n }, [setQuery]);\n\n /**\n * Strips a `?folder=` value we can't parse.\n */\n const stripFolderParam = useCallback(() => {\n setQuery(withEncodedUserParams(query, { folder: undefined }));\n }, [query, setQuery]);\n\n // Malformed ?folder= values (e.g. abc) parse as null; strip the param from the URL.\n // Deleted/missing folders (404) are handled in AssetsPage — that needs a fetch.\n useEffect(() => {\n if (query?.folder && currentFolderId === null) {\n stripFolderParam();\n }\n }, [query?.folder, currentFolderId, stripFolderParam]);\n\n /**\n * Convenience for the FolderTree sidebar: a single entry point that handles\n * both \"go home\" and \"go to folder X\" without forcing the caller to know\n * whether to call navigateToFolder or navigateToRoot.\n */\n const navigateToFolderId = useCallback(\n (folderId: number | null) => {\n if (folderId == null) {\n navigateToRoot();\n } else {\n setQuery({ folder: String(folderId), _q: undefined });\n }\n },\n [navigateToRoot, setQuery]\n );\n\n return {\n currentFolderId,\n navigateToFolder,\n navigateToRoot,\n navigateToFolderId,\n };\n};\n"],"names":["parseFolderIdFromQuery","folder","id","Number","isFinite","useFolderNavigation","query","setQuery","useListQueryParams","currentFolderId","navigateToFolder","useCallback","String","_q","undefined","navigateToRoot","stripFolderParam","withEncodedUserParams","useEffect","navigateToFolderId","folderId"],"mappings":";;;;AAQA,MAAMA,yBAAyB,CAACC,MAAAA,GAAAA;AAC9B,IAAA,IAAI,CAACA,MAAAA,EAAQ;QACX,OAAO,IAAA;AACT,IAAA;AAEA,IAAA,MAAMC,KAAKC,MAAAA,CAAOF,MAAAA,CAAAA;AAElB,IAAA,OAAOE,MAAAA,CAAOC,QAAQ,CAACF,EAAAA,CAAAA,GAAMA,EAAAA,GAAK,IAAA;AACpC,CAAA;MAOaG,mBAAAA,GAAsB,IAAA;AACjC,IAAA,MAAM,CAAC,EAAEC,KAAK,EAAE,EAAEC,SAAS,GAAGC,kBAAAA,EAAAA;IAE9B,MAAMC,eAAAA,GAAkBT,uBAAuBM,KAAAA,EAAOL,MAAAA,CAAAA;AAEtD;;;;MAKA,MAAMS,gBAAAA,GAAmBC,WAAAA,CACvB,CAACV,MAAAA,GAAAA;QACCM,QAAAA,CAAS;YAAEN,MAAAA,EAAQW,MAAAA,CAAOX,OAAOC,EAAE,CAAA;YAAGW,EAAAA,EAAIC;AAAU,SAAA,CAAA;IACtD,CAAA,EACA;AAACP,QAAAA;AAAS,KAAA,CAAA;AAGZ;;;;;MAMA,MAAMQ,iBAAiBJ,WAAAA,CAAY,IAAA;QACjCJ,QAAAA,CAAS;YAAEN,MAAAA,EAAQ,EAAA;YAAIY,EAAAA,EAAI;SAAG,EAAG,QAAA,CAAA;IACnC,CAAA,EAAG;AAACN,QAAAA;AAAS,KAAA,CAAA;AAEb;;MAGA,MAAMS,mBAAmBL,WAAAA,CAAY,IAAA;AACnCJ,QAAAA,QAAAA,CAASU,sBAAsBX,KAAAA,EAAO;YAAEL,MAAAA,EAAQa;AAAU,SAAA,CAAA,CAAA;IAC5D,CAAA,EAAG;AAACR,QAAAA,KAAAA;AAAOC,QAAAA;AAAS,KAAA,CAAA;;;IAIpBW,SAAAA,CAAU,IAAA;QACR,IAAIZ,KAAAA,EAAOL,MAAAA,IAAUQ,eAAAA,KAAoB,IAAA,EAAM;AAC7CO,YAAAA,gBAAAA,EAAAA;AACF,QAAA;IACF,CAAA,EAAG;QAACV,KAAAA,EAAOL,MAAAA;AAAQQ,QAAAA,eAAAA;AAAiBO,QAAAA;AAAiB,KAAA,CAAA;AAErD;;;;MAKA,MAAMG,kBAAAA,GAAqBR,WAAAA,CACzB,CAACS,QAAAA,GAAAA;AACC,QAAA,IAAIA,YAAY,IAAA,EAAM;AACpBL,YAAAA,cAAAA,EAAAA;QACF,CAAA,MAAO;YACLR,QAAAA,CAAS;AAAEN,gBAAAA,MAAAA,EAAQW,MAAAA,CAAOQ,QAAAA,CAAAA;gBAAWP,EAAAA,EAAIC;AAAU,aAAA,CAAA;AACrD,QAAA;IACF,CAAA,EACA;AAACC,QAAAA,cAAAA;AAAgBR,QAAAA;AAAS,KAAA,CAAA;IAG5B,OAAO;AACLE,QAAAA,eAAAA;AACAC,QAAAA,gBAAAA;AACAK,QAAAA,cAAAA;AACAI,QAAAA;AACF,KAAA;AACF;;;;"}
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var strapiAdmin = require('@strapi/admin/strapi-admin');
4
+ var useListQueryParams = require('./useListQueryParams.js');
4
5
 
5
6
  /**
6
7
  * Filter state for the assets list, backed by a single `?filters=` query param
@@ -130,7 +131,7 @@ const serializeBadge = (filter)=>{
130
131
  };
131
132
  const serializeFilters = (filters)=>filters.map(serializeBadge).join(';');
132
133
  const useListFilters = ()=>{
133
- const [{ query }, setQuery] = strapiAdmin.useQueryParams();
134
+ const [{ query }, setQuery] = useListQueryParams.useListQueryParams();
134
135
  const filters = parseFiltersParam(query?.filters);
135
136
  // `replace: true` on every write: filters are edited in rapid micro-steps
136
137
  // (each checkbox of the keep-open Type submenu, each badge segment edit), so