@scality/data-browser-library 1.0.9 → 1.1.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.
- package/dist/components/__tests__/BucketReplicationFormPage.test.js +33 -0
- package/dist/components/buckets/BucketReplicationFormPage.d.ts +1 -0
- package/dist/components/buckets/BucketReplicationFormPage.js +142 -116
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.js +2 -2
- package/dist/config/types.d.ts +11 -0
- package/package.json +1 -1
|
@@ -4,6 +4,7 @@ import user_event from "@testing-library/user-event";
|
|
|
4
4
|
import { MemoryRouter, Route, Routes } from "react-router";
|
|
5
5
|
import { useGetBucketReplication, useSetBucketReplication } from "../../hooks/bucketConfiguration.js";
|
|
6
6
|
import { useBuckets } from "../../hooks/bucketOperations.js";
|
|
7
|
+
import { useFeatures } from "../../hooks/useFeatures.js";
|
|
7
8
|
import { useISVBucketStatus } from "../../hooks/useISVBucketDetection.js";
|
|
8
9
|
import { createTestWrapper, findToggleByLabel, mockErrorSubmit, mockOffsetSize, mockSuccessSubmit, submitForm } from "../../test/testUtils.js";
|
|
9
10
|
import { BucketReplicationFormPage } from "../buckets/BucketReplicationFormPage.js";
|
|
@@ -14,12 +15,16 @@ jest.mock('../../hooks/bucketConfiguration', ()=>({
|
|
|
14
15
|
jest.mock('../../hooks/bucketOperations', ()=>({
|
|
15
16
|
useBuckets: jest.fn()
|
|
16
17
|
}));
|
|
18
|
+
jest.mock('../../hooks/useFeatures', ()=>({
|
|
19
|
+
useFeatures: jest.fn()
|
|
20
|
+
}));
|
|
17
21
|
jest.mock('../../hooks/useISVBucketDetection', ()=>({
|
|
18
22
|
useISVBucketStatus: jest.fn()
|
|
19
23
|
}));
|
|
20
24
|
const mockUseGetBucketReplication = jest.mocked(useGetBucketReplication);
|
|
21
25
|
const mockUseSetBucketReplication = jest.mocked(useSetBucketReplication);
|
|
22
26
|
const mockUseBuckets = jest.mocked(useBuckets);
|
|
27
|
+
const mockUseFeatures = jest.mocked(useFeatures);
|
|
23
28
|
const mockUseISVBucketStatus = jest.mocked(useISVBucketStatus);
|
|
24
29
|
const mockNavigate = jest.fn();
|
|
25
30
|
const mockShowToast = jest.fn();
|
|
@@ -107,6 +112,7 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
107
112
|
},
|
|
108
113
|
status: 'success'
|
|
109
114
|
});
|
|
115
|
+
mockUseFeatures.mockReturnValue(true);
|
|
110
116
|
mockUseISVBucketStatus.mockReturnValue({
|
|
111
117
|
isVeeamBucket: false,
|
|
112
118
|
isCommvaultBucket: false,
|
|
@@ -1946,4 +1952,31 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
1946
1952
|
expect(screen.getByText(/bucket used for external integration with Kasten/i)).toBeInTheDocument();
|
|
1947
1953
|
});
|
|
1948
1954
|
});
|
|
1955
|
+
describe('Feature Flag - replicationAdvanced', ()=>{
|
|
1956
|
+
it('hides Additional Options section when replicationAdvanced is disabled', ()=>{
|
|
1957
|
+
mockUseFeatures.mockReturnValue(false);
|
|
1958
|
+
renderBucketReplicationFormPage();
|
|
1959
|
+
expect(screen.queryByText('Replication Time Control (RTC)')).not.toBeInTheDocument();
|
|
1960
|
+
expect(screen.queryByText('RTC metrics and notifications')).not.toBeInTheDocument();
|
|
1961
|
+
expect(screen.queryByText('Replica modification sync')).not.toBeInTheDocument();
|
|
1962
|
+
expect(screen.queryByText('Delete marker replication')).not.toBeInTheDocument();
|
|
1963
|
+
});
|
|
1964
|
+
it('hides switchObjectOwnership toggle when replicationAdvanced is disabled', async ()=>{
|
|
1965
|
+
mockUseFeatures.mockReturnValue(false);
|
|
1966
|
+
renderBucketReplicationFormPage();
|
|
1967
|
+
const sameAccountToggle = findToggleByLabel('Same account destination');
|
|
1968
|
+
await user_event.click(sameAccountToggle);
|
|
1969
|
+
await waitFor(()=>{
|
|
1970
|
+
expect(screen.queryByText('Switch Object ownership')).not.toBeInTheDocument();
|
|
1971
|
+
});
|
|
1972
|
+
});
|
|
1973
|
+
it('shows Additional Options section when replicationAdvanced is enabled', ()=>{
|
|
1974
|
+
mockUseFeatures.mockReturnValue(true);
|
|
1975
|
+
renderBucketReplicationFormPage();
|
|
1976
|
+
expect(screen.getByText('Replication Time Control (RTC)')).toBeInTheDocument();
|
|
1977
|
+
expect(screen.getByText('RTC metrics and notifications')).toBeInTheDocument();
|
|
1978
|
+
expect(screen.getByText('Replica modification sync')).toBeInTheDocument();
|
|
1979
|
+
expect(screen.getByText('Delete marker replication')).toBeInTheDocument();
|
|
1980
|
+
});
|
|
1981
|
+
});
|
|
1949
1982
|
});
|
|
@@ -5,13 +5,14 @@ import { convertRemToPixels } from "@scality/core-ui/dist/components/tablev2/Tab
|
|
|
5
5
|
import { Box, Button, Input, Select } from "@scality/core-ui/dist/next";
|
|
6
6
|
import joi from "joi";
|
|
7
7
|
import { useCallback, useEffect, useMemo, useRef } from "react";
|
|
8
|
-
import { Controller, FormProvider, useFieldArray, useForm } from "react-hook-form";
|
|
8
|
+
import { Controller, FormProvider, useFieldArray, useForm, useFormContext } from "react-hook-form";
|
|
9
9
|
import { useParams } from "react-router";
|
|
10
10
|
import { useDataBrowserUICustomization } from "../../contexts/DataBrowserUICustomizationContext.js";
|
|
11
11
|
import { useGetBucketReplication, useSetBucketReplication } from "../../hooks/bucketConfiguration.js";
|
|
12
12
|
import { useBuckets } from "../../hooks/bucketOperations.js";
|
|
13
|
-
import { useISVBucketStatus } from "../../hooks/useISVBucketDetection.js";
|
|
14
13
|
import { useDataBrowserNavigate } from "../../hooks/useDataBrowserNavigate.js";
|
|
14
|
+
import { useFeatures } from "../../hooks/useFeatures.js";
|
|
15
|
+
import { useISVBucketStatus } from "../../hooks/useISVBucketDetection.js";
|
|
15
16
|
import { AWS_RULE_LIMITS, STATUS_OPTIONS, buildS3Filter } from "../../utils/s3RuleUtils.js";
|
|
16
17
|
import { FilterFormSection, createFilterValidationSchema } from "../ui/FilterFormSection.js";
|
|
17
18
|
const storageClassOptions = [
|
|
@@ -44,7 +45,7 @@ const storageClassOptions = [
|
|
|
44
45
|
label: 'Glacier Instant Retrieval'
|
|
45
46
|
}
|
|
46
47
|
];
|
|
47
|
-
const createSchema = (hasExistingRules)=>joi.object({
|
|
48
|
+
const createSchema = (hasExistingRules, hasCustomDestination)=>joi.object({
|
|
48
49
|
role: hasExistingRules ? joi.string().optional() : joi.string().required().messages({
|
|
49
50
|
'string.empty': 'Role ARN is required for first replication rule'
|
|
50
51
|
}),
|
|
@@ -61,10 +62,10 @@ const createSchema = (hasExistingRules)=>joi.object({
|
|
|
61
62
|
includeEncryptedObjects: joi.boolean(),
|
|
62
63
|
replicaModifications: joi.boolean(),
|
|
63
64
|
sameAccount: joi.boolean(),
|
|
64
|
-
targetBucket: joi.string().required().messages({
|
|
65
|
+
targetBucket: hasCustomDestination ? joi.string().allow('').optional() : joi.string().required().messages({
|
|
65
66
|
'string.empty': 'Target bucket is required'
|
|
66
67
|
}),
|
|
67
|
-
targetAccountId: joi.when('sameAccount', {
|
|
68
|
+
targetAccountId: hasCustomDestination ? joi.string().allow('').optional() : joi.when('sameAccount', {
|
|
68
69
|
is: false,
|
|
69
70
|
then: joi.string().required().messages({
|
|
70
71
|
'string.empty': 'Target account ID is required for cross-account replication'
|
|
@@ -185,8 +186,10 @@ const ToggleFormField = ({ name, label, id, control, labelHelpTooltip })=>/*#__P
|
|
|
185
186
|
})
|
|
186
187
|
})
|
|
187
188
|
});
|
|
188
|
-
const buildDestination = (data)=>
|
|
189
|
-
|
|
189
|
+
const buildDestination = (data, sourceBucketName)=>{
|
|
190
|
+
const bucketName = data.targetBucket || sourceBucketName;
|
|
191
|
+
return {
|
|
192
|
+
Bucket: `arn:aws:s3:::${bucketName}`,
|
|
190
193
|
...!data.sameAccount && data.targetAccountId && '' !== data.targetAccountId.trim() && {
|
|
191
194
|
Account: data.targetAccountId
|
|
192
195
|
},
|
|
@@ -219,7 +222,8 @@ const buildDestination = (data)=>({
|
|
|
219
222
|
Owner: 'Destination'
|
|
220
223
|
}
|
|
221
224
|
}
|
|
222
|
-
}
|
|
225
|
+
};
|
|
226
|
+
};
|
|
223
227
|
const buildSourceSelectionCriteria = (data)=>{
|
|
224
228
|
if (data.includeEncryptedObjects || data.replicaModifications) return {
|
|
225
229
|
...data.includeEncryptedObjects && {
|
|
@@ -234,12 +238,12 @@ const buildSourceSelectionCriteria = (data)=>{
|
|
|
234
238
|
}
|
|
235
239
|
};
|
|
236
240
|
};
|
|
237
|
-
const buildReplicationRule = (data)=>{
|
|
241
|
+
const buildReplicationRule = (data, sourceBucketName)=>{
|
|
238
242
|
const rule = {
|
|
239
243
|
ID: data.ruleId,
|
|
240
244
|
Status: data.status,
|
|
241
245
|
Priority: data.priority ?? 0,
|
|
242
|
-
Destination: buildDestination(data)
|
|
246
|
+
Destination: buildDestination(data, sourceBucketName)
|
|
243
247
|
};
|
|
244
248
|
const filter = buildS3Filter(data);
|
|
245
249
|
if (filter) rule.Filter = filter;
|
|
@@ -250,18 +254,95 @@ const buildReplicationRule = (data)=>{
|
|
|
250
254
|
};
|
|
251
255
|
return rule;
|
|
252
256
|
};
|
|
257
|
+
function DefaultReplicationDestinationFields() {
|
|
258
|
+
const { watch, register, control, formState: { errors } } = useFormContext();
|
|
259
|
+
const { bucketName } = useParams();
|
|
260
|
+
const { data: bucketsData } = useBuckets();
|
|
261
|
+
const availableBuckets = bucketsData?.Buckets || [];
|
|
262
|
+
const sameAccount = watch('sameAccount');
|
|
263
|
+
const showAdvancedReplication = useFeatures('replicationAdvanced');
|
|
264
|
+
return /*#__PURE__*/ jsxs(Fragment, {
|
|
265
|
+
children: [
|
|
266
|
+
/*#__PURE__*/ jsx(FormGroup, {
|
|
267
|
+
label: "Destination",
|
|
268
|
+
id: "sameAccount",
|
|
269
|
+
direction: "horizontal",
|
|
270
|
+
labelHelpTooltip: "Toggle between same-account and cross-account replication destination",
|
|
271
|
+
content: /*#__PURE__*/ jsx(Controller, {
|
|
272
|
+
name: "sameAccount",
|
|
273
|
+
control: control,
|
|
274
|
+
render: ({ field })=>/*#__PURE__*/ jsx(Toggle, {
|
|
275
|
+
toggle: field.value,
|
|
276
|
+
onChange: field.onChange,
|
|
277
|
+
label: field.value ? 'Same account destination' : 'Not same account destination'
|
|
278
|
+
})
|
|
279
|
+
})
|
|
280
|
+
}),
|
|
281
|
+
sameAccount ? /*#__PURE__*/ jsx(Fragment, {}) : /*#__PURE__*/ jsx("div", {
|
|
282
|
+
style: {
|
|
283
|
+
paddingLeft: spacing.r24
|
|
284
|
+
},
|
|
285
|
+
children: /*#__PURE__*/ jsx(FormGroup, {
|
|
286
|
+
label: "Target account ID",
|
|
287
|
+
id: "targetAccountId",
|
|
288
|
+
direction: "horizontal",
|
|
289
|
+
error: errors?.targetAccountId?.message,
|
|
290
|
+
helpErrorPosition: "bottom",
|
|
291
|
+
required: true,
|
|
292
|
+
content: /*#__PURE__*/ jsx(Input, {
|
|
293
|
+
id: "targetAccountId",
|
|
294
|
+
placeholder: "Account ID",
|
|
295
|
+
...register('targetAccountId')
|
|
296
|
+
})
|
|
297
|
+
})
|
|
298
|
+
}),
|
|
299
|
+
/*#__PURE__*/ jsx(FormGroup, {
|
|
300
|
+
label: "Target Bucket",
|
|
301
|
+
id: "targetBucket",
|
|
302
|
+
direction: "horizontal",
|
|
303
|
+
error: errors?.targetBucket?.message,
|
|
304
|
+
helpErrorPosition: "bottom",
|
|
305
|
+
required: true,
|
|
306
|
+
content: sameAccount ? /*#__PURE__*/ jsx(Controller, {
|
|
307
|
+
name: "targetBucket",
|
|
308
|
+
control: control,
|
|
309
|
+
render: ({ field })=>/*#__PURE__*/ jsx(Select, {
|
|
310
|
+
id: "targetBucket",
|
|
311
|
+
value: field.value,
|
|
312
|
+
onChange: field.onChange,
|
|
313
|
+
placeholder: "Select a bucket",
|
|
314
|
+
children: availableBuckets.filter((bucket)=>bucket.Name !== bucketName).map((bucket)=>/*#__PURE__*/ jsx(Select.Option, {
|
|
315
|
+
value: bucket.Name || '',
|
|
316
|
+
children: bucket.Name
|
|
317
|
+
}, bucket.Name))
|
|
318
|
+
})
|
|
319
|
+
}) : /*#__PURE__*/ jsx(Input, {
|
|
320
|
+
id: "targetBucket",
|
|
321
|
+
placeholder: "Bucket name",
|
|
322
|
+
...register('targetBucket')
|
|
323
|
+
})
|
|
324
|
+
}),
|
|
325
|
+
showAdvancedReplication && !sameAccount ? /*#__PURE__*/ jsx(ToggleFormField, {
|
|
326
|
+
name: "switchObjectOwnership",
|
|
327
|
+
label: "Switch Object ownership",
|
|
328
|
+
id: "switchObjectOwnership",
|
|
329
|
+
control: control,
|
|
330
|
+
labelHelpTooltip: "Change replica ownership to destination bucket owner (AccessControlTranslation)"
|
|
331
|
+
}) : /*#__PURE__*/ jsx(Fragment, {})
|
|
332
|
+
]
|
|
333
|
+
});
|
|
334
|
+
}
|
|
253
335
|
function BucketReplicationFormPage() {
|
|
254
|
-
const { storageClassSelector: StorageClassSelector, storageClassLabel } = useDataBrowserUICustomization();
|
|
336
|
+
const { storageClassSelector: StorageClassSelector, storageClassLabel, replicationRoleDefault, replicationDestinationFields: CustomDestinationFields } = useDataBrowserUICustomization();
|
|
255
337
|
const { bucketName, ruleId } = useParams();
|
|
256
338
|
const navigate = useDataBrowserNavigate();
|
|
257
339
|
const { showToast } = useToast();
|
|
258
340
|
const isEditMode = !!ruleId;
|
|
341
|
+
const showAdvancedReplication = useFeatures('replicationAdvanced');
|
|
259
342
|
const { isISVManaged, isvApplication, isLoading: isISVLoading } = useISVBucketStatus(bucketName);
|
|
260
343
|
const { data: replicationData, status: replicationStatus } = useGetBucketReplication({
|
|
261
344
|
Bucket: bucketName
|
|
262
345
|
});
|
|
263
|
-
const { data: bucketsData } = useBuckets();
|
|
264
|
-
const availableBuckets = bucketsData?.Buckets || [];
|
|
265
346
|
const existingRole = replicationData?.ReplicationConfiguration?.Role || '';
|
|
266
347
|
const hasExistingRules = (replicationData?.ReplicationConfiguration?.Rules || []).length > 0;
|
|
267
348
|
const existingRule = useMemo(()=>{
|
|
@@ -286,20 +367,21 @@ function BucketReplicationFormPage() {
|
|
|
286
367
|
}, [
|
|
287
368
|
replicationData
|
|
288
369
|
]);
|
|
289
|
-
const dynamicSchema = useMemo(()=>createSchema(hasExistingRules).keys({
|
|
370
|
+
const dynamicSchema = useMemo(()=>createSchema(hasExistingRules, !!CustomDestinationFields).keys({
|
|
290
371
|
ruleId: joi.string().required().invalid(...existingRuleIds).messages({
|
|
291
372
|
'string.empty': 'Rule ID is required',
|
|
292
373
|
'any.invalid': 'A rule with this ID already exists'
|
|
293
374
|
})
|
|
294
375
|
}), [
|
|
295
376
|
existingRuleIds,
|
|
296
|
-
hasExistingRules
|
|
377
|
+
hasExistingRules,
|
|
378
|
+
CustomDestinationFields
|
|
297
379
|
]);
|
|
298
380
|
const methods = useForm({
|
|
299
381
|
resolver: joiResolver(dynamicSchema),
|
|
300
382
|
mode: 'onChange',
|
|
301
383
|
defaultValues: {
|
|
302
|
-
role: '',
|
|
384
|
+
role: replicationRoleDefault || '',
|
|
303
385
|
ruleId: '',
|
|
304
386
|
status: 'Enabled',
|
|
305
387
|
priority: null,
|
|
@@ -327,11 +409,35 @@ function BucketReplicationFormPage() {
|
|
|
327
409
|
name: 'tags'
|
|
328
410
|
});
|
|
329
411
|
const filterType = watch('filterType');
|
|
330
|
-
const sameAccount = watch('sameAccount');
|
|
331
412
|
const encryptReplicatedObjects = watch('encryptReplicatedObjects');
|
|
332
413
|
const includeEncryptedObjects = watch('includeEncryptedObjects');
|
|
333
414
|
const deleteMarkerReplication = watch('deleteMarkerReplication');
|
|
334
415
|
const enforceRTC = watch('enforceRTC');
|
|
416
|
+
const storageClassField = /*#__PURE__*/ jsx(FormGroup, {
|
|
417
|
+
label: storageClassLabel || 'Storage Class',
|
|
418
|
+
id: "storageClass",
|
|
419
|
+
direction: "horizontal",
|
|
420
|
+
error: errors?.storageClass?.message,
|
|
421
|
+
helpErrorPosition: "bottom",
|
|
422
|
+
labelHelpTooltip: StorageClassSelector ? void 0 : 'Storage class for replicated objects in destination bucket',
|
|
423
|
+
content: /*#__PURE__*/ jsx(Controller, {
|
|
424
|
+
name: "storageClass",
|
|
425
|
+
control: control,
|
|
426
|
+
render: ({ field })=>StorageClassSelector ? /*#__PURE__*/ jsx(StorageClassSelector, {
|
|
427
|
+
value: field.value,
|
|
428
|
+
onChange: field.onChange,
|
|
429
|
+
context: "replication"
|
|
430
|
+
}) : /*#__PURE__*/ jsx(Select, {
|
|
431
|
+
id: "storageClass",
|
|
432
|
+
value: field.value,
|
|
433
|
+
onChange: field.onChange,
|
|
434
|
+
children: storageClassOptions.map((option)=>/*#__PURE__*/ jsx(Select.Option, {
|
|
435
|
+
value: option.value,
|
|
436
|
+
children: option.label
|
|
437
|
+
}, option.value))
|
|
438
|
+
})
|
|
439
|
+
})
|
|
440
|
+
});
|
|
335
441
|
const { mutate: setReplication, isPending: isSaving } = useSetBucketReplication();
|
|
336
442
|
const loadedRuleIdRef = useRef(null);
|
|
337
443
|
useEffect(()=>{
|
|
@@ -344,7 +450,7 @@ function BucketReplicationFormPage() {
|
|
|
344
450
|
} else if (!isEditMode && !isDirty) {
|
|
345
451
|
reset((prev)=>({
|
|
346
452
|
...prev,
|
|
347
|
-
role: existingRole,
|
|
453
|
+
role: existingRole || replicationRoleDefault || '',
|
|
348
454
|
priority: nextAvailablePriority
|
|
349
455
|
}));
|
|
350
456
|
loadedRuleIdRef.current = null;
|
|
@@ -353,6 +459,7 @@ function BucketReplicationFormPage() {
|
|
|
353
459
|
isEditMode,
|
|
354
460
|
existingRule,
|
|
355
461
|
existingRole,
|
|
462
|
+
replicationRoleDefault,
|
|
356
463
|
nextAvailablePriority,
|
|
357
464
|
isDirty,
|
|
358
465
|
reset
|
|
@@ -425,7 +532,7 @@ function BucketReplicationFormPage() {
|
|
|
425
532
|
]);
|
|
426
533
|
const onSubmit = useCallback((data)=>{
|
|
427
534
|
if (!bucketName) return;
|
|
428
|
-
const rule = buildReplicationRule(data);
|
|
535
|
+
const rule = buildReplicationRule(data, bucketName);
|
|
429
536
|
const existingRules = replicationData?.ReplicationConfiguration?.Rules || [];
|
|
430
537
|
const updatedRules = isEditMode ? existingRules.map((r)=>r.ID === existingRule?.ID ? rule : r) : [
|
|
431
538
|
...existingRules,
|
|
@@ -553,7 +660,7 @@ function BucketReplicationFormPage() {
|
|
|
553
660
|
direction: "horizontal",
|
|
554
661
|
error: errors?.role?.message,
|
|
555
662
|
helpErrorPosition: "bottom",
|
|
556
|
-
required:
|
|
663
|
+
required: true,
|
|
557
664
|
content: hasExistingRules ? /*#__PURE__*/ jsxs(Stack, {
|
|
558
665
|
direction: "vertical",
|
|
559
666
|
gap: "r8",
|
|
@@ -562,6 +669,7 @@ function BucketReplicationFormPage() {
|
|
|
562
669
|
children: existingRole || 'Not set'
|
|
563
670
|
}),
|
|
564
671
|
/*#__PURE__*/ jsx(Text, {
|
|
672
|
+
variant: "Small",
|
|
565
673
|
color: "textSecondary",
|
|
566
674
|
children: "To change the Role, edit it through bucket configuration or delete all rules first"
|
|
567
675
|
})
|
|
@@ -648,104 +756,22 @@ function BucketReplicationFormPage() {
|
|
|
648
756
|
removeTag: removeTag,
|
|
649
757
|
errors: errors
|
|
650
758
|
}),
|
|
651
|
-
/*#__PURE__*/
|
|
759
|
+
/*#__PURE__*/ jsx(FormSection, {
|
|
652
760
|
title: {
|
|
653
761
|
name: 'Destination'
|
|
654
762
|
},
|
|
655
763
|
forceLabelWidth: convertRemToPixels(15),
|
|
656
|
-
children:
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
onChange: field.onChange,
|
|
668
|
-
label: field.value ? 'Same account destination' : 'Not same account destination'
|
|
669
|
-
})
|
|
670
|
-
})
|
|
671
|
-
}),
|
|
672
|
-
sameAccount ? /*#__PURE__*/ jsx(Fragment, {}) : /*#__PURE__*/ jsx("div", {
|
|
673
|
-
style: {
|
|
674
|
-
paddingLeft: spacing.r24
|
|
675
|
-
},
|
|
676
|
-
children: /*#__PURE__*/ jsx(FormGroup, {
|
|
677
|
-
label: "Target account ID",
|
|
678
|
-
id: "targetAccountId",
|
|
679
|
-
direction: "horizontal",
|
|
680
|
-
error: errors?.targetAccountId?.message,
|
|
681
|
-
helpErrorPosition: "bottom",
|
|
682
|
-
required: true,
|
|
683
|
-
content: /*#__PURE__*/ jsx(Input, {
|
|
684
|
-
id: "targetAccountId",
|
|
685
|
-
placeholder: "Account ID",
|
|
686
|
-
...register('targetAccountId')
|
|
687
|
-
})
|
|
688
|
-
})
|
|
689
|
-
}),
|
|
690
|
-
/*#__PURE__*/ jsx(FormGroup, {
|
|
691
|
-
label: "Target Bucket",
|
|
692
|
-
id: "targetBucket",
|
|
693
|
-
direction: "horizontal",
|
|
694
|
-
error: errors?.targetBucket?.message,
|
|
695
|
-
helpErrorPosition: "bottom",
|
|
696
|
-
required: true,
|
|
697
|
-
content: sameAccount ? /*#__PURE__*/ jsx(Controller, {
|
|
698
|
-
name: "targetBucket",
|
|
699
|
-
control: control,
|
|
700
|
-
render: ({ field })=>/*#__PURE__*/ jsx(Select, {
|
|
701
|
-
id: "targetBucket",
|
|
702
|
-
value: field.value,
|
|
703
|
-
onChange: field.onChange,
|
|
704
|
-
placeholder: "Select a bucket",
|
|
705
|
-
children: availableBuckets.filter((bucket)=>bucket.Name !== bucketName).map((bucket)=>/*#__PURE__*/ jsx(Select.Option, {
|
|
706
|
-
value: bucket.Name || '',
|
|
707
|
-
children: bucket.Name
|
|
708
|
-
}, bucket.Name))
|
|
709
|
-
})
|
|
710
|
-
}) : /*#__PURE__*/ jsx(Input, {
|
|
711
|
-
id: "targetBucket",
|
|
712
|
-
placeholder: "Bucket name",
|
|
713
|
-
...register('targetBucket')
|
|
714
|
-
})
|
|
715
|
-
}),
|
|
716
|
-
/*#__PURE__*/ jsx(FormGroup, {
|
|
717
|
-
label: storageClassLabel || 'Storage Class',
|
|
718
|
-
id: "storageClass",
|
|
719
|
-
direction: "horizontal",
|
|
720
|
-
error: errors?.storageClass?.message,
|
|
721
|
-
helpErrorPosition: "bottom",
|
|
722
|
-
labelHelpTooltip: StorageClassSelector ? void 0 : 'Storage class for replicated objects in destination bucket',
|
|
723
|
-
content: /*#__PURE__*/ jsx(Controller, {
|
|
724
|
-
name: "storageClass",
|
|
725
|
-
control: control,
|
|
726
|
-
render: ({ field })=>StorageClassSelector ? /*#__PURE__*/ jsx(StorageClassSelector, {
|
|
727
|
-
value: field.value,
|
|
728
|
-
onChange: field.onChange,
|
|
729
|
-
context: "replication"
|
|
730
|
-
}) : /*#__PURE__*/ jsx(Select, {
|
|
731
|
-
id: "storageClass",
|
|
732
|
-
value: field.value,
|
|
733
|
-
onChange: field.onChange,
|
|
734
|
-
children: storageClassOptions.map((option)=>/*#__PURE__*/ jsx(Select.Option, {
|
|
735
|
-
value: option.value,
|
|
736
|
-
children: option.label
|
|
737
|
-
}, option.value))
|
|
738
|
-
})
|
|
739
|
-
})
|
|
740
|
-
}),
|
|
741
|
-
sameAccount ? /*#__PURE__*/ jsx(Fragment, {}) : /*#__PURE__*/ jsx(ToggleFormField, {
|
|
742
|
-
name: "switchObjectOwnership",
|
|
743
|
-
label: "Switch Object ownership",
|
|
744
|
-
id: "switchObjectOwnership",
|
|
745
|
-
control: control,
|
|
746
|
-
labelHelpTooltip: "Change replica ownership to destination bucket owner (AccessControlTranslation)"
|
|
747
|
-
})
|
|
748
|
-
]
|
|
764
|
+
children: CustomDestinationFields ? /*#__PURE__*/ jsxs(Fragment, {
|
|
765
|
+
children: [
|
|
766
|
+
storageClassField,
|
|
767
|
+
/*#__PURE__*/ jsx(CustomDestinationFields, {})
|
|
768
|
+
]
|
|
769
|
+
}) : /*#__PURE__*/ jsxs(Fragment, {
|
|
770
|
+
children: [
|
|
771
|
+
/*#__PURE__*/ jsx(DefaultReplicationDestinationFields, {}),
|
|
772
|
+
storageClassField
|
|
773
|
+
]
|
|
774
|
+
})
|
|
749
775
|
}),
|
|
750
776
|
/*#__PURE__*/ jsxs(FormSection, {
|
|
751
777
|
title: {
|
|
@@ -811,7 +837,7 @@ function BucketReplicationFormPage() {
|
|
|
811
837
|
}) : /*#__PURE__*/ jsx(Fragment, {})
|
|
812
838
|
]
|
|
813
839
|
}),
|
|
814
|
-
/*#__PURE__*/ jsxs(FormSection, {
|
|
840
|
+
showAdvancedReplication && /*#__PURE__*/ jsxs(FormSection, {
|
|
815
841
|
title: {
|
|
816
842
|
name: 'Additional Options'
|
|
817
843
|
},
|
|
@@ -894,4 +920,4 @@ function BucketReplicationFormPage() {
|
|
|
894
920
|
})
|
|
895
921
|
});
|
|
896
922
|
}
|
|
897
|
-
export { BucketReplicationFormPage };
|
|
923
|
+
export { BucketReplicationFormPage, DefaultReplicationDestinationFields };
|
|
@@ -8,7 +8,7 @@ export { BucketList } from './buckets/BucketList';
|
|
|
8
8
|
export { BucketOverview, BucketOverviewField, BucketOverviewSection, useBucketOverviewContext, } from './buckets/BucketOverview';
|
|
9
9
|
export { BucketPage } from './buckets/BucketPage';
|
|
10
10
|
export { BucketPolicyPage } from './buckets/BucketPolicyPage';
|
|
11
|
-
export { BucketReplicationFormPage } from './buckets/BucketReplicationFormPage';
|
|
11
|
+
export { BucketReplicationFormPage, DefaultReplicationDestinationFields, } from './buckets/BucketReplicationFormPage';
|
|
12
12
|
export { BucketVersioning } from './buckets/BucketVersioning';
|
|
13
13
|
export { DeleteBucketButton } from './buckets/DeleteBucketButton';
|
|
14
14
|
export { EmptyBucketButton } from './buckets/EmptyBucketButton';
|
package/dist/components/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import { BucketList } from "./buckets/BucketList.js";
|
|
|
8
8
|
import { BucketOverview, BucketOverviewField, BucketOverviewSection, useBucketOverviewContext } from "./buckets/BucketOverview.js";
|
|
9
9
|
import { BucketPage } from "./buckets/BucketPage.js";
|
|
10
10
|
import { BucketPolicyPage } from "./buckets/BucketPolicyPage.js";
|
|
11
|
-
import { BucketReplicationFormPage } from "./buckets/BucketReplicationFormPage.js";
|
|
11
|
+
import { BucketReplicationFormPage, DefaultReplicationDestinationFields } from "./buckets/BucketReplicationFormPage.js";
|
|
12
12
|
import { BucketVersioning } from "./buckets/BucketVersioning.js";
|
|
13
13
|
import { DeleteBucketButton } from "./buckets/DeleteBucketButton.js";
|
|
14
14
|
import { EmptyBucketButton } from "./buckets/EmptyBucketButton.js";
|
|
@@ -25,4 +25,4 @@ import { DataBrowserProvider, useDataBrowserConfig, useDataBrowserContext, useIn
|
|
|
25
25
|
import { QueryProvider } from "./providers/QueryProvider.js";
|
|
26
26
|
import { MetadataSearch } from "./search/MetadataSearch.js";
|
|
27
27
|
import { ArrayFieldActions } from "./ui/ArrayFieldActions.js";
|
|
28
|
-
export { ArrayFieldActions, Breadcrumb, BucketAccessor, BucketCorsPage, BucketCreate, BucketLifecycleFormPage, BucketList, BucketNotificationFormPage, BucketOverview, BucketOverviewField, BucketOverviewSection, BucketPage, BucketPolicyPage, BucketReplicationFormPage, BucketVersioning, CreateFolderButton, DataBrowserBreadcrumb, DataBrowserProvider, DataBrowserUI, DeleteBucketButton, EditRetentionButton, EmptyBucketButton, MetadataSearch, ObjectDetails, ObjectList, ObjectLockSettings, ObjectPage, QueryProvider, UploadButton, baseBucketCreateSchema, bucketErrorMessage, bucketNameValidationSchema, useBreadcrumbPaths, useBucketOverviewContext, useDataBrowserConfig, useDataBrowserContext, useDataBrowserNavigate, useInvalidateQueries };
|
|
28
|
+
export { ArrayFieldActions, Breadcrumb, BucketAccessor, BucketCorsPage, BucketCreate, BucketLifecycleFormPage, BucketList, BucketNotificationFormPage, BucketOverview, BucketOverviewField, BucketOverviewSection, BucketPage, BucketPolicyPage, BucketReplicationFormPage, BucketVersioning, CreateFolderButton, DataBrowserBreadcrumb, DataBrowserProvider, DataBrowserUI, DefaultReplicationDestinationFields, DeleteBucketButton, EditRetentionButton, EmptyBucketButton, MetadataSearch, ObjectDetails, ObjectList, ObjectLockSettings, ObjectPage, QueryProvider, UploadButton, baseBucketCreateSchema, bucketErrorMessage, bucketNameValidationSchema, useBreadcrumbPaths, useBucketOverviewContext, useDataBrowserConfig, useDataBrowserContext, useDataBrowserNavigate, useInvalidateQueries };
|
package/dist/config/types.d.ts
CHANGED
|
@@ -262,6 +262,17 @@ export interface DataBrowserUIProps {
|
|
|
262
262
|
* - "legalHold" - Legal Hold field
|
|
263
263
|
*/
|
|
264
264
|
extraObjectSummaryDataProtection?: FieldConfig[];
|
|
265
|
+
/** Pre-fills the Role ARN input field with this value. */
|
|
266
|
+
replicationRoleDefault?: string;
|
|
267
|
+
/**
|
|
268
|
+
* When provided, replaces the default destination fields
|
|
269
|
+
* (sameAccount toggle, targetBucket, targetAccountId, switchObjectOwnership).
|
|
270
|
+
* The StorageClass/Location selector is rendered separately above.
|
|
271
|
+
*
|
|
272
|
+
* Use `DefaultReplicationDestinationFields` (exported from the library)
|
|
273
|
+
* to fall back to default behavior for non-custom cases.
|
|
274
|
+
*/
|
|
275
|
+
replicationDestinationFields?: React.ComponentType;
|
|
265
276
|
}
|
|
266
277
|
export type S3EventType = 's3:ObjectCreated:*' | 's3:ObjectCreated:Put' | 's3:ObjectCreated:Post' | 's3:ObjectCreated:Copy' | 's3:ObjectCreated:CompleteMultipartUpload' | 's3:ObjectRemoved:*' | 's3:ObjectRemoved:Delete' | 's3:ObjectRemoved:DeleteMarkerCreated' | 's3:ObjectRestore:*' | 's3:ObjectRestore:Post' | 's3:ObjectRestore:Completed' | 's3:ObjectRestore:Delete' | 's3:LifecycleExpiration:*' | 's3:LifecycleExpiration:Delete' | 's3:LifecycleExpiration:DeleteMarkerCreated' | 's3:LifecycleTransition' | 's3:Replication:*' | 's3:Replication:OperationFailedReplication' | 's3:Replication:OperationMissedThreshold' | 's3:Replication:OperationReplicatedAfterThreshold' | 's3:Replication:OperationNotTracked' | 's3:ObjectTagging:*' | 's3:ObjectTagging:Put' | 's3:ObjectTagging:Delete' | 's3:ReducedRedundancyLostObject' | 's3:IntelligentTiering' | 's3:ObjectAcl:Put' | 's3:TestEvent';
|
|
267
278
|
export type S3EventCategory = 'Object Creation' | 'Object Deletion' | 'Object Restoration' | 'Lifecycle' | 'Replication' | 'Object Tagging' | 'Storage & Access' | 'Testing';
|