@scality/data-browser-library 1.0.7 → 1.0.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__/BucketCorsPage.test.js +67 -9
- package/dist/components/__tests__/BucketDetails.test.js +1 -0
- package/dist/components/__tests__/BucketLifecycleFormPage.test.js +16 -11
- package/dist/components/__tests__/BucketNotificationFormPage.test.js +45 -0
- package/dist/components/__tests__/BucketOverview.test.js +92 -2
- package/dist/components/__tests__/BucketPolicyPage.test.js +70 -51
- package/dist/components/__tests__/BucketReplicationFormPage.test.js +18 -24
- package/dist/components/__tests__/ObjectList.test.js +43 -2
- package/dist/components/buckets/BucketConfigEditButton.d.ts +2 -0
- package/dist/components/buckets/BucketConfigEditButton.js +9 -3
- package/dist/components/buckets/BucketCorsPage.js +57 -20
- package/dist/components/buckets/BucketDetails.js +27 -2
- package/dist/components/buckets/BucketLifecycleFormPage.js +310 -270
- package/dist/components/buckets/BucketOverview.js +21 -18
- package/dist/components/buckets/BucketPolicyPage.js +119 -83
- package/dist/components/buckets/BucketReplicationFormPage.js +39 -29
- package/dist/components/buckets/BucketVersioning.js +16 -10
- package/dist/components/buckets/__tests__/BucketVersioning.test.js +76 -23
- package/dist/components/buckets/notifications/BucketNotificationFormPage.js +13 -5
- package/dist/components/objects/ObjectList.js +22 -25
- package/dist/components/objects/ObjectLock/EditRetentionButton.js +2 -2
- package/dist/components/objects/UploadButton.js +25 -15
- package/dist/config/__tests__/resolveBrandingTheme.test.d.ts +1 -0
- package/dist/config/__tests__/resolveBrandingTheme.test.js +96 -0
- package/dist/config/resolveBrandingTheme.d.ts +16 -0
- package/dist/config/resolveBrandingTheme.js +23 -0
- package/dist/config/types.d.ts +36 -0
- package/dist/hooks/factories/useCreateS3InfiniteQueryHook.js +2 -0
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/objectOperations.d.ts +3 -3
- package/dist/hooks/objectOperations.js +3 -3
- package/dist/hooks/useBucketConfigEditor.d.ts +4 -4
- package/dist/hooks/useBucketConfigEditor.js +16 -31
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/test/mocks/esmOnlyModules.js +4 -0
- package/dist/types/index.d.ts +0 -1
- package/dist/utils/__tests__/proxyMiddleware.test.js +34 -0
- package/dist/utils/proxyMiddleware.js +2 -0
- package/package.json +4 -4
- package/dist/components/Editor.d.ts +0 -12
- package/dist/components/Editor.js +0 -28
- package/dist/types/monaco.d.ts +0 -13
- package/dist/types/monaco.js +0 -0
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { act, fireEvent, render, renderHook, screen, waitFor } from "@testing-library/react";
|
|
3
|
+
import { HttpResponse, http } from "msw";
|
|
3
4
|
import { MemoryRouter } from "react-router";
|
|
4
5
|
import { DataBrowserUICustomizationProvider } from "../../contexts/DataBrowserUICustomizationContext.js";
|
|
5
|
-
import { useListObjectVersions, useListObjects } from "../../hooks/index.js";
|
|
6
|
-
import {
|
|
6
|
+
import { useListObjectVersions, useListObjects, useSearchObjects } from "../../hooks/index.js";
|
|
7
|
+
import { getS3BaseUrl } from "../../test/msw/utils.js";
|
|
8
|
+
import { createTestWrapper, mockOffsetSize, overrideHandlers, setupMswServer } from "../../test/testUtils.js";
|
|
7
9
|
import { ObjectList } from "../objects/ObjectList.js";
|
|
8
10
|
import * as __rspack_external__hooks_useFeatures_js_a6a84786 from "../../hooks/useFeatures.js";
|
|
9
11
|
setupMswServer();
|
|
@@ -391,6 +393,45 @@ describe('ObjectList', ()=>{
|
|
|
391
393
|
});
|
|
392
394
|
jest.useRealTimers();
|
|
393
395
|
});
|
|
396
|
+
it('passes the search query parameter to the S3 request when metadata search is active', async ()=>{
|
|
397
|
+
let capturedSearchParam = null;
|
|
398
|
+
overrideHandlers(http.get(`${getS3BaseUrl()}/:bucketName`, async ({ request })=>{
|
|
399
|
+
const url = new URL(request.url);
|
|
400
|
+
if ('2' !== url.searchParams.get('list-type')) return;
|
|
401
|
+
capturedSearchParam = url.searchParams.get('search');
|
|
402
|
+
return HttpResponse.xml(`<?xml version="1.0" encoding="UTF-8"?>
|
|
403
|
+
<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
|
|
404
|
+
<Name>test-bucket</Name>
|
|
405
|
+
<Prefix></Prefix>
|
|
406
|
+
<Delimiter>/</Delimiter>
|
|
407
|
+
<MaxKeys>100</MaxKeys>
|
|
408
|
+
<IsTruncated>false</IsTruncated>
|
|
409
|
+
<Contents>
|
|
410
|
+
<Key>matched-file.pdf</Key>
|
|
411
|
+
<LastModified>2023-10-12T17:50:00.000Z</LastModified>
|
|
412
|
+
<ETag>"abc123"</ETag>
|
|
413
|
+
<Size>2048</Size>
|
|
414
|
+
<StorageClass>STANDARD</StorageClass>
|
|
415
|
+
</Contents>
|
|
416
|
+
</ListBucketResult>`, {
|
|
417
|
+
status: 200
|
|
418
|
+
});
|
|
419
|
+
}));
|
|
420
|
+
const searchQuery = 'key like /pdf$/';
|
|
421
|
+
const { result } = renderHook(()=>useSearchObjects({
|
|
422
|
+
Bucket: 'test-bucket',
|
|
423
|
+
Prefix: '',
|
|
424
|
+
MaxKeys: 100,
|
|
425
|
+
Delimiter: '/',
|
|
426
|
+
Query: searchQuery
|
|
427
|
+
}), {
|
|
428
|
+
wrapper: createTestWrapper()
|
|
429
|
+
});
|
|
430
|
+
await waitFor(()=>{
|
|
431
|
+
expect(result.current.isSuccess).toBe(true);
|
|
432
|
+
});
|
|
433
|
+
expect(capturedSearchParam).toBe(searchQuery);
|
|
434
|
+
});
|
|
394
435
|
});
|
|
395
436
|
describe('Multi-Selection', ()=>{
|
|
396
437
|
it('integrates with MultiSelectableContent', async ()=>{
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Icon, spacing } from "@scality/core-ui";
|
|
3
3
|
import { Box, Button } from "@scality/core-ui/dist/next";
|
|
4
|
-
const BucketConfigEditButton = ({ hasConfig, isLoading, onEdit, configName })=>{
|
|
4
|
+
const BucketConfigEditButton = ({ hasConfig, isLoading, onEdit, configName, disabled, tooltipOverlay })=>{
|
|
5
5
|
const action = hasConfig ? 'Edit' : 'Create';
|
|
6
6
|
return /*#__PURE__*/ jsx(Box, {
|
|
7
7
|
display: "flex",
|
|
@@ -12,10 +12,16 @@ const BucketConfigEditButton = ({ hasConfig, isLoading, onEdit, configName })=>{
|
|
|
12
12
|
variant: "outline",
|
|
13
13
|
label: action,
|
|
14
14
|
icon: /*#__PURE__*/ jsx(Icon, {
|
|
15
|
-
name: hasConfig ? '
|
|
15
|
+
name: hasConfig ? 'Pencil' : 'Create-add'
|
|
16
16
|
}),
|
|
17
17
|
onClick: onEdit,
|
|
18
|
-
"aria-label": `${action} ${configName}
|
|
18
|
+
"aria-label": `${action} ${configName}`,
|
|
19
|
+
disabled: disabled,
|
|
20
|
+
...tooltipOverlay && {
|
|
21
|
+
tooltip: {
|
|
22
|
+
overlay: tooltipOverlay
|
|
23
|
+
}
|
|
24
|
+
}
|
|
19
25
|
})
|
|
20
26
|
});
|
|
21
27
|
};
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Form, FormGroup, FormSection, Icon, Loader, Stack, Text, useToast } from "@scality/core-ui";
|
|
3
|
-
import { Box, Button, CopyButton } from "@scality/core-ui/dist/next";
|
|
4
|
-
import { useCallback, useMemo } from "react";
|
|
3
|
+
import { Box, Button, CopyButton, Editor } from "@scality/core-ui/dist/next";
|
|
4
|
+
import { useCallback, useEffect, useMemo } from "react";
|
|
5
5
|
import { Controller } from "react-hook-form";
|
|
6
6
|
import { useParams } from "react-router";
|
|
7
|
-
import { useBucketConfigEditor, useDeleteBucketCors, useGetBucketCors, useSetBucketCors } from "../../hooks/index.js";
|
|
8
|
-
import {
|
|
7
|
+
import { useBucketConfigEditor, useDeleteBucketCors, useGetBucketCors, useISVBucketStatus, useSetBucketCors } from "../../hooks/index.js";
|
|
8
|
+
import { useDataBrowserNavigate } from "../../hooks/useDataBrowserNavigate.js";
|
|
9
|
+
import { isNotFoundError } from "../../utils/errorHandling.js";
|
|
9
10
|
const DEFAULT_CORS_TEMPLATE = `[
|
|
10
11
|
{
|
|
11
12
|
"AllowedHeaders": [
|
|
12
13
|
"Authorization"
|
|
13
14
|
],
|
|
14
15
|
"AllowedMethods": [
|
|
15
|
-
"GET"
|
|
16
|
+
"GET",
|
|
17
|
+
"PUT"
|
|
16
18
|
],
|
|
17
19
|
"AllowedOrigins": [
|
|
18
20
|
"*"
|
|
@@ -47,22 +49,35 @@ const validateCorsConfig = (content)=>{
|
|
|
47
49
|
const BucketCorsPage = ()=>{
|
|
48
50
|
const { bucketName } = useParams();
|
|
49
51
|
const { showToast } = useToast();
|
|
52
|
+
const { isISVManaged, isLoading: isISVLoading } = useISVBucketStatus(bucketName);
|
|
53
|
+
const navigate = useDataBrowserNavigate();
|
|
54
|
+
useEffect(()=>{
|
|
55
|
+
if (isISVManaged) navigate(`/buckets/${bucketName}`, {
|
|
56
|
+
replace: true
|
|
57
|
+
});
|
|
58
|
+
}, [
|
|
59
|
+
isISVManaged,
|
|
60
|
+
bucketName,
|
|
61
|
+
navigate
|
|
62
|
+
]);
|
|
63
|
+
const shouldFetchData = !isISVManaged && !isISVLoading;
|
|
50
64
|
const { data: corsData, status: corsStatus, error: corsError } = useGetBucketCors({
|
|
51
65
|
Bucket: bucketName
|
|
66
|
+
}, {
|
|
67
|
+
enabled: shouldFetchData
|
|
52
68
|
});
|
|
53
69
|
const initialContent = useMemo(()=>{
|
|
70
|
+
if (isNotFoundError(corsError)) return;
|
|
54
71
|
if (corsData?.CORSRules && corsData.CORSRules.length > 0) return JSON.stringify(corsData.CORSRules);
|
|
55
72
|
}, [
|
|
56
|
-
corsData
|
|
73
|
+
corsData,
|
|
74
|
+
corsError
|
|
57
75
|
]);
|
|
58
|
-
const { form, content, isCreateMode, isValidFormat,
|
|
76
|
+
const { form, content, isCreateMode, isValidFormat, navigateToBucket, loadTemplate } = useBucketConfigEditor({
|
|
59
77
|
bucketName: bucketName,
|
|
60
78
|
initialContent,
|
|
61
79
|
defaultTemplate: DEFAULT_CORS_TEMPLATE,
|
|
62
80
|
isLoading: 'pending' === corsStatus,
|
|
63
|
-
notFoundErrorNames: [
|
|
64
|
-
'NoSuchCORSConfiguration'
|
|
65
|
-
],
|
|
66
81
|
errorInstance: corsError,
|
|
67
82
|
validate: validateCorsConfig
|
|
68
83
|
});
|
|
@@ -121,7 +136,8 @@ const BucketCorsPage = ()=>{
|
|
|
121
136
|
setError
|
|
122
137
|
]);
|
|
123
138
|
const isPending = isSaving || isDeleting;
|
|
124
|
-
|
|
139
|
+
if (isISVManaged || isISVLoading) return null;
|
|
140
|
+
const hasUnexpectedError = corsError && !isNotFoundError(corsError);
|
|
125
141
|
if ('pending' === corsStatus) return /*#__PURE__*/ jsx(Loader, {
|
|
126
142
|
centered: true,
|
|
127
143
|
size: "massive",
|
|
@@ -200,6 +216,11 @@ const BucketCorsPage = ()=>{
|
|
|
200
216
|
direction: "vertical",
|
|
201
217
|
error: errors.content?.message,
|
|
202
218
|
content: /*#__PURE__*/ jsxs(Stack, {
|
|
219
|
+
direction: "horizontal",
|
|
220
|
+
gap: "r16",
|
|
221
|
+
style: {
|
|
222
|
+
alignItems: 'flex-start'
|
|
223
|
+
},
|
|
203
224
|
children: [
|
|
204
225
|
/*#__PURE__*/ jsx(Controller, {
|
|
205
226
|
control: control,
|
|
@@ -212,17 +233,33 @@ const BucketCorsPage = ()=>{
|
|
|
212
233
|
},
|
|
213
234
|
language: "json",
|
|
214
235
|
height: "60vh",
|
|
215
|
-
width: "33rem"
|
|
216
|
-
beforeMount: handleBeforeMount
|
|
236
|
+
width: "33rem"
|
|
217
237
|
})
|
|
218
238
|
}),
|
|
219
|
-
/*#__PURE__*/
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
239
|
+
/*#__PURE__*/ jsxs(Stack, {
|
|
240
|
+
direction: "vertical",
|
|
241
|
+
gap: "r8",
|
|
242
|
+
children: [
|
|
243
|
+
/*#__PURE__*/ jsx(CopyButton, {
|
|
244
|
+
textToCopy: content,
|
|
245
|
+
label: "CORS",
|
|
246
|
+
variant: "outline"
|
|
247
|
+
}),
|
|
248
|
+
isCreateMode && !content && /*#__PURE__*/ jsx(Text, {
|
|
249
|
+
variant: "Smaller",
|
|
250
|
+
color: "textSecondary",
|
|
251
|
+
children: "Empty CORS rule"
|
|
252
|
+
}),
|
|
253
|
+
isCreateMode && !content && /*#__PURE__*/ jsx(Button, {
|
|
254
|
+
variant: "outline",
|
|
255
|
+
label: "Load a template",
|
|
256
|
+
onClick: loadTemplate,
|
|
257
|
+
type: "button",
|
|
258
|
+
style: {
|
|
259
|
+
minWidth: '9rem'
|
|
260
|
+
}
|
|
261
|
+
})
|
|
262
|
+
]
|
|
226
263
|
})
|
|
227
264
|
]
|
|
228
265
|
})
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
2
3
|
import { Tabs } from "@scality/core-ui/dist/next";
|
|
3
4
|
import { createContext, memo, useCallback, useContext, useMemo } from "react";
|
|
4
5
|
import { useParams } from "react-router";
|
|
6
|
+
import { useDataBrowserContext } from "../providers/DataBrowserProvider.js";
|
|
5
7
|
import { useDataBrowserUICustomization } from "../../contexts/DataBrowserUICustomizationContext.js";
|
|
6
8
|
import { useGetBucketLifecycle, useGetBucketNotification, useGetBucketReplication } from "../../hooks/bucketConfiguration.js";
|
|
7
9
|
import { useDataBrowserNavigate } from "../../hooks/useDataBrowserNavigate.js";
|
|
@@ -30,12 +32,35 @@ const ExtraSectionContent = /*#__PURE__*/ memo(({ render })=>/*#__PURE__*/ jsx(F
|
|
|
30
32
|
children: render()
|
|
31
33
|
}));
|
|
32
34
|
ExtraSectionContent.displayName = 'BucketDetails.ExtraSectionContent';
|
|
35
|
+
const LIST_BUCKETS_QUERY_KEY = 'ListBuckets';
|
|
33
36
|
const OverviewTab = /*#__PURE__*/ memo(()=>{
|
|
34
37
|
const { bucketName, navigate } = useBucketDetailsContext();
|
|
35
38
|
const { extraBucketOverviewSections } = useDataBrowserUICustomization();
|
|
39
|
+
const queryClient = useQueryClient();
|
|
40
|
+
const { s3ConfigIdentifier } = useDataBrowserContext();
|
|
41
|
+
const handleDeleteSuccess = useCallback(()=>{
|
|
42
|
+
queryClient.setQueriesData({
|
|
43
|
+
queryKey: [
|
|
44
|
+
s3ConfigIdentifier,
|
|
45
|
+
LIST_BUCKETS_QUERY_KEY
|
|
46
|
+
]
|
|
47
|
+
}, (prev)=>prev?.Buckets ? {
|
|
48
|
+
...prev,
|
|
49
|
+
Buckets: prev.Buckets.filter((b)=>b.Name !== bucketName)
|
|
50
|
+
} : prev);
|
|
51
|
+
navigate('/buckets');
|
|
52
|
+
}, [
|
|
53
|
+
queryClient,
|
|
54
|
+
s3ConfigIdentifier,
|
|
55
|
+
navigate,
|
|
56
|
+
bucketName
|
|
57
|
+
]);
|
|
36
58
|
const renderDeleteButton = useCallback((name)=>/*#__PURE__*/ jsx(DeleteBucketButton, {
|
|
37
|
-
bucketName: name
|
|
38
|
-
|
|
59
|
+
bucketName: name,
|
|
60
|
+
onDeleteSuccess: handleDeleteSuccess
|
|
61
|
+
}), [
|
|
62
|
+
handleDeleteSuccess
|
|
63
|
+
]);
|
|
39
64
|
const renderEmptyButton = useCallback((name)=>/*#__PURE__*/ jsx(EmptyBucketButton, {
|
|
40
65
|
bucketName: name
|
|
41
66
|
}), []);
|