@scality/data-browser-library 1.0.0-preview.9 → 1.0.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 (285) hide show
  1. package/dist/components/DataBrowserUI.d.ts +12 -0
  2. package/dist/components/DataBrowserUI.js +99 -0
  3. package/dist/components/Editor.d.ts +1 -1
  4. package/dist/components/Editor.js +3 -3
  5. package/dist/components/__tests__/BucketAccessor.test.js +214 -0
  6. package/dist/components/__tests__/BucketCorsPage.test.d.ts +1 -0
  7. package/dist/components/__tests__/BucketCorsPage.test.js +263 -0
  8. package/dist/components/__tests__/BucketCreate.test.js +271 -105
  9. package/dist/components/__tests__/BucketDetails.test.d.ts +1 -0
  10. package/dist/components/__tests__/BucketDetails.test.js +421 -0
  11. package/dist/components/__tests__/BucketLifecycleFormPage.test.d.ts +13 -0
  12. package/dist/components/__tests__/BucketLifecycleFormPage.test.js +178 -178
  13. package/dist/components/__tests__/BucketLifecycleList.test.js +85 -85
  14. package/dist/components/__tests__/BucketList.test.js +463 -239
  15. package/dist/components/__tests__/BucketNotificationFormPage.test.d.ts +1 -0
  16. package/dist/components/__tests__/BucketNotificationFormPage.test.js +348 -0
  17. package/dist/components/__tests__/BucketNotificationList.test.d.ts +1 -0
  18. package/dist/components/__tests__/BucketNotificationList.test.js +379 -0
  19. package/dist/components/__tests__/BucketOverview.test.js +281 -266
  20. package/dist/components/__tests__/BucketPolicyPage.test.js +151 -99
  21. package/dist/components/__tests__/BucketReplicationFormPage.test.d.ts +15 -0
  22. package/dist/components/__tests__/BucketReplicationFormPage.test.js +544 -544
  23. package/dist/components/__tests__/BucketReplicationList.test.js +106 -106
  24. package/dist/components/__tests__/CreateFolderButton.test.js +56 -56
  25. package/dist/components/__tests__/DeleteBucketButton.test.js +64 -64
  26. package/dist/components/__tests__/DeleteBucketConfigRuleButton.test.js +47 -47
  27. package/dist/components/__tests__/DeleteObjectButton.test.js +64 -64
  28. package/dist/components/__tests__/EmptyBucketButton.test.js +59 -59
  29. package/dist/components/__tests__/MetadataSearch.test.js +65 -65
  30. package/dist/components/__tests__/ObjectList.test.js +741 -240
  31. package/dist/components/__tests__/UploadButton.test.js +45 -45
  32. package/dist/components/breadcrumb/Breadcrumb.d.ts +6 -0
  33. package/dist/components/breadcrumb/Breadcrumb.js +37 -0
  34. package/dist/components/breadcrumb/DataBrowserBreadcrumb.d.ts +1 -0
  35. package/dist/components/breadcrumb/DataBrowserBreadcrumb.js +10 -0
  36. package/dist/components/breadcrumb/__tests__/Breadcrumb.test.d.ts +1 -0
  37. package/dist/components/breadcrumb/__tests__/Breadcrumb.test.js +196 -0
  38. package/dist/components/breadcrumb/__tests__/DataBrowserBreadcrumb.test.d.ts +1 -0
  39. package/dist/components/breadcrumb/__tests__/DataBrowserBreadcrumb.test.js +153 -0
  40. package/dist/components/breadcrumb/__tests__/useBreadcrumbPaths.test.d.ts +1 -0
  41. package/dist/components/breadcrumb/__tests__/useBreadcrumbPaths.test.js +134 -0
  42. package/dist/components/breadcrumb/index.d.ts +8 -0
  43. package/dist/components/breadcrumb/index.js +4 -0
  44. package/dist/components/breadcrumb/useBreadcrumbPaths.d.ts +2 -0
  45. package/dist/components/breadcrumb/useBreadcrumbPaths.js +82 -0
  46. package/dist/components/buckets/BucketAccessor.d.ts +2 -0
  47. package/dist/components/buckets/BucketAccessor.js +125 -0
  48. package/dist/components/buckets/BucketConfigEditButton.d.ts +8 -0
  49. package/dist/components/buckets/{BucketPolicyButton.js → BucketConfigEditButton.js} +9 -5
  50. package/dist/components/buckets/BucketCorsPage.d.ts +1 -0
  51. package/dist/components/buckets/BucketCorsPage.js +234 -0
  52. package/dist/components/buckets/BucketCreate.d.ts +3 -2
  53. package/dist/components/buckets/BucketCreate.js +89 -47
  54. package/dist/components/buckets/BucketDetails.d.ts +42 -0
  55. package/dist/components/buckets/BucketDetails.js +249 -85
  56. package/dist/components/buckets/BucketLifecycleFormPage.js +206 -190
  57. package/dist/components/buckets/BucketLifecycleList.d.ts +2 -2
  58. package/dist/components/buckets/BucketLifecycleList.js +47 -47
  59. package/dist/components/buckets/BucketList.d.ts +7 -8
  60. package/dist/components/buckets/BucketList.js +158 -101
  61. package/dist/components/buckets/BucketLocation.js +4 -4
  62. package/dist/components/buckets/BucketOverview.d.ts +22 -2
  63. package/dist/components/buckets/BucketOverview.js +394 -187
  64. package/dist/components/buckets/BucketPage.js +43 -21
  65. package/dist/components/buckets/BucketPolicyPage.js +155 -127
  66. package/dist/components/buckets/BucketReplicationFormPage.js +134 -133
  67. package/dist/components/buckets/BucketReplicationList.d.ts +2 -2
  68. package/dist/components/buckets/BucketReplicationList.js +42 -42
  69. package/dist/components/buckets/BucketVersioning.d.ts +4 -0
  70. package/dist/components/buckets/BucketVersioning.js +76 -0
  71. package/dist/components/buckets/DeleteBucketButton.js +8 -8
  72. package/dist/components/buckets/DeleteBucketConfigRuleButton.d.ts +2 -2
  73. package/dist/components/buckets/DeleteBucketConfigRuleButton.js +2 -2
  74. package/dist/components/buckets/EmptyBucketButton.js +24 -24
  75. package/dist/components/buckets/EmptyBucketSummary.d.ts +2 -2
  76. package/dist/components/buckets/EmptyBucketSummary.js +1 -1
  77. package/dist/components/buckets/EmptyBucketSummaryList.d.ts +1 -1
  78. package/dist/components/buckets/EmptyBucketSummaryList.js +22 -22
  79. package/dist/components/buckets/__tests__/BucketVersioning.test.d.ts +1 -0
  80. package/dist/components/buckets/__tests__/BucketVersioning.test.js +163 -0
  81. package/dist/components/buckets/notifications/BucketNotificationFormPage.d.ts +1 -0
  82. package/dist/components/buckets/notifications/BucketNotificationFormPage.js +316 -0
  83. package/dist/components/buckets/notifications/BucketNotificationList.d.ts +10 -0
  84. package/dist/components/buckets/notifications/BucketNotificationList.js +267 -0
  85. package/dist/components/buckets/notifications/EventsSection.js +145 -29
  86. package/dist/components/buckets/notifications/__tests__/events.test.d.ts +1 -0
  87. package/dist/components/buckets/notifications/__tests__/events.test.js +56 -0
  88. package/dist/components/buckets/notifications/events.d.ts +71 -7
  89. package/dist/components/buckets/notifications/events.js +98 -16
  90. package/dist/components/index.d.ts +27 -20
  91. package/dist/components/index.js +17 -10
  92. package/dist/components/layouts/ArrowNavigation.d.ts +3 -0
  93. package/dist/components/layouts/ArrowNavigation.js +28 -0
  94. package/dist/components/layouts/BrowserPageLayout.d.ts +5 -1
  95. package/dist/components/layouts/BrowserPageLayout.js +10 -5
  96. package/dist/components/objects/CreateFolderButton.d.ts +2 -2
  97. package/dist/components/objects/CreateFolderButton.js +12 -12
  98. package/dist/components/objects/DeleteObjectButton.d.ts +1 -1
  99. package/dist/components/objects/DeleteObjectButton.js +19 -21
  100. package/dist/components/objects/GetPresignedUrlButton.d.ts +7 -0
  101. package/dist/components/objects/GetPresignedUrlButton.js +255 -0
  102. package/dist/components/objects/ObjectDetails/ObjectMetadata.d.ts +2 -2
  103. package/dist/components/objects/ObjectDetails/ObjectMetadata.js +263 -230
  104. package/dist/components/objects/ObjectDetails/ObjectSummary.d.ts +2 -2
  105. package/dist/components/objects/ObjectDetails/ObjectSummary.js +540 -138
  106. package/dist/components/objects/ObjectDetails/ObjectTags.d.ts +2 -2
  107. package/dist/components/objects/ObjectDetails/ObjectTags.js +95 -123
  108. package/dist/components/objects/ObjectDetails/__tests__/ObjectDetails.test.d.ts +1 -0
  109. package/dist/components/objects/ObjectDetails/__tests__/ObjectDetails.test.js +516 -0
  110. package/dist/components/objects/ObjectDetails/__tests__/ObjectSummary.test.d.ts +1 -0
  111. package/dist/components/objects/ObjectDetails/__tests__/ObjectSummary.test.js +1064 -0
  112. package/dist/components/objects/ObjectDetails/index.d.ts +18 -2
  113. package/dist/components/objects/ObjectDetails/index.js +152 -40
  114. package/dist/components/objects/ObjectList.d.ts +12 -10
  115. package/dist/components/objects/ObjectList.js +590 -263
  116. package/dist/components/objects/ObjectLock/EditRetentionButton.js +4 -4
  117. package/dist/components/objects/ObjectLock/ObjectLockRetentionSettings.js +15 -15
  118. package/dist/components/objects/ObjectLock/ObjectLockSettings.d.ts +1 -1
  119. package/dist/components/objects/ObjectLock/ObjectLockSettings.js +32 -31
  120. package/dist/components/objects/ObjectLock/ObjectLockSettingsUtils.d.ts +1 -1
  121. package/dist/components/objects/ObjectLock/ObjectLockSettingsUtils.js +6 -6
  122. package/dist/components/objects/ObjectLock/__tests__/EditRetentionButton.test.js +51 -51
  123. package/dist/components/objects/ObjectLock/__tests__/ObjectLockSettings.test.js +78 -78
  124. package/dist/components/objects/ObjectPage.js +12 -8
  125. package/dist/components/objects/UploadButton.d.ts +3 -3
  126. package/dist/components/objects/UploadButton.js +10 -10
  127. package/dist/components/objects/__tests__/GetPresignedUrlButton.test.d.ts +1 -0
  128. package/dist/components/objects/__tests__/GetPresignedUrlButton.test.js +531 -0
  129. package/dist/components/providers/DataBrowserProvider.d.ts +23 -12
  130. package/dist/components/providers/DataBrowserProvider.js +60 -38
  131. package/dist/components/providers/QueryProvider.d.ts +9 -0
  132. package/dist/components/providers/QueryProvider.js +21 -0
  133. package/dist/components/search/MetadataSearch.js +29 -28
  134. package/dist/components/search/SearchHints.js +1 -1
  135. package/dist/components/ui/ArrayFieldActions.js +12 -7
  136. package/dist/components/ui/ConfirmDeleteRuleModal.d.ts +2 -2
  137. package/dist/components/ui/ConfirmDeleteRuleModal.js +6 -1
  138. package/dist/components/ui/DeleteObjectModalContent.d.ts +1 -1
  139. package/dist/components/ui/DeleteObjectModalContent.js +12 -12
  140. package/dist/components/ui/FilterFormSection.d.ts +2 -2
  141. package/dist/components/ui/FilterFormSection.js +29 -29
  142. package/dist/components/ui/Search.elements.d.ts +2 -2
  143. package/dist/components/ui/Search.elements.js +7 -7
  144. package/dist/components/ui/Table.elements.d.ts +2 -1
  145. package/dist/components/ui/Table.elements.js +18 -12
  146. package/dist/config/__tests__/factory.test.d.ts +1 -0
  147. package/dist/config/__tests__/factory.test.js +311 -0
  148. package/dist/config/factory.d.ts +10 -56
  149. package/dist/config/factory.js +23 -71
  150. package/dist/config/types.d.ts +212 -34
  151. package/dist/contexts/DataBrowserUICustomizationContext.d.ts +27 -0
  152. package/dist/contexts/DataBrowserUICustomizationContext.js +13 -0
  153. package/dist/hooks/__tests__/useAccessibleBuckets.test.d.ts +1 -0
  154. package/dist/hooks/__tests__/useAccessibleBuckets.test.js +145 -0
  155. package/dist/hooks/__tests__/useISVBucketDetection.test.js +45 -45
  156. package/dist/hooks/__tests__/useIsBucketEmpty.test.js +27 -27
  157. package/dist/hooks/__tests__/useLoginMutation.test.d.ts +1 -0
  158. package/dist/hooks/__tests__/useLoginMutation.test.js +194 -0
  159. package/dist/hooks/bucketConfiguration.d.ts +8 -1
  160. package/dist/hooks/bucketConfiguration.js +52 -51
  161. package/dist/hooks/bucketOperations.d.ts +10 -1
  162. package/dist/hooks/bucketOperations.js +10 -9
  163. package/dist/hooks/factories/__tests__/useCreateS3FunctionMutationHook.test.js +80 -80
  164. package/dist/hooks/factories/__tests__/useCreateS3InfiniteQueryHook.test.js +80 -80
  165. package/dist/hooks/factories/__tests__/useCreateS3LoginHook.test.js +44 -44
  166. package/dist/hooks/factories/__tests__/useCreateS3MutationHook.test.js +63 -63
  167. package/dist/hooks/factories/__tests__/useCreateS3QueryHook.test.js +65 -65
  168. package/dist/hooks/factories/index.d.ts +4 -4
  169. package/dist/hooks/factories/index.js +2 -2
  170. package/dist/hooks/factories/useCreateS3InfiniteQueryHook.d.ts +2 -2
  171. package/dist/hooks/factories/useCreateS3InfiniteQueryHook.js +16 -13
  172. package/dist/hooks/factories/useCreateS3LoginHook.d.ts +2 -2
  173. package/dist/hooks/factories/useCreateS3LoginHook.js +1 -1
  174. package/dist/hooks/factories/useCreateS3MutationHook.d.ts +3 -3
  175. package/dist/hooks/factories/useCreateS3MutationHook.js +7 -2
  176. package/dist/hooks/factories/useCreateS3QueryHook.d.ts +2 -2
  177. package/dist/hooks/factories/useCreateS3QueryHook.js +11 -6
  178. package/dist/hooks/index.d.ts +19 -12
  179. package/dist/hooks/index.js +16 -9
  180. package/dist/hooks/loginOperations.d.ts +1 -1
  181. package/dist/hooks/loginOperations.js +1 -1
  182. package/dist/hooks/objectOperations.d.ts +2 -2
  183. package/dist/hooks/objectOperations.js +50 -49
  184. package/dist/hooks/presignedOperations.d.ts +4 -4
  185. package/dist/hooks/presignedOperations.js +5 -5
  186. package/dist/hooks/useAccessibleBuckets.d.ts +11 -0
  187. package/dist/hooks/useAccessibleBuckets.js +115 -0
  188. package/dist/hooks/useBatchObjectLegalHold.d.ts +11 -0
  189. package/dist/hooks/useBatchObjectLegalHold.js +48 -0
  190. package/dist/hooks/useBucketConfigEditor.d.ts +31 -0
  191. package/dist/hooks/useBucketConfigEditor.js +82 -0
  192. package/dist/hooks/useDataBrowserNavigate.d.ts +28 -0
  193. package/dist/hooks/useDataBrowserNavigate.js +24 -0
  194. package/dist/hooks/useDeleteBucketConfigRule.d.ts +2 -2
  195. package/dist/hooks/useDeleteBucketConfigRule.js +4 -4
  196. package/dist/hooks/useEmptyBucket.js +11 -11
  197. package/dist/hooks/useFeatures.d.ts +7 -0
  198. package/dist/hooks/useFeatures.js +8 -0
  199. package/dist/hooks/useISVBucketDetection.js +6 -6
  200. package/dist/hooks/useIsBucketEmpty.js +4 -4
  201. package/dist/hooks/useLimitedAccessFlow.d.ts +48 -0
  202. package/dist/hooks/useLimitedAccessFlow.js +23 -0
  203. package/dist/hooks/useS3Client.d.ts +6 -0
  204. package/dist/hooks/useS3Client.js +3 -2
  205. package/dist/hooks/useS3ConfigSwitch.d.ts +11 -0
  206. package/dist/hooks/useS3ConfigSwitch.js +37 -0
  207. package/dist/hooks/useSupportedNotificationEvents.d.ts +6 -0
  208. package/dist/hooks/useSupportedNotificationEvents.js +8 -0
  209. package/dist/index.d.ts +6 -6
  210. package/dist/index.js +2 -2
  211. package/dist/schemas/bucketPolicySchema.json +3 -13
  212. package/dist/test/msw/handlers/deleteBucket.d.ts +1 -1
  213. package/dist/test/msw/handlers/deleteBucket.js +20 -10
  214. package/dist/test/msw/handlers/getBucketAcl.d.ts +1 -1
  215. package/dist/test/msw/handlers/getBucketAcl.js +29 -17
  216. package/dist/test/msw/handlers/getBucketLocation.d.ts +1 -1
  217. package/dist/test/msw/handlers/getBucketLocation.js +29 -15
  218. package/dist/test/msw/handlers/getBucketPolicy.d.ts +1 -1
  219. package/dist/test/msw/handlers/getBucketPolicy.js +52 -32
  220. package/dist/test/msw/handlers/headObject.d.ts +1 -1
  221. package/dist/test/msw/handlers/headObject.js +31 -13
  222. package/dist/test/msw/handlers/listBuckets.d.ts +1 -1
  223. package/dist/test/msw/handlers/listBuckets.js +5 -3
  224. package/dist/test/msw/handlers/listObjectVersions.d.ts +1 -1
  225. package/dist/test/msw/handlers/listObjectVersions.js +38 -26
  226. package/dist/test/msw/handlers/listObjects.d.ts +1 -1
  227. package/dist/test/msw/handlers/listObjects.js +35 -23
  228. package/dist/test/msw/handlers/objectLegalHold.d.ts +1 -1
  229. package/dist/test/msw/handlers/objectLegalHold.js +32 -17
  230. package/dist/test/msw/handlers/objectRetention.d.ts +1 -1
  231. package/dist/test/msw/handlers/objectRetention.js +31 -17
  232. package/dist/test/msw/handlers/putBucketAcl.d.ts +1 -1
  233. package/dist/test/msw/handlers/putBucketAcl.js +29 -14
  234. package/dist/test/msw/handlers/putObject.d.ts +1 -1
  235. package/dist/test/msw/handlers/putObject.js +27 -12
  236. package/dist/test/msw/handlers.d.ts +3 -3
  237. package/dist/test/msw/handlers.js +77 -54
  238. package/dist/test/msw/index.d.ts +2 -2
  239. package/dist/test/msw/index.js +1 -1
  240. package/dist/test/msw/server.d.ts +1 -1
  241. package/dist/test/msw/server.js +1 -1
  242. package/dist/test/msw/utils.js +2 -2
  243. package/dist/test/setup.d.ts +1 -1
  244. package/dist/test/setup.js +13 -30
  245. package/dist/test/testUtils.d.ts +85 -33
  246. package/dist/test/testUtils.js +176 -111
  247. package/dist/test/utils/errorHandling.test.js +119 -119
  248. package/dist/types/index.d.ts +49 -36
  249. package/dist/types/monaco.d.ts +13 -0
  250. package/dist/types/monaco.js +0 -0
  251. package/dist/utils/__tests__/proxyMiddleware.test.d.ts +1 -0
  252. package/dist/utils/__tests__/proxyMiddleware.test.js +579 -0
  253. package/dist/utils/__tests__/s3Client.test.d.ts +1 -0
  254. package/dist/utils/__tests__/s3Client.test.js +340 -0
  255. package/dist/utils/__tests__/s3ConfigIdentifier.test.d.ts +1 -0
  256. package/dist/utils/__tests__/s3ConfigIdentifier.test.js +437 -0
  257. package/dist/utils/constants.d.ts +10 -0
  258. package/dist/utils/constants.js +19 -9
  259. package/dist/utils/deletion/index.d.ts +2 -2
  260. package/dist/utils/deletion/index.js +1 -1
  261. package/dist/utils/deletion/messages.d.ts +1 -1
  262. package/dist/utils/deletion/messages.js +4 -4
  263. package/dist/utils/errorHandling.d.ts +3 -3
  264. package/dist/utils/errorHandling.js +6 -6
  265. package/dist/utils/hooks.js +8 -8
  266. package/dist/utils/index.d.ts +5 -4
  267. package/dist/utils/index.js +4 -2
  268. package/dist/utils/proxyMiddleware.d.ts +32 -13
  269. package/dist/utils/proxyMiddleware.js +90 -36
  270. package/dist/utils/s3Client.d.ts +14 -4
  271. package/dist/utils/s3Client.js +5 -26
  272. package/dist/utils/s3ConfigIdentifier.d.ts +79 -0
  273. package/dist/utils/s3ConfigIdentifier.js +57 -0
  274. package/dist/utils/s3RuleUtils.d.ts +5 -5
  275. package/dist/utils/s3RuleUtils.js +17 -17
  276. package/package.json +10 -8
  277. package/dist/components/__tests__/BucketNotificationCreatePage.test.js +0 -316
  278. package/dist/components/buckets/BucketPolicyButton.d.ts +0 -7
  279. package/dist/components/buckets/notifications/BucketNotificationCreatePage.d.ts +0 -1
  280. package/dist/components/buckets/notifications/BucketNotificationCreatePage.js +0 -234
  281. package/dist/hooks/useLoginMutation.d.ts +0 -21
  282. package/dist/hooks/useLoginMutation.js +0 -9
  283. package/dist/utils/useFeatures.d.ts +0 -1
  284. package/dist/utils/useFeatures.js +0 -7
  285. /package/dist/components/__tests__/{BucketNotificationCreatePage.test.d.ts → BucketAccessor.test.d.ts} +0 -0
