@scality/data-browser-library 1.0.0-preview.11

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 (256) hide show
  1. package/dist/components/Editor.d.ts +12 -0
  2. package/dist/components/Editor.js +28 -0
  3. package/dist/components/__tests__/BucketCreate.test.d.ts +1 -0
  4. package/dist/components/__tests__/BucketCreate.test.js +408 -0
  5. package/dist/components/__tests__/BucketLifecycleFormPage.test.d.ts +1 -0
  6. package/dist/components/__tests__/BucketLifecycleFormPage.test.js +618 -0
  7. package/dist/components/__tests__/BucketLifecycleList.test.d.ts +1 -0
  8. package/dist/components/__tests__/BucketLifecycleList.test.js +325 -0
  9. package/dist/components/__tests__/BucketList.test.d.ts +1 -0
  10. package/dist/components/__tests__/BucketList.test.js +415 -0
  11. package/dist/components/__tests__/BucketNotificationCreatePage.test.d.ts +1 -0
  12. package/dist/components/__tests__/BucketNotificationCreatePage.test.js +316 -0
  13. package/dist/components/__tests__/BucketOverview.test.d.ts +1 -0
  14. package/dist/components/__tests__/BucketOverview.test.js +769 -0
  15. package/dist/components/__tests__/BucketPolicyPage.test.d.ts +1 -0
  16. package/dist/components/__tests__/BucketPolicyPage.test.js +268 -0
  17. package/dist/components/__tests__/BucketReplicationFormPage.test.d.ts +1 -0
  18. package/dist/components/__tests__/BucketReplicationFormPage.test.js +1757 -0
  19. package/dist/components/__tests__/BucketReplicationList.test.d.ts +1 -0
  20. package/dist/components/__tests__/BucketReplicationList.test.js +344 -0
  21. package/dist/components/__tests__/CreateFolderButton.test.d.ts +1 -0
  22. package/dist/components/__tests__/CreateFolderButton.test.js +147 -0
  23. package/dist/components/__tests__/DeleteBucketButton.test.d.ts +1 -0
  24. package/dist/components/__tests__/DeleteBucketButton.test.js +272 -0
  25. package/dist/components/__tests__/DeleteBucketConfigRuleButton.test.d.ts +1 -0
  26. package/dist/components/__tests__/DeleteBucketConfigRuleButton.test.js +196 -0
  27. package/dist/components/__tests__/DeleteObjectButton.test.d.ts +1 -0
  28. package/dist/components/__tests__/DeleteObjectButton.test.js +302 -0
  29. package/dist/components/__tests__/EmptyBucketButton.test.d.ts +1 -0
  30. package/dist/components/__tests__/EmptyBucketButton.test.js +302 -0
  31. package/dist/components/__tests__/MetadataSearch.test.d.ts +1 -0
  32. package/dist/components/__tests__/MetadataSearch.test.js +201 -0
  33. package/dist/components/__tests__/ObjectList.test.d.ts +1 -0
  34. package/dist/components/__tests__/ObjectList.test.js +283 -0
  35. package/dist/components/__tests__/UploadButton.test.d.ts +1 -0
  36. package/dist/components/__tests__/UploadButton.test.js +144 -0
  37. package/dist/components/buckets/BucketCreate.d.ts +49 -0
  38. package/dist/components/buckets/BucketCreate.js +237 -0
  39. package/dist/components/buckets/BucketDetails.d.ts +1 -0
  40. package/dist/components/buckets/BucketDetails.js +106 -0
  41. package/dist/components/buckets/BucketLifecycleFormPage.d.ts +15 -0
  42. package/dist/components/buckets/BucketLifecycleFormPage.js +1085 -0
  43. package/dist/components/buckets/BucketLifecycleList.d.ts +10 -0
  44. package/dist/components/buckets/BucketLifecycleList.js +270 -0
  45. package/dist/components/buckets/BucketList.d.ts +15 -0
  46. package/dist/components/buckets/BucketList.js +146 -0
  47. package/dist/components/buckets/BucketLocation.d.ts +3 -0
  48. package/dist/components/buckets/BucketLocation.js +16 -0
  49. package/dist/components/buckets/BucketOverview.d.ts +88 -0
  50. package/dist/components/buckets/BucketOverview.js +291 -0
  51. package/dist/components/buckets/BucketPage.d.ts +2 -0
  52. package/dist/components/buckets/BucketPage.js +47 -0
  53. package/dist/components/buckets/BucketPolicyButton.d.ts +7 -0
  54. package/dist/components/buckets/BucketPolicyButton.js +18 -0
  55. package/dist/components/buckets/BucketPolicyPage.d.ts +1 -0
  56. package/dist/components/buckets/BucketPolicyPage.js +236 -0
  57. package/dist/components/buckets/BucketReplicationFormPage.d.ts +1 -0
  58. package/dist/components/buckets/BucketReplicationFormPage.js +834 -0
  59. package/dist/components/buckets/BucketReplicationList.d.ts +11 -0
  60. package/dist/components/buckets/BucketReplicationList.js +189 -0
  61. package/dist/components/buckets/BucketVersioning.d.ts +4 -0
  62. package/dist/components/buckets/BucketVersioning.js +73 -0
  63. package/dist/components/buckets/DeleteBucketButton.d.ts +8 -0
  64. package/dist/components/buckets/DeleteBucketButton.js +78 -0
  65. package/dist/components/buckets/DeleteBucketConfigRuleButton.d.ts +18 -0
  66. package/dist/components/buckets/DeleteBucketConfigRuleButton.js +53 -0
  67. package/dist/components/buckets/EmptyBucketButton.d.ts +5 -0
  68. package/dist/components/buckets/EmptyBucketButton.js +232 -0
  69. package/dist/components/buckets/EmptyBucketSummary.d.ts +9 -0
  70. package/dist/components/buckets/EmptyBucketSummary.js +60 -0
  71. package/dist/components/buckets/EmptyBucketSummaryList.d.ts +13 -0
  72. package/dist/components/buckets/EmptyBucketSummaryList.js +140 -0
  73. package/dist/components/buckets/__tests__/BucketVersioning.test.d.ts +1 -0
  74. package/dist/components/buckets/__tests__/BucketVersioning.test.js +163 -0
  75. package/dist/components/buckets/notifications/BucketNotificationCreatePage.d.ts +1 -0
  76. package/dist/components/buckets/notifications/BucketNotificationCreatePage.js +234 -0
  77. package/dist/components/buckets/notifications/EventsSection.d.ts +1 -0
  78. package/dist/components/buckets/notifications/EventsSection.js +123 -0
  79. package/dist/components/buckets/notifications/events.d.ts +12 -0
  80. package/dist/components/buckets/notifications/events.js +27 -0
  81. package/dist/components/index.d.ts +21 -0
  82. package/dist/components/index.js +22 -0
  83. package/dist/components/layouts/ArrowNavigation.d.ts +4 -0
  84. package/dist/components/layouts/ArrowNavigation.js +16 -0
  85. package/dist/components/layouts/BrowserPageLayout.d.ts +12 -0
  86. package/dist/components/layouts/BrowserPageLayout.js +51 -0
  87. package/dist/components/objects/CreateFolderButton.d.ts +29 -0
  88. package/dist/components/objects/CreateFolderButton.js +118 -0
  89. package/dist/components/objects/DeleteObjectButton.d.ts +8 -0
  90. package/dist/components/objects/DeleteObjectButton.js +191 -0
  91. package/dist/components/objects/ObjectDetails/ObjectMetadata.d.ts +2 -0
  92. package/dist/components/objects/ObjectDetails/ObjectMetadata.js +356 -0
  93. package/dist/components/objects/ObjectDetails/ObjectSummary.d.ts +3 -0
  94. package/dist/components/objects/ObjectDetails/ObjectSummary.js +241 -0
  95. package/dist/components/objects/ObjectDetails/ObjectTags.d.ts +3 -0
  96. package/dist/components/objects/ObjectDetails/ObjectTags.js +272 -0
  97. package/dist/components/objects/ObjectDetails/index.d.ts +9 -0
  98. package/dist/components/objects/ObjectDetails/index.js +75 -0
  99. package/dist/components/objects/ObjectList.d.ts +40 -0
  100. package/dist/components/objects/ObjectList.js +453 -0
  101. package/dist/components/objects/ObjectLock/EditRetentionButton.d.ts +4 -0
  102. package/dist/components/objects/ObjectLock/EditRetentionButton.js +32 -0
  103. package/dist/components/objects/ObjectLock/ObjectLockRetentionSettings.d.ts +3 -0
  104. package/dist/components/objects/ObjectLock/ObjectLockRetentionSettings.js +211 -0
  105. package/dist/components/objects/ObjectLock/ObjectLockSettings.d.ts +9 -0
  106. package/dist/components/objects/ObjectLock/ObjectLockSettings.js +158 -0
  107. package/dist/components/objects/ObjectLock/ObjectLockSettingsUtils.d.ts +8 -0
  108. package/dist/components/objects/ObjectLock/ObjectLockSettingsUtils.js +39 -0
  109. package/dist/components/objects/ObjectLock/__tests__/EditRetentionButton.test.d.ts +1 -0
  110. package/dist/components/objects/ObjectLock/__tests__/EditRetentionButton.test.js +204 -0
  111. package/dist/components/objects/ObjectLock/__tests__/ObjectLockSettings.test.d.ts +1 -0
  112. package/dist/components/objects/ObjectLock/__tests__/ObjectLockSettings.test.js +374 -0
  113. package/dist/components/objects/ObjectPage.d.ts +1 -0
  114. package/dist/components/objects/ObjectPage.js +45 -0
  115. package/dist/components/objects/UploadButton.d.ts +34 -0
  116. package/dist/components/objects/UploadButton.js +229 -0
  117. package/dist/components/providers/DataBrowserProvider.d.ts +20 -0
  118. package/dist/components/providers/DataBrowserProvider.js +42 -0
  119. package/dist/components/search/MetadataSearch.d.ts +5 -0
  120. package/dist/components/search/MetadataSearch.js +162 -0
  121. package/dist/components/search/SearchHints.d.ts +8 -0
  122. package/dist/components/search/SearchHints.js +21 -0
  123. package/dist/components/ui/ArrayFieldActions.d.ts +36 -0
  124. package/dist/components/ui/ArrayFieldActions.js +43 -0
  125. package/dist/components/ui/ConfirmDeleteRuleModal.d.ts +16 -0
  126. package/dist/components/ui/ConfirmDeleteRuleModal.js +43 -0
  127. package/dist/components/ui/DeleteObjectModalContent.d.ts +5 -0
  128. package/dist/components/ui/DeleteObjectModalContent.js +71 -0
  129. package/dist/components/ui/FilterFormSection.d.ts +44 -0
  130. package/dist/components/ui/FilterFormSection.js +159 -0
  131. package/dist/components/ui/Search.elements.d.ts +17 -0
  132. package/dist/components/ui/Search.elements.js +59 -0
  133. package/dist/components/ui/Table.elements.d.ts +36 -0
  134. package/dist/components/ui/Table.elements.js +87 -0
  135. package/dist/config/factory.d.ts +63 -0
  136. package/dist/config/factory.js +74 -0
  137. package/dist/config/types.d.ts +46 -0
  138. package/dist/config/types.js +0 -0
  139. package/dist/hooks/__tests__/useISVBucketDetection.test.d.ts +1 -0
  140. package/dist/hooks/__tests__/useISVBucketDetection.test.js +188 -0
  141. package/dist/hooks/__tests__/useIsBucketEmpty.test.d.ts +1 -0
  142. package/dist/hooks/__tests__/useIsBucketEmpty.test.js +122 -0
  143. package/dist/hooks/bucketConfiguration.d.ts +168 -0
  144. package/dist/hooks/bucketConfiguration.js +67 -0
  145. package/dist/hooks/bucketOperations.d.ts +36 -0
  146. package/dist/hooks/bucketOperations.js +12 -0
  147. package/dist/hooks/factories/__tests__/useCreateS3FunctionMutationHook.test.d.ts +1 -0
  148. package/dist/hooks/factories/__tests__/useCreateS3FunctionMutationHook.test.js +276 -0
  149. package/dist/hooks/factories/__tests__/useCreateS3InfiniteQueryHook.test.d.ts +1 -0
  150. package/dist/hooks/factories/__tests__/useCreateS3InfiniteQueryHook.test.js +259 -0
  151. package/dist/hooks/factories/__tests__/useCreateS3LoginHook.test.d.ts +1 -0
  152. package/dist/hooks/factories/__tests__/useCreateS3LoginHook.test.js +166 -0
  153. package/dist/hooks/factories/__tests__/useCreateS3MutationHook.test.d.ts +1 -0
  154. package/dist/hooks/factories/__tests__/useCreateS3MutationHook.test.js +200 -0
  155. package/dist/hooks/factories/__tests__/useCreateS3QueryHook.test.d.ts +1 -0
  156. package/dist/hooks/factories/__tests__/useCreateS3QueryHook.test.js +179 -0
  157. package/dist/hooks/factories/index.d.ts +18 -0
  158. package/dist/hooks/factories/index.js +5 -0
  159. package/dist/hooks/factories/useCreateS3InfiniteQueryHook.d.ts +13 -0
  160. package/dist/hooks/factories/useCreateS3InfiniteQueryHook.js +76 -0
  161. package/dist/hooks/factories/useCreateS3LoginHook.d.ts +8 -0
  162. package/dist/hooks/factories/useCreateS3LoginHook.js +22 -0
  163. package/dist/hooks/factories/useCreateS3MutationHook.d.ts +5 -0
  164. package/dist/hooks/factories/useCreateS3MutationHook.js +50 -0
  165. package/dist/hooks/factories/useCreateS3QueryHook.d.ts +3 -0
  166. package/dist/hooks/factories/useCreateS3QueryHook.js +51 -0
  167. package/dist/hooks/index.d.ts +13 -0
  168. package/dist/hooks/index.js +13 -0
  169. package/dist/hooks/loginOperations.d.ts +21 -0
  170. package/dist/hooks/loginOperations.js +9 -0
  171. package/dist/hooks/objectOperations.d.ts +190 -0
  172. package/dist/hooks/objectOperations.js +67 -0
  173. package/dist/hooks/presignedOperations.d.ts +73 -0
  174. package/dist/hooks/presignedOperations.js +72 -0
  175. package/dist/hooks/useBatchObjectLegalHold.d.ts +11 -0
  176. package/dist/hooks/useBatchObjectLegalHold.js +45 -0
  177. package/dist/hooks/useDeleteBucketConfigRule.d.ts +26 -0
  178. package/dist/hooks/useDeleteBucketConfigRule.js +46 -0
  179. package/dist/hooks/useEmptyBucket.d.ts +27 -0
  180. package/dist/hooks/useEmptyBucket.js +116 -0
  181. package/dist/hooks/useISVBucketDetection.d.ts +15 -0
  182. package/dist/hooks/useISVBucketDetection.js +27 -0
  183. package/dist/hooks/useIsBucketEmpty.d.ts +7 -0
  184. package/dist/hooks/useIsBucketEmpty.js +36 -0
  185. package/dist/hooks/useLoginMutation.d.ts +21 -0
  186. package/dist/hooks/useLoginMutation.js +9 -0
  187. package/dist/hooks/useS3Client.d.ts +1 -0
  188. package/dist/hooks/useS3Client.js +13 -0
  189. package/dist/hooks/useTableRowSelection.d.ts +9 -0
  190. package/dist/hooks/useTableRowSelection.js +45 -0
  191. package/dist/index.d.ts +6 -0
  192. package/dist/index.js +6 -0
  193. package/dist/schemas/bucketPolicySchema.json +321 -0
  194. package/dist/test/msw/handlers/deleteBucket.d.ts +1 -0
  195. package/dist/test/msw/handlers/deleteBucket.js +14 -0
  196. package/dist/test/msw/handlers/getBucketAcl.d.ts +1 -0
  197. package/dist/test/msw/handlers/getBucketAcl.js +96 -0
  198. package/dist/test/msw/handlers/getBucketLocation.d.ts +1 -0
  199. package/dist/test/msw/handlers/getBucketLocation.js +23 -0
  200. package/dist/test/msw/handlers/getBucketPolicy.d.ts +11 -0
  201. package/dist/test/msw/handlers/getBucketPolicy.js +72 -0
  202. package/dist/test/msw/handlers/headObject.d.ts +1 -0
  203. package/dist/test/msw/handlers/headObject.js +17 -0
  204. package/dist/test/msw/handlers/listBuckets.d.ts +1 -0
  205. package/dist/test/msw/handlers/listBuckets.js +24 -0
  206. package/dist/test/msw/handlers/listObjectVersions.d.ts +1 -0
  207. package/dist/test/msw/handlers/listObjectVersions.js +83 -0
  208. package/dist/test/msw/handlers/listObjects.d.ts +1 -0
  209. package/dist/test/msw/handlers/listObjects.js +66 -0
  210. package/dist/test/msw/handlers/objectLegalHold.d.ts +1 -0
  211. package/dist/test/msw/handlers/objectLegalHold.js +24 -0
  212. package/dist/test/msw/handlers/objectRetention.d.ts +1 -0
  213. package/dist/test/msw/handlers/objectRetention.js +27 -0
  214. package/dist/test/msw/handlers/putBucketAcl.d.ts +1 -0
  215. package/dist/test/msw/handlers/putBucketAcl.js +18 -0
  216. package/dist/test/msw/handlers/putObject.d.ts +1 -0
  217. package/dist/test/msw/handlers/putObject.js +16 -0
  218. package/dist/test/msw/handlers.d.ts +4 -0
  219. package/dist/test/msw/handlers.js +109 -0
  220. package/dist/test/msw/index.d.ts +2 -0
  221. package/dist/test/msw/index.js +3 -0
  222. package/dist/test/msw/server.d.ts +4 -0
  223. package/dist/test/msw/server.js +20 -0
  224. package/dist/test/msw/utils.d.ts +2 -0
  225. package/dist/test/msw/utils.js +13 -0
  226. package/dist/test/setup.d.ts +1 -0
  227. package/dist/test/setup.js +90 -0
  228. package/dist/test/testUtils.d.ts +181 -0
  229. package/dist/test/testUtils.js +310 -0
  230. package/dist/test/utils/errorHandling.test.d.ts +1 -0
  231. package/dist/test/utils/errorHandling.test.js +423 -0
  232. package/dist/types/index.d.ts +51 -0
  233. package/dist/types/index.js +0 -0
  234. package/dist/utils/constants.d.ts +12 -0
  235. package/dist/utils/constants.js +9 -0
  236. package/dist/utils/deletion/index.d.ts +2 -0
  237. package/dist/utils/deletion/index.js +2 -0
  238. package/dist/utils/deletion/messages.d.ts +5 -0
  239. package/dist/utils/deletion/messages.js +29 -0
  240. package/dist/utils/deletion/types.d.ts +11 -0
  241. package/dist/utils/deletion/types.js +0 -0
  242. package/dist/utils/errorHandling.d.ts +63 -0
  243. package/dist/utils/errorHandling.js +84 -0
  244. package/dist/utils/hooks.d.ts +2 -0
  245. package/dist/utils/hooks.js +26 -0
  246. package/dist/utils/index.d.ts +4 -0
  247. package/dist/utils/index.js +4 -0
  248. package/dist/utils/proxyMiddleware.d.ts +18 -0
  249. package/dist/utils/proxyMiddleware.js +56 -0
  250. package/dist/utils/s3Client.d.ts +5 -0
  251. package/dist/utils/s3Client.js +36 -0
  252. package/dist/utils/s3RuleUtils.d.ts +53 -0
  253. package/dist/utils/s3RuleUtils.js +101 -0
  254. package/dist/utils/useFeatures.d.ts +1 -0
  255. package/dist/utils/useFeatures.js +7 -0
  256. package/package.json +84 -0
