@scality/data-browser-library 1.1.5 → 1.1.7
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__/BucketReplicationFormPage.test.js +207 -2
- package/dist/components/__tests__/CreateFolderButton.test.js +67 -0
- package/dist/components/__tests__/DeleteObjectButton.test.js +249 -26
- package/dist/components/__tests__/ObjectList.test.js +65 -22
- package/dist/components/__tests__/UploadButton.test.js +80 -0
- package/dist/components/buckets/BucketReplicationFormPage.js +114 -22
- package/dist/components/objects/CreateFolderButton.js +2 -1
- package/dist/components/objects/DeleteObjectButton.js +89 -43
- package/dist/components/objects/ObjectList.js +21 -0
- package/dist/components/objects/UploadButton.js +2 -1
- package/dist/components/ui/DeleteObjectModalContent.d.ts +4 -1
- package/dist/components/ui/DeleteObjectModalContent.js +57 -18
- package/dist/hooks/__tests__/useDeleteFolder.test.d.ts +1 -0
- package/dist/hooks/__tests__/useDeleteFolder.test.js +203 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.js +2 -1
- package/dist/hooks/useDeleteFolder.d.ts +6 -0
- package/dist/hooks/useDeleteFolder.js +40 -0
- package/package.json +1 -1
|
@@ -112,7 +112,10 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
112
112
|
},
|
|
113
113
|
status: 'success'
|
|
114
114
|
});
|
|
115
|
-
mockUseFeatures.
|
|
115
|
+
mockUseFeatures.mockImplementation((feature)=>{
|
|
116
|
+
if ('replicationAdvanced' === feature) return true;
|
|
117
|
+
return false;
|
|
118
|
+
});
|
|
116
119
|
mockUseISVBucketStatus.mockReturnValue({
|
|
117
120
|
isVeeamBucket: false,
|
|
118
121
|
isCommvaultBucket: false,
|
|
@@ -1971,7 +1974,10 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
1971
1974
|
});
|
|
1972
1975
|
});
|
|
1973
1976
|
it('shows Additional Options section when replicationAdvanced is enabled', ()=>{
|
|
1974
|
-
mockUseFeatures.
|
|
1977
|
+
mockUseFeatures.mockImplementation((feature)=>{
|
|
1978
|
+
if ('replicationAdvanced' === feature) return true;
|
|
1979
|
+
return false;
|
|
1980
|
+
});
|
|
1975
1981
|
renderBucketReplicationFormPage();
|
|
1976
1982
|
expect(screen.getByText('Replication Time Control (RTC)')).toBeInTheDocument();
|
|
1977
1983
|
expect(screen.getByText('RTC metrics and notifications')).toBeInTheDocument();
|
|
@@ -1979,4 +1985,203 @@ describe('BucketReplicationFormPage', ()=>{
|
|
|
1979
1985
|
expect(screen.getByText('Delete marker replication')).toBeInTheDocument();
|
|
1980
1986
|
});
|
|
1981
1987
|
});
|
|
1988
|
+
describe('Feature Flag - replicationV1', ()=>{
|
|
1989
|
+
it('submits rule in V1 format when replicationV1 feature is enabled', async ()=>{
|
|
1990
|
+
mockUseFeatures.mockImplementation((feature)=>{
|
|
1991
|
+
if ('replicationV1' === feature) return true;
|
|
1992
|
+
return false;
|
|
1993
|
+
});
|
|
1994
|
+
mockUseGetBucketReplication.mockReturnValue({
|
|
1995
|
+
data: {
|
|
1996
|
+
ReplicationConfiguration: {
|
|
1997
|
+
Role: '',
|
|
1998
|
+
Rules: []
|
|
1999
|
+
}
|
|
2000
|
+
},
|
|
2001
|
+
status: 'success'
|
|
2002
|
+
});
|
|
2003
|
+
mockSuccessSubmit(mockMutate);
|
|
2004
|
+
renderBucketReplicationFormPage();
|
|
2005
|
+
await user_event.type(screen.getByRole('textbox', {
|
|
2006
|
+
name: /role arn/i
|
|
2007
|
+
}), 'arn:aws:iam::123456789012:role/replication');
|
|
2008
|
+
await user_event.type(screen.getByRole('textbox', {
|
|
2009
|
+
name: /rule id/i
|
|
2010
|
+
}), 'test-rule-v1');
|
|
2011
|
+
const targetBucketSelect = screen.getByLabelText(/target bucket/i);
|
|
2012
|
+
await user_event.click(targetBucketSelect);
|
|
2013
|
+
await user_event.click(screen.getByRole('option', {
|
|
2014
|
+
name: 'destination-bucket'
|
|
2015
|
+
}));
|
|
2016
|
+
await submitForm('create');
|
|
2017
|
+
await waitFor(()=>{
|
|
2018
|
+
expect(mockMutate).toHaveBeenCalled();
|
|
2019
|
+
});
|
|
2020
|
+
const submittedRule = mockMutate.mock.calls[0][0].ReplicationConfiguration.Rules[0];
|
|
2021
|
+
expect(submittedRule.Prefix).toBe('');
|
|
2022
|
+
expect(submittedRule.ID).toBe('test-rule-v1');
|
|
2023
|
+
expect(submittedRule.Status).toBe('Enabled');
|
|
2024
|
+
expect(submittedRule.Destination.Bucket).toBe('arn:aws:s3:::destination-bucket');
|
|
2025
|
+
expect(submittedRule).not.toHaveProperty('Filter');
|
|
2026
|
+
expect(submittedRule).not.toHaveProperty('Priority');
|
|
2027
|
+
expect(submittedRule).not.toHaveProperty('DeleteMarkerReplication');
|
|
2028
|
+
expect(submittedRule).not.toHaveProperty('SourceSelectionCriteria');
|
|
2029
|
+
});
|
|
2030
|
+
it('hides V2-only fields when replicationV1 is enabled', ()=>{
|
|
2031
|
+
mockUseFeatures.mockImplementation((feature)=>{
|
|
2032
|
+
if ('replicationV1' === feature) return true;
|
|
2033
|
+
return false;
|
|
2034
|
+
});
|
|
2035
|
+
mockUseGetBucketReplication.mockReturnValue({
|
|
2036
|
+
data: {
|
|
2037
|
+
ReplicationConfiguration: {
|
|
2038
|
+
Role: '',
|
|
2039
|
+
Rules: []
|
|
2040
|
+
}
|
|
2041
|
+
},
|
|
2042
|
+
status: 'success'
|
|
2043
|
+
});
|
|
2044
|
+
renderBucketReplicationFormPage();
|
|
2045
|
+
expect(screen.getByRole('textbox', {
|
|
2046
|
+
name: /role arn/i
|
|
2047
|
+
})).toBeInTheDocument();
|
|
2048
|
+
expect(screen.getByRole('textbox', {
|
|
2049
|
+
name: /rule id/i
|
|
2050
|
+
})).toBeInTheDocument();
|
|
2051
|
+
expect(screen.queryByRole('spinbutton', {
|
|
2052
|
+
name: /rule priority/i
|
|
2053
|
+
})).not.toBeInTheDocument();
|
|
2054
|
+
expect(screen.queryByText('Encryption')).not.toBeInTheDocument();
|
|
2055
|
+
expect(screen.queryByText('Additional Options')).not.toBeInTheDocument();
|
|
2056
|
+
});
|
|
2057
|
+
it('shows simplified destination without cross-account in V1 mode', ()=>{
|
|
2058
|
+
mockUseFeatures.mockImplementation((feature)=>{
|
|
2059
|
+
if ('replicationV1' === feature) return true;
|
|
2060
|
+
return false;
|
|
2061
|
+
});
|
|
2062
|
+
mockUseGetBucketReplication.mockReturnValue({
|
|
2063
|
+
data: {
|
|
2064
|
+
ReplicationConfiguration: {
|
|
2065
|
+
Role: '',
|
|
2066
|
+
Rules: []
|
|
2067
|
+
}
|
|
2068
|
+
},
|
|
2069
|
+
status: 'success'
|
|
2070
|
+
});
|
|
2071
|
+
renderBucketReplicationFormPage();
|
|
2072
|
+
expect(screen.getByText(/Target Bucket/i)).toBeInTheDocument();
|
|
2073
|
+
expect(screen.queryByText(/Same account destination/i)).not.toBeInTheDocument();
|
|
2074
|
+
});
|
|
2075
|
+
it('shows only prefix filter (no filter type selector) in V1 mode', ()=>{
|
|
2076
|
+
mockUseFeatures.mockImplementation((feature)=>{
|
|
2077
|
+
if ('replicationV1' === feature) return true;
|
|
2078
|
+
return false;
|
|
2079
|
+
});
|
|
2080
|
+
mockUseGetBucketReplication.mockReturnValue({
|
|
2081
|
+
data: {
|
|
2082
|
+
ReplicationConfiguration: {
|
|
2083
|
+
Role: '',
|
|
2084
|
+
Rules: []
|
|
2085
|
+
}
|
|
2086
|
+
},
|
|
2087
|
+
status: 'success'
|
|
2088
|
+
});
|
|
2089
|
+
renderBucketReplicationFormPage();
|
|
2090
|
+
expect(screen.getByRole('textbox', {
|
|
2091
|
+
name: /prefix/i
|
|
2092
|
+
})).toBeInTheDocument();
|
|
2093
|
+
expect(screen.queryByText('All objects')).not.toBeInTheDocument();
|
|
2094
|
+
expect(screen.queryByText('Tags filter')).not.toBeInTheDocument();
|
|
2095
|
+
});
|
|
2096
|
+
it('allows submission without priority in V1 mode', async ()=>{
|
|
2097
|
+
mockUseFeatures.mockImplementation((feature)=>{
|
|
2098
|
+
if ('replicationV1' === feature) return true;
|
|
2099
|
+
return false;
|
|
2100
|
+
});
|
|
2101
|
+
mockUseGetBucketReplication.mockReturnValue({
|
|
2102
|
+
data: {
|
|
2103
|
+
ReplicationConfiguration: {
|
|
2104
|
+
Role: '',
|
|
2105
|
+
Rules: []
|
|
2106
|
+
}
|
|
2107
|
+
},
|
|
2108
|
+
status: 'success'
|
|
2109
|
+
});
|
|
2110
|
+
mockSuccessSubmit(mockMutate);
|
|
2111
|
+
renderBucketReplicationFormPage();
|
|
2112
|
+
await user_event.type(screen.getByRole('textbox', {
|
|
2113
|
+
name: /role arn/i
|
|
2114
|
+
}), 'arn:aws:iam::123456789012:role/repl');
|
|
2115
|
+
await user_event.type(screen.getByRole('textbox', {
|
|
2116
|
+
name: /rule id/i
|
|
2117
|
+
}), 'v1-rule');
|
|
2118
|
+
const targetBucketSelect = screen.getByLabelText(/target bucket/i);
|
|
2119
|
+
await user_event.click(targetBucketSelect);
|
|
2120
|
+
await user_event.click(screen.getByRole('option', {
|
|
2121
|
+
name: 'destination-bucket'
|
|
2122
|
+
}));
|
|
2123
|
+
await submitForm('create');
|
|
2124
|
+
await waitFor(()=>{
|
|
2125
|
+
expect(mockMutate).toHaveBeenCalled();
|
|
2126
|
+
});
|
|
2127
|
+
const submittedRule = mockMutate.mock.calls[0][0].ReplicationConfiguration.Rules[0];
|
|
2128
|
+
expect(submittedRule.Prefix).toBe('');
|
|
2129
|
+
expect(submittedRule).not.toHaveProperty('Priority');
|
|
2130
|
+
});
|
|
2131
|
+
it('loads existing V1 rule (with Prefix at rule level) for editing', async ()=>{
|
|
2132
|
+
mockUseFeatures.mockImplementation((feature)=>{
|
|
2133
|
+
if ('replicationV1' === feature) return true;
|
|
2134
|
+
return false;
|
|
2135
|
+
});
|
|
2136
|
+
const v1Rule = {
|
|
2137
|
+
ID: 'existing-v1-rule',
|
|
2138
|
+
Status: 'Enabled',
|
|
2139
|
+
Prefix: 'documents/',
|
|
2140
|
+
Destination: {
|
|
2141
|
+
Bucket: 'arn:aws:s3:::destination-bucket',
|
|
2142
|
+
StorageClass: 'STANDARD'
|
|
2143
|
+
}
|
|
2144
|
+
};
|
|
2145
|
+
mockUseGetBucketReplication.mockReturnValue({
|
|
2146
|
+
data: {
|
|
2147
|
+
ReplicationConfiguration: {
|
|
2148
|
+
Role: 'arn:aws:iam::123456789012:role/repl',
|
|
2149
|
+
Rules: [
|
|
2150
|
+
v1Rule
|
|
2151
|
+
]
|
|
2152
|
+
}
|
|
2153
|
+
},
|
|
2154
|
+
status: 'success'
|
|
2155
|
+
});
|
|
2156
|
+
renderBucketReplicationFormPage('test-bucket', 'existing-v1-rule');
|
|
2157
|
+
await waitFor(()=>{
|
|
2158
|
+
expect(screen.getByText('existing-v1-rule')).toBeInTheDocument();
|
|
2159
|
+
});
|
|
2160
|
+
const prefixInput = screen.getByRole('textbox', {
|
|
2161
|
+
name: /prefix/i
|
|
2162
|
+
});
|
|
2163
|
+
expect(prefixInput.value).toBe('documents/');
|
|
2164
|
+
});
|
|
2165
|
+
it('shows all V2 fields when replicationV1 is not enabled', ()=>{
|
|
2166
|
+
mockUseFeatures.mockImplementation((feature)=>{
|
|
2167
|
+
if ('replicationAdvanced' === feature) return true;
|
|
2168
|
+
return false;
|
|
2169
|
+
});
|
|
2170
|
+
mockUseGetBucketReplication.mockReturnValue({
|
|
2171
|
+
data: {
|
|
2172
|
+
ReplicationConfiguration: {
|
|
2173
|
+
Role: '',
|
|
2174
|
+
Rules: []
|
|
2175
|
+
}
|
|
2176
|
+
},
|
|
2177
|
+
status: 'success'
|
|
2178
|
+
});
|
|
2179
|
+
renderBucketReplicationFormPage();
|
|
2180
|
+
expect(screen.getByRole('spinbutton', {
|
|
2181
|
+
name: /rule priority/i
|
|
2182
|
+
})).toBeInTheDocument();
|
|
2183
|
+
expect(screen.getByText(/^Encryption/)).toBeInTheDocument();
|
|
2184
|
+
expect(screen.getByText(/^Additional Options/)).toBeInTheDocument();
|
|
2185
|
+
});
|
|
2186
|
+
});
|
|
1982
2187
|
});
|
|
@@ -3,11 +3,30 @@ import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
|
|
3
3
|
import user_event from "@testing-library/user-event";
|
|
4
4
|
import { createTestWrapper } from "../../test/testUtils.js";
|
|
5
5
|
import { CreateFolderButton } from "../objects/CreateFolderButton.js";
|
|
6
|
+
const mockMutate = jest.fn();
|
|
7
|
+
jest.mock('../../hooks', ()=>({
|
|
8
|
+
...jest.requireActual('../../hooks'),
|
|
9
|
+
useCreateFolder: ()=>({
|
|
10
|
+
mutate: mockMutate,
|
|
11
|
+
mutateAsync: jest.fn(),
|
|
12
|
+
reset: jest.fn(),
|
|
13
|
+
isPending: false,
|
|
14
|
+
isIdle: true,
|
|
15
|
+
isError: false,
|
|
16
|
+
isSuccess: false,
|
|
17
|
+
status: 'idle',
|
|
18
|
+
data: void 0,
|
|
19
|
+
error: null
|
|
20
|
+
})
|
|
21
|
+
}));
|
|
6
22
|
describe('CreateFolderButton', ()=>{
|
|
7
23
|
const defaultProps = {
|
|
8
24
|
bucket: 'test-bucket',
|
|
9
25
|
prefix: 'test-prefix'
|
|
10
26
|
};
|
|
27
|
+
beforeEach(()=>{
|
|
28
|
+
mockMutate.mockClear();
|
|
29
|
+
});
|
|
11
30
|
const renderCreateFolderButton = (props = {})=>{
|
|
12
31
|
const Wrapper = createTestWrapper();
|
|
13
32
|
return render(/*#__PURE__*/ jsx(Wrapper, {
|
|
@@ -144,4 +163,52 @@ describe('CreateFolderButton', ()=>{
|
|
|
144
163
|
await user_event.type(input, '/invalid');
|
|
145
164
|
expect(saveButton).toBeDisabled();
|
|
146
165
|
});
|
|
166
|
+
it('constructs correct key when prefix has trailing slash', async ()=>{
|
|
167
|
+
renderCreateFolderButton({
|
|
168
|
+
prefix: 'documents/'
|
|
169
|
+
});
|
|
170
|
+
fireEvent.click(screen.getByRole('button', {
|
|
171
|
+
name: /folder/i
|
|
172
|
+
}));
|
|
173
|
+
await waitFor(()=>screen.getByText('Create a folder'));
|
|
174
|
+
await user_event.type(screen.getByRole('textbox'), 'sub-folder');
|
|
175
|
+
fireEvent.click(screen.getByRole('button', {
|
|
176
|
+
name: /save/i
|
|
177
|
+
}));
|
|
178
|
+
expect(mockMutate).toHaveBeenCalledWith(expect.objectContaining({
|
|
179
|
+
Key: 'documents/sub-folder/'
|
|
180
|
+
}), expect.anything());
|
|
181
|
+
});
|
|
182
|
+
it('constructs correct key when prefix has no trailing slash', async ()=>{
|
|
183
|
+
renderCreateFolderButton({
|
|
184
|
+
prefix: 'documents'
|
|
185
|
+
});
|
|
186
|
+
fireEvent.click(screen.getByRole('button', {
|
|
187
|
+
name: /folder/i
|
|
188
|
+
}));
|
|
189
|
+
await waitFor(()=>screen.getByText('Create a folder'));
|
|
190
|
+
await user_event.type(screen.getByRole('textbox'), 'sub-folder');
|
|
191
|
+
fireEvent.click(screen.getByRole('button', {
|
|
192
|
+
name: /save/i
|
|
193
|
+
}));
|
|
194
|
+
expect(mockMutate).toHaveBeenCalledWith(expect.objectContaining({
|
|
195
|
+
Key: 'documents/sub-folder/'
|
|
196
|
+
}), expect.anything());
|
|
197
|
+
});
|
|
198
|
+
it('constructs correct key when prefix is empty', async ()=>{
|
|
199
|
+
renderCreateFolderButton({
|
|
200
|
+
prefix: ''
|
|
201
|
+
});
|
|
202
|
+
fireEvent.click(screen.getByRole('button', {
|
|
203
|
+
name: /folder/i
|
|
204
|
+
}));
|
|
205
|
+
await waitFor(()=>screen.getByText('Create a folder'));
|
|
206
|
+
await user_event.type(screen.getByRole('textbox'), 'new-folder');
|
|
207
|
+
fireEvent.click(screen.getByRole('button', {
|
|
208
|
+
name: /save/i
|
|
209
|
+
}));
|
|
210
|
+
expect(mockMutate).toHaveBeenCalledWith(expect.objectContaining({
|
|
211
|
+
Key: 'new-folder/'
|
|
212
|
+
}), expect.anything());
|
|
213
|
+
});
|
|
147
214
|
});
|