@@ -0,0 +1,12 @@
1
+ import type React from 'react';
2
+ import type { DataBrowserUIProps } from '../config/types';
3
+ /**
4
+ * DataBrowserUI component - Main UI component for data browser.
5
+ * Must be wrapped with DataBrowserProvider for S3 configuration context,
6
+ * and a BrowserRouter for routing.
7
+ *
8
+ * Uses relative routing for route definitions. The `basePath` prop is used internally
9
+ * by `useDataBrowserNavigate()` to prefix all navigation paths, allowing the UI to be
10
+ * mounted at any route within your application.
11
+ */
12
+ export declare const DataBrowserUI: React.FC<DataBrowserUIProps>;
@@ -0,0 +1,99 @@
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { AppContainer } from "@scality/core-ui";
3
+ import { Route, Routes } from "react-router";
4
+ import styled_components from "styled-components";
5
+ import { DataBrowserUICustomizationProvider } from "../contexts/DataBrowserUICustomizationContext.js";
6
+ import { useS3ConfigSwitch } from "../hooks/useS3ConfigSwitch.js";
7
+ import { BucketAccessor, BucketCorsPage, BucketCreate, BucketLifecycleFormPage, BucketNotificationFormPage, BucketPage, BucketPolicyPage, BucketReplicationFormPage, ObjectLockSettings, ObjectPage } from "./index.js";
8
+ const RoutesContainer = styled_components.div`
9
+ flex: 1;
10
+ display: flex;
11
+ flex-direction: column;
12
+ width: 100%;
13
+ overflow: hidden;
14
+ `;
15
+ const DataBrowserUIContent = ({ header })=>{
16
+ useS3ConfigSwitch();
17
+ return /*#__PURE__*/ jsx(AppContainer, {
18
+ children: /*#__PURE__*/ jsxs(Fragment, {
19
+ children: [
20
+ header && /*#__PURE__*/ jsx(AppContainer.ContextContainer, {
21
+ children: /*#__PURE__*/ jsx("div", {
22
+ children: header
23
+ })
24
+ }),
25
+ /*#__PURE__*/ jsx(AppContainer.MainContent, {
26
+ children: /*#__PURE__*/ jsx(RoutesContainer, {
27
+ children: /*#__PURE__*/ jsxs(Routes, {
28
+ children: [
29
+ /*#__PURE__*/ jsx(Route, {
30
+ index: true,
31
+ element: /*#__PURE__*/ jsx(BucketPage, {})
32
+ }),
33
+ /*#__PURE__*/ jsx(Route, {
34
+ path: "-/access",
35
+ element: /*#__PURE__*/ jsx(BucketAccessor, {})
36
+ }),
37
+ /*#__PURE__*/ jsx(Route, {
38
+ path: "-/create",
39
+ element: /*#__PURE__*/ jsx(BucketCreate, {})
40
+ }),
41
+ /*#__PURE__*/ jsx(Route, {
42
+ path: ":bucketName/objects/object-lock-settings",
43
+ element: /*#__PURE__*/ jsx(ObjectLockSettings, {})
44
+ }),
45
+ /*#__PURE__*/ jsx(Route, {
46
+ path: ":bucketName/lifecycle/edit/:ruleId",
47
+ element: /*#__PURE__*/ jsx(BucketLifecycleFormPage, {})
48
+ }),
49
+ /*#__PURE__*/ jsx(Route, {
50
+ path: ":bucketName/lifecycle/create",
51
+ element: /*#__PURE__*/ jsx(BucketLifecycleFormPage, {})
52
+ }),
53
+ /*#__PURE__*/ jsx(Route, {
54
+ path: ":bucketName/replication/edit/:ruleId",
55
+ element: /*#__PURE__*/ jsx(BucketReplicationFormPage, {})
56
+ }),
57
+ /*#__PURE__*/ jsx(Route, {
58
+ path: ":bucketName/replication/create",
59
+ element: /*#__PURE__*/ jsx(BucketReplicationFormPage, {})
60
+ }),
61
+ /*#__PURE__*/ jsx(Route, {
62
+ path: ":bucketName/notifications/edit/:ruleId",
63
+ element: /*#__PURE__*/ jsx(BucketNotificationFormPage, {})
64
+ }),
65
+ /*#__PURE__*/ jsx(Route, {
66
+ path: ":bucketName/notifications/create",
67
+ element: /*#__PURE__*/ jsx(BucketNotificationFormPage, {})
68
+ }),
69
+ /*#__PURE__*/ jsx(Route, {
70
+ path: ":bucketName/objects",
71
+ element: /*#__PURE__*/ jsx(ObjectPage, {})
72
+ }),
73
+ /*#__PURE__*/ jsx(Route, {
74
+ path: ":bucketName/policy",
75
+ element: /*#__PURE__*/ jsx(BucketPolicyPage, {})
76
+ }),
77
+ /*#__PURE__*/ jsx(Route, {
78
+ path: ":bucketName/cors",
79
+ element: /*#__PURE__*/ jsx(BucketCorsPage, {})
80
+ }),
81
+ /*#__PURE__*/ jsx(Route, {
82
+ path: ":bucketName/*",
83
+ element: /*#__PURE__*/ jsx(BucketPage, {})
84
+ })
85
+ ]
86
+ })
87
+ })
88
+ })
89
+ ]
90
+ })
91
+ });
92
+ };
93
+ const DataBrowserUI = (props)=>/*#__PURE__*/ jsx(DataBrowserUICustomizationProvider, {
94
+ config: props,
95
+ children: /*#__PURE__*/ jsx(DataBrowserUIContent, {
96
+ header: props.header
97
+ })
98
+ });
99
+ export { DataBrowserUI };
@@ -1,4 +1,4 @@
1
- import { EditorProps, BeforeMount } from "@monaco-editor/react";
1
+ import { type BeforeMount, type EditorProps } from '@monaco-editor/react';
2
2
  interface EditorComponentProps {
3
3
  value: string;
4
4
  onChange: (value: string | undefined) => void;
@@ -1,7 +1,7 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import react from "@monaco-editor/react";
3
- const Editor = ({ value, onChange, readOnly = false, language = "json", height = "400px", width = "100%", beforeMount, ...rest })=>{
4
- const editorTheme = "vs-dark";
3
+ const Editor = ({ value, onChange, readOnly = false, language = 'json', height = '400px', width = '100%', beforeMount, ...rest })=>{
4
+ const editorTheme = 'vs-dark';
5
5
  return /*#__PURE__*/ jsx(react, {
6
6
  height: height,
7
7
  width: width,
@@ -16,7 +16,7 @@ const Editor = ({ value, onChange, readOnly = false, language = "json", height =
16
16
  enabled: false
17
17
  },
18
18
  fontSize: 12,
19
- lineNumbers: "on",
19
+ lineNumbers: 'on',
20
20
  automaticLayout: true,
21
21
  formatOnPaste: true,
22
22
  formatOnType: true
@@ -0,0 +1,214 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { render, screen, waitFor } from "@testing-library/react";
3
+ import user_event from "@testing-library/user-event";
4
+ import { MemoryRouter } from "react-router";
5
+ import { useAccessibleBuckets, useValidateBucketAccess } from "../../hooks/index.js";
6
+ import { createTestWrapper } from "../../test/testUtils.js";
7
+ import { BucketAccessor } from "../buckets/BucketAccessor.js";
8
+ jest.mock('../../hooks', ()=>({
9
+ useAccessibleBuckets: jest.fn(),
10
+ useValidateBucketAccess: jest.fn()
11
+ }));
12
+ const mockUseAccessibleBuckets = jest.mocked(useAccessibleBuckets);
13
+ const mockUseValidateBucketAccess = jest.mocked(useValidateBucketAccess);
14
+ const mockNavigate = jest.fn();
15
+ const mockShowToast = jest.fn();
16
+ jest.mock('../../hooks/useDataBrowserNavigate', ()=>({
17
+ useDataBrowserNavigate: ()=>mockNavigate
18
+ }));
19
+ jest.mock('@scality/core-ui', ()=>({
20
+ ...jest.requireActual('@scality/core-ui'),
21
+ useToast: ()=>({
22
+ showToast: mockShowToast
23
+ })
24
+ }));
25
+ const renderBucketAccessor = ()=>{
26
+ const Wrapper = createTestWrapper();
27
+ return render(/*#__PURE__*/ jsx(Wrapper, {
28
+ children: /*#__PURE__*/ jsx(MemoryRouter, {
29
+ children: /*#__PURE__*/ jsx(BucketAccessor, {})
30
+ })
31
+ }));
32
+ };
33
+ const mockRefetch = jest.fn();
34
+ const mockAddAccessibleBucket = jest.fn();
35
+ const setupMocks = (overrides = {})=>{
36
+ mockUseValidateBucketAccess.mockReturnValue({
37
+ refetch: mockRefetch,
38
+ isFetching: false,
39
+ error: null,
40
+ ...overrides
41
+ });
42
+ mockUseAccessibleBuckets.mockReturnValue({
43
+ hasLimitedAccess: false,
44
+ setLimitedAccess: jest.fn(),
45
+ accessibleBuckets: [],
46
+ addAccessibleBucket: mockAddAccessibleBucket,
47
+ clearAccessibleBuckets: jest.fn()
48
+ });
49
+ };
50
+ const fillBucketName = async (name)=>{
51
+ const nameInput = screen.getByLabelText(/bucket name/i);
52
+ await user_event.type(nameInput, name);
53
+ };
54
+ const fillPrefix = async (prefix)=>{
55
+ const prefixInput = screen.getByLabelText(/prefix/i);
56
+ await user_event.type(prefixInput, prefix);
57
+ };
58
+ const submitForm = async ()=>{
59
+ await waitFor(()=>{
60
+ const accessButton = screen.getByRole('button', {
61
+ name: /^access$/i
62
+ });
63
+ expect(accessButton).not.toBeDisabled();
64
+ }, {
65
+ timeout: 3000
66
+ });
67
+ const accessButton = screen.getByRole('button', {
68
+ name: /^access$/i
69
+ });
70
+ await user_event.click(accessButton);
71
+ };
72
+ describe('BucketAccessor', ()=>{
73
+ beforeEach(()=>{
74
+ jest.clearAllMocks();
75
+ setupMocks();
76
+ });
77
+ it('renders form with required fields', ()=>{
78
+ renderBucketAccessor();
79
+ expect(screen.getByText('Access a specific S3 Bucket')).toBeInTheDocument();
80
+ expect(screen.getByLabelText(/bucket name/i)).toBeInTheDocument();
81
+ expect(screen.getByLabelText(/prefix/i)).toBeInTheDocument();
82
+ });
83
+ it('disables access button when bucket name is empty', ()=>{
84
+ renderBucketAccessor();
85
+ expect(screen.getByRole('button', {
86
+ name: /^access$/i
87
+ })).toBeDisabled();
88
+ });
89
+ it('enables access button when bucket name is valid', async ()=>{
90
+ renderBucketAccessor();
91
+ await fillBucketName('test-bucket');
92
+ await waitFor(()=>{
93
+ expect(screen.getByRole('button', {
94
+ name: /^access$/i
95
+ })).not.toBeDisabled();
96
+ });
97
+ });
98
+ it('shows validation error when bucket name is empty', async ()=>{
99
+ renderBucketAccessor();
100
+ const nameInput = screen.getByLabelText(/bucket name/i);
101
+ await user_event.type(nameInput, 'test');
102
+ await user_event.clear(nameInput);
103
+ await user_event.tab();
104
+ await waitFor(()=>{
105
+ expect(screen.getByText(/bucket name is required/i)).toBeInTheDocument();
106
+ });
107
+ });
108
+ it('validates bucket access and navigates on success', async ()=>{
109
+ mockRefetch.mockResolvedValue({
110
+ isSuccess: true,
111
+ error: null
112
+ });
113
+ renderBucketAccessor();
114
+ await fillBucketName('my-bucket');
115
+ await submitForm();
116
+ await waitFor(()=>{
117
+ expect(mockRefetch).toHaveBeenCalled();
118
+ expect(mockAddAccessibleBucket).toHaveBeenCalledWith('my-bucket');
119
+ expect(mockNavigate).toHaveBeenCalledWith('/buckets/my-bucket/objects');
120
+ });
121
+ });
122
+ it('validates bucket access with prefix and navigates correctly', async ()=>{
123
+ mockRefetch.mockResolvedValue({
124
+ isSuccess: true,
125
+ error: null
126
+ });
127
+ renderBucketAccessor();
128
+ await fillBucketName('my-bucket');
129
+ await fillPrefix('my-folder');
130
+ await submitForm();
131
+ await waitFor(()=>{
132
+ expect(mockRefetch).toHaveBeenCalled();
133
+ expect(mockAddAccessibleBucket).toHaveBeenCalledWith('my-bucket');
134
+ expect(mockNavigate).toHaveBeenCalledWith('/buckets/my-bucket/objects?prefix=my-folder%2F');
135
+ });
136
+ });
137
+ it('shows error toast when bucket does not exist', async ()=>{
138
+ const error = new Error('NoSuchBucket: The specified bucket does not exist');
139
+ error.name = 'NoSuchBucket';
140
+ mockRefetch.mockResolvedValue({
141
+ isSuccess: false,
142
+ error
143
+ });
144
+ renderBucketAccessor();
145
+ await fillBucketName('non-existent-bucket');
146
+ await submitForm();
147
+ await waitFor(()=>{
148
+ expect(mockShowToast).toHaveBeenCalledWith({
149
+ open: true,
150
+ message: 'The specified bucket does not exist',
151
+ status: 'error'
152
+ });
153
+ expect(mockNavigate).not.toHaveBeenCalled();
154
+ });
155
+ });
156
+ it('shows error toast when access is denied', async ()=>{
157
+ const error = new Error('AccessDenied: You do not have permission to access this resource');
158
+ error.name = 'AccessDenied';
159
+ mockRefetch.mockResolvedValue({
160
+ isSuccess: false,
161
+ error
162
+ });
163
+ renderBucketAccessor();
164
+ await fillBucketName('restricted-bucket');
165
+ await submitForm();
166
+ await waitFor(()=>{
167
+ expect(mockShowToast).toHaveBeenCalledWith({
168
+ open: true,
169
+ message: "You don't have permission to access this bucket",
170
+ status: 'error'
171
+ });
172
+ expect(mockNavigate).not.toHaveBeenCalled();
173
+ });
174
+ });
175
+ it('shows generic error message for other errors', async ()=>{
176
+ const error = new Error('Network error');
177
+ mockRefetch.mockResolvedValue({
178
+ isSuccess: false,
179
+ error
180
+ });
181
+ renderBucketAccessor();
182
+ await fillBucketName('test-bucket');
183
+ await submitForm();
184
+ await waitFor(()=>{
185
+ expect(mockShowToast).toHaveBeenCalledWith({
186
+ open: true,
187
+ message: 'Network error',
188
+ status: 'error'
189
+ });
190
+ expect(mockNavigate).not.toHaveBeenCalled();
191
+ });
192
+ });
193
+ it('navigates to buckets list when cancel is clicked', async ()=>{
194
+ renderBucketAccessor();
195
+ const cancelButton = screen.getByRole('button', {
196
+ name: /cancel/i
197
+ });
198
+ await user_event.click(cancelButton);
199
+ expect(mockNavigate).toHaveBeenCalledWith('/buckets');
200
+ });
201
+ it('disables form during bucket access validation', async ()=>{
202
+ setupMocks({
203
+ isFetching: true
204
+ });
205
+ renderBucketAccessor();
206
+ await fillBucketName('test-bucket');
207
+ await waitFor(()=>{
208
+ const accessButton = screen.getByRole('button', {
209
+ name: /^access$/i
210
+ });
211
+ expect(accessButton).toBeDisabled();
212
+ });
213
+ });
214
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,263 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { fireEvent, render, screen, waitFor } from "@testing-library/react";
3
+ import { MemoryRouter, Route, Routes } from "react-router";
4
+ import { useDeleteBucketCors, useGetBucketCors, useSetBucketCors } from "../../hooks/index.js";
5
+ import { createMockMutationResult, createMockQueryResult, createTestWrapper } from "../../test/testUtils.js";
6
+ import { BucketCorsPage } from "../buckets/BucketCorsPage.js";
7
+ jest.mock('../../hooks', ()=>({
8
+ useGetBucketCors: jest.fn(),
9
+ useSetBucketCors: jest.fn(),
10
+ useDeleteBucketCors: jest.fn(),
11
+ useBucketConfigEditor: jest.requireActual('../../hooks').useBucketConfigEditor
12
+ }));
13
+ jest.mock('../Editor', ()=>({
14
+ Editor: ({ value, onChange })=>/*#__PURE__*/ jsx("textarea", {
15
+ "data-testid": "cors-editor",
16
+ value: value,
17
+ onChange: (e)=>onChange(e.target.value)
18
+ })
19
+ }));
20
+ const mockUseGetBucketCors = jest.mocked(useGetBucketCors);
21
+ const mockUseSetBucketCors = jest.mocked(useSetBucketCors);
22
+ const mockUseDeleteBucketCors = jest.mocked(useDeleteBucketCors);
23
+ const mockNavigate = jest.fn();
24
+ jest.mock('react-router', ()=>({
25
+ ...jest.requireActual('react-router'),
26
+ useNavigate: ()=>mockNavigate
27
+ }));
28
+ const existingCorsRules = [
29
+ {
30
+ AllowedHeaders: [
31
+ 'Authorization'
32
+ ],
33
+ AllowedMethods: [
34
+ 'GET',
35
+ 'PUT'
36
+ ],
37
+ AllowedOrigins: [
38
+ 'https://example.com'
39
+ ],
40
+ ExposeHeaders: [
41
+ 'ETag'
42
+ ],
43
+ MaxAgeSeconds: 3600
44
+ }
45
+ ];
46
+ const createNoSuchCorsError = ()=>{
47
+ const error = new Error('CORS configuration does not exist');
48
+ error.name = 'NoSuchCORSConfiguration';
49
+ return error;
50
+ };
51
+ const mockNoCorsExists = ()=>{
52
+ mockUseGetBucketCors.mockReturnValue(createMockQueryResult({
53
+ status: 'error',
54
+ error: createNoSuchCorsError()
55
+ }));
56
+ };
57
+ const mockCorsExists = (corsRules = existingCorsRules)=>{
58
+ mockUseGetBucketCors.mockReturnValue(createMockQueryResult({
59
+ data: {
60
+ CORSRules: corsRules,
61
+ $metadata: {}
62
+ },
63
+ status: 'success'
64
+ }));
65
+ };
66
+ const renderBucketCorsPage = (bucketName = 'test-bucket')=>{
67
+ const Wrapper = createTestWrapper();
68
+ return render(/*#__PURE__*/ jsx(MemoryRouter, {
69
+ initialEntries: [
70
+ `/buckets/${bucketName}/cors`
71
+ ],
72
+ children: /*#__PURE__*/ jsx(Wrapper, {
73
+ children: /*#__PURE__*/ jsx(Routes, {
74
+ children: /*#__PURE__*/ jsx(Route, {
75
+ path: "/buckets/:bucketName/cors",
76
+ element: /*#__PURE__*/ jsx(BucketCorsPage, {})
77
+ })
78
+ })
79
+ })
80
+ }));
81
+ };
82
+ describe('BucketCorsPage', ()=>{
83
+ const mockSaveMutate = jest.fn();
84
+ const mockDeleteMutate = jest.fn();
85
+ beforeEach(()=>{
86
+ jest.clearAllMocks();
87
+ mockUseSetBucketCors.mockReturnValue(createMockMutationResult(mockSaveMutate));
88
+ mockUseDeleteBucketCors.mockReturnValue(createMockMutationResult(mockDeleteMutate));
89
+ });
90
+ it('shows loading state while fetching CORS configuration', ()=>{
91
+ mockUseGetBucketCors.mockReturnValue(createMockQueryResult({
92
+ status: 'pending'
93
+ }));
94
+ renderBucketCorsPage();
95
+ expect(screen.getByText('Loading CORS configuration...')).toBeInTheDocument();
96
+ });
97
+ it('shows create mode with default template when no CORS exists', async ()=>{
98
+ mockNoCorsExists();
99
+ renderBucketCorsPage();
100
+ await waitFor(()=>{
101
+ expect(screen.getByText('Create Bucket CORS')).toBeInTheDocument();
102
+ });
103
+ const editor = screen.getByTestId('cors-editor');
104
+ expect(editor.value).toContain('AllowedHeaders');
105
+ });
106
+ it('shows edit mode with existing CORS rules', async ()=>{
107
+ mockCorsExists();
108
+ renderBucketCorsPage();
109
+ await waitFor(()=>{
110
+ expect(screen.getByText('Edit Bucket CORS')).toBeInTheDocument();
111
+ });
112
+ const editor = screen.getByTestId('cors-editor');
113
+ expect(JSON.parse(editor.value)).toEqual(existingCorsRules);
114
+ });
115
+ it('disables save button for invalid JSON format', async ()=>{
116
+ mockNoCorsExists();
117
+ renderBucketCorsPage();
118
+ await waitFor(()=>{
119
+ expect(screen.getByTestId('cors-editor')).toBeInTheDocument();
120
+ });
121
+ fireEvent.change(screen.getByTestId('cors-editor'), {
122
+ target: {
123
+ value: '{ invalid json'
124
+ }
125
+ });
126
+ await waitFor(()=>{
127
+ expect(screen.getByRole('button', {
128
+ name: /save/i
129
+ })).toBeDisabled();
130
+ });
131
+ });
132
+ it('disables save button when form has no changes', async ()=>{
133
+ mockCorsExists();
134
+ renderBucketCorsPage();
135
+ await waitFor(()=>{
136
+ expect(screen.getByTestId('cors-editor')).toBeInTheDocument();
137
+ });
138
+ expect(screen.getByRole('button', {
139
+ name: /save/i
140
+ })).toBeDisabled();
141
+ });
142
+ it('saves CORS configuration and navigates back', async ()=>{
143
+ mockNoCorsExists();
144
+ renderBucketCorsPage();
145
+ await waitFor(()=>{
146
+ expect(screen.getByTestId('cors-editor')).toBeInTheDocument();
147
+ });
148
+ fireEvent.change(screen.getByTestId('cors-editor'), {
149
+ target: {
150
+ value: JSON.stringify(existingCorsRules, null, 2)
151
+ }
152
+ });
153
+ mockSaveMutate.mockImplementation((_, options)=>{
154
+ options?.onSuccess?.();
155
+ });
156
+ await waitFor(()=>{
157
+ expect(screen.getByRole('button', {
158
+ name: /save/i
159
+ })).not.toBeDisabled();
160
+ });
161
+ fireEvent.click(screen.getByRole('button', {
162
+ name: /save/i
163
+ }));
164
+ await waitFor(()=>{
165
+ expect(mockSaveMutate).toHaveBeenCalledWith({
166
+ Bucket: 'test-bucket',
167
+ CORSConfiguration: {
168
+ CORSRules: existingCorsRules
169
+ }
170
+ }, expect.any(Object));
171
+ expect(mockNavigate).toHaveBeenCalledWith('/buckets/test-bucket');
172
+ });
173
+ });
174
+ it('stays on page and displays error message when save fails', async ()=>{
175
+ mockNoCorsExists();
176
+ renderBucketCorsPage();
177
+ await waitFor(()=>{
178
+ expect(screen.getByTestId('cors-editor')).toBeInTheDocument();
179
+ });
180
+ fireEvent.change(screen.getByTestId('cors-editor'), {
181
+ target: {
182
+ value: JSON.stringify(existingCorsRules, null, 2)
183
+ }
184
+ });
185
+ mockSaveMutate.mockImplementation((_, options)=>{
186
+ options?.onError?.(new Error('Access Denied'));
187
+ });
188
+ await waitFor(()=>{
189
+ expect(screen.getByRole('button', {
190
+ name: /save/i
191
+ })).not.toBeDisabled();
192
+ });
193
+ fireEvent.click(screen.getByRole('button', {
194
+ name: /save/i
195
+ }));
196
+ await waitFor(()=>{
197
+ expect(mockNavigate).not.toHaveBeenCalled();
198
+ expect(screen.getByText('Access Denied')).toBeInTheDocument();
199
+ });
200
+ });
201
+ it('navigates back when clicking cancel', async ()=>{
202
+ mockNoCorsExists();
203
+ renderBucketCorsPage();
204
+ await waitFor(()=>{
205
+ expect(screen.getByRole('button', {
206
+ name: /cancel/i
207
+ })).toBeInTheDocument();
208
+ });
209
+ fireEvent.click(screen.getByRole('button', {
210
+ name: /cancel/i
211
+ }));
212
+ expect(mockNavigate).toHaveBeenCalledWith('/buckets/test-bucket');
213
+ });
214
+ it('displays the bucket name', async ()=>{
215
+ mockNoCorsExists();
216
+ renderBucketCorsPage('my-custom-bucket');
217
+ await waitFor(()=>{
218
+ expect(screen.getByText('my-custom-bucket')).toBeInTheDocument();
219
+ });
220
+ });
221
+ it('deletes CORS configuration when saving empty content', async ()=>{
222
+ mockCorsExists();
223
+ renderBucketCorsPage();
224
+ const editor = await screen.findByTestId('cors-editor');
225
+ await waitFor(()=>{
226
+ expect(editor.value).toContain('AllowedHeaders');
227
+ });
228
+ fireEvent.change(editor, {
229
+ target: {
230
+ value: ''
231
+ }
232
+ });
233
+ mockDeleteMutate.mockImplementation((_, options)=>{
234
+ options?.onSuccess?.();
235
+ });
236
+ await waitFor(()=>{
237
+ expect(screen.getByRole('button', {
238
+ name: /save/i
239
+ })).not.toBeDisabled();
240
+ });
241
+ fireEvent.click(screen.getByRole('button', {
242
+ name: /save/i
243
+ }));
244
+ await waitFor(()=>{
245
+ expect(mockDeleteMutate).toHaveBeenCalledWith({
246
+ Bucket: 'test-bucket'
247
+ }, expect.any(Object));
248
+ expect(mockNavigate).toHaveBeenCalledWith('/buckets/test-bucket');
249
+ });
250
+ });
251
+ it('shows error message when fetching CORS fails with unexpected error', ()=>{
252
+ const accessDeniedError = new Error('Access Denied');
253
+ accessDeniedError.name = 'AccessDenied';
254
+ mockUseGetBucketCors.mockReturnValue(createMockQueryResult({
255
+ status: 'error',
256
+ error: accessDeniedError
257
+ }));
258
+ renderBucketCorsPage();
259
+ expect(screen.getByText(/Failed to load CORS configuration/i)).toBeInTheDocument();
260
+ expect(screen.getByText(/Access Denied/i)).toBeInTheDocument();
261
+ expect(screen.queryByTestId('cors-editor')).not.toBeInTheDocument();
262
+ });
263
+ });