@scality/data-browser-library 1.0.3 → 1.0.5
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__/BucketList.test.js +74 -1
- 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__/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/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/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 -4
|
@@ -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 };
|
|
@@ -10,11 +10,13 @@ const ObjectPage = ()=>{
|
|
|
10
10
|
const navigate = useDataBrowserNavigate();
|
|
11
11
|
const [searchParams] = useSearchParams();
|
|
12
12
|
const [item, setItem] = useState(null);
|
|
13
|
+
const [multipleSelected, setMultipleSelected] = useState(false);
|
|
13
14
|
const prefix = searchParams.get('prefix') || '';
|
|
14
15
|
const handlePrefixChange = useCallback((newPrefix)=>{
|
|
15
16
|
const newSearchParams = new URLSearchParams(searchParams);
|
|
16
17
|
newSearchParams.set('prefix', newPrefix);
|
|
17
18
|
setItem(null);
|
|
19
|
+
setMultipleSelected(false);
|
|
18
20
|
navigate(`?${newSearchParams.toString()}`, {
|
|
19
21
|
replace: true
|
|
20
22
|
});
|
|
@@ -22,12 +24,25 @@ const ObjectPage = ()=>{
|
|
|
22
24
|
navigate,
|
|
23
25
|
searchParams
|
|
24
26
|
]);
|
|
27
|
+
const handleObjectSelect = useCallback((object)=>{
|
|
28
|
+
setItem(object);
|
|
29
|
+
setMultipleSelected(false);
|
|
30
|
+
}, []);
|
|
31
|
+
const handleSelectedObjectsChange = useCallback((objects)=>{
|
|
32
|
+
if (1 === objects.length) {
|
|
33
|
+
setItem(objects[0]);
|
|
34
|
+
setMultipleSelected(false);
|
|
35
|
+
} else if (objects.length > 1) {
|
|
36
|
+
setItem(null);
|
|
37
|
+
setMultipleSelected(true);
|
|
38
|
+
} else {
|
|
39
|
+
setItem(null);
|
|
40
|
+
setMultipleSelected(false);
|
|
41
|
+
}
|
|
42
|
+
}, []);
|
|
25
43
|
if (!bucketName) return /*#__PURE__*/ jsx("div", {
|
|
26
44
|
children: "Bucket name is required"
|
|
27
45
|
});
|
|
28
|
-
const handleObjectSelect = (object)=>{
|
|
29
|
-
setItem(object);
|
|
30
|
-
};
|
|
31
46
|
return /*#__PURE__*/ jsx(BrowserPageLayout, {
|
|
32
47
|
iconName: "Bucket",
|
|
33
48
|
title: bucketName,
|
|
@@ -35,10 +50,12 @@ const ObjectPage = ()=>{
|
|
|
35
50
|
bucketName: bucketName,
|
|
36
51
|
prefix: prefix,
|
|
37
52
|
onObjectSelect: handleObjectSelect,
|
|
38
|
-
onPrefixChange: handlePrefixChange
|
|
53
|
+
onPrefixChange: handlePrefixChange,
|
|
54
|
+
onSelectedObjectsChange: handleSelectedObjectsChange
|
|
39
55
|
}),
|
|
40
56
|
rightPanel: /*#__PURE__*/ jsx(ObjectDetails, {
|
|
41
|
-
item: item
|
|
57
|
+
item: item,
|
|
58
|
+
multipleSelected: multipleSelected
|
|
42
59
|
}),
|
|
43
60
|
withArrowNavigation: true,
|
|
44
61
|
arrowNavigationPath: `/buckets/${bucketName}`
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Icon, spacing } from "@scality/core-ui";
|
|
3
|
-
import { convertSizeToRem } from "@scality/core-ui/dist/components/inputv2/inputv2";
|
|
4
3
|
import { Box, Button } from "@scality/core-ui/dist/next";
|
|
5
4
|
function ArrayFieldActions({ onRemove, onAdd, canRemove, canAdd = true, showAdd, removeLabel = 'Remove', addLabel = 'Add' }) {
|
|
6
5
|
return /*#__PURE__*/ jsxs(Box, {
|
|
7
6
|
display: "flex",
|
|
8
|
-
width: convertSizeToRem('1/2'),
|
|
9
7
|
gap: spacing.r8,
|
|
10
8
|
justifyContent: "flex-start",
|
|
11
9
|
children: [
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { FormGroup, FormSection, Stack
|
|
2
|
+
import { FormGroup, FormSection, Stack } from "@scality/core-ui";
|
|
3
3
|
import { convertRemToPixels } from "@scality/core-ui/dist/components/tablev2/TableUtils";
|
|
4
|
-
import {
|
|
4
|
+
import { Input, Select } from "@scality/core-ui/dist/next";
|
|
5
5
|
import { ArrayFieldActions } from "./ArrayFieldActions.js";
|
|
6
|
+
import { FormCell, FormColumnHeaders, FormRow } from "./FormGrid.js";
|
|
6
7
|
const filterTypeOptions = [
|
|
7
8
|
{
|
|
8
9
|
value: 'none',
|
|
@@ -68,42 +69,22 @@ function FilterFormSection({ filterType, onFilterTypeChange, prefixRegister, tag
|
|
|
68
69
|
direction: "vertical",
|
|
69
70
|
gap: "r8",
|
|
70
71
|
children: [
|
|
71
|
-
/*#__PURE__*/
|
|
72
|
-
|
|
73
|
-
children: [
|
|
74
|
-
/*#__PURE__*/ jsx(Box, {
|
|
75
|
-
flex: "1",
|
|
76
|
-
children: /*#__PURE__*/ jsx(Text, {
|
|
77
|
-
color: "textSecondary",
|
|
78
|
-
children: "Key"
|
|
79
|
-
})
|
|
80
|
-
}),
|
|
81
|
-
/*#__PURE__*/ jsx(Box, {
|
|
82
|
-
flex: "1",
|
|
83
|
-
children: /*#__PURE__*/ jsx(Text, {
|
|
84
|
-
color: "textSecondary",
|
|
85
|
-
children: "Value"
|
|
86
|
-
})
|
|
87
|
-
}),
|
|
88
|
-
/*#__PURE__*/ jsx(Box, {
|
|
89
|
-
width: "80px"
|
|
90
|
-
})
|
|
91
|
-
]
|
|
92
|
-
}),
|
|
93
|
-
tagFields.map((field, index)=>/*#__PURE__*/ jsxs(Stack, {
|
|
94
|
-
gap: "r8",
|
|
72
|
+
/*#__PURE__*/ jsx(FormColumnHeaders, {}),
|
|
73
|
+
tagFields.map((field, index)=>/*#__PURE__*/ jsxs(FormRow, {
|
|
95
74
|
children: [
|
|
96
|
-
/*#__PURE__*/ jsx(
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
75
|
+
/*#__PURE__*/ jsx(FormCell, {
|
|
76
|
+
children: /*#__PURE__*/ jsx(Input, {
|
|
77
|
+
id: `tag-key-${index}`,
|
|
78
|
+
placeholder: "Key",
|
|
79
|
+
...tagKeyRegister(index)
|
|
80
|
+
})
|
|
101
81
|
}),
|
|
102
|
-
/*#__PURE__*/ jsx(
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
82
|
+
/*#__PURE__*/ jsx(FormCell, {
|
|
83
|
+
children: /*#__PURE__*/ jsx(Input, {
|
|
84
|
+
id: `tag-value-${index}`,
|
|
85
|
+
placeholder: "Value",
|
|
86
|
+
...tagValueRegister(index)
|
|
87
|
+
})
|
|
107
88
|
}),
|
|
108
89
|
/*#__PURE__*/ jsx(ArrayFieldActions, {
|
|
109
90
|
showAdd: index === tagFields.length - 1,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const FormRow: import("styled-components").StyledComponent<"div", any, {
|
|
2
|
+
columns?: string;
|
|
3
|
+
}, never>;
|
|
4
|
+
export declare const FormCell: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
5
|
+
export declare const FormColumnHeaders: ({ wideKey }: {
|
|
6
|
+
wideKey?: boolean;
|
|
7
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Text, spacing } from "@scality/core-ui";
|
|
3
|
+
import styled_components from "styled-components";
|
|
4
|
+
const ACTIONS_WIDTH = `calc(${spacing.r32} * 2 + ${spacing.r8})`;
|
|
5
|
+
const FormRow = styled_components.div`
|
|
6
|
+
display: grid;
|
|
7
|
+
grid-template-columns: ${({ columns })=>columns || '1fr 1fr'} ${ACTIONS_WIDTH};
|
|
8
|
+
gap: ${spacing.r8};
|
|
9
|
+
align-items: center;
|
|
10
|
+
`;
|
|
11
|
+
const FormCell = styled_components.div`
|
|
12
|
+
min-width: 0;
|
|
13
|
+
> * {
|
|
14
|
+
width: 100% !important;
|
|
15
|
+
}
|
|
16
|
+
`;
|
|
17
|
+
const FormColumnHeaders = ({ wideKey })=>/*#__PURE__*/ jsxs(FormRow, {
|
|
18
|
+
columns: wideKey ? '3fr auto 2fr' : void 0,
|
|
19
|
+
children: [
|
|
20
|
+
/*#__PURE__*/ jsx(Text, {
|
|
21
|
+
color: "textPrimary",
|
|
22
|
+
children: "Key"
|
|
23
|
+
}),
|
|
24
|
+
wideKey && /*#__PURE__*/ jsx("span", {
|
|
25
|
+
style: {
|
|
26
|
+
visibility: 'hidden'
|
|
27
|
+
},
|
|
28
|
+
children: ":"
|
|
29
|
+
}),
|
|
30
|
+
/*#__PURE__*/ jsx(Text, {
|
|
31
|
+
color: "textPrimary",
|
|
32
|
+
children: "Value"
|
|
33
|
+
}),
|
|
34
|
+
/*#__PURE__*/ jsx("span", {})
|
|
35
|
+
]
|
|
36
|
+
});
|
|
37
|
+
export { FormCell, FormColumnHeaders, FormRow };
|