@strapi/upload 5.52.2 → 5.53.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 (285) hide show
  1. package/dist/admin/components/AssetCard/AssetCard.js +1 -0
  2. package/dist/admin/components/AssetCard/AssetCard.js.map +1 -1
  3. package/dist/admin/components/AssetCard/AssetCard.mjs +1 -0
  4. package/dist/admin/components/AssetCard/AssetCard.mjs.map +1 -1
  5. package/dist/admin/components/AssetCard/AssetCardBase.js +1 -0
  6. package/dist/admin/components/AssetCard/AssetCardBase.js.map +1 -1
  7. package/dist/admin/components/AssetCard/AssetCardBase.mjs +1 -0
  8. package/dist/admin/components/AssetCard/AssetCardBase.mjs.map +1 -1
  9. package/dist/admin/components/AssetCard/ImageAssetCard.js +1 -0
  10. package/dist/admin/components/AssetCard/ImageAssetCard.js.map +1 -1
  11. package/dist/admin/components/AssetCard/ImageAssetCard.mjs +1 -0
  12. package/dist/admin/components/AssetCard/ImageAssetCard.mjs.map +1 -1
  13. package/dist/admin/components/AssetCard/UploadingAssetCard.js +1 -0
  14. package/dist/admin/components/AssetCard/UploadingAssetCard.js.map +1 -1
  15. package/dist/admin/components/AssetCard/UploadingAssetCard.mjs +1 -0
  16. package/dist/admin/components/AssetCard/UploadingAssetCard.mjs.map +1 -1
  17. package/dist/admin/components/AssetCard/VideoAssetCard.js +1 -0
  18. package/dist/admin/components/AssetCard/VideoAssetCard.js.map +1 -1
  19. package/dist/admin/components/AssetCard/VideoAssetCard.mjs +1 -0
  20. package/dist/admin/components/AssetCard/VideoAssetCard.mjs.map +1 -1
  21. package/dist/admin/components/AssetDialog/BrowseStep/BrowseStep.js +1 -0
  22. package/dist/admin/components/AssetDialog/BrowseStep/BrowseStep.js.map +1 -1
  23. package/dist/admin/components/AssetDialog/BrowseStep/BrowseStep.mjs +1 -0
  24. package/dist/admin/components/AssetDialog/BrowseStep/BrowseStep.mjs.map +1 -1
  25. package/dist/admin/components/AssetDialog/BrowseStep/Filters.js +1 -0
  26. package/dist/admin/components/AssetDialog/BrowseStep/Filters.js.map +1 -1
  27. package/dist/admin/components/AssetDialog/BrowseStep/Filters.mjs +1 -0
  28. package/dist/admin/components/AssetDialog/BrowseStep/Filters.mjs.map +1 -1
  29. package/dist/admin/components/AssetDialog/BrowseStep/SearchAsset/SearchAsset.js +1 -0
  30. package/dist/admin/components/AssetDialog/BrowseStep/SearchAsset/SearchAsset.js.map +1 -1
  31. package/dist/admin/components/AssetDialog/BrowseStep/SearchAsset/SearchAsset.mjs +1 -0
  32. package/dist/admin/components/AssetDialog/BrowseStep/SearchAsset/SearchAsset.mjs.map +1 -1
  33. package/dist/admin/components/AssetDialog/SelectedStep/SelectedStep.js +1 -0
  34. package/dist/admin/components/AssetDialog/SelectedStep/SelectedStep.js.map +1 -1
  35. package/dist/admin/components/AssetDialog/SelectedStep/SelectedStep.mjs +1 -0
  36. package/dist/admin/components/AssetDialog/SelectedStep/SelectedStep.mjs.map +1 -1
  37. package/dist/admin/components/BulkMoveDialog/BulkMoveDialog.js +1 -0
  38. package/dist/admin/components/BulkMoveDialog/BulkMoveDialog.js.map +1 -1
  39. package/dist/admin/components/BulkMoveDialog/BulkMoveDialog.mjs +1 -0
  40. package/dist/admin/components/BulkMoveDialog/BulkMoveDialog.mjs.map +1 -1
  41. package/dist/admin/components/EditAssetDialog/EditAssetContent.js +1 -0
  42. package/dist/admin/components/EditAssetDialog/EditAssetContent.js.map +1 -1
  43. package/dist/admin/components/EditAssetDialog/EditAssetContent.mjs +1 -0
  44. package/dist/admin/components/EditAssetDialog/EditAssetContent.mjs.map +1 -1
  45. package/dist/admin/components/EditAssetDialog/PreviewBox/AssetPreview.js +1 -0
  46. package/dist/admin/components/EditAssetDialog/PreviewBox/AssetPreview.js.map +1 -1
  47. package/dist/admin/components/EditAssetDialog/PreviewBox/AssetPreview.mjs +1 -0
  48. package/dist/admin/components/EditAssetDialog/PreviewBox/AssetPreview.mjs.map +1 -1
  49. package/dist/admin/components/EditAssetDialog/PreviewBox/CroppingActions.js +1 -0
  50. package/dist/admin/components/EditAssetDialog/PreviewBox/CroppingActions.js.map +1 -1
  51. package/dist/admin/components/EditAssetDialog/PreviewBox/CroppingActions.mjs +1 -0
  52. package/dist/admin/components/EditAssetDialog/PreviewBox/CroppingActions.mjs.map +1 -1
  53. package/dist/admin/components/EditAssetDialog/PreviewBox/FocalPointActions.js +1 -0
  54. package/dist/admin/components/EditAssetDialog/PreviewBox/FocalPointActions.js.map +1 -1
  55. package/dist/admin/components/EditAssetDialog/PreviewBox/FocalPointActions.mjs +1 -0
  56. package/dist/admin/components/EditAssetDialog/PreviewBox/FocalPointActions.mjs.map +1 -1
  57. package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewBox.js +1 -0
  58. package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewBox.js.map +1 -1
  59. package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewBox.mjs +1 -0
  60. package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewBox.mjs.map +1 -1
  61. package/dist/admin/components/EditAssetDialog/ReplaceMediaButton.js +1 -0
  62. package/dist/admin/components/EditAssetDialog/ReplaceMediaButton.js.map +1 -1
  63. package/dist/admin/components/EditAssetDialog/ReplaceMediaButton.mjs +1 -0
  64. package/dist/admin/components/EditAssetDialog/ReplaceMediaButton.mjs.map +1 -1
  65. package/dist/admin/components/EditFolderDialog/ModalHeader/ModalHeader.js +1 -0
  66. package/dist/admin/components/EditFolderDialog/ModalHeader/ModalHeader.js.map +1 -1
  67. package/dist/admin/components/EditFolderDialog/ModalHeader/ModalHeader.mjs +1 -0
  68. package/dist/admin/components/EditFolderDialog/ModalHeader/ModalHeader.mjs.map +1 -1
  69. package/dist/admin/components/FilterList/FilterList.js +2 -2
  70. package/dist/admin/components/FilterList/FilterList.js.map +1 -1
  71. package/dist/admin/components/FilterList/FilterList.mjs +2 -2
  72. package/dist/admin/components/FilterList/FilterList.mjs.map +1 -1
  73. package/dist/admin/components/FilterPopover/FilterPopover.js +4 -4
  74. package/dist/admin/components/FilterPopover/FilterPopover.js.map +1 -1
  75. package/dist/admin/components/FilterPopover/FilterPopover.mjs +4 -4
  76. package/dist/admin/components/FilterPopover/FilterPopover.mjs.map +1 -1
  77. package/dist/admin/components/MediaLibraryInput/Carousel/CarouselAsset.js +1 -0
  78. package/dist/admin/components/MediaLibraryInput/Carousel/CarouselAsset.js.map +1 -1
  79. package/dist/admin/components/MediaLibraryInput/Carousel/CarouselAsset.mjs +1 -0
  80. package/dist/admin/components/MediaLibraryInput/Carousel/CarouselAsset.mjs.map +1 -1
  81. package/dist/admin/components/MediaLibraryInput/Carousel/CarouselAssetActions.js +1 -0
  82. package/dist/admin/components/MediaLibraryInput/Carousel/CarouselAssetActions.js.map +1 -1
  83. package/dist/admin/components/MediaLibraryInput/Carousel/CarouselAssetActions.mjs +1 -0
  84. package/dist/admin/components/MediaLibraryInput/Carousel/CarouselAssetActions.mjs.map +1 -1
  85. package/dist/admin/components/MediaLibraryInput/Carousel/EmptyStateAsset.js +4 -10
  86. package/dist/admin/components/MediaLibraryInput/Carousel/EmptyStateAsset.js.map +1 -1
  87. package/dist/admin/components/MediaLibraryInput/Carousel/EmptyStateAsset.mjs +4 -10
  88. package/dist/admin/components/MediaLibraryInput/Carousel/EmptyStateAsset.mjs.map +1 -1
  89. package/dist/admin/components/SortPicker/SortPicker.js +1 -0
  90. package/dist/admin/components/SortPicker/SortPicker.js.map +1 -1
  91. package/dist/admin/components/SortPicker/SortPicker.mjs +1 -0
  92. package/dist/admin/components/SortPicker/SortPicker.mjs.map +1 -1
  93. package/dist/admin/components/TableList/CellContent.js +1 -0
  94. package/dist/admin/components/TableList/CellContent.js.map +1 -1
  95. package/dist/admin/components/TableList/CellContent.mjs +1 -0
  96. package/dist/admin/components/TableList/CellContent.mjs.map +1 -1
  97. package/dist/admin/components/TableList/PreviewCell.js +1 -0
  98. package/dist/admin/components/TableList/PreviewCell.js.map +1 -1
  99. package/dist/admin/components/TableList/PreviewCell.mjs +1 -0
  100. package/dist/admin/components/TableList/PreviewCell.mjs.map +1 -1
  101. package/dist/admin/components/TableList/TableList.js +1 -0
  102. package/dist/admin/components/TableList/TableList.js.map +1 -1
  103. package/dist/admin/components/TableList/TableList.mjs +1 -0
  104. package/dist/admin/components/TableList/TableList.mjs.map +1 -1
  105. package/dist/admin/components/TableList/TableRows.js +1 -0
  106. package/dist/admin/components/TableList/TableRows.js.map +1 -1
  107. package/dist/admin/components/TableList/TableRows.mjs +1 -0
  108. package/dist/admin/components/TableList/TableRows.mjs.map +1 -1
  109. package/dist/admin/components/UploadAssetDialog/AddAssetStep/AddAssetStep.js +1 -0
  110. package/dist/admin/components/UploadAssetDialog/AddAssetStep/AddAssetStep.js.map +1 -1
  111. package/dist/admin/components/UploadAssetDialog/AddAssetStep/AddAssetStep.mjs +1 -0
  112. package/dist/admin/components/UploadAssetDialog/AddAssetStep/AddAssetStep.mjs.map +1 -1
  113. package/dist/admin/components/UploadAssetDialog/AddAssetStep/FromComputerForm.js +9 -21
  114. package/dist/admin/components/UploadAssetDialog/AddAssetStep/FromComputerForm.js.map +1 -1
  115. package/dist/admin/components/UploadAssetDialog/AddAssetStep/FromComputerForm.mjs +9 -21
  116. package/dist/admin/components/UploadAssetDialog/AddAssetStep/FromComputerForm.mjs.map +1 -1
  117. package/dist/admin/components/UploadAssetDialog/AddAssetStep/FromUrlForm.js +1 -0
  118. package/dist/admin/components/UploadAssetDialog/AddAssetStep/FromUrlForm.js.map +1 -1
  119. package/dist/admin/components/UploadAssetDialog/AddAssetStep/FromUrlForm.mjs +1 -0
  120. package/dist/admin/components/UploadAssetDialog/AddAssetStep/FromUrlForm.mjs.map +1 -1
  121. package/dist/admin/components/UploadAssetDialog/PendingAssetStep/PendingAssetStep.js +1 -0
  122. package/dist/admin/components/UploadAssetDialog/PendingAssetStep/PendingAssetStep.js.map +1 -1
  123. package/dist/admin/components/UploadAssetDialog/PendingAssetStep/PendingAssetStep.mjs +1 -0
  124. package/dist/admin/components/UploadAssetDialog/PendingAssetStep/PendingAssetStep.mjs.map +1 -1
  125. package/dist/admin/constants.js +1 -0
  126. package/dist/admin/constants.js.map +1 -1
  127. package/dist/admin/constants.mjs +1 -0
  128. package/dist/admin/constants.mjs.map +1 -1
  129. package/dist/admin/future/components/Drawer.js +17 -3
  130. package/dist/admin/future/components/Drawer.js.map +1 -1
  131. package/dist/admin/future/components/Drawer.mjs +17 -3
  132. package/dist/admin/future/components/Drawer.mjs.map +1 -1
  133. package/dist/admin/future/components/UploadProgressDialog.js +46 -12
  134. package/dist/admin/future/components/UploadProgressDialog.js.map +1 -1
  135. package/dist/admin/future/components/UploadProgressDialog.mjs +47 -13
  136. package/dist/admin/future/components/UploadProgressDialog.mjs.map +1 -1
  137. package/dist/admin/future/pages/Assets/AssetsPage.js +27 -2
  138. package/dist/admin/future/pages/Assets/AssetsPage.js.map +1 -1
  139. package/dist/admin/future/pages/Assets/AssetsPage.mjs +27 -2
  140. package/dist/admin/future/pages/Assets/AssetsPage.mjs.map +1 -1
  141. package/dist/admin/future/pages/Assets/components/AssetActionsMenu.js +9 -1
  142. package/dist/admin/future/pages/Assets/components/AssetActionsMenu.js.map +1 -1
  143. package/dist/admin/future/pages/Assets/components/AssetActionsMenu.mjs +9 -1
  144. package/dist/admin/future/pages/Assets/components/AssetActionsMenu.mjs.map +1 -1
  145. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetCropEditor.js +19 -4
  146. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetCropEditor.js.map +1 -1
  147. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetCropEditor.mjs +19 -4
  148. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetCropEditor.mjs.map +1 -1
  149. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js +64 -10
  150. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js.map +1 -1
  151. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs +66 -12
  152. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs.map +1 -1
  153. package/dist/admin/future/pages/Assets/components/AssetsGrid.js +17 -5
  154. package/dist/admin/future/pages/Assets/components/AssetsGrid.js.map +1 -1
  155. package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs +17 -5
  156. package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs.map +1 -1
  157. package/dist/admin/future/pages/Assets/components/AssetsTable.js +56 -28
  158. package/dist/admin/future/pages/Assets/components/AssetsTable.js.map +1 -1
  159. package/dist/admin/future/pages/Assets/components/AssetsTable.mjs +58 -30
  160. package/dist/admin/future/pages/Assets/components/AssetsTable.mjs.map +1 -1
  161. package/dist/admin/future/pages/Assets/components/BulkActionsBar.js +203 -83
  162. package/dist/admin/future/pages/Assets/components/BulkActionsBar.js.map +1 -1
  163. package/dist/admin/future/pages/Assets/components/BulkActionsBar.mjs +207 -87
  164. package/dist/admin/future/pages/Assets/components/BulkActionsBar.mjs.map +1 -1
  165. package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js +21 -3
  166. package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js.map +1 -1
  167. package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs +21 -3
  168. package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs.map +1 -1
  169. package/dist/admin/future/pages/Assets/components/MainAreaContextMenu.js +181 -0
  170. package/dist/admin/future/pages/Assets/components/MainAreaContextMenu.js.map +1 -0
  171. package/dist/admin/future/pages/Assets/components/MainAreaContextMenu.mjs +179 -0
  172. package/dist/admin/future/pages/Assets/components/MainAreaContextMenu.mjs.map +1 -0
  173. package/dist/admin/future/pages/Assets/constants.js +22 -0
  174. package/dist/admin/future/pages/Assets/constants.js.map +1 -1
  175. package/dist/admin/future/pages/Assets/constants.mjs +19 -1
  176. package/dist/admin/future/pages/Assets/constants.mjs.map +1 -1
  177. package/dist/admin/future/pages/Assets/hooks/useFolderNavigation.js +4 -3
  178. package/dist/admin/future/pages/Assets/hooks/useFolderNavigation.js.map +1 -1
  179. package/dist/admin/future/pages/Assets/hooks/useFolderNavigation.mjs +5 -4
  180. package/dist/admin/future/pages/Assets/hooks/useFolderNavigation.mjs.map +1 -1
  181. package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.js +105 -12
  182. package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.js.map +1 -1
  183. package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.mjs +106 -13
  184. package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.mjs.map +1 -1
  185. package/dist/admin/future/pages/Assets/hooks/useListFilters.js +5 -5
  186. package/dist/admin/future/pages/Assets/hooks/useListFilters.js.map +1 -1
  187. package/dist/admin/future/pages/Assets/hooks/useListFilters.mjs +6 -6
  188. package/dist/admin/future/pages/Assets/hooks/useListFilters.mjs.map +1 -1
  189. package/dist/admin/future/pages/Assets/hooks/useListScrollRestoration.js +111 -0
  190. package/dist/admin/future/pages/Assets/hooks/useListScrollRestoration.js.map +1 -0
  191. package/dist/admin/future/pages/Assets/hooks/useListScrollRestoration.mjs +109 -0
  192. package/dist/admin/future/pages/Assets/hooks/useListScrollRestoration.mjs.map +1 -0
  193. package/dist/admin/future/pages/Assets/hooks/useListSort.js +10 -10
  194. package/dist/admin/future/pages/Assets/hooks/useListSort.js.map +1 -1
  195. package/dist/admin/future/pages/Assets/hooks/useListSort.mjs +11 -11
  196. package/dist/admin/future/pages/Assets/hooks/useListSort.mjs.map +1 -1
  197. package/dist/admin/future/pages/Assets/utils/mergeUploadedAssets.js +86 -0
  198. package/dist/admin/future/pages/Assets/utils/mergeUploadedAssets.js.map +1 -0
  199. package/dist/admin/future/pages/Assets/utils/mergeUploadedAssets.mjs +83 -0
  200. package/dist/admin/future/pages/Assets/utils/mergeUploadedAssets.mjs.map +1 -0
  201. package/dist/admin/future/pages/Assets/utils/renderedKeys.js +19 -0
  202. package/dist/admin/future/pages/Assets/utils/renderedKeys.js.map +1 -0
  203. package/dist/admin/future/pages/Assets/utils/renderedKeys.mjs +17 -0
  204. package/dist/admin/future/pages/Assets/utils/renderedKeys.mjs.map +1 -0
  205. package/dist/admin/future/services/api.js +19 -6
  206. package/dist/admin/future/services/api.js.map +1 -1
  207. package/dist/admin/future/services/api.mjs +19 -6
  208. package/dist/admin/future/services/api.mjs.map +1 -1
  209. package/dist/admin/future/store/uploadProgress.js +55 -2
  210. package/dist/admin/future/store/uploadProgress.js.map +1 -1
  211. package/dist/admin/future/store/uploadProgress.mjs +53 -3
  212. package/dist/admin/future/store/uploadProgress.mjs.map +1 -1
  213. package/dist/admin/index.js +1 -0
  214. package/dist/admin/index.js.map +1 -1
  215. package/dist/admin/index.mjs +1 -0
  216. package/dist/admin/index.mjs.map +1 -1
  217. package/dist/admin/pages/App/ConfigureTheView/components/Settings.js +1 -0
  218. package/dist/admin/pages/App/ConfigureTheView/components/Settings.js.map +1 -1
  219. package/dist/admin/pages/App/ConfigureTheView/components/Settings.mjs +1 -0
  220. package/dist/admin/pages/App/ConfigureTheView/components/Settings.mjs.map +1 -1
  221. package/dist/admin/pages/App/MediaLibrary.js +7 -9
  222. package/dist/admin/pages/App/MediaLibrary.js.map +1 -1
  223. package/dist/admin/pages/App/MediaLibrary.mjs +8 -10
  224. package/dist/admin/pages/App/MediaLibrary.mjs.map +1 -1
  225. package/dist/admin/pages/App/components/BulkActions.js +1 -0
  226. package/dist/admin/pages/App/components/BulkActions.js.map +1 -1
  227. package/dist/admin/pages/App/components/BulkActions.mjs +1 -0
  228. package/dist/admin/pages/App/components/BulkActions.mjs.map +1 -1
  229. package/dist/admin/pages/App/components/EmptyOrNoPermissions.js +1 -0
  230. package/dist/admin/pages/App/components/EmptyOrNoPermissions.js.map +1 -1
  231. package/dist/admin/pages/App/components/EmptyOrNoPermissions.mjs +1 -0
  232. package/dist/admin/pages/App/components/EmptyOrNoPermissions.mjs.map +1 -1
  233. package/dist/admin/pages/App/components/Filters.js +8 -8
  234. package/dist/admin/pages/App/components/Filters.js.map +1 -1
  235. package/dist/admin/pages/App/components/Filters.mjs +9 -9
  236. package/dist/admin/pages/App/components/Filters.mjs.map +1 -1
  237. package/dist/admin/pages/App/components/Header.js +1 -1
  238. package/dist/admin/pages/App/components/Header.js.map +1 -1
  239. package/dist/admin/pages/App/components/Header.mjs +2 -2
  240. package/dist/admin/pages/App/components/Header.mjs.map +1 -1
  241. package/dist/admin/src/future/components/Drawer.d.ts +10 -0
  242. package/dist/admin/src/future/pages/Assets/components/AssetsGrid.d.ts +4 -1
  243. package/dist/admin/src/future/pages/Assets/components/AssetsTable.d.ts +4 -1
  244. package/dist/admin/src/future/pages/Assets/components/BulkActionsBar.d.ts +8 -1
  245. package/dist/admin/src/future/pages/Assets/components/MainAreaContextMenu.d.ts +28 -0
  246. package/dist/admin/src/future/pages/Assets/constants.d.ts +20 -0
  247. package/dist/admin/src/future/pages/Assets/hooks/useInfiniteAssets.d.ts +4 -0
  248. package/dist/admin/src/future/pages/Assets/hooks/useListScrollRestoration.d.ts +15 -0
  249. package/dist/admin/src/future/pages/Assets/utils/mergeUploadedAssets.d.ts +35 -0
  250. package/dist/admin/src/future/pages/Assets/utils/renderedKeys.d.ts +19 -0
  251. package/dist/admin/src/future/store/uploadProgress.d.ts +51 -0
  252. package/dist/admin/src/utils/index.d.ts +1 -0
  253. package/dist/admin/src/utils/rawFileToAsset.d.ts +2 -2
  254. package/dist/admin/src/utils/resolveFileMime.d.ts +13 -0
  255. package/dist/admin/translations/en.json.js +5 -1
  256. package/dist/admin/translations/en.json.js.map +1 -1
  257. package/dist/admin/translations/en.json.mjs +5 -1
  258. package/dist/admin/translations/en.json.mjs.map +1 -1
  259. package/dist/admin/utils/getFolderURL.js +2 -1
  260. package/dist/admin/utils/getFolderURL.js.map +1 -1
  261. package/dist/admin/utils/getFolderURL.mjs +2 -1
  262. package/dist/admin/utils/getFolderURL.mjs.map +1 -1
  263. package/dist/admin/utils/rawFileToAsset.js +5 -3
  264. package/dist/admin/utils/rawFileToAsset.js.map +1 -1
  265. package/dist/admin/utils/rawFileToAsset.mjs +5 -3
  266. package/dist/admin/utils/rawFileToAsset.mjs.map +1 -1
  267. package/dist/admin/utils/resolveFileMime.js +69 -0
  268. package/dist/admin/utils/resolveFileMime.js.map +1 -0
  269. package/dist/admin/utils/resolveFileMime.mjs +64 -0
  270. package/dist/admin/utils/resolveFileMime.mjs.map +1 -0
  271. package/dist/admin/utils/urlsToAssets.js +8 -4
  272. package/dist/admin/utils/urlsToAssets.js.map +1 -1
  273. package/dist/admin/utils/urlsToAssets.mjs +8 -4
  274. package/dist/admin/utils/urlsToAssets.mjs.map +1 -1
  275. package/dist/server/services/upload.js +20 -8
  276. package/dist/server/services/upload.js.map +1 -1
  277. package/dist/server/services/upload.mjs +20 -8
  278. package/dist/server/services/upload.mjs.map +1 -1
  279. package/dist/server/src/index.d.ts +2 -0
  280. package/dist/server/src/index.d.ts.map +1 -1
  281. package/dist/server/src/services/index.d.ts +2 -0
  282. package/dist/server/src/services/index.d.ts.map +1 -1
  283. package/dist/server/src/services/upload.d.ts +2 -0
  284. package/dist/server/src/services/upload.d.ts.map +1 -1
  285. package/package.json +6 -6
