@scality/data-browser-library 1.0.0-preview.8 → 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 (303) 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.d.ts +1 -0
  9. package/dist/components/__tests__/BucketCreate.test.js +574 -0
  10. package/dist/components/__tests__/BucketDetails.test.d.ts +1 -0
  11. package/dist/components/__tests__/BucketDetails.test.js +421 -0
  12. package/dist/components/__tests__/BucketLifecycleFormPage.test.d.ts +14 -0
  13. package/dist/components/__tests__/BucketLifecycleFormPage.test.js +618 -0
  14. package/dist/components/__tests__/BucketLifecycleList.test.d.ts +1 -0
  15. package/dist/components/__tests__/BucketLifecycleList.test.js +325 -0
  16. package/dist/components/__tests__/BucketList.test.js +495 -81
  17. package/dist/components/__tests__/BucketNotificationFormPage.test.d.ts +1 -0
  18. package/dist/components/__tests__/BucketNotificationFormPage.test.js +348 -0
  19. package/dist/components/__tests__/BucketNotificationList.test.d.ts +1 -0
  20. package/dist/components/__tests__/BucketNotificationList.test.js +379 -0
  21. package/dist/components/__tests__/BucketOverview.test.js +484 -179
  22. package/dist/components/__tests__/BucketPolicyPage.test.js +151 -99
  23. package/dist/components/__tests__/BucketReplicationFormPage.test.d.ts +16 -0
  24. package/dist/components/__tests__/BucketReplicationFormPage.test.js +1757 -0
  25. package/dist/components/__tests__/BucketReplicationList.test.d.ts +1 -0
  26. package/dist/components/__tests__/BucketReplicationList.test.js +344 -0
  27. package/dist/components/__tests__/CreateFolderButton.test.js +56 -56
  28. package/dist/components/__tests__/DeleteBucketButton.test.js +64 -64
  29. package/dist/components/__tests__/DeleteBucketConfigRuleButton.test.d.ts +1 -0
  30. package/dist/components/__tests__/DeleteBucketConfigRuleButton.test.js +196 -0
  31. package/dist/components/__tests__/DeleteObjectButton.test.js +64 -64
  32. package/dist/components/__tests__/EmptyBucketButton.test.d.ts +1 -0
  33. package/dist/components/__tests__/EmptyBucketButton.test.js +302 -0
  34. package/dist/components/__tests__/MetadataSearch.test.js +65 -65
  35. package/dist/components/__tests__/ObjectList.test.js +741 -240
  36. package/dist/components/__tests__/UploadButton.test.js +45 -45
  37. package/dist/components/breadcrumb/Breadcrumb.d.ts +6 -0
  38. package/dist/components/breadcrumb/Breadcrumb.js +37 -0
  39. package/dist/components/breadcrumb/DataBrowserBreadcrumb.d.ts +1 -0
  40. package/dist/components/breadcrumb/DataBrowserBreadcrumb.js +10 -0
  41. package/dist/components/breadcrumb/__tests__/Breadcrumb.test.d.ts +1 -0
  42. package/dist/components/breadcrumb/__tests__/Breadcrumb.test.js +196 -0
  43. package/dist/components/breadcrumb/__tests__/DataBrowserBreadcrumb.test.d.ts +1 -0
  44. package/dist/components/breadcrumb/__tests__/DataBrowserBreadcrumb.test.js +153 -0
  45. package/dist/components/breadcrumb/__tests__/useBreadcrumbPaths.test.d.ts +1 -0
  46. package/dist/components/breadcrumb/__tests__/useBreadcrumbPaths.test.js +134 -0
  47. package/dist/components/breadcrumb/index.d.ts +8 -0
  48. package/dist/components/breadcrumb/index.js +4 -0
  49. package/dist/components/breadcrumb/useBreadcrumbPaths.d.ts +2 -0
  50. package/dist/components/breadcrumb/useBreadcrumbPaths.js +82 -0
  51. package/dist/components/buckets/BucketAccessor.d.ts +2 -0
  52. package/dist/components/buckets/BucketAccessor.js +125 -0
  53. package/dist/components/buckets/BucketConfigEditButton.d.ts +8 -0
  54. package/dist/components/buckets/{BucketPolicyButton.js → BucketConfigEditButton.js} +9 -5
  55. package/dist/components/buckets/BucketCorsPage.d.ts +1 -0
  56. package/dist/components/buckets/BucketCorsPage.js +234 -0
  57. package/dist/components/buckets/BucketCreate.d.ts +50 -0
  58. package/dist/components/buckets/BucketCreate.js +279 -0
  59. package/dist/components/buckets/BucketDetails.d.ts +42 -0
  60. package/dist/components/buckets/BucketDetails.js +256 -40
  61. package/dist/components/buckets/BucketLifecycleFormPage.d.ts +15 -0
  62. package/dist/components/buckets/BucketLifecycleFormPage.js +1086 -0
  63. package/dist/components/buckets/BucketLifecycleList.d.ts +10 -0
  64. package/dist/components/buckets/BucketLifecycleList.js +270 -0
  65. package/dist/components/buckets/BucketList.d.ts +6 -4
  66. package/dist/components/buckets/BucketList.js +161 -94
  67. package/dist/components/buckets/BucketLocation.js +4 -4
  68. package/dist/components/buckets/BucketOverview.d.ts +86 -5
  69. package/dist/components/buckets/BucketOverview.js +481 -192
  70. package/dist/components/buckets/BucketPage.js +44 -22
  71. package/dist/components/buckets/BucketPolicyPage.js +155 -127
  72. package/dist/components/buckets/BucketReplicationFormPage.d.ts +1 -0
  73. package/dist/components/buckets/BucketReplicationFormPage.js +835 -0
  74. package/dist/components/buckets/BucketReplicationList.d.ts +11 -0
  75. package/dist/components/buckets/BucketReplicationList.js +189 -0
  76. package/dist/components/buckets/BucketVersioning.d.ts +4 -0
  77. package/dist/components/buckets/BucketVersioning.js +76 -0
  78. package/dist/components/buckets/DeleteBucketButton.js +8 -8
  79. package/dist/components/buckets/DeleteBucketConfigRuleButton.d.ts +18 -0
  80. package/dist/components/buckets/DeleteBucketConfigRuleButton.js +53 -0
  81. package/dist/components/buckets/EmptyBucketButton.d.ts +5 -0
  82. package/dist/components/buckets/EmptyBucketButton.js +232 -0
  83. package/dist/components/buckets/EmptyBucketSummary.d.ts +9 -0
  84. package/dist/components/buckets/EmptyBucketSummary.js +60 -0
  85. package/dist/components/buckets/EmptyBucketSummaryList.d.ts +13 -0
  86. package/dist/components/buckets/EmptyBucketSummaryList.js +140 -0
  87. package/dist/components/buckets/__tests__/BucketVersioning.test.d.ts +1 -0
  88. package/dist/components/buckets/__tests__/BucketVersioning.test.js +163 -0
  89. package/dist/components/buckets/notifications/BucketNotificationFormPage.d.ts +1 -0
  90. package/dist/components/buckets/notifications/BucketNotificationFormPage.js +316 -0
  91. package/dist/components/buckets/notifications/BucketNotificationList.d.ts +10 -0
  92. package/dist/components/buckets/notifications/BucketNotificationList.js +267 -0
  93. package/dist/components/buckets/notifications/EventsSection.js +145 -29
  94. package/dist/components/buckets/notifications/__tests__/events.test.d.ts +1 -0
  95. package/dist/components/buckets/notifications/__tests__/events.test.js +56 -0
  96. package/dist/components/buckets/notifications/events.d.ts +71 -7
  97. package/dist/components/buckets/notifications/events.js +98 -16
  98. package/dist/components/index.d.ts +27 -13
  99. package/dist/components/index.js +20 -6
  100. package/dist/components/layouts/ArrowNavigation.d.ts +3 -0
  101. package/dist/components/layouts/ArrowNavigation.js +28 -0
  102. package/dist/components/layouts/BrowserPageLayout.d.ts +5 -1
  103. package/dist/components/layouts/BrowserPageLayout.js +10 -5
  104. package/dist/components/objects/CreateFolderButton.d.ts +2 -2
  105. package/dist/components/objects/CreateFolderButton.js +12 -12
  106. package/dist/components/objects/DeleteObjectButton.d.ts +1 -1
  107. package/dist/components/objects/DeleteObjectButton.js +19 -21
  108. package/dist/components/objects/GetPresignedUrlButton.d.ts +7 -0
  109. package/dist/components/objects/GetPresignedUrlButton.js +255 -0
  110. package/dist/components/objects/ObjectDetails/ObjectMetadata.d.ts +2 -2
  111. package/dist/components/objects/ObjectDetails/ObjectMetadata.js +263 -230
  112. package/dist/components/objects/ObjectDetails/ObjectSummary.d.ts +2 -2
  113. package/dist/components/objects/ObjectDetails/ObjectSummary.js +540 -138
  114. package/dist/components/objects/ObjectDetails/ObjectTags.d.ts +2 -2
  115. package/dist/components/objects/ObjectDetails/ObjectTags.js +95 -123
  116. package/dist/components/objects/ObjectDetails/__tests__/ObjectDetails.test.d.ts +1 -0
  117. package/dist/components/objects/ObjectDetails/__tests__/ObjectDetails.test.js +516 -0
  118. package/dist/components/objects/ObjectDetails/__tests__/ObjectSummary.test.d.ts +1 -0
  119. package/dist/components/objects/ObjectDetails/__tests__/ObjectSummary.test.js +1064 -0
  120. package/dist/components/objects/ObjectDetails/index.d.ts +18 -2
  121. package/dist/components/objects/ObjectDetails/index.js +152 -40
  122. package/dist/components/objects/ObjectList.d.ts +12 -10
  123. package/dist/components/objects/ObjectList.js +590 -263
  124. package/dist/components/objects/ObjectLock/EditRetentionButton.d.ts +4 -0
  125. package/dist/components/objects/ObjectLock/EditRetentionButton.js +32 -0
  126. package/dist/components/objects/ObjectLock/ObjectLockRetentionSettings.d.ts +3 -0
  127. package/dist/components/objects/ObjectLock/ObjectLockRetentionSettings.js +211 -0
  128. package/dist/components/objects/ObjectLock/ObjectLockSettings.d.ts +9 -0
  129. package/dist/components/objects/ObjectLock/ObjectLockSettings.js +159 -0
  130. package/dist/components/objects/ObjectLock/ObjectLockSettingsUtils.d.ts +8 -0
  131. package/dist/components/objects/ObjectLock/ObjectLockSettingsUtils.js +39 -0
  132. package/dist/components/objects/ObjectLock/__tests__/EditRetentionButton.test.d.ts +1 -0
  133. package/dist/components/objects/ObjectLock/__tests__/EditRetentionButton.test.js +204 -0
  134. package/dist/components/objects/ObjectLock/__tests__/ObjectLockSettings.test.d.ts +1 -0
  135. package/dist/components/objects/ObjectLock/__tests__/ObjectLockSettings.test.js +374 -0
  136. package/dist/components/objects/ObjectPage.js +12 -8
  137. package/dist/components/objects/UploadButton.d.ts +3 -3
  138. package/dist/components/objects/UploadButton.js +10 -10
  139. package/dist/components/objects/__tests__/GetPresignedUrlButton.test.d.ts +1 -0
  140. package/dist/components/objects/__tests__/GetPresignedUrlButton.test.js +531 -0
  141. package/dist/components/providers/DataBrowserProvider.d.ts +23 -12
  142. package/dist/components/providers/DataBrowserProvider.js +60 -38
  143. package/dist/components/providers/QueryProvider.d.ts +9 -0
  144. package/dist/components/providers/QueryProvider.js +21 -0
  145. package/dist/components/search/MetadataSearch.js +29 -28
  146. package/dist/components/search/SearchHints.js +1 -1
  147. package/dist/components/ui/ArrayFieldActions.d.ts +36 -0
  148. package/dist/components/ui/ArrayFieldActions.js +43 -0
  149. package/dist/components/ui/ConfirmDeleteRuleModal.d.ts +16 -0
  150. package/dist/components/ui/ConfirmDeleteRuleModal.js +48 -0
  151. package/dist/components/ui/DeleteObjectModalContent.d.ts +1 -1
  152. package/dist/components/ui/DeleteObjectModalContent.js +12 -12
  153. package/dist/components/ui/FilterFormSection.d.ts +44 -0
  154. package/dist/components/ui/FilterFormSection.js +159 -0
  155. package/dist/components/ui/Search.elements.d.ts +2 -2
  156. package/dist/components/ui/Search.elements.js +7 -7
  157. package/dist/components/ui/Table.elements.d.ts +2 -1
  158. package/dist/components/ui/Table.elements.js +18 -12
  159. package/dist/config/__tests__/factory.test.d.ts +1 -0
  160. package/dist/config/__tests__/factory.test.js +311 -0
  161. package/dist/config/factory.d.ts +14 -49
  162. package/dist/config/factory.js +23 -68
  163. package/dist/config/types.d.ts +212 -34
  164. package/dist/contexts/DataBrowserUICustomizationContext.d.ts +27 -0
  165. package/dist/contexts/DataBrowserUICustomizationContext.js +13 -0
  166. package/dist/hooks/__tests__/useAccessibleBuckets.test.d.ts +1 -0
  167. package/dist/hooks/__tests__/useAccessibleBuckets.test.js +145 -0
  168. package/dist/hooks/__tests__/useISVBucketDetection.test.d.ts +1 -0
  169. package/dist/hooks/__tests__/useISVBucketDetection.test.js +188 -0
  170. package/dist/hooks/__tests__/useIsBucketEmpty.test.js +27 -27
  171. package/dist/hooks/__tests__/useLoginMutation.test.d.ts +1 -0
  172. package/dist/hooks/__tests__/useLoginMutation.test.js +194 -0
  173. package/dist/hooks/bucketConfiguration.d.ts +8 -1
  174. package/dist/hooks/bucketConfiguration.js +52 -51
  175. package/dist/hooks/bucketOperations.d.ts +10 -1
  176. package/dist/hooks/bucketOperations.js +10 -9
  177. package/dist/hooks/factories/__tests__/useCreateS3FunctionMutationHook.test.js +80 -80
  178. package/dist/hooks/factories/__tests__/useCreateS3InfiniteQueryHook.test.js +80 -80
  179. package/dist/hooks/factories/__tests__/useCreateS3LoginHook.test.js +44 -44
  180. package/dist/hooks/factories/__tests__/useCreateS3MutationHook.test.js +63 -63
  181. package/dist/hooks/factories/__tests__/useCreateS3QueryHook.test.js +95 -52
  182. package/dist/hooks/factories/index.d.ts +4 -4
  183. package/dist/hooks/factories/index.js +2 -2
  184. package/dist/hooks/factories/useCreateS3InfiniteQueryHook.d.ts +2 -2
  185. package/dist/hooks/factories/useCreateS3InfiniteQueryHook.js +16 -13
  186. package/dist/hooks/factories/useCreateS3LoginHook.d.ts +2 -2
  187. package/dist/hooks/factories/useCreateS3LoginHook.js +1 -1
  188. package/dist/hooks/factories/useCreateS3MutationHook.d.ts +3 -3
  189. package/dist/hooks/factories/useCreateS3MutationHook.js +7 -2
  190. package/dist/hooks/factories/useCreateS3QueryHook.d.ts +2 -2
  191. package/dist/hooks/factories/useCreateS3QueryHook.js +29 -3
  192. package/dist/hooks/index.d.ts +19 -8
  193. package/dist/hooks/index.js +16 -5
  194. package/dist/hooks/loginOperations.d.ts +1 -1
  195. package/dist/hooks/loginOperations.js +1 -1
  196. package/dist/hooks/objectOperations.d.ts +2 -2
  197. package/dist/hooks/objectOperations.js +50 -49
  198. package/dist/hooks/presignedOperations.d.ts +4 -4
  199. package/dist/hooks/presignedOperations.js +5 -5
  200. package/dist/hooks/useAccessibleBuckets.d.ts +11 -0
  201. package/dist/hooks/useAccessibleBuckets.js +115 -0
  202. package/dist/hooks/useBatchObjectLegalHold.d.ts +11 -0
  203. package/dist/hooks/useBatchObjectLegalHold.js +48 -0
  204. package/dist/hooks/useBucketConfigEditor.d.ts +31 -0
  205. package/dist/hooks/useBucketConfigEditor.js +82 -0
  206. package/dist/hooks/useDataBrowserNavigate.d.ts +28 -0
  207. package/dist/hooks/useDataBrowserNavigate.js +24 -0
  208. package/dist/hooks/useDeleteBucketConfigRule.d.ts +26 -0
  209. package/dist/hooks/useDeleteBucketConfigRule.js +46 -0
  210. package/dist/hooks/useEmptyBucket.d.ts +27 -0
  211. package/dist/hooks/useEmptyBucket.js +116 -0
  212. package/dist/hooks/useFeatures.d.ts +7 -0
  213. package/dist/hooks/useFeatures.js +8 -0
  214. package/dist/hooks/useISVBucketDetection.d.ts +15 -0
  215. package/dist/hooks/useISVBucketDetection.js +27 -0
  216. package/dist/hooks/useIsBucketEmpty.js +4 -4
  217. package/dist/hooks/useLimitedAccessFlow.d.ts +48 -0
  218. package/dist/hooks/useLimitedAccessFlow.js +23 -0
  219. package/dist/hooks/useS3Client.d.ts +6 -0
  220. package/dist/hooks/useS3Client.js +3 -2
  221. package/dist/hooks/useS3ConfigSwitch.d.ts +11 -0
  222. package/dist/hooks/useS3ConfigSwitch.js +37 -0
  223. package/dist/hooks/useSupportedNotificationEvents.d.ts +6 -0
  224. package/dist/hooks/useSupportedNotificationEvents.js +8 -0
  225. package/dist/hooks/useTableRowSelection.d.ts +9 -0
  226. package/dist/hooks/useTableRowSelection.js +45 -0
  227. package/dist/index.d.ts +6 -6
  228. package/dist/index.js +2 -2
  229. package/dist/schemas/bucketPolicySchema.json +3 -13
  230. package/dist/test/msw/handlers/deleteBucket.d.ts +1 -1
  231. package/dist/test/msw/handlers/deleteBucket.js +20 -10
  232. package/dist/test/msw/handlers/getBucketAcl.d.ts +1 -1
  233. package/dist/test/msw/handlers/getBucketAcl.js +29 -17
  234. package/dist/test/msw/handlers/getBucketLocation.d.ts +1 -1
  235. package/dist/test/msw/handlers/getBucketLocation.js +29 -15
  236. package/dist/test/msw/handlers/getBucketPolicy.d.ts +1 -1
  237. package/dist/test/msw/handlers/getBucketPolicy.js +52 -32
  238. package/dist/test/msw/handlers/headObject.d.ts +1 -1
  239. package/dist/test/msw/handlers/headObject.js +31 -13
  240. package/dist/test/msw/handlers/listBuckets.d.ts +1 -1
  241. package/dist/test/msw/handlers/listBuckets.js +5 -3
  242. package/dist/test/msw/handlers/listObjectVersions.d.ts +1 -1
  243. package/dist/test/msw/handlers/listObjectVersions.js +38 -26
  244. package/dist/test/msw/handlers/listObjects.d.ts +1 -1
  245. package/dist/test/msw/handlers/listObjects.js +35 -23
  246. package/dist/test/msw/handlers/objectLegalHold.d.ts +1 -1
  247. package/dist/test/msw/handlers/objectLegalHold.js +32 -17
  248. package/dist/test/msw/handlers/objectRetention.d.ts +1 -1
  249. package/dist/test/msw/handlers/objectRetention.js +31 -17
  250. package/dist/test/msw/handlers/putBucketAcl.d.ts +1 -1
  251. package/dist/test/msw/handlers/putBucketAcl.js +29 -14
  252. package/dist/test/msw/handlers/putObject.d.ts +1 -1
  253. package/dist/test/msw/handlers/putObject.js +27 -12
  254. package/dist/test/msw/handlers.d.ts +3 -3
  255. package/dist/test/msw/handlers.js +77 -54
  256. package/dist/test/msw/index.d.ts +2 -2
  257. package/dist/test/msw/index.js +1 -1
  258. package/dist/test/msw/server.d.ts +1 -1
  259. package/dist/test/msw/server.js +1 -1
  260. package/dist/test/msw/utils.js +2 -2
  261. package/dist/test/setup.d.ts +1 -1
  262. package/dist/test/setup.js +13 -30
  263. package/dist/test/testUtils.d.ts +170 -36
  264. package/dist/test/testUtils.js +229 -116
  265. package/dist/test/utils/errorHandling.test.js +146 -108
  266. package/dist/types/index.d.ts +49 -36
  267. package/dist/types/monaco.d.ts +13 -0
  268. package/dist/types/monaco.js +0 -0
  269. package/dist/utils/__tests__/proxyMiddleware.test.d.ts +1 -0
  270. package/dist/utils/__tests__/proxyMiddleware.test.js +579 -0
  271. package/dist/utils/__tests__/s3Client.test.d.ts +1 -0
  272. package/dist/utils/__tests__/s3Client.test.js +340 -0
  273. package/dist/utils/__tests__/s3ConfigIdentifier.test.d.ts +1 -0
  274. package/dist/utils/__tests__/s3ConfigIdentifier.test.js +437 -0
  275. package/dist/utils/constants.d.ts +22 -0
  276. package/dist/utils/constants.js +19 -0
  277. package/dist/utils/deletion/index.d.ts +2 -2
  278. package/dist/utils/deletion/index.js +1 -1
  279. package/dist/utils/deletion/messages.d.ts +1 -1
  280. package/dist/utils/deletion/messages.js +4 -4
  281. package/dist/utils/errorHandling.d.ts +12 -3
  282. package/dist/utils/errorHandling.js +12 -7
  283. package/dist/utils/hooks.js +8 -8
  284. package/dist/utils/index.d.ts +5 -2
  285. package/dist/utils/index.js +5 -1
  286. package/dist/utils/proxyMiddleware.d.ts +32 -13
  287. package/dist/utils/proxyMiddleware.js +90 -36
  288. package/dist/utils/s3Client.d.ts +14 -4
  289. package/dist/utils/s3Client.js +5 -26
  290. package/dist/utils/s3ConfigIdentifier.d.ts +79 -0
  291. package/dist/utils/s3ConfigIdentifier.js +57 -0
  292. package/dist/utils/s3RuleUtils.d.ts +53 -0
  293. package/dist/utils/s3RuleUtils.js +101 -0
  294. package/package.json +10 -8
  295. package/dist/components/__tests__/BucketNotificationCreatePage.test.js +0 -316
  296. package/dist/components/buckets/BucketPolicyButton.d.ts +0 -7
  297. package/dist/components/buckets/notifications/BucketNotificationCreatePage.d.ts +0 -1
  298. package/dist/components/buckets/notifications/BucketNotificationCreatePage.js +0 -234
  299. package/dist/hooks/useLoginMutation.d.ts +0 -21
  300. package/dist/hooks/useLoginMutation.js +0 -9
  301. package/dist/utils/useFeatures.d.ts +0 -1
  302. package/dist/utils/useFeatures.js +0 -7
  303. /package/dist/components/__tests__/{BucketNotificationCreatePage.test.d.ts → BucketAccessor.test.d.ts} +0 -0
