@aws-amplify/ui-react-storage 3.15.0 → 3.17.0
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/browser.js +1 -1
- package/dist/{createStorageBrowser-CG-6mXiT.js → createStorageBrowser-De4hcP-u.js} +710 -158
- package/dist/esm/browser.mjs +1 -0
- package/dist/esm/components/StorageBrowser/ErrorBoundary/ErrorBoundary.mjs +1 -4
- package/dist/esm/components/StorageBrowser/actions/configs/defaults.mjs +13 -3
- package/dist/esm/components/StorageBrowser/actions/handlers/delete.mjs +39 -8
- package/dist/esm/components/StorageBrowser/components/ComponentsProvider.mjs +1 -4
- package/dist/esm/components/StorageBrowser/components/base/preview/DownloadButton.mjs +1 -4
- package/dist/esm/components/StorageBrowser/components/composables/ActionConfirmationModal.mjs +34 -0
- package/dist/esm/components/StorageBrowser/components/composables/defaults.mjs +2 -0
- package/dist/esm/components/StorageBrowser/components/elements/definitions.mjs +2 -2
- package/dist/esm/components/StorageBrowser/configuration/paginationContext.mjs +15 -0
- package/dist/esm/components/StorageBrowser/controls/ActionConfirmationModalControl.mjs +12 -0
- package/dist/esm/components/StorageBrowser/controls/DataTableControl.mjs +1 -4
- package/dist/esm/components/StorageBrowser/controls/hooks/useActionConfirmationModal.mjs +17 -0
- package/dist/esm/components/StorageBrowser/createStorageBrowser/StorageBrowserDefault.mjs +9 -4
- package/dist/esm/components/StorageBrowser/createStorageBrowser/createProvider.mjs +11 -9
- package/dist/esm/components/StorageBrowser/createStorageBrowser/createStorageBrowser.mjs +10 -5
- package/dist/esm/components/StorageBrowser/displayText/libraries/en/deleteView.mjs +117 -5
- package/dist/esm/components/StorageBrowser/displayText/libraries/en/locationDetailView.mjs +1 -0
- package/dist/esm/components/StorageBrowser/displayText/libraries/en/shared.mjs +1 -0
- package/dist/esm/components/StorageBrowser/locationItems/context.mjs +17 -14
- package/dist/esm/components/StorageBrowser/locationItems/utils.mjs +38 -0
- package/dist/esm/components/StorageBrowser/store/validateStoreProps.mjs +1 -1
- package/dist/esm/components/StorageBrowser/tasks/useProcessTasks.mjs +7 -4
- package/dist/esm/components/StorageBrowser/useAction/useHandler.mjs +1 -0
- package/dist/esm/components/StorageBrowser/useAction/useListFolderItems.mjs +1 -0
- package/dist/esm/components/StorageBrowser/useAction/useListLocationItems.mjs +1 -0
- package/dist/esm/components/StorageBrowser/useAction/utils.mjs +0 -5
- package/dist/esm/components/StorageBrowser/utils/validatePageSize.mjs +12 -0
- package/dist/esm/components/StorageBrowser/views/LocationActionView/CopyView/CopyView.mjs +1 -4
- package/dist/esm/components/StorageBrowser/views/LocationActionView/CopyView/CopyViewProvider.mjs +5 -4
- package/dist/esm/components/StorageBrowser/views/LocationActionView/CopyView/FoldersMessageControl.mjs +1 -4
- package/dist/esm/components/StorageBrowser/views/LocationActionView/CopyView/useCopyView.mjs +1 -4
- package/dist/esm/components/StorageBrowser/views/LocationActionView/CopyView/useFolders.mjs +1 -4
- package/dist/esm/components/StorageBrowser/views/LocationActionView/CreateFolderView/CreateFolderView.mjs +1 -4
- package/dist/esm/components/StorageBrowser/views/LocationActionView/CreateFolderView/useCreateFolderView.mjs +1 -4
- package/dist/esm/components/StorageBrowser/views/LocationActionView/DeleteView/DeleteView.mjs +6 -6
- package/dist/esm/components/StorageBrowser/views/LocationActionView/DeleteView/DeleteViewProvider.mjs +7 -6
- package/dist/esm/components/StorageBrowser/views/LocationActionView/DeleteView/useDeleteView.mjs +70 -7
- package/dist/esm/components/StorageBrowser/views/LocationActionView/DeleteView/utils.mjs +87 -0
- package/dist/esm/components/StorageBrowser/views/LocationActionView/DownloadView/DownloadView.mjs +1 -4
- package/dist/esm/components/StorageBrowser/views/LocationActionView/DownloadView/DownloadViewProvider.mjs +9 -0
- package/dist/esm/components/StorageBrowser/views/LocationActionView/DownloadView/useDownloadView.mjs +1 -4
- package/dist/esm/components/StorageBrowser/views/LocationActionView/UploadView/UploadView.mjs +3 -6
- package/dist/esm/components/StorageBrowser/views/LocationActionView/UploadView/UploadViewProvider.mjs +3 -0
- package/dist/esm/components/StorageBrowser/views/LocationActionView/UploadView/useUploadView.mjs +11 -12
- package/dist/esm/components/StorageBrowser/views/LocationDetailView/LocationDetailView.mjs +1 -4
- package/dist/esm/components/StorageBrowser/views/LocationDetailView/LocationDetailViewProvider.mjs +2 -1
- package/dist/esm/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/getFolderRowContent.mjs +38 -27
- package/dist/esm/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/getLocationDetailViewTableData.mjs +8 -1
- package/dist/esm/components/StorageBrowser/views/LocationDetailView/useLocationDetailView.mjs +24 -20
- package/dist/esm/components/StorageBrowser/views/LocationsView/LocationsView.mjs +1 -4
- package/dist/esm/components/StorageBrowser/views/LocationsView/LocationsViewProvider.mjs +1 -4
- package/dist/esm/components/StorageBrowser/views/LocationsView/useLocationsView.mjs +13 -10
- package/dist/esm/components/StorageBrowser/views/context/actionViews.mjs +12 -8
- package/dist/esm/components/StorageBrowser/views/context/primaryViews.mjs +9 -4
- package/dist/esm/components/StorageBrowser/views/hooks/usePaginate.mjs +18 -7
- package/dist/esm/components/StorageBrowser/views/utils/tableResolvers/constants.mjs +10 -1
- package/dist/esm/components/StorageBrowser/views/utils/tableResolvers/deleteResolvers.mjs +123 -13
- package/dist/esm/components/StorageBrowser/views/utils/tableResolvers/utils.mjs +3 -3
- package/dist/esm/version.mjs +1 -1
- package/dist/index.js +1 -1
- package/dist/styles.css +83 -1
- package/dist/types/components/StorageBrowser/StorageBrowserAmplify.d.ts +3 -1
- package/dist/types/components/StorageBrowser/actions/handlers/delete.d.ts +5 -3
- package/dist/types/components/StorageBrowser/actions/handlers/types.d.ts +15 -1
- package/dist/types/components/StorageBrowser/components/composables/ActionConfirmationModal.d.ts +12 -0
- package/dist/types/components/StorageBrowser/components/composables/types.d.ts +2 -0
- package/dist/types/components/StorageBrowser/configuration/index.d.ts +2 -0
- package/dist/types/components/StorageBrowser/configuration/paginationContext.d.ts +12 -0
- package/dist/types/components/StorageBrowser/controls/ActionConfirmationModalControl.d.ts +2 -0
- package/dist/types/components/StorageBrowser/controls/hooks/useActionConfirmationModal.d.ts +2 -0
- package/dist/types/components/StorageBrowser/controls/index.d.ts +1 -0
- package/dist/types/components/StorageBrowser/controls/types.d.ts +4 -0
- package/dist/types/components/StorageBrowser/createStorageBrowser/types.d.ts +7 -1
- package/dist/types/components/StorageBrowser/displayText/types.d.ts +7 -0
- package/dist/types/components/StorageBrowser/locationItems/context.d.ts +12 -3
- package/dist/types/components/StorageBrowser/locationItems/index.d.ts +1 -0
- package/dist/types/components/StorageBrowser/locationItems/utils.d.ts +27 -0
- package/dist/types/components/StorageBrowser/store/types.d.ts +7 -0
- package/dist/types/components/StorageBrowser/tasks/types.d.ts +7 -2
- package/dist/types/components/StorageBrowser/utils/index.d.ts +1 -0
- package/dist/types/components/StorageBrowser/utils/validatePageSize.d.ts +1 -0
- package/dist/types/components/StorageBrowser/views/LocationActionView/DeleteView/types.d.ts +5 -0
- package/dist/types/components/StorageBrowser/views/LocationActionView/DeleteView/utils.d.ts +26 -0
- package/dist/types/components/StorageBrowser/views/LocationActionView/UploadView/types.d.ts +7 -0
- package/dist/types/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/getFolderRowContent.d.ts +4 -1
- package/dist/types/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/getLocationDetailViewTableData.d.ts +3 -2
- package/dist/types/components/StorageBrowser/views/LocationDetailView/types.d.ts +10 -3
- package/dist/types/components/StorageBrowser/views/LocationsView/types.d.ts +2 -2
- package/dist/types/components/StorageBrowser/views/hooks/usePaginate.d.ts +1 -1
- package/dist/types/components/StorageBrowser/views/types.d.ts +6 -0
- package/dist/types/components/StorageBrowser/views/utils/index.d.ts +1 -1
- package/dist/types/components/StorageBrowser/views/utils/tableResolvers/constants.d.ts +1 -0
- package/dist/types/components/StorageBrowser/views/utils/tableResolvers/deleteResolvers.d.ts +5 -2
- package/dist/types/components/StorageBrowser/views/utils/tableResolvers/index.d.ts +1 -1
- package/dist/types/components/StorageBrowser/views/utils/tableResolvers/types.d.ts +4 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/version.d.ts +1 -1
- package/package.json +7 -7
package/dist/esm/browser.mjs
CHANGED
|
@@ -18,6 +18,7 @@ import './components/StorageBrowser/useAction/context.mjs';
|
|
|
18
18
|
import '@aws-amplify/ui-react-core/elements';
|
|
19
19
|
import './components/StorageBrowser/credentials/context.mjs';
|
|
20
20
|
import './components/StorageBrowser/configuration/context.mjs';
|
|
21
|
+
import './components/StorageBrowser/configuration/paginationContext.mjs';
|
|
21
22
|
import './components/StorageBrowser/displayText/context.mjs';
|
|
22
23
|
export { DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT as DefaultStorageBrowserDisplayText } from './components/StorageBrowser/displayText/libraries/en/default.mjs';
|
|
23
24
|
import './components/StorageBrowser/filePreview/context.mjs';
|
|
@@ -11,10 +11,7 @@ import '@aws-amplify/ui-react-core/elements';
|
|
|
11
11
|
import '../credentials/context.mjs';
|
|
12
12
|
import '@aws-amplify/storage/internals';
|
|
13
13
|
import '../configuration/context.mjs';
|
|
14
|
-
import '
|
|
15
|
-
import 'jszip';
|
|
16
|
-
import 'aws-amplify/storage';
|
|
17
|
-
import '../actions/configs/context.mjs';
|
|
14
|
+
import '../configuration/paginationContext.mjs';
|
|
18
15
|
import '../actions/configs/defaults.mjs';
|
|
19
16
|
import '../displayText/context.mjs';
|
|
20
17
|
import '../filePreview/context.mjs';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { hasSelectedFolders } from '../../locationItems/utils.mjs';
|
|
1
2
|
import '@aws-amplify/storage/internals';
|
|
2
3
|
import 'aws-amplify';
|
|
3
4
|
import '@aws-amplify/ui';
|
|
@@ -8,7 +9,10 @@ import 'aws-amplify/storage';
|
|
|
8
9
|
const copyActionConfig = {
|
|
9
10
|
viewName: 'CopyView',
|
|
10
11
|
actionListItem: {
|
|
11
|
-
disable: (selected) =>
|
|
12
|
+
disable: (selected) => {
|
|
13
|
+
const hasNoSelection = !selected || selected.length === 0;
|
|
14
|
+
return hasNoSelection || hasSelectedFolders(selected);
|
|
15
|
+
},
|
|
12
16
|
hide: (permissions) => !permissions.includes('write'),
|
|
13
17
|
icon: 'copy-file',
|
|
14
18
|
label: 'Copy',
|
|
@@ -18,7 +22,10 @@ const copyActionConfig = {
|
|
|
18
22
|
const deleteActionConfig = {
|
|
19
23
|
viewName: 'DeleteView',
|
|
20
24
|
actionListItem: {
|
|
21
|
-
disable: (selected) =>
|
|
25
|
+
disable: (selected) => {
|
|
26
|
+
const hasNoSelection = !selected || selected.length === 0;
|
|
27
|
+
return hasNoSelection;
|
|
28
|
+
},
|
|
22
29
|
hide: (permissions) => !permissions.includes('delete'),
|
|
23
30
|
icon: 'delete-file',
|
|
24
31
|
label: 'Delete',
|
|
@@ -46,7 +53,10 @@ const uploadActionConfig = {
|
|
|
46
53
|
const downloadActionConfig = {
|
|
47
54
|
viewName: 'DownloadView',
|
|
48
55
|
actionListItem: {
|
|
49
|
-
disable: (selected) =>
|
|
56
|
+
disable: (selected) => {
|
|
57
|
+
const hasNoSelection = !selected || selected.length === 0;
|
|
58
|
+
return hasNoSelection || hasSelectedFolders(selected);
|
|
59
|
+
},
|
|
50
60
|
hide: (permissions) => !permissions.includes('get'),
|
|
51
61
|
icon: 'download',
|
|
52
62
|
label: 'Download',
|
|
@@ -1,27 +1,58 @@
|
|
|
1
1
|
import { remove } from '@aws-amplify/storage/internals';
|
|
2
2
|
import { constructBucket } from './utils.mjs';
|
|
3
3
|
|
|
4
|
-
const deleteHandler = ({ config, data, }) => {
|
|
4
|
+
const deleteHandler = ({ config, data, options, }) => {
|
|
5
5
|
const { key } = data;
|
|
6
6
|
const { accountId, credentials, customEndpoint } = config;
|
|
7
|
-
const
|
|
7
|
+
const { onProgress } = options ?? {};
|
|
8
|
+
let cumulativeSuccessCount = 0;
|
|
9
|
+
let cumulativeFailureCount = 0;
|
|
10
|
+
let operationCancel = () => {
|
|
11
|
+
// noop
|
|
12
|
+
};
|
|
13
|
+
const cancel = () => {
|
|
14
|
+
operationCancel?.();
|
|
15
|
+
};
|
|
16
|
+
const operation = remove({
|
|
8
17
|
path: key,
|
|
9
18
|
options: {
|
|
10
19
|
bucket: constructBucket(config),
|
|
11
20
|
locationCredentialsProvider: credentials,
|
|
12
21
|
expectedBucketOwner: accountId,
|
|
13
22
|
customEndpoint,
|
|
23
|
+
onProgress: (progress) => {
|
|
24
|
+
if (!progress) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const batchSuccessCount = progress?.deleted?.length ?? 0;
|
|
28
|
+
const batchFailureCount = progress?.failed?.length ?? 0;
|
|
29
|
+
cumulativeSuccessCount += batchSuccessCount;
|
|
30
|
+
cumulativeFailureCount += batchFailureCount;
|
|
31
|
+
onProgress?.(data, {
|
|
32
|
+
successCount: cumulativeSuccessCount,
|
|
33
|
+
failureCount: cumulativeFailureCount,
|
|
34
|
+
});
|
|
35
|
+
},
|
|
14
36
|
},
|
|
37
|
+
});
|
|
38
|
+
operationCancel = operation?.cancel ? operation?.cancel : () => { };
|
|
39
|
+
const operationPromise = operation?.result ?? operation;
|
|
40
|
+
const result = operationPromise
|
|
41
|
+
?.then?.(({ path }) => {
|
|
42
|
+
return {
|
|
43
|
+
status: 'COMPLETE',
|
|
44
|
+
value: {
|
|
45
|
+
key: path,
|
|
46
|
+
successCount: cumulativeSuccessCount,
|
|
47
|
+
failureCount: cumulativeFailureCount,
|
|
48
|
+
},
|
|
49
|
+
};
|
|
15
50
|
})
|
|
16
|
-
|
|
17
|
-
status: 'COMPLETE',
|
|
18
|
-
value: { key: path },
|
|
19
|
-
}))
|
|
20
|
-
.catch((error) => {
|
|
51
|
+
?.catch?.((error) => {
|
|
21
52
|
const { message } = error;
|
|
22
53
|
return { error, message, status: 'FAILED' };
|
|
23
54
|
});
|
|
24
|
-
return { result };
|
|
55
|
+
return { result, cancel };
|
|
25
56
|
};
|
|
26
57
|
|
|
27
58
|
export { deleteHandler };
|
|
@@ -11,10 +11,7 @@ import '../useAction/context.mjs';
|
|
|
11
11
|
import '../credentials/context.mjs';
|
|
12
12
|
import '@aws-amplify/storage/internals';
|
|
13
13
|
import '../configuration/context.mjs';
|
|
14
|
-
import '
|
|
15
|
-
import 'jszip';
|
|
16
|
-
import 'aws-amplify/storage';
|
|
17
|
-
import '../actions/configs/context.mjs';
|
|
14
|
+
import '../configuration/paginationContext.mjs';
|
|
18
15
|
import '../actions/configs/defaults.mjs';
|
|
19
16
|
import '../displayText/context.mjs';
|
|
20
17
|
import '../filePreview/context.mjs';
|
|
@@ -11,11 +11,8 @@ import '@aws-amplify/ui-react-core/elements';
|
|
|
11
11
|
import '../../../credentials/context.mjs';
|
|
12
12
|
import '@aws-amplify/storage/internals';
|
|
13
13
|
import '../../../configuration/context.mjs';
|
|
14
|
+
import '../../../configuration/paginationContext.mjs';
|
|
14
15
|
import '@aws-amplify/ui';
|
|
15
|
-
import 'aws-amplify';
|
|
16
|
-
import 'jszip';
|
|
17
|
-
import 'aws-amplify/storage';
|
|
18
|
-
import '../../../actions/configs/context.mjs';
|
|
19
16
|
import '../../../actions/configs/defaults.mjs';
|
|
20
17
|
import { useDisplayText } from '../../../displayText/context.mjs';
|
|
21
18
|
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import React__default from 'react';
|
|
2
|
+
import '@aws-amplify/ui-react';
|
|
3
|
+
import { ViewElement, HeadingElement, TextElement, ButtonElement } from '../elements/definitions.mjs';
|
|
4
|
+
import '../elements/IconElement.mjs';
|
|
5
|
+
|
|
6
|
+
const ActionConfirmationModal = ({ isOpen = false, title, message, content, onConfirm, onCancel, confirmLabel, cancelLabel, }) => {
|
|
7
|
+
const modalRef = React__default.useRef(null);
|
|
8
|
+
React__default.useEffect(() => {
|
|
9
|
+
if (isOpen && modalRef.current) {
|
|
10
|
+
modalRef.current.focus();
|
|
11
|
+
}
|
|
12
|
+
}, [isOpen]);
|
|
13
|
+
const handleKeyDown = (event) => {
|
|
14
|
+
if (event.key === 'Escape') {
|
|
15
|
+
onCancel?.();
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
if (!isOpen)
|
|
19
|
+
return null;
|
|
20
|
+
return (React__default.createElement("div", { ref: modalRef, className: "amplify-modal__overlay", role: "dialog", "aria-modal": "true", tabIndex: -1, onKeyDown: handleKeyDown, onClick: (e) => {
|
|
21
|
+
if (e.target === e.currentTarget) {
|
|
22
|
+
onCancel?.();
|
|
23
|
+
}
|
|
24
|
+
} },
|
|
25
|
+
React__default.createElement(ViewElement, { className: "amplify-modal__content", role: "document" },
|
|
26
|
+
React__default.createElement(HeadingElement, { className: "amplify-modal__title" }, title),
|
|
27
|
+
message && (React__default.createElement(TextElement, { className: "amplify-modal__body" }, message)),
|
|
28
|
+
content && (React__default.createElement(ViewElement, { className: "amplify-modal__body" }, content)),
|
|
29
|
+
React__default.createElement(ViewElement, { className: "amplify-modal__footer" },
|
|
30
|
+
React__default.createElement(ButtonElement, { className: "amplify-modal__cancel", onClick: onCancel, variant: "cancel" }, cancelLabel),
|
|
31
|
+
React__default.createElement(ButtonElement, { className: "amplify-modal__confirm", onClick: onConfirm, variant: "primary" }, confirmLabel)))));
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export { ActionConfirmationModal };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ActionCancel } from './ActionCancel.mjs';
|
|
2
|
+
import { ActionConfirmationModal } from './ActionConfirmationModal.mjs';
|
|
2
3
|
import { ActionDestination } from './ActionDestination.mjs';
|
|
3
4
|
import { ActionExit } from './ActionExit.mjs';
|
|
4
5
|
import { ActionStart } from './ActionStart.mjs';
|
|
@@ -22,6 +23,7 @@ import { Title } from './Title.mjs';
|
|
|
22
23
|
|
|
23
24
|
const DEFAULT_COMPOSABLES = {
|
|
24
25
|
ActionCancel,
|
|
26
|
+
ActionConfirmationModal,
|
|
25
27
|
ActionDestination,
|
|
26
28
|
ActionExit,
|
|
27
29
|
ActionStart,
|
|
@@ -29,7 +29,7 @@ const OrderedListElement = defineBaseElement({
|
|
|
29
29
|
type: 'ol',
|
|
30
30
|
displayName: 'OrderedList',
|
|
31
31
|
});
|
|
32
|
-
defineBaseElement({
|
|
32
|
+
const UnorderedListElement = defineBaseElement({
|
|
33
33
|
type: 'ul',
|
|
34
34
|
displayName: 'UnorderedList',
|
|
35
35
|
});
|
|
@@ -83,4 +83,4 @@ const SpanElement = defineBaseElement({
|
|
|
83
83
|
displayName: 'Span',
|
|
84
84
|
});
|
|
85
85
|
|
|
86
|
-
export { ButtonElement, DescriptionDetailsElement, DescriptionListElement, DescriptionTermElement, HeadingElement, InputElement, LabelElement, ListItemElement, NavElement, OrderedListElement, SpanElement, TableBodyElement, TableDataCellElement, TableElement, TableHeadElement, TableHeaderElement, TableRowElement, TextElement, ViewElement };
|
|
86
|
+
export { ButtonElement, DescriptionDetailsElement, DescriptionListElement, DescriptionTermElement, HeadingElement, InputElement, LabelElement, ListItemElement, NavElement, OrderedListElement, SpanElement, TableBodyElement, TableDataCellElement, TableElement, TableHeadElement, TableHeaderElement, TableRowElement, TextElement, UnorderedListElement, ViewElement };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React__default from 'react';
|
|
2
|
+
import { createContextUtilities } from '@aws-amplify/ui-react-core';
|
|
3
|
+
import { validatePageSize } from '../utils/validatePageSize.mjs';
|
|
4
|
+
|
|
5
|
+
const ERROR_MESSAGE = '`usePaginationConfig` must be called from within a `PaginationConfigProvider`.';
|
|
6
|
+
const { usePaginationConfig, PaginationConfigContext } = createContextUtilities({
|
|
7
|
+
contextName: 'PaginationConfig',
|
|
8
|
+
errorMessage: ERROR_MESSAGE,
|
|
9
|
+
});
|
|
10
|
+
function PaginationConfigProvider({ children, pageSize, }) {
|
|
11
|
+
const value = React__default.useMemo(() => ({ pageSize: validatePageSize(pageSize) }), [pageSize]);
|
|
12
|
+
return (React__default.createElement(PaginationConfigContext.Provider, { value: value }, children));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export { PaginationConfigContext, PaginationConfigProvider, usePaginationConfig };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React__default from 'react';
|
|
2
|
+
import { ActionConfirmationModal } from '../components/composables/ActionConfirmationModal.mjs';
|
|
3
|
+
import { useResolvedComposable } from './hooks/useResolvedComposable.mjs';
|
|
4
|
+
import { useActionConfirmationModal } from './hooks/useActionConfirmationModal.mjs';
|
|
5
|
+
|
|
6
|
+
const ActionConfirmationModalControl = () => {
|
|
7
|
+
const props = useActionConfirmationModal();
|
|
8
|
+
const Resolved = useResolvedComposable(ActionConfirmationModal, 'ActionConfirmationModal');
|
|
9
|
+
return React__default.createElement(Resolved, { ...props });
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export { ActionConfirmationModalControl };
|
|
@@ -11,10 +11,7 @@ import '@aws-amplify/ui-react-core/elements';
|
|
|
11
11
|
import '../credentials/context.mjs';
|
|
12
12
|
import '@aws-amplify/storage/internals';
|
|
13
13
|
import '../configuration/context.mjs';
|
|
14
|
-
import '
|
|
15
|
-
import 'jszip';
|
|
16
|
-
import 'aws-amplify/storage';
|
|
17
|
-
import '../actions/configs/context.mjs';
|
|
14
|
+
import '../configuration/paginationContext.mjs';
|
|
18
15
|
import '../actions/configs/defaults.mjs';
|
|
19
16
|
import '../displayText/context.mjs';
|
|
20
17
|
import '../filePreview/context.mjs';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { useControlsContext } from '../context.mjs';
|
|
2
|
+
|
|
3
|
+
const useActionConfirmationModal = () => {
|
|
4
|
+
const { data: { confirmationModal = {} }, onConfirmationModalConfirm = () => { }, onConfirmationModalCancel = () => { }, } = useControlsContext();
|
|
5
|
+
return {
|
|
6
|
+
isOpen: false,
|
|
7
|
+
title: 'Confirm Action',
|
|
8
|
+
message: '',
|
|
9
|
+
confirmLabel: 'Confirm',
|
|
10
|
+
cancelLabel: 'Cancel',
|
|
11
|
+
...confirmationModal,
|
|
12
|
+
onConfirm: onConfirmationModalConfirm,
|
|
13
|
+
onCancel: onConfirmationModalCancel,
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export { useActionConfirmationModal };
|
|
@@ -9,19 +9,24 @@ import '@aws-amplify/ui-react-core/elements';
|
|
|
9
9
|
import '../credentials/context.mjs';
|
|
10
10
|
import '@aws-amplify/storage/internals';
|
|
11
11
|
import '../configuration/context.mjs';
|
|
12
|
+
import '../configuration/paginationContext.mjs';
|
|
12
13
|
import '@aws-amplify/ui-react-core';
|
|
13
|
-
import 'aws-amplify';
|
|
14
|
-
import 'jszip';
|
|
15
|
-
import 'aws-amplify/storage';
|
|
16
|
-
import '../actions/configs/context.mjs';
|
|
17
14
|
import '../actions/configs/defaults.mjs';
|
|
18
15
|
import '../views/LocationActionView/CreateFolderView/CreateFolderView.mjs';
|
|
19
16
|
import '../views/LocationActionView/DeleteView/DeleteView.mjs';
|
|
17
|
+
import '../displayText/context.mjs';
|
|
18
|
+
import '@aws-amplify/ui-react';
|
|
19
|
+
import '../components/elements/definitions.mjs';
|
|
20
|
+
import '../components/elements/IconElement.mjs';
|
|
21
|
+
import 'aws-amplify';
|
|
22
|
+
import 'jszip';
|
|
23
|
+
import 'aws-amplify/storage';
|
|
20
24
|
import '../views/LocationActionView/DownloadView/DownloadView.mjs';
|
|
21
25
|
import '../views/context/actionViews.mjs';
|
|
22
26
|
import '../views/LocationActionView/UploadView/UploadView.mjs';
|
|
23
27
|
import '../fileItems/context.mjs';
|
|
24
28
|
import '../views/LocationDetailView/LocationDetailView.mjs';
|
|
29
|
+
import '../actions/configs/context.mjs';
|
|
25
30
|
import '../filePreview/context.mjs';
|
|
26
31
|
import '../views/LocationsView/LocationsView.mjs';
|
|
27
32
|
|
|
@@ -16,6 +16,7 @@ import { ComponentsProvider } from '../components/ComponentsProvider.mjs';
|
|
|
16
16
|
import { componentsDefault } from '../components/defaults.mjs';
|
|
17
17
|
import { createConfigurationProvider } from '../configuration/createConfigurationProvider.mjs';
|
|
18
18
|
import '../configuration/context.mjs';
|
|
19
|
+
import { PaginationConfigProvider } from '../configuration/paginationContext.mjs';
|
|
19
20
|
import { DisplayTextProvider } from '../displayText/context.mjs';
|
|
20
21
|
import { FileItemsProvider } from '../fileItems/context.mjs';
|
|
21
22
|
import { defaultValidateFile } from '../fileItems/utils.mjs';
|
|
@@ -69,17 +70,18 @@ function createProvider({ actions, components, config, options, filePreview = {}
|
|
|
69
70
|
* Provides state, configuration and action values that are shared between
|
|
70
71
|
* the primary View components
|
|
71
72
|
*/
|
|
72
|
-
function Provider({ children, displayText, views, ...props }) {
|
|
73
|
+
function Provider({ children, displayText, views, pageSize, ...props }) {
|
|
73
74
|
return (React__default.createElement(StoreProvider, { ...props },
|
|
74
75
|
React__default.createElement(ConfigurationProvider, null,
|
|
75
|
-
React__default.createElement(
|
|
76
|
-
React__default.createElement(
|
|
77
|
-
React__default.createElement(
|
|
78
|
-
React__default.createElement(
|
|
79
|
-
React__default.createElement(
|
|
80
|
-
React__default.createElement(
|
|
81
|
-
React__default.createElement(
|
|
82
|
-
React__default.createElement(
|
|
76
|
+
React__default.createElement(PaginationConfigProvider, { pageSize: pageSize },
|
|
77
|
+
React__default.createElement(ActionConfigsProvider, { actionConfigs: actionConfigs },
|
|
78
|
+
React__default.createElement(ActionHandlersProvider, { handlers: handlers },
|
|
79
|
+
React__default.createElement(DisplayTextProvider, { displayText: displayText },
|
|
80
|
+
React__default.createElement(ViewsProvider, { actions: resolvedActions, views: views },
|
|
81
|
+
React__default.createElement(ComponentsProvider, { composables: composables },
|
|
82
|
+
React__default.createElement(LocationItemsProvider, null,
|
|
83
|
+
React__default.createElement(FileItemsProvider, { validateFile: validateFile },
|
|
84
|
+
React__default.createElement(FilePreviewProvider, { filePreview: filePreview }, children))))))))))));
|
|
83
85
|
}
|
|
84
86
|
return Provider;
|
|
85
87
|
}
|
|
@@ -9,12 +9,9 @@ import '@aws-amplify/ui-react-core/elements';
|
|
|
9
9
|
import '../credentials/context.mjs';
|
|
10
10
|
import '@aws-amplify/storage/internals';
|
|
11
11
|
import '../configuration/context.mjs';
|
|
12
|
-
import '
|
|
13
|
-
import 'jszip';
|
|
14
|
-
import 'aws-amplify/storage';
|
|
15
|
-
import { assertRegisterAuthListener } from '../validators/assertRegisterAuthListener.mjs';
|
|
16
|
-
import '../actions/configs/context.mjs';
|
|
12
|
+
import '../configuration/paginationContext.mjs';
|
|
17
13
|
import '../actions/configs/defaults.mjs';
|
|
14
|
+
import { assertRegisterAuthListener } from '../validators/assertRegisterAuthListener.mjs';
|
|
18
15
|
import '../views/context/actionViews.mjs';
|
|
19
16
|
import '../views/context/primaryViews.mjs';
|
|
20
17
|
import { CopyView } from '../views/LocationActionView/CopyView/CopyView.mjs';
|
|
@@ -22,11 +19,19 @@ import '../locationItems/context.mjs';
|
|
|
22
19
|
import '../store/context.mjs';
|
|
23
20
|
import { CreateFolderView } from '../views/LocationActionView/CreateFolderView/CreateFolderView.mjs';
|
|
24
21
|
import { DeleteView } from '../views/LocationActionView/DeleteView/DeleteView.mjs';
|
|
22
|
+
import '../displayText/context.mjs';
|
|
23
|
+
import '@aws-amplify/ui-react';
|
|
24
|
+
import '../components/elements/definitions.mjs';
|
|
25
|
+
import '../components/elements/IconElement.mjs';
|
|
26
|
+
import 'aws-amplify';
|
|
27
|
+
import 'jszip';
|
|
28
|
+
import 'aws-amplify/storage';
|
|
25
29
|
import { DownloadView } from '../views/LocationActionView/DownloadView/DownloadView.mjs';
|
|
26
30
|
import { LocationActionView } from '../views/LocationActionView/LocationActionView.mjs';
|
|
27
31
|
import { UploadView } from '../views/LocationActionView/UploadView/UploadView.mjs';
|
|
28
32
|
import '../fileItems/context.mjs';
|
|
29
33
|
import { LocationDetailView } from '../views/LocationDetailView/LocationDetailView.mjs';
|
|
34
|
+
import '../actions/configs/context.mjs';
|
|
30
35
|
import '../filePreview/context.mjs';
|
|
31
36
|
import { LocationsView } from '../views/LocationsView/LocationsView.mjs';
|
|
32
37
|
import { useView } from '../views/useView.mjs';
|
|
@@ -1,20 +1,132 @@
|
|
|
1
1
|
import { DEFAULT_ACTION_VIEW_DISPLAY_TEXT } from './shared.mjs';
|
|
2
2
|
|
|
3
|
+
const pluralize = (count, word) => count === 1 ? word : `${word}s`;
|
|
4
|
+
const formatCount = (count, word) => `${count === 1 ? '' : 'All '}${count} ${pluralize(count, word)}`;
|
|
3
5
|
const DEFAULT_DELETE_VIEW_DISPLAY_TEXT = {
|
|
4
6
|
...DEFAULT_ACTION_VIEW_DISPLAY_TEXT,
|
|
5
7
|
title: 'Delete',
|
|
6
8
|
actionStartLabel: 'Delete',
|
|
9
|
+
confirmationModalTitle: 'Confirm Deletion',
|
|
10
|
+
confirmationModalConfirmLabel: 'Delete',
|
|
11
|
+
confirmationModalCancelLabel: 'Cancel',
|
|
12
|
+
confirmationModalMessage: 'The items that will be deleted contain {count} folder{plural}',
|
|
13
|
+
confirmationModalFolderListTitle: 'Folder list:',
|
|
7
14
|
getActionCompleteMessage: (data) => {
|
|
8
|
-
const { counts } = data ?? {};
|
|
9
|
-
const { COMPLETE, FAILED, TOTAL } = counts ?? {};
|
|
15
|
+
const { counts, tasks } = data ?? {};
|
|
16
|
+
const { COMPLETE = 0, FAILED = 0, TOTAL = 0 } = counts ?? {};
|
|
17
|
+
if (!TOTAL || TOTAL === 0) {
|
|
18
|
+
return { content: 'No items to delete.', type: 'info' };
|
|
19
|
+
}
|
|
20
|
+
if (tasks && tasks.length > 0) {
|
|
21
|
+
const folderTasks = tasks.filter((task) => task.data.type === 'FOLDER');
|
|
22
|
+
const fileTasks = tasks.filter((task) => task.data.type === 'FILE');
|
|
23
|
+
const completeFolders = folderTasks.filter((task) => task.status === 'COMPLETE').length;
|
|
24
|
+
const failedFolders = folderTasks.filter((task) => task.status === 'FAILED').length;
|
|
25
|
+
const completeFiles = fileTasks.filter((task) => task.status === 'COMPLETE').length;
|
|
26
|
+
const failedFiles = fileTasks.filter((task) => task.status === 'FAILED').length;
|
|
27
|
+
const hasFolders = folderTasks.length > 0;
|
|
28
|
+
const hasFiles = fileTasks.length > 0;
|
|
29
|
+
const isMixed = hasFolders && hasFiles;
|
|
30
|
+
// All successful
|
|
31
|
+
if (COMPLETE === TOTAL) {
|
|
32
|
+
if (isMixed) {
|
|
33
|
+
return {
|
|
34
|
+
content: `${formatCount(completeFolders, 'folder')} and ${completeFiles} ${pluralize(completeFiles, 'file')} deleted successfully.`,
|
|
35
|
+
type: 'success',
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
else if (hasFolders) {
|
|
39
|
+
return {
|
|
40
|
+
content: `${formatCount(completeFolders, 'folder')} deleted successfully.`,
|
|
41
|
+
type: 'success',
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
return {
|
|
46
|
+
content: `${formatCount(completeFiles, 'file')} deleted successfully.`,
|
|
47
|
+
type: 'success',
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// Complete failure
|
|
52
|
+
if (FAILED === TOTAL) {
|
|
53
|
+
if (isMixed) {
|
|
54
|
+
return {
|
|
55
|
+
content: `Failed to delete ${failedFolders} ${pluralize(failedFolders, 'folder')} and ${failedFiles} ${pluralize(failedFiles, 'file')}. Some contents may have been deleted.`,
|
|
56
|
+
type: 'error',
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
else if (hasFolders) {
|
|
60
|
+
return {
|
|
61
|
+
content: `Failed to delete ${failedFolders} ${pluralize(failedFolders, 'folder')}. Some items may have been deleted.`,
|
|
62
|
+
type: 'error',
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
return {
|
|
67
|
+
content: `Failed to delete ${failedFiles} ${pluralize(failedFiles, 'file')}.`,
|
|
68
|
+
type: 'error',
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Partial failure
|
|
73
|
+
if (isMixed) {
|
|
74
|
+
const messages = [];
|
|
75
|
+
if (completeFiles > 0) {
|
|
76
|
+
messages.push(`${completeFiles} ${pluralize(completeFiles, 'file')} deleted`);
|
|
77
|
+
}
|
|
78
|
+
if (completeFolders > 0) {
|
|
79
|
+
messages.push(`${completeFolders} ${pluralize(completeFolders, 'folder')} deleted`);
|
|
80
|
+
}
|
|
81
|
+
if (failedFiles > 0) {
|
|
82
|
+
messages.push(`${failedFiles} ${pluralize(failedFiles, 'file')} failed`);
|
|
83
|
+
}
|
|
84
|
+
if (failedFolders > 0) {
|
|
85
|
+
messages.push(`${failedFolders} ${pluralize(failedFolders, 'folder')} failed`);
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
content: messages.join(', ') + '. Some items may have been deleted.',
|
|
89
|
+
type: 'error',
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
else if (hasFolders) {
|
|
93
|
+
// Folders only partial failure
|
|
94
|
+
if (completeFolders > 0) {
|
|
95
|
+
return {
|
|
96
|
+
content: `${completeFolders} ${pluralize(completeFolders, 'folder')} deleted, ${failedFolders} ${pluralize(failedFolders, 'folder')} failed. Some items may have been deleted.`,
|
|
97
|
+
type: 'error',
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
return {
|
|
102
|
+
content: `Failed to delete ${failedFolders} ${pluralize(failedFolders, 'folder')}. Some items may have been deleted.`,
|
|
103
|
+
type: 'error',
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
// Files only partial failure
|
|
109
|
+
return {
|
|
110
|
+
content: `${completeFiles} ${pluralize(completeFiles, 'file')} deleted, ${failedFiles} ${pluralize(failedFiles, 'file')} failed.`,
|
|
111
|
+
type: 'error',
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Fallback to generic messaging if tasks not available
|
|
10
116
|
if (COMPLETE === TOTAL) {
|
|
11
|
-
return {
|
|
117
|
+
return {
|
|
118
|
+
content: `${formatCount(TOTAL, 'item')} deleted successfully.`,
|
|
119
|
+
type: 'success',
|
|
120
|
+
};
|
|
12
121
|
}
|
|
13
122
|
if (FAILED === TOTAL) {
|
|
14
|
-
return {
|
|
123
|
+
return {
|
|
124
|
+
content: `Failed to delete ${formatCount(TOTAL, 'item')}.`,
|
|
125
|
+
type: 'error',
|
|
126
|
+
};
|
|
15
127
|
}
|
|
16
128
|
return {
|
|
17
|
-
content: `${COMPLETE}
|
|
129
|
+
content: `${COMPLETE} ${pluralize(COMPLETE, 'item')} deleted, ${FAILED} ${pluralize(FAILED, 'item')} failed to delete.`,
|
|
18
130
|
type: 'error',
|
|
19
131
|
};
|
|
20
132
|
},
|
|
@@ -69,6 +69,7 @@ const DEFAULT_LOCATION_DETAIL_VIEW_DISPLAY_TEXT = {
|
|
|
69
69
|
tableColumnSizeHeader: 'Size',
|
|
70
70
|
tableColumnTypeHeader: 'Type',
|
|
71
71
|
selectFileLabel: 'Select file',
|
|
72
|
+
selectFolderLabel: 'Select folder',
|
|
72
73
|
selectAllFilesLabel: 'Select all files',
|
|
73
74
|
getActionListItemLabel: (key = '') => {
|
|
74
75
|
switch (key) {
|
|
@@ -17,6 +17,7 @@ const DEFAULT_ACTION_VIEW_DISPLAY_TEXT = {
|
|
|
17
17
|
tableColumnNameHeader: 'Name',
|
|
18
18
|
tableColumnTypeHeader: 'Type',
|
|
19
19
|
tableColumnSizeHeader: 'Size',
|
|
20
|
+
tableColumnProgressHeader: 'Progress',
|
|
20
21
|
};
|
|
21
22
|
const DEFAULT_LIST_VIEW_DISPLAY_TEXT = {
|
|
22
23
|
loadingIndicatorLabel: 'Loading',
|
|
@@ -9,6 +9,7 @@ import '../actions/configs/context.mjs';
|
|
|
9
9
|
import '../actions/configs/defaults.mjs';
|
|
10
10
|
|
|
11
11
|
const DEFAULT_STATE = {
|
|
12
|
+
dataItems: undefined,
|
|
12
13
|
fileDataItems: undefined,
|
|
13
14
|
};
|
|
14
15
|
const locationItemsReducer = (prevState, event) => {
|
|
@@ -17,27 +18,29 @@ const locationItemsReducer = (prevState, event) => {
|
|
|
17
18
|
const { items } = event;
|
|
18
19
|
if (!items?.length)
|
|
19
20
|
return prevState;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
const nextDataItems = !prevState.dataItems?.length
|
|
22
|
+
? items
|
|
23
|
+
: prevState.dataItems.concat(items.filter((data) => !prevState.dataItems?.some(({ id }) => id === data.id)));
|
|
24
|
+
const fileItems = items.filter((item) => item.type === 'FILE');
|
|
25
|
+
const nextFileDataItems = !prevState.fileDataItems?.length
|
|
26
|
+
? fileItems.map(createFileDataItem)
|
|
27
|
+
: prevState.fileDataItems.concat(fileItems
|
|
28
|
+
.filter((data) => !prevState.fileDataItems?.some(({ id }) => id === data.id))
|
|
29
|
+
.map(createFileDataItem));
|
|
28
30
|
return {
|
|
29
|
-
|
|
31
|
+
dataItems: nextDataItems,
|
|
32
|
+
fileDataItems: nextFileDataItems,
|
|
30
33
|
};
|
|
31
34
|
}
|
|
32
35
|
case 'REMOVE_LOCATION_ITEM': {
|
|
33
36
|
const { id } = event;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
const dataItems = prevState.dataItems?.filter((item) => item.id !== id);
|
|
38
|
+
const fileDataItems = prevState.fileDataItems?.filter((item) => item.id !== id);
|
|
39
|
+
if (dataItems?.length === prevState.dataItems?.length &&
|
|
40
|
+
fileDataItems?.length === prevState.fileDataItems?.length) {
|
|
38
41
|
return prevState;
|
|
39
42
|
}
|
|
40
|
-
return { fileDataItems };
|
|
43
|
+
return { dataItems, fileDataItems };
|
|
41
44
|
}
|
|
42
45
|
case 'RESET_LOCATION_ITEMS': {
|
|
43
46
|
return DEFAULT_STATE;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Selection utility functions for LocationItems
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Get selected files from dataItems
|
|
6
|
+
*/
|
|
7
|
+
const getSelectedFiles = (dataItems) => {
|
|
8
|
+
return dataItems?.filter((item) => item.type === 'FILE') ?? [];
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Get selected folders from dataItems
|
|
12
|
+
*/
|
|
13
|
+
const getSelectedFolders = (dataItems) => {
|
|
14
|
+
return dataItems?.filter((item) => item.type === 'FOLDER') ?? [];
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Check if selection contains folders
|
|
18
|
+
*/
|
|
19
|
+
const hasSelectedFolders = (dataItems) => {
|
|
20
|
+
return dataItems?.some((item) => item.type === 'FOLDER') ?? false;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Get selection summary
|
|
24
|
+
*/
|
|
25
|
+
const getSelectionSummary = (dataItems) => {
|
|
26
|
+
const files = getSelectedFiles(dataItems);
|
|
27
|
+
const folders = getSelectedFolders(dataItems);
|
|
28
|
+
return {
|
|
29
|
+
total: dataItems?.length ?? 0,
|
|
30
|
+
files: files.length,
|
|
31
|
+
folders: folders.length,
|
|
32
|
+
hasFiles: files.length > 0,
|
|
33
|
+
hasFolders: folders.length > 0,
|
|
34
|
+
isMixed: files.length > 0 && folders.length > 0,
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export { getSelectedFiles, getSelectedFolders, getSelectionSummary, hasSelectedFolders };
|
|
@@ -12,7 +12,7 @@ const DEPRECATED_PROP_KEYS = ['actionType', 'location', 'path'];
|
|
|
12
12
|
const template = (key, index, values) => `\`${key}\`${index < values.length - 1 ? ', ' : ''}`;
|
|
13
13
|
const getMissingLocationKeys = (location) => location === null
|
|
14
14
|
? []
|
|
15
|
-
: REQUIRED_LOCATION_KEYS.filter((key) =>
|
|
15
|
+
: REQUIRED_LOCATION_KEYS.filter((key) => location[key] === undefined || location[key] === null);
|
|
16
16
|
let didWarnConflictingBehavior = false;
|
|
17
17
|
let didWarnDeprecatedAndConflictingProps = false;
|
|
18
18
|
let didWarnDeprecatedProps = false;
|