@scality/data-browser-library 1.1.9 → 1.1.10

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.
@@ -598,6 +598,112 @@ describe('BucketLifecycleFormPage', ()=>{
598
598
  expect(transitionToggle).toBeChecked();
599
599
  });
600
600
  });
601
+ it('does not add extra transition rows when loading a rule with existing transitions', async ()=>{
602
+ const rule = {
603
+ ID: 'transition-rule',
604
+ Status: 'Enabled',
605
+ Filter: {},
606
+ Transitions: [
607
+ {
608
+ Days: 60,
609
+ StorageClass: 'STANDARD_IA'
610
+ }
611
+ ]
612
+ };
613
+ mockUseGetBucketLifecycle.mockReturnValue({
614
+ data: {
615
+ Rules: [
616
+ rule
617
+ ]
618
+ },
619
+ status: 'success'
620
+ });
621
+ renderBucketLifecycleFormPage('test-bucket', 'transition-rule');
622
+ await waitFor(()=>{
623
+ const transitionToggle = findToggleByLabel('Transition current version');
624
+ expect(transitionToggle).toBeChecked();
625
+ expect(screen.getByDisplayValue('60')).toBeInTheDocument();
626
+ });
627
+ expect(document.getElementById('transition-days-1')).not.toBeInTheDocument();
628
+ });
629
+ it('auto-adds a transition row when enabling transitions in edit mode on a rule without transitions', async ()=>{
630
+ const rule = {
631
+ ID: 'delete-marker-rule',
632
+ Status: 'Enabled',
633
+ Filter: {},
634
+ Expiration: {
635
+ ExpiredObjectDeleteMarker: true
636
+ }
637
+ };
638
+ mockUseGetBucketLifecycle.mockReturnValue({
639
+ data: {
640
+ Rules: [
641
+ rule
642
+ ]
643
+ },
644
+ status: 'success'
645
+ });
646
+ renderBucketLifecycleFormPage('test-bucket', 'delete-marker-rule');
647
+ await waitFor(()=>{
648
+ expect(screen.getByText('Edit Lifecycle Rule')).toBeInTheDocument();
649
+ });
650
+ const transitionToggle = findToggleByLabel('Transition current version');
651
+ fireEvent.click(transitionToggle);
652
+ await waitFor(()=>{
653
+ expect(screen.getByText('Time Type')).toBeInTheDocument();
654
+ expect(screen.getByText('Storage Class')).toBeInTheDocument();
655
+ expect(screen.getByDisplayValue('30')).toBeInTheDocument();
656
+ });
657
+ });
658
+ it('auto-adds a noncurrent transition row when enabling noncurrent transitions in edit mode', async ()=>{
659
+ const rule = {
660
+ ID: 'expiration-only-rule',
661
+ Status: 'Enabled',
662
+ Filter: {},
663
+ Expiration: {
664
+ Days: 30
665
+ }
666
+ };
667
+ mockUseGetBucketLifecycle.mockReturnValue({
668
+ data: {
669
+ Rules: [
670
+ rule
671
+ ]
672
+ },
673
+ status: 'success'
674
+ });
675
+ renderBucketLifecycleFormPage('test-bucket', 'expiration-only-rule');
676
+ await waitFor(()=>{
677
+ expect(screen.getByText('Edit Lifecycle Rule')).toBeInTheDocument();
678
+ });
679
+ const noncurrentToggle = findToggleByLabel('Transition noncurrent version');
680
+ fireEvent.click(noncurrentToggle);
681
+ await waitFor(()=>{
682
+ expect(screen.getByText('Noncurrent Days')).toBeInTheDocument();
683
+ expect(document.getElementById('noncurrent-transition-days-0')).toBeInTheDocument();
684
+ });
685
+ });
686
+ });
687
+ describe('Transition Auto-Add in Create Mode', ()=>{
688
+ it('auto-adds a transition row when enabling transitions', async ()=>{
689
+ renderBucketLifecycleFormPage();
690
+ const transitionToggle = findToggleByLabel('Transition current version');
691
+ fireEvent.click(transitionToggle);
692
+ await waitFor(()=>{
693
+ expect(screen.getByText('Time Type')).toBeInTheDocument();
694
+ expect(screen.getByText('Storage Class')).toBeInTheDocument();
695
+ expect(screen.getByDisplayValue('30')).toBeInTheDocument();
696
+ });
697
+ });
698
+ it('auto-adds a noncurrent transition row when enabling noncurrent transitions', async ()=>{
699
+ renderBucketLifecycleFormPage();
700
+ const noncurrentToggle = findToggleByLabel('Transition noncurrent version');
701
+ fireEvent.click(noncurrentToggle);
702
+ await waitFor(()=>{
703
+ expect(screen.getByText('Noncurrent Days')).toBeInTheDocument();
704
+ expect(document.getElementById('noncurrent-transition-days-0')).toBeInTheDocument();
705
+ });
706
+ });
601
707
  });