@@ -1,283 +1,784 @@
1
- import { jsx } from "react/jsx-runtime";
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { fireEvent, render, renderHook, screen, waitFor } from "@testing-library/react";
3
3
  import { MemoryRouter } from "react-router";
4
- import { createTestWrapper, mockOffsetSize, setupMswServer } from "../../test/testUtils.js";
4
+ import { DataBrowserUICustomizationProvider } from "../../contexts/DataBrowserUICustomizationContext.js";
5
5
  import { useListObjectVersions, useListObjects } from "../../hooks/index.js";
6
+ import { createTestWrapper, mockOffsetSize, setupMswServer } from "../../test/testUtils.js";
6
7
  import { ObjectList } from "../objects/ObjectList.js";
7
- import * as __WEBPACK_EXTERNAL_MODULE__utils_useFeatures_js_1facdd0d__ from "../../utils/useFeatures.js";
8
+ import * as __rspack_external__hooks_useFeatures_js_a6a84786 from "../../hooks/useFeatures.js";
8
9
  setupMswServer();
9
- const renderObjectList = (props = {})=>{
10
+ const renderObjectList = (props = {}, customization)=>{
10
11
  const Wrapper = createTestWrapper();
12
+ const defaultCustomization = {
13
+ extraObjectListColumns: customization?.extraObjectListColumns || [],
14
+ extraObjectListActions: customization?.extraObjectListActions || []
15
+ };
11
16
  return render(/*#__PURE__*/ jsx(MemoryRouter, {
12
17
  children: /*#__PURE__*/ jsx(Wrapper, {
13
- children: /*#__PURE__*/ jsx(ObjectList, {
14
- bucketName: "test-bucket",
15
- prefix: "",
16
- onObjectSelect: jest.fn(),
17
- onPrefixChange: jest.fn(),
18
- ...props
18
+ children: /*#__PURE__*/ jsx(DataBrowserUICustomizationProvider, {
19
+ config: defaultCustomization,
20
+ children: /*#__PURE__*/ jsx(ObjectList, {
21
+ bucketName: "test-bucket",
22
+ prefix: "",
23
+ onObjectSelect: jest.fn(),
24
+ onPrefixChange: jest.fn(),
25
+ ...props
26
+ })
19
27
  })
20
28
  })
21
29
  }));
22
30
  };
23
- describe("ObjectList", ()=>{
31
+ describe('ObjectList', ()=>{
24
32
  beforeEach(()=>{
25
33
  jest.clearAllMocks();
26
34
  mockOffsetSize(800, 600);
27
- jest.spyOn(__WEBPACK_EXTERNAL_MODULE__utils_useFeatures_js_1facdd0d__, "useFeatures").mockReturnValue(false);
35
+ jest.spyOn(__rspack_external__hooks_useFeatures_js_a6a84786, 'useFeatures').mockReturnValue(false);
28
36
  });
29
37
  afterEach(()=>{
30
38
  jest.restoreAllMocks();
31
39
  });
32
- it("shows a table with proper headers", async ()=>{
33
- renderObjectList();
34
- await waitFor(()=>{
35
- expect(screen.getByRole("grid")).toBeInTheDocument();
36
- });
37
- expect(screen.getByText("Name")).toBeInTheDocument();
38
- expect(screen.getByText("Modified on")).toBeInTheDocument();
39
- expect(screen.getByText("Size")).toBeInTheDocument();
40
- expect(screen.getByText("Storage Location")).toBeInTheDocument();
41
- });
42
- it("renders content and handles interactions", async ()=>{
43
- const onObjectSelect = jest.fn();
44
- const onPrefixChange = jest.fn();
45
- renderObjectList({
46
- onObjectSelect,
47
- onPrefixChange
48
- });
49
- await waitFor(()=>{
50
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
51
- });
52
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
53
- expect(screen.getByText("file2.txt")).toBeInTheDocument();
54
- expect(screen.getByText("folder1/")).toBeInTheDocument();
55
- fireEvent.click(screen.getByText("file1.txt"));
56
- expect(onObjectSelect).toHaveBeenCalledWith(expect.objectContaining({
57
- Key: "file1.txt",
58
- type: "object"
59
- }));
60
- fireEvent.click(screen.getByText("folder1/"));
61
- expect(onPrefixChange).toHaveBeenCalledWith("folder1/");
62
- const rows = screen.getAllByRole("row");
63
- expect(rows.length).toBe(4);
64
- });
65
- it("displays data formatting correctly", async ()=>{
66
- renderObjectList();
67
- await waitFor(()=>{
68
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
69
- });
70
- const gridElement = screen.getByRole("grid");
71
- expect(gridElement).toHaveTextContent("2023");
72
- const dateElements = screen.getAllByText(/2023/);
73
- expect(dateElements.length).toBeGreaterThanOrEqual(2);
74
- expect(screen.getByText("1 KB")).toBeInTheDocument();
75
- expect(screen.getByText("512 B")).toBeInTheDocument();
76
- const defaultElements = screen.getAllByText("default");
77
- expect(defaultElements.length).toBeGreaterThan(0);
78
- const dashes = screen.getAllByText("-");
79
- expect(dashes.length).toBeGreaterThanOrEqual(2);
40
+ describe('Basic Rendering', ()=>{
41
+ it('shows a table with proper headers', async ()=>{
42
+ renderObjectList();
43
+ await waitFor(()=>{
44
+ expect(screen.getByRole('grid')).toBeInTheDocument();
45
+ });
46
+ expect(screen.getByText('Name')).toBeInTheDocument();
47
+ expect(screen.getByText('Modified on')).toBeInTheDocument();
48
+ expect(screen.getByText('Size')).toBeInTheDocument();
49
+ expect(screen.getByText('Storage Location')).toBeInTheDocument();
50
+ });
51
+ it('renders empty state for empty bucket', async ()=>{
52
+ renderObjectList({
53
+ bucketName: 'empty-bucket'
54
+ });
55
+ await waitFor(()=>{
56
+ expect(screen.getByRole('grid')).toBeInTheDocument();
57
+ });
58
+ expect(screen.getByText('Name')).toBeInTheDocument();
59
+ const rows = screen.getAllByRole('row');
60
+ expect(rows.length).toBe(1);
61
+ expect(screen.queryByText('file1.txt')).not.toBeInTheDocument();
62
+ expect(screen.queryByText('folder1/')).not.toBeInTheDocument();
63
+ });
64
+ it('handles loading states correctly', async ()=>{
65
+ renderObjectList();
66
+ expect(screen.getByRole('grid')).toBeInTheDocument();
67
+ await waitFor(()=>{
68
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
69
+ });
70
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
71
+ expect(screen.getByText('file2.txt')).toBeInTheDocument();
72
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
73
+ });
80
74
  });
81
- it("handles edge cases gracefully", async ()=>{
82
- renderObjectList({
83
- bucketName: "empty-bucket"
84
- });
85
- await waitFor(()=>{
86
- expect(screen.getByRole("grid")).toBeInTheDocument();
87
- });
88
- expect(screen.getByText("Name")).toBeInTheDocument();
89
- const mockOnObjectSelect = jest.fn();
90
- const mockOnPrefixChange = jest.fn();
91
- renderObjectList({
92
- onObjectSelect: mockOnObjectSelect,
93
- onPrefixChange: mockOnPrefixChange
94
- });
95
- await waitFor(()=>{
96
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
97
- });
98
- expect(()=>{
99
- fireEvent.click(screen.getByText("file1.txt"));
100
- fireEvent.click(screen.getByText("folder1/"));
101
- }).not.toThrow();
102
- expect(mockOnObjectSelect).toHaveBeenCalled();
103
- expect(mockOnPrefixChange).toHaveBeenCalled();
75
+ describe('Content Display', ()=>{
76
+ it('renders content and handles interactions', async ()=>{
77
+ const onObjectSelect = jest.fn();
78
+ const onPrefixChange = jest.fn();
79
+ renderObjectList({
80
+ onObjectSelect,
81
+ onPrefixChange
82
+ });
83
+ await waitFor(()=>{
84
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
85
+ });
86
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
87
+ expect(screen.getByText('file2.txt')).toBeInTheDocument();
88
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
89
+ fireEvent.click(screen.getByText('folder1/'));
90
+ expect(onPrefixChange).toHaveBeenCalledWith('folder1/');
91
+ const rows = screen.getAllByRole('row');
92
+ expect(rows.length).toBe(4);
93
+ });
94
+ it('displays data formatting correctly', async ()=>{
95
+ renderObjectList();
96
+ await waitFor(()=>{
97
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
98
+ });
99
+ const gridElement = screen.getByRole('grid');
100
+ expect(gridElement).toHaveTextContent('2023');
101
+ const dateElements = screen.getAllByText(/2023/);
102
+ expect(dateElements.length).toBeGreaterThanOrEqual(2);
103
+ expect(screen.getByText('1 KB')).toBeInTheDocument();
104
+ expect(screen.getByText('512 B')).toBeInTheDocument();
105
+ const defaultElements = screen.getAllByText('default');
106
+ expect(defaultElements.length).toBeGreaterThan(0);
107
+ const dashes = screen.getAllByText('-');
108
+ expect(dashes.length).toBeGreaterThanOrEqual(2);
109
+ });
110
+ it('displays correct icons for folders and files', async ()=>{
111
+ renderObjectList();
112
+ await waitFor(()=>{
113
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
114
+ });
115
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
116
+ expect(screen.getByText('file2.txt')).toBeInTheDocument();
117
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
118
+ const nameCells = screen.getAllByRole('gridcell').filter((cell)=>cell.textContent?.includes('folder1/') || cell.textContent?.includes('file1.txt') || cell.textContent?.includes('file2.txt'));
119
+ expect(nameCells.length).toBe(3);
120
+ nameCells.forEach((cell)=>{
121
+ const iconElement = cell.querySelector('svg, img, i');
122
+ const linkElement = cell.querySelector('a');
123
+ expect(iconElement).toBeInTheDocument();
124
+ expect(linkElement).toBeInTheDocument();
125
+ });
126
+ });
127
+ it('removes prefix from displayed names correctly', async ()=>{
128
+ renderObjectList({
129
+ prefix: 'my-prefix/subfolder/',
130
+ bucketName: 'test-bucket'
131
+ });
132
+ await waitFor(()=>{
133
+ expect(screen.getByRole('grid')).toBeInTheDocument();
134
+ });
135
+ expect(screen.getByText('Name')).toBeInTheDocument();
136
+ });
104
137
  });
105
- it("handles loading states", async ()=>{
106
- renderObjectList();
107
- expect(screen.getByRole("grid")).toBeInTheDocument();
108
- await waitFor(()=>{
109
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
110
- });
111
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
112
- expect(screen.getByText("file2.txt")).toBeInTheDocument();
113
- expect(screen.getByText("folder1/")).toBeInTheDocument();
138
+ describe('Interaction Behaviors', ()=>{
139
+ it('prevents event propagation when clicking links', async ()=>{
140
+ const onPrefixChange = jest.fn();
141
+ renderObjectList({
142
+ onPrefixChange
143
+ });
144
+ await waitFor(()=>{
145
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
146
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
147
+ });
148
+ fireEvent.click(screen.getByText('folder1/'));
149
+ expect(onPrefixChange).toHaveBeenCalledWith('folder1/');
150
+ expect(onPrefixChange).toHaveBeenCalledTimes(1);
151
+ });
152
+ it('supports prefix-based navigation', async ()=>{
153
+ const onPrefixChange = jest.fn();
154
+ renderObjectList({
155
+ onPrefixChange
156
+ });
157
+ await waitFor(()=>{
158
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
159
+ });
160
+ fireEvent.click(screen.getByText('folder1/'));
161
+ expect(onPrefixChange).toHaveBeenCalledWith('folder1/');
162
+ expect(onPrefixChange).toHaveBeenCalledTimes(1);
163
+ });
164
+ it('handles folder navigation correctly', async ()=>{
165
+ const onPrefixChange = jest.fn();
166
+ renderObjectList({
167
+ onPrefixChange
168
+ });
169
+ await waitFor(()=>{
170
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
171
+ });
172
+ fireEvent.click(screen.getByText('folder1/'));
173
+ expect(onPrefixChange).toHaveBeenCalledWith('folder1/');
174
+ });
114
175
  });
115
- it("prevents event propagation when clicking links", async ()=>{
116
- const onObjectSelect = jest.fn();
117
- const onPrefixChange = jest.fn();
118
- renderObjectList({
119
- onObjectSelect,
120
- onPrefixChange
121
- });
122
- await waitFor(()=>{
123
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
124
- });
125
- fireEvent.click(screen.getByText("file1.txt"));
126
- expect(onObjectSelect).toHaveBeenCalledWith(expect.objectContaining({
127
- Key: "file1.txt",
128
- type: "object"
129
- }));
130
- expect(onPrefixChange).not.toHaveBeenCalled();
176
+ describe('Pagination and Infinite Scroll', ()=>{
177
+ it('handles infinite scroll pagination correctly', async ()=>{
178
+ renderObjectList({
179
+ bucketName: 'paginated-bucket'
180
+ });
181
+ await waitFor(()=>{
182
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
183
+ expect(screen.getByText('file2.txt')).toBeInTheDocument();
184
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
185
+ });
186
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
187
+ expect(screen.getByText('file2.txt')).toBeInTheDocument();
188
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
189
+ const table = screen.getByRole('grid');
190
+ expect(table).toBeInTheDocument();
191
+ const rows = screen.getAllByRole('row');
192
+ expect(rows.length).toBeGreaterThanOrEqual(4);
193
+ expect(screen.getByText('1 KB')).toBeInTheDocument();
194
+ expect(screen.getByText('512 B')).toBeInTheDocument();
195
+ });
196
+ it('integrates with infinite query hook for data loading', async ()=>{
197
+ const { result } = renderHook(()=>useListObjects({
198
+ Bucket: 'paginated-bucket',
199
+ MaxKeys: 20,
200
+ Delimiter: '/'
201
+ }), {
202
+ wrapper: createTestWrapper()
203
+ });
204
+ await waitFor(()=>{
205
+ expect(result.current.isSuccess).toBe(true);
206
+ });
207
+ expect(result.current.data).toBeDefined();
208
+ expect(result.current.hasNextPage).toBe(true);
209
+ expect(typeof result.current.fetchNextPage).toBe('function');
210
+ expect(result.current.isFetchingNextPage).toBe(false);
211
+ const firstPage = result.current.data?.pages[0];
212
+ expect(firstPage).toBeDefined();
213
+ expect(firstPage?.Contents).toHaveLength(2);
214
+ expect(firstPage?.CommonPrefixes).toHaveLength(1);
215
+ result.current.fetchNextPage();
216
+ await waitFor(()=>{
217
+ const updatedData = result.current.data;
218
+ expect(updatedData?.pages).toHaveLength(2);
219
+ });
220
+ const secondPage = result.current.data?.pages[1];
221
+ expect(secondPage).toBeDefined();
222
+ expect(secondPage?.Contents).toHaveLength(1);
223
+ expect(result.current.hasNextPage).toBe(false);
224
+ });
131
225
  });
132
- it("supports prefix-based navigation", async ()=>{
133
- renderObjectList({
134
- prefix: "folder1/"
226
+ describe('Version Management', ()=>{
227
+ it('renders List Versions toggle', async ()=>{
228
+ renderObjectList();
229
+ await waitFor(()=>{
230
+ expect(screen.getByText('List Versions')).toBeInTheDocument();
231
+ });
232
+ const toggleLabel = screen.getByText(/list versions/i);
233
+ const toggle = toggleLabel.closest('label')?.querySelector('input[type="checkbox"]');
234
+ expect(toggle).toBeInTheDocument();
235
+ expect(toggle).not.toBeChecked();
236
+ });
237
+ it('shows Version ID column when toggle is enabled', async ()=>{
238
+ renderObjectList();
239
+ await waitFor(()=>{
240
+ expect(screen.getByText('List Versions')).toBeInTheDocument();
241
+ });
242
+ const toggleLabel = screen.getByText(/list versions/i);
243
+ const toggle = toggleLabel.closest('label')?.querySelector('input[type="checkbox"]');
244
+ fireEvent.click(toggle);
245
+ await waitFor(()=>{
246
+ expect(screen.getByText('Version ID')).toBeInTheDocument();
247
+ });
248
+ });
249
+ it('does not show Version ID column by default', async ()=>{
250
+ renderObjectList();
251
+ await waitFor(()=>{
252
+ expect(screen.getByText('Name')).toBeInTheDocument();
253
+ });
254
+ expect(screen.queryByText('Version ID')).not.toBeInTheDocument();
135
255
  });
136
- await waitFor(()=>{
137
- expect(screen.getByRole("grid")).toBeInTheDocument();
256
+ it('integrates with version listing hook', async ()=>{
257
+ const { result } = renderHook(()=>useListObjectVersions({
258
+ Bucket: 'test-bucket',
259
+ MaxKeys: 20,
260
+ Delimiter: '/'
261
+ }), {
262
+ wrapper: createTestWrapper()
263
+ });
264
+ await waitFor(()=>{
265
+ expect(result.current.isSuccess).toBe(true);
266
+ });
267
+ expect(result.current.data).toBeDefined();
268
+ expect(typeof result.current.fetchNextPage).toBe('function');
269
+ const firstPage = result.current.data?.pages[0];
270
+ expect(firstPage).toBeDefined();
271
+ });
272
+ it('clears selections when toggling versions', async ()=>{
273
+ renderObjectList();
274
+ await waitFor(()=>{
275
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
276
+ });
277
+ const toggleLabel = screen.getByText(/list versions/i);
278
+ const toggle = toggleLabel.closest('label')?.querySelector('input[type="checkbox"]');
279
+ fireEvent.click(toggle);
280
+ await waitFor(()=>{
281
+ expect(screen.getByText('Version ID')).toBeInTheDocument();
282
+ });
138
283
  });
139
- expect(screen.getByText("Name")).toBeInTheDocument();
140
284
  });
141
- it("displays correct icons for folders and files", async ()=>{
142
- renderObjectList();
143
- await waitFor(()=>{
144
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
145
- });
146
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
147
- expect(screen.getByText("file2.txt")).toBeInTheDocument();
148
- expect(screen.getByText("folder1/")).toBeInTheDocument();
149
- const nameCells = screen.getAllByRole("gridcell").filter((cell)=>cell.textContent?.includes("folder1/") || cell.textContent?.includes("file1.txt") || cell.textContent?.includes("file2.txt"));
150
- expect(nameCells.length).toBe(3);
151
- nameCells.forEach((cell)=>{
152
- const iconElement = cell.querySelector("svg, img, i");
153
- const linkElement = cell.querySelector("a");
154
- expect(iconElement).toBeInTheDocument();
155
- expect(linkElement).toBeInTheDocument();
285
+ describe('Search Features', ()=>{
286
+ it('renders table search when metadata-search feature is disabled', async ()=>{
287
+ jest.spyOn(__rspack_external__hooks_useFeatures_js_a6a84786, 'useFeatures').mockReturnValue(false);
288
+ renderObjectList();
289
+ await waitFor(()=>{
290
+ expect(screen.getByRole('grid')).toBeInTheDocument();
291
+ });
292
+ expect(screen.queryByPlaceholderText(/Metadata Search/i)).not.toBeInTheDocument();
293
+ });
294
+ it('renders MetadataSearch component when metadata-search feature is enabled', async ()=>{
295
+ jest.spyOn(__rspack_external__hooks_useFeatures_js_a6a84786, 'useFeatures').mockReturnValue(true);
296
+ renderObjectList();
297
+ await waitFor(()=>{
298
+ expect(screen.getByRole('grid')).toBeInTheDocument();
299
+ });
300
+ expect(screen.getByPlaceholderText(/Metadata Search/i)).toBeInTheDocument();
156
301
  });
157
302
  });
158
- it("integrates with MultiSelectableContent", async ()=>{
159
- renderObjectList();
160
- await waitFor(()=>{
161
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
162
- });
163
- expect(screen.getByRole("grid")).toBeInTheDocument();
164
- const rows = screen.getAllByRole("row");
165
- expect(rows.length).toBe(4);
303
+ describe('Multi-Selection', ()=>{
304
+ it('integrates with MultiSelectableContent', async ()=>{
305
+ renderObjectList();
306
+ await waitFor(()=>{
307
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
308
+ });
309
+ expect(screen.getByRole('grid')).toBeInTheDocument();
310
+ const rows = screen.getAllByRole('row');
311
+ expect(rows.length).toBe(4);
312
+ const checkboxes = screen.getAllByRole('checkbox');
313
+ expect(checkboxes.length).toBeGreaterThan(0);
314
+ });
315
+ it('handles multi-selection state changes', async ()=>{
316
+ renderObjectList();
317
+ await waitFor(()=>{
318
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
319
+ });
320
+ const checkboxes = screen.getAllByRole('checkbox');
321
+ expect(checkboxes.length).toBeGreaterThan(0);
322
+ const firstCheckbox = checkboxes[0];
323
+ expect(firstCheckbox).not.toBeChecked();
324
+ fireEvent.click(firstCheckbox);
325
+ expect(firstCheckbox).toBeChecked();
326
+ });
327
+ it('clears selections when prefix changes', async ()=>{
328
+ const { rerender } = render(/*#__PURE__*/ jsx(MemoryRouter, {
329
+ children: (()=>{
330
+ const Wrapper = createTestWrapper();
331
+ const customization = {
332
+ extraObjectListColumns: [],
333
+ extraObjectListActions: []
334
+ };
335
+ return /*#__PURE__*/ jsx(Wrapper, {
336
+ children: /*#__PURE__*/ jsx(DataBrowserUICustomizationProvider, {
337
+ config: customization,
338
+ children: /*#__PURE__*/ jsx(ObjectList, {
339
+ bucketName: "test-bucket",
340
+ prefix: "",
341
+ onObjectSelect: jest.fn(),
342
+ onPrefixChange: jest.fn()
343
+ })
344
+ })
345
+ });
346
+ })()
347
+ }));
348
+ await waitFor(()=>{
349
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
350
+ });
351
+ const checkboxesBefore = screen.getAllByRole('checkbox');
352
+ expect(checkboxesBefore.length).toBeGreaterThan(0);
353
+ const firstCheckbox = checkboxesBefore[1];
354
+ fireEvent.click(firstCheckbox);
355
+ expect(firstCheckbox).toBeChecked();
356
+ rerender(/*#__PURE__*/ jsx(MemoryRouter, {
357
+ children: (()=>{
358
+ const Wrapper = createTestWrapper();
359
+ const customization = {
360
+ extraObjectListColumns: [],
361
+ extraObjectListActions: []
362
+ };
363
+ return /*#__PURE__*/ jsx(Wrapper, {
364
+ children: /*#__PURE__*/ jsx(DataBrowserUICustomizationProvider, {
365
+ config: customization,
366
+ children: /*#__PURE__*/ jsx(ObjectList, {
367
+ bucketName: "test-bucket",
368
+ prefix: "folder1/",
369
+ onObjectSelect: jest.fn(),
370
+ onPrefixChange: jest.fn()
371
+ })
372
+ })
373
+ });
374
+ })()
375
+ }));
376
+ await waitFor(()=>{
377
+ expect(screen.getByRole('grid')).toBeInTheDocument();
378
+ });
379
+ const checkboxesAfter = screen.getAllByRole('checkbox');
380
+ checkboxesAfter.forEach((checkbox)=>{
381
+ expect(checkbox).not.toBeChecked();
382
+ });
383
+ });
166
384
  });
167
- it("handles infinite scroll pagination correctly", async ()=>{
168
- renderObjectList({
169
- bucketName: "paginated-bucket"
170
- });
171
- await waitFor(()=>{
172
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
173
- });
174
- expect(screen.getByText("file1.txt")).toBeInTheDocument();
175
- expect(screen.getByText("file2.txt")).toBeInTheDocument();
176
- expect(screen.getByText("folder1/")).toBeInTheDocument();
177
- expect(screen.queryByText("file3.txt")).not.toBeInTheDocument();
178
- const table = screen.getByRole("grid");
179
- expect(table).toBeInTheDocument();
180
- const tableContent = table.querySelector('[role="rowgroup"]') || table.querySelector('[data-testid*="multi-selectable"]');
181
- expect(tableContent).toBeInTheDocument();
182
- const rows = screen.getAllByRole("row");
183
- expect(rows.length).toBe(4);
184
- expect(()=>{
185
- screen.getByText("Name");
186
- screen.getByText("Modified on");
187
- screen.getByText("Size");
188
- screen.getByText("Storage Location");
189
- }).not.toThrow();
190
- expect(screen.getByText("1 KB")).toBeInTheDocument();
191
- expect(screen.getByText("512 B")).toBeInTheDocument();
385
+ describe('Action Buttons', ()=>{
386
+ it('renders upload and create folder buttons', async ()=>{
387
+ renderObjectList();
388
+ await waitFor(()=>{
389
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
390
+ });
391
+ expect(screen.getByText('Upload')).toBeInTheDocument();
392
+ expect(screen.getByRole('button', {
393
+ name: /folder/i
394
+ })).toBeInTheDocument();
395
+ });
396
+ it('renders delete button', async ()=>{
397
+ renderObjectList();
398
+ await waitFor(()=>{
399
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
400
+ });
401
+ expect(screen.getByText('Delete')).toBeInTheDocument();
402
+ });
192
403
  });
193
- it("integrates with infinite query hook for data loading", async ()=>{
194
- const { result } = renderHook(()=>useListObjects({
195
- Bucket: "paginated-bucket",
196
- MaxKeys: 20,
197
- Delimiter: "/"
198
- }), {
199
- wrapper: createTestWrapper()
200
- });
201
- await waitFor(()=>{
202
- expect(result.current.isSuccess).toBe(true);
203
- });
204
- expect(result.current.data).toBeDefined();
205
- expect(result.current.hasNextPage).toBe(true);
206
- expect(typeof result.current.fetchNextPage).toBe("function");
207
- expect(result.current.isFetchingNextPage).toBe(false);
208
- const firstPage = result.current.data?.pages[0];
209
- expect(firstPage).toBeDefined();
210
- expect(firstPage?.Contents).toHaveLength(2);
211
- expect(firstPage?.CommonPrefixes).toHaveLength(1);
212
- result.current.fetchNextPage();
213
- await waitFor(()=>{
214
- const updatedData = result.current.data;
215
- expect(updatedData?.pages).toHaveLength(2);
216
- });
217
- const secondPage = result.current.data?.pages[1];
218
- expect(secondPage).toBeDefined();
219
- expect(secondPage?.Contents).toHaveLength(1);
220
- expect(result.current.hasNextPage).toBe(false);
404
+ describe('Error Handling', ()=>{
405
+ it('handles errors gracefully', async ()=>{
406
+ const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
407
+ expect(()=>{
408
+ renderObjectList();
409
+ }).not.toThrow();
410
+ await waitFor(()=>{
411
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
412
+ });
413
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
414
+ consoleErrorSpy.mockRestore();
415
+ });
221
416
  });
222
- it("renders List Versions toggle", async ()=>{
223
- renderObjectList();
224
- await waitFor(()=>{
225
- expect(screen.getByText("List Versions")).toBeInTheDocument();
226
- });
227
- const toggleLabel = screen.getByText(/list versions/i);
228
- const toggle = toggleLabel.closest("label")?.querySelector('input[type="checkbox"]');
229
- expect(toggle).toBeInTheDocument();
230
- expect(toggle).not.toBeChecked();
417
+ describe('Column Sorting', ()=>{
418
+ it('sorts folders before files', async ()=>{
419
+ renderObjectList();
420
+ await waitFor(()=>{
421
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
422
+ });
423
+ const rows = screen.getAllByRole('row');
424
+ const dataRows = rows.slice(1);
425
+ const firstRowText = dataRows[0]?.textContent || '';
426
+ expect(firstRowText).toContain('folder1/');
427
+ });
428
+ it('sorts items alphabetically within their type', async ()=>{
429
+ renderObjectList();
430
+ await waitFor(()=>{
431
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
432
+ });
433
+ const rows = screen.getAllByRole('row');
434
+ const dataRows = rows.slice(1);
435
+ const fileRows = dataRows.filter((row)=>row.textContent?.includes('file') && !row.textContent?.includes('folder'));
436
+ expect(fileRows.length).toBeGreaterThanOrEqual(2);
437
+ const firstFileName = fileRows[0]?.textContent || '';
438
+ const secondFileName = fileRows[1]?.textContent || '';
439
+ expect(firstFileName.includes('file1')).toBe(true);
440
+ expect(secondFileName.includes('file2')).toBe(true);
441
+ });
231
442
  });
232
- it("shows Version ID column when toggle is enabled", async ()=>{
233
- renderObjectList();
234
- await waitFor(()=>{
235
- expect(screen.getByText("List Versions")).toBeInTheDocument();
443
+ describe('Customization', ()=>{
444
+ it('supports custom columns', async ()=>{
445
+ const CustomCell = ({ data })=>/*#__PURE__*/ jsxs("div", {
446
+ children: [
447
+ "Custom: ",
448
+ data.Key
449
+ ]
450
+ });
451
+ const customization = {
452
+ extraObjectListColumns: [
453
+ {
454
+ id: 'custom',
455
+ header: 'Custom Column',
456
+ render: CustomCell,
457
+ width: '200px'
458
+ }
459
+ ],
460
+ extraObjectListActions: []
461
+ };
462
+ renderObjectList({}, customization);
463
+ await waitFor(()=>{
464
+ expect(screen.getByText('Custom Column')).toBeInTheDocument();
465
+ });
466
+ });
467
+ it('supports custom actions', async ()=>{
468
+ const CustomAction = ()=>/*#__PURE__*/ jsx("button", {
469
+ children: "Custom Action"
470
+ });
471
+ const customization = {
472
+ extraObjectListColumns: [],
473
+ extraObjectListActions: [
474
+ {
475
+ id: 'customAction',
476
+ render: CustomAction
477
+ }
478
+ ]
479
+ };
480
+ renderObjectList({}, customization);
481
+ await waitFor(()=>{
482
+ expect(screen.getByText('Custom Action')).toBeInTheDocument();
483
+ });
236
484
  });
237
- const toggleLabel = screen.getByText(/list versions/i);
238
- const toggle = toggleLabel.closest("label")?.querySelector('input[type="checkbox"]');
239
- fireEvent.click(toggle);
240
- await waitFor(()=>{
241
- expect(screen.getByText("Version ID")).toBeInTheDocument();
485
+ it('allows overriding default columns', async ()=>{
486
+ const CustomNameCell = ({ data })=>/*#__PURE__*/ jsxs("div", {
487
+ children: [
488
+ "Override: ",
489
+ data.displayName
490
+ ]
491
+ });
492
+ const customization = {
493
+ extraObjectListColumns: [
494
+ {
495
+ id: 'name',
496
+ header: 'Custom Name',
497
+ render: CustomNameCell
498
+ }
499
+ ],
500
+ extraObjectListActions: []
501
+ };
502
+ renderObjectList({}, customization);
503
+ await waitFor(()=>{
504
+ expect(screen.getByText('Custom Name')).toBeInTheDocument();
505
+ });
242
506
  });
243
507
  });
244
- it("does not show Version ID column by default", async ()=>{
245
- renderObjectList();
246
- await waitFor(()=>{
247
- expect(screen.getByText("Name")).toBeInTheDocument();
508
+ describe('Edge Cases', ()=>{
509
+ it('handles edge cases gracefully', async ()=>{
510
+ const mockOnPrefixChange = jest.fn();
511
+ renderObjectList({
512
+ onPrefixChange: mockOnPrefixChange
513
+ });
514
+ await waitFor(()=>{
515
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
516
+ });
517
+ expect(()=>{
518
+ fireEvent.click(screen.getByText('folder1/'));
519
+ }).not.toThrow();
520
+ expect(mockOnPrefixChange).toHaveBeenCalled();
248
521
  });
249
- expect(screen.queryByText("Version ID")).not.toBeInTheDocument();
250
522
  });
251
- it("integrates with version listing hook", async ()=>{
252
- const { result } = renderHook(()=>useListObjectVersions({
253
- Bucket: "test-bucket",
254
- MaxKeys: 20,
255
- Delimiter: "/"
256
- }), {
257
- wrapper: createTestWrapper()
258
- });
259
- await waitFor(()=>{
260
- expect(result.current.isSuccess).toBe(true);
261
- });
262
- expect(result.current.data).toBeDefined();
263
- expect(typeof result.current.fetchNextPage).toBe("function");
264
- const firstPage = result.current.data?.pages[0];
265
- expect(firstPage).toBeDefined();
523
+ describe('Callback Stability', ()=>{
524
+ it('maintains stable callback references', async ()=>{
525
+ const onPrefixChange = jest.fn();
526
+ const { rerender } = render(/*#__PURE__*/ jsx(MemoryRouter, {
527
+ children: (()=>{
528
+ const Wrapper = createTestWrapper();
529
+ const customization = {
530
+ extraObjectListColumns: [],
531
+ extraObjectListActions: []
532
+ };
533
+ return /*#__PURE__*/ jsx(Wrapper, {
534
+ children: /*#__PURE__*/ jsx(DataBrowserUICustomizationProvider, {
535
+ config: customization,
536
+ children: /*#__PURE__*/ jsx(ObjectList, {
537
+ bucketName: "test-bucket",
538
+ prefix: "",
539
+ onObjectSelect: jest.fn(),
540
+ onPrefixChange: onPrefixChange
541
+ })
542
+ })
543
+ });
544
+ })()
545
+ }));
546
+ await waitFor(()=>{
547
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
548
+ });
549
+ fireEvent.click(screen.getByText('folder1/'));
550
+ expect(onPrefixChange).toHaveBeenCalledTimes(1);
551
+ const firstCallArgs = onPrefixChange.mock.calls[0];
552
+ rerender(/*#__PURE__*/ jsx(MemoryRouter, {
553
+ children: (()=>{
554
+ const Wrapper = createTestWrapper();
555
+ const customization = {
556
+ extraObjectListColumns: [],
557
+ extraObjectListActions: []
558
+ };
559
+ return /*#__PURE__*/ jsx(Wrapper, {
560
+ children: /*#__PURE__*/ jsx(DataBrowserUICustomizationProvider, {
561
+ config: customization,
562
+ children: /*#__PURE__*/ jsx(ObjectList, {
563
+ bucketName: "test-bucket",
564
+ prefix: "",
565
+ onObjectSelect: jest.fn(),
566
+ onPrefixChange: onPrefixChange
567
+ })
568
+ })
569
+ });
570
+ })()
571
+ }));
572
+ await waitFor(()=>{
573
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
574
+ });
575
+ fireEvent.click(screen.getByText('folder1/'));
576
+ expect(onPrefixChange).toHaveBeenCalledTimes(2);
577
+ const secondCallArgs = onPrefixChange.mock.calls[1];
578
+ expect(secondCallArgs[0]).toEqual(firstCallArgs[0]);
579
+ });
266
580
  });
267
- it("renders table search when metadata-search feature is disabled", async ()=>{
268
- jest.spyOn(__WEBPACK_EXTERNAL_MODULE__utils_useFeatures_js_1facdd0d__, "useFeatures").mockReturnValue(false);
269
- renderObjectList();
270
- await waitFor(()=>{
271
- expect(screen.getByRole("grid")).toBeInTheDocument();
581
+ describe('File Download', ()=>{
582
+ beforeEach(()=>{
583
+ mockOffsetSize(800, 600);
584
+ });
585
+ it('triggers download when clicking on file name without errors', async ()=>{
586
+ renderObjectList();
587
+ await waitFor(()=>{
588
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
589
+ });
590
+ const fileLink = screen.getByText('file1.txt');
591
+ expect(()=>{
592
+ fireEvent.click(fileLink);
593
+ }).not.toThrow();
594
+ });
595
+ it('does not download folders - navigates to prefix instead', async ()=>{
596
+ const onPrefixChange = jest.fn();
597
+ renderObjectList({
598
+ onPrefixChange
599
+ });
600
+ await waitFor(()=>{
601
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
602
+ });
603
+ const folderLink = screen.getByText('folder1/');
604
+ fireEvent.click(folderLink);
605
+ expect(onPrefixChange).toHaveBeenCalledWith('folder1/');
606
+ });
607
+ it('supports clicking on different files independently', async ()=>{
608
+ renderObjectList();
609
+ await waitFor(()=>{
610
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
611
+ expect(screen.getByText('file2.txt')).toBeInTheDocument();
612
+ });
613
+ const file1Link = screen.getByText('file1.txt');
614
+ const file2Link = screen.getByText('file2.txt');
615
+ expect(()=>{
616
+ fireEvent.click(file1Link);
617
+ fireEvent.click(file2Link);
618
+ }).not.toThrow();
619
+ });
620
+ it('renders file and folder names as clickable links', async ()=>{
621
+ renderObjectList();
622
+ await waitFor(()=>{
623
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
624
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
625
+ });
626
+ const fileLink = screen.getByText('file1.txt');
627
+ const folderLink = screen.getByText('folder1/');
628
+ expect(fileLink.closest('a')).toBeInTheDocument();
629
+ expect(folderLink.closest('a')).toBeInTheDocument();
630
+ });
631
+ it('handles download errors gracefully', async ()=>{
632
+ const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
633
+ renderObjectList();
634
+ await waitFor(()=>{
635
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
636
+ });
637
+ expect(()=>{
638
+ fireEvent.click(screen.getByText('file1.txt'));
639
+ }).not.toThrow();
640
+ consoleErrorSpy.mockRestore();
272
641
  });
273
- expect(screen.queryByPlaceholderText(/Metadata Search/i)).not.toBeInTheDocument();
274
642
  });
275
- it("renders MetadataSearch component when metadata-search feature is enabled", async ()=>{
276
- jest.spyOn(__WEBPACK_EXTERNAL_MODULE__utils_useFeatures_js_1facdd0d__, "useFeatures").mockReturnValue(true);
277
- renderObjectList();
278
- await waitFor(()=>{
279
- expect(screen.getByRole("grid")).toBeInTheDocument();
643
+ describe('Accessibility', ()=>{
644
+ it('renders file and folder names as clickable links', async ()=>{
645
+ renderObjectList();
646
+ await waitFor(()=>{
647
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
648
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
649
+ });
650
+ const fileLink = screen.getByText('file1.txt').closest('a');
651
+ const folderLink = screen.getByText('folder1/').closest('a');
652
+ expect(fileLink).toBeInTheDocument();
653
+ expect(folderLink).toBeInTheDocument();
654
+ });
655
+ it('provides focusable links for keyboard navigation', async ()=>{
656
+ renderObjectList();
657
+ await waitFor(()=>{
658
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
659
+ });
660
+ const fileLink = screen.getByText('file1.txt').closest('a');
661
+ expect(fileLink).toBeInTheDocument();
662
+ expect(fileLink?.tagName.toLowerCase()).toBe('a');
663
+ });
664
+ it('ensures interactive elements are keyboard accessible', async ()=>{
665
+ renderObjectList();
666
+ await waitFor(()=>{
667
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
668
+ });
669
+ const fileLink = screen.getByText('file1.txt').closest('a');
670
+ const folderLink = screen.getByText('folder1/').closest('a');
671
+ expect(fileLink).toBeInTheDocument();
672
+ expect(folderLink).toBeInTheDocument();
673
+ if (fileLink) {
674
+ const tabIndex = fileLink.getAttribute('tabindex');
675
+ if (null !== tabIndex) expect(parseInt(tabIndex, 10)).toBeGreaterThanOrEqual(-1);
676
+ }
677
+ if (folderLink) {
678
+ const tabIndex = folderLink.getAttribute('tabindex');
679
+ if (null !== tabIndex) expect(parseInt(tabIndex, 10)).toBeGreaterThanOrEqual(-1);
680
+ }
681
+ });
682
+ it('provides keyboard interaction for Enter key on file links', async ()=>{
683
+ renderObjectList();
684
+ await waitFor(()=>{
685
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
686
+ });
687
+ const fileLink = screen.getByText('file1.txt').closest('a');
688
+ if (!fileLink) throw new Error('File link not found');
689
+ expect(()=>{
690
+ fireEvent.keyDown(fileLink, {
691
+ key: 'Enter',
692
+ code: 'Enter'
693
+ });
694
+ }).not.toThrow();
695
+ });
696
+ it('provides keyboard interaction for Space key on folder links', async ()=>{
697
+ const onPrefixChange = jest.fn();
698
+ renderObjectList({
699
+ onPrefixChange
700
+ });
701
+ await waitFor(()=>{
702
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
703
+ });
704
+ const folderLink = screen.getByText('folder1/').closest('a');
705
+ if (!folderLink) throw new Error('Folder link not found');
706
+ fireEvent.keyDown(folderLink, {
707
+ key: ' ',
708
+ code: 'Space'
709
+ });
710
+ fireEvent.click(folderLink);
711
+ expect(onPrefixChange).toHaveBeenCalledWith('folder1/');
712
+ });
713
+ it('has proper ARIA roles for the table structure', async ()=>{
714
+ renderObjectList();
715
+ await waitFor(()=>{
716
+ expect(screen.getByRole('grid')).toBeInTheDocument();
717
+ });
718
+ const gridElement = screen.getByRole('grid');
719
+ expect(gridElement).toBeInTheDocument();
720
+ const rows = screen.getAllByRole('row');
721
+ expect(rows.length).toBeGreaterThan(0);
722
+ });
723
+ });
724
+ describe('Error Scenarios', ()=>{
725
+ let consoleErrorSpy;
726
+ beforeEach(()=>{
727
+ consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
728
+ });
729
+ afterEach(()=>{
730
+ consoleErrorSpy.mockRestore();
731
+ });
732
+ it('continues to function when download initiation fails', async ()=>{
733
+ renderObjectList();
734
+ await waitFor(()=>{
735
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
736
+ });
737
+ const fileLink = screen.getByText('file1.txt');
738
+ fireEvent.click(fileLink);
739
+ fireEvent.click(fileLink);
740
+ expect(()=>{
741
+ fireEvent.click(fileLink);
742
+ }).not.toThrow();
743
+ await waitFor(()=>{
744
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
745
+ });
746
+ });
747
+ it('handles rapid clicking without breaking the UI', async ()=>{
748
+ renderObjectList();
749
+ await waitFor(()=>{
750
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
751
+ });
752
+ const fileLink = screen.getByText('file1.txt');
753
+ for(let i = 0; i < 10; i++)fireEvent.click(fileLink);
754
+ await waitFor(()=>{
755
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
756
+ });
757
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
758
+ });
759
+ it('properly invokes navigation callbacks', async ()=>{
760
+ const onPrefixChange = jest.fn();
761
+ renderObjectList({
762
+ onPrefixChange
763
+ });
764
+ await waitFor(()=>{
765
+ expect(screen.getByText('folder1/')).toBeInTheDocument();
766
+ });
767
+ const folderLink = screen.getByText('folder1/');
768
+ fireEvent.click(folderLink);
769
+ expect(onPrefixChange).toHaveBeenCalledWith('folder1/');
770
+ expect(onPrefixChange).toHaveBeenCalledTimes(1);
771
+ });
772
+ it('recovers gracefully from failed async operations', async ()=>{
773
+ renderObjectList();
774
+ await waitFor(()=>{
775
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
776
+ });
777
+ fireEvent.click(screen.getByText('file1.txt'));
778
+ await waitFor(()=>{
779
+ expect(screen.getByText('file1.txt')).toBeInTheDocument();
780
+ });
781
+ expect(screen.getByText('file2.txt')).toBeInTheDocument();
280
782
  });
281
- expect(screen.getByPlaceholderText(/Metadata Search/i)).toBeInTheDocument();
282
783
  });
283
784
  });