@scality/data-browser-library 1.0.0-preview.7 → 1.0.0-preview.9
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__/BucketCreate.test.d.ts +1 -0
- package/dist/components/__tests__/BucketCreate.test.js +408 -0
- package/dist/components/__tests__/BucketLifecycleFormPage.test.d.ts +1 -0
- package/dist/components/__tests__/BucketLifecycleFormPage.test.js +618 -0
- package/dist/components/__tests__/BucketLifecycleList.test.d.ts +1 -0
- package/dist/components/__tests__/BucketLifecycleList.test.js +325 -0
- package/dist/components/__tests__/BucketList.test.js +190 -0
- package/dist/components/__tests__/BucketOverview.test.js +298 -8
- package/dist/components/__tests__/BucketReplicationFormPage.test.d.ts +1 -0
- package/dist/components/__tests__/BucketReplicationFormPage.test.js +1757 -0
- package/dist/components/__tests__/BucketReplicationList.test.d.ts +1 -0
- package/dist/components/__tests__/BucketReplicationList.test.js +344 -0
- package/dist/components/__tests__/DeleteBucketConfigRuleButton.test.d.ts +1 -0
- package/dist/components/__tests__/DeleteBucketConfigRuleButton.test.js +196 -0
- package/dist/components/__tests__/EmptyBucketButton.test.d.ts +1 -0
- package/dist/components/__tests__/EmptyBucketButton.test.js +302 -0
- package/dist/components/buckets/BucketCreate.d.ts +49 -0
- package/dist/components/buckets/BucketCreate.js +237 -0
- package/dist/components/buckets/BucketDetails.js +62 -10
- package/dist/components/buckets/BucketLifecycleFormPage.d.ts +15 -0
- package/dist/components/buckets/BucketLifecycleFormPage.js +1070 -0
- package/dist/components/buckets/BucketLifecycleList.d.ts +10 -0
- package/dist/components/buckets/BucketLifecycleList.js +270 -0
- package/dist/components/buckets/BucketList.d.ts +5 -2
- package/dist/components/buckets/BucketList.js +38 -28
- package/dist/components/buckets/BucketOverview.d.ts +65 -4
- package/dist/components/buckets/BucketOverview.js +261 -179
- package/dist/components/buckets/BucketPage.js +1 -1
- package/dist/components/buckets/BucketReplicationFormPage.d.ts +1 -0
- package/dist/components/buckets/BucketReplicationFormPage.js +834 -0
- package/dist/components/buckets/BucketReplicationList.d.ts +11 -0
- package/dist/components/buckets/BucketReplicationList.js +189 -0
- package/dist/components/buckets/DeleteBucketConfigRuleButton.d.ts +18 -0
- package/dist/components/buckets/DeleteBucketConfigRuleButton.js +53 -0
- package/dist/components/buckets/EmptyBucketButton.d.ts +5 -0
- package/dist/components/buckets/EmptyBucketButton.js +232 -0
- package/dist/components/buckets/EmptyBucketSummary.d.ts +9 -0
- package/dist/components/buckets/EmptyBucketSummary.js +60 -0
- package/dist/components/buckets/EmptyBucketSummaryList.d.ts +13 -0
- package/dist/components/buckets/EmptyBucketSummaryList.js +140 -0
- package/dist/components/buckets/notifications/BucketNotificationCreatePage.js +8 -8
- package/dist/components/index.d.ts +8 -1
- package/dist/components/index.js +9 -2
- package/dist/components/objects/ObjectLock/EditRetentionButton.d.ts +4 -0
- package/dist/components/objects/ObjectLock/EditRetentionButton.js +32 -0
- package/dist/components/objects/ObjectLock/ObjectLockRetentionSettings.d.ts +3 -0
- package/dist/components/objects/ObjectLock/ObjectLockRetentionSettings.js +211 -0
- package/dist/components/objects/ObjectLock/ObjectLockSettings.d.ts +9 -0
- package/dist/components/objects/ObjectLock/ObjectLockSettings.js +158 -0
- package/dist/components/objects/ObjectLock/ObjectLockSettingsUtils.d.ts +8 -0
- package/dist/components/objects/ObjectLock/ObjectLockSettingsUtils.js +39 -0
- package/dist/components/objects/ObjectLock/__tests__/EditRetentionButton.test.d.ts +1 -0
- package/dist/components/objects/ObjectLock/__tests__/EditRetentionButton.test.js +204 -0
- package/dist/components/objects/ObjectLock/__tests__/ObjectLockSettings.test.d.ts +1 -0
- package/dist/components/objects/ObjectLock/__tests__/ObjectLockSettings.test.js +374 -0
- package/dist/components/ui/ArrayFieldActions.d.ts +36 -0
- package/dist/components/ui/ArrayFieldActions.js +38 -0
- package/dist/components/ui/ConfirmDeleteRuleModal.d.ts +16 -0
- package/dist/components/ui/ConfirmDeleteRuleModal.js +43 -0
- package/dist/components/ui/FilterFormSection.d.ts +44 -0
- package/dist/components/ui/FilterFormSection.js +159 -0
- package/dist/config/factory.d.ts +13 -2
- package/dist/config/factory.js +9 -6
- package/dist/hooks/__tests__/useISVBucketDetection.test.d.ts +1 -0
- package/dist/hooks/__tests__/useISVBucketDetection.test.js +188 -0
- package/dist/hooks/factories/__tests__/useCreateS3QueryHook.test.js +44 -1
- package/dist/hooks/factories/useCreateS3QueryHook.js +22 -1
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/index.js +5 -1
- package/dist/hooks/useDeleteBucketConfigRule.d.ts +26 -0
- package/dist/hooks/useDeleteBucketConfigRule.js +46 -0
- package/dist/hooks/useEmptyBucket.d.ts +27 -0
- package/dist/hooks/useEmptyBucket.js +116 -0
- package/dist/hooks/useISVBucketDetection.d.ts +15 -0
- package/dist/hooks/useISVBucketDetection.js +27 -0
- package/dist/hooks/useTableRowSelection.d.ts +9 -0
- package/dist/hooks/useTableRowSelection.js +45 -0
- package/dist/test/setup.js +8 -0
- package/dist/test/testUtils.d.ts +99 -17
- package/dist/test/testUtils.js +64 -16
- package/dist/test/utils/errorHandling.test.js +39 -1
- package/dist/utils/constants.d.ts +12 -0
- package/dist/utils/constants.js +9 -0
- package/dist/utils/errorHandling.d.ts +9 -0
- package/dist/utils/errorHandling.js +6 -1
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/s3RuleUtils.d.ts +53 -0
- package/dist/utils/s3RuleUtils.js +101 -0
- package/package.json +1 -1
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { BasicText, Icon, IconHelp, Stack, Text } from "@scality/core-ui";
|
|
3
|
+
import { Table } from "@scality/core-ui/dist/components/tablev2/Tablev2.component";
|
|
4
|
+
import { useMemo } from "react";
|
|
5
|
+
const getUniqueErrorMessages = (errorMessages)=>{
|
|
6
|
+
const uniqueArray = errorMessages.reduce((acc, message)=>{
|
|
7
|
+
const existingItem = acc.find((item)=>item.message === message);
|
|
8
|
+
if (existingItem) existingItem.errorNumbers++;
|
|
9
|
+
else acc.push({
|
|
10
|
+
message,
|
|
11
|
+
errorNumbers: 1
|
|
12
|
+
});
|
|
13
|
+
return acc;
|
|
14
|
+
}, []);
|
|
15
|
+
return uniqueArray;
|
|
16
|
+
};
|
|
17
|
+
const ErrorsTable = ({ messages })=>{
|
|
18
|
+
const messagesColumns = [
|
|
19
|
+
{
|
|
20
|
+
Header: "Error Message",
|
|
21
|
+
accessor: "message",
|
|
22
|
+
cellStyle: {
|
|
23
|
+
minWidth: "8rem"
|
|
24
|
+
},
|
|
25
|
+
Cell ({ value }) {
|
|
26
|
+
return /*#__PURE__*/ jsx(Text, {
|
|
27
|
+
children: value
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
Header: "Number of errors",
|
|
33
|
+
accessor: "errorNumbers",
|
|
34
|
+
cellStyle: {
|
|
35
|
+
minWidth: "8rem"
|
|
36
|
+
},
|
|
37
|
+
Cell ({ value }) {
|
|
38
|
+
return /*#__PURE__*/ jsx(Text, {
|
|
39
|
+
children: value
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
];
|
|
44
|
+
const list = getUniqueErrorMessages(messages);
|
|
45
|
+
const TABLE_HEIGHT = 5 * list.length;
|
|
46
|
+
return /*#__PURE__*/ jsx(IconHelp, {
|
|
47
|
+
placement: "top",
|
|
48
|
+
overlayStyle: {
|
|
49
|
+
width: "30rem"
|
|
50
|
+
},
|
|
51
|
+
tooltipMessage: /*#__PURE__*/ jsx("div", {
|
|
52
|
+
style: {
|
|
53
|
+
height: `${TABLE_HEIGHT}rem`
|
|
54
|
+
},
|
|
55
|
+
children: /*#__PURE__*/ jsx(Table, {
|
|
56
|
+
columns: messagesColumns,
|
|
57
|
+
data: list,
|
|
58
|
+
children: /*#__PURE__*/ jsx(Table.SingleSelectableContent, {
|
|
59
|
+
rowHeight: "h32",
|
|
60
|
+
separationLineVariant: "backgroundLevel3"
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
})
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
const SummaryCell = (value, isFailed = false, withIcon = false, messages)=>{
|
|
67
|
+
const text = 1 === value ? "1 object" : `${value} objects`;
|
|
68
|
+
if (withIcon) return /*#__PURE__*/ jsxs(Stack, {
|
|
69
|
+
children: [
|
|
70
|
+
/*#__PURE__*/ jsx(Icon, {
|
|
71
|
+
name: isFailed ? "Exclamation-circle" : "Check-circle",
|
|
72
|
+
color: isFailed ? "statusCritical" : "statusHealthy"
|
|
73
|
+
}),
|
|
74
|
+
/*#__PURE__*/ jsx(BasicText, {
|
|
75
|
+
children: text
|
|
76
|
+
}),
|
|
77
|
+
messages?.length ? /*#__PURE__*/ jsx(ErrorsTable, {
|
|
78
|
+
messages: messages
|
|
79
|
+
}) : null
|
|
80
|
+
]
|
|
81
|
+
});
|
|
82
|
+
return /*#__PURE__*/ jsx(BasicText, {
|
|
83
|
+
children: text
|
|
84
|
+
});
|
|
85
|
+
};
|
|
86
|
+
const useCreateDeleteSummaryColumns = ()=>useMemo(()=>[
|
|
87
|
+
{
|
|
88
|
+
Header: "Total attempts",
|
|
89
|
+
accessor: "attempts",
|
|
90
|
+
cellStyle: {
|
|
91
|
+
minWidth: "12rem"
|
|
92
|
+
},
|
|
93
|
+
Cell ({ value }) {
|
|
94
|
+
return SummaryCell(value);
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
Header: "Successfully deleted",
|
|
99
|
+
accessor: "deleted",
|
|
100
|
+
cellStyle: {
|
|
101
|
+
minWidth: "12rem"
|
|
102
|
+
},
|
|
103
|
+
Cell ({ value }) {
|
|
104
|
+
return SummaryCell(value, false, true);
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
Header: "Deletion failed",
|
|
109
|
+
accessor: "errors",
|
|
110
|
+
cellStyle: {
|
|
111
|
+
minWidth: "12rem"
|
|
112
|
+
},
|
|
113
|
+
Cell ({ value }) {
|
|
114
|
+
return SummaryCell(value.nbErrors, true, true, value.messages);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
], []);
|
|
118
|
+
const EmptyBucketSummaryList = ({ summaryData })=>{
|
|
119
|
+
const summaryColumns = useCreateDeleteSummaryColumns();
|
|
120
|
+
return /*#__PURE__*/ jsx("div", {
|
|
121
|
+
style: {
|
|
122
|
+
height: "15rem"
|
|
123
|
+
},
|
|
124
|
+
children: /*#__PURE__*/ jsx(Table, {
|
|
125
|
+
columns: summaryColumns,
|
|
126
|
+
data: summaryData,
|
|
127
|
+
children: /*#__PURE__*/ jsx("div", {
|
|
128
|
+
style: {
|
|
129
|
+
height: "10rem",
|
|
130
|
+
paddingBottom: "5rem"
|
|
131
|
+
},
|
|
132
|
+
children: /*#__PURE__*/ jsx(Table.SingleSelectableContent, {
|
|
133
|
+
rowHeight: "h40",
|
|
134
|
+
separationLineVariant: "backgroundLevel1"
|
|
135
|
+
})
|
|
136
|
+
})
|
|
137
|
+
})
|
|
138
|
+
});
|
|
139
|
+
};
|
|
140
|
+
export { EmptyBucketSummaryList };
|
|
@@ -3,25 +3,25 @@ import { joiResolver } from "@hookform/resolvers/joi";
|
|
|
3
3
|
import { Form, FormGroup, FormSection, Loader, Stack, Text, useToast } from "@scality/core-ui";
|
|
4
4
|
import { convertRemToPixels } from "@scality/core-ui/dist/components/tablev2/TableUtils";
|
|
5
5
|
import { Button, Input } from "@scality/core-ui/dist/next";
|
|
6
|
-
import
|
|
6
|
+
import joi from "joi";
|
|
7
7
|
import { useCallback } from "react";
|
|
8
8
|
import { FormProvider, useForm } from "react-hook-form";
|
|
9
9
|
import { useNavigate, useParams } from "react-router-dom";
|
|
10
10
|
import { useGetBucketNotification, useSetBucketNotification } from "../../../hooks/index.js";
|
|
11
11
|
import { EventsSection } from "./EventsSection.js";
|
|
12
|
-
const schema = object({
|
|
13
|
-
ruleName: string().required().messages({
|
|
12
|
+
const schema = joi.object({
|
|
13
|
+
ruleName: joi.string().required().messages({
|
|
14
14
|
"string.empty": "This field is required"
|
|
15
15
|
}),
|
|
16
|
-
queueArn: string().required().pattern(/^arn:aws:sqs:[a-z0-9-]+:\d+:.+$/).messages({
|
|
16
|
+
queueArn: joi.string().required().pattern(/^arn:aws:sqs:[a-z0-9-]+:\d+:.+$/).messages({
|
|
17
17
|
"string.empty": "This field is required",
|
|
18
18
|
"string.pattern.base": "Must be a valid ARN (e.g., arn:aws:sqs:region:account-id:queue-name)"
|
|
19
19
|
}),
|
|
20
|
-
events: array().min(1).required().messages({
|
|
20
|
+
events: joi.array().min(1).required().messages({
|
|
21
21
|
"array.min": "At least one event must be selected"
|
|
22
22
|
}),
|
|
23
|
-
prefix: string().allow("").optional(),
|
|
24
|
-
suffix: string().allow("").optional()
|
|
23
|
+
prefix: joi.string().allow("").optional(),
|
|
24
|
+
suffix: joi.string().allow("").optional()
|
|
25
25
|
});
|
|
26
26
|
function BucketNotificationCreatePage() {
|
|
27
27
|
const { bucketName } = useParams();
|
|
@@ -32,7 +32,7 @@ function BucketNotificationCreatePage() {
|
|
|
32
32
|
});
|
|
33
33
|
const existingRuleNames = existingNotificationData?.QueueConfigurations?.map((config)=>config.Id) || [];
|
|
34
34
|
const dynamicSchema = schema.keys({
|
|
35
|
-
ruleName: string().required().invalid(...existingRuleNames).messages({
|
|
35
|
+
ruleName: joi.string().required().invalid(...existingRuleNames).messages({
|
|
36
36
|
"string.empty": "This field is required",
|
|
37
37
|
"any.invalid": "A rule with this name already exists"
|
|
38
38
|
})
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
export { DeleteBucketButton } from "./buckets/DeleteBucketButton";
|
|
2
2
|
export { BucketList } from "./buckets/BucketList";
|
|
3
|
-
export { BucketOverview } from "./buckets/BucketOverview";
|
|
3
|
+
export { BucketOverview, BucketOverviewSection, BucketOverviewField, } from "./buckets/BucketOverview";
|
|
4
4
|
export { BucketPage } from "./buckets/BucketPage";
|
|
5
5
|
export { BucketPolicyPage } from "./buckets/BucketPolicyPage";
|
|
6
|
+
export { BucketLifecycleFormPage } from "./buckets/BucketLifecycleFormPage";
|
|
7
|
+
export { BucketReplicationFormPage } from "./buckets/BucketReplicationFormPage";
|
|
6
8
|
export { BucketNotificationCreatePage } from "./buckets/notifications/BucketNotificationCreatePage";
|
|
9
|
+
export { EmptyBucketButton } from "./buckets/EmptyBucketButton";
|
|
10
|
+
export { BucketCreate, baseBucketCreateSchema, bucketNameValidationSchema, bucketErrorMessage, type BucketCreateFormData, } from "./buckets/BucketCreate";
|
|
7
11
|
export { UploadButton } from "./objects/UploadButton";
|
|
8
12
|
export { CreateFolderButton } from "./objects/CreateFolderButton";
|
|
9
13
|
export { ObjectDetails } from "./objects/ObjectDetails";
|
|
10
14
|
export { ObjectList } from "./objects/ObjectList";
|
|
11
15
|
export { ObjectPage } from "./objects/ObjectPage";
|
|
16
|
+
export { ObjectLockSettings } from "./objects/ObjectLock/ObjectLockSettings";
|
|
17
|
+
export { EditRetentionButton } from "./objects/ObjectLock/EditRetentionButton";
|
|
12
18
|
export { MetadataSearch } from "./search/MetadataSearch";
|
|
19
|
+
export { ArrayFieldActions } from "./ui/ArrayFieldActions";
|
|
13
20
|
export { DataBrowserProvider, useDataBrowserContext, useDataBrowserTheme, } from "./providers/DataBrowserProvider";
|
package/dist/components/index.js
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
import { DeleteBucketButton } from "./buckets/DeleteBucketButton.js";
|
|
2
2
|
import { BucketList } from "./buckets/BucketList.js";
|
|
3
|
-
import { BucketOverview } from "./buckets/BucketOverview.js";
|
|
3
|
+
import { BucketOverview, BucketOverviewField, BucketOverviewSection } from "./buckets/BucketOverview.js";
|
|
4
4
|
import { BucketPage } from "./buckets/BucketPage.js";
|
|
5
5
|
import { BucketPolicyPage } from "./buckets/BucketPolicyPage.js";
|
|
6
|
+
import { BucketLifecycleFormPage } from "./buckets/BucketLifecycleFormPage.js";
|
|
7
|
+
import { BucketReplicationFormPage } from "./buckets/BucketReplicationFormPage.js";
|
|
6
8
|
import { BucketNotificationCreatePage } from "./buckets/notifications/BucketNotificationCreatePage.js";
|
|
9
|
+
import { EmptyBucketButton } from "./buckets/EmptyBucketButton.js";
|
|
10
|
+
import { BucketCreate, baseBucketCreateSchema, bucketErrorMessage, bucketNameValidationSchema } from "./buckets/BucketCreate.js";
|
|
7
11
|
import { UploadButton } from "./objects/UploadButton.js";
|
|
8
12
|
import { CreateFolderButton } from "./objects/CreateFolderButton.js";
|
|
9
13
|
import { ObjectDetails } from "./objects/ObjectDetails/index.js";
|
|
10
14
|
import { ObjectList } from "./objects/ObjectList.js";
|
|
11
15
|
import { ObjectPage } from "./objects/ObjectPage.js";
|
|
16
|
+
import { ObjectLockSettings } from "./objects/ObjectLock/ObjectLockSettings.js";
|
|
17
|
+
import { EditRetentionButton } from "./objects/ObjectLock/EditRetentionButton.js";
|
|
12
18
|
import { MetadataSearch } from "./search/MetadataSearch.js";
|
|
19
|
+
import { ArrayFieldActions } from "./ui/ArrayFieldActions.js";
|
|
13
20
|
import { DataBrowserProvider, useDataBrowserContext, useDataBrowserTheme } from "./providers/DataBrowserProvider.js";
|
|
14
|
-
export { BucketList, BucketNotificationCreatePage, BucketOverview, BucketPage, BucketPolicyPage, CreateFolderButton, DataBrowserProvider, DeleteBucketButton, MetadataSearch, ObjectDetails, ObjectList, ObjectPage, UploadButton, useDataBrowserContext, useDataBrowserTheme };
|
|
21
|
+
export { ArrayFieldActions, BucketCreate, BucketLifecycleFormPage, BucketList, BucketNotificationCreatePage, BucketOverview, BucketOverviewField, BucketOverviewSection, BucketPage, BucketPolicyPage, BucketReplicationFormPage, CreateFolderButton, DataBrowserProvider, DeleteBucketButton, EditRetentionButton, EmptyBucketButton, MetadataSearch, ObjectDetails, ObjectList, ObjectLockSettings, ObjectPage, UploadButton, baseBucketCreateSchema, bucketErrorMessage, bucketNameValidationSchema, useDataBrowserContext, useDataBrowserTheme };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useISVBucketStatus } from "../../../hooks/index.js";
|
|
3
|
+
import { Icon } from "@scality/core-ui";
|
|
4
|
+
import { Button } from "@scality/core-ui/dist/next";
|
|
5
|
+
import { useNavigate } from "react-router-dom";
|
|
6
|
+
const EditRetentionButton = ({ bucketName })=>{
|
|
7
|
+
const navigate = useNavigate();
|
|
8
|
+
const { isVeeamBucket, isCommvaultBucket, isISVManaged, isLoading } = useISVBucketStatus(bucketName);
|
|
9
|
+
const tooltipOverlay = isCommvaultBucket ? "Edition is disabled as it is managed by Commvault." : isVeeamBucket ? "Edition is disabled as it is managed by Veeam." : void 0;
|
|
10
|
+
return /*#__PURE__*/ jsx(Button, {
|
|
11
|
+
id: "edit-retention-btn",
|
|
12
|
+
variant: "outline",
|
|
13
|
+
label: "Edit",
|
|
14
|
+
"aria-label": "Edit default retention",
|
|
15
|
+
icon: /*#__PURE__*/ jsx(Icon, {
|
|
16
|
+
name: "Pencil"
|
|
17
|
+
}),
|
|
18
|
+
type: "button",
|
|
19
|
+
onClick: ()=>{
|
|
20
|
+
navigate(`/buckets/${bucketName}/objects/object-lock-settings`);
|
|
21
|
+
},
|
|
22
|
+
disabled: isISVManaged,
|
|
23
|
+
...tooltipOverlay && {
|
|
24
|
+
tooltip: {
|
|
25
|
+
overlay: tooltipOverlay
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
isLoading: isLoading
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
const ObjectLock_EditRetentionButton = EditRetentionButton;
|
|
32
|
+
export { EditRetentionButton, ObjectLock_EditRetentionButton as default };
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Checkbox, FormGroup, FormSection, Stack, Text } from "@scality/core-ui";
|
|
3
|
+
import { convertRemToPixels } from "@scality/core-ui/dist/components/tablev2/TableUtils";
|
|
4
|
+
import { Controller, useFormContext } from "react-hook-form";
|
|
5
|
+
import { Input, Select } from "@scality/core-ui/dist/next";
|
|
6
|
+
function ObjectLockRetentionSettings({ isEditRetentionSettings = false }) {
|
|
7
|
+
const { control, register, watch, formState: { errors }, setValue } = useFormContext();
|
|
8
|
+
const isDefaultRetentionEnabled = watch("isDefaultRetentionEnabled");
|
|
9
|
+
const isObjectLockEnabled = watch("isObjectLockEnabled");
|
|
10
|
+
const matchVersioning = (checked)=>{
|
|
11
|
+
if (checked) setValue("isVersioning", true);
|
|
12
|
+
};
|
|
13
|
+
return /*#__PURE__*/ jsxs(FormSection, {
|
|
14
|
+
title: isEditRetentionSettings ? void 0 : {
|
|
15
|
+
name: "Object-lock"
|
|
16
|
+
},
|
|
17
|
+
forceLabelWidth: convertRemToPixels(17.5),
|
|
18
|
+
children: [
|
|
19
|
+
/*#__PURE__*/ jsx(FormGroup, {
|
|
20
|
+
id: "isObjectLockEnabled",
|
|
21
|
+
label: "Object-lock",
|
|
22
|
+
content: /*#__PURE__*/ jsx(Checkbox, {
|
|
23
|
+
id: "isObjectLockEnabled",
|
|
24
|
+
label: isObjectLockEnabled ? "Enabled" : "Disabled",
|
|
25
|
+
disabled: isEditRetentionSettings && isObjectLockEnabled,
|
|
26
|
+
...register("isObjectLockEnabled", {
|
|
27
|
+
onChange (e) {
|
|
28
|
+
matchVersioning(e.target.checked);
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
}),
|
|
32
|
+
labelHelpTooltip: /*#__PURE__*/ jsxs("ul", {
|
|
33
|
+
children: [
|
|
34
|
+
/*#__PURE__*/ jsx("li", {
|
|
35
|
+
children: "Permanently allows objects in this bucket to be locked"
|
|
36
|
+
}),
|
|
37
|
+
/*#__PURE__*/ jsx("li", {
|
|
38
|
+
children: "Object-lock option cannot be removed after bucket creation, but you will be able to disable the retention itself on edition."
|
|
39
|
+
}),
|
|
40
|
+
/*#__PURE__*/ jsx("li", {
|
|
41
|
+
children: "Once the bucket is created, you might be blocked from deleting the objects and the bucket."
|
|
42
|
+
}),
|
|
43
|
+
/*#__PURE__*/ jsx("li", {
|
|
44
|
+
children: "Enabling Object-lock automatically activates Versioning for the bucket, and you won’t be able to suspend Versioning."
|
|
45
|
+
})
|
|
46
|
+
]
|
|
47
|
+
}),
|
|
48
|
+
helpErrorPosition: "bottom",
|
|
49
|
+
disabled: isEditRetentionSettings
|
|
50
|
+
}),
|
|
51
|
+
isObjectLockEnabled && /*#__PURE__*/ jsxs(Fragment, {
|
|
52
|
+
children: [
|
|
53
|
+
/*#__PURE__*/ jsx(FormGroup, {
|
|
54
|
+
id: "isDefaultRetentionEnabled",
|
|
55
|
+
label: "Default Retention",
|
|
56
|
+
helpErrorPosition: "bottom",
|
|
57
|
+
labelHelpTooltip: isEditRetentionSettings ? /*#__PURE__*/ jsxs("ul", {
|
|
58
|
+
children: [
|
|
59
|
+
/*#__PURE__*/ jsx("li", {
|
|
60
|
+
children: "These settings apply only to new objects placed into the bucket without any specific object-lock parameters."
|
|
61
|
+
}),
|
|
62
|
+
/*#__PURE__*/ jsx("li", {
|
|
63
|
+
children: "Automatically protect objects put into this bucket from being deleted or overwritten."
|
|
64
|
+
}),
|
|
65
|
+
/*#__PURE__*/ jsx("li", {
|
|
66
|
+
children: "If objects are uploaded into the bucket with their own Retention settings, these will override the Default Retention setting placed on the bucket."
|
|
67
|
+
})
|
|
68
|
+
]
|
|
69
|
+
}) : /*#__PURE__*/ jsxs("ul", {
|
|
70
|
+
children: [
|
|
71
|
+
/*#__PURE__*/ jsx("li", {
|
|
72
|
+
children: "Automatically protect objects put into this bucket from being deleted or overwritten."
|
|
73
|
+
}),
|
|
74
|
+
/*#__PURE__*/ jsx("li", {
|
|
75
|
+
children: "These settings apply only to new objects placed into the bucket without any specific object-lock parameters."
|
|
76
|
+
}),
|
|
77
|
+
/*#__PURE__*/ jsx("li", {
|
|
78
|
+
children: "You can activate this option after the bucket creation."
|
|
79
|
+
}),
|
|
80
|
+
/*#__PURE__*/ jsx("li", {
|
|
81
|
+
children: "If objects are uploaded into the bucket with their own Retention settings, these will override the Default Retention setting placed on the bucket."
|
|
82
|
+
})
|
|
83
|
+
]
|
|
84
|
+
}),
|
|
85
|
+
content: /*#__PURE__*/ jsx(Checkbox, {
|
|
86
|
+
id: "isDefaultRetentionEnabled",
|
|
87
|
+
label: isDefaultRetentionEnabled ? "Active" : "Inactive",
|
|
88
|
+
...register("isDefaultRetentionEnabled")
|
|
89
|
+
})
|
|
90
|
+
}),
|
|
91
|
+
/*#__PURE__*/ jsx(FormGroup, {
|
|
92
|
+
id: "objectlockMode",
|
|
93
|
+
label: "Retention mode",
|
|
94
|
+
direction: "vertical",
|
|
95
|
+
disabled: !isDefaultRetentionEnabled,
|
|
96
|
+
helpErrorPosition: "bottom",
|
|
97
|
+
content: /*#__PURE__*/ jsx("div", {
|
|
98
|
+
style: {
|
|
99
|
+
opacity: isDefaultRetentionEnabled ? 1 : 0.5
|
|
100
|
+
},
|
|
101
|
+
children: /*#__PURE__*/ jsxs(Stack, {
|
|
102
|
+
direction: "vertical",
|
|
103
|
+
children: [
|
|
104
|
+
/*#__PURE__*/ jsxs(Stack, {
|
|
105
|
+
direction: "vertical",
|
|
106
|
+
children: [
|
|
107
|
+
/*#__PURE__*/ jsxs(Stack, {
|
|
108
|
+
children: [
|
|
109
|
+
/*#__PURE__*/ jsx("input", {
|
|
110
|
+
id: "locktype-governance",
|
|
111
|
+
type: "radio",
|
|
112
|
+
value: "GOVERNANCE",
|
|
113
|
+
disabled: !isDefaultRetentionEnabled,
|
|
114
|
+
...register("retentionMode")
|
|
115
|
+
}),
|
|
116
|
+
/*#__PURE__*/ jsx("label", {
|
|
117
|
+
htmlFor: "locktype-governance",
|
|
118
|
+
children: "Governance"
|
|
119
|
+
})
|
|
120
|
+
]
|
|
121
|
+
}),
|
|
122
|
+
/*#__PURE__*/ jsx(Text, {
|
|
123
|
+
color: "textSecondary",
|
|
124
|
+
isEmphazed: true,
|
|
125
|
+
variant: "Smaller",
|
|
126
|
+
children: "A user with a specific IAM permissions can overwrite/delete protected object versions during the retention period."
|
|
127
|
+
})
|
|
128
|
+
]
|
|
129
|
+
}),
|
|
130
|
+
/*#__PURE__*/ jsxs(Stack, {
|
|
131
|
+
children: [
|
|
132
|
+
/*#__PURE__*/ jsx("input", {
|
|
133
|
+
id: "locktype-compliance",
|
|
134
|
+
type: "radio",
|
|
135
|
+
value: "COMPLIANCE",
|
|
136
|
+
disabled: !isDefaultRetentionEnabled,
|
|
137
|
+
...register("retentionMode")
|
|
138
|
+
}),
|
|
139
|
+
/*#__PURE__*/ jsx("label", {
|
|
140
|
+
htmlFor: "locktype-compliance",
|
|
141
|
+
children: "Compliance"
|
|
142
|
+
})
|
|
143
|
+
]
|
|
144
|
+
}),
|
|
145
|
+
/*#__PURE__*/ jsx(Text, {
|
|
146
|
+
color: "textSecondary",
|
|
147
|
+
isEmphazed: true,
|
|
148
|
+
variant: "Smaller",
|
|
149
|
+
children: "No one can overwrite protected object versions during the retention period."
|
|
150
|
+
})
|
|
151
|
+
]
|
|
152
|
+
})
|
|
153
|
+
})
|
|
154
|
+
}),
|
|
155
|
+
/*#__PURE__*/ jsx(FormGroup, {
|
|
156
|
+
id: "retentionPeriod",
|
|
157
|
+
label: "Retention period",
|
|
158
|
+
direction: "horizontal",
|
|
159
|
+
helpErrorPosition: "bottom",
|
|
160
|
+
help: "Must be a positive whole number.",
|
|
161
|
+
error: errors.retentionPeriod?.message,
|
|
162
|
+
disabled: !isDefaultRetentionEnabled,
|
|
163
|
+
content: /*#__PURE__*/ jsxs(Stack, {
|
|
164
|
+
direction: "horizontal",
|
|
165
|
+
children: [
|
|
166
|
+
/*#__PURE__*/ jsx(Controller, {
|
|
167
|
+
control: control,
|
|
168
|
+
name: "retentionPeriod",
|
|
169
|
+
render: ({ field: { onChange, value: retentionPeriod } })=>/*#__PURE__*/ jsx(Input, {
|
|
170
|
+
id: "retentionPeriod",
|
|
171
|
+
name: "retentionPeriod",
|
|
172
|
+
value: retentionPeriod,
|
|
173
|
+
onChange: (e)=>onChange(e.target.valueAsNumber),
|
|
174
|
+
type: "number",
|
|
175
|
+
step: "1",
|
|
176
|
+
min: "1",
|
|
177
|
+
size: "2/3"
|
|
178
|
+
})
|
|
179
|
+
}),
|
|
180
|
+
/*#__PURE__*/ jsx(Controller, {
|
|
181
|
+
control: control,
|
|
182
|
+
name: "retentionPeriodFrequencyChoice",
|
|
183
|
+
defaultValue: "DAYS",
|
|
184
|
+
render: ({ field: { onChange, value: retentionPeriodFrequencyChoice } })=>/*#__PURE__*/ jsxs(Select, {
|
|
185
|
+
id: "retentionPeriodFrequencyChoice",
|
|
186
|
+
onChange: onChange,
|
|
187
|
+
placeholder: "retentionPeriodFrequencyChoice",
|
|
188
|
+
value: retentionPeriodFrequencyChoice,
|
|
189
|
+
disabled: !isDefaultRetentionEnabled,
|
|
190
|
+
size: "1/3",
|
|
191
|
+
children: [
|
|
192
|
+
/*#__PURE__*/ jsx(Select.Option, {
|
|
193
|
+
value: "DAYS",
|
|
194
|
+
children: "Days"
|
|
195
|
+
}),
|
|
196
|
+
/*#__PURE__*/ jsx(Select.Option, {
|
|
197
|
+
value: "YEARS",
|
|
198
|
+
children: "Years"
|
|
199
|
+
})
|
|
200
|
+
]
|
|
201
|
+
})
|
|
202
|
+
})
|
|
203
|
+
]
|
|
204
|
+
})
|
|
205
|
+
})
|
|
206
|
+
]
|
|
207
|
+
})
|
|
208
|
+
]
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
export { ObjectLockRetentionSettings as default };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import Joi from "joi";
|
|
2
|
+
export declare const objectLockRetentionSettingsValidationRules: {
|
|
3
|
+
isObjectLockEnabled: Joi.BooleanSchema<boolean>;
|
|
4
|
+
isDefaultRetentionEnabled: Joi.BooleanSchema<boolean>;
|
|
5
|
+
retentionMode: Joi.AlternativesSchema<any>;
|
|
6
|
+
retentionPeriod: Joi.AlternativesSchema<any>;
|
|
7
|
+
retentionPeriodFrequencyChoice: Joi.AlternativesSchema<any>;
|
|
8
|
+
};
|
|
9
|
+
export declare function ObjectLockSettings(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef } from "react";
|
|
3
|
+
import { useNavigate, useParams } from "react-router-dom";
|
|
4
|
+
import { FormProvider, useForm } from "react-hook-form";
|
|
5
|
+
import { joiResolver } from "@hookform/resolvers/joi";
|
|
6
|
+
import joi from "joi";
|
|
7
|
+
import { Form, Icon, Loader, Stack, Text, useToast } from "@scality/core-ui";
|
|
8
|
+
import { Button } from "@scality/core-ui/dist/next";
|
|
9
|
+
import { useGetBucketObjectLockConfiguration, useSetBucketObjectLockConfiguration } from "../../../hooks/index.js";
|
|
10
|
+
import ObjectLockRetentionSettings from "./ObjectLockRetentionSettings.js";
|
|
11
|
+
const objectLockRetentionSettingsValidationRules = {
|
|
12
|
+
isObjectLockEnabled: joi.boolean(),
|
|
13
|
+
isDefaultRetentionEnabled: joi.boolean().default(false),
|
|
14
|
+
retentionMode: joi.when("isDefaultRetentionEnabled", {
|
|
15
|
+
is: joi.equal(true),
|
|
16
|
+
then: joi.string().valid("GOVERNANCE", "COMPLIANCE").required(),
|
|
17
|
+
otherwise: joi.any()
|
|
18
|
+
}),
|
|
19
|
+
retentionPeriod: joi.when("isDefaultRetentionEnabled", {
|
|
20
|
+
is: joi.equal(true),
|
|
21
|
+
then: joi.number().integer().min(1).required(),
|
|
22
|
+
otherwise: joi.any()
|
|
23
|
+
}),
|
|
24
|
+
retentionPeriodFrequencyChoice: joi.when("isDefaultRetentionEnabled", {
|
|
25
|
+
is: joi.equal(true),
|
|
26
|
+
then: joi.string().valid("DAYS", "YEARS").required(),
|
|
27
|
+
otherwise: joi.any()
|
|
28
|
+
})
|
|
29
|
+
};
|
|
30
|
+
const schema = joi.object(objectLockRetentionSettingsValidationRules);
|
|
31
|
+
function ObjectLockSettings() {
|
|
32
|
+
const { bucketName } = useParams();
|
|
33
|
+
const navigate = useNavigate();
|
|
34
|
+
const { showToast } = useToast();
|
|
35
|
+
const { data: objectLockData, status: objectLockStatus } = useGetBucketObjectLockConfiguration({
|
|
36
|
+
Bucket: bucketName
|
|
37
|
+
});
|
|
38
|
+
const setBucketObjectLockMutation = useSetBucketObjectLockConfiguration();
|
|
39
|
+
const isObjectLockEnabled = objectLockData?.ObjectLockConfiguration?.ObjectLockEnabled === "Enabled";
|
|
40
|
+
const defaultRetention = objectLockData?.ObjectLockConfiguration?.Rule?.DefaultRetention;
|
|
41
|
+
const useFormMethods = useForm({
|
|
42
|
+
mode: "all",
|
|
43
|
+
resolver: joiResolver(schema),
|
|
44
|
+
defaultValues: {
|
|
45
|
+
isObjectLockEnabled: isObjectLockEnabled,
|
|
46
|
+
isDefaultRetentionEnabled: !!defaultRetention,
|
|
47
|
+
retentionMode: defaultRetention?.Mode || "GOVERNANCE",
|
|
48
|
+
retentionPeriod: defaultRetention?.Days || defaultRetention?.Years || 1,
|
|
49
|
+
retentionPeriodFrequencyChoice: defaultRetention ? defaultRetention?.Days ? "DAYS" : "YEARS" : "DAYS"
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
const { watch, setValue, handleSubmit, formState: { isValid } } = useFormMethods;
|
|
53
|
+
const isObjectLockEnabledValue = watch("isObjectLockEnabled");
|
|
54
|
+
const isFormInitialized = useRef(false);
|
|
55
|
+
useEffect(()=>{
|
|
56
|
+
if ("success" === objectLockStatus && objectLockData && !isFormInitialized.current) {
|
|
57
|
+
const isEnabled = objectLockData.ObjectLockConfiguration?.ObjectLockEnabled === "Enabled";
|
|
58
|
+
const defaultRet = objectLockData.ObjectLockConfiguration?.Rule?.DefaultRetention;
|
|
59
|
+
setValue("isObjectLockEnabled", isEnabled);
|
|
60
|
+
setValue("isDefaultRetentionEnabled", !!defaultRet);
|
|
61
|
+
if (defaultRet) {
|
|
62
|
+
setValue("retentionMode", defaultRet.Mode);
|
|
63
|
+
setValue("retentionPeriod", defaultRet.Days || defaultRet.Years || 1);
|
|
64
|
+
setValue("retentionPeriodFrequencyChoice", defaultRet.Days ? "DAYS" : "YEARS");
|
|
65
|
+
}
|
|
66
|
+
isFormInitialized.current = true;
|
|
67
|
+
}
|
|
68
|
+
}, [
|
|
69
|
+
objectLockData,
|
|
70
|
+
objectLockStatus,
|
|
71
|
+
setValue
|
|
72
|
+
]);
|
|
73
|
+
const handleCancel = ()=>{
|
|
74
|
+
navigate(`/buckets/${bucketName}`);
|
|
75
|
+
};
|
|
76
|
+
const onSubmit = (data)=>{
|
|
77
|
+
setBucketObjectLockMutation.mutate({
|
|
78
|
+
Bucket: bucketName,
|
|
79
|
+
ObjectLockConfiguration: data.isObjectLockEnabled ? {
|
|
80
|
+
ObjectLockEnabled: "Enabled",
|
|
81
|
+
...data.isDefaultRetentionEnabled && {
|
|
82
|
+
Rule: {
|
|
83
|
+
DefaultRetention: {
|
|
84
|
+
Mode: data.retentionMode,
|
|
85
|
+
..."DAYS" === data.retentionPeriodFrequencyChoice ? {
|
|
86
|
+
Days: data.retentionPeriod
|
|
87
|
+
} : {
|
|
88
|
+
Years: data.retentionPeriod
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
} : void 0
|
|
94
|
+
}, {
|
|
95
|
+
onSuccess: ()=>{
|
|
96
|
+
showToast({
|
|
97
|
+
open: true,
|
|
98
|
+
message: "Object Lock settings saved successfully",
|
|
99
|
+
status: "success"
|
|
100
|
+
});
|
|
101
|
+
navigate(`/buckets/${bucketName}`);
|
|
102
|
+
},
|
|
103
|
+
onError: (error)=>{
|
|
104
|
+
const errorMessage = error instanceof Error ? error.message : "Failed to save Object Lock settings";
|
|
105
|
+
showToast({
|
|
106
|
+
open: true,
|
|
107
|
+
message: errorMessage,
|
|
108
|
+
status: "error"
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
if ("pending" === objectLockStatus) return /*#__PURE__*/ jsx(Loader, {
|
|
114
|
+
centered: true,
|
|
115
|
+
children: /*#__PURE__*/ jsx(Text, {
|
|
116
|
+
children: "Loading retention settings..."
|
|
117
|
+
})
|
|
118
|
+
});
|
|
119
|
+
return /*#__PURE__*/ jsx(FormProvider, {
|
|
120
|
+
...useFormMethods,
|
|
121
|
+
children: /*#__PURE__*/ jsx(Form, {
|
|
122
|
+
onSubmit: handleSubmit(onSubmit),
|
|
123
|
+
requireMode: "partial",
|
|
124
|
+
layout: {
|
|
125
|
+
kind: "page",
|
|
126
|
+
title: "Object-lock settings"
|
|
127
|
+
},
|
|
128
|
+
rightActions: /*#__PURE__*/ jsxs(Stack, {
|
|
129
|
+
gap: "r16",
|
|
130
|
+
children: [
|
|
131
|
+
/*#__PURE__*/ jsx(Button, {
|
|
132
|
+
id: "cancel-btn",
|
|
133
|
+
variant: "outline",
|
|
134
|
+
onClick: handleCancel,
|
|
135
|
+
type: "button",
|
|
136
|
+
label: "Cancel",
|
|
137
|
+
disabled: setBucketObjectLockMutation.isPending
|
|
138
|
+
}),
|
|
139
|
+
/*#__PURE__*/ jsx(Button, {
|
|
140
|
+
disabled: !isValid || !isObjectLockEnabledValue || setBucketObjectLockMutation.isPending,
|
|
141
|
+
id: "edit-retention-setting-btn",
|
|
142
|
+
type: "submit",
|
|
143
|
+
variant: "primary",
|
|
144
|
+
label: "Save",
|
|
145
|
+
icon: /*#__PURE__*/ jsx(Icon, {
|
|
146
|
+
name: "Save"
|
|
147
|
+
}),
|
|
148
|
+
isLoading: setBucketObjectLockMutation.isPending
|
|
149
|
+
})
|
|
150
|
+
]
|
|
151
|
+
}),
|
|
152
|
+
children: /*#__PURE__*/ jsx(ObjectLockRetentionSettings, {
|
|
153
|
+
isEditRetentionSettings: true
|
|
154
|
+
})
|
|
155
|
+
})
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
export { ObjectLockSettings, objectLockRetentionSettingsValidationRules };
|