@strapi/upload 5.51.2 → 5.52.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) hide show
  1. package/dist/admin/future/App.js +3 -3
  2. package/dist/admin/future/App.js.map +1 -1
  3. package/dist/admin/future/App.mjs +4 -4
  4. package/dist/admin/future/App.mjs.map +1 -1
  5. package/dist/admin/future/components/BetaNotice.js +72 -0
  6. package/dist/admin/future/components/BetaNotice.js.map +1 -0
  7. package/dist/admin/future/components/BetaNotice.mjs +70 -0
  8. package/dist/admin/future/components/BetaNotice.mjs.map +1 -0
  9. package/dist/admin/future/components/Drawer.js +16 -3
  10. package/dist/admin/future/components/Drawer.js.map +1 -1
  11. package/dist/admin/future/components/Drawer.mjs +16 -3
  12. package/dist/admin/future/components/Drawer.mjs.map +1 -1
  13. package/dist/admin/future/components/TruncatedText.js +76 -0
  14. package/dist/admin/future/components/TruncatedText.js.map +1 -0
  15. package/dist/admin/future/components/TruncatedText.mjs +74 -0
  16. package/dist/admin/future/components/TruncatedText.mjs.map +1 -0
  17. package/dist/admin/future/hooks/useAIMetadataEnabled.js +39 -0
  18. package/dist/admin/future/hooks/useAIMetadataEnabled.js.map +1 -0
  19. package/dist/admin/future/hooks/useAIMetadataEnabled.mjs +37 -0
  20. package/dist/admin/future/hooks/useAIMetadataEnabled.mjs.map +1 -0
  21. package/dist/admin/future/hooks/useTracking.js +57 -0
  22. package/dist/admin/future/hooks/useTracking.js.map +1 -0
  23. package/dist/admin/future/hooks/useTracking.mjs +53 -0
  24. package/dist/admin/future/hooks/useTracking.mjs.map +1 -0
  25. package/dist/admin/future/pages/Assets/AssetsPage.js +328 -139
  26. package/dist/admin/future/pages/Assets/AssetsPage.js.map +1 -1
  27. package/dist/admin/future/pages/Assets/AssetsPage.mjs +332 -143
  28. package/dist/admin/future/pages/Assets/AssetsPage.mjs.map +1 -1
  29. package/dist/admin/future/pages/Assets/components/ActionsMenuContent.js +46 -0
  30. package/dist/admin/future/pages/Assets/components/ActionsMenuContent.js.map +1 -0
  31. package/dist/admin/future/pages/Assets/components/ActionsMenuContent.mjs +44 -0
  32. package/dist/admin/future/pages/Assets/components/ActionsMenuContent.mjs.map +1 -0
  33. package/dist/admin/future/pages/Assets/components/AssetActionsMenu.js +328 -0
  34. package/dist/admin/future/pages/Assets/components/AssetActionsMenu.js.map +1 -0
  35. package/dist/admin/future/pages/Assets/components/AssetActionsMenu.mjs +326 -0
  36. package/dist/admin/future/pages/Assets/components/AssetActionsMenu.mjs.map +1 -0
  37. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetCropEditor.js +35 -14
  38. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetCropEditor.js.map +1 -1
  39. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetCropEditor.mjs +35 -14
  40. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetCropEditor.mjs.map +1 -1
  41. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js +74 -53
  42. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js.map +1 -1
  43. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs +74 -54
  44. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs.map +1 -1
  45. package/dist/admin/future/pages/Assets/components/AssetsGrid.js +92 -28
  46. package/dist/admin/future/pages/Assets/components/AssetsGrid.js.map +1 -1
  47. package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs +94 -30
  48. package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs.map +1 -1
  49. package/dist/admin/future/pages/Assets/components/AssetsSearchInput.js +26 -4
  50. package/dist/admin/future/pages/Assets/components/AssetsSearchInput.js.map +1 -1
  51. package/dist/admin/future/pages/Assets/components/AssetsSearchInput.mjs +27 -5
  52. package/dist/admin/future/pages/Assets/components/AssetsSearchInput.mjs.map +1 -1
  53. package/dist/admin/future/pages/Assets/components/AssetsTable.js +172 -60
  54. package/dist/admin/future/pages/Assets/components/AssetsTable.js.map +1 -1
  55. package/dist/admin/future/pages/Assets/components/AssetsTable.mjs +175 -63
  56. package/dist/admin/future/pages/Assets/components/AssetsTable.mjs.map +1 -1
  57. package/dist/admin/future/pages/Assets/components/BulkActionsBar.js +64 -132
  58. package/dist/admin/future/pages/Assets/components/BulkActionsBar.js.map +1 -1
  59. package/dist/admin/future/pages/Assets/components/BulkActionsBar.mjs +64 -132
  60. package/dist/admin/future/pages/Assets/components/BulkActionsBar.mjs.map +1 -1
  61. package/dist/admin/future/pages/Assets/components/BulkMoveDialog.js +123 -76
  62. package/dist/admin/future/pages/Assets/components/BulkMoveDialog.js.map +1 -1
  63. package/dist/admin/future/pages/Assets/components/BulkMoveDialog.mjs +126 -79
  64. package/dist/admin/future/pages/Assets/components/BulkMoveDialog.mjs.map +1 -1
  65. package/dist/admin/future/pages/Assets/components/BusyOverlay.js +36 -0
  66. package/dist/admin/future/pages/Assets/components/BusyOverlay.js.map +1 -0
  67. package/dist/admin/future/pages/Assets/components/BusyOverlay.mjs +34 -0
  68. package/dist/admin/future/pages/Assets/components/BusyOverlay.mjs.map +1 -0
  69. package/dist/admin/future/pages/Assets/components/DeleteItemsDialog.js +131 -0
  70. package/dist/admin/future/pages/Assets/components/DeleteItemsDialog.js.map +1 -0
  71. package/dist/admin/future/pages/Assets/components/DeleteItemsDialog.mjs +129 -0
  72. package/dist/admin/future/pages/Assets/components/DeleteItemsDialog.mjs.map +1 -0
  73. package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.js +27 -17
  74. package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.js.map +1 -1
  75. package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.mjs +28 -18
  76. package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.mjs.map +1 -1
  77. package/dist/admin/future/pages/Assets/components/Dnd/buildDragSet.js +28 -31
  78. package/dist/admin/future/pages/Assets/components/Dnd/buildDragSet.js.map +1 -1
  79. package/dist/admin/future/pages/Assets/components/Dnd/buildDragSet.mjs +28 -31
  80. package/dist/admin/future/pages/Assets/components/Dnd/buildDragSet.mjs.map +1 -1
  81. package/dist/admin/future/pages/Assets/components/Dnd/useAssetDnd.js +10 -15
  82. package/dist/admin/future/pages/Assets/components/Dnd/useAssetDnd.js.map +1 -1
  83. package/dist/admin/future/pages/Assets/components/Dnd/useAssetDnd.mjs +10 -15
  84. package/dist/admin/future/pages/Assets/components/Dnd/useAssetDnd.mjs.map +1 -1
  85. package/dist/admin/future/pages/Assets/components/FilterBadges.js +13 -4
  86. package/dist/admin/future/pages/Assets/components/FilterBadges.js.map +1 -1
  87. package/dist/admin/future/pages/Assets/components/FilterBadges.mjs +13 -4
  88. package/dist/admin/future/pages/Assets/components/FilterBadges.mjs.map +1 -1
  89. package/dist/admin/future/pages/Assets/components/FilterMenu.js +259 -63
  90. package/dist/admin/future/pages/Assets/components/FilterMenu.js.map +1 -1
  91. package/dist/admin/future/pages/Assets/components/FilterMenu.mjs +262 -66
  92. package/dist/admin/future/pages/Assets/components/FilterMenu.mjs.map +1 -1
  93. package/dist/admin/future/pages/Assets/components/FolderActionsMenu.js +146 -0
  94. package/dist/admin/future/pages/Assets/components/FolderActionsMenu.js.map +1 -0
  95. package/dist/admin/future/pages/Assets/components/FolderActionsMenu.mjs +144 -0
  96. package/dist/admin/future/pages/Assets/components/FolderActionsMenu.mjs.map +1 -0
  97. package/dist/admin/future/pages/Assets/components/{CreateFolderDialog.js → FolderFormDialog.js} +62 -16
  98. package/dist/admin/future/pages/Assets/components/FolderFormDialog.js.map +1 -0
  99. package/dist/admin/future/pages/Assets/components/{CreateFolderDialog.mjs → FolderFormDialog.mjs} +64 -18
  100. package/dist/admin/future/pages/Assets/components/FolderFormDialog.mjs.map +1 -0
  101. package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js +132 -229
  102. package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js.map +1 -1
  103. package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs +135 -232
  104. package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs.map +1 -1
  105. package/dist/admin/future/pages/Assets/components/SortMenu.js +14 -0
  106. package/dist/admin/future/pages/Assets/components/SortMenu.js.map +1 -1
  107. package/dist/admin/future/pages/Assets/components/SortMenu.mjs +14 -0
  108. package/dist/admin/future/pages/Assets/components/SortMenu.mjs.map +1 -1
  109. package/dist/admin/future/pages/Assets/hooks/useAssetSelection.js +5 -0
  110. package/dist/admin/future/pages/Assets/hooks/useAssetSelection.js.map +1 -1
  111. package/dist/admin/future/pages/Assets/hooks/useAssetSelection.mjs +6 -1
  112. package/dist/admin/future/pages/Assets/hooks/useAssetSelection.mjs.map +1 -1
  113. package/dist/admin/future/pages/Assets/hooks/useBusyAssets.js +47 -0
  114. package/dist/admin/future/pages/Assets/hooks/useBusyAssets.js.map +1 -0
  115. package/dist/admin/future/pages/Assets/hooks/useBusyAssets.mjs +44 -0
  116. package/dist/admin/future/pages/Assets/hooks/useBusyAssets.mjs.map +1 -0
  117. package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.js +203 -62
  118. package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.js.map +1 -1
  119. package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.mjs +204 -63
  120. package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.mjs.map +1 -1
  121. package/dist/admin/future/pages/Assets/hooks/useInfiniteScrollSentinel.js +75 -0
  122. package/dist/admin/future/pages/Assets/hooks/useInfiniteScrollSentinel.js.map +1 -0
  123. package/dist/admin/future/pages/Assets/hooks/useInfiniteScrollSentinel.mjs +73 -0
  124. package/dist/admin/future/pages/Assets/hooks/useInfiniteScrollSentinel.mjs.map +1 -0
  125. package/dist/admin/future/pages/Assets/utils/selection.js +17 -0
  126. package/dist/admin/future/pages/Assets/utils/selection.js.map +1 -1
  127. package/dist/admin/future/pages/Assets/utils/selection.mjs +17 -1
  128. package/dist/admin/future/pages/Assets/utils/selection.mjs.map +1 -1
  129. package/dist/admin/future/services/api.js +31 -8
  130. package/dist/admin/future/services/api.js.map +1 -1
  131. package/dist/admin/future/services/api.mjs +31 -8
  132. package/dist/admin/future/services/api.mjs.map +1 -1
  133. package/dist/admin/future/services/assets.js +22 -23
  134. package/dist/admin/future/services/assets.js.map +1 -1
  135. package/dist/admin/future/services/assets.mjs +22 -23
  136. package/dist/admin/future/services/assets.mjs.map +1 -1
  137. package/dist/admin/future/services/folders.js +37 -2
  138. package/dist/admin/future/services/folders.js.map +1 -1
  139. package/dist/admin/future/services/folders.mjs +37 -3
  140. package/dist/admin/future/services/folders.mjs.map +1 -1
  141. package/dist/admin/future/utils/buildDragSetFromSelection.js +7 -5
  142. package/dist/admin/future/utils/buildDragSetFromSelection.js.map +1 -1
  143. package/dist/admin/future/utils/buildDragSetFromSelection.mjs +7 -5
  144. package/dist/admin/future/utils/buildDragSetFromSelection.mjs.map +1 -1
  145. package/dist/admin/future/utils/formatMoveSuccessMessage.js +12 -1
  146. package/dist/admin/future/utils/formatMoveSuccessMessage.js.map +1 -1
  147. package/dist/admin/future/utils/formatMoveSuccessMessage.mjs +12 -1
  148. package/dist/admin/future/utils/formatMoveSuccessMessage.mjs.map +1 -1
  149. package/dist/admin/future/utils/getRelationId.js +24 -0
  150. package/dist/admin/future/utils/getRelationId.js.map +1 -0
  151. package/dist/admin/future/utils/getRelationId.mjs +22 -0
  152. package/dist/admin/future/utils/getRelationId.mjs.map +1 -0
  153. package/dist/admin/future/utils/isEventFromWithin.js +14 -0
  154. package/dist/admin/future/utils/isEventFromWithin.js.map +1 -0
  155. package/dist/admin/future/utils/isEventFromWithin.mjs +12 -0
  156. package/dist/admin/future/utils/isEventFromWithin.mjs.map +1 -0
  157. package/dist/admin/future/utils/itemLocations.js +40 -0
  158. package/dist/admin/future/utils/itemLocations.js.map +1 -0
  159. package/dist/admin/future/utils/itemLocations.mjs +36 -0
  160. package/dist/admin/future/utils/itemLocations.mjs.map +1 -0
  161. package/dist/admin/future/utils/itemSource.js +36 -0
  162. package/dist/admin/future/utils/itemSource.js.map +1 -0
  163. package/dist/admin/future/utils/itemSource.mjs +32 -0
  164. package/dist/admin/future/utils/itemSource.mjs.map +1 -0
  165. package/dist/admin/hooks/useAIMetadataJob.js +1 -1
  166. package/dist/admin/hooks/useAIMetadataJob.js.map +1 -1
  167. package/dist/admin/hooks/useAIMetadataJob.mjs +1 -1
  168. package/dist/admin/hooks/useAIMetadataJob.mjs.map +1 -1
  169. package/dist/admin/index.js +11 -17
  170. package/dist/admin/index.js.map +1 -1
  171. package/dist/admin/index.mjs +12 -18
  172. package/dist/admin/index.mjs.map +1 -1
  173. package/dist/admin/pages/SettingsPage/SettingsPage.js +2 -2
  174. package/dist/admin/pages/SettingsPage/SettingsPage.js.map +1 -1
  175. package/dist/admin/pages/SettingsPage/SettingsPage.mjs +2 -2
  176. package/dist/admin/pages/SettingsPage/SettingsPage.mjs.map +1 -1
  177. package/dist/admin/src/future/App.d.ts +1 -1
  178. package/dist/admin/src/future/components/BetaNotice.d.ts +11 -0
  179. package/dist/admin/src/future/components/Drawer.d.ts +5 -1
  180. package/dist/admin/src/future/components/TruncatedText.d.ts +32 -0
  181. package/dist/admin/src/future/hooks/useAIMetadataEnabled.d.ts +26 -0
  182. package/dist/admin/src/future/hooks/useTracking.d.ts +29 -0
  183. package/dist/admin/src/future/pages/Assets/components/ActionsMenuContent.d.ts +33 -0
  184. package/dist/admin/src/future/pages/Assets/components/AssetActionsMenu.d.ts +26 -0
  185. package/dist/admin/src/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.d.ts +16 -0
  186. package/dist/admin/src/future/pages/Assets/components/BulkActionsBar.d.ts +8 -1
  187. package/dist/admin/src/future/pages/Assets/components/BulkMoveDialog.d.ts +17 -6
  188. package/dist/admin/src/future/pages/Assets/components/BusyOverlay.d.ts +9 -0
  189. package/dist/admin/src/future/pages/Assets/components/DeleteItemsDialog.d.ts +27 -0
  190. package/dist/admin/src/future/pages/Assets/components/Dnd/AssetsDndProvider.d.ts +8 -1
  191. package/dist/admin/src/future/pages/Assets/components/Dnd/buildDragSet.d.ts +18 -3
  192. package/dist/admin/src/future/pages/Assets/components/Dnd/useAssetDnd.d.ts +2 -1
  193. package/dist/admin/src/future/pages/Assets/components/FilterBadges.d.ts +3 -1
  194. package/dist/admin/src/future/pages/Assets/components/FilterMenu.d.ts +4 -0
  195. package/dist/admin/src/future/pages/Assets/components/FolderActionsMenu.d.ts +21 -0
  196. package/dist/admin/src/future/pages/Assets/components/FolderFormDialog.d.ts +16 -0
  197. package/dist/admin/src/future/pages/Assets/hooks/useAssetSelection.d.ts +2 -0
  198. package/dist/admin/src/future/pages/Assets/hooks/useBusyAssets.d.ts +38 -0
  199. package/dist/admin/src/future/pages/Assets/hooks/useInfiniteAssets.d.ts +20 -6
  200. package/dist/admin/src/future/pages/Assets/hooks/useInfiniteScrollSentinel.d.ts +41 -0
  201. package/dist/admin/src/future/pages/Assets/utils/selection.d.ts +10 -0
  202. package/dist/admin/src/future/services/api.d.ts +6 -7
  203. package/dist/admin/src/future/services/folders.d.ts +6 -1
  204. package/dist/admin/src/future/utils/buildDragSetFromSelection.d.ts +4 -3
  205. package/dist/admin/src/future/utils/formatMoveSuccessMessage.d.ts +7 -1
  206. package/dist/admin/src/future/utils/getRelationId.d.ts +11 -0
  207. package/dist/admin/src/future/utils/isEventFromWithin.d.ts +11 -0
  208. package/dist/admin/src/future/utils/itemLocations.d.ts +31 -0
  209. package/dist/admin/src/future/utils/itemSource.d.ts +22 -0
  210. package/dist/admin/translations/en.json.js +25 -4
  211. package/dist/admin/translations/en.json.js.map +1 -1
  212. package/dist/admin/translations/en.json.mjs +25 -4
  213. package/dist/admin/translations/en.json.mjs.map +1 -1
  214. package/dist/server/controllers/admin-file.js +27 -9
  215. package/dist/server/controllers/admin-file.js.map +1 -1
  216. package/dist/server/controllers/admin-file.mjs +27 -9
  217. package/dist/server/controllers/admin-file.mjs.map +1 -1
  218. package/dist/server/controllers/admin-upload.js +24 -8
  219. package/dist/server/controllers/admin-upload.js.map +1 -1
  220. package/dist/server/controllers/admin-upload.mjs +24 -8
  221. package/dist/server/controllers/admin-upload.mjs.map +1 -1
  222. package/dist/server/routes/admin.js +41 -21
  223. package/dist/server/routes/admin.js.map +1 -1
  224. package/dist/server/routes/admin.mjs +41 -21
  225. package/dist/server/routes/admin.mjs.map +1 -1
  226. package/dist/server/services/ai-metadata.js.map +1 -1
  227. package/dist/server/services/ai-metadata.mjs.map +1 -1
  228. package/dist/server/services/image-manipulation.js.map +1 -1
  229. package/dist/server/services/image-manipulation.mjs.map +1 -1
  230. package/dist/server/src/controllers/admin-file.d.ts +29 -8
  231. package/dist/server/src/controllers/admin-file.d.ts.map +1 -1
  232. package/dist/server/src/controllers/admin-upload.d.ts +20 -4
  233. package/dist/server/src/controllers/admin-upload.d.ts.map +1 -1
  234. package/dist/server/src/controllers/index.d.ts +4 -4
  235. package/dist/server/src/index.d.ts +4 -4
  236. package/dist/server/src/routes/admin.d.ts.map +1 -1
  237. package/dist/server/src/services/ai-metadata.d.ts +2 -2
  238. package/dist/server/src/services/ai-metadata.d.ts.map +1 -1
  239. package/dist/server/src/services/image-manipulation.d.ts +0 -5
  240. package/dist/server/src/services/image-manipulation.d.ts.map +1 -1
  241. package/dist/shared/contracts/ai-metadata-jobs.d.ts +10 -32
  242. package/dist/shared/contracts/ai-metadata-jobs.d.ts.map +1 -1
  243. package/dist/shared/contracts/files.d.ts +10 -10
  244. package/dist/shared/contracts/files.d.ts.map +1 -1
  245. package/package.json +9 -9
  246. package/dist/admin/future/pages/Assets/components/CreateFolderDialog.js.map +0 -1
  247. package/dist/admin/future/pages/Assets/components/CreateFolderDialog.mjs.map +0 -1
  248. package/dist/admin/future/pages/Assets/components/FolderTree/filterFolderTree.js +0 -33
  249. package/dist/admin/future/pages/Assets/components/FolderTree/filterFolderTree.js.map +0 -1
  250. package/dist/admin/future/pages/Assets/components/FolderTree/filterFolderTree.mjs +0 -31
  251. package/dist/admin/future/pages/Assets/components/FolderTree/filterFolderTree.mjs.map +0 -1
  252. package/dist/admin/src/future/pages/Assets/components/CreateFolderDialog.d.ts +0 -8
  253. package/dist/admin/src/future/pages/Assets/components/FolderTree/filterFolderTree.d.ts +0 -16