602
708
  describe('Navigation', ()=>{
603
709
  it('navigates back to bucket lifecycle tab when cancel is clicked', ()=>{
@@ -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";
@@ -405,39 +405,6 @@ function BucketLifecycleFormPage() {
405
405
  isISVManaged,
406
406
  methods
407
407
  ]);
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
408
  const prevFilterTypeRef = useRef();
442
409
  useEffect(()=>{
443
410
  const prevFilterType = prevFilterTypeRef.current;
@@ -693,7 +660,15 @@ function BucketLifecycleFormPage() {
693
660
  control: control,
694
661
  render: ({ field })=>/*#__PURE__*/ jsx(Toggle, {
695
662
  toggle: field.value,
696
- onChange: field.onChange,
663
+ onChange: (e)=>{
664
+ field.onChange(e);
665
+ if (e.target.checked && 0 === transitionFields.length) appendTransition({
666
+ timeType: 'days',
667
+ days: 30,
668
+ date: '',
669
+ storageClass: hasCustomSelector ? '' : 'STANDARD_IA'
670
+ });
671
+ },
697
672
  label: field.value ? 'Enabled' : 'Disabled'
698
673
  })
699
674
  })
@@ -964,13 +939,20 @@ function BucketLifecycleFormPage() {
964
939
  label: "Transition noncurrent version",
965
940
  id: "noncurrentTransitionsEnabled",
966
941
  direction: "horizontal",
967
- labelHelpTooltip: noncurrentTransitionsHelpText || "Transition noncurrent object versions to a different storage class after a specified number of days",
942
+ labelHelpTooltip: noncurrentTransitionsHelpText || 'Transition noncurrent object versions to a different storage class after a specified number of days',
968
943
  content: /*#__PURE__*/ jsx(Controller, {
969
944
  name: "noncurrentTransitionsEnabled",
970
945
  control: control,
971
946
  render: ({ field })=>/*#__PURE__*/ jsx(Toggle, {
972
947
  toggle: field.value,
973
- onChange: field.onChange,
948
+ onChange: (e)=>{
949
+ field.onChange(e);
950
+ if (e.target.checked && 0 === noncurrentTransitionFields.length) appendNoncurrentTransition({
951
+ noncurrentDays: 30,
952
+ storageClass: hasCustomSelector ? '' : 'GLACIER',
953
+ newerNoncurrentVersions: 0
954
+ });
955
+ },
974
956
  label: field.value ? 'Enabled' : 'Disabled'
975
957
  })
976
958
  })
@@ -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",
@@ -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.5'
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.5',
50
- textAlign: 'right',
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.5'
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.5',
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",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scality/data-browser-library",
3
- "version": "1.1.9",
3
+ "version": "1.1.10",
4
4
  "description": "A modular React component library for browsing S3 buckets and objects",
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.ts",
@@ -61,7 +61,7 @@
61
61
  "jest": "^30.0.5",
62
62
  "jest-environment-jsdom": "^30.0.5",
63
63
  "msw": "^2.12.3",
64
- "ts-jest": "^29.4.1"
64
+ "ts-jest": "^29.4.6"
65
65
  },
66
66
  "repository": {
67
67
  "type": "git",