@@ -0,0 +1,834 @@
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { joiResolver } from "@hookform/resolvers/joi";
3
+ import { Form, FormGroup, FormSection, Icon, Loader, Stack, Text, Toggle, spacing, useToast } from "@scality/core-ui";
4
+ import { convertRemToPixels } from "@scality/core-ui/dist/components/tablev2/TableUtils";
5
+ import { Box, Button, Input, Select } from "@scality/core-ui/dist/next";
6
+ import joi from "joi";
7
+ import { useCallback, useEffect, useMemo, useRef } from "react";
8
+ import { Controller, FormProvider, useFieldArray, useForm } from "react-hook-form";
9
+ import { useNavigate, useParams } from "react-router-dom";
10
+ import { useGetBucketReplication, useSetBucketReplication } from "../../hooks/bucketConfiguration.js";
11
+ import { useBuckets } from "../../hooks/bucketOperations.js";
12
+ import { FilterFormSection, createFilterValidationSchema } from "../ui/FilterFormSection.js";
13
+ import { AWS_RULE_LIMITS, STATUS_OPTIONS, buildS3Filter } from "../../utils/s3RuleUtils.js";
14
+ const storageClassOptions = [
15
+ {
16
+ value: "",
17
+ label: "Same as source"
18
+ },
19
+ {
20
+ value: "GLACIER",
21
+ label: "Glacier"
22
+ },
23
+ {
24
+ value: "DEEP_ARCHIVE",
25
+ label: "Glacier Deep Archive"
26
+ },
27
+ {
28
+ value: "STANDARD_IA",
29
+ label: "Standard-IA"
30
+ },
31
+ {
32
+ value: "ONEZONE_IA",
33
+ label: "One Zone-IA"
34
+ },
35
+ {
36
+ value: "INTELLIGENT_TIERING",
37
+ label: "Intelligent-Tiering"
38
+ },
39
+ {
40
+ value: "GLACIER_IR",
41
+ label: "Glacier Instant Retrieval"
42
+ }
43
+ ];
44
+ const createSchema = (hasExistingRules)=>joi.object({
45
+ role: hasExistingRules ? joi.string().optional() : joi.string().required().messages({
46
+ "string.empty": "Role ARN is required for first replication rule"
47
+ }),
48
+ ruleId: joi.string().required().max(AWS_RULE_LIMITS.RULE_ID_MAX_LENGTH).messages({
49
+ "string.empty": "Rule ID is required",
50
+ "string.max": `Rule ID must not exceed ${AWS_RULE_LIMITS.RULE_ID_MAX_LENGTH} characters`
51
+ }),
52
+ status: joi.string().valid(...STATUS_OPTIONS.map((o)=>o.value)).required(),
53
+ priority: joi.number().integer().min(0).allow(null).optional().messages({
54
+ "number.base": "Priority must be a number",
55
+ "number.min": "Priority must be at least 0"
56
+ }),
57
+ ...createFilterValidationSchema(joi),
58
+ includeEncryptedObjects: joi.boolean(),
59
+ replicaModifications: joi.boolean(),
60
+ sameAccount: joi.boolean(),
61
+ targetBucket: joi.string().required().messages({
62
+ "string.empty": "Target bucket is required"
63
+ }),
64
+ targetAccountId: joi.when("sameAccount", {
65
+ is: false,
66
+ then: joi.string().required().messages({
67
+ "string.empty": "Target account ID is required for cross-account replication"
68
+ }),
69
+ otherwise: joi.string().allow("").optional()
70
+ }),
71
+ storageClass: joi.string().allow("").optional(),
72
+ encryptReplicatedObjects: joi.boolean().custom((value, helpers)=>{
73
+ const { includeEncryptedObjects } = helpers.state.ancestors[0];
74
+ if (includeEncryptedObjects && !value) return helpers.error("any.invalid", {
75
+ message: "Encryption must be enabled when replicating encrypted objects"
76
+ });
77
+ return value;
78
+ }),
79
+ replicaKmsKeyId: joi.when("encryptReplicatedObjects", {
80
+ is: true,
81
+ then: joi.string().required().messages({
82
+ "string.empty": "Replica KMS Key ID is required when encrypting replicated objects"
83
+ }),
84
+ otherwise: joi.string().allow("").optional()
85
+ }),
86
+ enforceRTC: joi.boolean(),
87
+ enableRTCNotification: joi.when("enforceRTC", {
88
+ is: true,
89
+ then: joi.boolean().valid(true).messages({
90
+ "any.only": "Metrics must be enabled when RTC is enabled"
91
+ }),
92
+ otherwise: joi.boolean()
93
+ }),
94
+ deleteMarkerReplication: joi.boolean(),
95
+ switchObjectOwnership: joi.boolean()
96
+ });
97
+ const ruleToFormValues = (rule, role)=>{
98
+ const formValues = {
99
+ role,
100
+ ruleId: rule.ID || "",
101
+ status: rule.Status || "Enabled",
102
+ priority: rule.Priority ?? null,
103
+ filterType: "none",
104
+ prefix: "",
105
+ tags: [],
106
+ includeEncryptedObjects: false,
107
+ replicaModifications: false,
108
+ sameAccount: true,
109
+ targetBucket: "",
110
+ targetAccountId: "",
111
+ storageClass: "",
112
+ encryptReplicatedObjects: false,
113
+ replicaKmsKeyId: "",
114
+ enforceRTC: false,
115
+ enableRTCNotification: false,
116
+ deleteMarkerReplication: false,
117
+ switchObjectOwnership: false
118
+ };
119
+ if (void 0 !== rule.Prefix && "" !== rule.Prefix) {
120
+ formValues.filterType = "prefix";
121
+ formValues.prefix = rule.Prefix;
122
+ } else if (rule.Filter) {
123
+ if (rule.Filter.And) {
124
+ formValues.filterType = "and";
125
+ formValues.prefix = rule.Filter.And.Prefix || "";
126
+ formValues.tags = rule.Filter.And.Tags?.map((tag)=>({
127
+ key: tag.Key || "",
128
+ value: tag.Value || ""
129
+ })) || [];
130
+ } else if (void 0 !== rule.Filter.Prefix) {
131
+ formValues.filterType = "prefix";
132
+ formValues.prefix = rule.Filter.Prefix;
133
+ } else if (rule.Filter.Tag) {
134
+ formValues.filterType = "tags";
135
+ formValues.tags = [
136
+ {
137
+ key: rule.Filter.Tag.Key || "",
138
+ value: rule.Filter.Tag.Value || ""
139
+ }
140
+ ];
141
+ }
142
+ }
143
+ if (rule.SourceSelectionCriteria) {
144
+ formValues.includeEncryptedObjects = rule.SourceSelectionCriteria.SseKmsEncryptedObjects?.Status === "Enabled";
145
+ formValues.replicaModifications = rule.SourceSelectionCriteria.ReplicaModifications?.Status === "Enabled";
146
+ }
147
+ if (rule.Destination) {
148
+ const bucketArn = rule.Destination.Bucket || "";
149
+ const parts = bucketArn.split(":::");
150
+ formValues.targetBucket = parts[parts.length - 1] || bucketArn;
151
+ if (rule.Destination.Account) {
152
+ formValues.sameAccount = false;
153
+ formValues.targetAccountId = rule.Destination.Account;
154
+ } else formValues.sameAccount = true;
155
+ formValues.storageClass = rule.Destination.StorageClass || "";
156
+ formValues.switchObjectOwnership = rule.Destination.AccessControlTranslation?.Owner === "Destination";
157
+ if (rule.Destination.ReplicationTime) formValues.enforceRTC = "Enabled" === rule.Destination.ReplicationTime.Status;
158
+ if (rule.Destination.Metrics) formValues.enableRTCNotification = "Enabled" === rule.Destination.Metrics.Status;
159
+ if (rule.Destination.EncryptionConfiguration) {
160
+ formValues.encryptReplicatedObjects = true;
161
+ formValues.replicaKmsKeyId = rule.Destination.EncryptionConfiguration.ReplicaKmsKeyID || "";
162
+ }
163
+ }
164
+ if (rule.DeleteMarkerReplication) formValues.deleteMarkerReplication = "Enabled" === rule.DeleteMarkerReplication.Status;
165
+ return formValues;
166
+ };
167
+ const ToggleFormField = ({ name, label, id, control, labelHelpTooltip })=>/*#__PURE__*/ jsx(FormGroup, {
168
+ label: label,
169
+ id: id,
170
+ direction: "horizontal",
171
+ labelHelpTooltip: labelHelpTooltip,
172
+ content: /*#__PURE__*/ jsx(Controller, {
173
+ name: name,
174
+ control: control,
175
+ render: ({ field })=>/*#__PURE__*/ jsx(Toggle, {
176
+ toggle: field.value,
177
+ onChange: field.onChange,
178
+ label: field.value ? "Enabled" : "Disabled"
179
+ })
180
+ })
181
+ });
182
+ const buildDestination = (data)=>({
183
+ Bucket: `arn:aws:s3:::${data.targetBucket}`,
184
+ ...!data.sameAccount && data.targetAccountId && "" !== data.targetAccountId.trim() && {
185
+ Account: data.targetAccountId
186
+ },
187
+ ...data.storageClass && "" !== data.storageClass.trim() && {
188
+ StorageClass: data.storageClass
189
+ },
190
+ ...(data.enforceRTC || data.enableRTCNotification) && {
191
+ ReplicationTime: {
192
+ Status: data.enforceRTC ? "Enabled" : "Disabled",
193
+ Time: {
194
+ Minutes: 15
195
+ }
196
+ },
197
+ Metrics: {
198
+ Status: "Enabled",
199
+ ...data.enforceRTC && {
200
+ EventThreshold: {
201
+ Minutes: 15
202
+ }
203
+ }
204
+ }
205
+ },
206
+ ...data.encryptReplicatedObjects && data.replicaKmsKeyId && "" !== data.replicaKmsKeyId.trim() && {
207
+ EncryptionConfiguration: {
208
+ ReplicaKmsKeyID: data.replicaKmsKeyId
209
+ }
210
+ },
211
+ ...!data.sameAccount && data.switchObjectOwnership && data.targetAccountId && "" !== data.targetAccountId.trim() && {
212
+ AccessControlTranslation: {
213
+ Owner: "Destination"
214
+ }
215
+ }
216
+ });
217
+ const buildSourceSelectionCriteria = (data)=>{
218
+ if (data.includeEncryptedObjects || data.replicaModifications) return {
219
+ ...data.includeEncryptedObjects && {
220
+ SseKmsEncryptedObjects: {
221
+ Status: "Enabled"
222
+ }
223
+ },
224
+ ...data.replicaModifications && {
225
+ ReplicaModifications: {
226
+ Status: "Enabled"
227
+ }
228
+ }
229
+ };
230
+ };
231
+ const buildReplicationRule = (data)=>{
232
+ const rule = {
233
+ ID: data.ruleId,
234
+ Status: data.status,
235
+ Priority: data.priority ?? 0,
236
+ Destination: buildDestination(data)
237
+ };
238
+ const filter = buildS3Filter(data);
239
+ if (filter) rule.Filter = filter;
240
+ const sourceSelectionCriteria = buildSourceSelectionCriteria(data);
241
+ if (sourceSelectionCriteria) rule.SourceSelectionCriteria = sourceSelectionCriteria;
242
+ rule.DeleteMarkerReplication = {
243
+ Status: data.deleteMarkerReplication ? "Enabled" : "Disabled"
244
+ };
245
+ return rule;
246
+ };
247
+ function BucketReplicationFormPage() {
248
+ const { bucketName, ruleId } = useParams();
249
+ const navigate = useNavigate();
250
+ const { showToast } = useToast();
251
+ const isEditMode = !!ruleId;
252
+ const { data: replicationData, status: replicationStatus } = useGetBucketReplication({
253
+ Bucket: bucketName
254
+ });
255
+ const { data: bucketsData } = useBuckets();
256
+ const availableBuckets = bucketsData?.Buckets || [];
257
+ const existingRole = replicationData?.ReplicationConfiguration?.Role || "";
258
+ const hasExistingRules = (replicationData?.ReplicationConfiguration?.Rules || []).length > 0;
259
+ const existingRule = useMemo(()=>{
260
+ if (!isEditMode || !replicationData?.ReplicationConfiguration?.Rules || !ruleId) return null;
261
+ return replicationData.ReplicationConfiguration.Rules.find((rule)=>rule.ID === decodeURIComponent(ruleId)) || null;
262
+ }, [
263
+ isEditMode,
264
+ replicationData,
265
+ ruleId
266
+ ]);
267
+ const existingRuleIds = useMemo(()=>(replicationData?.ReplicationConfiguration?.Rules || []).map((rule)=>rule.ID).filter(Boolean).filter((id)=>!isEditMode || id !== existingRule?.ID), [
268
+ replicationData,
269
+ isEditMode,
270
+ existingRule
271
+ ]);
272
+ const nextAvailablePriority = useMemo(()=>{
273
+ const existingRules = replicationData?.ReplicationConfiguration?.Rules || [];
274
+ if (0 === existingRules.length) return 0;
275
+ const priorities = existingRules.map((rule)=>rule.Priority).filter((p)=>null != p);
276
+ if (0 === priorities.length) return 0;
277
+ return Math.max(...priorities) + 1;
278
+ }, [
279
+ replicationData
280
+ ]);
281
+ const dynamicSchema = useMemo(()=>createSchema(hasExistingRules).keys({
282
+ ruleId: joi.string().required().invalid(...existingRuleIds).messages({
283
+ "string.empty": "Rule ID is required",
284
+ "any.invalid": "A rule with this ID already exists"
285
+ })
286
+ }), [
287
+ existingRuleIds,
288
+ hasExistingRules
289
+ ]);
290
+ const methods = useForm({
291
+ resolver: joiResolver(dynamicSchema),
292
+ mode: "onChange",
293
+ defaultValues: {
294
+ role: "",
295
+ ruleId: "",
296
+ status: "Enabled",
297
+ priority: null,
298
+ filterType: "none",
299
+ prefix: "",
300
+ tags: [],
301
+ includeEncryptedObjects: false,
302
+ replicaModifications: false,
303
+ sameAccount: true,
304
+ targetBucket: "",
305
+ targetAccountId: "",
306
+ storageClass: "",
307
+ encryptReplicatedObjects: false,
308
+ replicaKmsKeyId: "",
309
+ enforceRTC: false,
310
+ enableRTCNotification: false,
311
+ deleteMarkerReplication: false,
312
+ switchObjectOwnership: false
313
+ }
314
+ });
315
+ const { handleSubmit, register, control, watch, reset, formState: { isValid, isDirty, errors } } = methods;
316
+ const { fields: tagFields, append: appendTag, remove: removeTag } = useFieldArray({
317
+ control,
318
+ name: "tags"
319
+ });
320
+ const filterType = watch("filterType");
321
+ const sameAccount = watch("sameAccount");
322
+ const encryptReplicatedObjects = watch("encryptReplicatedObjects");
323
+ const includeEncryptedObjects = watch("includeEncryptedObjects");
324
+ const deleteMarkerReplication = watch("deleteMarkerReplication");
325
+ const enforceRTC = watch("enforceRTC");
326
+ const { mutate: setReplication, isPending: isSaving } = useSetBucketReplication();
327
+ const loadedRuleIdRef = useRef(null);
328
+ useEffect(()=>{
329
+ if (isEditMode && existingRule) {
330
+ if (loadedRuleIdRef.current !== existingRule.ID) {
331
+ const formValues = ruleToFormValues(existingRule, existingRole);
332
+ reset(formValues);
333
+ loadedRuleIdRef.current = existingRule.ID || null;
334
+ }
335
+ } else if (!isEditMode && !isDirty) {
336
+ reset((prev)=>({
337
+ ...prev,
338
+ role: existingRole,
339
+ priority: nextAvailablePriority
340
+ }));
341
+ loadedRuleIdRef.current = null;
342
+ }
343
+ }, [
344
+ isEditMode,
345
+ existingRule,
346
+ existingRole,
347
+ nextAvailablePriority,
348
+ isDirty,
349
+ reset
350
+ ]);
351
+ const prevFilterTypeRef = useRef();
352
+ useEffect(()=>{
353
+ const prevFilterType = prevFilterTypeRef.current;
354
+ prevFilterTypeRef.current = filterType;
355
+ if (("tags" === filterType || "and" === filterType) && 0 === tagFields.length) {
356
+ if (!isEditMode || void 0 !== prevFilterType && prevFilterType !== filterType) appendTag({
357
+ key: "",
358
+ value: ""
359
+ });
360
+ }
361
+ if (void 0 !== prevFilterType && prevFilterType !== filterType) {
362
+ if (("none" === filterType || "prefix" === filterType) && tagFields.length > 0) tagFields.forEach((_, index)=>{
363
+ removeTag(tagFields.length - 1 - index);
364
+ });
365
+ if ("none" === filterType) methods.setValue("prefix", "", {
366
+ shouldDirty: true
367
+ });
368
+ }
369
+ }, [
370
+ isEditMode,
371
+ filterType,
372
+ tagFields,
373
+ appendTag,
374
+ removeTag,
375
+ methods
376
+ ]);
377
+ useEffect(()=>{
378
+ if (includeEncryptedObjects && !encryptReplicatedObjects) methods.setValue("encryptReplicatedObjects", true, {
379
+ shouldValidate: true
380
+ });
381
+ }, [
382
+ includeEncryptedObjects,
383
+ encryptReplicatedObjects,
384
+ methods
385
+ ]);
386
+ useEffect(()=>{
387
+ if (("tags" === filterType || "and" === filterType) && deleteMarkerReplication) methods.setValue("deleteMarkerReplication", false, {
388
+ shouldValidate: true
389
+ });
390
+ }, [
391
+ filterType,
392
+ deleteMarkerReplication,
393
+ methods
394
+ ]);
395
+ useEffect(()=>{
396
+ if (enforceRTC) methods.setValue("enableRTCNotification", true, {
397
+ shouldValidate: true
398
+ });
399
+ }, [
400
+ enforceRTC,
401
+ methods
402
+ ]);
403
+ const handleCancel = useCallback(()=>{
404
+ navigate(`/buckets/${bucketName}?tab=replication`);
405
+ }, [
406
+ navigate,
407
+ bucketName
408
+ ]);
409
+ const onSubmit = useCallback((data)=>{
410
+ if (!bucketName) return;
411
+ const rule = buildReplicationRule(data);
412
+ const existingRules = replicationData?.ReplicationConfiguration?.Rules || [];
413
+ const updatedRules = isEditMode ? existingRules.map((r)=>r.ID === existingRule?.ID ? rule : r) : [
414
+ ...existingRules,
415
+ rule
416
+ ];
417
+ setReplication({
418
+ Bucket: bucketName,
419
+ ReplicationConfiguration: {
420
+ Role: data.role,
421
+ Rules: updatedRules
422
+ }
423
+ }, {
424
+ onSuccess: ()=>{
425
+ showToast({
426
+ open: true,
427
+ message: `Replication rule ${isEditMode ? "updated" : "created"} successfully`,
428
+ status: "success"
429
+ });
430
+ navigate(`/buckets/${bucketName}?tab=replication`);
431
+ },
432
+ onError: (error)=>{
433
+ const errorMessage = error instanceof Error ? error.message : `Failed to ${isEditMode ? "update" : "create"} replication rule`;
434
+ showToast({
435
+ open: true,
436
+ message: errorMessage,
437
+ status: "error"
438
+ });
439
+ }
440
+ });
441
+ }, [
442
+ bucketName,
443
+ setReplication,
444
+ navigate,
445
+ showToast,
446
+ replicationData,
447
+ isEditMode,
448
+ existingRule
449
+ ]);
450
+ if ("pending" === replicationStatus) return /*#__PURE__*/ jsx(Loader, {
451
+ centered: true,
452
+ children: /*#__PURE__*/ jsx(Text, {
453
+ children: "Loading..."
454
+ })
455
+ });
456
+ if (isEditMode && !existingRule) return /*#__PURE__*/ jsx(Box, {
457
+ padding: spacing.r16,
458
+ children: /*#__PURE__*/ jsx(Text, {
459
+ color: "statusCritical",
460
+ children: "Rule not found"
461
+ })
462
+ });
463
+ return /*#__PURE__*/ jsx(FormProvider, {
464
+ ...methods,
465
+ children: /*#__PURE__*/ jsxs(Form, {
466
+ layout: {
467
+ kind: "page",
468
+ title: isEditMode ? "Edit Replication Rule" : "Create Replication Rule"
469
+ },
470
+ requireMode: "partial",
471
+ onSubmit: handleSubmit(onSubmit),
472
+ rightActions: /*#__PURE__*/ jsxs(Stack, {
473
+ gap: "r16",
474
+ children: [
475
+ /*#__PURE__*/ jsx(Button, {
476
+ id: "cancel-btn",
477
+ variant: "outline",
478
+ type: "button",
479
+ label: "Cancel",
480
+ onClick: handleCancel,
481
+ disabled: isSaving
482
+ }),
483
+ /*#__PURE__*/ jsx(Button, {
484
+ id: isEditMode ? "save-replication-btn" : "create-replication-btn",
485
+ type: "submit",
486
+ variant: "primary",
487
+ label: isEditMode ? "Save" : "Create",
488
+ icon: isEditMode ? /*#__PURE__*/ jsx(Icon, {
489
+ name: "Save"
490
+ }) : void 0,
491
+ disabled: !isDirty || !isValid || isSaving
492
+ })
493
+ ]
494
+ }),
495
+ children: [
496
+ /*#__PURE__*/ jsx(FormSection, {
497
+ title: {
498
+ name: "Role"
499
+ },
500
+ forceLabelWidth: convertRemToPixels(15),
501
+ children: /*#__PURE__*/ jsx(FormGroup, {
502
+ label: "Role ARN",
503
+ id: "role",
504
+ direction: "horizontal",
505
+ error: errors?.role?.message,
506
+ helpErrorPosition: "bottom",
507
+ required: !hasExistingRules,
508
+ content: hasExistingRules ? /*#__PURE__*/ jsxs(Stack, {
509
+ direction: "vertical",
510
+ gap: "r8",
511
+ children: [
512
+ /*#__PURE__*/ jsx(Text, {
513
+ children: existingRole || "Not set"
514
+ }),
515
+ /*#__PURE__*/ jsx(Text, {
516
+ color: "textSecondary",
517
+ children: "To change the Role, edit it through bucket configuration or delete all rules first"
518
+ })
519
+ ]
520
+ }) : /*#__PURE__*/ jsx(Input, {
521
+ id: "role",
522
+ placeholder: "arn:aws:iam::123456789012:role/replication-role",
523
+ ...register("role")
524
+ })
525
+ })
526
+ }),
527
+ /*#__PURE__*/ jsxs(FormSection, {
528
+ title: {
529
+ name: "Rule Scope"
530
+ },
531
+ forceLabelWidth: convertRemToPixels(15),
532
+ children: [
533
+ /*#__PURE__*/ jsx(FormGroup, {
534
+ label: "Rule ID / Name",
535
+ id: "ruleId",
536
+ direction: "horizontal",
537
+ error: errors?.ruleId?.message,
538
+ helpErrorPosition: "bottom",
539
+ required: true,
540
+ content: isEditMode ? /*#__PURE__*/ jsx(Text, {
541
+ children: watch("ruleId")
542
+ }) : /*#__PURE__*/ jsx(Input, {
543
+ id: "ruleId",
544
+ ...register("ruleId")
545
+ })
546
+ }),
547
+ /*#__PURE__*/ jsx(FormGroup, {
548
+ label: "Status",
549
+ id: "status",
550
+ direction: "horizontal",
551
+ error: errors?.status?.message,
552
+ helpErrorPosition: "bottom",
553
+ required: true,
554
+ content: /*#__PURE__*/ jsx(Controller, {
555
+ name: "status",
556
+ control: control,
557
+ render: ({ field })=>/*#__PURE__*/ jsx(Select, {
558
+ id: "status",
559
+ value: field.value,
560
+ onChange: field.onChange,
561
+ children: STATUS_OPTIONS.map((option)=>/*#__PURE__*/ jsx(Select.Option, {
562
+ value: option.value,
563
+ children: option.label
564
+ }, option.value))
565
+ })
566
+ })
567
+ }),
568
+ /*#__PURE__*/ jsx(FormGroup, {
569
+ label: "Rule priority",
570
+ id: "priority",
571
+ direction: "horizontal",
572
+ error: errors?.priority?.message,
573
+ helpErrorPosition: "bottom",
574
+ labelHelpTooltip: "Lower numbers have higher priority. Rules are evaluated in priority order when filters overlap.",
575
+ content: /*#__PURE__*/ jsx(Box, {
576
+ flex: "1",
577
+ children: /*#__PURE__*/ jsx(Input, {
578
+ type: "number",
579
+ id: "priority",
580
+ placeholder: isEditMode ? void 0 : `Auto-assigned: ${nextAvailablePriority}`,
581
+ ...register("priority", {
582
+ setValueAs: (v)=>{
583
+ if ("" === v || null == v) return null;
584
+ const parsed = parseInt(v, 10);
585
+ return isNaN(parsed) ? null : parsed;
586
+ }
587
+ })
588
+ })
589
+ })
590
+ })
591
+ ]
592
+ }),
593
+ /*#__PURE__*/ jsx(FilterFormSection, {
594
+ filterType: filterType,
595
+ onFilterTypeChange: (value)=>methods.setValue("filterType", value),
596
+ prefixRegister: register("prefix"),
597
+ tagFields: tagFields,
598
+ tagKeyRegister: (index)=>register(`tags.${index}.key`),
599
+ tagValueRegister: (index)=>register(`tags.${index}.value`),
600
+ getTagKeyValue: (index)=>watch(`tags.${index}.key`),
601
+ getTagValueValue: (index)=>watch(`tags.${index}.value`),
602
+ appendTag: appendTag,
603
+ removeTag: removeTag,
604
+ errors: errors
605
+ }),
606
+ /*#__PURE__*/ jsxs(FormSection, {
607
+ title: {
608
+ name: "Destination"
609
+ },
610
+ forceLabelWidth: convertRemToPixels(15),
611
+ children: [
612
+ /*#__PURE__*/ jsx(FormGroup, {
613
+ label: "Destination",
614
+ id: "sameAccount",
615
+ direction: "horizontal",
616
+ content: /*#__PURE__*/ jsx(Controller, {
617
+ name: "sameAccount",
618
+ control: control,
619
+ render: ({ field })=>/*#__PURE__*/ jsx(Toggle, {
620
+ toggle: field.value,
621
+ onChange: field.onChange,
622
+ label: field.value ? "Same account destination" : "Not same account destination"
623
+ })
624
+ })
625
+ }),
626
+ sameAccount ? /*#__PURE__*/ jsx(Fragment, {}) : /*#__PURE__*/ jsx(FormGroup, {
627
+ label: "Target account ID",
628
+ id: "targetAccountId",
629
+ direction: "horizontal",
630
+ error: errors?.targetAccountId?.message,
631
+ helpErrorPosition: "bottom",
632
+ required: true,
633
+ content: /*#__PURE__*/ jsx(Input, {
634
+ id: "targetAccountId",
635
+ placeholder: "Account ID",
636
+ ...register("targetAccountId")
637
+ })
638
+ }),
639
+ /*#__PURE__*/ jsx(FormGroup, {
640
+ label: "Target Bucket",
641
+ id: "targetBucket",
642
+ direction: "horizontal",
643
+ error: errors?.targetBucket?.message,
644
+ helpErrorPosition: "bottom",
645
+ required: true,
646
+ content: sameAccount ? /*#__PURE__*/ jsx(Controller, {
647
+ name: "targetBucket",
648
+ control: control,
649
+ render: ({ field })=>/*#__PURE__*/ jsx(Select, {
650
+ id: "targetBucket",
651
+ value: field.value,
652
+ onChange: field.onChange,
653
+ placeholder: "Select a bucket",
654
+ children: availableBuckets.filter((bucket)=>bucket.Name !== bucketName).map((bucket)=>/*#__PURE__*/ jsx(Select.Option, {
655
+ value: bucket.Name || "",
656
+ children: bucket.Name
657
+ }, bucket.Name))
658
+ })
659
+ }) : /*#__PURE__*/ jsx(Input, {
660
+ id: "targetBucket",
661
+ placeholder: "Bucket name",
662
+ ...register("targetBucket")
663
+ })
664
+ }),
665
+ /*#__PURE__*/ jsx(FormGroup, {
666
+ label: "Storage Class",
667
+ id: "storageClass",
668
+ direction: "horizontal",
669
+ error: errors?.storageClass?.message,
670
+ helpErrorPosition: "bottom",
671
+ labelHelpTooltip: "Storage class for replicated objects in destination bucket",
672
+ content: /*#__PURE__*/ jsx(Controller, {
673
+ name: "storageClass",
674
+ control: control,
675
+ render: ({ field })=>/*#__PURE__*/ jsx(Select, {
676
+ id: "storageClass",
677
+ value: field.value,
678
+ onChange: field.onChange,
679
+ children: storageClassOptions.map((option)=>/*#__PURE__*/ jsx(Select.Option, {
680
+ value: option.value,
681
+ children: option.label
682
+ }, option.value))
683
+ })
684
+ })
685
+ }),
686
+ sameAccount ? /*#__PURE__*/ jsx(Fragment, {}) : /*#__PURE__*/ jsx(ToggleFormField, {
687
+ name: "switchObjectOwnership",
688
+ label: "Switch Object ownership",
689
+ id: "switchObjectOwnership",
690
+ control: control,
691
+ labelHelpTooltip: "Change replica ownership to destination bucket owner (AccessControlTranslation)"
692
+ })
693
+ ]
694
+ }),
695
+ /*#__PURE__*/ jsxs(FormSection, {
696
+ title: {
697
+ name: "Encryption"
698
+ },
699
+ forceLabelWidth: convertRemToPixels(15),
700
+ children: [
701
+ /*#__PURE__*/ jsx(ToggleFormField, {
702
+ name: "includeEncryptedObjects",
703
+ label: "Replicate encrypted objects",
704
+ id: "includeEncryptedObjects",
705
+ control: control,
706
+ labelHelpTooltip: "Replicate objects encrypted with KMS from source bucket"
707
+ }),
708
+ /*#__PURE__*/ jsx(FormGroup, {
709
+ label: "Encrypt replicated objects",
710
+ id: "encryptReplicatedObjects",
711
+ direction: "horizontal",
712
+ error: errors?.encryptReplicatedObjects?.message,
713
+ helpErrorPosition: "bottom",
714
+ labelHelpTooltip: "Encrypt objects in destination bucket using KMS",
715
+ required: includeEncryptedObjects,
716
+ content: /*#__PURE__*/ jsxs(Stack, {
717
+ direction: "vertical",
718
+ gap: "r8",
719
+ children: [
720
+ /*#__PURE__*/ jsx(Controller, {
721
+ name: "encryptReplicatedObjects",
722
+ control: control,
723
+ render: ({ field })=>/*#__PURE__*/ jsx(Toggle, {
724
+ toggle: field.value,
725
+ onChange: field.onChange,
726
+ label: field.value ? "Enabled" : "Disabled",
727
+ disabled: includeEncryptedObjects
728
+ })
729
+ }),
730
+ includeEncryptedObjects && /*#__PURE__*/ jsx(Text, {
731
+ color: "textSecondary",
732
+ children: "Encryption is required when replicating encrypted objects"
733
+ })
734
+ ]
735
+ })
736
+ }),
737
+ encryptReplicatedObjects ? /*#__PURE__*/ jsx(FormGroup, {
738
+ label: "Replica KMS Key ID",
739
+ id: "replicaKmsKeyId",
740
+ direction: "horizontal",
741
+ error: errors?.replicaKmsKeyId?.message,
742
+ helpErrorPosition: "bottom",
743
+ labelHelpTooltip: "KMS key ID or ARN to use for encrypting replicated objects",
744
+ required: true,
745
+ content: /*#__PURE__*/ jsx(Input, {
746
+ id: "replicaKmsKeyId",
747
+ placeholder: "KMS Key ID or ARN",
748
+ ...register("replicaKmsKeyId")
749
+ })
750
+ }) : /*#__PURE__*/ jsx(Fragment, {})
751
+ ]
752
+ }),
753
+ /*#__PURE__*/ jsxs(FormSection, {
754
+ title: {
755
+ name: "Additional Options"
756
+ },
757
+ forceLabelWidth: convertRemToPixels(15),
758
+ children: [
759
+ /*#__PURE__*/ jsx(ToggleFormField, {
760
+ name: "enforceRTC",
761
+ label: "Replication Time Control (RTC)",
762
+ id: "enforceRTC",
763
+ control: control,
764
+ labelHelpTooltip: "Guarantees replication within 15 minutes with SLA monitoring"
765
+ }),
766
+ /*#__PURE__*/ jsx(FormGroup, {
767
+ label: "RTC metrics and notifications",
768
+ id: "enableRTCNotification",
769
+ direction: "horizontal",
770
+ labelHelpTooltip: "Emit S3 events when replication exceeds 15-minute RTC threshold",
771
+ required: enforceRTC,
772
+ content: /*#__PURE__*/ jsxs(Stack, {
773
+ direction: "vertical",
774
+ gap: "r8",
775
+ children: [
776
+ /*#__PURE__*/ jsx(Controller, {
777
+ name: "enableRTCNotification",
778
+ control: control,
779
+ render: ({ field })=>/*#__PURE__*/ jsx(Toggle, {
780
+ toggle: field.value,
781
+ onChange: field.onChange,
782
+ label: field.value ? "Enabled" : "Disabled",
783
+ disabled: enforceRTC
784
+ })
785
+ }),
786
+ enforceRTC && /*#__PURE__*/ jsx(Text, {
787
+ color: "textSecondary",
788
+ children: "Metrics must be enabled when RTC is enabled"
789
+ })
790
+ ]
791
+ })
792
+ }),
793
+ /*#__PURE__*/ jsx(ToggleFormField, {
794
+ name: "replicaModifications",
795
+ label: "Replica modification sync",
796
+ id: "replicaModifications",
797
+ control: control,
798
+ labelHelpTooltip: "Replicate metadata changes made to replica objects"
799
+ }),
800
+ /*#__PURE__*/ jsx(FormGroup, {
801
+ label: "Delete marker replication",
802
+ id: "deleteMarkerReplication",
803
+ direction: "horizontal",
804
+ error: errors?.deleteMarkerReplication?.message,
805
+ helpErrorPosition: "bottom",
806
+ labelHelpTooltip: "Replicate delete markers created when objects are deleted in versioned buckets",
807
+ content: /*#__PURE__*/ jsxs(Stack, {
808
+ direction: "vertical",
809
+ gap: "r8",
810
+ children: [
811
+ /*#__PURE__*/ jsx(Controller, {
812
+ name: "deleteMarkerReplication",
813
+ control: control,
814
+ render: ({ field })=>/*#__PURE__*/ jsx(Toggle, {
815
+ toggle: field.value,
816
+ onChange: field.onChange,
817
+ label: field.value ? "Enabled" : "Disabled",
818
+ disabled: "tags" === filterType || "and" === filterType
819
+ })
820
+ }),
821
+ ("tags" === filterType || "and" === filterType) && /*#__PURE__*/ jsx(Text, {
822
+ color: "textSecondary",
823
+ children: "Delete marker replication is not supported for tag-based filters"
824
+ })
825
+ ]
826
+ })
827
+ })
828
+ ]
829
+ })
830
+ ]
831
+ })
832
+ });
833
+ }
834
+ export { BucketReplicationFormPage };