@@ -0,0 +1,179 @@
1
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
+ import { useState, useCallback, useEffect } from 'react';
3
+ import { Menu } from '@strapi/design-system';
4
+ import { Folder, Files, Link } from '@strapi/icons';
5
+ import { useIntl } from 'react-intl';
6
+ import { getTranslationKey } from '../../../utils/translations.mjs';
7
+ import { ActionsMenuContent } from './ActionsMenuContent.mjs';
8
+
9
+ /**
10
+ * The admin layout marks the element that scrolls the main column. Listening on
11
+ * it rather than a wrapper of our own is what makes the whole column part of the
12
+ * hit area: it carries a responsive `padding-bottom` (16 / 24 / 40px) that no
13
+ * descendant can cover, and that strip is exactly where a right-click "below the
14
+ * list" lands.
15
+ */ const SCROLL_ROOT_SELECTOR = '[data-strapi-main-content]';
16
+ /**
17
+ * Subtrees that keep the browser's own context menu instead of opening the
18
+ * create menu.
19
+ *
20
+ * `data-native-context-menu` is the explicit opt-out carried by the list items
21
+ * themselves (asset cards, folder cards, table rows) and by the bulk actions
22
+ * bar — right-clicking one of those must behave exactly as it does today. The
23
+ * rest are the generic cases where the native menu is the useful one: links,
24
+ * buttons and anything the user can type into or select text in.
25
+ *
26
+ * `thead` covers the table's header row, which is chrome rather than empty
27
+ * background even though it carries no `data-native-context-menu` item.
28
+ */ const NATIVE_CONTEXT_MENU_SELECTOR = [
29
+ '[data-native-context-menu]',
30
+ 'thead',
31
+ 'a',
32
+ 'button',
33
+ 'input',
34
+ 'textarea',
35
+ 'select',
36
+ '[contenteditable="true"]'
37
+ ].join(', ');
38
+ /**
39
+ * The menu is anchored to a zero-sized element parked at the cursor, because
40
+ * the design system's `Menu` is a dropdown: it positions its content against a
41
+ * trigger, and there is no real trigger for a right-click on empty space.
42
+ *
43
+ * Inline styles rather than a `styled` wrapper — the trigger renders a design
44
+ * system `Button`, and losing the specificity race with its own class would put
45
+ * a stray button on the page.
46
+ */ const CURSOR_ANCHOR_STYLE = {
47
+ position: 'fixed',
48
+ width: 0,
49
+ height: 0,
50
+ minWidth: 0,
51
+ minHeight: 0,
52
+ padding: 0,
53
+ border: 0,
54
+ opacity: 0,
55
+ overflow: 'hidden',
56
+ pointerEvents: 'none'
57
+ };
58
+ const LOCATOR_STYLE = {
59
+ height: 0
60
+ };
61
+ /**
62
+ * Drive/Dropbox-style right-click on the empty parts of the assets area: the
63
+ * same creation actions the header "New" menu offers, acting on the folder
64
+ * currently open.
65
+ *
66
+ * Renders no wrapper — it finds the scrolling column and listens there, so the
67
+ * hit area is the whole column including the padding below the list.
68
+ *
69
+ * Deliberately background-only. Right-clicking an asset, a folder or a table
70
+ * row is left alone — those carry `data-native-context-menu` and keep the
71
+ * browser's menu (which is what you want over a thumbnail or a filename).
72
+ */ const MainAreaContextMenu = ({ onCreateFolder, onImportFiles, onImportFromUrl, disabled })=>{
73
+ const { formatMessage } = useIntl();
74
+ const [position, setPosition] = useState(null);
75
+ const [locator, setLocator] = useState(null);
76
+ const anchorRef = useCallback((node)=>setLocator(node), []);
77
+ useEffect(()=>{
78
+ const container = locator?.closest(SCROLL_ROOT_SELECTOR);
79
+ if (!container || disabled) {
80
+ return;
81
+ }
82
+ const handleContextMenu = (event)=>{
83
+ if (!(event.target instanceof Element)) {
84
+ return;
85
+ }
86
+ if (event.target.closest(NATIVE_CONTEXT_MENU_SELECTOR)) {
87
+ return;
88
+ }
89
+ event.preventDefault();
90
+ // A right-click while the menu is open reaches Radix's dismiss listener
91
+ // first, which closes it; re-anchoring here reopens it under the new
92
+ // cursor rather than leaving the user with a menu that just vanished.
93
+ setPosition({
94
+ x: event.clientX,
95
+ y: event.clientY
96
+ });
97
+ };
98
+ container.addEventListener('contextmenu', handleContextMenu);
99
+ return ()=>container.removeEventListener('contextmenu', handleContextMenu);
100
+ }, [
101
+ locator,
102
+ disabled
103
+ ]);
104
+ return /*#__PURE__*/ jsxs(Fragment, {
105
+ children: [
106
+ /*#__PURE__*/ jsx("div", {
107
+ ref: anchorRef,
108
+ style: LOCATOR_STYLE,
109
+ "aria-hidden": true
110
+ }),
111
+ !disabled && /*#__PURE__*/ jsxs(Menu.Root, {
112
+ modal: false,
113
+ open: position !== null,
114
+ onOpenChange: (open)=>{
115
+ if (!open) {
116
+ setPosition(null);
117
+ }
118
+ },
119
+ children: [
120
+ /*#__PURE__*/ jsx(Menu.Trigger, {
121
+ tabIndex: -1,
122
+ // No visible content, so the name has to come from `aria-label` —
123
+ // the trigger's `label` prop renders as button text, which would
124
+ // defeat the point of an invisible anchor. Radix points the menu's
125
+ // `aria-labelledby` at this element, so it names the menu too.
126
+ endIcon: null,
127
+ "aria-label": formatMessage({
128
+ id: getTranslationKey('list.context-menu.label'),
129
+ defaultMessage: 'Media library actions'
130
+ }),
131
+ style: {
132
+ ...CURSOR_ANCHOR_STYLE,
133
+ top: position?.y ?? 0,
134
+ left: position?.x ?? 0
135
+ }
136
+ }),
137
+ /*#__PURE__*/ jsxs(ActionsMenuContent, {
138
+ popoverPlacement: "bottom-start",
139
+ zIndex: 2,
140
+ minWidth: "22rem",
141
+ // The anchor is invisible and sits wherever the cursor was, so
142
+ // handing focus back to it on close would be a focus ring nobody can
143
+ // see. Let it fall to the body instead.
144
+ onCloseAutoFocus: (event)=>event.preventDefault(),
145
+ children: [
146
+ /*#__PURE__*/ jsx(Menu.Item, {
147
+ onSelect: onCreateFolder,
148
+ startIcon: /*#__PURE__*/ jsx(Folder, {}),
149
+ children: formatMessage({
150
+ id: getTranslationKey('folder.create.title'),
151
+ defaultMessage: 'New folder'
152
+ })
153
+ }),
154
+ /*#__PURE__*/ jsx(Menu.Item, {
155
+ onSelect: onImportFiles,
156
+ startIcon: /*#__PURE__*/ jsx(Files, {}),
157
+ children: formatMessage({
158
+ id: getTranslationKey('import-files'),
159
+ defaultMessage: 'File upload'
160
+ })
161
+ }),
162
+ /*#__PURE__*/ jsx(Menu.Item, {
163
+ onSelect: onImportFromUrl,
164
+ startIcon: /*#__PURE__*/ jsx(Link, {}),
165
+ children: formatMessage({
166
+ id: getTranslationKey('import-from-url'),
167
+ defaultMessage: 'File upload from URL'
168
+ })
169
+ })
170
+ ]
171
+ })
172
+ ]
173
+ })
174
+ ]
175
+ });
176
+ };
177
+
178
+ export { MainAreaContextMenu };
179
+ //# sourceMappingURL=MainAreaContextMenu.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MainAreaContextMenu.mjs","sources":["../../../../../../admin/src/future/pages/Assets/components/MainAreaContextMenu.tsx"],"sourcesContent":["import { useCallback, useEffect, useState, type CSSProperties } from 'react';\n\nimport { Menu } from '@strapi/design-system';\nimport { Files, Folder as FolderIcon, Link } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\n\nimport { getTranslationKey } from '../../../utils/translations';\n\nimport { ActionsMenuContent } from './ActionsMenuContent';\n\n/**\n * The admin layout marks the element that scrolls the main column. Listening on\n * it rather than a wrapper of our own is what makes the whole column part of the\n * hit area: it carries a responsive `padding-bottom` (16 / 24 / 40px) that no\n * descendant can cover, and that strip is exactly where a right-click \"below the\n * list\" lands.\n */\nconst SCROLL_ROOT_SELECTOR = '[data-strapi-main-content]';\n\n/**\n * Subtrees that keep the browser's own context menu instead of opening the\n * create menu.\n *\n * `data-native-context-menu` is the explicit opt-out carried by the list items\n * themselves (asset cards, folder cards, table rows) and by the bulk actions\n * bar — right-clicking one of those must behave exactly as it does today. The\n * rest are the generic cases where the native menu is the useful one: links,\n * buttons and anything the user can type into or select text in.\n *\n * `thead` covers the table's header row, which is chrome rather than empty\n * background even though it carries no `data-native-context-menu` item.\n */\nconst NATIVE_CONTEXT_MENU_SELECTOR = [\n '[data-native-context-menu]',\n 'thead',\n 'a',\n 'button',\n 'input',\n 'textarea',\n 'select',\n '[contenteditable=\"true\"]',\n].join(', ');\n\n/**\n * The menu is anchored to a zero-sized element parked at the cursor, because\n * the design system's `Menu` is a dropdown: it positions its content against a\n * trigger, and there is no real trigger for a right-click on empty space.\n *\n * Inline styles rather than a `styled` wrapper — the trigger renders a design\n * system `Button`, and losing the specificity race with its own class would put\n * a stray button on the page.\n */\nconst CURSOR_ANCHOR_STYLE: CSSProperties = {\n position: 'fixed',\n width: 0,\n height: 0,\n minWidth: 0,\n minHeight: 0,\n padding: 0,\n border: 0,\n opacity: 0,\n overflow: 'hidden',\n pointerEvents: 'none',\n};\n\nconst LOCATOR_STYLE: CSSProperties = { height: 0 };\n\ninterface CursorPosition {\n x: number;\n y: number;\n}\n\ninterface MainAreaContextMenuProps {\n /** Opens the \"new folder\" dialog in the folder currently on screen. */\n onCreateFolder: () => void;\n /** Opens the native file picker — same entry point as the header \"New\" menu. */\n onImportFiles: () => void;\n /** Opens the \"import from URL\" dialog. */\n onImportFromUrl: () => void;\n /**\n * RBAC gate — without `assets.create` there is nothing to offer, so the\n * right-click falls through to the browser. Required (not defaulted) so a\n * permission gate can't silently regress to permissive.\n */\n disabled: boolean;\n}\n\n/**\n * Drive/Dropbox-style right-click on the empty parts of the assets area: the\n * same creation actions the header \"New\" menu offers, acting on the folder\n * currently open.\n *\n * Renders no wrapper — it finds the scrolling column and listens there, so the\n * hit area is the whole column including the padding below the list.\n *\n * Deliberately background-only. Right-clicking an asset, a folder or a table\n * row is left alone — those carry `data-native-context-menu` and keep the\n * browser's menu (which is what you want over a thumbnail or a filename).\n */\nexport const MainAreaContextMenu = ({\n onCreateFolder,\n onImportFiles,\n onImportFromUrl,\n disabled,\n}: MainAreaContextMenuProps) => {\n const { formatMessage } = useIntl();\n const [position, setPosition] = useState<CursorPosition | null>(null);\n const [locator, setLocator] = useState<HTMLElement | null>(null);\n\n const anchorRef = useCallback((node: HTMLElement | null) => setLocator(node), []);\n\n useEffect(() => {\n const container = locator?.closest<HTMLElement>(SCROLL_ROOT_SELECTOR);\n\n if (!container || disabled) {\n return;\n }\n\n const handleContextMenu = (event: MouseEvent) => {\n if (!(event.target instanceof Element)) {\n return;\n }\n\n if (event.target.closest(NATIVE_CONTEXT_MENU_SELECTOR)) {\n return;\n }\n\n event.preventDefault();\n // A right-click while the menu is open reaches Radix's dismiss listener\n // first, which closes it; re-anchoring here reopens it under the new\n // cursor rather than leaving the user with a menu that just vanished.\n setPosition({ x: event.clientX, y: event.clientY });\n };\n\n container.addEventListener('contextmenu', handleContextMenu);\n\n return () => container.removeEventListener('contextmenu', handleContextMenu);\n }, [locator, disabled]);\n\n return (\n <>\n <div ref={anchorRef} style={LOCATOR_STYLE} aria-hidden />\n {/* Non-modal, like the row-level menus: a right-click elsewhere is both\n \"close this\" and \"open that\", which a modal layer would swallow.\n Skipped entirely without the permission — the anchor is a real\n (if invisible) button, and one that can never open is noise in the\n accessibility tree. */}\n {!disabled && (\n <Menu.Root\n modal={false}\n open={position !== null}\n onOpenChange={(open) => {\n if (!open) {\n setPosition(null);\n }\n }}\n >\n <Menu.Trigger\n tabIndex={-1}\n // No visible content, so the name has to come from `aria-label` —\n // the trigger's `label` prop renders as button text, which would\n // defeat the point of an invisible anchor. Radix points the menu's\n // `aria-labelledby` at this element, so it names the menu too.\n endIcon={null}\n aria-label={formatMessage({\n id: getTranslationKey('list.context-menu.label'),\n defaultMessage: 'Media library actions',\n })}\n style={{ ...CURSOR_ANCHOR_STYLE, top: position?.y ?? 0, left: position?.x ?? 0 }}\n />\n <ActionsMenuContent\n popoverPlacement=\"bottom-start\"\n zIndex={2}\n minWidth=\"22rem\"\n // The anchor is invisible and sits wherever the cursor was, so\n // handing focus back to it on close would be a focus ring nobody can\n // see. Let it fall to the body instead.\n onCloseAutoFocus={(event) => event.preventDefault()}\n >\n <Menu.Item onSelect={onCreateFolder} startIcon={<FolderIcon />}>\n {formatMessage({\n id: getTranslationKey('folder.create.title'),\n defaultMessage: 'New folder',\n })}\n </Menu.Item>\n <Menu.Item onSelect={onImportFiles} startIcon={<Files />}>\n {formatMessage({\n id: getTranslationKey('import-files'),\n defaultMessage: 'File upload',\n })}\n </Menu.Item>\n <Menu.Item onSelect={onImportFromUrl} startIcon={<Link />}>\n {formatMessage({\n id: getTranslationKey('import-from-url'),\n defaultMessage: 'File upload from URL',\n })}\n </Menu.Item>\n </ActionsMenuContent>\n </Menu.Root>\n )}\n </>\n );\n};\n"],"names":["SCROLL_ROOT_SELECTOR","NATIVE_CONTEXT_MENU_SELECTOR","join","CURSOR_ANCHOR_STYLE","position","width","height","minWidth","minHeight","padding","border","opacity","overflow","pointerEvents","LOCATOR_STYLE","MainAreaContextMenu","onCreateFolder","onImportFiles","onImportFromUrl","disabled","formatMessage","useIntl","setPosition","useState","locator","setLocator","anchorRef","useCallback","node","useEffect","container","closest","handleContextMenu","event","target","Element","preventDefault","x","clientX","y","clientY","addEventListener","removeEventListener","_jsxs","_Fragment","_jsx","div","ref","style","aria-hidden","Menu","Root","modal","open","onOpenChange","Trigger","tabIndex","endIcon","aria-label","id","getTranslationKey","defaultMessage","top","left","ActionsMenuContent","popoverPlacement","zIndex","onCloseAutoFocus","Item","onSelect","startIcon","FolderIcon","Files","Link"],"mappings":";;;;;;;;AAUA;;;;;;AAMC,IACD,MAAMA,oBAAAA,GAAuB,4BAAA;AAE7B;;;;;;;;;;;;AAYC,IACD,MAAMC,4BAAAA,GAA+B;AACnC,IAAA,4BAAA;AACA,IAAA,OAAA;AACA,IAAA,GAAA;AACA,IAAA,QAAA;AACA,IAAA,OAAA;AACA,IAAA,UAAA;AACA,IAAA,QAAA;AACA,IAAA;AACD,CAAA,CAACC,IAAI,CAAC,IAAA,CAAA;AAEP;;;;;;;;AAQC,IACD,MAAMC,mBAAAA,GAAqC;IACzCC,QAAAA,EAAU,OAAA;IACVC,KAAAA,EAAO,CAAA;IACPC,MAAAA,EAAQ,CAAA;IACRC,QAAAA,EAAU,CAAA;IACVC,SAAAA,EAAW,CAAA;IACXC,OAAAA,EAAS,CAAA;IACTC,MAAAA,EAAQ,CAAA;IACRC,OAAAA,EAAS,CAAA;IACTC,QAAAA,EAAU,QAAA;IACVC,aAAAA,EAAe;AACjB,CAAA;AAEA,MAAMC,aAAAA,GAA+B;IAAER,MAAAA,EAAQ;AAAE,CAAA;AAsBjD;;;;;;;;;;;AAWC,IACM,MAAMS,mBAAAA,GAAsB,CAAC,EAClCC,cAAc,EACdC,aAAa,EACbC,eAAe,EACfC,QAAQ,EACiB,GAAA;IACzB,MAAM,EAAEC,aAAa,EAAE,GAAGC,OAAAA,EAAAA;AAC1B,IAAA,MAAM,CAACjB,QAAAA,EAAUkB,WAAAA,CAAY,GAAGC,QAAAA,CAAgC,IAAA,CAAA;AAChE,IAAA,MAAM,CAACC,OAAAA,EAASC,UAAAA,CAAW,GAAGF,QAAAA,CAA6B,IAAA,CAAA;AAE3D,IAAA,MAAMG,YAAYC,WAAAA,CAAY,CAACC,IAAAA,GAA6BH,UAAAA,CAAWG,OAAO,EAAE,CAAA;IAEhFC,SAAAA,CAAU,IAAA;QACR,MAAMC,SAAAA,GAAYN,SAASO,OAAAA,CAAqB/B,oBAAAA,CAAAA;QAEhD,IAAI,CAAC8B,aAAaX,QAAAA,EAAU;AAC1B,YAAA;AACF,QAAA;AAEA,QAAA,MAAMa,oBAAoB,CAACC,KAAAA,GAAAA;AACzB,YAAA,IAAI,EAAEA,KAAAA,CAAMC,MAAM,YAAYC,OAAM,CAAA,EAAI;AACtC,gBAAA;AACF,YAAA;AAEA,YAAA,IAAIF,KAAAA,CAAMC,MAAM,CAACH,OAAO,CAAC9B,4BAAAA,CAAAA,EAA+B;AACtD,gBAAA;AACF,YAAA;AAEAgC,YAAAA,KAAAA,CAAMG,cAAc,EAAA;;;;YAIpBd,WAAAA,CAAY;AAAEe,gBAAAA,CAAAA,EAAGJ,MAAMK,OAAO;AAAEC,gBAAAA,CAAAA,EAAGN,MAAMO;AAAQ,aAAA,CAAA;AACnD,QAAA,CAAA;QAEAV,SAAAA,CAAUW,gBAAgB,CAAC,aAAA,EAAeT,iBAAAA,CAAAA;AAE1C,QAAA,OAAO,IAAMF,SAAAA,CAAUY,mBAAmB,CAAC,aAAA,EAAeV,iBAAAA,CAAAA;IAC5D,CAAA,EAAG;AAACR,QAAAA,OAAAA;AAASL,QAAAA;AAAS,KAAA,CAAA;IAEtB,qBACEwB,IAAA,CAAAC,QAAA,EAAA;;0BACEC,GAAA,CAACC,KAAAA,EAAAA;gBAAIC,GAAAA,EAAKrB,SAAAA;gBAAWsB,KAAAA,EAAOlC,aAAAA;gBAAemC,aAAW,EAAA;;YAMrD,CAAC9B,QAAAA,kBACAwB,IAAA,CAACO,IAAAA,CAAKC,IAAI,EAAA;gBACRC,KAAAA,EAAO,KAAA;AACPC,gBAAAA,IAAAA,EAAMjD,QAAAA,KAAa,IAAA;AACnBkD,gBAAAA,YAAAA,EAAc,CAACD,IAAAA,GAAAA;AACb,oBAAA,IAAI,CAACA,IAAAA,EAAM;wBACT/B,WAAAA,CAAY,IAAA,CAAA;AACd,oBAAA;AACF,gBAAA,CAAA;;AAEA,kCAAAuB,GAAA,CAACK,KAAKK,OAAO,EAAA;AACXC,wBAAAA,QAAAA,EAAU,EAAC;;;;;wBAKXC,OAAAA,EAAS,IAAA;AACTC,wBAAAA,YAAAA,EAAYtC,aAAAA,CAAc;AACxBuC,4BAAAA,EAAAA,EAAIC,iBAAAA,CAAkB,yBAAA,CAAA;4BACtBC,cAAAA,EAAgB;AAClB,yBAAA,CAAA;wBACAb,KAAAA,EAAO;AAAE,4BAAA,GAAG7C,mBAAmB;AAAE2D,4BAAAA,GAAAA,EAAK1D,UAAUmC,CAAAA,IAAK,CAAA;AAAGwB,4BAAAA,IAAAA,EAAM3D,UAAUiC,CAAAA,IAAK;AAAE;;kCAEjFM,IAAA,CAACqB,kBAAAA,EAAAA;wBACCC,gBAAAA,EAAiB,cAAA;wBACjBC,MAAAA,EAAQ,CAAA;wBACR3D,QAAAA,EAAS,OAAA;;;;wBAIT4D,gBAAAA,EAAkB,CAAClC,KAAAA,GAAUA,KAAAA,CAAMG,cAAc,EAAA;;AAEjD,0CAAAS,GAAA,CAACK,KAAKkB,IAAI,EAAA;gCAACC,QAAAA,EAAUrD,cAAAA;AAAgBsD,gCAAAA,SAAAA,gBAAWzB,GAAA,CAAC0B,MAAAA,EAAAA,EAAAA,CAAAA;0CAC9CnD,aAAAA,CAAc;AACbuC,oCAAAA,EAAAA,EAAIC,iBAAAA,CAAkB,qBAAA,CAAA;oCACtBC,cAAAA,EAAgB;AAClB,iCAAA;;AAEF,0CAAAhB,GAAA,CAACK,KAAKkB,IAAI,EAAA;gCAACC,QAAAA,EAAUpD,aAAAA;AAAeqD,gCAAAA,SAAAA,gBAAWzB,GAAA,CAAC2B,KAAAA,EAAAA,EAAAA,CAAAA;0CAC7CpD,aAAAA,CAAc;AACbuC,oCAAAA,EAAAA,EAAIC,iBAAAA,CAAkB,cAAA,CAAA;oCACtBC,cAAAA,EAAgB;AAClB,iCAAA;;AAEF,0CAAAhB,GAAA,CAACK,KAAKkB,IAAI,EAAA;gCAACC,QAAAA,EAAUnD,eAAAA;AAAiBoD,gCAAAA,SAAAA,gBAAWzB,GAAA,CAAC4B,IAAAA,EAAAA,EAAAA,CAAAA;0CAC/CrD,aAAAA,CAAc;AACbuC,oCAAAA,EAAAA,EAAIC,iBAAAA,CAAkB,iBAAA,CAAA;oCACtBC,cAAAA,EAAgB;AAClB,iCAAA;;;;;;;;AAOd;;;;"}
@@ -9,6 +9,24 @@ const viewOptions = {
9
9
  GRID: 0,
10
10
  TABLE: 1
11
11
  };