@@ -0,0 +1,146 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var React = require('react');
5
+ var strapiAdmin = require('@strapi/admin/strapi-admin');
6
+ var designSystem = require('@strapi/design-system');
7
+ var icons = require('@strapi/icons');
8
+ var reactIntl = require('react-intl');
9
+ var translations = require('../../../utils/translations.js');
10
+ var useAssetSelection = require('../hooks/useAssetSelection.js');
11
+ var selection = require('../utils/selection.js');
12
+ var ActionsMenuContent = require('./ActionsMenuContent.js');
13
+ var BulkMoveDialog = require('./BulkMoveDialog.js');
14
+ var DeleteItemsDialog = require('./DeleteItemsDialog.js');
15
+ var FolderFormDialog = require('./FolderFormDialog.js');
16
+
17
+ /**
18
+ * The "..." menu on a folder row/card. Always acts on that one folder, whatever
19
+ * the current multi-selection is (the bulk actions bar is the selection-scoped
20
+ * affordance). It reuses the shared move and delete dialogs, which mount only
21
+ * while open.
22
+ *
23
+ * A successful move or delete deselects this one folder and leaves the rest of
24
+ * the selection intact: they only invalidate RTK tags, so without it a
25
+ * `folder:<id>` key for a folder that no longer lives where the selection thinks
26
+ * it does would linger. A rename leaves the id valid and the folder in place, so
27
+ * it touches the selection not at all.
28
+ */ const FolderActionsMenu = ({ folder, dragData })=>{
29
+ const { formatMessage } = reactIntl.useIntl();
30
+ const { copy } = strapiAdmin.useClipboard();
31
+ const { toggleNotification } = strapiAdmin.useNotification();
32
+ const { deselect } = useAssetSelection.useAssetSelection();
33
+ const [isRenameOpen, setIsRenameOpen] = React.useState(false);
34
+ const [isMoveOpen, setIsMoveOpen] = React.useState(false);
35
+ const [isDeleteOpen, setIsDeleteOpen] = React.useState(false);
36
+ // Stable identity: the move dialog memoizes its destination walk on it.
37
+ const moveItems = React.useMemo(()=>[
38
+ dragData
39
+ ], [
40
+ dragData
41
+ ]);
42
+ // Built from window.location so the link inherits whatever path the library is
43
+ // mounted at. Every other query param (search, sort, open drawer) is dropped —
44
+ // this is a clean deep-link to the folder.
45
+ const handleCopyLink = async ()=>{
46
+ const url = `${window.location.origin}${window.location.pathname}?folder=${folder.id}`;
47
+ const didCopy = await copy(url);
48
+ toggleNotification({
49
+ type: didCopy ? 'success' : 'danger',
50
+ message: formatMessage(didCopy ? {
51
+ id: translations.getTranslationKey('list.folder.actions.copy-link.success'),
52
+ defaultMessage: 'Folder link copied.'
53
+ } : {
54
+ id: translations.getTranslationKey('list.folder.actions.copy-link.error'),
55
+ defaultMessage: 'Failed to copy the folder link.'
56
+ })
57
+ });
58
+ };
59
+ return /*#__PURE__*/ jsxRuntime.jsxs(jsxRuntime.Fragment, {
60
+ children: [
61
+ /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Menu.Root, {
62
+ modal: false,
63
+ children: [
64
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Menu.Trigger, {
65
+ tag: designSystem.IconButton,
66
+ icon: /*#__PURE__*/ jsxRuntime.jsx(icons.More, {}),
67
+ variant: "ghost",
68
+ label: formatMessage({
69
+ id: translations.getTranslationKey('control-card.more-actions'),
70
+ defaultMessage: 'More actions'
71
+ })
72
+ }),
73
+ /*#__PURE__*/ jsxRuntime.jsxs(ActionsMenuContent.ActionsMenuContent, {
74
+ popoverPlacement: "bottom-end",
75
+ zIndex: 2,
76
+ minWidth: "22rem",
77
+ children: [
78
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Menu.Item, {
79
+ startIcon: /*#__PURE__*/ jsxRuntime.jsx(icons.Link, {}),
80
+ onSelect: handleCopyLink,
81
+ children: formatMessage({
82
+ id: translations.getTranslationKey('list.folder.actions.copy-link'),
83
+ defaultMessage: 'Copy link to folder'
84
+ })
85
+ }),
86
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Menu.Separator, {}),
87
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Menu.Item, {
88
+ startIcon: /*#__PURE__*/ jsxRuntime.jsx(icons.Pencil, {}),
89
+ onSelect: ()=>setIsRenameOpen(true),
90
+ children: formatMessage({
91
+ id: translations.getTranslationKey('list.folder.actions.rename'),
92
+ defaultMessage: 'Rename folder'
93
+ })
94
+ }),
95
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Menu.Item, {
96
+ startIcon: /*#__PURE__*/ jsxRuntime.jsx(icons.ArrowRight, {}),
97
+ onSelect: ()=>setIsMoveOpen(true),
98
+ children: formatMessage({
99
+ id: translations.getTranslationKey('list.folder.actions.move'),
100
+ defaultMessage: 'Move to folder'
101
+ })
102
+ }),
103
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Menu.Item, {
104
+ startIcon: /*#__PURE__*/ jsxRuntime.jsx(icons.Trash, {}),
105
+ variant: "danger",
106
+ onSelect: ()=>setIsDeleteOpen(true),
107
+ children: formatMessage({
108
+ id: translations.getTranslationKey('list.folder.actions.delete'),
109
+ defaultMessage: 'Delete folder'
110
+ })
111
+ })
112
+ ]
113
+ })
114
+ ]
115
+ }),
116
+ isRenameOpen && /*#__PURE__*/ jsxRuntime.jsx(FolderFormDialog.FolderFormDialog, {
117
+ open: true,
118
+ mode: "rename",
119
+ folderId: folder.id,
120
+ initialName: folder.name,
121
+ parentFolderId: dragData.parentId,
122
+ onClose: ()=>setIsRenameOpen(false)
123
+ }),
124
+ isMoveOpen && /*#__PURE__*/ jsxRuntime.jsx(BulkMoveDialog.BulkMoveDialog, {
125
+ open: true,
126
+ onClose: ()=>setIsMoveOpen(false),
127
+ items: moveItems,
128
+ onSuccess: ()=>deselect(selection.folderKey(folder.id))
129
+ }),
130
+ isDeleteOpen && /*#__PURE__*/ jsxRuntime.jsx(DeleteItemsDialog.DeleteItemsDialog, {
131
+ open: true,
132
+ onClose: ()=>setIsDeleteOpen(false),
133
+ target: {
134
+ fileIds: [],
135
+ folderIds: [
136
+ folder.id
137
+ ]
138
+ },
139
+ onSuccess: ()=>deselect(selection.folderKey(folder.id))
140
+ })
141
+ ]
142
+ });
143
+ };
144
+
145
+ exports.FolderActionsMenu = FolderActionsMenu;
146
+ //# sourceMappingURL=FolderActionsMenu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FolderActionsMenu.js","sources":["../../../../../../admin/src/future/pages/Assets/components/FolderActionsMenu.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\n\nimport { useClipboard, useNotification } from '@strapi/admin/strapi-admin';\nimport { IconButton, Menu } from '@strapi/design-system';\nimport { ArrowRight, Link, More, Pencil, Trash } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\n\nimport { getTranslationKey } from '../../../utils/translations';\nimport { useAssetSelection } from '../hooks/useAssetSelection';\nimport { folderKey } from '../utils/selection';\n\nimport { ActionsMenuContent } from './ActionsMenuContent';\nimport { BulkMoveDialog } from './BulkMoveDialog';\nimport { DeleteItemsDialog } from './DeleteItemsDialog';\nimport { FolderFormDialog } from './FolderFormDialog';\n\nimport type { Folder } from '../../../../../../shared/contracts/folders';\nimport type { DragFolderData } from '../../../types/dnd';\n\ninterface FolderActionsMenuProps {\n folder: Folder;\n /** Drag data for this folder, so the move dialog validates against its real parent. */\n dragData: DragFolderData;\n}\n\n/**\n * The \"...\" menu on a folder row/card. Always acts on that one folder, whatever\n * the current multi-selection is (the bulk actions bar is the selection-scoped\n * affordance). It reuses the shared move and delete dialogs, which mount only\n * while open.\n *\n * A successful move or delete deselects this one folder and leaves the rest of\n * the selection intact: they only invalidate RTK tags, so without it a\n * `folder:<id>` key for a folder that no longer lives where the selection thinks\n * it does would linger. A rename leaves the id valid and the folder in place, so\n * it touches the selection not at all.\n */\nexport const FolderActionsMenu = ({ folder, dragData }: FolderActionsMenuProps) => {\n const { formatMessage } = useIntl();\n const { copy } = useClipboard();\n const { toggleNotification } = useNotification();\n const { deselect } = useAssetSelection();\n const [isRenameOpen, setIsRenameOpen] = useState(false);\n const [isMoveOpen, setIsMoveOpen] = useState(false);\n const [isDeleteOpen, setIsDeleteOpen] = useState(false);\n\n // Stable identity: the move dialog memoizes its destination walk on it.\n const moveItems = useMemo(() => [dragData], [dragData]);\n\n // Built from window.location so the link inherits whatever path the library is\n // mounted at. Every other query param (search, sort, open drawer) is dropped —\n // this is a clean deep-link to the folder.\n const handleCopyLink = async () => {\n const url = `${window.location.origin}${window.location.pathname}?folder=${folder.id}`;\n const didCopy = await copy(url);\n\n toggleNotification({\n type: didCopy ? 'success' : 'danger',\n message: formatMessage(\n didCopy\n ? {\n id: getTranslationKey('list.folder.actions.copy-link.success'),\n defaultMessage: 'Folder link copied.',\n }\n : {\n id: getTranslationKey('list.folder.actions.copy-link.error'),\n defaultMessage: 'Failed to copy the folder link.',\n }\n ),\n });\n };\n\n return (\n <>\n {/* See AssetActionsMenu: non-modal so clicking another row's trigger\n closes this menu and opens that one in a single click. */}\n <Menu.Root modal={false}>\n <Menu.Trigger\n tag={IconButton}\n icon={<More />}\n variant=\"ghost\"\n label={formatMessage({\n id: getTranslationKey('control-card.more-actions'),\n defaultMessage: 'More actions',\n })}\n />\n {/* See ActionsMenuContent: the design system's 15rem default clamps the\n menu against a hidden scrollbar, so items can be silently cut off\n near the viewport edge. This one is shorter, but kept in sync. */}\n <ActionsMenuContent popoverPlacement=\"bottom-end\" zIndex={2} minWidth=\"22rem\">\n <Menu.Item startIcon={<Link />} onSelect={handleCopyLink}>\n {formatMessage({\n id: getTranslationKey('list.folder.actions.copy-link'),\n defaultMessage: 'Copy link to folder',\n })}\n </Menu.Item>\n <Menu.Separator />\n {/* TODO: gate Rename, Move and Delete on `assets.canUpdate` CMS-387 */}\n <Menu.Item startIcon={<Pencil />} onSelect={() => setIsRenameOpen(true)}>\n {formatMessage({\n id: getTranslationKey('list.folder.actions.rename'),\n defaultMessage: 'Rename folder',\n })}\n </Menu.Item>\n <Menu.Item startIcon={<ArrowRight />} onSelect={() => setIsMoveOpen(true)}>\n {formatMessage({\n id: getTranslationKey('list.folder.actions.move'),\n defaultMessage: 'Move to folder',\n })}\n </Menu.Item>\n <Menu.Item startIcon={<Trash />} variant=\"danger\" onSelect={() => setIsDeleteOpen(true)}>\n {formatMessage({\n id: getTranslationKey('list.folder.actions.delete'),\n defaultMessage: 'Delete folder',\n })}\n </Menu.Item>\n </ActionsMenuContent>\n </Menu.Root>\n {/* These dialogs live inside the row, so a background refetch that drops\n the row would take an open dialog with it. Nothing invalidates until\n the mutation resolves, and the dialog closes in the same tick, so the\n flows themselves can't trigger it. */}\n {isRenameOpen && (\n <FolderFormDialog\n open\n mode=\"rename\"\n folderId={folder.id}\n initialName={folder.name}\n parentFolderId={dragData.parentId}\n onClose={() => setIsRenameOpen(false)}\n />\n )}\n {isMoveOpen && (\n <BulkMoveDialog\n open\n onClose={() => setIsMoveOpen(false)}\n items={moveItems}\n onSuccess={() => deselect(folderKey(folder.id))}\n />\n )}\n {isDeleteOpen && (\n <DeleteItemsDialog\n open\n onClose={() => setIsDeleteOpen(false)}\n target={{ fileIds: [], folderIds: [folder.id] }}\n onSuccess={() => deselect(folderKey(folder.id))}\n />\n )}\n </>\n );\n};\n"],"names":["FolderActionsMenu","folder","dragData","formatMessage","useIntl","copy","useClipboard","toggleNotification","useNotification","deselect","useAssetSelection","isRenameOpen","setIsRenameOpen","useState","isMoveOpen","setIsMoveOpen","isDeleteOpen","setIsDeleteOpen","moveItems","useMemo","handleCopyLink","url","window","location","origin","pathname","id","didCopy","type","message","getTranslationKey","defaultMessage","_jsxs","_Fragment","Menu","Root","modal","_jsx","Trigger","tag","IconButton","icon","More","variant","label","ActionsMenuContent","popoverPlacement","zIndex","minWidth","Item","startIcon","Link","onSelect","Separator","Pencil","ArrowRight","Trash","FolderFormDialog","open","mode","folderId","initialName","name","parentFolderId","parentId","onClose","BulkMoveDialog","items","onSuccess","folderKey","DeleteItemsDialog","target","fileIds","folderIds"],"mappings":"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"}
@@ -0,0 +1,144 @@
1
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
+ import { useState, useMemo } from 'react';
3
+ import { useClipboard, useNotification } from '@strapi/admin/strapi-admin';
4
+ import { Menu, IconButton } from '@strapi/design-system';
5
+ import { More, Link, Pencil, ArrowRight, Trash } from '@strapi/icons';
6
+ import { useIntl } from 'react-intl';
7
+ import { getTranslationKey } from '../../../utils/translations.mjs';
8
+ import { useAssetSelection } from '../hooks/useAssetSelection.mjs';
9
+ import { folderKey } from '../utils/selection.mjs';
10
+ import { ActionsMenuContent } from './ActionsMenuContent.mjs';
11
+ import { BulkMoveDialog } from './BulkMoveDialog.mjs';
12
+ import { DeleteItemsDialog } from './DeleteItemsDialog.mjs';
13
+ import { FolderFormDialog } from './FolderFormDialog.mjs';
14
+
15
+ /**
16
+ * The "..." menu on a folder row/card. Always acts on that one folder, whatever
17
+ * the current multi-selection is (the bulk actions bar is the selection-scoped
18
+ * affordance). It reuses the shared move and delete dialogs, which mount only
19
+ * while open.
20
+ *
21
+ * A successful move or delete deselects this one folder and leaves the rest of
22
+ * the selection intact: they only invalidate RTK tags, so without it a
23
+ * `folder:<id>` key for a folder that no longer lives where the selection thinks
24
+ * it does would linger. A rename leaves the id valid and the folder in place, so
25
+ * it touches the selection not at all.
26
+ */ const FolderActionsMenu = ({ folder, dragData })=>{
27
+ const { formatMessage } = useIntl();
28
+ const { copy } = useClipboard();
29
+ const { toggleNotification } = useNotification();
30
+ const { deselect } = useAssetSelection();
31
+ const [isRenameOpen, setIsRenameOpen] = useState(false);
32
+ const [isMoveOpen, setIsMoveOpen] = useState(false);
33
+ const [isDeleteOpen, setIsDeleteOpen] = useState(false);
34
+ // Stable identity: the move dialog memoizes its destination walk on it.
35
+ const moveItems = useMemo(()=>[
36
+ dragData
37
+ ], [
38
+ dragData
39
+ ]);
40
+ // Built from window.location so the link inherits whatever path the library is
41
+ // mounted at. Every other query param (search, sort, open drawer) is dropped —
42
+ // this is a clean deep-link to the folder.
43
+ const handleCopyLink = async ()=>{
44
+ const url = `${window.location.origin}${window.location.pathname}?folder=${folder.id}`;
45
+ const didCopy = await copy(url);
46
+ toggleNotification({
47
+ type: didCopy ? 'success' : 'danger',
48
+ message: formatMessage(didCopy ? {
49
+ id: getTranslationKey('list.folder.actions.copy-link.success'),
50
+ defaultMessage: 'Folder link copied.'
51
+ } : {
52
+ id: getTranslationKey('list.folder.actions.copy-link.error'),
53
+ defaultMessage: 'Failed to copy the folder link.'
54
+ })
55
+ });
56
+ };
57
+ return /*#__PURE__*/ jsxs(Fragment, {
58
+ children: [
59
+ /*#__PURE__*/ jsxs(Menu.Root, {
60
+ modal: false,
61
+ children: [
62
+ /*#__PURE__*/ jsx(Menu.Trigger, {
63
+ tag: IconButton,
64
+ icon: /*#__PURE__*/ jsx(More, {}),
65
+ variant: "ghost",
66
+ label: formatMessage({
67
+ id: getTranslationKey('control-card.more-actions'),
68
+ defaultMessage: 'More actions'
69
+ })
70
+ }),
71
+ /*#__PURE__*/ jsxs(ActionsMenuContent, {
72
+ popoverPlacement: "bottom-end",
73
+ zIndex: 2,
74
+ minWidth: "22rem",
75
+ children: [
76
+ /*#__PURE__*/ jsx(Menu.Item, {
77
+ startIcon: /*#__PURE__*/ jsx(Link, {}),
78
+ onSelect: handleCopyLink,
79
+ children: formatMessage({
80
+ id: getTranslationKey('list.folder.actions.copy-link'),
81
+ defaultMessage: 'Copy link to folder'
82
+ })
83
+ }),
84
+ /*#__PURE__*/ jsx(Menu.Separator, {}),
85
+ /*#__PURE__*/ jsx(Menu.Item, {
86
+ startIcon: /*#__PURE__*/ jsx(Pencil, {}),
87
+ onSelect: ()=>setIsRenameOpen(true),
88
+ children: formatMessage({
89
+ id: getTranslationKey('list.folder.actions.rename'),
90
+ defaultMessage: 'Rename folder'
91
+ })
92
+ }),
93
+ /*#__PURE__*/ jsx(Menu.Item, {
94
+ startIcon: /*#__PURE__*/ jsx(ArrowRight, {}),
95
+ onSelect: ()=>setIsMoveOpen(true),
96
+ children: formatMessage({
97
+ id: getTranslationKey('list.folder.actions.move'),
98
+ defaultMessage: 'Move to folder'
99
+ })
100
+ }),
101
+ /*#__PURE__*/ jsx(Menu.Item, {
102
+ startIcon: /*#__PURE__*/ jsx(Trash, {}),
103
+ variant: "danger",
104
+ onSelect: ()=>setIsDeleteOpen(true),
105
+ children: formatMessage({
106
+ id: getTranslationKey('list.folder.actions.delete'),
107
+ defaultMessage: 'Delete folder'
108
+ })
109
+ })
110
+ ]
111
+ })
112
+ ]
113
+ }),
114
+ isRenameOpen && /*#__PURE__*/ jsx(FolderFormDialog, {
115
+ open: true,
116
+ mode: "rename",
117
+ folderId: folder.id,
118
+ initialName: folder.name,
119
+ parentFolderId: dragData.parentId,
120
+ onClose: ()=>setIsRenameOpen(false)
121
+ }),
122
+ isMoveOpen && /*#__PURE__*/ jsx(BulkMoveDialog, {
123
+ open: true,
124
+ onClose: ()=>setIsMoveOpen(false),
125
+ items: moveItems,
126
+ onSuccess: ()=>deselect(folderKey(folder.id))
127
+ }),
128
+ isDeleteOpen && /*#__PURE__*/ jsx(DeleteItemsDialog, {
129
+ open: true,
130
+ onClose: ()=>setIsDeleteOpen(false),
131
+ target: {
132
+ fileIds: [],
133
+ folderIds: [
134
+ folder.id
135
+ ]
136
+ },
137
+ onSuccess: ()=>deselect(folderKey(folder.id))
138
+ })
139
+ ]
140
+ });
141
+ };
142
+
143
+ export { FolderActionsMenu };
144
+ //# sourceMappingURL=FolderActionsMenu.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FolderActionsMenu.mjs","sources":["../../../../../../admin/src/future/pages/Assets/components/FolderActionsMenu.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\n\nimport { useClipboard, useNotification } from '@strapi/admin/strapi-admin';\nimport { IconButton, Menu } from '@strapi/design-system';\nimport { ArrowRight, Link, More, Pencil, Trash } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\n\nimport { getTranslationKey } from '../../../utils/translations';\nimport { useAssetSelection } from '../hooks/useAssetSelection';\nimport { folderKey } from '../utils/selection';\n\nimport { ActionsMenuContent } from './ActionsMenuContent';\nimport { BulkMoveDialog } from './BulkMoveDialog';\nimport { DeleteItemsDialog } from './DeleteItemsDialog';\nimport { FolderFormDialog } from './FolderFormDialog';\n\nimport type { Folder } from '../../../../../../shared/contracts/folders';\nimport type { DragFolderData } from '../../../types/dnd';\n\ninterface FolderActionsMenuProps {\n folder: Folder;\n /** Drag data for this folder, so the move dialog validates against its real parent. */\n dragData: DragFolderData;\n}\n\n/**\n * The \"...\" menu on a folder row/card. Always acts on that one folder, whatever\n * the current multi-selection is (the bulk actions bar is the selection-scoped\n * affordance). It reuses the shared move and delete dialogs, which mount only\n * while open.\n *\n * A successful move or delete deselects this one folder and leaves the rest of\n * the selection intact: they only invalidate RTK tags, so without it a\n * `folder:<id>` key for a folder that no longer lives where the selection thinks\n * it does would linger. A rename leaves the id valid and the folder in place, so\n * it touches the selection not at all.\n */\nexport const FolderActionsMenu = ({ folder, dragData }: FolderActionsMenuProps) => {\n const { formatMessage } = useIntl();\n const { copy } = useClipboard();\n const { toggleNotification } = useNotification();\n const { deselect } = useAssetSelection();\n const [isRenameOpen, setIsRenameOpen] = useState(false);\n const [isMoveOpen, setIsMoveOpen] = useState(false);\n const [isDeleteOpen, setIsDeleteOpen] = useState(false);\n\n // Stable identity: the move dialog memoizes its destination walk on it.\n const moveItems = useMemo(() => [dragData], [dragData]);\n\n // Built from window.location so the link inherits whatever path the library is\n // mounted at. Every other query param (search, sort, open drawer) is dropped —\n // this is a clean deep-link to the folder.\n const handleCopyLink = async () => {\n const url = `${window.location.origin}${window.location.pathname}?folder=${folder.id}`;\n const didCopy = await copy(url);\n\n toggleNotification({\n type: didCopy ? 'success' : 'danger',\n message: formatMessage(\n didCopy\n ? {\n id: getTranslationKey('list.folder.actions.copy-link.success'),\n defaultMessage: 'Folder link copied.',\n }\n : {\n id: getTranslationKey('list.folder.actions.copy-link.error'),\n defaultMessage: 'Failed to copy the folder link.',\n }\n ),\n });\n };\n\n return (\n <>\n {/* See AssetActionsMenu: non-modal so clicking another row's trigger\n closes this menu and opens that one in a single click. */}\n <Menu.Root modal={false}>\n <Menu.Trigger\n tag={IconButton}\n icon={<More />}\n variant=\"ghost\"\n label={formatMessage({\n id: getTranslationKey('control-card.more-actions'),\n defaultMessage: 'More actions',\n })}\n />\n {/* See ActionsMenuContent: the design system's 15rem default clamps the\n menu against a hidden scrollbar, so items can be silently cut off\n near the viewport edge. This one is shorter, but kept in sync. */}\n <ActionsMenuContent popoverPlacement=\"bottom-end\" zIndex={2} minWidth=\"22rem\">\n <Menu.Item startIcon={<Link />} onSelect={handleCopyLink}>\n {formatMessage({\n id: getTranslationKey('list.folder.actions.copy-link'),\n defaultMessage: 'Copy link to folder',\n })}\n </Menu.Item>\n <Menu.Separator />\n {/* TODO: gate Rename, Move and Delete on `assets.canUpdate` CMS-387 */}\n <Menu.Item startIcon={<Pencil />} onSelect={() => setIsRenameOpen(true)}>\n {formatMessage({\n id: getTranslationKey('list.folder.actions.rename'),\n defaultMessage: 'Rename folder',\n })}\n </Menu.Item>\n <Menu.Item startIcon={<ArrowRight />} onSelect={() => setIsMoveOpen(true)}>\n {formatMessage({\n id: getTranslationKey('list.folder.actions.move'),\n defaultMessage: 'Move to folder',\n })}\n </Menu.Item>\n <Menu.Item startIcon={<Trash />} variant=\"danger\" onSelect={() => setIsDeleteOpen(true)}>\n {formatMessage({\n id: getTranslationKey('list.folder.actions.delete'),\n defaultMessage: 'Delete folder',\n })}\n </Menu.Item>\n </ActionsMenuContent>\n </Menu.Root>\n {/* These dialogs live inside the row, so a background refetch that drops\n the row would take an open dialog with it. Nothing invalidates until\n the mutation resolves, and the dialog closes in the same tick, so the\n flows themselves can't trigger it. */}\n {isRenameOpen && (\n <FolderFormDialog\n open\n mode=\"rename\"\n folderId={folder.id}\n initialName={folder.name}\n parentFolderId={dragData.parentId}\n onClose={() => setIsRenameOpen(false)}\n />\n )}\n {isMoveOpen && (\n <BulkMoveDialog\n open\n onClose={() => setIsMoveOpen(false)}\n items={moveItems}\n onSuccess={() => deselect(folderKey(folder.id))}\n />\n )}\n {isDeleteOpen && (\n <DeleteItemsDialog\n open\n onClose={() => setIsDeleteOpen(false)}\n target={{ fileIds: [], folderIds: [folder.id] }}\n onSuccess={() => deselect(folderKey(folder.id))}\n />\n )}\n </>\n );\n};\n"],"names":["FolderActionsMenu","folder","dragData","formatMessage","useIntl","copy","useClipboard","toggleNotification","useNotification","deselect","useAssetSelection","isRenameOpen","setIsRenameOpen","useState","isMoveOpen","setIsMoveOpen","isDeleteOpen","setIsDeleteOpen","moveItems","useMemo","handleCopyLink","url","window","location","origin","pathname","id","didCopy","type","message","getTranslationKey","defaultMessage","_jsxs","_Fragment","Menu","Root","modal","_jsx","Trigger","tag","IconButton","icon","More","variant","label","ActionsMenuContent","popoverPlacement","zIndex","minWidth","Item","startIcon","Link","onSelect","Separator","Pencil","ArrowRight","Trash","FolderFormDialog","open","mode","folderId","initialName","name","parentFolderId","parentId","onClose","BulkMoveDialog","items","onSuccess","folderKey","DeleteItemsDialog","target","fileIds","folderIds"],"mappings":"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"}
@@ -6,25 +6,39 @@ var strapiAdmin = require('@strapi/admin/strapi-admin');
6
6
  var designSystem = require('@strapi/design-system');
