@scality/data-browser-library 1.1.9 → 1.1.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.
- package/dist/components/__tests__/BucketCorsPage.test.js +14 -6
- package/dist/components/__tests__/BucketLifecycleFormPage.test.js +131 -0
- package/dist/components/__tests__/BucketNotificationFormPage.test.js +15 -3
- package/dist/components/buckets/BucketCorsPage.js +5 -7
- package/dist/components/buckets/BucketLifecycleFormPage.js +32 -44
- package/dist/components/buckets/BucketLifecycleList.js +8 -4
- package/dist/components/buckets/BucketOverview.js +1 -1
- package/dist/components/buckets/BucketPolicyPage.js +4 -7
- package/dist/components/buckets/BucketReplicationFormPage.js +12 -6
- package/dist/components/buckets/BucketReplicationList.js +12 -9
- package/dist/components/buckets/BucketVersioning.js +1 -1
- package/dist/components/buckets/notifications/BucketNotificationFormPage.js +2 -2
- package/dist/components/buckets/notifications/BucketNotificationList.js +1 -1
- package/dist/components/objects/DeleteObjectButton.js +1 -1
- package/dist/components/objects/GetPresignedUrlButton.js +1 -1
- package/dist/components/objects/ObjectDetails/ObjectMetadata.js +1 -1
- package/dist/components/objects/ObjectDetails/ObjectSummary.js +2 -2
- package/dist/components/objects/ObjectDetails/ObjectTags.js +1 -1
- package/dist/components/objects/ObjectDetails/__tests__/ObjectSummary.test.js +37 -1
- package/dist/components/objects/ObjectLock/ObjectLockSettings.js +1 -1
- package/dist/components/objects/__tests__/GetPresignedUrlButton.test.js +30 -1
- package/dist/components/providers/QueryProvider.js +2 -1
- package/dist/hooks/bucketConfiguration.js +15 -15
- package/dist/hooks/bucketOperations.js +1 -1
- package/dist/hooks/factories/__tests__/useCreateS3FunctionMutationHook.test.js +7 -35
- package/dist/hooks/factories/__tests__/useCreateS3InfiniteQueryHook.test.js +1 -1
- package/dist/hooks/factories/__tests__/useCreateS3MutationHook.test.js +1 -1
- package/dist/hooks/factories/__tests__/useCreateS3QueryHook.test.js +1 -1
- package/dist/hooks/factories/useCreateS3InfiniteQueryHook.d.ts +1 -1
- package/dist/hooks/factories/useCreateS3InfiniteQueryHook.js +2 -2
- package/dist/hooks/factories/useCreateS3MutationHook.d.ts +3 -3
- package/dist/hooks/factories/useCreateS3MutationHook.js +20 -8
- package/dist/hooks/factories/useCreateS3QueryHook.d.ts +1 -1
- package/dist/hooks/factories/useCreateS3QueryHook.js +2 -2
- package/dist/hooks/objectOperations.js +6 -6
- package/dist/hooks/presignedOperations.js +1 -1
- package/dist/hooks/useDeleteFolder.js +1 -1
- package/dist/test/utils/errorHandling.test.js +45 -33
- package/dist/utils/errorHandling.d.ts +2 -1
- package/dist/utils/errorHandling.js +8 -7
- package/package.json +2 -2
|
@@ -306,16 +306,24 @@ describe('BucketCorsPage', ()=>{
|
|
|
306
306
|
replace: true
|
|
307
307
|
});
|
|
308
308
|
});
|
|
309
|
-
it('shows
|
|
310
|
-
const
|
|
311
|
-
accessDeniedError.name = 'AccessDenied';
|
|
309
|
+
it('shows permission message when fetching CORS fails with 403 error', ()=>{
|
|
310
|
+
const authError = new EnhancedS3Error("You don't have permission to load CORS configuration. Contact your administrator.", 'AccessDenied', ErrorCategory.AUTHORIZATION, new Error('Access Denied'), 403);
|
|
312
311
|
mockUseGetBucketCors.mockReturnValue(createMockQueryResult({
|
|
313
312
|
status: 'error',
|
|
314
|
-
error:
|
|
313
|
+
error: authError
|
|
315
314
|
}));
|
|
316
315
|
renderBucketCorsPage();
|
|
317
|
-
expect(screen.getByText(
|
|
318
|
-
expect(screen.
|
|
316
|
+
expect(screen.getByText("You don't have permission to load CORS configuration. Contact your administrator.")).toBeInTheDocument();
|
|
317
|
+
expect(screen.queryByTestId('cors-editor')).not.toBeInTheDocument();
|
|
318
|
+
});
|
|
319
|
+
it('shows original error message when fetching CORS fails with non-403 error', ()=>{
|
|
320
|
+
const serverError = new EnhancedS3Error('Internal Server Error', 'InternalError', ErrorCategory.SERVER_ERROR, new Error('Internal Server Error'), 500);
|
|
321
|
+
mockUseGetBucketCors.mockReturnValue(createMockQueryResult({
|
|
322
|
+
status: 'error',
|
|
323
|
+
error: serverError
|
|
324
|
+
}));
|
|
325
|
+
renderBucketCorsPage();
|
|
326
|
+
expect(screen.getByText('Internal Server Error')).toBeInTheDocument();
|
|
319
327
|
expect(screen.queryByTestId('cors-editor')).not.toBeInTheDocument();
|
|
320
328
|
});
|
|
321
329
|
});
|
|
@@ -441,6 +441,31 @@ describe('BucketLifecycleFormPage', ()=>{
|
|
|
441
441
|
});
|
|
442
442
|
});
|
|
443
443
|
describe('Rule Data Loading', ()=>{
|
|
444
|
+
it('loads rule with empty prefix filter as "All objects" (no filter)', async ()=>{
|
|
445
|
+
const rule = {
|
|
446
|
+
ID: 'no-filter-rule',
|
|
447
|
+
Status: 'Enabled',
|
|
448
|
+
Filter: {
|
|
449
|
+
Prefix: ''
|
|
450
|
+
},
|
|
451
|
+
Expiration: {
|
|
452
|
+
Days: 30
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
mockUseGetBucketLifecycle.mockReturnValue({
|
|
456
|
+
data: {
|
|
457
|
+
Rules: [
|
|
458
|
+
rule
|
|
459
|
+
]
|
|
460
|
+
},
|
|
461
|
+
status: 'success'
|
|
462
|
+
});
|
|
463
|
+
renderBucketLifecycleFormPage('test-bucket', 'no-filter-rule');
|
|
464
|
+
await waitFor(()=>{
|
|
465
|
+
expect(screen.getByText('All objects')).toBeInTheDocument();
|
|
466
|
+
});
|
|
467
|
+
expect(screen.queryByPlaceholderText('folder/')).not.toBeInTheDocument();
|
|
468
|
+
});
|
|
444
469
|
it('loads rule with prefix filter correctly', async ()=>{
|
|
445
470
|
const rule = {
|
|
446
471
|
ID: 'prefix-rule',
|
|
@@ -598,6 +623,112 @@ describe('BucketLifecycleFormPage', ()=>{
|
|
|
598
623
|
expect(transitionToggle).toBeChecked();
|
|
599
624
|
});
|
|
600
625
|
});
|
|
626
|
+
it('does not add extra transition rows when loading a rule with existing transitions', async ()=>{
|
|
627
|
+
const rule = {
|
|
628
|
+
ID: 'transition-rule',
|
|
629
|
+
Status: 'Enabled',
|
|
630
|
+
Filter: {},
|
|
631
|
+
Transitions: [
|
|
632
|
+
{
|
|
633
|
+
Days: 60,
|
|
634
|
+
StorageClass: 'STANDARD_IA'
|
|
635
|
+
}
|
|
636
|
+
]
|
|
637
|
+
};
|
|
638
|
+
mockUseGetBucketLifecycle.mockReturnValue({
|
|
639
|
+
data: {
|
|
640
|
+
Rules: [
|
|
641
|
+
rule
|
|
642
|
+
]
|
|
643
|
+
},
|
|
644
|
+
status: 'success'
|
|
645
|
+
});
|
|
646
|
+
renderBucketLifecycleFormPage('test-bucket', 'transition-rule');
|
|
647
|
+
await waitFor(()=>{
|
|
648
|
+
const transitionToggle = findToggleByLabel('Transition current version');
|
|
649
|
+
expect(transitionToggle).toBeChecked();
|
|
650
|
+
expect(screen.getByDisplayValue('60')).toBeInTheDocument();
|
|
651
|
+
});
|
|
652
|
+
expect(document.getElementById('transition-days-1')).not.toBeInTheDocument();
|
|
653
|
+
});
|
|
654
|
+
it('auto-adds a transition row when enabling transitions in edit mode on a rule without transitions', async ()=>{
|
|
655
|
+
const rule = {
|
|
656
|
+
ID: 'delete-marker-rule',
|
|
657
|
+
Status: 'Enabled',
|
|
658
|
+
Filter: {},
|
|
659
|
+
Expiration: {
|
|
660
|
+
ExpiredObjectDeleteMarker: true
|
|
661
|
+
}
|
|
662
|
+
};
|
|
663
|
+
mockUseGetBucketLifecycle.mockReturnValue({
|
|
664
|
+
data: {
|
|
665
|
+
Rules: [
|
|
666
|
+
rule
|
|
667
|
+
]
|
|
668
|
+
},
|
|
669
|
+
status: 'success'
|
|
670
|
+
});
|
|
671
|
+
renderBucketLifecycleFormPage('test-bucket', 'delete-marker-rule');
|
|
672
|
+
await waitFor(()=>{
|
|
673
|
+
expect(screen.getByText('Edit Lifecycle Rule')).toBeInTheDocument();
|
|
674
|
+
});
|
|
675
|
+
const transitionToggle = findToggleByLabel('Transition current version');
|
|
676
|
+
fireEvent.click(transitionToggle);
|
|
677
|
+
await waitFor(()=>{
|
|
678
|
+
expect(screen.getByText('Time Type')).toBeInTheDocument();
|
|
679
|
+
expect(screen.getByText('Storage Class')).toBeInTheDocument();
|
|
680
|
+
expect(screen.getByDisplayValue('30')).toBeInTheDocument();
|
|
681
|
+
});
|
|
682
|
+
});
|
|
683
|
+
it('auto-adds a noncurrent transition row when enabling noncurrent transitions in edit mode', async ()=>{
|
|
684
|
+
const rule = {
|
|
685
|
+
ID: 'expiration-only-rule',
|
|
686
|
+
Status: 'Enabled',
|
|
687
|
+
Filter: {},
|
|
688
|
+
Expiration: {
|
|
689
|
+
Days: 30
|
|
690
|
+
}
|
|
691
|
+
};
|
|
692
|
+
mockUseGetBucketLifecycle.mockReturnValue({
|
|
693
|
+
data: {
|
|
694
|
+
Rules: [
|
|
695
|
+
rule
|
|
696
|
+
]
|
|
697
|
+
},
|
|
698
|
+
status: 'success'
|
|
699
|
+
});
|
|
700
|
+
renderBucketLifecycleFormPage('test-bucket', 'expiration-only-rule');
|
|
701
|
+
await waitFor(()=>{
|
|
702
|
+
expect(screen.getByText('Edit Lifecycle Rule')).toBeInTheDocument();
|
|
703
|
+
});
|
|
704
|
+
const noncurrentToggle = findToggleByLabel('Transition noncurrent version');
|
|
705
|
+
fireEvent.click(noncurrentToggle);
|
|
706
|
+
await waitFor(()=>{
|
|
707
|
+
expect(screen.getByText('Noncurrent Days')).toBeInTheDocument();
|
|
708
|
+
expect(document.getElementById('noncurrent-transition-days-0')).toBeInTheDocument();
|
|
709
|
+
});
|
|
710
|
+
});
|
|
711
|
+
});
|
|
712
|
+
describe('Transition Auto-Add in Create Mode', ()=>{
|
|
713
|
+
it('auto-adds a transition row when enabling transitions', async ()=>{
|
|
714
|
+
renderBucketLifecycleFormPage();
|
|
715
|
+
const transitionToggle = findToggleByLabel('Transition current version');
|
|
716
|
+
fireEvent.click(transitionToggle);
|
|
717
|
+
await waitFor(()=>{
|
|
718
|
+
expect(screen.getByText('Time Type')).toBeInTheDocument();
|
|
719
|
+
expect(screen.getByText('Storage Class')).toBeInTheDocument();
|
|
720
|
+
expect(screen.getByDisplayValue('30')).toBeInTheDocument();
|
|
721
|
+
});
|
|
722
|
+
});
|
|
723
|
+
it('auto-adds a noncurrent transition row when enabling noncurrent transitions', async ()=>{
|
|
724
|
+
renderBucketLifecycleFormPage();
|
|
725
|
+
const noncurrentToggle = findToggleByLabel('Transition noncurrent version');
|
|
726
|
+
fireEvent.click(noncurrentToggle);
|
|
727
|
+
await waitFor(()=>{
|
|
728
|
+
expect(screen.getByText('Noncurrent Days')).toBeInTheDocument();
|
|
729
|
+
expect(document.getElementById('noncurrent-transition-days-0')).toBeInTheDocument();
|
|
730
|
+
});
|
|
731
|
+
});
|
|
601
732
|
});
|
|
602
733
|
describe('Navigation', ()=>{
|
|
603
734
|
it('navigates back to bucket lifecycle tab when cancel is clicked', ()=>{
|
|
@@ -5,6 +5,7 @@ import { MemoryRouter, Route, Routes } from "react-router";
|
|
|
5
5
|
import { useGetBucketNotification, useSetBucketNotification } from "../../hooks/index.js";
|
|
6
6
|
import { useSupportedNotificationEvents } from "../../hooks/useSupportedNotificationEvents.js";
|
|
7
7
|
import { createTestWrapper } from "../../test/testUtils.js";
|
|
8
|
+
import { EnhancedS3Error, ErrorCategory } from "../../utils/errorHandling.js";
|
|
8
9
|
import { BucketNotificationFormPage } from "../buckets/notifications/BucketNotificationFormPage.js";
|
|
9
10
|
jest.mock('../../hooks', ()=>({
|
|
10
11
|
useGetBucketNotification: jest.fn(),
|
|
@@ -235,14 +236,25 @@ describe('BucketNotificationFormPage', ()=>{
|
|
|
235
236
|
renderCreatePage();
|
|
236
237
|
expect(screen.getByText(/failed to fetch notification configuration/i)).toBeInTheDocument();
|
|
237
238
|
});
|
|
238
|
-
it('shows
|
|
239
|
+
it('shows permission message when notification data fails to load with 403 error', ()=>{
|
|
240
|
+
const authError = new EnhancedS3Error("You don't have permission to load the notification configuration. Contact your administrator.", 'AccessDenied', ErrorCategory.AUTHORIZATION, new Error('Access Denied'), 403);
|
|
239
241
|
mockUseGetBucketNotification.mockReturnValue({
|
|
240
242
|
data: void 0,
|
|
241
243
|
status: 'error',
|
|
242
|
-
error:
|
|
244
|
+
error: authError
|
|
243
245
|
});
|
|
244
246
|
renderCreatePage();
|
|
245
|
-
expect(screen.getByText(
|
|
247
|
+
expect(screen.getByText("You don't have permission to load the notification configuration. Contact your administrator.")).toBeInTheDocument();
|
|
248
|
+
});
|
|
249
|
+
it('shows error message from EnhancedS3Error', ()=>{
|
|
250
|
+
const error = new EnhancedS3Error('Something went wrong', 'InternalError', ErrorCategory.SERVER_ERROR, new Error('Something went wrong'), 500);
|
|
251
|
+
mockUseGetBucketNotification.mockReturnValue({
|
|
252
|
+
data: void 0,
|
|
253
|
+
status: 'error',
|
|
254
|
+
error
|
|
255
|
+
});
|
|
256
|
+
renderCreatePage();
|
|
257
|
+
expect(screen.getByText(/Something went wrong/i)).toBeInTheDocument();
|
|
246
258
|
});
|
|
247
259
|
});
|
|
248
260
|
describe('Edit Mode', ()=>{
|
|
@@ -102,7 +102,7 @@ const BucketCorsPage = ()=>{
|
|
|
102
102
|
onError: (error)=>{
|
|
103
103
|
setError('content', {
|
|
104
104
|
type: 'server',
|
|
105
|
-
message: error
|
|
105
|
+
message: error.message
|
|
106
106
|
});
|
|
107
107
|
}
|
|
108
108
|
});
|
|
@@ -123,7 +123,7 @@ const BucketCorsPage = ()=>{
|
|
|
123
123
|
onError: (error)=>{
|
|
124
124
|
setError('content', {
|
|
125
125
|
type: 'server',
|
|
126
|
-
message: error
|
|
126
|
+
message: error.message
|
|
127
127
|
});
|
|
128
128
|
}
|
|
129
129
|
});
|
|
@@ -163,12 +163,9 @@ const BucketCorsPage = ()=>{
|
|
|
163
163
|
size: "2x",
|
|
164
164
|
color: "statusWarning"
|
|
165
165
|
}),
|
|
166
|
-
/*#__PURE__*/
|
|
166
|
+
/*#__PURE__*/ jsx(Text, {
|
|
167
167
|
variant: "Large",
|
|
168
|
-
children:
|
|
169
|
-
"Failed to load CORS configuration: ",
|
|
170
|
-
corsError.message || 'Unknown error'
|
|
171
|
-
]
|
|
168
|
+
children: corsError.message
|
|
172
169
|
})
|
|
173
170
|
]
|
|
174
171
|
})
|
|
@@ -214,6 +211,7 @@ const BucketCorsPage = ()=>{
|
|
|
214
211
|
id: "corsConfiguration",
|
|
215
212
|
label: "CORS Rules",
|
|
216
213
|
direction: "vertical",
|
|
214
|
+
helpErrorPosition: "bottom",
|
|
217
215
|
error: errors.content?.message,
|
|
218
216
|
content: /*#__PURE__*/ jsxs(Stack, {
|
|
219
217
|
direction: "horizontal",
|
|
@@ -9,8 +9,8 @@ import { Controller, FormProvider, useFieldArray, useForm } from "react-hook-for
|
|
|
9
9
|
import { useParams } from "react-router";
|
|
10
10
|
import { useDataBrowserUICustomization } from "../../contexts/DataBrowserUICustomizationContext.js";
|
|
11
11
|
import { useGetBucketLifecycle, useSetBucketLifecycle } from "../../hooks/bucketConfiguration.js";
|
|
12
|
-
import { useISVBucketStatus } from "../../hooks/useISVBucketDetection.js";
|
|
13
12
|
import { useDataBrowserNavigate } from "../../hooks/useDataBrowserNavigate.js";
|
|
13
|
+
import { useISVBucketStatus } from "../../hooks/useISVBucketDetection.js";
|
|
14
14
|
import { AWS_RULE_LIMITS, STATUS_OPTIONS, buildS3Filter } from "../../utils/s3RuleUtils.js";
|
|
15
15
|
import { ArrayFieldActions } from "../ui/ArrayFieldActions.js";
|
|
16
16
|
import { FilterFormSection, createFilterValidationSchema } from "../ui/FilterFormSection.js";
|
|
@@ -209,7 +209,7 @@ const ruleToFormValues = (rule)=>{
|
|
|
209
209
|
key: tag.Key || '',
|
|
210
210
|
value: tag.Value || ''
|
|
211
211
|
})) || [];
|
|
212
|
-
} else if (void 0 !== rule.Filter.Prefix) {
|
|
212
|
+
} else if (void 0 !== rule.Filter.Prefix && '' !== rule.Filter.Prefix) {
|
|
213
213
|
formValues.filterType = 'prefix';
|
|
214
214
|
formValues.prefix = rule.Filter.Prefix;
|
|
215
215
|
} else if (rule.Filter.Tag) {
|
|
@@ -347,7 +347,8 @@ function BucketLifecycleFormPage() {
|
|
|
347
347
|
understandISVRisk: true
|
|
348
348
|
}
|
|
349
349
|
});
|
|
350
|
-
const { handleSubmit, register, control, watch, reset, formState: { isValid,
|
|
350
|
+
const { handleSubmit, register, control, watch, reset, formState: { isValid, dirtyFields, errors } } = methods;
|
|
351
|
+
const hasRuleChanges = Object.keys(dirtyFields).some((key)=>'understandISVRisk' !== key);
|
|
351
352
|
const { fields: transitionFields, append: appendTransition, remove: removeTransition } = useFieldArray({
|
|
352
353
|
control,
|
|
353
354
|
name: 'transitions'
|
|
@@ -390,54 +391,26 @@ function BucketLifecycleFormPage() {
|
|
|
390
391
|
useEffect(()=>{
|
|
391
392
|
if (isEditMode && existingRule) {
|
|
392
393
|
const formValues = ruleToFormValues(existingRule);
|
|
393
|
-
reset(
|
|
394
|
+
reset({
|
|
395
|
+
...formValues,
|
|
396
|
+
understandISVRisk: !isISVManaged
|
|
397
|
+
});
|
|
394
398
|
}
|
|
395
399
|
}, [
|
|
396
400
|
isEditMode,
|
|
397
401
|
existingRule,
|
|
398
|
-
reset
|
|
402
|
+
reset,
|
|
403
|
+
isISVManaged
|
|
399
404
|
]);
|
|
400
405
|
useEffect(()=>{
|
|
401
|
-
methods.setValue('understandISVRisk', !isISVManaged, {
|
|
406
|
+
if (!isEditMode) methods.setValue('understandISVRisk', !isISVManaged, {
|
|
402
407
|
shouldValidate: true
|
|
403
408
|
});
|
|
404
409
|
}, [
|
|
410
|
+
isEditMode,
|
|
405
411
|
isISVManaged,
|
|
406
412
|
methods
|
|
407
413
|
]);
|
|
408
|
-
const prevTransitionsEnabledRef = useRef(null);
|
|
409
|
-
const prevNoncurrentTransitionsEnabledRef = useRef(null);
|
|
410
|
-
useEffect(()=>{
|
|
411
|
-
const prevValue = prevTransitionsEnabledRef.current;
|
|
412
|
-
prevTransitionsEnabledRef.current = transitionsEnabled;
|
|
413
|
-
if (!isEditMode && null !== prevValue && !prevValue && transitionsEnabled && 0 === transitionFields.length) appendTransition({
|
|
414
|
-
timeType: 'days',
|
|
415
|
-
days: 30,
|
|
416
|
-
date: '',
|
|
417
|
-
storageClass: hasCustomSelector ? '' : 'STANDARD_IA'
|
|
418
|
-
});
|
|
419
|
-
}, [
|
|
420
|
-
isEditMode,
|
|
421
|
-
transitionsEnabled,
|
|
422
|
-
transitionFields.length,
|
|
423
|
-
appendTransition,
|
|
424
|
-
hasCustomSelector
|
|
425
|
-
]);
|
|
426
|
-
useEffect(()=>{
|
|
427
|
-
const prevValue = prevNoncurrentTransitionsEnabledRef.current;
|
|
428
|
-
prevNoncurrentTransitionsEnabledRef.current = noncurrentTransitionsEnabled;
|
|
429
|
-
if (!isEditMode && null !== prevValue && !prevValue && noncurrentTransitionsEnabled && 0 === noncurrentTransitionFields.length) appendNoncurrentTransition({
|
|
430
|
-
noncurrentDays: 30,
|
|
431
|
-
storageClass: hasCustomSelector ? '' : 'GLACIER',
|
|
432
|
-
newerNoncurrentVersions: 0
|
|
433
|
-
});
|
|
434
|
-
}, [
|
|
435
|
-
isEditMode,
|
|
436
|
-
noncurrentTransitionsEnabled,
|
|
437
|
-
noncurrentTransitionFields.length,
|
|
438
|
-
appendNoncurrentTransition,
|
|
439
|
-
hasCustomSelector
|
|
440
|
-
]);
|
|
441
414
|
const prevFilterTypeRef = useRef();
|
|
442
415
|
useEffect(()=>{
|
|
443
416
|
const prevFilterType = prevFilterTypeRef.current;
|
|
@@ -529,7 +502,7 @@ function BucketLifecycleFormPage() {
|
|
|
529
502
|
navigate(`/buckets/${bucketName}?tab=lifecycle`);
|
|
530
503
|
},
|
|
531
504
|
onError: (error)=>{
|
|
532
|
-
const errorMessage = error
|
|
505
|
+
const errorMessage = error.message;
|
|
533
506
|
showToast({
|
|
534
507
|
open: true,
|
|
535
508
|
message: errorMessage,
|
|
@@ -587,7 +560,7 @@ function BucketLifecycleFormPage() {
|
|
|
587
560
|
icon: isEditMode ? /*#__PURE__*/ jsx(Icon, {
|
|
588
561
|
name: "Save"
|
|
589
562
|
}) : void 0,
|
|
590
|
-
disabled: isEditMode ? !
|
|
563
|
+
disabled: isEditMode ? !hasRuleChanges || !isValid || isSaving : !isValid || isSaving
|
|
591
564
|
})
|
|
592
565
|
]
|
|
593
566
|
}),
|
|
@@ -693,7 +666,15 @@ function BucketLifecycleFormPage() {
|
|
|
693
666
|
control: control,
|
|
694
667
|
render: ({ field })=>/*#__PURE__*/ jsx(Toggle, {
|
|
695
668
|
toggle: field.value,
|
|
696
|
-
onChange:
|
|
669
|
+
onChange: (e)=>{
|
|
670
|
+
field.onChange(e);
|
|
671
|
+
if (e.target.checked && 0 === transitionFields.length) appendTransition({
|
|
672
|
+
timeType: 'days',
|
|
673
|
+
days: 30,
|
|
674
|
+
date: '',
|
|
675
|
+
storageClass: hasCustomSelector ? '' : 'STANDARD_IA'
|
|
676
|
+
});
|
|
677
|
+
},
|
|
697
678
|
label: field.value ? 'Enabled' : 'Disabled'
|
|
698
679
|
})
|
|
699
680
|
})
|
|
@@ -964,13 +945,20 @@ function BucketLifecycleFormPage() {
|
|
|
964
945
|
label: "Transition noncurrent version",
|
|
965
946
|
id: "noncurrentTransitionsEnabled",
|
|
966
947
|
direction: "horizontal",
|
|
967
|
-
labelHelpTooltip: noncurrentTransitionsHelpText ||
|
|
948
|
+
labelHelpTooltip: noncurrentTransitionsHelpText || 'Transition noncurrent object versions to a different storage class after a specified number of days',
|
|
968
949
|
content: /*#__PURE__*/ jsx(Controller, {
|
|
969
950
|
name: "noncurrentTransitionsEnabled",
|
|
970
951
|
control: control,
|
|
971
952
|
render: ({ field })=>/*#__PURE__*/ jsx(Toggle, {
|
|
972
953
|
toggle: field.value,
|
|
973
|
-
onChange:
|
|
954
|
+
onChange: (e)=>{
|
|
955
|
+
field.onChange(e);
|
|
956
|
+
if (e.target.checked && 0 === noncurrentTransitionFields.length) appendNoncurrentTransition({
|
|
957
|
+
noncurrentDays: 30,
|
|
958
|
+
storageClass: hasCustomSelector ? '' : 'GLACIER',
|
|
959
|
+
newerNoncurrentVersions: 0
|
|
960
|
+
});
|
|
961
|
+
},
|
|
974
962
|
label: field.value ? 'Enabled' : 'Disabled'
|
|
975
963
|
})
|
|
976
964
|
})
|
|
@@ -77,7 +77,8 @@ function BucketLifecycleList({ bucketName, lifecycleRules, lifecycleStatus, onCr
|
|
|
77
77
|
}),
|
|
78
78
|
cellStyle: {
|
|
79
79
|
flex: '1',
|
|
80
|
-
width: 'unset'
|
|
80
|
+
width: 'unset',
|
|
81
|
+
minWidth: 0
|
|
81
82
|
}
|
|
82
83
|
},
|
|
83
84
|
{
|
|
@@ -92,7 +93,8 @@ function BucketLifecycleList({ bucketName, lifecycleRules, lifecycleStatus, onCr
|
|
|
92
93
|
},
|
|
93
94
|
cellStyle: {
|
|
94
95
|
width: 'unset',
|
|
95
|
-
flex: '0.5'
|
|
96
|
+
flex: '0.5',
|
|
97
|
+
minWidth: 0
|
|
96
98
|
}
|
|
97
99
|
},
|
|
98
100
|
{
|
|
@@ -165,7 +167,8 @@ function BucketLifecycleList({ bucketName, lifecycleRules, lifecycleStatus, onCr
|
|
|
165
167
|
},
|
|
166
168
|
cellStyle: {
|
|
167
169
|
width: 'unset',
|
|
168
|
-
flex: '1.5'
|
|
170
|
+
flex: '1.5',
|
|
171
|
+
minWidth: 0
|
|
169
172
|
}
|
|
170
173
|
},
|
|
171
174
|
{
|
|
@@ -176,7 +179,8 @@ function BucketLifecycleList({ bucketName, lifecycleRules, lifecycleStatus, onCr
|
|
|
176
179
|
flex: '0.5',
|
|
177
180
|
textAlign: 'right',
|
|
178
181
|
paddingRight: spacing.r16,
|
|
179
|
-
width: 'unset'
|
|
182
|
+
width: 'unset',
|
|
183
|
+
minWidth: 0
|
|
180
184
|
},
|
|
181
185
|
Cell: ({ value })=>/*#__PURE__*/ jsxs(Box, {
|
|
182
186
|
display: "flex",
|
|
@@ -476,7 +476,7 @@ const PermissionsSection = /*#__PURE__*/ memo(({ onEditPolicy, onEditCors, owner
|
|
|
476
476
|
onError: (error)=>{
|
|
477
477
|
showToast({
|
|
478
478
|
open: true,
|
|
479
|
-
message: error
|
|
479
|
+
message: error.message,
|
|
480
480
|
status: 'error'
|
|
481
481
|
});
|
|
482
482
|
}
|
|
@@ -94,7 +94,7 @@ const BucketPolicyPage = ()=>{
|
|
|
94
94
|
onError: (error)=>{
|
|
95
95
|
setError('content', {
|
|
96
96
|
type: 'server',
|
|
97
|
-
message: error
|
|
97
|
+
message: error.message
|
|
98
98
|
});
|
|
99
99
|
}
|
|
100
100
|
});
|
|
@@ -114,7 +114,7 @@ const BucketPolicyPage = ()=>{
|
|
|
114
114
|
onError: (error)=>{
|
|
115
115
|
setError('content', {
|
|
116
116
|
type: 'server',
|
|
117
|
-
message: error
|
|
117
|
+
message: error.message
|
|
118
118
|
});
|
|
119
119
|
}
|
|
120
120
|
});
|
|
@@ -153,12 +153,9 @@ const BucketPolicyPage = ()=>{
|
|
|
153
153
|
size: "2x",
|
|
154
154
|
color: "statusWarning"
|
|
155
155
|
}),
|
|
156
|
-
/*#__PURE__*/
|
|
156
|
+
/*#__PURE__*/ jsx(Text, {
|
|
157
157
|
variant: "Large",
|
|
158
|
-
children:
|
|
159
|
-
"Failed to load bucket policy: ",
|
|
160
|
-
policyError.message || 'Unknown error'
|
|
161
|
-
]
|
|
158
|
+
children: policyError.message
|
|
162
159
|
})
|
|
163
160
|
]
|
|
164
161
|
})
|
|
@@ -450,7 +450,8 @@ function BucketReplicationFormPage() {
|
|
|
450
450
|
understandISVRisk: true
|
|
451
451
|
}
|
|
452
452
|
});
|
|
453
|
-
const { handleSubmit, register, control, watch, reset, formState: { isValid, isDirty, errors } } = methods;
|
|
453
|
+
const { handleSubmit, register, control, watch, reset, formState: { isValid, isDirty, dirtyFields, errors } } = methods;
|
|
454
|
+
const hasRuleChanges = Object.keys(dirtyFields).some((key)=>'understandISVRisk' !== key);
|
|
454
455
|
const { fields: tagFields, append: appendTag, remove: removeTag } = useFieldArray({
|
|
455
456
|
control,
|
|
456
457
|
name: 'tags'
|
|
@@ -491,7 +492,10 @@ function BucketReplicationFormPage() {
|
|
|
491
492
|
if (isEditMode && existingRule) {
|
|
492
493
|
if (loadedRuleIdRef.current !== existingRule.ID) {
|
|
493
494
|
const formValues = ruleToFormValues(existingRule, existingRole);
|
|
494
|
-
reset(
|
|
495
|
+
reset({
|
|
496
|
+
...formValues,
|
|
497
|
+
understandISVRisk: !isISVManaged
|
|
498
|
+
});
|
|
495
499
|
loadedRuleIdRef.current = existingRule.ID || null;
|
|
496
500
|
}
|
|
497
501
|
} else if (!isEditMode && !isDirty) {
|
|
@@ -509,7 +513,8 @@ function BucketReplicationFormPage() {
|
|
|
509
513
|
replicationRoleDefault,
|
|
510
514
|
nextAvailablePriority,
|
|
511
515
|
isDirty,
|
|
512
|
-
reset
|
|
516
|
+
reset,
|
|
517
|
+
isISVManaged
|
|
513
518
|
]);
|
|
514
519
|
const prevFilterTypeRef = useRef();
|
|
515
520
|
useEffect(()=>{
|
|
@@ -564,10 +569,11 @@ function BucketReplicationFormPage() {
|
|
|
564
569
|
methods
|
|
565
570
|
]);
|
|
566
571
|
useEffect(()=>{
|
|
567
|
-
methods.setValue('understandISVRisk', !isISVManaged, {
|
|
572
|
+
if (!isEditMode) methods.setValue('understandISVRisk', !isISVManaged, {
|
|
568
573
|
shouldValidate: true
|
|
569
574
|
});
|
|
570
575
|
}, [
|
|
576
|
+
isEditMode,
|
|
571
577
|
isISVManaged,
|
|
572
578
|
methods
|
|
573
579
|
]);
|
|
@@ -601,7 +607,7 @@ function BucketReplicationFormPage() {
|
|
|
601
607
|
navigate(`/buckets/${bucketName}?tab=replication`);
|
|
602
608
|
},
|
|
603
609
|
onError: (error)=>{
|
|
604
|
-
const errorMessage = error
|
|
610
|
+
const errorMessage = error.message;
|
|
605
611
|
showToast({
|
|
606
612
|
open: true,
|
|
607
613
|
message: errorMessage,
|
|
@@ -660,7 +666,7 @@ function BucketReplicationFormPage() {
|
|
|
660
666
|
icon: isEditMode ? /*#__PURE__*/ jsx(Icon, {
|
|
661
667
|
name: "Save"
|
|
662
668
|
}) : void 0,
|
|
663
|
-
disabled: !
|
|
669
|
+
disabled: isEditMode ? !hasRuleChanges || !isValid || isSaving : !isValid || isSaving
|
|
664
670
|
})
|
|
665
671
|
]
|
|
666
672
|
}),
|
|
@@ -19,7 +19,8 @@ function BucketReplicationList({ bucketName, replicationRules, replicationRole,
|
|
|
19
19
|
}),
|
|
20
20
|
cellStyle: {
|
|
21
21
|
flex: '1',
|
|
22
|
-
width: 'unset'
|
|
22
|
+
width: 'unset',
|
|
23
|
+
minWidth: 0
|
|
23
24
|
}
|
|
24
25
|
},
|
|
25
26
|
{
|
|
@@ -34,7 +35,8 @@ function BucketReplicationList({ bucketName, replicationRules, replicationRole,
|
|
|
34
35
|
},
|
|
35
36
|
cellStyle: {
|
|
36
37
|
width: 'unset',
|
|
37
|
-
flex: '0.
|
|
38
|
+
flex: '0.6',
|
|
39
|
+
minWidth: 0
|
|
38
40
|
}
|
|
39
41
|
},
|
|
40
42
|
{
|
|
@@ -46,9 +48,8 @@ function BucketReplicationList({ bucketName, replicationRules, replicationRole,
|
|
|
46
48
|
}),
|
|
47
49
|
cellStyle: {
|
|
48
50
|
width: 'unset',
|
|
49
|
-
flex: '0.
|
|
50
|
-
|
|
51
|
-
paddingRight: spacing.r16
|
|
51
|
+
flex: '0.8',
|
|
52
|
+
minWidth: 0
|
|
52
53
|
}
|
|
53
54
|
},
|
|
54
55
|
{
|
|
@@ -84,7 +85,8 @@ function BucketReplicationList({ bucketName, replicationRules, replicationRole,
|
|
|
84
85
|
},
|
|
85
86
|
cellStyle: {
|
|
86
87
|
width: 'unset',
|
|
87
|
-
flex: '1.
|
|
88
|
+
flex: '1.2',
|
|
89
|
+
minWidth: 0
|
|
88
90
|
}
|
|
89
91
|
},
|
|
90
92
|
{
|
|
@@ -92,10 +94,11 @@ function BucketReplicationList({ bucketName, replicationRules, replicationRole,
|
|
|
92
94
|
accessor: 'ID',
|
|
93
95
|
id: 'operations',
|
|
94
96
|
cellStyle: {
|
|
95
|
-
flex: '0.
|
|
97
|
+
flex: '0.8',
|
|
98
|
+
width: 'unset',
|
|
99
|
+
minWidth: 0,
|
|
96
100
|
textAlign: 'right',
|
|
97
|
-
paddingRight: spacing.r16
|
|
98
|
-
width: 'unset'
|
|
101
|
+
paddingRight: spacing.r16
|
|
99
102
|
},
|
|
100
103
|
Cell: ({ value })=>/*#__PURE__*/ jsxs(Box, {
|
|
101
104
|
display: "flex",
|
|
@@ -157,7 +157,7 @@ function BucketNotificationFormPage() {
|
|
|
157
157
|
navigate(`/buckets/${bucketName}?tab=notification`);
|
|
158
158
|
},
|
|
159
159
|
onError: (error)=>{
|
|
160
|
-
const errorMessage = error
|
|
160
|
+
const errorMessage = error.message;
|
|
161
161
|
showToast({
|
|
162
162
|
open: true,
|
|
163
163
|
message: errorMessage,
|
|
@@ -181,7 +181,7 @@ function BucketNotificationFormPage() {
|
|
|
181
181
|
})
|
|
182
182
|
});
|
|
183
183
|
if ('error' === notificationStatus && notificationError) {
|
|
184
|
-
const errorMessage = notificationError
|
|
184
|
+
const errorMessage = notificationError.message;
|
|
185
185
|
return /*#__PURE__*/ jsx(Form, {
|
|
186
186
|
layout: {
|
|
187
187
|
kind: 'page',
|
|
@@ -45,7 +45,7 @@ function BucketNotificationList({ bucketName, notificationRules, notificationSta
|
|
|
45
45
|
});
|
|
46
46
|
},
|
|
47
47
|
onError: (error)=>{
|
|
48
|
-
const errorMessage = error
|
|
48
|
+
const errorMessage = error.message;
|
|
49
49
|
showToast({
|
|
50
50
|
open: true,
|
|
51
51
|
message: errorMessage,
|
|
@@ -110,7 +110,7 @@ const DeleteObjectButton = ({ objects, bucketName, onDeleteSuccess })=>{
|
|
|
110
110
|
} catch (error) {
|
|
111
111
|
showToast({
|
|
112
112
|
open: true,
|
|
113
|
-
message: error instanceof Error ? error.message : '
|
|
113
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
114
114
|
status: 'error'
|
|
115
115
|
});
|
|
116
116
|
} finally{
|