@scality/data-browser-library 1.0.4 → 1.0.6
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/DataBrowserUI.js +18 -8
- package/dist/components/__tests__/BucketCreate.test.js +60 -20
- package/dist/components/__tests__/BucketList.test.js +91 -6
- package/dist/components/__tests__/BucketNotificationFormPage.test.js +54 -19
- package/dist/components/__tests__/BucketReplicationFormPage.test.js +183 -61
- package/dist/components/__tests__/MetadataSearch.test.js +18 -12
- package/dist/components/__tests__/ObjectList.test.js +94 -2
- package/dist/components/buckets/BucketCreate.d.ts +1 -0
- package/dist/components/buckets/BucketCreate.js +57 -7
- package/dist/components/buckets/BucketDetails.js +0 -1
- package/dist/components/buckets/BucketLifecycleFormPage.js +209 -213
- package/dist/components/buckets/BucketList.js +25 -4
- package/dist/components/buckets/BucketReplicationFormPage.js +9 -3
- package/dist/components/buckets/DeleteBucketConfigRuleButton.js +1 -1
- package/dist/components/buckets/notifications/BucketNotificationList.js +1 -1
- package/dist/components/objects/DeleteObjectButton.d.ts +1 -0
- package/dist/components/objects/DeleteObjectButton.js +11 -5
- package/dist/components/objects/ObjectDetails/FormComponents.d.ts +9 -0
- package/dist/components/objects/ObjectDetails/FormComponents.js +37 -0
- package/dist/components/objects/ObjectDetails/ObjectMetadata.js +182 -204
- package/dist/components/objects/ObjectDetails/ObjectSummary.js +22 -5
- package/dist/components/objects/ObjectDetails/ObjectTags.js +109 -154
- package/dist/components/objects/ObjectDetails/__tests__/ObjectDetails.test.js +3 -3
- package/dist/components/objects/ObjectDetails/__tests__/ObjectMetadata.test.d.ts +1 -0
- package/dist/components/objects/ObjectDetails/__tests__/ObjectMetadata.test.js +230 -0
- package/dist/components/objects/ObjectDetails/__tests__/ObjectTags.test.d.ts +1 -0
- package/dist/components/objects/ObjectDetails/__tests__/ObjectTags.test.js +342 -0
- package/dist/components/objects/ObjectDetails/__tests__/formUtils.test.d.ts +1 -0
- package/dist/components/objects/ObjectDetails/__tests__/formUtils.test.js +202 -0
- package/dist/components/objects/ObjectDetails/index.d.ts +2 -1
- package/dist/components/objects/ObjectDetails/index.js +12 -16
- package/dist/components/objects/ObjectList.d.ts +3 -2
- package/dist/components/objects/ObjectList.js +204 -104
- package/dist/components/objects/ObjectLock/__tests__/ObjectLockSettings.test.js +78 -26
- package/dist/components/objects/ObjectPage.js +22 -5
- package/dist/components/ui/ArrayFieldActions.js +0 -2
- package/dist/components/ui/FilterFormSection.js +17 -36
- package/dist/components/ui/FormGrid.d.ts +7 -0
- package/dist/components/ui/FormGrid.js +37 -0
- package/dist/components/ui/Table.elements.js +1 -0
- package/dist/config/__tests__/factory.test.js +29 -1
- package/dist/config/factory.d.ts +2 -0
- package/dist/config/factory.js +3 -1
- package/dist/config/types.d.ts +45 -2
- package/dist/hooks/__tests__/usePresigningS3Client.test.d.ts +1 -0
- package/dist/hooks/__tests__/usePresigningS3Client.test.js +104 -0
- package/dist/hooks/factories/index.d.ts +1 -1
- package/dist/hooks/factories/index.js +2 -2
- package/dist/hooks/factories/useCreateS3MutationHook.d.ts +2 -1
- package/dist/hooks/factories/useCreateS3MutationHook.js +10 -3
- package/dist/hooks/factories/useCreateS3QueryHook.d.ts +1 -0
- package/dist/hooks/factories/useCreateS3QueryHook.js +9 -6
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.js +2 -1
- package/dist/hooks/presignedOperations.js +4 -4
- package/dist/hooks/useBucketLocations.d.ts +6 -0
- package/dist/hooks/useBucketLocations.js +45 -0
- package/dist/hooks/usePresigningS3Client.d.ts +13 -0
- package/dist/hooks/usePresigningS3Client.js +21 -0
- package/package.json +4 -3
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { ConstrainedText, FormattedDateTime, Icon, Link, PrettyBytes, Text, Toggle, Wrap, spacing, useToast } from "@scality/core-ui";
|
|
2
|
+
import { ConstrainedText, FormattedDateTime, Icon, Link, PrettyBytes, SearchInput, Text, Toggle, Wrap, spacing, useToast } from "@scality/core-ui";
|
|
3
3
|
import { Box, Table } from "@scality/core-ui/dist/next";
|
|
4
4
|
import { Fragment, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
5
|
+
import { useLocation, useNavigate } from "react-router";
|
|
6
|
+
import styled_components from "styled-components";
|
|
5
7
|
import { useDataBrowserUICustomization } from "../../contexts/DataBrowserUICustomizationContext.js";
|
|
6
8
|
import { useSearchObjects, useSearchObjectsVersions } from "../../hooks/index.js";
|
|
7
9
|
import { useGetPresignedDownload } from "../../hooks/presignedOperations.js";
|
|
@@ -13,6 +15,19 @@ import MetadataSearch from "../search/MetadataSearch.js";
|
|
|
13
15
|
import CreateFolderButton from "./CreateFolderButton.js";
|
|
14
16
|
import DeleteObjectButton from "./DeleteObjectButton.js";
|
|
15
17
|
import UploadButton from "./UploadButton.js";
|
|
18
|
+
const TableWithAlignedRows = styled_components.div`
|
|
19
|
+
height: 100%;
|
|
20
|
+
flex: 1;
|
|
21
|
+
.tr {
|
|
22
|
+
gap: ${spacing.r16};
|
|
23
|
+
}
|
|
24
|
+
`;
|
|
25
|
+
const TruncatedName = styled_components.div`
|
|
26
|
+
overflow: hidden;
|
|
27
|
+
text-overflow: ellipsis;
|
|
28
|
+
white-space: nowrap;
|
|
29
|
+
min-width: 0;
|
|
30
|
+
`;
|
|
16
31
|
const DEFAULT_PAGE_SIZE = 20;
|
|
17
32
|
const SEARCH_QUERY_PARAM = 'search';
|
|
18
33
|
const NAME_COLUMN_FLEX = '2';
|
|
@@ -26,6 +41,21 @@ const getVersionTextColor = (row)=>{
|
|
|
26
41
|
const isVersion = 'version' === row.original.type;
|
|
27
42
|
return !isLatest && isVersion ? 'infoPrimary' : 'textPrimary';
|
|
28
43
|
};
|
|
44
|
+
const pinFolderFirst = (rowA, rowB, desc)=>{
|
|
45
|
+
const aIsFolder = 'folder' === rowA.original.type;
|
|
46
|
+
const bIsFolder = 'folder' === rowB.original.type;
|
|
47
|
+
if (aIsFolder === bIsFolder) return 0;
|
|
48
|
+
if (aIsFolder) return desc ? 1 : -1;
|
|
49
|
+
return desc ? -1 : 1;
|
|
50
|
+
};
|
|
51
|
+
const pinLatestVersion = (rowA, rowB, desc)=>{
|
|
52
|
+
const aKey = rowA.original.Key || '';
|
|
53
|
+
const bKey = rowB.original.Key || '';
|
|
54
|
+
if (!aKey || !bKey || aKey !== bKey) return 0;
|
|
55
|
+
if (rowA.original.IsLatest && !rowB.original.IsLatest) return desc ? 1 : -1;
|
|
56
|
+
if (!rowA.original.IsLatest && rowB.original.IsLatest) return desc ? -1 : 1;
|
|
57
|
+
return 0;
|
|
58
|
+
};
|
|
29
59
|
const removePrefix = (path, prefix)=>{
|
|
30
60
|
if (!prefix) return path;
|
|
31
61
|
if (path.startsWith(prefix)) return path.slice(prefix.length);
|
|
@@ -55,16 +85,20 @@ const createNameColumn = (onPrefixChange, onDownload)=>({
|
|
|
55
85
|
Header: 'Name',
|
|
56
86
|
accessor: 'displayName',
|
|
57
87
|
id: 'name',
|
|
58
|
-
sortType: (rowA, rowB)=>{
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
if (aIsFolder && !bIsFolder) return -1;
|
|
62
|
-
if (!aIsFolder && bIsFolder) return 1;
|
|
88
|
+
sortType: (rowA, rowB, _columnId, desc)=>{
|
|
89
|
+
const folderOrder = pinFolderFirst(rowA, rowB, desc);
|
|
90
|
+
if (0 !== folderOrder) return folderOrder;
|
|
63
91
|
const aName = String(rowA.values.displayName || '');
|
|
64
92
|
const bName = String(rowB.values.displayName || '');
|
|
65
|
-
|
|
93
|
+
const nameComparison = aName.localeCompare(bName, 'en', {
|
|
66
94
|
sensitivity: 'base'
|
|
67
95
|
});
|
|
96
|
+
if (0 !== nameComparison) return nameComparison;
|
|
97
|
+
const pinOrder = pinLatestVersion(rowA, rowB, desc);
|
|
98
|
+
if (0 !== pinOrder) return pinOrder;
|
|
99
|
+
const aTime = rowA.original.LastModified ? new Date(rowA.original.LastModified).getTime() : 0;
|
|
100
|
+
const bTime = rowB.original.LastModified ? new Date(rowB.original.LastModified).getTime() : 0;
|
|
101
|
+
return bTime - aTime;
|
|
68
102
|
},
|
|
69
103
|
Cell: ({ value, row })=>{
|
|
70
104
|
const isFolder = 'folder' === row.original.type;
|
|
@@ -75,24 +109,25 @@ const createNameColumn = (onPrefixChange, onDownload)=>({
|
|
|
75
109
|
iconName = isFolder ? 'Folder' : isDeleteMarker ? 'Deletion-marker' : 'File';
|
|
76
110
|
const shouldIndent = isVersion && !isLatest;
|
|
77
111
|
const isLegalHoldEnabled = isObjectLike(row.original) && Boolean(row.original.isLegalHoldEnabled);
|
|
78
|
-
return /*#__PURE__*/
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
112
|
+
return /*#__PURE__*/ jsxs(Box, {
|
|
113
|
+
display: "flex",
|
|
114
|
+
alignItems: "center",
|
|
115
|
+
gap: spacing.r8,
|
|
116
|
+
paddingLeft: shouldIndent ? spacing.r24 : 0,
|
|
117
|
+
minWidth: 0,
|
|
118
|
+
children: [
|
|
119
|
+
/*#__PURE__*/ jsx(Icon, {
|
|
120
|
+
name: iconName,
|
|
121
|
+
size: "sm",
|
|
122
|
+
color: getVersionTextColor(row)
|
|
123
|
+
}),
|
|
124
|
+
isLegalHoldEnabled && /*#__PURE__*/ jsx(Icon, {
|
|
125
|
+
name: "Rebalance",
|
|
126
|
+
size: "sm",
|
|
127
|
+
color: getVersionTextColor(row)
|
|
128
|
+
}),
|
|
129
|
+
/*#__PURE__*/ jsx(TruncatedName, {
|
|
130
|
+
children: isDeleteMarker ? /*#__PURE__*/ jsx(Text, {
|
|
96
131
|
color: getVersionTextColor(row),
|
|
97
132
|
children: value
|
|
98
133
|
}) : /*#__PURE__*/ jsx(Text, {
|
|
@@ -106,14 +141,14 @@ const createNameColumn = (onPrefixChange, onDownload)=>({
|
|
|
106
141
|
children: value
|
|
107
142
|
})
|
|
108
143
|
})
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
lineClamp: 2
|
|
144
|
+
})
|
|
145
|
+
]
|
|
112
146
|
});
|
|
113
147
|
},
|
|
114
148
|
cellStyle: {
|
|
115
149
|
flex: NAME_COLUMN_FLEX,
|
|
116
|
-
width: 'unset'
|
|
150
|
+
width: 'unset',
|
|
151
|
+
minWidth: 0
|
|
117
152
|
}
|
|
118
153
|
});
|
|
119
154
|
const createVersionIdColumn = ()=>({
|
|
@@ -132,7 +167,11 @@ const createVersionIdColumn = ()=>({
|
|
|
132
167
|
return /*#__PURE__*/ jsx(ConstrainedText, {
|
|
133
168
|
text: versionId,
|
|
134
169
|
lineClamp: 1,
|
|
135
|
-
color: textColor
|
|
170
|
+
color: textColor,
|
|
171
|
+
tooltipStyle: {
|
|
172
|
+
maxWidth: '20rem',
|
|
173
|
+
wordBreak: 'break-all'
|
|
174
|
+
}
|
|
136
175
|
});
|
|
137
176
|
},
|
|
138
177
|
cellStyle: {
|
|
@@ -143,10 +182,25 @@ const createVersionIdColumn = ()=>({
|
|
|
143
182
|
maxWidth: '8rem'
|
|
144
183
|
}
|
|
145
184
|
});
|
|
146
|
-
const createLastModifiedColumn = ()=>({
|
|
185
|
+
const createLastModifiedColumn = (groupLatestModified)=>({
|
|
147
186
|
Header: 'Modified on',
|
|
148
187
|
accessor: 'LastModified',
|
|
149
188
|
id: 'lastModified',
|
|
189
|
+
sortType: (rowA, rowB, _columnId, desc)=>{
|
|
190
|
+
const folderOrder = pinFolderFirst(rowA, rowB, desc);
|
|
191
|
+
if (0 !== folderOrder) return folderOrder;
|
|
192
|
+
const pinOrder = pinLatestVersion(rowA, rowB, desc);
|
|
193
|
+
if (0 !== pinOrder) return pinOrder;
|
|
194
|
+
const aKey = rowA.original.Key || '';
|
|
195
|
+
const bKey = rowB.original.Key || '';
|
|
196
|
+
const sameKey = '' !== aKey && '' !== bKey && aKey === bKey;
|
|
197
|
+
const a = !sameKey && groupLatestModified?.get(aKey) || rowA.original.LastModified;
|
|
198
|
+
const b = !sameKey && groupLatestModified?.get(bKey) || rowB.original.LastModified;
|
|
199
|
+
if (!a && !b) return 0;
|
|
200
|
+
if (!a) return -1;
|
|
201
|
+
if (!b) return 1;
|
|
202
|
+
return new Date(a).getTime() - new Date(b).getTime();
|
|
203
|
+
},
|
|
150
204
|
Cell: ({ value, row })=>{
|
|
151
205
|
if ('folder' === row.original.type || null == value) return /*#__PURE__*/ jsx(Text, {
|
|
152
206
|
children: "-"
|
|
@@ -162,7 +216,6 @@ const createLastModifiedColumn = ()=>({
|
|
|
162
216
|
cellStyle: {
|
|
163
217
|
flex: LAST_MODIFIED_COLUMN_FLEX,
|
|
164
218
|
textAlign: 'right',
|
|
165
|
-
paddingRight: spacing.r16,
|
|
166
219
|
width: 'unset',
|
|
167
220
|
minWidth: '10rem'
|
|
168
221
|
}
|
|
@@ -190,7 +243,6 @@ const createSizeColumn = ()=>({
|
|
|
190
243
|
cellStyle: {
|
|
191
244
|
flex: SIZE_COLUMN_FLEX,
|
|
192
245
|
textAlign: 'right',
|
|
193
|
-
paddingRight: spacing.r16,
|
|
194
246
|
width: 'unset'
|
|
195
247
|
}
|
|
196
248
|
});
|
|
@@ -239,12 +291,16 @@ function createOverrideMap(customItems) {
|
|
|
239
291
|
item
|
|
240
292
|
]));
|
|
241
293
|
}
|
|
242
|
-
const ObjectList = ({ bucketName, prefix, onObjectSelect, onPrefixChange })=>{
|
|
294
|
+
const ObjectList = ({ bucketName, prefix, onObjectSelect, onPrefixChange, onSelectedObjectsChange })=>{
|
|
243
295
|
const { extraObjectListColumns, extraObjectListActions } = useDataBrowserUICustomization();
|
|
244
296
|
const invalidateQueries = useInvalidateQueries();
|
|
245
297
|
const [showVersions, setShowVersions] = useState(false);
|
|
246
298
|
const isMetadataSearchEnabled = useFeatures('metadatasearch');
|
|
247
|
-
const
|
|
299
|
+
const queryParams = useQueryParams();
|
|
300
|
+
const metadataSearchQuery = queryParams.get('metadatasearch');
|
|
301
|
+
const { search: locationSearch, pathname } = useLocation();
|
|
302
|
+
const navigate = useNavigate();
|
|
303
|
+
const [searchValue, setSearchValue] = useState(queryParams.get(SEARCH_QUERY_PARAM) || '');
|
|
248
304
|
const [selectedObjects, setSelectedObjects] = useState([]);
|
|
249
305
|
const { mutateAsync: getPresignedDownload } = useGetPresignedDownload();
|
|
250
306
|
const downloadingRef = useRef(new Set());
|
|
@@ -338,7 +394,8 @@ const ObjectList = ({ bucketName, prefix, onObjectSelect, onPrefixChange })=>{
|
|
|
338
394
|
const versionSearchParams = useMemo(()=>({
|
|
339
395
|
Bucket: bucketName,
|
|
340
396
|
Prefix: prefix,
|
|
341
|
-
MaxKeys: DEFAULT_PAGE_SIZE
|
|
397
|
+
MaxKeys: DEFAULT_PAGE_SIZE,
|
|
398
|
+
Delimiter: '/'
|
|
342
399
|
}), [
|
|
343
400
|
bucketName,
|
|
344
401
|
prefix
|
|
@@ -348,6 +405,7 @@ const ObjectList = ({ bucketName, prefix, onObjectSelect, onPrefixChange })=>{
|
|
|
348
405
|
});
|
|
349
406
|
useEffect(()=>{
|
|
350
407
|
setSelectedObjects([]);
|
|
408
|
+
onObjectSelectRef.current(null);
|
|
351
409
|
}, [
|
|
352
410
|
prefix,
|
|
353
411
|
showVersions
|
|
@@ -429,9 +487,10 @@ const ObjectList = ({ bucketName, prefix, onObjectSelect, onPrefixChange })=>{
|
|
|
429
487
|
}, [
|
|
430
488
|
prefix
|
|
431
489
|
]);
|
|
432
|
-
const tableData = useMemo(()=>{
|
|
490
|
+
const { tableData, versionGroupLatestModified } = useMemo(()=>{
|
|
433
491
|
let folders = [];
|
|
434
492
|
const items = [];
|
|
493
|
+
const latestModifiedMap = new Map();
|
|
435
494
|
if (showVersions) {
|
|
436
495
|
folders = listObjectsQuery.data?.pages ? processFolders(listObjectsQuery.data.pages) : [];
|
|
437
496
|
const objectsWithVersions = new Set();
|
|
@@ -467,6 +526,8 @@ const ObjectList = ({ bucketName, prefix, onObjectSelect, onPrefixChange })=>{
|
|
|
467
526
|
const bTime = b.LastModified?.getTime() ?? 0;
|
|
468
527
|
return bTime - aTime;
|
|
469
528
|
});
|
|
529
|
+
const latestItem = allItems[0];
|
|
530
|
+
if (latestItem?.Key && latestItem.LastModified) latestModifiedMap.set(latestItem.Key, latestItem.LastModified);
|
|
470
531
|
allItems.forEach((item)=>{
|
|
471
532
|
if (!item.Key) return;
|
|
472
533
|
if (item.Key.endsWith('/')) return;
|
|
@@ -506,11 +567,13 @@ const ObjectList = ({ bucketName, prefix, onObjectSelect, onPrefixChange })=>{
|
|
|
506
567
|
});
|
|
507
568
|
});
|
|
508
569
|
}
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
570
|
+
return {
|
|
571
|
+
tableData: [
|
|
572
|
+
...folders,
|
|
573
|
+
...items
|
|
574
|
+
],
|
|
575
|
+
versionGroupLatestModified: latestModifiedMap
|
|
576
|
+
};
|
|
514
577
|
}, [
|
|
515
578
|
showVersions,
|
|
516
579
|
listObjectsQuery.data,
|
|
@@ -520,7 +583,9 @@ const ObjectList = ({ bucketName, prefix, onObjectSelect, onPrefixChange })=>{
|
|
|
520
583
|
createObjectItem
|
|
521
584
|
]);
|
|
522
585
|
const versionIdColumn = useMemo(()=>createVersionIdColumn(), []);
|
|
523
|
-
const lastModifiedColumn = useMemo(()=>createLastModifiedColumn(), [
|
|
586
|
+
const lastModifiedColumn = useMemo(()=>createLastModifiedColumn(versionGroupLatestModified), [
|
|
587
|
+
versionGroupLatestModified
|
|
588
|
+
]);
|
|
524
589
|
const sizeColumn = useMemo(()=>createSizeColumn(), []);
|
|
525
590
|
const storageClassColumn = useMemo(()=>createStorageClassColumn(), []);
|
|
526
591
|
const nameColumn = useMemo(()=>createNameColumn(handlePrefixChange, handleDownload), [
|
|
@@ -587,6 +652,19 @@ const ObjectList = ({ bucketName, prefix, onObjectSelect, onPrefixChange })=>{
|
|
|
587
652
|
}, [
|
|
588
653
|
invalidateQueries
|
|
589
654
|
]);
|
|
655
|
+
const handleSearchChange = useCallback((value)=>{
|
|
656
|
+
setSearchValue(value);
|
|
657
|
+
const params = new URLSearchParams(locationSearch);
|
|
658
|
+
if (value) params.set(SEARCH_QUERY_PARAM, value);
|
|
659
|
+
else params.delete(SEARCH_QUERY_PARAM);
|
|
660
|
+
navigate(`${pathname}?${params.toString()}`, {
|
|
661
|
+
replace: true
|
|
662
|
+
});
|
|
663
|
+
}, [
|
|
664
|
+
locationSearch,
|
|
665
|
+
pathname,
|
|
666
|
+
navigate
|
|
667
|
+
]);
|
|
590
668
|
const handleUploadError = useCallback(()=>{}, []);
|
|
591
669
|
const handleFolderError = useCallback(()=>{}, []);
|
|
592
670
|
const renderUploadAction = useCallback(()=>/*#__PURE__*/ jsx(UploadButton, {
|
|
@@ -611,12 +689,21 @@ const ObjectList = ({ bucketName, prefix, onObjectSelect, onPrefixChange })=>{
|
|
|
611
689
|
handleFolderSuccess,
|
|
612
690
|
handleFolderError
|
|
613
691
|
]);
|
|
692
|
+
const handleDeleteSuccess = useCallback(()=>{
|
|
693
|
+
setSelectedObjects([]);
|
|
694
|
+
onSelectedObjectsChange?.([]);
|
|
695
|
+
onObjectSelectRef.current(null);
|
|
696
|
+
}, [
|
|
697
|
+
onSelectedObjectsChange
|
|
698
|
+
]);
|
|
614
699
|
const renderDeleteAction = useCallback(()=>/*#__PURE__*/ jsx(DeleteObjectButton, {
|
|
615
700
|
objects: selectedObjects,
|
|
616
|
-
bucketName: bucketName
|
|
701
|
+
bucketName: bucketName,
|
|
702
|
+
onDeleteSuccess: handleDeleteSuccess
|
|
617
703
|
}), [
|
|
618
704
|
selectedObjects,
|
|
619
|
-
bucketName
|
|
705
|
+
bucketName,
|
|
706
|
+
handleDeleteSuccess
|
|
620
707
|
]);
|
|
621
708
|
const actions = useMemo(()=>{
|
|
622
709
|
const defaultActionsMap = {
|
|
@@ -662,73 +749,86 @@ const ObjectList = ({ bucketName, prefix, onObjectSelect, onPrefixChange })=>{
|
|
|
662
749
|
const handleMultiSelectionChanged = useCallback((rows)=>{
|
|
663
750
|
const objects = rows.map((row)=>row.original);
|
|
664
751
|
setSelectedObjects(objects);
|
|
665
|
-
|
|
752
|
+
onSelectedObjectsChange?.(objects);
|
|
753
|
+
}, [
|
|
754
|
+
onSelectedObjectsChange
|
|
755
|
+
]);
|
|
666
756
|
const handleSingleRowSelected = useCallback((row)=>{
|
|
667
757
|
handleObjectSelect(row.original);
|
|
758
|
+
setSelectedObjects([
|
|
759
|
+
row.original
|
|
760
|
+
]);
|
|
761
|
+
onSelectedObjectsChange?.([
|
|
762
|
+
row.original
|
|
763
|
+
]);
|
|
668
764
|
}, [
|
|
669
|
-
handleObjectSelect
|
|
765
|
+
handleObjectSelect,
|
|
766
|
+
onSelectedObjectsChange
|
|
670
767
|
]);
|
|
671
768
|
const handleToggleAll = useCallback((selected)=>{
|
|
672
|
-
selected ?
|
|
769
|
+
const objects = selected ? tableData : [];
|
|
770
|
+
setSelectedObjects(objects);
|
|
771
|
+
onSelectedObjectsChange?.(objects);
|
|
673
772
|
}, [
|
|
674
|
-
tableData
|
|
773
|
+
tableData,
|
|
774
|
+
onSelectedObjectsChange
|
|
675
775
|
]);
|
|
676
776
|
const tableStatus = isLoading ? 'loading' : error ? 'error' : 'success';
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
777
|
+
return /*#__PURE__*/ jsx(TableWithAlignedRows, {
|
|
778
|
+
children: /*#__PURE__*/ jsxs(Table, {
|
|
779
|
+
columns: columns,
|
|
780
|
+
data: tableData,
|
|
781
|
+
status: tableStatus,
|
|
782
|
+
onBottom: handleReachBottom,
|
|
783
|
+
globalFilter: isMetadataSearchEnabled ? void 0 : searchValue,
|
|
784
|
+
children: [
|
|
785
|
+
/*#__PURE__*/ jsxs(Wrap, {
|
|
786
|
+
padding: spacing.r16,
|
|
787
|
+
children: [
|
|
788
|
+
isMetadataSearchEnabled ? /*#__PURE__*/ jsx(MetadataSearch, {
|
|
789
|
+
isError: !!error
|
|
790
|
+
}) : /*#__PURE__*/ jsx(SearchInput, {
|
|
791
|
+
value: searchValue,
|
|
792
|
+
placeholder: "Search",
|
|
793
|
+
size: "1",
|
|
794
|
+
onChange: (e)=>handleSearchChange(e.target.value),
|
|
795
|
+
onReset: ()=>handleSearchChange('')
|
|
796
|
+
}),
|
|
797
|
+
/*#__PURE__*/ jsxs(Box, {
|
|
798
|
+
display: "flex",
|
|
799
|
+
justifyContent: "space-between",
|
|
800
|
+
alignItems: "center",
|
|
801
|
+
gap: spacing.r8,
|
|
802
|
+
children: [
|
|
803
|
+
/*#__PURE__*/ jsx(Box, {
|
|
804
|
+
display: "flex",
|
|
805
|
+
alignItems: "center",
|
|
806
|
+
gap: spacing.r8,
|
|
807
|
+
children: actions.map((action)=>/*#__PURE__*/ jsx(Fragment, {
|
|
808
|
+
children: action.render()
|
|
809
|
+
}, action.id))
|
|
810
|
+
}),
|
|
811
|
+
/*#__PURE__*/ jsx(Toggle, {
|
|
812
|
+
toggle: showVersions,
|
|
813
|
+
onChange: (e)=>setShowVersions(e.target.checked),
|
|
814
|
+
label: "List Versions",
|
|
815
|
+
"aria-label": showVersions ? 'Hide object versions' : 'Show object versions',
|
|
816
|
+
"aria-pressed": showVersions
|
|
817
|
+
})
|
|
818
|
+
]
|
|
819
|
+
})
|
|
820
|
+
]
|
|
821
|
+
}),
|
|
822
|
+
/*#__PURE__*/ jsx(Table.MultiSelectableContent, {
|
|
823
|
+
rowHeight: "h40",
|
|
824
|
+
onMultiSelectionChanged: handleMultiSelectionChanged,
|
|
825
|
+
onSingleRowSelected: handleSingleRowSelected,
|
|
826
|
+
onToggleAll: handleToggleAll,
|
|
827
|
+
separationLineVariant: "backgroundLevel1",
|
|
828
|
+
isLoadingMoreItems: isFetchingNextPage
|
|
829
|
+
})
|
|
830
|
+
]
|
|
831
|
+
})
|
|
732
832
|
});
|
|
733
833
|
};
|
|
734
834
|
export { ObjectList, isObjectLike };
|
|
@@ -59,7 +59,9 @@ describe('ObjectLockSettings', ()=>{
|
|
|
59
59
|
await waitFor(()=>{
|
|
60
60
|
expect(screen.getByText('Object-lock settings')).toBeInTheDocument();
|
|
61
61
|
});
|
|
62
|
-
expect(screen.
|
|
62
|
+
expect(screen.getByRole('checkbox', {
|
|
63
|
+
name: /object-lock/i
|
|
64
|
+
})).toBeInTheDocument();
|
|
63
65
|
});
|
|
64
66
|
it('disables save button when Object Lock is not enabled', async ()=>{
|
|
65
67
|
renderObjectLockSettings();
|
|
@@ -81,9 +83,15 @@ describe('ObjectLockSettings', ()=>{
|
|
|
81
83
|
});
|
|
82
84
|
renderObjectLockSettings();
|
|
83
85
|
await waitFor(()=>{
|
|
84
|
-
expect(screen.
|
|
85
|
-
|
|
86
|
-
|
|
86
|
+
expect(screen.getByRole('checkbox', {
|
|
87
|
+
name: /default retention/i
|
|
88
|
+
})).toBeInTheDocument();
|
|
89
|
+
expect(screen.getByRole('radio', {
|
|
90
|
+
name: /governance/i
|
|
91
|
+
})).toBeInTheDocument();
|
|
92
|
+
expect(screen.getByRole('spinbutton', {
|
|
93
|
+
name: /retention period/i
|
|
94
|
+
})).toBeInTheDocument();
|
|
87
95
|
}, {
|
|
88
96
|
timeout: 3000
|
|
89
97
|
});
|
|
@@ -118,13 +126,19 @@ describe('ObjectLockSettings', ()=>{
|
|
|
118
126
|
});
|
|
119
127
|
renderObjectLockSettings();
|
|
120
128
|
await waitFor(()=>{
|
|
121
|
-
expect(screen.
|
|
129
|
+
expect(screen.getByRole('checkbox', {
|
|
130
|
+
name: /default retention/i
|
|
131
|
+
})).toBeInTheDocument();
|
|
132
|
+
});
|
|
133
|
+
const defaultRetentionCheckbox = screen.getByRole('checkbox', {
|
|
134
|
+
name: /default retention/i
|
|
122
135
|
});
|
|
123
|
-
const defaultRetentionCheckbox = screen.getByLabelText(/default retention/i);
|
|
124
136
|
expect(defaultRetentionCheckbox).not.toBeChecked();
|
|
125
137
|
fireEvent.click(defaultRetentionCheckbox);
|
|
126
138
|
await waitFor(()=>{
|
|
127
|
-
const governanceRadio = screen.
|
|
139
|
+
const governanceRadio = screen.getByRole('radio', {
|
|
140
|
+
name: /governance/i
|
|
141
|
+
});
|
|
128
142
|
expect(governanceRadio).not.toBeDisabled();
|
|
129
143
|
}, {
|
|
130
144
|
timeout: 3000
|
|
@@ -147,11 +161,15 @@ describe('ObjectLockSettings', ()=>{
|
|
|
147
161
|
});
|
|
148
162
|
renderObjectLockSettings();
|
|
149
163
|
await waitFor(()=>{
|
|
150
|
-
const defaultRetentionCheckbox = screen.
|
|
164
|
+
const defaultRetentionCheckbox = screen.getByRole('checkbox', {
|
|
165
|
+
name: /default retention/i
|
|
166
|
+
});
|
|
151
167
|
fireEvent.click(defaultRetentionCheckbox);
|
|
152
168
|
});
|
|
153
169
|
await waitFor(()=>{
|
|
154
|
-
const governanceRadio = screen.
|
|
170
|
+
const governanceRadio = screen.getByRole('radio', {
|
|
171
|
+
name: /governance/i
|
|
172
|
+
});
|
|
155
173
|
expect(governanceRadio).toBeDisabled();
|
|
156
174
|
});
|
|
157
175
|
});
|
|
@@ -166,15 +184,23 @@ describe('ObjectLockSettings', ()=>{
|
|
|
166
184
|
});
|
|
167
185
|
renderObjectLockSettings();
|
|
168
186
|
await waitFor(()=>{
|
|
169
|
-
expect(screen.
|
|
187
|
+
expect(screen.getByRole('checkbox', {
|
|
188
|
+
name: /default retention/i
|
|
189
|
+
})).toBeInTheDocument();
|
|
190
|
+
});
|
|
191
|
+
const defaultRetentionCheckbox = screen.getByRole('checkbox', {
|
|
192
|
+
name: /default retention/i
|
|
170
193
|
});
|
|
171
|
-
const defaultRetentionCheckbox = screen.getByLabelText(/default retention/i);
|
|
172
194
|
fireEvent.click(defaultRetentionCheckbox);
|
|
173
195
|
await waitFor(()=>{
|
|
174
|
-
const retentionPeriodInput = screen.
|
|
196
|
+
const retentionPeriodInput = screen.getByRole('spinbutton', {
|
|
197
|
+
name: /retention period/i
|
|
198
|
+
});
|
|
175
199
|
expect(retentionPeriodInput).toBeInTheDocument();
|
|
176
200
|
});
|
|
177
|
-
const retentionPeriodInput = screen.
|
|
201
|
+
const retentionPeriodInput = screen.getByRole('spinbutton', {
|
|
202
|
+
name: /retention period/i
|
|
203
|
+
});
|
|
178
204
|
await user_event.clear(retentionPeriodInput);
|
|
179
205
|
await user_event.type(retentionPeriodInput, '0');
|
|
180
206
|
await waitFor(()=>{
|
|
@@ -197,18 +223,28 @@ describe('ObjectLockSettings', ()=>{
|
|
|
197
223
|
});
|
|
198
224
|
renderObjectLockSettings();
|
|
199
225
|
await waitFor(()=>{
|
|
200
|
-
expect(screen.
|
|
226
|
+
expect(screen.getByRole('checkbox', {
|
|
227
|
+
name: /default retention/i
|
|
228
|
+
})).toBeInTheDocument();
|
|
229
|
+
});
|
|
230
|
+
const defaultRetentionCheckbox = screen.getByRole('checkbox', {
|
|
231
|
+
name: /default retention/i
|
|
201
232
|
});
|
|
202
|
-
const defaultRetentionCheckbox = screen.getByLabelText(/default retention/i);
|
|
203
233
|
fireEvent.click(defaultRetentionCheckbox);
|
|
204
234
|
await waitFor(()=>{
|
|
205
|
-
const retentionPeriodInput = screen.
|
|
235
|
+
const retentionPeriodInput = screen.getByRole('spinbutton', {
|
|
236
|
+
name: /retention period/i
|
|
237
|
+
});
|
|
206
238
|
expect(retentionPeriodInput).toBeInTheDocument();
|
|
207
239
|
});
|
|
208
|
-
const retentionPeriodInput = screen.
|
|
240
|
+
const retentionPeriodInput = screen.getByRole('spinbutton', {
|
|
241
|
+
name: /retention period/i
|
|
242
|
+
});
|
|
209
243
|
await user_event.clear(retentionPeriodInput);
|
|
210
244
|
await user_event.type(retentionPeriodInput, '30');
|
|
211
|
-
const governanceRadio = screen.
|
|
245
|
+
const governanceRadio = screen.getByRole('radio', {
|
|
246
|
+
name: /governance/i
|
|
247
|
+
});
|
|
212
248
|
fireEvent.click(governanceRadio);
|
|
213
249
|
mockMutate.mockImplementation((_, options)=>{
|
|
214
250
|
options?.onSuccess?.();
|
|
@@ -241,15 +277,23 @@ describe('ObjectLockSettings', ()=>{
|
|
|
241
277
|
});
|
|
242
278
|
renderObjectLockSettings();
|
|
243
279
|
await waitFor(()=>{
|
|
244
|
-
expect(screen.
|
|
280
|
+
expect(screen.getByRole('checkbox', {
|
|
281
|
+
name: /default retention/i
|
|
282
|
+
})).toBeInTheDocument();
|
|
283
|
+
});
|
|
284
|
+
const defaultRetentionCheckbox = screen.getByRole('checkbox', {
|
|
285
|
+
name: /default retention/i
|
|
245
286
|
});
|
|
246
|
-
const defaultRetentionCheckbox = screen.getByLabelText(/default retention/i);
|
|
247
287
|
fireEvent.click(defaultRetentionCheckbox);
|
|
248
288
|
await waitFor(()=>{
|
|
249
|
-
const retentionPeriodInput = screen.
|
|
289
|
+
const retentionPeriodInput = screen.getByRole('spinbutton', {
|
|
290
|
+
name: /retention period/i
|
|
291
|
+
});
|
|
250
292
|
expect(retentionPeriodInput).toBeInTheDocument();
|
|
251
293
|
});
|
|
252
|
-
const retentionPeriodInput = screen.
|
|
294
|
+
const retentionPeriodInput = screen.getByRole('spinbutton', {
|
|
295
|
+
name: /retention period/i
|
|
296
|
+
});
|
|
253
297
|
await user_event.clear(retentionPeriodInput);
|
|
254
298
|
await user_event.type(retentionPeriodInput, '2');
|
|
255
299
|
mockMutate.mockImplementation((_, options)=>{
|
|
@@ -361,14 +405,22 @@ describe('ObjectLockSettings', ()=>{
|
|
|
361
405
|
});
|
|
362
406
|
renderObjectLockSettings();
|
|
363
407
|
await waitFor(()=>{
|
|
364
|
-
const objectLockCheckbox = screen.
|
|
408
|
+
const objectLockCheckbox = screen.getByRole('checkbox', {
|
|
409
|
+
name: /object-lock/i
|
|
410
|
+
});
|
|
365
411
|
expect(objectLockCheckbox).toBeChecked();
|
|
366
412
|
});
|
|
367
|
-
const defaultRetentionCheckbox = screen.
|
|
413
|
+
const defaultRetentionCheckbox = screen.getByRole('checkbox', {
|
|
414
|
+
name: /default retention/i
|
|
415
|
+
});
|
|
368
416
|
expect(defaultRetentionCheckbox).toBeChecked();
|
|
369
|
-
const complianceRadio = screen.
|
|
417
|
+
const complianceRadio = screen.getByRole('radio', {
|
|
418
|
+
name: /compliance/i
|
|
419
|
+
});
|
|
370
420
|
expect(complianceRadio).toBeChecked();
|
|
371
|
-
const retentionPeriodInput = screen.
|
|
421
|
+
const retentionPeriodInput = screen.getByRole('spinbutton', {
|
|
422
|
+
name: /retention period/i
|
|
423
|
+
});
|
|
372
424
|
expect(retentionPeriodInput).toHaveValue(60);
|
|
373
425
|
});
|
|
374
426
|
});
|