12
+ const ASSET_DETAILS_TRIGGER_ATTRIBUTE = 'data-asset-details-trigger';
13
+ /**
14
+ * Spread onto grid cards and table rows, whose click opens or switches the
15
+ * asset details drawer. The drawer's outside-click dismissal skips presses
16
+ * landing on one of these, so switching assets doesn't close-then-reopen it.
17
+ */ const ASSET_DETAILS_TRIGGER_PROPS = {
18
+ [ASSET_DETAILS_TRIGGER_ATTRIBUTE]: ''
19
+ };
20
+ const ASSET_ITEM_CONTROL_ATTRIBUTE = 'data-asset-item-control';
21
+ /**
22
+ * Spread onto the controls inside an asset card or row that act on the item
23
+ * rather than opening it — its selection checkbox and its actions menu. They
24
+ * stop the card's own click, so no details switch follows them.
25
+ */ const ASSET_ITEM_CONTROL_PROPS = {
26
+ [ASSET_ITEM_CONTROL_ATTRIBUTE]: ''
27
+ };
28
+ /** Matches an element carrying {@link ASSET_ITEM_CONTROL_PROPS}. */ const ASSET_ITEM_CONTROL_SELECTOR = `[${ASSET_ITEM_CONTROL_ATTRIBUTE}]`;
29
+ /** Matches an element carrying {@link ASSET_DETAILS_TRIGGER_PROPS}. */ const ASSET_DETAILS_TRIGGER_SELECTOR = `[${ASSET_DETAILS_TRIGGER_ATTRIBUTE}]`;
12
30
  const TABLE_HEADERS = [
13
31
  {
14
32
  name: 'name',
@@ -48,6 +66,10 @@ const TABLE_HEADERS = [
48
66
  }
49
67
  ];
50
68
 
69
+ exports.ASSET_DETAILS_TRIGGER_PROPS = ASSET_DETAILS_TRIGGER_PROPS;
70
+ exports.ASSET_DETAILS_TRIGGER_SELECTOR = ASSET_DETAILS_TRIGGER_SELECTOR;
71
+ exports.ASSET_ITEM_CONTROL_PROPS = ASSET_ITEM_CONTROL_PROPS;
72
+ exports.ASSET_ITEM_CONTROL_SELECTOR = ASSET_ITEM_CONTROL_SELECTOR;
51
73
  exports.TABLE_HEADERS = TABLE_HEADERS;
52
74
  exports.localStorageKeys = localStorageKeys;
53
75
  exports.viewOptions = viewOptions;
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sources":["../../../../../admin/src/future/pages/Assets/constants.ts"],"sourcesContent":["import { getTranslationKey } from '../../utils/translations';\n\nexport const localStorageKeys = {\n view: `STRAPI_UPLOAD_LIBRARY_VIEW`,\n};\n\nexport const viewOptions = {\n GRID: 0,\n TABLE: 1,\n};\n\ninterface TableHeader {\n name: string;\n label: { id: string; defaultMessage: string };\n isVisuallyHidden?: boolean;\n}\n\nexport const TABLE_HEADERS: TableHeader[] = [\n {\n name: 'name',\n label: { id: getTranslationKey('list.table.header.name'), defaultMessage: 'name' },\n },\n {\n name: 'createdAt',\n label: {\n id: getTranslationKey('list.table.header.creationDate'),\n defaultMessage: 'creation date',\n },\n },\n {\n name: 'updatedAt',\n label: {\n id: getTranslationKey('list.table.header.lastModified'),\n defaultMessage: 'last modified',\n },\n },\n {\n name: 'size',\n label: { id: getTranslationKey('list.table.header.size'), defaultMessage: 'size' },\n },\n {\n name: 'actions',\n label: { id: getTranslationKey('list.table.header.actions'), defaultMessage: 'actions' },\n isVisuallyHidden: true,\n },\n];\n"],"names":["localStorageKeys","view","viewOptions","GRID","TABLE","TABLE_HEADERS","name","label","id","getTranslationKey","defaultMessage","isVisuallyHidden"],"mappings":";;;;MAEaA,gBAAAA,GAAmB;IAC9BC,IAAAA,EAAM,CAAC,0BAA0B;AACnC;MAEaC,WAAAA,GAAc;IACzBC,IAAAA,EAAM,CAAA;IACNC,KAAAA,EAAO;AACT;MAQaC,aAAAA,GAA+B;AAC1C,IAAA;QACEC,IAAAA,EAAM,MAAA;QACNC,KAAAA,EAAO;AAAEC,YAAAA,EAAAA,EAAIC,8BAAAA,CAAkB,wBAAA,CAAA;YAA2BC,cAAAA,EAAgB;AAAO;AACnF,KAAA;AACA,IAAA;QACEJ,IAAAA,EAAM,WAAA;QACNC,KAAAA,EAAO;AACLC,YAAAA,EAAAA,EAAIC,8BAAAA,CAAkB,gCAAA,CAAA;YACtBC,cAAAA,EAAgB;AAClB;AACF,KAAA;AACA,IAAA;QACEJ,IAAAA,EAAM,WAAA;QACNC,KAAAA,EAAO;AACLC,YAAAA,EAAAA,EAAIC,8BAAAA,CAAkB,gCAAA,CAAA;YACtBC,cAAAA,EAAgB;AAClB;AACF,KAAA;AACA,IAAA;QACEJ,IAAAA,EAAM,MAAA;QACNC,KAAAA,EAAO;AAAEC,YAAAA,EAAAA,EAAIC,8BAAAA,CAAkB,wBAAA,CAAA;YAA2BC,cAAAA,EAAgB;AAAO;AACnF,KAAA;AACA,IAAA;QACEJ,IAAAA,EAAM,SAAA;QACNC,KAAAA,EAAO;AAAEC,YAAAA,EAAAA,EAAIC,8BAAAA,CAAkB,2BAAA,CAAA;YAA8BC,cAAAA,EAAgB;AAAU,SAAA;QACvFC,gBAAAA,EAAkB;AACpB;;;;;;;"}
1
+ {"version":3,"file":"constants.js","sources":["../../../../../admin/src/future/pages/Assets/constants.ts"],"sourcesContent":["import { getTranslationKey } from '../../utils/translations';\n\nexport const localStorageKeys = {\n view: `STRAPI_UPLOAD_LIBRARY_VIEW`,\n};\n\nexport const viewOptions = {\n GRID: 0,\n TABLE: 1,\n};\n\nconst ASSET_DETAILS_TRIGGER_ATTRIBUTE = 'data-asset-details-trigger';\n\n/**\n * Spread onto grid cards and table rows, whose click opens or switches the\n * asset details drawer. The drawer's outside-click dismissal skips presses\n * landing on one of these, so switching assets doesn't close-then-reopen it.\n */\nexport const ASSET_DETAILS_TRIGGER_PROPS = { [ASSET_DETAILS_TRIGGER_ATTRIBUTE]: '' };\n\nconst ASSET_ITEM_CONTROL_ATTRIBUTE = 'data-asset-item-control';\n\n/**\n * Spread onto the controls inside an asset card or row that act on the item\n * rather than opening it — its selection checkbox and its actions menu. They\n * stop the card's own click, so no details switch follows them.\n */\nexport const ASSET_ITEM_CONTROL_PROPS = { [ASSET_ITEM_CONTROL_ATTRIBUTE]: '' };\n\n/** Matches an element carrying {@link ASSET_ITEM_CONTROL_PROPS}. */\nexport const ASSET_ITEM_CONTROL_SELECTOR = `[${ASSET_ITEM_CONTROL_ATTRIBUTE}]`;\n\n/** Matches an element carrying {@link ASSET_DETAILS_TRIGGER_PROPS}. */\nexport const ASSET_DETAILS_TRIGGER_SELECTOR = `[${ASSET_DETAILS_TRIGGER_ATTRIBUTE}]`;\n\ninterface TableHeader {\n name: string;\n label: { id: string; defaultMessage: string };\n isVisuallyHidden?: boolean;\n}\n\nexport const TABLE_HEADERS: TableHeader[] = [\n {\n name: 'name',\n label: { id: getTranslationKey('list.table.header.name'), defaultMessage: 'name' },\n },\n {\n name: 'createdAt',\n label: {\n id: getTranslationKey('list.table.header.creationDate'),\n defaultMessage: 'creation date',\n },\n },\n {\n name: 'updatedAt',\n label: {\n id: getTranslationKey('list.table.header.lastModified'),\n defaultMessage: 'last modified',\n },\n },\n {\n name: 'size',\n label: { id: getTranslationKey('list.table.header.size'), defaultMessage: 'size' },\n },\n {\n name: 'actions',\n label: { id: getTranslationKey('list.table.header.actions'), defaultMessage: 'actions' },\n isVisuallyHidden: true,\n },\n];\n"],"names":["localStorageKeys","view","viewOptions","GRID","TABLE","ASSET_DETAILS_TRIGGER_ATTRIBUTE","ASSET_DETAILS_TRIGGER_PROPS","ASSET_ITEM_CONTROL_ATTRIBUTE","ASSET_ITEM_CONTROL_PROPS","ASSET_ITEM_CONTROL_SELECTOR","ASSET_DETAILS_TRIGGER_SELECTOR","TABLE_HEADERS","name","label","id","getTranslationKey","defaultMessage","isVisuallyHidden"],"mappings":";;;;MAEaA,gBAAAA,GAAmB;IAC9BC,IAAAA,EAAM,CAAC,0BAA0B;AACnC;MAEaC,WAAAA,GAAc;IACzBC,IAAAA,EAAM,CAAA;IACNC,KAAAA,EAAO;AACT;AAEA,MAAMC,+BAAAA,GAAkC,4BAAA;AAExC;;;;UAKaC,2BAAAA,GAA8B;AAAE,IAAA,CAACD,kCAAkC;AAAG;AAEnF,MAAME,4BAAAA,GAA+B,yBAAA;AAErC;;;;UAKaC,wBAAAA,GAA2B;AAAE,IAAA,CAACD,+BAA+B;AAAG;AAE7E,qEACO,MAAME,2BAAAA,GAA8B,CAAC,CAAC,EAAEF,4BAAAA,CAA6B,CAAC;AAE7E,wEACO,MAAMG,8BAAAA,GAAiC,CAAC,CAAC,EAAEL,+BAAAA,CAAgC,CAAC;MAQtEM,aAAAA,GAA+B;AAC1C,IAAA;QACEC,IAAAA,EAAM,MAAA;QACNC,KAAAA,EAAO;AAAEC,YAAAA,EAAAA,EAAIC,8BAAAA,CAAkB,wBAAA,CAAA;YAA2BC,cAAAA,EAAgB;AAAO;AACnF,KAAA;AACA,IAAA;QACEJ,IAAAA,EAAM,WAAA;QACNC,KAAAA,EAAO;AACLC,YAAAA,EAAAA,EAAIC,8BAAAA,CAAkB,gCAAA,CAAA;YACtBC,cAAAA,EAAgB;AAClB;AACF,KAAA;AACA,IAAA;QACEJ,IAAAA,EAAM,WAAA;QACNC,KAAAA,EAAO;AACLC,YAAAA,EAAAA,EAAIC,8BAAAA,CAAkB,gCAAA,CAAA;YACtBC,cAAAA,EAAgB;AAClB;AACF,KAAA;AACA,IAAA;QACEJ,IAAAA,EAAM,MAAA;QACNC,KAAAA,EAAO;AAAEC,YAAAA,EAAAA,EAAIC,8BAAAA,CAAkB,wBAAA,CAAA;YAA2BC,cAAAA,EAAgB;AAAO;AACnF,KAAA;AACA,IAAA;QACEJ,IAAAA,EAAM,SAAA;QACNC,KAAAA,EAAO;AAAEC,YAAAA,EAAAA,EAAIC,8BAAAA,CAAkB,2BAAA,CAAA;YAA8BC,cAAAA,EAAgB;AAAU,SAAA;QACvFC,gBAAAA,EAAkB;AACpB;;;;;;;;;;;"}
@@ -7,6 +7,24 @@ const viewOptions = {
7
7
  GRID: 0,
8
8
  TABLE: 1
9
9
  };
10
+ const ASSET_DETAILS_TRIGGER_ATTRIBUTE = 'data-asset-details-trigger';
11
+ /**
12
+ * Spread onto grid cards and table rows, whose click opens or switches the
13
+ * asset details drawer. The drawer's outside-click dismissal skips presses
14
+ * landing on one of these, so switching assets doesn't close-then-reopen it.
15
+ */ const ASSET_DETAILS_TRIGGER_PROPS = {
16
+ [ASSET_DETAILS_TRIGGER_ATTRIBUTE]: ''
17
+ };
18
+ const ASSET_ITEM_CONTROL_ATTRIBUTE = 'data-asset-item-control';
19
+ /**
20
+ * Spread onto the controls inside an asset card or row that act on the item
21
+ * rather than opening it — its selection checkbox and its actions menu. They
22
+ * stop the card's own click, so no details switch follows them.
23
+ */ const ASSET_ITEM_CONTROL_PROPS = {
24
+ [ASSET_ITEM_CONTROL_ATTRIBUTE]: ''
25
+ };
26
+ /** Matches an element carrying {@link ASSET_ITEM_CONTROL_PROPS}. */ const ASSET_ITEM_CONTROL_SELECTOR = `[${ASSET_ITEM_CONTROL_ATTRIBUTE}]`;
27
+ /** Matches an element carrying {@link ASSET_DETAILS_TRIGGER_PROPS}. */ const ASSET_DETAILS_TRIGGER_SELECTOR = `[${ASSET_DETAILS_TRIGGER_ATTRIBUTE}]`;
10
28
  const TABLE_HEADERS = [
11
29
  {
12
30
  name: 'name',
@@ -46,5 +64,5 @@ const TABLE_HEADERS = [
46
64
  }
47
65
  ];
48
66
 
49
- export { TABLE_HEADERS, localStorageKeys, viewOptions };
67
+ export { ASSET_DETAILS_TRIGGER_PROPS, ASSET_DETAILS_TRIGGER_SELECTOR, ASSET_ITEM_CONTROL_PROPS, ASSET_ITEM_CONTROL_SELECTOR, TABLE_HEADERS, localStorageKeys, viewOptions };
50
68
  //# sourceMappingURL=constants.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.mjs","sources":["../../../../../admin/src/future/pages/Assets/constants.ts"],"sourcesContent":["import { getTranslationKey } from '../../utils/translations';\n\nexport const localStorageKeys = {\n view: `STRAPI_UPLOAD_LIBRARY_VIEW`,\n};\n\nexport const viewOptions = {\n GRID: 0,\n TABLE: 1,\n};\n\ninterface TableHeader {\n name: string;\n label: { id: string; defaultMessage: string };\n isVisuallyHidden?: boolean;\n}\n\nexport const TABLE_HEADERS: TableHeader[] = [\n {\n name: 'name',\n label: { id: getTranslationKey('list.table.header.name'), defaultMessage: 'name' },\n },\n {\n name: 'createdAt',\n label: {\n id: getTranslationKey('list.table.header.creationDate'),\n defaultMessage: 'creation date',\n },\n },\n {\n name: 'updatedAt',\n label: {\n id: getTranslationKey('list.table.header.lastModified'),\n defaultMessage: 'last modified',\n },\n },\n {\n name: 'size',\n label: { id: getTranslationKey('list.table.header.size'), defaultMessage: 'size' },\n },\n {\n name: 'actions',\n label: { id: getTranslationKey('list.table.header.actions'), defaultMessage: 'actions' },\n isVisuallyHidden: true,\n },\n];\n"],"names":["localStorageKeys","view","viewOptions","GRID","TABLE","TABLE_HEADERS","name","label","id","getTranslationKey","defaultMessage","isVisuallyHidden"],"mappings":";;MAEaA,gBAAAA,GAAmB;IAC9BC,IAAAA,EAAM,CAAC,0BAA0B;AACnC;MAEaC,WAAAA,GAAc;IACzBC,IAAAA,EAAM,CAAA;IACNC,KAAAA,EAAO;AACT;MAQaC,aAAAA,GAA+B;AAC1C,IAAA;QACEC,IAAAA,EAAM,MAAA;QACNC,KAAAA,EAAO;AAAEC,YAAAA,EAAAA,EAAIC,iBAAAA,CAAkB,wBAAA,CAAA;YAA2BC,cAAAA,EAAgB;AAAO;AACnF,KAAA;AACA,IAAA;QACEJ,IAAAA,EAAM,WAAA;QACNC,KAAAA,EAAO;AACLC,YAAAA,EAAAA,EAAIC,iBAAAA,CAAkB,gCAAA,CAAA;YACtBC,cAAAA,EAAgB;AAClB;AACF,KAAA;AACA,IAAA;QACEJ,IAAAA,EAAM,WAAA;QACNC,KAAAA,EAAO;AACLC,YAAAA,EAAAA,EAAIC,iBAAAA,CAAkB,gCAAA,CAAA;YACtBC,cAAAA,EAAgB;AAClB;AACF,KAAA;AACA,IAAA;QACEJ,IAAAA,EAAM,MAAA;QACNC,KAAAA,EAAO;AAAEC,YAAAA,EAAAA,EAAIC,iBAAAA,CAAkB,wBAAA,CAAA;YAA2BC,cAAAA,EAAgB;AAAO;AACnF,KAAA;AACA,IAAA;QACEJ,IAAAA,EAAM,SAAA;QACNC,KAAAA,EAAO;AAAEC,YAAAA,EAAAA,EAAIC,iBAAAA,CAAkB,2BAAA,CAAA;YAA8BC,cAAAA,EAAgB;AAAU,SAAA;QACvFC,gBAAAA,EAAkB;AACpB;;;;;"}
1
+ {"version":3,"file":"constants.mjs","sources":["../../../../../admin/src/future/pages/Assets/constants.ts"],"sourcesContent":["import { getTranslationKey } from '../../utils/translations';\n\nexport const localStorageKeys = {\n view: `STRAPI_UPLOAD_LIBRARY_VIEW`,\n};\n\nexport const viewOptions = {\n GRID: 0,\n TABLE: 1,\n};\n\nconst ASSET_DETAILS_TRIGGER_ATTRIBUTE = 'data-asset-details-trigger';\n\n/**\n * Spread onto grid cards and table rows, whose click opens or switches the\n * asset details drawer. The drawer's outside-click dismissal skips presses\n * landing on one of these, so switching assets doesn't close-then-reopen it.\n */\nexport const ASSET_DETAILS_TRIGGER_PROPS = { [ASSET_DETAILS_TRIGGER_ATTRIBUTE]: '' };\n\nconst ASSET_ITEM_CONTROL_ATTRIBUTE = 'data-asset-item-control';\n\n/**\n * Spread onto the controls inside an asset card or row that act on the item\n * rather than opening it — its selection checkbox and its actions menu. They\n * stop the card's own click, so no details switch follows them.\n */\nexport const ASSET_ITEM_CONTROL_PROPS = { [ASSET_ITEM_CONTROL_ATTRIBUTE]: '' };\n\n/** Matches an element carrying {@link ASSET_ITEM_CONTROL_PROPS}. */\nexport const ASSET_ITEM_CONTROL_SELECTOR = `[${ASSET_ITEM_CONTROL_ATTRIBUTE}]`;\n\n/** Matches an element carrying {@link ASSET_DETAILS_TRIGGER_PROPS}. */\nexport const ASSET_DETAILS_TRIGGER_SELECTOR = `[${ASSET_DETAILS_TRIGGER_ATTRIBUTE}]`;\n\ninterface TableHeader {\n name: string;\n label: { id: string; defaultMessage: string };\n isVisuallyHidden?: boolean;\n}\n\nexport const TABLE_HEADERS: TableHeader[] = [\n {\n name: 'name',\n label: { id: getTranslationKey('list.table.header.name'), defaultMessage: 'name' },\n },\n {\n name: 'createdAt',\n label: {\n id: getTranslationKey('list.table.header.creationDate'),\n defaultMessage: 'creation date',\n },\n },\n {\n name: 'updatedAt',\n label: {\n id: getTranslationKey('list.table.header.lastModified'),\n defaultMessage: 'last modified',\n },\n },\n {\n name: 'size',\n label: { id: getTranslationKey('list.table.header.size'), defaultMessage: 'size' },\n },\n {\n name: 'actions',\n label: { id: getTranslationKey('list.table.header.actions'), defaultMessage: 'actions' },\n isVisuallyHidden: true,\n },\n];\n"],"names":["localStorageKeys","view","viewOptions","GRID","TABLE","ASSET_DETAILS_TRIGGER_ATTRIBUTE","ASSET_DETAILS_TRIGGER_PROPS","ASSET_ITEM_CONTROL_ATTRIBUTE","ASSET_ITEM_CONTROL_PROPS","ASSET_ITEM_CONTROL_SELECTOR","ASSET_DETAILS_TRIGGER_SELECTOR","TABLE_HEADERS","name","label","id","getTranslationKey","defaultMessage","isVisuallyHidden"],"mappings":";;MAEaA,gBAAAA,GAAmB;IAC9BC,IAAAA,EAAM,CAAC,0BAA0B;AACnC;MAEaC,WAAAA,GAAc;IACzBC,IAAAA,EAAM,CAAA;IACNC,KAAAA,EAAO;AACT;AAEA,MAAMC,+BAAAA,GAAkC,4BAAA;AAExC;;;;UAKaC,2BAAAA,GAA8B;AAAE,IAAA,CAACD,kCAAkC;AAAG;AAEnF,MAAME,4BAAAA,GAA+B,yBAAA;AAErC;;;;UAKaC,wBAAAA,GAA2B;AAAE,IAAA,CAACD,+BAA+B;AAAG;AAE7E,qEACO,MAAME,2BAAAA,GAA8B,CAAC,CAAC,EAAEF,4BAAAA,CAA6B,CAAC;AAE7E,wEACO,MAAMG,8BAAAA,GAAiC,CAAC,CAAC,EAAEL,+BAAAA,CAAgC,CAAC;MAQtEM,aAAAA,GAA+B;AAC1C,IAAA;QACEC,IAAAA,EAAM,MAAA;QACNC,KAAAA,EAAO;AAAEC,YAAAA,EAAAA,EAAIC,iBAAAA,CAAkB,wBAAA,CAAA;YAA2BC,cAAAA,EAAgB;AAAO;AACnF,KAAA;AACA,IAAA;QACEJ,IAAAA,EAAM,WAAA;QACNC,KAAAA,EAAO;AACLC,YAAAA,EAAAA,EAAIC,iBAAAA,CAAkB,gCAAA,CAAA;YACtBC,cAAAA,EAAgB;AAClB;AACF,KAAA;AACA,IAAA;QACEJ,IAAAA,EAAM,WAAA;QACNC,KAAAA,EAAO;AACLC,YAAAA,EAAAA,EAAIC,iBAAAA,CAAkB,gCAAA,CAAA;YACtBC,cAAAA,EAAgB;AAClB;AACF,KAAA;AACA,IAAA;QACEJ,IAAAA,EAAM,MAAA;QACNC,KAAAA,EAAO;AAAEC,YAAAA,EAAAA,EAAIC,iBAAAA,CAAkB,wBAAA,CAAA;YAA2BC,cAAAA,EAAgB;AAAO;AACnF,KAAA;AACA,IAAA;QACEJ,IAAAA,EAAM,SAAA;QACNC,KAAAA,EAAO;AAAEC,YAAAA,EAAAA,EAAIC,iBAAAA,CAAkB,2BAAA,CAAA;YAA8BC,cAAAA,EAAgB;AAAU,SAAA;QACvFC,gBAAAA,EAAkB;AACpB;;;;;"}
@@ -41,10 +41,11 @@ const useFolderNavigation = ()=>{
41
41
  /**
42
42
  * Strips a `?folder=` value we can't parse.
43
43
  */ const stripFolderParam = React.useCallback(()=>{
44
- setQuery({
45
- folder: ''
46
- }, 'remove');
44
+ setQuery(strapiAdmin.withEncodedUserParams(query, {
45
+ folder: undefined
46
+ }));
47
47
  }, [
48
+ query,
48
49
  setQuery
49
50
  ]);
50
51
  // Malformed ?folder= values (e.g. abc) parse as null; strip the param from the URL.
@@ -1 +1 @@
1
- {"version":3,"file":"useFolderNavigation.js","sources":["../../../../../../admin/src/future/pages/Assets/hooks/useFolderNavigation.ts"],"sourcesContent":["import { useCallback, useEffect } from 'react';\n\nimport { useQueryParams } 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({ folder: '' }, 'remove');\n }, [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","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;QACnCJ,QAAAA,CAAS;YAAEN,MAAAA,EAAQ;SAAG,EAAG,QAAA,CAAA;IAC3B,CAAA,EAAG;AAACM,QAAAA;AAAS,KAAA,CAAA;;;IAIbU,eAAAA,CAAU,IAAA;QACR,IAAIX,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,MAAME,kBAAAA,GAAqBP,iBAAAA,CACzB,CAACQ,QAAAA,GAAAA;AACC,QAAA,IAAIA,YAAY,IAAA,EAAM;AACpBJ,YAAAA,cAAAA,EAAAA;QACF,CAAA,MAAO;YACLR,QAAAA,CAAS;AAAEN,gBAAAA,MAAAA,EAAQW,MAAAA,CAAOO,QAAAA,CAAAA;gBAAWN,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;AACAG,QAAAA;AACF,KAAA;AACF;;;;"}
1
+ {"version":3,"file":"useFolderNavigation.js","sources":["../../../../../../admin/src/future/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,5 +1,5 @@
1
1
  import { useCallback, useEffect } from 'react';
2
- import { useQueryParams } from '@strapi/admin/strapi-admin';
2
+ import { useQueryParams, withEncodedUserParams } from '@strapi/admin/strapi-admin';
3
3
 
4
4
  const parseFolderIdFromQuery = (folder)=>{
5
5
  if (!folder) {
@@ -39,10 +39,11 @@ const useFolderNavigation = ()=>{
39
39
  /**
40
40
  * Strips a `?folder=` value we can't parse.
41
41
  */ const stripFolderParam = useCallback(()=>{
42
- setQuery({
43
- folder: ''
44
- }, 'remove');
42
+ setQuery(withEncodedUserParams(query, {
43
+ folder: undefined
44
+ }));
45
45
  }, [
46
+ query,
46
47
  setQuery
47
48
  ]);
48
49
  // Malformed ?folder= values (e.g. abc) parse as null; strip the param from the URL.
@@ -1 +1 @@
1
- {"version":3,"file":"useFolderNavigation.mjs","sources":["../../../../../../admin/src/future/pages/Assets/hooks/useFolderNavigation.ts"],"sourcesContent":["import { useCallback, useEffect } from 'react';\n\nimport { useQueryParams } 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({ folder: '' }, 'remove');\n }, [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","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;QACnCJ,QAAAA,CAAS;YAAEN,MAAAA,EAAQ;SAAG,EAAG,QAAA,CAAA;IAC3B,CAAA,EAAG;AAACM,QAAAA;AAAS,KAAA,CAAA;;;IAIbU,SAAAA,CAAU,IAAA;QACR,IAAIX,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,MAAME,kBAAAA,GAAqBP,WAAAA,CACzB,CAACQ,QAAAA,GAAAA;AACC,QAAA,IAAIA,YAAY,IAAA,EAAM;AACpBJ,YAAAA,cAAAA,EAAAA;QACF,CAAA,MAAO;YACLR,QAAAA,CAAS;AAAEN,gBAAAA,MAAAA,EAAQW,MAAAA,CAAOO,QAAAA,CAAAA;gBAAWN,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;AACAG,QAAAA;AACF,KAAA;AACF;;;;"}
1
+ {"version":3,"file":"useFolderNavigation.mjs","sources":["../../../../../../admin/src/future/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;;;;"}
@@ -4,8 +4,15 @@ var React = require('react');
4
4
  var reactRedux = require('react-redux');
5
5
  var api = require('../../../services/api.js');
6
6
  var assets = require('../../../services/assets.js');
7
+ var hooks = require('../../../store/hooks.js');
8
+ var uploadProgress = require('../../../store/uploadProgress.js');
9
+ var getRelationId = require('../../../utils/getRelationId.js');
10
+ var mergeUploadedAssets = require('../utils/mergeUploadedAssets.js');
7
11
 
8
12
  const PAGE_SIZE = 20;
13
+ /**
14
+ * How many list views keep their loaded pages in memory.
15
+ */ const MAX_REMEMBERED_LISTS = 10;
9
16
  /**
10
17
  * Concatenates the pages in ascending order, one entry per asset id.
11
18
  *
@@ -23,6 +30,10 @@ const PAGE_SIZE = 20;
23
30
  ...byId.values()
24
31
  ];
25
32
  };
33
+ /**
34
+ * The highest page an accumulator holds — where the list was last read to, and
35
+ * so where to resume from on the way back.
36
+ */ const deepestPage = (pages)=>Object.keys(pages).reduce((deepest, key)=>Math.max(deepest, Number(key)), 1);
26
37
  /**
27
38
  * Keeps one earlier page's `getAssets` query subscribed and reports its results
28
39
  * back up whenever they change.
@@ -60,6 +71,10 @@ const PAGE_SIZE = 20;
60
71
  * The caller MUST render the returned `subscribers` node — that is what keeps
61
72
  * every loaded page subscribed, so `{Asset, LIST}` invalidations keep the whole
62
73
  * list consistent rather than only the current page.
74
+ *
75
+ * Loaded pages survive navigating away and back: each list's accumulator is
76
+ * remembered (LRU, `MAX_REMEMBERED_LISTS`) and restored when its key returns, so
77
+ * stepping into a subfolder and back out keeps the rows the user scrolled for.
63
78
  */ const useInfiniteAssets = ({ folder = null, sort, search, filters, enabled = true } = {})=>{
64
79
  // Derived from the request args themselves, so a new filter can't reach the
65
80
  // API without also invalidating what was accumulated under the old one.
@@ -90,17 +105,32 @@ const PAGE_SIZE = 20;
90
105
  listKey,
91
106
  pages: {}
92
107
  });
93
- // Derived rather than read straight from state: the render that discovers
94
- // the key change still reaches the query below, and a list with no page 1
95
- // must never be requested at page 2.
96
- const page = pageState.queryKey === queryKey ? pageState.page : 1;
97
- if (pageState.queryKey !== queryKey) {
108
+ // Each list's loaded pages, kept across navigation away from it.
109
+ const memoryRef = React.useRef(new Map());
110
+ const isNewList = pageState.queryKey !== queryKey;
111
+ const remembered = isNewList ? memoryRef.current.get(queryKey) : undefined;
112
+ // Derived rather than read from state: the render that discovers the key
113
+ // change still reaches the query below, and a list with no page 1 must never
114
+ // be requested at page 2. A remembered list always holds page 1, so resuming
115
+ // at its deepest page can't skip one.
116
+ let page;
117
+ if (!isNewList) {
118
+ page = pageState.page;
119
+ } else if (remembered) {
120
+ page = deepestPage(remembered.pages);
121
+ } else {
122
+ page = 1;
123
+ }
124
+ if (isNewList) {
98
125
  setPageState({
99
126
  queryKey,
100
- page: 1
127
+ page
101
128
  });
129
+ if (remembered) {
130
+ setAccumulated(remembered);
131
+ }
102
132
  }
103
- const { currentData, isLoading, isFetching, error } = assets.useGetAssetsQuery({
133
+ const { currentData, isLoading, isFetching, error, startedTimeStamp, fulfilledTimeStamp } = assets.useGetAssetsQuery({
104
134
  ...queryArgs,
105
135
  page,
106
136
  pageSize: PAGE_SIZE
@@ -111,7 +141,8 @@ const PAGE_SIZE = 20;
111
141
  // `currentData` is only ever the payload for the args just passed, so it
112
142
  // belongs to this key at this page — nothing to infer. Its reference is
113
143
  // stable per cache entry, so this settles after one extra render.
114
- if (currentData && (!isSameQuery || accumulated.pages[page] !== currentData.results)) {
144
+ if (// A restore already set the accumulator from memory; don't overwrite it.
145
+ !remembered && currentData && (!isSameQuery || accumulated.pages[page] !== currentData.results)) {
115
146
  setAccumulated(isSameQuery ? {
116
147
  ...accumulated,
117
148
  pages: {
@@ -159,6 +190,29 @@ const PAGE_SIZE = 20;
159
190
  page: earlierPage,
160
191
  onRefreshed: handlePageRefreshed
161
192
  })));
193
+ // Remember what this list has read, so leaving it isn't forgetting it. Filed
194
+ // under `accumulated.queryKey`, not the live `queryKey`: the accumulator names
195
+ // the list it belongs to, so an entry still describing the list being left
196
+ // can't be misfiled under the one being entered.
197
+ React.useEffect(()=>{
198
+ if (Object.keys(accumulated.pages).length === 0) {
199
+ return;
200
+ }
201
+ const memory = memoryRef.current;
202
+ // Delete before set so the entry moves to the end. Map iterates in
203
+ // insertion order, so the first key is the least recently used.
204
+ memory.delete(accumulated.queryKey);
205
+ memory.set(accumulated.queryKey, accumulated);
206
+ while(memory.size > MAX_REMEMBERED_LISTS){
207
+ const oldest = memory.keys().next();
208
+ if (oldest.done) {
209
+ break;
210
+ }
211
+ memory.delete(oldest.value);
212
+ }
213
+ }, [
214
+ accumulated
215
+ ]);
162
216
  // Drop the left folder's cached `getAssets` pages when the folder changes.
163
217
  //
164
218
  // RTK Query 1.9.7 leaves a query's store subscription in place when its last
@@ -168,8 +222,9 @@ const PAGE_SIZE = 20;
168
222
  // next `{Asset, LIST}` invalidation (an upload in the new folder) refetch the
169
223
  // *previous* folder's pages: one bogus `/upload/files` request per loaded
170
224
  // page. There is no public per-entry unsubscribe, so evict the left folder's
171
- // entries outright returning reloads from page 1, which the accumulator
172
- // already does on a list change.
225
+ // entries outright. Returning then re-reads every page it had loaded, but the
226
+ // rows come straight back from the accumulator memory above — so those
227
+ // requests refresh a list already on screen rather than being waited on.
173
228
  const dispatch = reactRedux.useDispatch();
174
229
  const store = reactRedux.useStore();
175
230
  const prevFolderRef = React.useRef(folder);
@@ -206,14 +261,52 @@ const PAGE_SIZE = 20;
206
261
  // previous folder. Reported as loading so the page shows a spinner instead
207
262
  // of the outgoing folder's assets under the incoming folder's header.
208
263
  const isChangingList = accumulated.listKey !== listKey;
209
- const assets$1 = React.useMemo(()=>isChangingList ? [] : flattenPages(accumulated.pages), [
264
+ const loadedAssets = React.useMemo(()=>isChangingList ? [] : flattenPages(accumulated.pages), [
210
265
  isChangingList,
211
266
  accumulated.pages
212
267
  ]);
213
268
  // Deliberately the live value, not the stale-tolerant one below: paging must
214
269
  // never be driven by a total that belongs to the previous query.
215
270
  const hasNextPage = currentData ? page < currentData.pagination.pageCount : false;
271
+ const completedUploads = hooks.useTypedSelector(uploadProgress.selectCompletedUploads);
272
+ // Only an unfiltered, unsearched list can place an upload locally: deciding
273
+ // whether an asset satisfies a filter means reimplementing the server's
274
+ // filter semantics client-side. Filtered views still refresh on the
275
+ // end-of-batch invalidation, as they did before.
276
+ const canPlaceUploads = !search && (filters?.length ?? 0) === 0;
277
+ // When the loaded data came back from a request that started after a given
278
+ // upload — i.e. the server had already stored it when asked. Past that point
279
+ // the list is the authority on whether the asset is there at all, so bridging
280
+ // must stop: otherwise a later delete or move, which refetches without it,
281
+ // would have it re-inserted.
282
+ const listAnsweredAfter = fulfilledTimeStamp !== undefined && startedTimeStamp !== undefined && // A refetch in flight leaves `fulfilledTimeStamp` on the previous response,
283
+ // which predates this request — so only settled data counts.
284
+ fulfilledTimeStamp > startedTimeStamp ? startedTimeStamp : undefined;
285
+ const assets$1 = React.useMemo(()=>{
286
+ if (!canPlaceUploads || completedUploads.length === 0) {
287
+ return loadedAssets;
288
+ }
289
+ const bridging = completedUploads.filter(({ asset, completedAt })=>getRelationId.getRelationId(asset.folder) === folder && (listAnsweredAfter === undefined || completedAt > listAnsweredAfter));
290
+ return mergeUploadedAssets.mergeUploadedAssets({
291
+ assets: loadedAssets,
292
+ uploaded: bridging.map(({ asset })=>asset),
293
+ sort,
294
+ hasNextPage
295
+ });
296
+ }, [
297
+ canPlaceUploads,
298
+ completedUploads,
299
+ loadedAssets,
300
+ folder,
301
+ sort,
302
+ hasNextPage,
303
+ listAnsweredAfter
304
+ ]);
216
305
  const isFetchingMore = isFetching && page > 1;
306
+ // A restored list already has rows on screen, so re-reading its current page
307
+ // is a background refresh — reporting it as loading would swap those rows for
308
+ // a spinner. Only an empty list has nothing better to show.
309
+ const isLoadingList = isChangingList || isLoading && assets$1.length === 0;
217
310
  const fetchNextPage = React.useCallback(()=>{
218
311
  setPageState((prev)=>({
219
312
  queryKey,
@@ -241,7 +334,7 @@ const PAGE_SIZE = 20;
241
334
  // Falls back to the accumulated total so a consumer showing the count
242
335
  // doesn't flash zero mid-transition, matching the possibly stale `assets`.
243
336
  pagination: currentData?.pagination ?? accumulated.pagination,
244
- isLoading: isLoading || isChangingList,
337
+ isLoading: isLoadingList,
245
338
  isFetchingMore,
246
339
  hasNextPage,
247
340
  fetchNextPage,