Skip to content

Commit 8a7ebe5

Browse files
authored
fix(storage-browser): remove key parsing in useDeleteView (#6450)
1 parent 75bf540 commit 8a7ebe5

File tree

16 files changed

+190
-65
lines changed

16 files changed

+190
-65
lines changed

.changeset/metal-dogs-attack.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@aws-amplify/ui-react-storage": patch
3+
---
4+
5+
fix(storage-browser): remove key parsing in useDeleteView

packages/react-storage/src/components/StorageBrowser/views/LocationActionView/CopyView/CopyViewProvider.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React from 'react';
22

3+
import { MessageProps } from '../../../composables/Message';
34
import { ControlsContextProvider } from '../../../controls/context';
45
import { useDisplayText } from '../../../displayText';
56

@@ -9,7 +10,7 @@ import { FoldersMessageProvider } from './FoldersMessageControl';
910
import { FoldersPaginationProvider } from './FoldersPaginationControl';
1011
import { FoldersTableProvider } from './FoldersTableControl';
1112
import { CopyViewProviderProps } from './types';
12-
import { MessageProps } from '../../../composables/Message';
13+
import { getFolderText } from './utils';
1314

1415
export function CopyViewProvider({
1516
children,
@@ -30,14 +31,14 @@ export function CopyViewProvider({
3031
statusDisplayCompletedLabel,
3132
statusDisplayFailedLabel,
3233
statusDisplayQueuedLabel,
34+
title,
3335
} = displayText;
3436

3537
const {
3638
destination,
3739
folders,
3840
isProcessing,
3941
isProcessingComplete,
40-
location,
4142
statusCounts,
4243
tasks,
4344
onActionCancel,
@@ -64,11 +65,9 @@ export function CopyViewProvider({
6465
onSelectFolder,
6566
} = folders;
6667

67-
const { key: locationKey } = location ?? {};
68-
6968
const tableData = getActionViewTableData({
69+
getFolderText,
7070
tasks,
71-
locationKey,
7271
isProcessing,
7372
displayText,
7473
onTaskRemove,
@@ -110,6 +109,7 @@ export function CopyViewProvider({
110109
statusDisplayFailedLabel,
111110
statusDisplayQueuedLabel,
112111
tableData,
112+
title,
113113
}}
114114
onActionCancel={onActionCancel}
115115
onActionExit={onActionExit}

packages/react-storage/src/components/StorageBrowser/views/LocationActionView/CopyView/__tests__/CopyViewProvider.spec.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,10 @@ jest.spyOn(Config, 'useGetActionInput').mockReturnValue(() => ({
3232

3333
const getActionCompleteMessage = jest.fn();
3434
const getListFoldersResultsMessage = jest.fn();
35+
const title = 'Copy';
3536
jest.mock('../../../../displayText', () => ({
3637
useDisplayText: () => ({
37-
CopyView: { getActionCompleteMessage, getListFoldersResultsMessage },
38+
CopyView: { getActionCompleteMessage, getListFoldersResultsMessage, title },
3839
}),
3940
}));
4041

@@ -174,6 +175,7 @@ describe('CopyViewProvider', () => {
174175
isActionExitDisabled: true,
175176
isActionDestinationNavigable: false,
176177
statusCounts: processingViewState.statusCounts,
178+
title,
177179
},
178180
...actionCallbacks,
179181
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { CopyHandlerData } from '../../../../actions';
2+
import { Task } from '../../../../tasks';
3+
4+
import { getFolderText } from '../utils';
5+
6+
describe('getFolderText', () => {
7+
it('returns the expected value', () => {
8+
const expected = 'my-prefix/';
9+
const fileKey = 'my-key.jpg';
10+
const sourceKey = `${expected}${fileKey}`;
11+
12+
const task: Task<CopyHandlerData> = {
13+
data: {
14+
fileKey,
15+
key: `my-destination/${fileKey}`,
16+
sourceKey,
17+
id: 'id',
18+
lastModified: new Date(),
19+
},
20+
message: undefined,
21+
progress: undefined,
22+
status: 'QUEUED',
23+
};
24+
const output = getFolderText(task);
25+
26+
expect(output).toBe(expected);
27+
});
28+
});
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { CopyHandlerData } from '../../../actions';
2+
import { Task } from '../../../tasks';
3+
4+
export const getFolderText = ({
5+
data: { fileKey, sourceKey },
6+
}: Task<CopyHandlerData>): string => sourceKey.slice(0, -fileKey.length);

packages/react-storage/src/components/StorageBrowser/views/LocationActionView/DeleteView/DeleteViewProvider.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ import React from 'react';
22

33
import { ControlsContextProvider } from '../../../controls/context';
44
import { useDisplayText } from '../../../displayText';
5+
56
import { getActionViewTableData } from '../getActionViewTableData';
67
import { DeleteViewProviderProps } from './types';
8+
import { getFolderText } from './utils';
79

810
export function DeleteViewProvider({
911
children,
@@ -25,7 +27,6 @@ export function DeleteViewProvider({
2527
const {
2628
isProcessing,
2729
isProcessingComplete,
28-
location,
2930
statusCounts,
3031
tasks,
3132
onActionCancel,
@@ -40,9 +41,9 @@ export function DeleteViewProvider({
4041

4142
const tableData = getActionViewTableData({
4243
tasks,
43-
locationKey: location.key,
4444
isProcessing,
4545
displayText,
46+
getFolderText,
4647
onTaskRemove,
4748
});
4849

packages/react-storage/src/components/StorageBrowser/views/LocationActionView/DeleteView/__tests__/useDeleteView.spec.ts

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,43 @@ import { renderHook, act } from '@testing-library/react';
22

33
import { useStore } from '../../../../providers/store';
44
import { useAction } from '../../../../useAction';
5+
import { FileDataItem } from '../../../../actions';
56

67
import { useDeleteView } from '../useDeleteView';
78
import { INITIAL_STATUS_COUNTS } from '../../../../tasks';
89

910
jest.mock('../../../../providers/store');
1011
jest.mock('../../../../useAction');
1112

13+
const fileDataItems: FileDataItem[] = [
14+
{
15+
key: 'pretend-prefix/test-file.txt',
16+
fileKey: 'test-file.txt',
17+
lastModified: new Date(),
18+
id: 'id-1',
19+
size: 10,
20+
type: 'FILE',
21+
},
22+
{
23+
key: 'pretend-prefix/deeply-nested/test-file.txt',
24+
fileKey: 'test-file.txt',
25+
lastModified: new Date(),
26+
id: 'id-2',
27+
size: 10,
28+
type: 'FILE',
29+
},
30+
];
31+
1232
describe('useDeleteView', () => {
13-
const mockeUseAction = jest.mocked(useAction);
14-
const mockeUseStore = jest.mocked(useStore);
33+
const mockUseAction = jest.mocked(useAction);
34+
const mockUseStore = jest.mocked(useStore);
1535
const mockCancel = jest.fn();
1636
const mockDispatchStoreAction = jest.fn();
1737
const mockHandleDelete = jest.fn();
1838
const mockReset = jest.fn();
1939

2040
beforeEach(() => {
21-
mockeUseStore.mockReturnValue([
41+
mockUseStore.mockReturnValue([
2242
{
2343
actionType: 'DELETE',
2444
files: [],
@@ -33,23 +53,12 @@ describe('useDeleteView', () => {
3353
path: '',
3454
key: 'test-prefix/',
3555
},
36-
locationItems: {
37-
fileDataItems: [
38-
{
39-
key: 'pretend-prefix/test-file.txt',
40-
fileKey: 'test-file.txt',
41-
lastModified: new Date(),
42-
id: 'id',
43-
size: 10,
44-
type: 'FILE',
45-
},
46-
],
47-
},
56+
locationItems: { fileDataItems },
4857
},
4958
mockDispatchStoreAction,
5059
]);
5160

52-
mockeUseAction.mockReturnValue([
61+
mockUseAction.mockReturnValue([
5362
{
5463
isProcessing: false,
5564
isProcessingComplete: false,
@@ -88,8 +97,8 @@ describe('useDeleteView', () => {
8897
mockDispatchStoreAction.mockClear();
8998
mockHandleDelete.mockClear();
9099
mockReset.mockClear();
91-
mockeUseAction.mockReset();
92-
mockeUseStore.mockReset();
100+
mockUseAction.mockReset();
101+
mockUseStore.mockReset();
93102
});
94103

95104
it('should return the correct initial state', () => {
@@ -151,4 +160,14 @@ describe('useDeleteView', () => {
151160
type: 'RESET_ACTION_TYPE',
152161
});
153162
});
163+
164+
it('provides the unmodified value of `fileDataItems` to `useAction` as `items`', () => {
165+
renderHook(() => useDeleteView());
166+
167+
expect(mockUseAction).toHaveBeenCalledTimes(1);
168+
expect(mockUseAction).toHaveBeenCalledWith(
169+
'delete',
170+
expect.objectContaining({ items: fileDataItems })
171+
);
172+
});
154173
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { DeleteHandlerData } from '../../../../actions';
2+
import { Task } from '../../../../tasks';
3+
4+
import { getFolderText } from '../utils';
5+
6+
describe('getFolderText', () => {
7+
it('returns the expected value', () => {
8+
const expected = 'my-prefix/';
9+
const fileKey = 'my-key.jpg';
10+
const key = `${expected}${fileKey}`;
11+
12+
const task: Task<DeleteHandlerData> = {
13+
data: {
14+
fileKey,
15+
key,
16+
id: 'id',
17+
},
18+
message: undefined,
19+
progress: undefined,
20+
status: 'QUEUED',
21+
};
22+
const output = getFolderText(task);
23+
24+
expect(output).toBe(expected);
25+
});
26+
});

packages/react-storage/src/components/StorageBrowser/views/LocationActionView/DeleteView/useDeleteView.ts

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,26 @@
11
import React from 'react';
22
import { isFunction } from '@aws-amplify/ui';
33

4+
import { FileDataItem } from '../../../actions';
45
import { useStore } from '../../../providers/store';
56
import { Task } from '../../../tasks';
67
import { useAction } from '../../../useAction';
78

89
import { DeleteViewState, UseDeleteViewOptions } from './types';
910

11+
// assign to constant to ensure referential equality
12+
const EMPTY_ITEMS: FileDataItem[] = [];
13+
1014
export const useDeleteView = (
1115
options?: UseDeleteViewOptions
1216
): DeleteViewState => {
1317
const { onExit: _onExit } = options ?? {};
1418

1519
const [{ location, locationItems }, dispatchStoreAction] = useStore();
16-
const { fileDataItems } = locationItems;
17-
const { current, key } = location;
18-
19-
const data = React.useMemo(
20-
() =>
21-
!fileDataItems
22-
? []
23-
: fileDataItems.map((item) => ({
24-
...item,
25-
key: `${key}${item.fileKey}`,
26-
})),
27-
[fileDataItems, key]
28-
);
20+
const { current } = location;
21+
const { fileDataItems: items = EMPTY_ITEMS } = locationItems;
2922

30-
const [processState, handleProcess] = useAction('delete', { items: data });
23+
const [processState, handleProcess] = useAction('delete', { items });
3124

3225
const { isProcessing, isProcessingComplete, statusCounts, tasks } =
3326
processState;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { DeleteHandlerData } from '../../../actions';
2+
import { Task } from '../../../tasks';
3+
4+
export const getFolderText = ({
5+
data: { fileKey, key },
6+
}: Task<DeleteHandlerData>): string => key.slice(0, -fileKey.length);

0 commit comments

Comments
 (0)