7
7
  var reactIntl = require('react-intl');
8
8
  var styledComponents = require('styled-components');
9
+ var useTracking = require('../../../hooks/useTracking.js');
9
10
  var folders = require('../../../services/folders.js');
10
11
  var translations = require('../../../utils/translations.js');
11
12
 
12
13
  const StyledModalContent = styledComponents.styled(designSystem.Modal.Content)`
13
14
  max-width: 51.6rem;
14
15
  `;
15
- const CreateFolderDialog = ({ open, folderName, parentFolderId, onClose })=>{
16
+ const FolderFormDialog = (props)=>{
17
+ const { open, parentFolderId, onClose, mode } = props;
18
+ const initialName = props.mode === 'rename' ? props.initialName : '';
16
19
  const { formatMessage } = reactIntl.useIntl();
17
20
  const { toggleNotification } = strapiAdmin.useNotification();
18
- const [name, setName] = React.useState('');
21
+ const { trackUsage } = useTracking.useTracking();
22
+ const [name, setName] = React.useState(initialName);
19
23
  const [fieldError, setFieldError] = React.useState();
20
- const [createFolder, { isLoading }] = folders.useCreateFolderMutation();
24
+ const inputRef = React.useRef(null);
25
+ const [createFolder, { isLoading: isCreating }] = folders.useCreateFolderMutation();
26
+ const [updateFolder, { isLoading: isUpdating }] = folders.useUpdateFolderMutation();
27
+ const isLoading = mode === 'rename' ? isUpdating : isCreating;
21
28
  React.useEffect(()=>{
22
29
  if (open) {
23
- setName('');
30
+ setName(initialName);
24
31
  setFieldError(undefined);
32
+ // Renaming starts from the current name, so select it: typing replaces
33
+ // the whole thing, as in Finder / VS Code / GitHub.
34
+ if (mode === 'rename') {
35
+ inputRef.current?.select();
36
+ }
25
37
  }
26
38
  }, [
27
- open
39
+ open,
40
+ initialName,
41
+ mode
28
42
  ]);
29
43
  const handleSubmit = async (e)=>{
30
44
  e.preventDefault();
@@ -37,13 +51,34 @@ const CreateFolderDialog = ({ open, folderName, parentFolderId, onClose })=>{
37
51
  return;
38
52
  }
39
53
  try {
40
- await createFolder({
41
- name: trimmedName,
42
- parent: parentFolderId
43
- }).unwrap();
54
+ if (props.mode === 'rename') {
55
+ await updateFolder({
56
+ id: props.folderId,
57
+ name: trimmedName,
58
+ parent: parentFolderId
59
+ }).unwrap();
60
+ // Matches the legacy folder-edit payload. This dialog only renames
61
+ // (parent is fixed), so the location never changes here.
62
+ trackUsage('didEditMediaLibraryElements', {
63
+ location: useTracking.MEDIA_LIBRARY_LOCATION,
64
+ type: 'folder',
65
+ changeLocation: false
66
+ });
67
+ } else {
68
+ await createFolder({
69
+ name: trimmedName,
70
+ parent: parentFolderId
71
+ }).unwrap();
72
+ trackUsage('didAddMediaLibraryFolders', {
73
+ location: useTracking.MEDIA_LIBRARY_LOCATION
74
+ });
75
+ }
44
76
  toggleNotification({
45
77
  type: 'success',
46
- message: formatMessage({
78
+ message: mode === 'rename' ? formatMessage({
79
+ id: translations.getTranslationKey('folder.rename.success'),
80
+ defaultMessage: 'Folder has been renamed'
81
+ }) : formatMessage({
47
82
  id: translations.getTranslationKey('folder.create.success'),
48
83
  defaultMessage: 'Folder has been created'
49
84
  })
@@ -56,7 +91,10 @@ const CreateFolderDialog = ({ open, folderName, parentFolderId, onClose })=>{
56
91
  } else {
57
92
  toggleNotification({
58
93
  type: 'danger',
59
- message: formatMessage({
94
+ message: mode === 'rename' ? formatMessage({
95
+ id: translations.getTranslationKey('folder.rename.form.error.unknown'),
96
+ defaultMessage: 'An error occurred while renaming the folder'
97
+ }) : formatMessage({
60
98
  id: translations.getTranslationKey('folder.create.form.error.unknown'),
61
99
  defaultMessage: 'An error occurred while creating the folder'
62
100
  })
@@ -71,11 +109,14 @@ const CreateFolderDialog = ({ open, folderName, parentFolderId, onClose })=>{
71
109
  children: [
72
110
  /*#__PURE__*/ jsxRuntime.jsx(designSystem.Modal.Header, {
73
111
  children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Modal.Title, {
74
- children: formatMessage({
112
+ children: props.mode === 'rename' ? formatMessage({
113
+ id: translations.getTranslationKey('folder.rename.title'),
114
+ defaultMessage: 'Rename folder'
115
+ }) : formatMessage({
75
116
  id: translations.getTranslationKey('folder.create.title-in'),
76
117
  defaultMessage: 'New folder in {folderName}'
77
118
  }, {
78
- folderName
119
+ folderName: props.parentFolderName
79
120
  })
80
121
  })
81
122
  }),
@@ -95,6 +136,7 @@ const CreateFolderDialog = ({ open, folderName, parentFolderId, onClose })=>{
95
136
  })
96
137
  }),
97
138
  /*#__PURE__*/ jsxRuntime.jsx(designSystem.TextInput, {
139
+ ref: inputRef,
98
140
  value: name,
99
141
  onChange: (e)=>{
100
142
  setName(e.target.value);
@@ -124,7 +166,11 @@ const CreateFolderDialog = ({ open, folderName, parentFolderId, onClose })=>{
124
166
  /*#__PURE__*/ jsxRuntime.jsx(designSystem.Button, {
125
167
  type: "submit",
126
168
  loading: isLoading,
127
- children: formatMessage({
169
+ disabled: mode === 'rename' && name.trim() === initialName.trim(),
170
+ children: mode === 'rename' ? formatMessage({
171
+ id: translations.getTranslationKey('folder.rename.submit'),
172
+ defaultMessage: 'Save'
173
+ }) : formatMessage({
128
174
  id: translations.getTranslationKey('folder.create.submit'),
129
175
  defaultMessage: 'Create folder'
130
176
  })
@@ -139,5 +185,5 @@ const CreateFolderDialog = ({ open, folderName, parentFolderId, onClose })=>{
139
185
  });
140
186
  };
141
187
 
142
- exports.CreateFolderDialog = CreateFolderDialog;
143
- //# sourceMappingURL=CreateFolderDialog.js.map
188
+ exports.FolderFormDialog = FolderFormDialog;
189
+ //# sourceMappingURL=FolderFormDialog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FolderFormDialog.js","sources":["../../../../../../admin/src/future/pages/Assets/components/FolderFormDialog.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\n\nimport { useNotification } from '@strapi/admin/strapi-admin';\nimport { Button, Field, Flex, Modal, TextInput } from '@strapi/design-system';\nimport { useIntl } from 'react-intl';\nimport { styled } from 'styled-components';\n\nimport { useTracking, MEDIA_LIBRARY_LOCATION } from '../../../hooks/useTracking';\nimport { useCreateFolderMutation, useUpdateFolderMutation } from '../../../services/folders';\nimport { getTranslationKey } from '../../../utils/translations';\n\ninterface FolderFormDialogBaseProps {\n open: boolean;\n onClose: () => void;\n /** Sent as `parent`. Create: the folder being created in. Rename: the folder's existing parent. */\n parentFolderId: number | null;\n}\n\ntype FolderFormDialogProps = FolderFormDialogBaseProps &\n (\n | { mode: 'create'; parentFolderName: string }\n | { mode: 'rename'; folderId: number; initialName: string }\n );\n\nconst StyledModalContent = styled(Modal.Content)`\n max-width: 51.6rem;\n`;\n\nexport const FolderFormDialog = (props: FolderFormDialogProps) => {\n const { open, parentFolderId, onClose, mode } = props;\n const initialName = props.mode === 'rename' ? props.initialName : '';\n\n const { formatMessage } = useIntl();\n const { toggleNotification } = useNotification();\n const { trackUsage } = useTracking();\n const [name, setName] = useState(initialName);\n const [fieldError, setFieldError] = useState<string | undefined>();\n const inputRef = useRef<HTMLInputElement>(null);\n const [createFolder, { isLoading: isCreating }] = useCreateFolderMutation();\n const [updateFolder, { isLoading: isUpdating }] = useUpdateFolderMutation();\n\n const isLoading = mode === 'rename' ? isUpdating : isCreating;\n\n useEffect(() => {\n if (open) {\n setName(initialName);\n setFieldError(undefined);\n\n // Renaming starts from the current name, so select it: typing replaces\n // the whole thing, as in Finder / VS Code / GitHub.\n if (mode === 'rename') {\n inputRef.current?.select();\n }\n }\n }, [open, initialName, mode]);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n\n const trimmedName = name.trim();\n\n if (!trimmedName) {\n setFieldError(\n formatMessage({\n id: getTranslationKey('folder.create.form.error.name-required'),\n defaultMessage: 'Name is required',\n })\n );\n return;\n }\n\n try {\n if (props.mode === 'rename') {\n await updateFolder({\n id: props.folderId,\n name: trimmedName,\n parent: parentFolderId,\n }).unwrap();\n // Matches the legacy folder-edit payload. This dialog only renames\n // (parent is fixed), so the location never changes here.\n trackUsage('didEditMediaLibraryElements', {\n location: MEDIA_LIBRARY_LOCATION,\n type: 'folder',\n changeLocation: false,\n });\n } else {\n await createFolder({ name: trimmedName, parent: parentFolderId }).unwrap();\n trackUsage('didAddMediaLibraryFolders', { location: MEDIA_LIBRARY_LOCATION });\n }\n\n toggleNotification({\n type: 'success',\n message:\n mode === 'rename'\n ? formatMessage({\n id: getTranslationKey('folder.rename.success'),\n defaultMessage: 'Folder has been renamed',\n })\n : formatMessage({\n id: getTranslationKey('folder.create.success'),\n defaultMessage: 'Folder has been created',\n }),\n });\n\n onClose();\n } catch (err) {\n const apiError = err as { message?: string };\n\n if (apiError?.message) {\n setFieldError(apiError.message);\n } else {\n toggleNotification({\n type: 'danger',\n message:\n mode === 'rename'\n ? formatMessage({\n id: getTranslationKey('folder.rename.form.error.unknown'),\n defaultMessage: 'An error occurred while renaming the folder',\n })\n : formatMessage({\n id: getTranslationKey('folder.create.form.error.unknown'),\n defaultMessage: 'An error occurred while creating the folder',\n }),\n });\n }\n }\n };\n\n return (\n <Modal.Root open={open} onOpenChange={onClose}>\n <StyledModalContent>\n <Modal.Header>\n <Modal.Title>\n {props.mode === 'rename'\n ? formatMessage({\n id: getTranslationKey('folder.rename.title'),\n defaultMessage: 'Rename folder',\n })\n : formatMessage(\n {\n id: getTranslationKey('folder.create.title-in'),\n defaultMessage: 'New folder in {folderName}',\n },\n { folderName: props.parentFolderName }\n )}\n </Modal.Title>\n </Modal.Header>\n <form onSubmit={handleSubmit}>\n <Modal.Body>\n <Field.Root error={fieldError} name=\"name\" required>\n <Field.Label>\n {formatMessage({\n id: getTranslationKey('folder.form.name.label'),\n defaultMessage: 'Folder name',\n })}\n </Field.Label>\n <TextInput\n ref={inputRef}\n value={name}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n setName(e.target.value);\n setFieldError(undefined);\n }}\n autoFocus\n />\n <Field.Error />\n </Field.Root>\n </Modal.Body>\n <Modal.Footer>\n <Flex gap={2} justifyContent=\"space-between\" width=\"100%\">\n <Button variant=\"tertiary\" onClick={onClose} type=\"button\">\n {formatMessage({ id: 'app.components.Button.cancel', defaultMessage: 'Cancel' })}\n </Button>\n <Button\n type=\"submit\"\n loading={isLoading}\n disabled={mode === 'rename' && name.trim() === initialName.trim()}\n >\n {mode === 'rename'\n ? formatMessage({\n id: getTranslationKey('folder.rename.submit'),\n defaultMessage: 'Save',\n })\n : formatMessage({\n id: getTranslationKey('folder.create.submit'),\n defaultMessage: 'Create folder',\n })}\n </Button>\n </Flex>\n </Modal.Footer>\n </form>\n </StyledModalContent>\n </Modal.Root>\n );\n};\n"],"names":["StyledModalContent","styled","Modal","Content","FolderFormDialog","props","open","parentFolderId","onClose","mode","initialName","formatMessage","useIntl","toggleNotification","useNotification","trackUsage","useTracking","name","setName","useState","fieldError","setFieldError","inputRef","useRef","createFolder","isLoading","isCreating","useCreateFolderMutation","updateFolder","isUpdating","useUpdateFolderMutation","useEffect","undefined","current","select","handleSubmit","e","preventDefault","trimmedName","trim","id","getTranslationKey","defaultMessage","folderId","parent","unwrap","location","MEDIA_LIBRARY_LOCATION","type","changeLocation","message","err","apiError","_jsx","Root","onOpenChange","_jsxs","Header","Title","folderName","parentFolderName","form","onSubmit","Body","Field","error","required","Label","TextInput","ref","value","onChange","target","autoFocus","Error","Footer","Flex","gap","justifyContent","width","Button","variant","onClick","loading","disabled"],"mappings":"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"}