@aws-amplify/ui-react-storage 3.12.2 → 3.13.1
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-pzJe4BD8.js → createStorageBrowser-DaVWyJzC.js} +1884 -1068
- package/dist/esm/browser.mjs +6 -2
- package/dist/esm/components/StorageBrowser/ErrorBoundary/ErrorBoundary.mjs +9 -0
- package/dist/esm/components/StorageBrowser/components/ComponentsProvider.mjs +9 -0
- package/dist/esm/components/StorageBrowser/components/base/Table.mjs +1 -1
- package/dist/esm/components/StorageBrowser/components/base/preview/DownloadButton.mjs +39 -0
- package/dist/esm/components/StorageBrowser/components/base/preview/FileMetadata.mjs +40 -0
- package/dist/esm/components/StorageBrowser/components/base/preview/FilePreviewLayout.mjs +19 -0
- package/dist/esm/components/StorageBrowser/components/base/preview/ImagePreview.mjs +37 -0
- package/dist/esm/components/StorageBrowser/components/base/preview/PreviewFallback.mjs +34 -0
- package/dist/esm/components/StorageBrowser/components/base/preview/PreviewPlaceholder.mjs +13 -0
- package/dist/esm/components/StorageBrowser/components/base/preview/TextPreview.mjs +64 -0
- package/dist/esm/components/StorageBrowser/components/base/preview/VideoPreview.mjs +61 -0
- package/dist/esm/components/StorageBrowser/components/composables/DataTable/DataTable.mjs +2 -1
- package/dist/esm/components/StorageBrowser/components/composables/FilePreview.mjs +85 -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/controls/DataTableControl.mjs +9 -0
- package/dist/esm/components/StorageBrowser/controls/FilePreviewControl.mjs +24 -0
- package/dist/esm/components/StorageBrowser/createStorageBrowser/StorageBrowserDefault.mjs +1 -0
- package/dist/esm/components/StorageBrowser/createStorageBrowser/createProvider.mjs +4 -2
- package/dist/esm/components/StorageBrowser/createStorageBrowser/createStorageBrowser.mjs +1 -0
- package/dist/esm/components/StorageBrowser/displayText/context.mjs +4 -0
- package/dist/esm/components/StorageBrowser/displayText/libraries/en/locationDetailView.mjs +28 -0
- package/dist/esm/components/StorageBrowser/filePreview/context.mjs +12 -0
- package/dist/esm/components/StorageBrowser/views/LocationActionView/CopyView/CopyView.mjs +9 -0
- package/dist/esm/components/StorageBrowser/views/LocationActionView/CopyView/CopyViewProvider.mjs +8 -0
- package/dist/esm/components/StorageBrowser/views/LocationActionView/CopyView/FoldersMessageControl.mjs +8 -0
- package/dist/esm/components/StorageBrowser/views/LocationActionView/CreateFolderView/CreateFolderView.mjs +9 -0
- package/dist/esm/components/StorageBrowser/views/LocationActionView/DeleteView/DeleteView.mjs +9 -0
- package/dist/esm/components/StorageBrowser/views/LocationActionView/DownloadView/DownloadView.mjs +9 -0
- package/dist/esm/components/StorageBrowser/views/LocationActionView/UploadView/UploadView.mjs +9 -0
- package/dist/esm/components/StorageBrowser/views/LocationDetailView/LocationDetailView.mjs +17 -4
- package/dist/esm/components/StorageBrowser/views/LocationDetailView/LocationDetailViewProvider.mjs +9 -2
- package/dist/esm/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/constants.mjs +69 -1
- package/dist/esm/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/fileIcon.mjs +11 -0
- package/dist/esm/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/getFileRowContent.mjs +8 -5
- package/dist/esm/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/getLocationDetailViewTableData.mjs +8 -1
- package/dist/esm/components/StorageBrowser/views/LocationDetailView/useLocationDetailView.mjs +76 -3
- package/dist/esm/components/StorageBrowser/views/LocationsView/LocationsView.mjs +9 -0
- package/dist/esm/components/StorageBrowser/views/LocationsView/LocationsViewProvider.mjs +8 -0
- package/dist/esm/components/StorageBrowser/views/context/primaryViews.mjs +1 -0
- package/dist/esm/components/StorageBrowser/views/hooks/useFilePreview/useFilePreview.mjs +115 -0
- package/dist/esm/components/StorageBrowser/views/utils/files/const.mjs +62 -0
- package/dist/esm/components/StorageBrowser/views/utils/files/fileName.mjs +12 -0
- package/dist/esm/components/StorageBrowser/views/utils/files/fileSize.mjs +23 -0
- package/dist/esm/components/StorageBrowser/views/utils/files/fileType.mjs +87 -0
- package/dist/esm/components/StorageBrowser/views/utils/files/safeGetProperties.mjs +12 -0
- package/dist/esm/components/StorageBrowser/views/utils/files/url.mjs +16 -0
- package/dist/esm/version.mjs +1 -1
- package/dist/index.js +1 -1
- package/dist/styles.css +250 -0
- package/dist/types/components/StorageBrowser/actions/configs/defaults.d.ts +2 -2
- package/dist/types/components/StorageBrowser/actions/handlers/types.d.ts +4 -0
- package/dist/types/components/StorageBrowser/components/base/Table.d.ts +1 -0
- package/dist/types/components/StorageBrowser/components/base/preview/DownloadButton.d.ts +4 -0
- package/dist/types/components/StorageBrowser/components/base/preview/FileMetadata.d.ts +7 -0
- package/dist/types/components/StorageBrowser/components/base/preview/FilePreviewLayout.d.ts +8 -0
- package/dist/types/components/StorageBrowser/components/base/preview/ImagePreview.d.ts +3 -0
- package/dist/types/components/StorageBrowser/components/base/preview/PreviewFallback.d.ts +10 -0
- package/dist/types/components/StorageBrowser/components/base/preview/PreviewPlaceholder.d.ts +2 -0
- package/dist/types/components/StorageBrowser/components/base/preview/TextPreview.d.ts +3 -0
- package/dist/types/components/StorageBrowser/components/base/preview/VideoPreview.d.ts +3 -0
- package/dist/types/components/StorageBrowser/components/base/preview/type.d.ts +6 -0
- package/dist/types/components/StorageBrowser/components/composables/DataTable/DataTable.d.ts +1 -0
- package/dist/types/components/StorageBrowser/components/composables/FilePreview.d.ts +12 -0
- package/dist/types/components/StorageBrowser/components/composables/types.d.ts +2 -0
- package/dist/types/components/StorageBrowser/controls/FilePreviewControl.d.ts +2 -0
- package/dist/types/components/StorageBrowser/controls/types.d.ts +11 -2
- package/dist/types/components/StorageBrowser/createStorageBrowser/createProvider.d.ts +2 -1
- package/dist/types/components/StorageBrowser/createStorageBrowser/createStorageBrowser.d.ts +4 -1
- package/dist/types/components/StorageBrowser/createStorageBrowser/types.d.ts +78 -2
- package/dist/types/components/StorageBrowser/displayText/types.d.ts +30 -1
- package/dist/types/components/StorageBrowser/filePreview/context.d.ts +10 -0
- package/dist/types/components/StorageBrowser/filePreview/index.d.ts +1 -0
- package/dist/types/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/constants.d.ts +6 -0
- package/dist/types/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/fileIcon.d.ts +2 -0
- package/dist/types/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/getFileRowContent.d.ts +3 -1
- package/dist/types/components/StorageBrowser/views/LocationDetailView/getLocationDetailViewTableData/getLocationDetailViewTableData.d.ts +5 -2
- package/dist/types/components/StorageBrowser/views/LocationDetailView/types.d.ts +10 -0
- package/dist/types/components/StorageBrowser/views/hooks/useFilePreview/index.d.ts +2 -0
- package/dist/types/components/StorageBrowser/views/hooks/useFilePreview/types.d.ts +28 -0
- package/dist/types/components/StorageBrowser/views/hooks/useFilePreview/useFilePreview.d.ts +5 -0
- package/dist/types/components/StorageBrowser/views/utils/files/const.d.ts +9 -0
- package/dist/types/components/StorageBrowser/views/utils/files/fileName.d.ts +6 -0
- package/dist/types/components/StorageBrowser/views/utils/files/fileSize.d.ts +2 -0
- package/dist/types/components/StorageBrowser/views/utils/files/fileType.d.ts +12 -0
- package/dist/types/components/StorageBrowser/views/utils/files/safeGetProperties.d.ts +2 -0
- package/dist/types/components/StorageBrowser/views/utils/files/url.d.ts +2 -0
- package/dist/types/version.d.ts +1 -1
- package/package.json +6 -6
|
@@ -32,7 +32,7 @@ function _interopNamespace(e) {
|
|
|
32
32
|
|
|
33
33
|
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
34
34
|
|
|
35
|
-
const VERSION = '3.
|
|
35
|
+
const VERSION = '3.13.1';
|
|
36
36
|
|
|
37
37
|
const toAccessGrantPermission = (permission) => {
|
|
38
38
|
let result = '';
|
|
@@ -784,7 +784,7 @@ const NavElement = elements.defineBaseElement({
|
|
|
784
784
|
type: 'nav',
|
|
785
785
|
displayName: 'Nav',
|
|
786
786
|
});
|
|
787
|
-
elements.defineBaseElement({
|
|
787
|
+
const TextElement = elements.defineBaseElement({
|
|
788
788
|
type: 'p',
|
|
789
789
|
displayName: 'Text',
|
|
790
790
|
});
|
|
@@ -919,7 +919,7 @@ function PaginationButton({ isDisabled, onClick, type, }) {
|
|
|
919
919
|
const Table = ({ headers, rows }) => {
|
|
920
920
|
return (React__namespace["default"].createElement(TableElement, { className: `${STORAGE_BROWSER_BLOCK}__table` },
|
|
921
921
|
React__namespace["default"].createElement(TableHeadElement, { className: `${STORAGE_BROWSER_BLOCK}__table-head` }, headers.length ? (React__namespace["default"].createElement(TableRowElement, { className: `${STORAGE_BROWSER_BLOCK}__table-row` }, headers.map(({ key, content }) => (React__namespace["default"].createElement(TableHeaderElement, { key: key, className: `${STORAGE_BROWSER_BLOCK}__table-header` }, content))))) : null),
|
|
922
|
-
React__namespace["default"].createElement(TableBodyElement, { className: `${STORAGE_BROWSER_BLOCK}__table-body` }, rows?.map(({ key, content }) => (React__namespace["default"].createElement(TableRowElement, { key: key, className: `${STORAGE_BROWSER_BLOCK}__table-row` }, content.map(({ key, content, type }) => {
|
|
922
|
+
React__namespace["default"].createElement(TableBodyElement, { className: `${STORAGE_BROWSER_BLOCK}__table-body` }, rows?.map(({ key, content, active }) => (React__namespace["default"].createElement(TableRowElement, { key: key, className: `${STORAGE_BROWSER_BLOCK}__table-row${active ? ` ${STORAGE_BROWSER_BLOCK}__table-row_active` : ''}` }, content.map(({ key, content, type }) => {
|
|
923
923
|
return type === 'header' ? (React__namespace["default"].createElement(TableHeaderElement, { key: key, className: `${STORAGE_BROWSER_BLOCK}__table-header`, role: "rowheader" }, content)) : (React__namespace["default"].createElement(TableDataCellElement, { key: key, className: `${STORAGE_BROWSER_BLOCK}__table-data-cell` }, content));
|
|
924
924
|
})))))));
|
|
925
925
|
};
|
|
@@ -1049,8 +1049,9 @@ const DataTable = ({ headers, isLoading, rows, }) => {
|
|
|
1049
1049
|
});
|
|
1050
1050
|
const mappedRows = isLoading
|
|
1051
1051
|
? []
|
|
1052
|
-
: rows.map(({ key, content }) => ({
|
|
1052
|
+
: rows.map(({ key, content, active }) => ({
|
|
1053
1053
|
key,
|
|
1054
|
+
active,
|
|
1054
1055
|
content: content.map(({ key, content, type }) => {
|
|
1055
1056
|
switch (type) {
|
|
1056
1057
|
case 'button': {
|
|
@@ -1146,218 +1147,21 @@ const Navigation$1 = ({ items, }) => {
|
|
|
1146
1147
|
return React__namespace["default"].createElement(BreadcrumbNavigation, { breadcrumbs: items });
|
|
1147
1148
|
};
|
|
1148
1149
|
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
const Pagination$1 = ({ page, hasNextPage, onPaginate, highestPageVisited, }) => {
|
|
1155
|
-
if (!page)
|
|
1156
|
-
return null;
|
|
1157
|
-
return (React__namespace["default"].createElement(NavElement, { "aria-label": 'Pagination', className: `${STORAGE_BROWSER_BLOCK_TO_BE_UPDATED}__pagination` },
|
|
1158
|
-
React__namespace["default"].createElement(OrderedListElement, { className: `${STORAGE_BROWSER_BLOCK_TO_BE_UPDATED}__pagination-list` },
|
|
1159
|
-
React__namespace["default"].createElement(ListItemElement, { className: `${STORAGE_BROWSER_BLOCK_TO_BE_UPDATED}__pagination-list-item` },
|
|
1160
|
-
React__namespace["default"].createElement(PaginationButton, { isDisabled: page <= 1, onClick: () => {
|
|
1161
|
-
if (onPaginate)
|
|
1162
|
-
onPaginate(page - 1);
|
|
1163
|
-
}, type: "previous" })),
|
|
1164
|
-
React__namespace["default"].createElement(ListItemElement, { className: `${STORAGE_BROWSER_BLOCK_TO_BE_UPDATED}__pagination-list-item` },
|
|
1165
|
-
React__namespace["default"].createElement(SpanElement, { "aria-label": `Page ${page}`, "aria-current": "page", className: `${STORAGE_BROWSER_BLOCK_TO_BE_UPDATED}__pagination-current-page` }, page)),
|
|
1166
|
-
React__namespace["default"].createElement(ListItemElement, { className: `${STORAGE_BROWSER_BLOCK_TO_BE_UPDATED}__pagination-list-item` },
|
|
1167
|
-
React__namespace["default"].createElement(PaginationButton, { isDisabled: !highestPageVisited ||
|
|
1168
|
-
(page >= highestPageVisited && !hasNextPage), onClick: () => {
|
|
1169
|
-
if (onPaginate)
|
|
1170
|
-
onPaginate(page + 1);
|
|
1171
|
-
}, type: "next" })))));
|
|
1172
|
-
};
|
|
1173
|
-
|
|
1174
|
-
const SearchField$1 = ({ id, label, clearLabel, submitLabel, onSearch, onClear, placeholder, query = '', onQueryChange, }) => {
|
|
1175
|
-
// FIXME: focus not returning to input field after clear
|
|
1176
|
-
return (React__namespace["default"].createElement(React__namespace["default"].Fragment, null,
|
|
1177
|
-
React__namespace["default"].createElement(Field, { id: id, label: label, icon: React__namespace["default"].createElement(IconElement, { className: `${STORAGE_BROWSER_BLOCK_TO_BE_UPDATED}__search-field-icon`, variant: "search" }), className: `${STORAGE_BROWSER_BLOCK_TO_BE_UPDATED}__search-field`, variant: "search", onChange: (e) => {
|
|
1178
|
-
onQueryChange?.(e.target.value);
|
|
1179
|
-
}, placeholder: placeholder, onKeyUp: (event) => {
|
|
1180
|
-
if (event.key === 'Enter') {
|
|
1181
|
-
onSearch?.();
|
|
1182
|
-
}
|
|
1183
|
-
}, value: query }, query ? (React__namespace["default"].createElement(ButtonElement, { "aria-label": clearLabel, className: `${STORAGE_BROWSER_BLOCK_TO_BE_UPDATED}__search-field-clear`, onClick: onClear, variant: "refresh" },
|
|
1184
|
-
React__namespace["default"].createElement(IconElement, { variant: "dismiss" }))) : null),
|
|
1185
|
-
React__namespace["default"].createElement(ButtonElement, { className: `${STORAGE_BROWSER_BLOCK_TO_BE_UPDATED}__search-submit`, onClick: onSearch }, submitLabel)));
|
|
1186
|
-
};
|
|
1187
|
-
|
|
1188
|
-
const SEARCH_SUBFOLDERS_TOGGLE_ID = 'search-subfolders-toggle';
|
|
1189
|
-
const SearchSubfoldersToggle$1 = ({ isSearchingSubfolders, label, onToggle, }) => (React__namespace["default"].createElement(ViewElement, { className: `${STORAGE_BROWSER_BLOCK}__search-subfolders-toggle` },
|
|
1190
|
-
React__namespace["default"].createElement(InputElement, { checked: isSearchingSubfolders, id: SEARCH_SUBFOLDERS_TOGGLE_ID, onChange: onToggle, type: "checkbox" }),
|
|
1191
|
-
React__namespace["default"].createElement(LabelElement, { htmlFor: SEARCH_SUBFOLDERS_TOGGLE_ID }, label)));
|
|
1192
|
-
|
|
1193
|
-
const StatusDisplay$1 = ({ statuses, total, }) => {
|
|
1194
|
-
if (!statuses?.length) {
|
|
1195
|
-
return null;
|
|
1196
|
-
}
|
|
1197
|
-
const descriptions = statuses.map(({ name, count }) => ({
|
|
1198
|
-
term: name,
|
|
1199
|
-
details: `${count}/${total}`,
|
|
1200
|
-
}));
|
|
1201
|
-
return (React__namespace["default"].createElement(DescriptionList, { className: `${STORAGE_BROWSER_BLOCK}__status-display`, descriptions: descriptions }));
|
|
1202
|
-
};
|
|
1203
|
-
|
|
1204
|
-
const Title$1 = ({ title }) => (React__namespace["default"].createElement(HeadingElement, { className: `${STORAGE_BROWSER_BLOCK}__title` }, title));
|
|
1205
|
-
|
|
1206
|
-
const DEFAULT_COMPOSABLES = {
|
|
1207
|
-
ActionCancel,
|
|
1208
|
-
ActionDestination: ActionDestination$1,
|
|
1209
|
-
ActionExit,
|
|
1210
|
-
ActionStart,
|
|
1211
|
-
ActionsList: ActionsList$1,
|
|
1212
|
-
AddFiles,
|
|
1213
|
-
AddFolder,
|
|
1214
|
-
DataRefresh: DataRefresh$1,
|
|
1215
|
-
DataTable,
|
|
1216
|
-
DropZone,
|
|
1217
|
-
FolderNameField: FolderNameField$1,
|
|
1218
|
-
LoadingIndicator: LoadingIndicator$1,
|
|
1219
|
-
Message,
|
|
1220
|
-
Navigation: Navigation$1,
|
|
1221
|
-
OverwriteToggle: OverwriteToggle$1,
|
|
1222
|
-
Pagination: Pagination$1,
|
|
1223
|
-
SearchSubfoldersToggle: SearchSubfoldersToggle$1,
|
|
1224
|
-
SearchField: SearchField$1,
|
|
1225
|
-
StatusDisplay: StatusDisplay$1,
|
|
1226
|
-
Title: Title$1,
|
|
1227
|
-
};
|
|
1228
|
-
|
|
1229
|
-
function ComponentsProvider(props) {
|
|
1230
|
-
const { children, composables } = props;
|
|
1231
|
-
return (React__namespace["default"].createElement(elements.ElementsProvider, { elements: elementsDefault },
|
|
1232
|
-
React__namespace["default"].createElement(ComposablesProvider, { composables: composables }, children)));
|
|
1150
|
+
function PreviewPlaceholder() {
|
|
1151
|
+
return (React__namespace["default"].createElement(ViewElement, { className: `${STORAGE_BROWSER_BLOCK}__preview-placeholder` },
|
|
1152
|
+
React__namespace["default"].createElement(ViewElement, { className: `${STORAGE_BROWSER_BLOCK}__preview-placeholder-content` },
|
|
1153
|
+
React__namespace["default"].createElement(uiReact.Placeholder, { width: "100%", height: "400px" }))));
|
|
1233
1154
|
}
|
|
1234
1155
|
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
};
|
|
1245
|
-
const Pagination = ({ page = 1, onPaginate, hasNextPage, highestPageVisited, }) => {
|
|
1246
|
-
return (React__namespace.createElement(uiReact.Pagination, { currentPage: page, totalPages: highestPageVisited ?? 1, hasMorePages: hasNextPage, siblingCount: 1, onChange: (index) => {
|
|
1247
|
-
onPaginate?.(index ?? 0);
|
|
1248
|
-
}, onNext: () => {
|
|
1249
|
-
onPaginate?.(page + 1);
|
|
1250
|
-
}, onPrevious: () => {
|
|
1251
|
-
onPaginate?.(page - 1);
|
|
1252
|
-
} }));
|
|
1253
|
-
};
|
|
1254
|
-
const SearchField = ({ onQueryChange, onSearch, onClear, placeholder, label, query, }) => {
|
|
1255
|
-
return (React__namespace.createElement(uiReact.SearchField, { label: label, size: "small", clearButtonLabel: "Clear search", placeholder: placeholder, value: query, onChange: (e) => {
|
|
1256
|
-
onQueryChange?.(e.target.value);
|
|
1257
|
-
}, onSubmit: () => {
|
|
1258
|
-
onSearch?.();
|
|
1259
|
-
}, onClear: () => {
|
|
1260
|
-
onClear?.();
|
|
1261
|
-
} }));
|
|
1262
|
-
};
|
|
1263
|
-
const Navigation = ({ items }) => {
|
|
1264
|
-
return (React__namespace.createElement(uiReact.Breadcrumbs.Container, null, items.map((item, i) => {
|
|
1265
|
-
return (React__namespace.createElement(uiReact.Breadcrumbs.Item, { key: i },
|
|
1266
|
-
React__namespace.createElement(uiReact.Breadcrumbs.Link, { as: item.isCurrent ? 'span' : 'button', isCurrent: item.isCurrent, onClick: item.onNavigate }, item.name),
|
|
1267
|
-
item.isCurrent ? null : React__namespace.createElement(uiReact.Breadcrumbs.Separator, null)));
|
|
1268
|
-
})));
|
|
1269
|
-
};
|
|
1270
|
-
const LoadingIndicator = ({ isLoading, }) => {
|
|
1271
|
-
if (isLoading) {
|
|
1272
|
-
return (React__namespace.createElement(uiReact.Loader, { className: "amplify-storage-browser__loader", variation: "linear", size: "small" }));
|
|
1273
|
-
}
|
|
1274
|
-
};
|
|
1275
|
-
const FolderNameField = ({ onChange, label, placeholder, validationMessage, onValidate, }) => {
|
|
1276
|
-
const handleValidate = ({ target: { value }, }) => {
|
|
1277
|
-
onValidate?.(value);
|
|
1278
|
-
};
|
|
1279
|
-
return (React__namespace.createElement(uiReact.TextField, { label: label, placeholder: placeholder, errorMessage: validationMessage, hasError: !!validationMessage, onBlur: handleValidate, onChange: (event) => {
|
|
1280
|
-
const { value } = event.target;
|
|
1281
|
-
handleValidate?.(event);
|
|
1282
|
-
onChange?.(value);
|
|
1283
|
-
} }));
|
|
1284
|
-
};
|
|
1285
|
-
const DataRefresh = ({ onRefresh, }) => {
|
|
1286
|
-
return (React__namespace.createElement(uiReact.Button, { onClick: () => {
|
|
1287
|
-
onRefresh?.();
|
|
1288
|
-
}, "aria-label": "Refresh data" },
|
|
1289
|
-
React__namespace.createElement(IconElement, { className: "amplify-icon", variant: "refresh" })));
|
|
1290
|
-
};
|
|
1291
|
-
const ActionsList = ({ items, onActionSelect, isDisabled, }) => {
|
|
1292
|
-
return (React__namespace.createElement(uiReact.Menu, { isDisabled: isDisabled, trigger: React__namespace.createElement(uiReact.Button, { ariaLabel: "Menu Toggle" },
|
|
1293
|
-
React__namespace.createElement(IconElement, { className: "amplify-icon", variant: "menu" })) }, items
|
|
1294
|
-
.filter(({ isHidden }) => !isHidden)
|
|
1295
|
-
.map(({ actionType, icon, label, isDisabled }, i) => {
|
|
1296
|
-
return (React__namespace.createElement(uiReact.MenuItem, { key: i, size: "small", gap: "xs", isDisabled: isDisabled, onClick: () => {
|
|
1297
|
-
onActionSelect?.(actionType);
|
|
1298
|
-
} },
|
|
1299
|
-
icon && React__namespace.createElement(IconElement, { variant: icon }),
|
|
1300
|
-
label));
|
|
1301
|
-
})));
|
|
1302
|
-
};
|
|
1303
|
-
const StatusDisplay = ({ statuses, total, }) => {
|
|
1304
|
-
if (!statuses?.length) {
|
|
1305
|
-
return null;
|
|
1306
|
-
}
|
|
1307
|
-
return (React__namespace.createElement(uiReact.View, { as: "dl", className: `${STORAGE_BROWSER_BLOCK}__status-display` }, statuses.map(({ name, count }, i) => (React__namespace.createElement(uiReact.View, { as: "div", className: `${STORAGE_BROWSER_BLOCK}__status`, key: i },
|
|
1308
|
-
React__namespace.createElement(uiReact.View, { as: "dt", className: `${STORAGE_BROWSER_BLOCK}__status-label` }, name),
|
|
1309
|
-
React__namespace.createElement(uiReact.View, { as: "dd", className: `${STORAGE_BROWSER_BLOCK}__status-value` }, `${count}/${total}`))))));
|
|
1310
|
-
};
|
|
1311
|
-
const ActionDestination = ({ isNavigable, items, label, }) => {
|
|
1312
|
-
if (!items.length) {
|
|
1313
|
-
return null;
|
|
1314
|
-
}
|
|
1315
|
-
return (React__namespace.createElement(uiReact.View, { as: "dl", className: `${STORAGE_BROWSER_BLOCK}__destination` },
|
|
1316
|
-
React__namespace.createElement(uiReact.View, { as: "dt", className: `${STORAGE_BROWSER_BLOCK}__destination-label` }, label),
|
|
1317
|
-
React__namespace.createElement(uiReact.View, { as: "dd", className: `${STORAGE_BROWSER_BLOCK}__destination-value` },
|
|
1318
|
-
React__namespace.createElement(uiReact.Breadcrumbs.Container, null, items.map((item, i) => {
|
|
1319
|
-
return (React__namespace.createElement(uiReact.Breadcrumbs.Item, { key: i },
|
|
1320
|
-
isNavigable ? (React__namespace.createElement(uiReact.Breadcrumbs.Link, { as: item.isCurrent ? 'span' : 'button', isCurrent: item.isCurrent, onClick: item.onNavigate }, item.name)) : (item.name),
|
|
1321
|
-
item.isCurrent ? null : React__namespace.createElement(uiReact.Breadcrumbs.Separator, null)));
|
|
1322
|
-
})))));
|
|
1323
|
-
};
|
|
1324
|
-
const Title = ({ title }) => {
|
|
1325
|
-
return (React__namespace.createElement(uiReact.Heading, { className: `${STORAGE_BROWSER_BLOCK}__title`, level: 2 }, title));
|
|
1326
|
-
};
|
|
1327
|
-
const componentsDefault = {
|
|
1328
|
-
ActionDestination,
|
|
1329
|
-
ActionsList,
|
|
1330
|
-
DataRefresh,
|
|
1331
|
-
LoadingIndicator,
|
|
1332
|
-
Pagination,
|
|
1333
|
-
Navigation,
|
|
1334
|
-
OverwriteToggle,
|
|
1335
|
-
SearchField,
|
|
1336
|
-
SearchSubfoldersToggle,
|
|
1337
|
-
StatusDisplay,
|
|
1338
|
-
FolderNameField,
|
|
1339
|
-
Title,
|
|
1340
|
-
};
|
|
1341
|
-
|
|
1342
|
-
const Fallback = () => (React__namespace["default"].createElement("div", { className: STORAGE_BROWSER_BLOCK_TO_BE_UPDATED },
|
|
1343
|
-
React__namespace["default"].createElement("div", { className: `${STORAGE_BROWSER_BLOCK_TO_BE_UPDATED}__error-boundary` }, "Something went wrong.")));
|
|
1344
|
-
class ErrorBoundary extends React__namespace["default"].Component {
|
|
1345
|
-
constructor(props) {
|
|
1346
|
-
super(props);
|
|
1347
|
-
this.state = { hasError: false };
|
|
1348
|
-
}
|
|
1349
|
-
static getDerivedStateFromError(_error) {
|
|
1350
|
-
// Update state so the next render will show the fallback UI.
|
|
1351
|
-
return { hasError: true };
|
|
1352
|
-
}
|
|
1353
|
-
render() {
|
|
1354
|
-
const { hasError } = this.state;
|
|
1355
|
-
const { children } = this.props;
|
|
1356
|
-
if (hasError) {
|
|
1357
|
-
return React__namespace["default"].createElement(Fallback, null);
|
|
1358
|
-
}
|
|
1359
|
-
return children;
|
|
1360
|
-
}
|
|
1156
|
+
/**
|
|
1157
|
+
* Extracts the filename from a file key path
|
|
1158
|
+
* @param fileKey - The full file key/path
|
|
1159
|
+
* @returns The filename (last part after '/') or empty string if fileKey is null/undefined
|
|
1160
|
+
*/
|
|
1161
|
+
function getFileName(fileKey) {
|
|
1162
|
+
if (!fileKey)
|
|
1163
|
+
return '';
|
|
1164
|
+
return fileKey.split('/').pop() ?? fileKey;
|
|
1361
1165
|
}
|
|
1362
1166
|
|
|
1363
1167
|
const { ActionHandlersProvider, useActionHandlers } = uiReactCore.createContextUtilities({
|
|
@@ -2204,938 +2008,1706 @@ const getActionHandlers = (configs) => {
|
|
|
2204
2008
|
: { ...handlers, [key]: resolveHandler(config) }, defaultHandlers);
|
|
2205
2009
|
};
|
|
2206
2010
|
|
|
2207
|
-
const
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2011
|
+
const DEFAULT_ACTION_VIEW_DISPLAY_TEXT = {
|
|
2012
|
+
actionCancelLabel: 'Cancel',
|
|
2013
|
+
actionExitLabel: 'Exit',
|
|
2014
|
+
actionDestinationLabel: 'Destination',
|
|
2015
|
+
statusDisplayCanceledLabel: 'Canceled',
|
|
2016
|
+
statusDisplayCompletedLabel: 'Completed',
|
|
2017
|
+
statusDisplayFailedLabel: 'Failed',
|
|
2018
|
+
statusDisplayInProgressLabel: 'In progress',
|
|
2019
|
+
statusDisplayTotalLabel: 'Total',
|
|
2020
|
+
statusDisplayQueuedLabel: 'Not started',
|
|
2021
|
+
// empty by default
|
|
2022
|
+
tableColumnCancelHeader: '',
|
|
2023
|
+
tableColumnStatusHeader: 'Status',
|
|
2024
|
+
tableColumnFolderHeader: 'Folder',
|
|
2025
|
+
tableColumnNameHeader: 'Name',
|
|
2026
|
+
tableColumnTypeHeader: 'Type',
|
|
2027
|
+
tableColumnSizeHeader: 'Size',
|
|
2028
|
+
};
|
|
2029
|
+
const DEFAULT_LIST_VIEW_DISPLAY_TEXT = {
|
|
2030
|
+
loadingIndicatorLabel: 'Loading',
|
|
2031
|
+
searchSubmitLabel: 'Submit',
|
|
2032
|
+
searchClearLabel: 'Clear search',
|
|
2033
|
+
getDateDisplayValue: (date) => new Intl.DateTimeFormat('en-US', {
|
|
2034
|
+
month: 'short',
|
|
2035
|
+
day: 'numeric',
|
|
2036
|
+
hour: 'numeric',
|
|
2037
|
+
year: 'numeric',
|
|
2038
|
+
minute: 'numeric',
|
|
2039
|
+
hourCycle: 'h12',
|
|
2040
|
+
}).format(date),
|
|
2220
2041
|
};
|
|
2221
2042
|
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2043
|
+
const DEFAULT_CREATE_FOLDER_VIEW_DISPLAY_TEXT = {
|
|
2044
|
+
...DEFAULT_ACTION_VIEW_DISPLAY_TEXT,
|
|
2045
|
+
title: 'Create folder',
|
|
2046
|
+
actionStartLabel: 'Create folder',
|
|
2047
|
+
folderNameLabel: 'Folder name',
|
|
2048
|
+
folderNamePlaceholder: 'Folder name cannot contain "/", nor end or start with "."',
|
|
2049
|
+
getValidationMessage: () => 'Folder name cannot contain "/", nor end or start with "."',
|
|
2050
|
+
getActionCompleteMessage: (data) => {
|
|
2051
|
+
const { counts } = data ?? {};
|
|
2052
|
+
const { FAILED, OVERWRITE_PREVENTED } = counts ?? {};
|
|
2053
|
+
if (OVERWRITE_PREVENTED) {
|
|
2054
|
+
return {
|
|
2055
|
+
content: 'A folder already exists with the provided name',
|
|
2056
|
+
type: 'warning',
|
|
2057
|
+
};
|
|
2058
|
+
}
|
|
2059
|
+
if (FAILED) {
|
|
2060
|
+
return {
|
|
2061
|
+
content: 'There was an issue creating the folder.',
|
|
2062
|
+
type: 'error',
|
|
2063
|
+
};
|
|
2064
|
+
}
|
|
2065
|
+
return { content: 'Folder created.', type: 'success' };
|
|
2066
|
+
},
|
|
2239
2067
|
};
|
|
2240
2068
|
|
|
2241
|
-
const
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2069
|
+
const DEFAULT_COPY_VIEW_DISPLAY_TEXT = {
|
|
2070
|
+
...DEFAULT_ACTION_VIEW_DISPLAY_TEXT,
|
|
2071
|
+
title: 'Copy',
|
|
2072
|
+
actionStartLabel: 'Copy',
|
|
2073
|
+
actionDestinationLabel: 'Copy destination',
|
|
2074
|
+
getListFoldersResultsMessage: ({ folders, query, message, hasError, hasExhaustedSearch, }) => {
|
|
2075
|
+
if (!folders?.length) {
|
|
2076
|
+
return {
|
|
2077
|
+
content: query
|
|
2078
|
+
? `No folders found matching "${query}"`
|
|
2079
|
+
: 'No subfolders found within selected folder.',
|
|
2080
|
+
type: 'info',
|
|
2081
|
+
};
|
|
2082
|
+
}
|
|
2083
|
+
if (message && !!query) {
|
|
2084
|
+
return { content: 'Error loading folders.', type: 'error' };
|
|
2085
|
+
}
|
|
2086
|
+
if (hasError) {
|
|
2087
|
+
return { content: 'Error loading folders.', type: 'error' };
|
|
2088
|
+
}
|
|
2089
|
+
if (hasExhaustedSearch) {
|
|
2090
|
+
return {
|
|
2091
|
+
content: 'Showing results for up to the first 10,000 items.',
|
|
2092
|
+
type: 'info',
|
|
2093
|
+
};
|
|
2094
|
+
}
|
|
2095
|
+
},
|
|
2096
|
+
loadingIndicatorLabel: 'Loading',
|
|
2097
|
+
overwriteWarningMessage: 'Copied files will overwrite existing files at selected destination.',
|
|
2098
|
+
searchPlaceholder: 'Search for folders',
|
|
2099
|
+
getActionCompleteMessage: (data) => {
|
|
2100
|
+
const { counts } = data ?? {};
|
|
2101
|
+
const { COMPLETE, FAILED, TOTAL } = counts ?? {};
|
|
2102
|
+
if (COMPLETE === TOTAL) {
|
|
2103
|
+
return {
|
|
2104
|
+
content: 'All files copied.',
|
|
2105
|
+
type: 'success',
|
|
2106
|
+
};
|
|
2107
|
+
}
|
|
2108
|
+
if (FAILED === TOTAL) {
|
|
2109
|
+
return { content: 'All files failed to copy.', type: 'error' };
|
|
2248
2110
|
}
|
|
2249
|
-
const destinationPath = `${destinationSubpaths.concat('').join('/')}`;
|
|
2250
|
-
const destination = {
|
|
2251
|
-
id: crypto.randomUUID(),
|
|
2252
|
-
type,
|
|
2253
|
-
permissions,
|
|
2254
|
-
bucket,
|
|
2255
|
-
prefix,
|
|
2256
|
-
};
|
|
2257
2111
|
return {
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
onNavigate: () => {
|
|
2261
|
-
onNavigate?.(destination, destinationPath);
|
|
2262
|
-
},
|
|
2112
|
+
content: `${COMPLETE} files copied, ${FAILED} files failed to copy.`,
|
|
2113
|
+
type: 'error',
|
|
2263
2114
|
};
|
|
2264
|
-
}
|
|
2115
|
+
},
|
|
2116
|
+
searchSubmitLabel: 'Submit',
|
|
2117
|
+
searchClearLabel: 'Clear search',
|
|
2265
2118
|
};
|
|
2266
2119
|
|
|
2267
|
-
const
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
if (trimmedPrefix) {
|
|
2277
|
-
if (includeBucketInPrefix) {
|
|
2278
|
-
firstPrefixPart.push('/');
|
|
2279
|
-
}
|
|
2280
|
-
firstPrefixPart.push(trimmedPrefix);
|
|
2120
|
+
const DEFAULT_DELETE_VIEW_DISPLAY_TEXT = {
|
|
2121
|
+
...DEFAULT_ACTION_VIEW_DISPLAY_TEXT,
|
|
2122
|
+
title: 'Delete',
|
|
2123
|
+
actionStartLabel: 'Delete',
|
|
2124
|
+
getActionCompleteMessage: (data) => {
|
|
2125
|
+
const { counts } = data ?? {};
|
|
2126
|
+
const { COMPLETE, FAILED, TOTAL } = counts ?? {};
|
|
2127
|
+
if (COMPLETE === TOTAL) {
|
|
2128
|
+
return { content: 'All files deleted.', type: 'success' };
|
|
2281
2129
|
}
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
if (type === 'BUCKET' && trimmedPrefix) {
|
|
2285
|
-
prefixParts.push(trimmedPrefix);
|
|
2286
|
-
}
|
|
2287
|
-
const pathParts = trimmedPath ? trimmedPath.split('/') : [];
|
|
2288
|
-
return prefixParts.concat(pathParts);
|
|
2289
|
-
};
|
|
2290
|
-
|
|
2291
|
-
const useActionDestination = () => {
|
|
2292
|
-
const { data, onSelectDestination } = useControlsContext();
|
|
2293
|
-
const { actionDestinationLabel, isActionDestinationNavigable, destination } = data;
|
|
2294
|
-
return React__namespace["default"].useMemo(() => {
|
|
2295
|
-
if (!destination?.current) {
|
|
2296
|
-
return { items: [] };
|
|
2130
|
+
if (FAILED === TOTAL) {
|
|
2131
|
+
return { content: 'All files failed to delete.', type: 'error' };
|
|
2297
2132
|
}
|
|
2298
|
-
const { current, path } = destination;
|
|
2299
|
-
const destinationParts = getNavigationParts({
|
|
2300
|
-
location: current,
|
|
2301
|
-
path,
|
|
2302
|
-
});
|
|
2303
2133
|
return {
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
location: current,
|
|
2307
|
-
destinationParts,
|
|
2308
|
-
onNavigate: onSelectDestination,
|
|
2309
|
-
}),
|
|
2310
|
-
isNavigable: isActionDestinationNavigable,
|
|
2134
|
+
content: `${COMPLETE} files deleted, ${FAILED} files failed to delete.`,
|
|
2135
|
+
type: 'error',
|
|
2311
2136
|
};
|
|
2312
|
-
},
|
|
2313
|
-
actionDestinationLabel,
|
|
2314
|
-
isActionDestinationNavigable,
|
|
2315
|
-
destination,
|
|
2316
|
-
onSelectDestination,
|
|
2317
|
-
]);
|
|
2318
|
-
};
|
|
2319
|
-
|
|
2320
|
-
const ActionDestinationControl = () => {
|
|
2321
|
-
const props = useActionDestination();
|
|
2322
|
-
const Resolved = useResolvedComposable(ActionDestination$1, 'ActionDestination');
|
|
2323
|
-
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
2324
|
-
};
|
|
2325
|
-
|
|
2326
|
-
const useActionExit = () => {
|
|
2327
|
-
const { data: { actionExitLabel: label, isActionExitDisabled: isDisabled }, onActionExit: onExit, } = useControlsContext();
|
|
2328
|
-
return { label, isDisabled, onExit };
|
|
2137
|
+
},
|
|
2329
2138
|
};
|
|
2330
2139
|
|
|
2331
|
-
const
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2140
|
+
const DEFAULT_ERROR_MESSAGE$1 = 'There was an error loading items.';
|
|
2141
|
+
const DEFAULT_FILE_PREVIEW_DISPLAY_TEXT = {
|
|
2142
|
+
closeButtonLabel: 'Close',
|
|
2143
|
+
filePreviewTitle: 'File Preview',
|
|
2144
|
+
fileInformationTitle: 'File Information',
|
|
2145
|
+
errorMessage: 'Something went wrong',
|
|
2146
|
+
sizeLimitMessage: 'File preview not possible due to preview size limit',
|
|
2147
|
+
unsupportedFileMessage: 'File preview not supported for this file type',
|
|
2148
|
+
keyLabel: 'Key',
|
|
2149
|
+
sizeLabel: 'Size',
|
|
2150
|
+
versionIdLabel: 'Version Id',
|
|
2151
|
+
lastModifiedLabel: 'Last Modified',
|
|
2152
|
+
entityTagLabel: 'Entity tag',
|
|
2153
|
+
typeLabel: 'Type',
|
|
2154
|
+
unknownValue: 'Unknown',
|
|
2155
|
+
errorDescription: 'We encountered an issue while loading the file preview.',
|
|
2156
|
+
unsupportedFileDescription: 'This file format is not supported for preview. You can download the file to view it with an appropriate application.',
|
|
2157
|
+
imageLoadErrorDescription: 'The image could not be loaded. This may be due to network issues, file corruption, or an unsupported image format.',
|
|
2158
|
+
videoLoadErrorDescription: 'The video could not be played. This may be due to network issues, file corruption, or an unsupported video format or codec.',
|
|
2159
|
+
textLoadErrorDescription: 'The text file could not be loaded. This may be due to network issues, file access permissions, or the file being too large to display.',
|
|
2160
|
+
generalPreviewErrorDescription: 'An unexpected error occurred while loading the file preview. Please try again or download the file to view it with an appropriate application.',
|
|
2161
|
+
fileSizeLimitDescription: 'This file is too large to preview in the browser. You can download the file to view it with an appropriate application.',
|
|
2162
|
+
filePrefix: 'File: ',
|
|
2163
|
+
retryButtonLabel: 'Retry',
|
|
2164
|
+
downloadButtonLabel: 'Download',
|
|
2165
|
+
getTextErrorMessage: (error) => `Error loading file: ${error}`,
|
|
2166
|
+
emptyFileMessage: 'File is empty',
|
|
2335
2167
|
};
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2168
|
+
const DEFAULT_LOCATION_DETAIL_VIEW_DISPLAY_TEXT = {
|
|
2169
|
+
...DEFAULT_LIST_VIEW_DISPLAY_TEXT,
|
|
2170
|
+
getListItemsResultMessage: (data) => {
|
|
2171
|
+
const { items, hasExhaustedSearch, hasError = false, message, isLoading, } = data ?? {};
|
|
2172
|
+
if (isLoading) {
|
|
2173
|
+
return undefined;
|
|
2174
|
+
}
|
|
2175
|
+
if (hasError) {
|
|
2176
|
+
return {
|
|
2177
|
+
type: 'error',
|
|
2178
|
+
content: message ?? DEFAULT_ERROR_MESSAGE$1,
|
|
2179
|
+
};
|
|
2180
|
+
}
|
|
2181
|
+
if (!items?.length && hasExhaustedSearch) {
|
|
2182
|
+
return {
|
|
2183
|
+
type: 'info',
|
|
2184
|
+
content: `No results found in the first 10,000 items.`,
|
|
2185
|
+
};
|
|
2186
|
+
}
|
|
2187
|
+
if (!items?.length) {
|
|
2188
|
+
return {
|
|
2189
|
+
type: 'info',
|
|
2190
|
+
content: 'No files.',
|
|
2191
|
+
};
|
|
2192
|
+
}
|
|
2193
|
+
if (hasExhaustedSearch) {
|
|
2194
|
+
return {
|
|
2195
|
+
type: 'info',
|
|
2196
|
+
content: `Showing results for up to the first 10,000 items.`,
|
|
2197
|
+
};
|
|
2198
|
+
}
|
|
2199
|
+
// TODO: add more cases as needed
|
|
2200
|
+
return undefined;
|
|
2201
|
+
},
|
|
2202
|
+
searchSubfoldersToggleLabel: 'Include subfolders',
|
|
2203
|
+
searchPlaceholder: 'Search current folder',
|
|
2204
|
+
tableColumnLastModifiedHeader: 'Last modified',
|
|
2205
|
+
tableColumnNameHeader: 'Name',
|
|
2206
|
+
tableColumnSizeHeader: 'Size',
|
|
2207
|
+
tableColumnTypeHeader: 'Type',
|
|
2208
|
+
selectFileLabel: 'Select file',
|
|
2209
|
+
selectAllFilesLabel: 'Select all files',
|
|
2210
|
+
getActionListItemLabel: (key = '') => {
|
|
2211
|
+
switch (key) {
|
|
2212
|
+
case 'Copy':
|
|
2213
|
+
return 'Copy';
|
|
2214
|
+
case 'Delete':
|
|
2215
|
+
return 'Delete';
|
|
2216
|
+
case 'Create folder':
|
|
2217
|
+
return 'Create folder';
|
|
2218
|
+
case 'Upload':
|
|
2219
|
+
return 'Upload';
|
|
2220
|
+
case 'Download':
|
|
2221
|
+
return 'Download';
|
|
2222
|
+
default:
|
|
2223
|
+
return key;
|
|
2224
|
+
}
|
|
2225
|
+
},
|
|
2226
|
+
getTitle: (location) => {
|
|
2227
|
+
const { current, key } = location;
|
|
2228
|
+
const { bucket = '' } = current ?? {};
|
|
2229
|
+
return key || bucket;
|
|
2230
|
+
},
|
|
2231
|
+
filePreview: DEFAULT_FILE_PREVIEW_DISPLAY_TEXT,
|
|
2344
2232
|
};
|
|
2345
2233
|
|
|
2346
|
-
const
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
const
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2234
|
+
const DEFAULT_ERROR_MESSAGE = 'There was an error loading locations.';
|
|
2235
|
+
const DEFAULT_LOCATIONS_VIEW_DISPLAY_TEXT = {
|
|
2236
|
+
...DEFAULT_LIST_VIEW_DISPLAY_TEXT,
|
|
2237
|
+
title: 'Home',
|
|
2238
|
+
searchPlaceholder: 'Filter folders and files',
|
|
2239
|
+
getListLocationsResultMessage: (data) => {
|
|
2240
|
+
const { isLoading, items, hasExhaustedSearch, hasError = false, message, } = data ?? {};
|
|
2241
|
+
if (isLoading) {
|
|
2242
|
+
return undefined;
|
|
2243
|
+
}
|
|
2244
|
+
if (hasError) {
|
|
2245
|
+
return {
|
|
2246
|
+
type: 'error',
|
|
2247
|
+
content: message ?? DEFAULT_ERROR_MESSAGE,
|
|
2248
|
+
};
|
|
2249
|
+
}
|
|
2250
|
+
if (items?.length === 0 && !hasExhaustedSearch) {
|
|
2251
|
+
return {
|
|
2252
|
+
type: 'info',
|
|
2253
|
+
content: 'No folders or files.',
|
|
2254
|
+
};
|
|
2255
|
+
}
|
|
2256
|
+
if (hasExhaustedSearch) {
|
|
2257
|
+
return {
|
|
2258
|
+
type: 'info',
|
|
2259
|
+
content: `Showing results for up to the first 10,000 items.`,
|
|
2260
|
+
};
|
|
2261
|
+
}
|
|
2262
|
+
// TODO: add more cases as needed
|
|
2263
|
+
return undefined;
|
|
2264
|
+
},
|
|
2265
|
+
getPermissionName: (permissions) => {
|
|
2266
|
+
let text = '';
|
|
2267
|
+
if (permissions.includes('get') || permissions.includes('list')) {
|
|
2268
|
+
text = 'Read';
|
|
2269
|
+
}
|
|
2270
|
+
if (permissions.includes('write') || permissions.includes('delete')) {
|
|
2271
|
+
text = text ? 'Read/Write' : 'Write';
|
|
2272
|
+
}
|
|
2273
|
+
if (!text) {
|
|
2274
|
+
text = permissions.join('/');
|
|
2275
|
+
}
|
|
2276
|
+
return text;
|
|
2277
|
+
},
|
|
2278
|
+
getDownloadLabel: (fileName) => `Download ${fileName}`,
|
|
2279
|
+
tableColumnBucketHeader: 'Bucket',
|
|
2280
|
+
tableColumnFolderHeader: 'Folder',
|
|
2281
|
+
tableColumnPermissionsHeader: 'Permissions',
|
|
2282
|
+
tableColumnActionsHeader: 'Actions',
|
|
2359
2283
|
};
|
|
2360
2284
|
|
|
2361
|
-
const
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2285
|
+
const DEFAULT_UPLOAD_VIEW_DISPLAY_TEXT = {
|
|
2286
|
+
...DEFAULT_ACTION_VIEW_DISPLAY_TEXT,
|
|
2287
|
+
actionStartLabel: 'Upload',
|
|
2288
|
+
addFilesLabel: 'Add files',
|
|
2289
|
+
addFolderLabel: 'Add folder',
|
|
2290
|
+
getActionCompleteMessage: (data) => {
|
|
2291
|
+
const { counts } = data ?? {};
|
|
2292
|
+
const { COMPLETE, FAILED, OVERWRITE_PREVENTED, CANCELED, TOTAL } = counts ?? {};
|
|
2293
|
+
const hasPreventedOverwrite = !!OVERWRITE_PREVENTED;
|
|
2294
|
+
const hasFailure = !!FAILED;
|
|
2295
|
+
const hasSuccess = !!COMPLETE;
|
|
2296
|
+
const hasCanceled = !!CANCELED;
|
|
2297
|
+
const type = hasFailure
|
|
2298
|
+
? 'error'
|
|
2299
|
+
: hasPreventedOverwrite || hasCanceled
|
|
2300
|
+
? 'warning'
|
|
2301
|
+
: 'success';
|
|
2302
|
+
const preventedOverwriteMessage = hasPreventedOverwrite
|
|
2303
|
+
? [
|
|
2304
|
+
'Overwrite prevented for',
|
|
2305
|
+
OVERWRITE_PREVENTED === TOTAL ? 'all' : String(OVERWRITE_PREVENTED),
|
|
2306
|
+
OVERWRITE_PREVENTED > 1 || OVERWRITE_PREVENTED === TOTAL
|
|
2307
|
+
? `files`
|
|
2308
|
+
: 'file',
|
|
2309
|
+
].join(' ')
|
|
2310
|
+
: undefined;
|
|
2311
|
+
const canceledMessage = hasCanceled
|
|
2312
|
+
? [
|
|
2313
|
+
CANCELED === TOTAL ? 'All' : String(CANCELED),
|
|
2314
|
+
CANCELED > 1 || CANCELED === TOTAL ? `uploads` : 'upload',
|
|
2315
|
+
'canceled',
|
|
2316
|
+
].join(' ')
|
|
2317
|
+
: undefined;
|
|
2318
|
+
const failedMessage = hasFailure
|
|
2319
|
+
? [
|
|
2320
|
+
FAILED === TOTAL ? 'All' : String(FAILED),
|
|
2321
|
+
FAILED > 1 || FAILED === TOTAL ? `files` : 'file',
|
|
2322
|
+
'failed to upload',
|
|
2323
|
+
].join(' ')
|
|
2324
|
+
: undefined;
|
|
2325
|
+
const completedMessage = hasSuccess
|
|
2326
|
+
? [
|
|
2327
|
+
COMPLETE === TOTAL ? 'All' : String(COMPLETE),
|
|
2328
|
+
COMPLETE > 1 || COMPLETE === TOTAL ? `files` : 'file',
|
|
2329
|
+
'uploaded',
|
|
2330
|
+
].join(' ')
|
|
2331
|
+
: undefined;
|
|
2332
|
+
const messages = [
|
|
2333
|
+
preventedOverwriteMessage,
|
|
2334
|
+
failedMessage,
|
|
2335
|
+
canceledMessage,
|
|
2336
|
+
completedMessage,
|
|
2337
|
+
].filter(Boolean);
|
|
2338
|
+
if (messages.length > 0) {
|
|
2339
|
+
return {
|
|
2340
|
+
content: messages.join(', ') + '.',
|
|
2341
|
+
type,
|
|
2342
|
+
};
|
|
2343
|
+
}
|
|
2344
|
+
return { content: 'All files uploaded.', type };
|
|
2345
|
+
},
|
|
2346
|
+
getFilesValidationMessage: (data) => {
|
|
2347
|
+
if (!data?.invalidFiles) {
|
|
2348
|
+
return undefined;
|
|
2349
|
+
}
|
|
2350
|
+
const invalidFileNames = data.invalidFiles
|
|
2351
|
+
.map(({ file }) => file.name)
|
|
2352
|
+
.join(', ');
|
|
2353
|
+
if (invalidFileNames) {
|
|
2354
|
+
return {
|
|
2355
|
+
content: `Files larger than 160GB cannot be added to the upload queue: ${invalidFileNames}`,
|
|
2356
|
+
type: 'warning',
|
|
2357
|
+
};
|
|
2358
|
+
}
|
|
2359
|
+
return undefined;
|
|
2360
|
+
},
|
|
2361
|
+
overwriteToggleLabel: 'Overwrite existing files',
|
|
2362
|
+
statusDisplayOverwritePreventedLabel: 'Overwrite prevented',
|
|
2363
|
+
tableColumnProgressHeader: 'Progress',
|
|
2364
|
+
title: 'Upload',
|
|
2365
2365
|
};
|
|
2366
2366
|
|
|
2367
|
-
const
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2367
|
+
const DEFAULT_DOWNLOAD_VIEW_DISPLAY_TEXT = {
|
|
2368
|
+
...DEFAULT_ACTION_VIEW_DISPLAY_TEXT,
|
|
2369
|
+
title: 'Download',
|
|
2370
|
+
actionStartLabel: 'Download',
|
|
2371
|
+
getActionCompleteMessage: (data) => {
|
|
2372
|
+
const { counts } = data ?? {};
|
|
2373
|
+
const { COMPLETE, FAILED, TOTAL } = counts ?? {};
|
|
2374
|
+
if (COMPLETE === TOTAL) {
|
|
2375
|
+
return { content: 'All files downloaded.', type: 'success' };
|
|
2376
|
+
}
|
|
2377
|
+
if (FAILED === TOTAL) {
|
|
2378
|
+
return { content: 'All files failed to download.', type: 'error' };
|
|
2379
|
+
}
|
|
2380
|
+
return {
|
|
2381
|
+
content: `${COMPLETE} files downloaded, ${FAILED} files failed to download.`,
|
|
2382
|
+
type: 'error',
|
|
2383
|
+
};
|
|
2384
|
+
},
|
|
2374
2385
|
};
|
|
2375
2386
|
|
|
2376
|
-
const
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2387
|
+
const DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT = {
|
|
2388
|
+
CopyView: DEFAULT_COPY_VIEW_DISPLAY_TEXT,
|
|
2389
|
+
CreateFolderView: DEFAULT_CREATE_FOLDER_VIEW_DISPLAY_TEXT,
|
|
2390
|
+
DeleteView: DEFAULT_DELETE_VIEW_DISPLAY_TEXT,
|
|
2391
|
+
DownloadView: DEFAULT_DOWNLOAD_VIEW_DISPLAY_TEXT,
|
|
2392
|
+
LocationDetailView: DEFAULT_LOCATION_DETAIL_VIEW_DISPLAY_TEXT,
|
|
2393
|
+
LocationsView: DEFAULT_LOCATIONS_VIEW_DISPLAY_TEXT,
|
|
2394
|
+
UploadView: DEFAULT_UPLOAD_VIEW_DISPLAY_TEXT,
|
|
2380
2395
|
};
|
|
2381
2396
|
|
|
2382
|
-
const
|
|
2383
|
-
|
|
2397
|
+
const { DisplayTextContext, useDisplayText } = uiReactCore.createContextUtilities({
|
|
2398
|
+
contextName: 'DisplayText',
|
|
2399
|
+
errorMessage: '`useDisplayText` must be called inside `DisplayTextProvider`',
|
|
2400
|
+
});
|
|
2401
|
+
function resolveDisplayText(displayText) {
|
|
2402
|
+
if (!displayText)
|
|
2403
|
+
return DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT;
|
|
2404
|
+
// override
|
|
2405
|
+
const { CopyView, CreateFolderView, DeleteView, DownloadView, LocationDetailView, LocationsView, UploadView, } = displayText;
|
|
2384
2406
|
return {
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2407
|
+
CopyView: { ...DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.CopyView, ...CopyView },
|
|
2408
|
+
CreateFolderView: {
|
|
2409
|
+
...DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.CreateFolderView,
|
|
2410
|
+
...CreateFolderView,
|
|
2411
|
+
},
|
|
2412
|
+
DeleteView: {
|
|
2413
|
+
...DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.DeleteView,
|
|
2414
|
+
...DeleteView,
|
|
2415
|
+
},
|
|
2416
|
+
DownloadView: {
|
|
2417
|
+
...DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.DownloadView,
|
|
2418
|
+
...DownloadView,
|
|
2419
|
+
},
|
|
2420
|
+
LocationDetailView: {
|
|
2421
|
+
...DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.LocationDetailView,
|
|
2422
|
+
...LocationDetailView,
|
|
2423
|
+
filePreview: {
|
|
2424
|
+
...DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.LocationDetailView.filePreview,
|
|
2425
|
+
...(LocationDetailView?.filePreview ?? {}),
|
|
2426
|
+
},
|
|
2427
|
+
},
|
|
2428
|
+
LocationsView: {
|
|
2429
|
+
...DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.LocationsView,
|
|
2430
|
+
...LocationsView,
|
|
2431
|
+
},
|
|
2432
|
+
UploadView: {
|
|
2433
|
+
...DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.UploadView,
|
|
2434
|
+
...UploadView,
|
|
2435
|
+
},
|
|
2388
2436
|
};
|
|
2389
|
-
}
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
const
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
};
|
|
2396
|
-
|
|
2397
|
-
const useDataRefresh = () => {
|
|
2398
|
-
const { data: { isDataRefreshDisabled }, onRefresh, } = useControlsContext();
|
|
2399
|
-
return { isDisabled: isDataRefreshDisabled, onRefresh };
|
|
2400
|
-
};
|
|
2437
|
+
}
|
|
2438
|
+
function DisplayTextProvider({ children, displayText: _override, }) {
|
|
2439
|
+
// do deep merge here of default and override here
|
|
2440
|
+
const resolvedDisplayText = React__namespace["default"].useMemo(() => resolveDisplayText(_override), [_override]);
|
|
2441
|
+
return (React__namespace["default"].createElement(DisplayTextContext.Provider, { value: resolvedDisplayText }, children));
|
|
2442
|
+
}
|
|
2401
2443
|
|
|
2402
|
-
const
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
2406
|
-
};
|
|
2444
|
+
const isCopyViewDisplayTextKey = (value) => !!DEFAULT_COPY_VIEW_DISPLAY_TEXT[value];
|
|
2445
|
+
const isDeleteViewDisplayTextKey = (value) => !!DEFAULT_DELETE_VIEW_DISPLAY_TEXT[value];
|
|
2446
|
+
const isDownloadViewDisplayTextKey = (value) => !!DEFAULT_DOWNLOAD_VIEW_DISPLAY_TEXT[value];
|
|
2407
2447
|
|
|
2408
|
-
const
|
|
2409
|
-
|
|
2410
|
-
|
|
2448
|
+
const DownloadButton = ({ fileKey }) => {
|
|
2449
|
+
const [{ isProcessing: downloadPending }, handleDownload] = useAction('download');
|
|
2450
|
+
const fileName = React.useMemo(() => getFileName(fileKey), [fileKey]);
|
|
2451
|
+
const { LocationDetailView: displayText } = useDisplayText();
|
|
2452
|
+
const { filePreview: { downloadButtonLabel }, } = displayText;
|
|
2453
|
+
const handleDownloadClick = React.useCallback(() => {
|
|
2454
|
+
handleDownload({
|
|
2455
|
+
data: {
|
|
2456
|
+
fileKey: fileName,
|
|
2457
|
+
key: fileKey,
|
|
2458
|
+
id: crypto.randomUUID(),
|
|
2459
|
+
},
|
|
2460
|
+
});
|
|
2461
|
+
}, [fileName, fileKey, handleDownload]);
|
|
2462
|
+
return (React__namespace["default"].createElement(ButtonElement, { ['aria-label']: `Download ${fileName} file`, className: `${STORAGE_BROWSER_BLOCK}__download-button`, onClick: handleDownloadClick, disabled: downloadPending, variant: "primary" },
|
|
2463
|
+
downloadPending ? (React__namespace["default"].createElement(IconElement, { className: `${STORAGE_BROWSER_BLOCK}__download-button_icon`, variant: "action-progress" })) : null,
|
|
2464
|
+
downloadButtonLabel));
|
|
2465
|
+
};
|
|
2466
|
+
|
|
2467
|
+
const DEFAULT_URL_OPTIONS = {
|
|
2468
|
+
expiresIn: 7200,
|
|
2469
|
+
validateObjectExistence: true,
|
|
2470
|
+
};
|
|
2471
|
+
const DEFAULT_FILE_SIZE_LIMIT = 200 * 1024 * 1024; // 200MB
|
|
2472
|
+
const DEFAULT_FILE_SIZE_LIMITS = {
|
|
2473
|
+
image: 200 * 1024 * 1024,
|
|
2474
|
+
video: 2 * 1024 * 1024 * 1024,
|
|
2475
|
+
text: 10 * 1024 * 1024, // 10MB
|
|
2476
|
+
};
|
|
2477
|
+
const GENERIC_CONTENT_TYPES = new Set([
|
|
2478
|
+
'application/octet-stream',
|
|
2479
|
+
'binary/octet-stream',
|
|
2480
|
+
'application/unknown',
|
|
2481
|
+
'unknown/unknown',
|
|
2482
|
+
'application/force-download',
|
|
2483
|
+
'application/download',
|
|
2484
|
+
'application/x-download',
|
|
2485
|
+
'application/binary',
|
|
2486
|
+
]);
|
|
2487
|
+
const EXTENSION_MAPPINGS = {
|
|
2488
|
+
// Images
|
|
2489
|
+
jpg: 'image',
|
|
2490
|
+
jpeg: 'image',
|
|
2491
|
+
png: 'image',
|
|
2492
|
+
gif: 'image',
|
|
2493
|
+
webp: 'image',
|
|
2494
|
+
svg: 'image',
|
|
2495
|
+
bmp: 'image',
|
|
2496
|
+
tiff: 'image',
|
|
2497
|
+
tif: 'image',
|
|
2498
|
+
ico: 'image',
|
|
2499
|
+
heic: 'image',
|
|
2500
|
+
heif: 'image',
|
|
2501
|
+
avif: 'image',
|
|
2502
|
+
// Videos
|
|
2503
|
+
mp4: 'video',
|
|
2504
|
+
avi: 'video',
|
|
2505
|
+
mov: 'video',
|
|
2506
|
+
wmv: 'video',
|
|
2507
|
+
flv: 'video',
|
|
2508
|
+
webm: 'video',
|
|
2509
|
+
mkv: 'video',
|
|
2510
|
+
m4v: 'video',
|
|
2511
|
+
mpg: 'video',
|
|
2512
|
+
mpeg: 'video',
|
|
2513
|
+
'3gp': 'video',
|
|
2514
|
+
ogv: 'video',
|
|
2515
|
+
// Plain text files only
|
|
2516
|
+
txt: 'text',
|
|
2517
|
+
csv: 'text',
|
|
2518
|
+
log: 'text',
|
|
2519
|
+
json: 'text',
|
|
2520
|
+
xml: 'text',
|
|
2521
|
+
yaml: 'text',
|
|
2522
|
+
yml: 'text',
|
|
2523
|
+
ini: 'text',
|
|
2524
|
+
conf: 'text',
|
|
2525
|
+
cfg: 'text',
|
|
2526
|
+
};
|
|
2527
|
+
|
|
2528
|
+
function isGenericContentType(contentType) {
|
|
2529
|
+
if (!contentType || typeof contentType !== 'string') {
|
|
2530
|
+
return true;
|
|
2411
2531
|
}
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
if (a === undefined) {
|
|
2420
|
-
return b === undefined ? 0 : 1;
|
|
2532
|
+
const normalizedContentType = contentType.toLowerCase().trim();
|
|
2533
|
+
return GENERIC_CONTENT_TYPES.has(normalizedContentType);
|
|
2534
|
+
}
|
|
2535
|
+
function isTextBasedApplicationType(contentType) {
|
|
2536
|
+
if (contentType === 'application/json' ||
|
|
2537
|
+
(contentType.startsWith('application/') && contentType.includes('+json'))) {
|
|
2538
|
+
return true;
|
|
2421
2539
|
}
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
? compareContent$2(a.content, b.content)
|
|
2426
|
-
: compareContent$2(b.content, a.content);
|
|
2427
|
-
|
|
2428
|
-
const compareContent$1 = ({ value: a }, { value: b }) => {
|
|
2429
|
-
if (a === undefined) {
|
|
2430
|
-
return b === undefined ? 0 : 1;
|
|
2540
|
+
if (contentType === 'application/xml' ||
|
|
2541
|
+
(contentType.startsWith('application/') && contentType.includes('+xml'))) {
|
|
2542
|
+
return true;
|
|
2431
2543
|
}
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2544
|
+
const textBasedTypes = [
|
|
2545
|
+
'application/csv',
|
|
2546
|
+
'application/yaml',
|
|
2547
|
+
'application/toml',
|
|
2548
|
+
];
|
|
2549
|
+
return textBasedTypes.includes(contentType);
|
|
2550
|
+
}
|
|
2551
|
+
function getFileTypeFromContentType(contentType) {
|
|
2552
|
+
if (!contentType || typeof contentType !== 'string') {
|
|
2553
|
+
return null;
|
|
2441
2554
|
}
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
'
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
const
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
});
|
|
2481
|
-
},
|
|
2482
|
-
sortDirection: sortState.index === index ? sortState.direction : undefined,
|
|
2483
|
-
},
|
|
2484
|
-
};
|
|
2485
|
-
}
|
|
2486
|
-
case 'checkbox':
|
|
2487
|
-
case 'text':
|
|
2488
|
-
default: {
|
|
2489
|
-
return header;
|
|
2555
|
+
const normalizedContentType = contentType.toLowerCase().trim().split(';')[0];
|
|
2556
|
+
if (normalizedContentType.startsWith('image/')) {
|
|
2557
|
+
return 'image';
|
|
2558
|
+
}
|
|
2559
|
+
if (normalizedContentType.startsWith('video/')) {
|
|
2560
|
+
return 'video';
|
|
2561
|
+
}
|
|
2562
|
+
if (normalizedContentType.startsWith('text/') ||
|
|
2563
|
+
isTextBasedApplicationType(normalizedContentType)) {
|
|
2564
|
+
return 'text';
|
|
2565
|
+
}
|
|
2566
|
+
return null;
|
|
2567
|
+
}
|
|
2568
|
+
function getFileExtension(key) {
|
|
2569
|
+
if (!key || typeof key !== 'string') {
|
|
2570
|
+
return null;
|
|
2571
|
+
}
|
|
2572
|
+
const lastDotIndex = key.lastIndexOf('.');
|
|
2573
|
+
if (lastDotIndex === -1 || lastDotIndex === key.length - 1) {
|
|
2574
|
+
return null;
|
|
2575
|
+
}
|
|
2576
|
+
return key.slice(lastDotIndex + 1).toLowerCase();
|
|
2577
|
+
}
|
|
2578
|
+
function getFileTypeFromExtension(extension) {
|
|
2579
|
+
if (!extension || typeof extension !== 'string') {
|
|
2580
|
+
return null;
|
|
2581
|
+
}
|
|
2582
|
+
const normalizedExtension = extension.toLowerCase().trim();
|
|
2583
|
+
return EXTENSION_MAPPINGS[normalizedExtension] || null;
|
|
2584
|
+
}
|
|
2585
|
+
function determineFileType(options) {
|
|
2586
|
+
const { fileData, fileTypeResolver } = options;
|
|
2587
|
+
const { contentType, key } = fileData ?? {};
|
|
2588
|
+
if (typeof fileTypeResolver === 'function') {
|
|
2589
|
+
try {
|
|
2590
|
+
const customResult = fileTypeResolver(fileData);
|
|
2591
|
+
if (customResult !== undefined && customResult !== null) {
|
|
2592
|
+
return customResult;
|
|
2490
2593
|
}
|
|
2491
2594
|
}
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
// Early return if there is no table data
|
|
2495
|
-
if (!tableData) {
|
|
2496
|
-
return;
|
|
2595
|
+
catch (error) {
|
|
2596
|
+
//
|
|
2497
2597
|
}
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2598
|
+
}
|
|
2599
|
+
if (!isGenericContentType(contentType)) {
|
|
2600
|
+
const typeFromContentType = getFileTypeFromContentType(contentType);
|
|
2601
|
+
if (typeFromContentType) {
|
|
2602
|
+
return typeFromContentType;
|
|
2501
2603
|
}
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
};
|
|
2510
|
-
tableData.rows.forEach((row) => {
|
|
2511
|
-
const { type } = row.content[index];
|
|
2512
|
-
groupedRows[type].push(row);
|
|
2513
|
-
});
|
|
2514
|
-
const groupOrder = direction === 'ascending' ? GROUP_ORDER : [...GROUP_ORDER].reverse();
|
|
2515
|
-
return groupOrder
|
|
2516
|
-
.map((groupType) => {
|
|
2517
|
-
if (UNSORTABLE_GROUPS.includes(groupType)) {
|
|
2518
|
-
return groupedRows[groupType];
|
|
2519
|
-
}
|
|
2520
|
-
return groupedRows[groupType].sort((rowA, rowB) => {
|
|
2521
|
-
switch (groupType) {
|
|
2522
|
-
case 'button': {
|
|
2523
|
-
return compareButtonData(rowA.content[index], rowB.content[index], direction);
|
|
2524
|
-
}
|
|
2525
|
-
case 'date': {
|
|
2526
|
-
return compareDateData(rowA.content[index], rowB.content[index], direction);
|
|
2527
|
-
}
|
|
2528
|
-
case 'number': {
|
|
2529
|
-
return compareNumberData(rowA.content[index], rowB.content[index], direction);
|
|
2530
|
-
}
|
|
2531
|
-
case 'text':
|
|
2532
|
-
default: {
|
|
2533
|
-
return compareTextData(rowA.content[index], rowB.content[index], direction);
|
|
2534
|
-
}
|
|
2535
|
-
}
|
|
2536
|
-
});
|
|
2537
|
-
})
|
|
2538
|
-
.flat();
|
|
2539
|
-
}, [sortState, tableData]);
|
|
2540
|
-
return {
|
|
2541
|
-
headers: mappedHeaders ?? [],
|
|
2542
|
-
isLoading,
|
|
2543
|
-
rows: sortedRows ?? [],
|
|
2544
|
-
};
|
|
2545
|
-
};
|
|
2604
|
+
}
|
|
2605
|
+
const extension = getFileExtension(key);
|
|
2606
|
+
if (extension) {
|
|
2607
|
+
return getFileTypeFromExtension(extension);
|
|
2608
|
+
}
|
|
2609
|
+
return null;
|
|
2610
|
+
}
|
|
2546
2611
|
|
|
2547
|
-
const
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2612
|
+
const LOCATION_DETAIL_VIEW_HEADERS = [
|
|
2613
|
+
'checkbox',
|
|
2614
|
+
'name',
|
|
2615
|
+
'type',
|
|
2616
|
+
'last-modified',
|
|
2617
|
+
'size',
|
|
2618
|
+
'download',
|
|
2619
|
+
];
|
|
2620
|
+
const GENERIC_FILE_ICON = 'file';
|
|
2621
|
+
const EXTENSION_THUMBNAIL_MAPPINGS = {
|
|
2622
|
+
// Images
|
|
2623
|
+
jpg: 'file-image',
|
|
2624
|
+
jpeg: 'file-image',
|
|
2625
|
+
png: 'file-image',
|
|
2626
|
+
gif: 'file-image',
|
|
2627
|
+
webp: 'file-image',
|
|
2628
|
+
svg: 'file-image',
|
|
2629
|
+
bmp: 'file-image',
|
|
2630
|
+
tiff: 'file-image',
|
|
2631
|
+
tif: 'file-image',
|
|
2632
|
+
ico: 'file-image',
|
|
2633
|
+
heic: 'file-image',
|
|
2634
|
+
heif: 'file-image',
|
|
2635
|
+
avif: 'file-image',
|
|
2636
|
+
// Videos
|
|
2637
|
+
mp4: 'file-video',
|
|
2638
|
+
avi: 'file-video',
|
|
2639
|
+
mov: 'file-video',
|
|
2640
|
+
wmv: 'file-video',
|
|
2641
|
+
flv: 'file-video',
|
|
2642
|
+
webm: 'file-video',
|
|
2643
|
+
mkv: 'file-video',
|
|
2644
|
+
m4v: 'file-video',
|
|
2645
|
+
mpg: 'file-video',
|
|
2646
|
+
mpeg: 'file-video',
|
|
2647
|
+
'3gp': 'file-video',
|
|
2648
|
+
ogv: 'file-video',
|
|
2649
|
+
// Plain text files only
|
|
2650
|
+
txt: 'file-text',
|
|
2651
|
+
log: 'file-text',
|
|
2652
|
+
json: 'file-text',
|
|
2653
|
+
xml: 'file-text',
|
|
2654
|
+
yaml: 'file-text',
|
|
2655
|
+
yml: 'file-text',
|
|
2656
|
+
ini: 'file-text',
|
|
2657
|
+
conf: 'file-text',
|
|
2658
|
+
cfg: 'file-text',
|
|
2659
|
+
// Audio
|
|
2660
|
+
mp3: 'file-audio',
|
|
2661
|
+
wav: 'file-audio',
|
|
2662
|
+
flac: 'file-audio',
|
|
2663
|
+
aac: 'file-audio',
|
|
2664
|
+
ogg: 'file-audio',
|
|
2665
|
+
wma: 'file-audio',
|
|
2666
|
+
m4a: 'file-audio',
|
|
2667
|
+
// Documents
|
|
2668
|
+
pdf: 'file-pdf',
|
|
2669
|
+
// Excel
|
|
2670
|
+
xls: 'file-excel',
|
|
2671
|
+
xlsx: 'file-excel',
|
|
2672
|
+
csv: 'file-excel',
|
|
2673
|
+
// Word
|
|
2674
|
+
doc: 'file-word',
|
|
2675
|
+
docx: 'file-word',
|
|
2676
|
+
rtf: 'file-word',
|
|
2677
|
+
// PowerPoint
|
|
2678
|
+
ppt: 'file-powerpoint',
|
|
2679
|
+
pptx: 'file-powerpoint',
|
|
2680
|
+
// Archives
|
|
2681
|
+
zip: 'file-archive',
|
|
2682
|
+
rar: 'file-archive',
|
|
2683
|
+
'7z': 'file-archive',
|
|
2684
|
+
tar: 'file-archive',
|
|
2685
|
+
gz: 'file-archive',
|
|
2686
|
+
bz2: 'file-archive',
|
|
2687
|
+
};
|
|
2688
|
+
|
|
2689
|
+
function getFileThumbnail(fileKey) {
|
|
2690
|
+
const extension = getFileExtension(fileKey);
|
|
2691
|
+
if (!fileKey || !extension)
|
|
2692
|
+
return GENERIC_FILE_ICON;
|
|
2693
|
+
return EXTENSION_THUMBNAIL_MAPPINGS[extension] || GENERIC_FILE_ICON;
|
|
2694
|
+
}
|
|
2552
2695
|
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
const
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
}
|
|
2696
|
+
function PreviewFallback({ fileKey, message, description, isError = false, onRetry, showRetry = false, }) {
|
|
2697
|
+
const { LocationDetailView: displayText } = useDisplayText();
|
|
2698
|
+
const { filePreview: { errorDescription, unsupportedFileDescription, filePrefix, retryButtonLabel, }, } = displayText;
|
|
2699
|
+
const fileName = getFileName(fileKey);
|
|
2700
|
+
const fallbackClass = isError
|
|
2701
|
+
? `${STORAGE_BROWSER_BLOCK}__preview-fallback--error`
|
|
2702
|
+
: `${STORAGE_BROWSER_BLOCK}__preview-fallback--default`;
|
|
2703
|
+
return (React__namespace["default"].createElement(ViewElement, { className: ui.classNames(`${STORAGE_BROWSER_BLOCK}__preview-fallback`, fallbackClass) },
|
|
2704
|
+
React__namespace["default"].createElement(ViewElement, { className: `${STORAGE_BROWSER_BLOCK}__preview-fallback-icon` },
|
|
2705
|
+
React__namespace["default"].createElement(IconElement, { className: "amplify-icon", variant: isError ? 'error' : getFileThumbnail(fileKey) })),
|
|
2706
|
+
React__namespace["default"].createElement(ViewElement, null,
|
|
2707
|
+
React__namespace["default"].createElement(TextElement, { className: `${STORAGE_BROWSER_BLOCK}__preview-fallback-title` }, message),
|
|
2708
|
+
React__namespace["default"].createElement(TextElement, { className: `${STORAGE_BROWSER_BLOCK}__preview-fallback-description` }, description ??
|
|
2709
|
+
(isError ? errorDescription : unsupportedFileDescription)),
|
|
2710
|
+
React__namespace["default"].createElement(TextElement, { className: `${STORAGE_BROWSER_BLOCK}__preview-fallback-filename` },
|
|
2711
|
+
filePrefix,
|
|
2712
|
+
fileName)),
|
|
2713
|
+
React__namespace["default"].createElement(ViewElement, { className: `${STORAGE_BROWSER_BLOCK}__preview-fallback-actions` },
|
|
2714
|
+
showRetry && onRetry && (React__namespace["default"].createElement(ButtonElement, { variant: "primary", onClick: onRetry, ['aria-label']: `Retry loading ${fileName} file` }, retryButtonLabel)),
|
|
2715
|
+
React__namespace["default"].createElement(DownloadButton, { fileKey: fileKey }))));
|
|
2716
|
+
}
|
|
2561
2717
|
|
|
2562
|
-
|
|
2563
|
-
const
|
|
2564
|
-
const
|
|
2565
|
-
|
|
2566
|
-
};
|
|
2718
|
+
function ImagePreview({ url, fileKey, }) {
|
|
2719
|
+
const [error, setError] = React.useState(null);
|
|
2720
|
+
const [isLoading, setIsLoading] = React.useState(true);
|
|
2721
|
+
const [imageKey, setImageKey] = React.useState(0);
|
|
2722
|
+
const { LocationDetailView: displayText } = useDisplayText();
|
|
2723
|
+
const { filePreview: { imageLoadErrorDescription }, } = displayText;
|
|
2724
|
+
const handleError = React.useCallback(() => {
|
|
2725
|
+
setError('Failed to load image');
|
|
2726
|
+
setIsLoading(false);
|
|
2727
|
+
}, []);
|
|
2728
|
+
const handleLoad = React.useCallback(() => {
|
|
2729
|
+
setIsLoading(false);
|
|
2730
|
+
setError(null);
|
|
2731
|
+
}, []);
|
|
2732
|
+
const handleRetry = React.useCallback(() => {
|
|
2733
|
+
setError(null);
|
|
2734
|
+
setIsLoading(true);
|
|
2735
|
+
setImageKey((prev) => prev + 1);
|
|
2736
|
+
}, []);
|
|
2737
|
+
if (error) {
|
|
2738
|
+
return (React__namespace["default"].createElement(PreviewFallback, { fileKey: fileKey, message: error, description: imageLoadErrorDescription, isError: true, onRetry: handleRetry, showRetry: true }));
|
|
2739
|
+
}
|
|
2740
|
+
return (React__namespace["default"].createElement("div", { className: `${STORAGE_BROWSER_BLOCK}__image-container` },
|
|
2741
|
+
isLoading && React__namespace["default"].createElement(PreviewPlaceholder, null),
|
|
2742
|
+
React__namespace["default"].createElement("div", { className: `${STORAGE_BROWSER_BLOCK}__image-preview`, style: { display: isLoading ? 'none' : 'flex' } },
|
|
2743
|
+
React__namespace["default"].createElement("img", { key: imageKey, className: ui.classNames(ui.ComponentClassName.StorageImage), src: url, alt: `Image preview for ${getFileName(fileKey)}`, onError: handleError, onLoad: handleLoad }))));
|
|
2744
|
+
}
|
|
2567
2745
|
|
|
2568
|
-
const
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
onChange: onFolderNameChange,
|
|
2576
|
-
onValidate: onValidateFolderName,
|
|
2577
|
-
placeholder: folderNamePlaceholder,
|
|
2578
|
-
validationMessage: folderNameValidationMessage,
|
|
2579
|
-
};
|
|
2580
|
-
};
|
|
2746
|
+
const { FilePreviewContext, useFilePreview: useFilePreviewContext } = uiReactCore.createContextUtilities({
|
|
2747
|
+
contextName: 'FilePreview',
|
|
2748
|
+
defaultValue: {},
|
|
2749
|
+
});
|
|
2750
|
+
function FilePreviewProvider({ children, filePreview, }) {
|
|
2751
|
+
return (React__namespace["default"].createElement(FilePreviewContext.Provider, { value: filePreview }, children));
|
|
2752
|
+
}
|
|
2581
2753
|
|
|
2582
|
-
|
|
2583
|
-
const
|
|
2584
|
-
const
|
|
2585
|
-
|
|
2586
|
-
};
|
|
2754
|
+
function VideoPreview({ url, fileKey, }) {
|
|
2755
|
+
const [error, setError] = React.useState(null);
|
|
2756
|
+
const [isLoading, setIsLoading] = React.useState(true);
|
|
2757
|
+
const [videoKey, setVideoKey] = React.useState(0);
|
|
2758
|
+
const { LocationDetailView: displayText } = useDisplayText();
|
|
2759
|
+
const { filePreview: { videoLoadErrorDescription }, } = displayText;
|
|
2760
|
+
const handleError = React.useCallback((event) => {
|
|
2761
|
+
const videoElement = event.currentTarget;
|
|
2762
|
+
const errorCode = videoElement.error?.code;
|
|
2763
|
+
let errorMessage = 'Failed to load video';
|
|
2764
|
+
switch (errorCode) {
|
|
2765
|
+
case MediaError.MEDIA_ERR_ABORTED:
|
|
2766
|
+
errorMessage = 'Video loading was aborted';
|
|
2767
|
+
break;
|
|
2768
|
+
case MediaError.MEDIA_ERR_NETWORK:
|
|
2769
|
+
errorMessage = 'Network error occurred while loading video';
|
|
2770
|
+
break;
|
|
2771
|
+
case MediaError.MEDIA_ERR_DECODE:
|
|
2772
|
+
errorMessage = 'Video format is not supported or corrupted';
|
|
2773
|
+
break;
|
|
2774
|
+
case MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED:
|
|
2775
|
+
errorMessage = 'Video format is not supported';
|
|
2776
|
+
break;
|
|
2777
|
+
default:
|
|
2778
|
+
errorMessage = 'An unknown error occurred while loading video';
|
|
2779
|
+
}
|
|
2780
|
+
setError(errorMessage);
|
|
2781
|
+
setIsLoading(false);
|
|
2782
|
+
}, []);
|
|
2783
|
+
const handleLoadStart = React.useCallback(() => {
|
|
2784
|
+
setIsLoading(true);
|
|
2785
|
+
setError(null);
|
|
2786
|
+
}, []);
|
|
2787
|
+
const handleLoadedData = React.useCallback(() => {
|
|
2788
|
+
setIsLoading(false);
|
|
2789
|
+
setError(null);
|
|
2790
|
+
}, []);
|
|
2791
|
+
const handleRetry = React.useCallback(() => {
|
|
2792
|
+
setError(null);
|
|
2793
|
+
setIsLoading(true);
|
|
2794
|
+
setVideoKey((prev) => prev + 1);
|
|
2795
|
+
}, []);
|
|
2796
|
+
if (error) {
|
|
2797
|
+
return (React__namespace["default"].createElement(PreviewFallback, { fileKey: fileKey, message: error, description: videoLoadErrorDescription, isError: true, onRetry: handleRetry, showRetry: true }));
|
|
2798
|
+
}
|
|
2799
|
+
return (React__namespace["default"].createElement("div", { className: `${STORAGE_BROWSER_BLOCK}__video-container` },
|
|
2800
|
+
isLoading && React__namespace["default"].createElement(PreviewPlaceholder, null),
|
|
2801
|
+
React__namespace["default"].createElement("div", { className: `${STORAGE_BROWSER_BLOCK}__video-preview`, style: { display: isLoading ? 'none' : 'flex' } },
|
|
2802
|
+
React__namespace["default"].createElement("video", { key: videoKey, controls: true, preload: "metadata", onError: handleError, onLoadStart: handleLoadStart, onLoadedData: handleLoadedData, "aria-label": `Video preview for ${getFileName(fileKey)}` },
|
|
2803
|
+
React__namespace["default"].createElement("source", { src: url }),
|
|
2804
|
+
"Your browser does not support the video tag."))));
|
|
2805
|
+
}
|
|
2587
2806
|
|
|
2588
|
-
|
|
2589
|
-
const
|
|
2590
|
-
|
|
2591
|
-
|
|
2807
|
+
function TextPreview({ url, fileKey, }) {
|
|
2808
|
+
const [content, setContent] = React.useState('');
|
|
2809
|
+
const [isLoading, setIsLoading] = React.useState(true);
|
|
2810
|
+
const [error, setError] = React.useState(null);
|
|
2811
|
+
const [retryCount, setRetryCount] = React.useState(0);
|
|
2812
|
+
const { LocationDetailView: displayText } = useDisplayText();
|
|
2813
|
+
const { filePreview: { emptyFileMessage, textLoadErrorDescription }, } = displayText;
|
|
2814
|
+
const handleRetry = React.useCallback(() => {
|
|
2815
|
+
setRetryCount((prev) => prev + 1);
|
|
2816
|
+
}, []);
|
|
2817
|
+
React.useEffect(() => {
|
|
2818
|
+
if (!url)
|
|
2819
|
+
return;
|
|
2820
|
+
const controller = new AbortController();
|
|
2821
|
+
async function loadTextFileContent() {
|
|
2822
|
+
try {
|
|
2823
|
+
setIsLoading(true);
|
|
2824
|
+
setError(null);
|
|
2825
|
+
const response = await fetch(url, {
|
|
2826
|
+
signal: controller.signal,
|
|
2827
|
+
});
|
|
2828
|
+
if (!response.ok) {
|
|
2829
|
+
throw new Error(`Failed to fetch file: ${response.statusText}`);
|
|
2830
|
+
}
|
|
2831
|
+
const textContent = await response.text();
|
|
2832
|
+
setContent(textContent);
|
|
2833
|
+
}
|
|
2834
|
+
catch (err) {
|
|
2835
|
+
if (err instanceof Error && err.name !== 'AbortError') {
|
|
2836
|
+
const errorMessage = err.message || 'Failed to load file';
|
|
2837
|
+
setError(errorMessage);
|
|
2838
|
+
}
|
|
2839
|
+
}
|
|
2840
|
+
finally {
|
|
2841
|
+
if (!controller.signal.aborted) {
|
|
2842
|
+
setIsLoading(false);
|
|
2843
|
+
}
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2846
|
+
loadTextFileContent();
|
|
2847
|
+
return () => {
|
|
2848
|
+
controller.abort();
|
|
2849
|
+
};
|
|
2850
|
+
}, [url, fileKey, retryCount]);
|
|
2851
|
+
if (isLoading) {
|
|
2852
|
+
return React__namespace["default"].createElement(PreviewPlaceholder, null);
|
|
2853
|
+
}
|
|
2854
|
+
if (error) {
|
|
2855
|
+
return (React__namespace["default"].createElement(PreviewFallback, { fileKey: fileKey, message: error, description: textLoadErrorDescription, isError: true, onRetry: handleRetry, showRetry: true }));
|
|
2856
|
+
}
|
|
2857
|
+
return (React__namespace["default"].createElement("div", { className: `${STORAGE_BROWSER_BLOCK}__text-container` },
|
|
2858
|
+
React__namespace["default"].createElement(ViewElement, { className: `${STORAGE_BROWSER_BLOCK}__text-preview` }, content || emptyFileMessage)));
|
|
2859
|
+
}
|
|
2592
2860
|
|
|
2593
|
-
const
|
|
2594
|
-
|
|
2595
|
-
const
|
|
2596
|
-
|
|
2597
|
-
};
|
|
2861
|
+
const NONE = 'None';
|
|
2862
|
+
function FileMetadata({ fileData, }) {
|
|
2863
|
+
const { key, lastModified, versionId = NONE, size, eTag } = fileData;
|
|
2864
|
+
const { LocationDetailView: displayText } = useDisplayText();
|
|
2865
|
+
const { filePreview: { keyLabel, sizeLabel, versionIdLabel, lastModifiedLabel, entityTagLabel, typeLabel, fileInformationTitle, unknownValue, }, } = displayText;
|
|
2866
|
+
return (React__namespace["default"].createElement(ViewElement, { className: `${STORAGE_BROWSER_BLOCK}__file-preview-section` },
|
|
2867
|
+
React__namespace["default"].createElement(HeadingElement, { className: `${STORAGE_BROWSER_BLOCK}__file-preview-title` }, fileInformationTitle),
|
|
2868
|
+
React__namespace["default"].createElement(ViewElement, { className: `${STORAGE_BROWSER_BLOCK}__file-metadata` }, [
|
|
2869
|
+
{ label: keyLabel, value: key },
|
|
2870
|
+
{
|
|
2871
|
+
label: sizeLabel,
|
|
2872
|
+
value: ui.humanFileSize(size, true),
|
|
2873
|
+
},
|
|
2874
|
+
{ label: versionIdLabel, value: versionId },
|
|
2875
|
+
{
|
|
2876
|
+
label: lastModifiedLabel,
|
|
2877
|
+
value: lastModified?.toLocaleString() || unknownValue,
|
|
2878
|
+
},
|
|
2879
|
+
{ label: entityTagLabel, value: eTag },
|
|
2880
|
+
{
|
|
2881
|
+
label: typeLabel,
|
|
2882
|
+
value: getFileExtension(key) ?? NONE,
|
|
2883
|
+
},
|
|
2884
|
+
].map(({ label, value }) => (React__namespace["default"].createElement(ViewElement, { key: label, className: `${STORAGE_BROWSER_BLOCK}__file-metadata-item` },
|
|
2885
|
+
React__namespace["default"].createElement(TextElement, { className: `${STORAGE_BROWSER_BLOCK}__file-metadata-label` },
|
|
2886
|
+
label,
|
|
2887
|
+
":"),
|
|
2888
|
+
React__namespace["default"].createElement(TextElement, { className: `${STORAGE_BROWSER_BLOCK}__file-metadata-value` }, value)))))));
|
|
2889
|
+
}
|
|
2598
2890
|
|
|
2599
|
-
|
|
2600
|
-
const {
|
|
2601
|
-
|
|
2602
|
-
|
|
2891
|
+
function FilePreviewLayout({ fileData, children, }) {
|
|
2892
|
+
const { LocationDetailView: displayText } = useDisplayText();
|
|
2893
|
+
const { filePreview: { filePreviewTitle }, } = displayText;
|
|
2894
|
+
return (React__namespace["default"].createElement(React__namespace["default"].Fragment, null,
|
|
2895
|
+
React__namespace["default"].createElement(ViewElement, { className: `${STORAGE_BROWSER_BLOCK}__file-preview-section` },
|
|
2896
|
+
React__namespace["default"].createElement(HeadingElement, { className: `${STORAGE_BROWSER_BLOCK}__file-preview-title` }, filePreviewTitle),
|
|
2897
|
+
React__namespace["default"].createElement("div", { className: `${STORAGE_BROWSER_BLOCK}__file-preview-content` }, children)),
|
|
2898
|
+
React__namespace["default"].createElement(FileMetadata, { fileData: fileData })));
|
|
2899
|
+
}
|
|
2603
2900
|
|
|
2604
|
-
const
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2901
|
+
const rendererMap = {
|
|
2902
|
+
image: ImagePreview,
|
|
2903
|
+
video: VideoPreview,
|
|
2904
|
+
text: TextPreview,
|
|
2608
2905
|
};
|
|
2609
|
-
|
|
2610
|
-
const
|
|
2611
|
-
const {
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2906
|
+
const DefaultRenderer = ({ url, type, fileKey }) => {
|
|
2907
|
+
const { LocationDetailView: displayText } = useDisplayText();
|
|
2908
|
+
const { filePreview: { unsupportedFileDescription, unsupportedFileMessage }, } = displayText;
|
|
2909
|
+
if (type && type in rendererMap) {
|
|
2910
|
+
const PreviewComponent = rendererMap[type];
|
|
2911
|
+
return React__namespace["default"].createElement(PreviewComponent, { fileKey: fileKey, url: url });
|
|
2912
|
+
}
|
|
2913
|
+
return (React__namespace["default"].createElement(PreviewFallback, { fileKey: fileKey, message: unsupportedFileMessage, description: unsupportedFileDescription }));
|
|
2914
|
+
};
|
|
2915
|
+
const ResolvedRenderer = ({ fileKey, url, fileData }) => {
|
|
2916
|
+
const { rendererResolver } = (useFilePreviewContext() ?? {}) || {};
|
|
2917
|
+
if (rendererResolver && fileData.fileType) {
|
|
2918
|
+
const CustomRenderer = rendererResolver(fileData.fileType);
|
|
2919
|
+
if (CustomRenderer) {
|
|
2920
|
+
return React__namespace["default"].createElement(CustomRenderer, { url: url, fileData: fileData });
|
|
2616
2921
|
}
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
location: current,
|
|
2620
|
-
path,
|
|
2621
|
-
includeBucketInPrefix: true,
|
|
2622
|
-
});
|
|
2623
|
-
const homeItem = [
|
|
2624
|
-
{ name: 'Home', onNavigate: onNavigateHome },
|
|
2625
|
-
];
|
|
2626
|
-
return {
|
|
2627
|
-
items: homeItem.concat(getNavigationItems({ location: current, destinationParts, onNavigate })),
|
|
2628
|
-
};
|
|
2629
|
-
}, [location, onNavigate, onNavigateHome]);
|
|
2630
|
-
};
|
|
2631
|
-
|
|
2632
|
-
const NavigationControl = () => {
|
|
2633
|
-
const props = useNavigation();
|
|
2634
|
-
const Resolved = useResolvedComposable(Navigation$1, 'Navigation');
|
|
2635
|
-
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
2922
|
+
}
|
|
2923
|
+
return (React__namespace["default"].createElement(DefaultRenderer, { fileKey: fileKey, url: url, type: fileData.fileType }));
|
|
2636
2924
|
};
|
|
2925
|
+
const FilePreviewContent = ({ filePreview, activeFile, onRetryFilePreview, onSelectActiveFile, activeFileHasNext, activeFileHasPrev, }) => {
|
|
2926
|
+
const { LocationDetailView: displayText } = useDisplayText();
|
|
2927
|
+
const { filePreview: { errorMessage, sizeLimitMessage, generalPreviewErrorDescription, fileSizeLimitDescription, }, } = displayText;
|
|
2928
|
+
const { key } = activeFile;
|
|
2929
|
+
if (filePreview.isLoading) {
|
|
2930
|
+
return (React__namespace["default"].createElement(FilePreviewLayout, { fileData: activeFile },
|
|
2931
|
+
React__namespace["default"].createElement(PreviewPlaceholder, null)));
|
|
2932
|
+
}
|
|
2933
|
+
if (!filePreview.ok) {
|
|
2934
|
+
if (filePreview.error === 'LIMIT_EXCEEDED') {
|
|
2935
|
+
return (React__namespace["default"].createElement(FilePreviewLayout, { fileData: activeFile },
|
|
2936
|
+
React__namespace["default"].createElement(PreviewFallback, { fileKey: key, message: sizeLimitMessage, description: fileSizeLimitDescription })));
|
|
2937
|
+
}
|
|
2938
|
+
return (React__namespace["default"].createElement(FilePreviewLayout, { fileData: activeFile },
|
|
2939
|
+
React__namespace["default"].createElement(PreviewFallback, { fileKey: key, message: errorMessage, description: generalPreviewErrorDescription, isError: true, onRetry: onRetryFilePreview, showRetry: true })));
|
|
2940
|
+
}
|
|
2941
|
+
return (React__namespace["default"].createElement(FilePreviewLayout, { fileData: filePreview.fileData },
|
|
2942
|
+
React__namespace["default"].createElement(ResolvedRenderer, { fileKey: key, url: filePreview.url, fileData: filePreview.fileData }),
|
|
2943
|
+
React__namespace["default"].createElement("div", { style: { display: 'flex', flexFlow: 'row nowrap' } },
|
|
2944
|
+
React__namespace["default"].createElement(ButtonElement, { disabled: !activeFileHasPrev, onClick: () => onSelectActiveFile('prev'), variant: 'paginate-previous' },
|
|
2945
|
+
React__namespace["default"].createElement(IconElement, { variant: 'paginate-previous' })),
|
|
2946
|
+
React__namespace["default"].createElement(DownloadButton, { fileKey: key }),
|
|
2947
|
+
React__namespace["default"].createElement(ButtonElement, { disabled: !activeFileHasNext, onClick: () => onSelectActiveFile('next'), variant: 'paginate-next' },
|
|
2948
|
+
React__namespace["default"].createElement(IconElement, { variant: 'paginate-next' })))));
|
|
2949
|
+
};
|
|
2950
|
+
function FilePreview(props) {
|
|
2951
|
+
const { filePreview, activeFileHasNext, activeFileHasPrev, onRetryFilePreview = () => undefined, activeFile, onSelectActiveFile = () => undefined, } = props;
|
|
2952
|
+
const { LocationDetailView: displayText } = useDisplayText();
|
|
2953
|
+
const { filePreview: { closeButtonLabel }, } = displayText;
|
|
2954
|
+
if (!activeFile || !filePreview) {
|
|
2955
|
+
return null;
|
|
2956
|
+
}
|
|
2957
|
+
if (!filePreview.enabled) {
|
|
2958
|
+
return null;
|
|
2959
|
+
}
|
|
2960
|
+
return (React__namespace["default"].createElement(ViewElement, { className: `${STORAGE_BROWSER_BLOCK}__file-preview` },
|
|
2961
|
+
React__namespace["default"].createElement(ViewElement, { className: `${STORAGE_BROWSER_BLOCK}__file-preview-header` },
|
|
2962
|
+
React__namespace["default"].createElement(ButtonElement, { variant: "exit", onClick: () => onSelectActiveFile(undefined) },
|
|
2963
|
+
React__namespace["default"].createElement(IconElement, { variant: "dismiss" }),
|
|
2964
|
+
closeButtonLabel)),
|
|
2965
|
+
React__namespace["default"].createElement(ViewElement, { className: `${STORAGE_BROWSER_BLOCK}__file-preview-container` },
|
|
2966
|
+
React__namespace["default"].createElement(FilePreviewContent, { filePreview: filePreview, activeFile: activeFile, activeFileHasNext: activeFileHasNext, activeFileHasPrev: activeFileHasPrev, onRetryFilePreview: onRetryFilePreview, onSelectActiveFile: onSelectActiveFile }))));
|
|
2967
|
+
}
|
|
2637
2968
|
|
|
2638
|
-
const
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
isOverwritingEnabled,
|
|
2643
|
-
label: overwriteToggleLabel,
|
|
2644
|
-
onToggle: onToggleOverwrite,
|
|
2645
|
-
};
|
|
2646
|
-
};
|
|
2969
|
+
const OVERWRITE_TOGGLE_ID = 'overwrite-toggle';
|
|
2970
|
+
const OverwriteToggle$1 = ({ isOverwritingEnabled, isDisabled, label, onToggle, }) => (React__namespace["default"].createElement(ViewElement, { className: `${STORAGE_BROWSER_BLOCK}__overwrite-toggle` },
|
|
2971
|
+
React__namespace["default"].createElement(InputElement, { checked: isOverwritingEnabled, disabled: isDisabled, id: OVERWRITE_TOGGLE_ID, onChange: onToggle, type: "checkbox" }),
|
|
2972
|
+
React__namespace["default"].createElement(LabelElement, { htmlFor: OVERWRITE_TOGGLE_ID }, label)));
|
|
2647
2973
|
|
|
2648
|
-
const
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
return React__namespace["default"].createElement(
|
|
2974
|
+
const Pagination$1 = ({ page, hasNextPage, onPaginate, highestPageVisited, }) => {
|
|
2975
|
+
if (!page)
|
|
2976
|
+
return null;
|
|
2977
|
+
return (React__namespace["default"].createElement(NavElement, { "aria-label": 'Pagination', className: `${STORAGE_BROWSER_BLOCK_TO_BE_UPDATED}__pagination` },
|
|
2978
|
+
React__namespace["default"].createElement(OrderedListElement, { className: `${STORAGE_BROWSER_BLOCK_TO_BE_UPDATED}__pagination-list` },
|
|
2979
|
+
React__namespace["default"].createElement(ListItemElement, { className: `${STORAGE_BROWSER_BLOCK_TO_BE_UPDATED}__pagination-list-item` },
|
|
2980
|
+
React__namespace["default"].createElement(PaginationButton, { isDisabled: page <= 1, onClick: () => {
|
|
2981
|
+
if (onPaginate)
|
|
2982
|
+
onPaginate(page - 1);
|
|
2983
|
+
}, type: "previous" })),
|
|
2984
|
+
React__namespace["default"].createElement(ListItemElement, { className: `${STORAGE_BROWSER_BLOCK_TO_BE_UPDATED}__pagination-list-item` },
|
|
2985
|
+
React__namespace["default"].createElement(SpanElement, { "aria-label": `Page ${page}`, "aria-current": "page", className: `${STORAGE_BROWSER_BLOCK_TO_BE_UPDATED}__pagination-current-page` }, page)),
|
|
2986
|
+
React__namespace["default"].createElement(ListItemElement, { className: `${STORAGE_BROWSER_BLOCK_TO_BE_UPDATED}__pagination-list-item` },
|
|
2987
|
+
React__namespace["default"].createElement(PaginationButton, { isDisabled: !highestPageVisited ||
|
|
2988
|
+
(page >= highestPageVisited && !hasNextPage), onClick: () => {
|
|
2989
|
+
if (onPaginate)
|
|
2990
|
+
onPaginate(page + 1);
|
|
2991
|
+
}, type: "next" })))));
|
|
2652
2992
|
};
|
|
2653
2993
|
|
|
2654
|
-
const
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2994
|
+
const SearchField$1 = ({ id, label, clearLabel, submitLabel, onSearch, onClear, placeholder, query = '', onQueryChange, }) => {
|
|
2995
|
+
// FIXME: focus not returning to input field after clear
|
|
2996
|
+
return (React__namespace["default"].createElement(React__namespace["default"].Fragment, null,
|
|
2997
|
+
React__namespace["default"].createElement(Field, { id: id, label: label, icon: React__namespace["default"].createElement(IconElement, { className: `${STORAGE_BROWSER_BLOCK_TO_BE_UPDATED}__search-field-icon`, variant: "search" }), className: `${STORAGE_BROWSER_BLOCK_TO_BE_UPDATED}__search-field`, variant: "search", onChange: (e) => {
|
|
2998
|
+
onQueryChange?.(e.target.value);
|
|
2999
|
+
}, placeholder: placeholder, onKeyUp: (event) => {
|
|
3000
|
+
if (event.key === 'Enter') {
|
|
3001
|
+
onSearch?.();
|
|
3002
|
+
}
|
|
3003
|
+
}, value: query }, query ? (React__namespace["default"].createElement(ButtonElement, { "aria-label": clearLabel, className: `${STORAGE_BROWSER_BLOCK_TO_BE_UPDATED}__search-field-clear`, onClick: onClear, variant: "refresh" },
|
|
3004
|
+
React__namespace["default"].createElement(IconElement, { variant: "dismiss" }))) : null),
|
|
3005
|
+
React__namespace["default"].createElement(ButtonElement, { className: `${STORAGE_BROWSER_BLOCK_TO_BE_UPDATED}__search-submit`, onClick: onSearch }, submitLabel)));
|
|
2658
3006
|
};
|
|
2659
3007
|
|
|
2660
|
-
const
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
};
|
|
3008
|
+
const SEARCH_SUBFOLDERS_TOGGLE_ID = 'search-subfolders-toggle';
|
|
3009
|
+
const SearchSubfoldersToggle$1 = ({ isSearchingSubfolders, label, onToggle, }) => (React__namespace["default"].createElement(ViewElement, { className: `${STORAGE_BROWSER_BLOCK}__search-subfolders-toggle` },
|
|
3010
|
+
React__namespace["default"].createElement(InputElement, { checked: isSearchingSubfolders, id: SEARCH_SUBFOLDERS_TOGGLE_ID, onChange: onToggle, type: "checkbox" }),
|
|
3011
|
+
React__namespace["default"].createElement(LabelElement, { htmlFor: SEARCH_SUBFOLDERS_TOGGLE_ID }, label)));
|
|
2665
3012
|
|
|
2666
|
-
const
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
onQueryChange: onSearchQueryChange,
|
|
2676
|
-
onSearch,
|
|
2677
|
-
};
|
|
3013
|
+
const StatusDisplay$1 = ({ statuses, total, }) => {
|
|
3014
|
+
if (!statuses?.length) {
|
|
3015
|
+
return null;
|
|
3016
|
+
}
|
|
3017
|
+
const descriptions = statuses.map(({ name, count }) => ({
|
|
3018
|
+
term: name,
|
|
3019
|
+
details: `${count}/${total}`,
|
|
3020
|
+
}));
|
|
3021
|
+
return (React__namespace["default"].createElement(DescriptionList, { className: `${STORAGE_BROWSER_BLOCK}__status-display`, descriptions: descriptions }));
|
|
2678
3022
|
};
|
|
2679
3023
|
|
|
2680
|
-
const
|
|
2681
|
-
const props = useSearchField();
|
|
2682
|
-
const Resolved = useResolvedComposable(SearchField$1, 'SearchField');
|
|
2683
|
-
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
2684
|
-
};
|
|
3024
|
+
const Title$1 = ({ title }) => (React__namespace["default"].createElement(HeadingElement, { className: `${STORAGE_BROWSER_BLOCK}__title` }, title));
|
|
2685
3025
|
|
|
2686
|
-
const
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
3026
|
+
const DEFAULT_COMPOSABLES = {
|
|
3027
|
+
ActionCancel,
|
|
3028
|
+
ActionDestination: ActionDestination$1,
|
|
3029
|
+
ActionExit,
|
|
3030
|
+
ActionStart,
|
|
3031
|
+
ActionsList: ActionsList$1,
|
|
3032
|
+
AddFiles,
|
|
3033
|
+
AddFolder,
|
|
3034
|
+
DataRefresh: DataRefresh$1,
|
|
3035
|
+
DataTable,
|
|
3036
|
+
DropZone,
|
|
3037
|
+
FolderNameField: FolderNameField$1,
|
|
3038
|
+
LoadingIndicator: LoadingIndicator$1,
|
|
3039
|
+
Message,
|
|
3040
|
+
Navigation: Navigation$1,
|
|
3041
|
+
OverwriteToggle: OverwriteToggle$1,
|
|
3042
|
+
Pagination: Pagination$1,
|
|
3043
|
+
SearchSubfoldersToggle: SearchSubfoldersToggle$1,
|
|
3044
|
+
SearchField: SearchField$1,
|
|
3045
|
+
StatusDisplay: StatusDisplay$1,
|
|
3046
|
+
Title: Title$1,
|
|
3047
|
+
FilePreview,
|
|
2693
3048
|
};
|
|
2694
3049
|
|
|
2695
|
-
|
|
2696
|
-
const
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
}
|
|
3050
|
+
function ComponentsProvider(props) {
|
|
3051
|
+
const { children, composables } = props;
|
|
3052
|
+
return (React__namespace["default"].createElement(elements.ElementsProvider, { elements: elementsDefault },
|
|
3053
|
+
React__namespace["default"].createElement(ComposablesProvider, { composables: composables }, children)));
|
|
3054
|
+
}
|
|
2700
3055
|
|
|
2701
|
-
const
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
return { statuses: [], total: 0 };
|
|
2706
|
-
}
|
|
2707
|
-
const statuses = [
|
|
2708
|
-
{ name: statusDisplayCompletedLabel ?? '', count: statusCounts.COMPLETE },
|
|
2709
|
-
{ name: statusDisplayFailedLabel ?? '', count: statusCounts.FAILED },
|
|
2710
|
-
{ name: statusDisplayCanceledLabel ?? '', count: statusCounts.CANCELED },
|
|
2711
|
-
{ name: statusDisplayQueuedLabel ?? '', count: statusCounts.QUEUED },
|
|
2712
|
-
];
|
|
2713
|
-
return { statuses, total: statusCounts.TOTAL };
|
|
3056
|
+
const OverwriteToggle = ({ isDisabled, isOverwritingEnabled, label = '', onToggle, }) => {
|
|
3057
|
+
return (React__namespace.createElement(uiReact.CheckboxField, { name: label, label: label, labelPosition: "end", isDisabled: isDisabled, checked: isOverwritingEnabled, onChange: () => {
|
|
3058
|
+
onToggle?.();
|
|
3059
|
+
} }));
|
|
2714
3060
|
};
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
3061
|
+
const SearchSubfoldersToggle = ({ isSearchingSubfolders, label = '', onToggle }) => {
|
|
3062
|
+
return (React__namespace.createElement(uiReact.CheckboxField, { name: label, label: label, labelPosition: "end", checked: isSearchingSubfolders, onChange: () => {
|
|
3063
|
+
onToggle?.();
|
|
3064
|
+
} }));
|
|
2720
3065
|
};
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
3066
|
+
const Pagination = ({ page = 1, onPaginate, hasNextPage, highestPageVisited, }) => {
|
|
3067
|
+
return (React__namespace.createElement(uiReact.Pagination, { currentPage: page, totalPages: highestPageVisited ?? 1, hasMorePages: hasNextPage, siblingCount: 1, onChange: (index) => {
|
|
3068
|
+
onPaginate?.(index ?? 0);
|
|
3069
|
+
}, onNext: () => {
|
|
3070
|
+
onPaginate?.(page + 1);
|
|
3071
|
+
}, onPrevious: () => {
|
|
3072
|
+
onPaginate?.(page - 1);
|
|
3073
|
+
} }));
|
|
2727
3074
|
};
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
3075
|
+
const SearchField = ({ onQueryChange, onSearch, onClear, placeholder, label, query, }) => {
|
|
3076
|
+
return (React__namespace.createElement(uiReact.SearchField, { label: label, size: "small", clearButtonLabel: "Clear search", placeholder: placeholder, value: query, onChange: (e) => {
|
|
3077
|
+
onQueryChange?.(e.target.value);
|
|
3078
|
+
}, onSubmit: () => {
|
|
3079
|
+
onSearch?.();
|
|
3080
|
+
}, onClear: () => {
|
|
3081
|
+
onClear?.();
|
|
3082
|
+
} }));
|
|
2733
3083
|
};
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
statusDisplayCompletedLabel: 'Completed',
|
|
2741
|
-
statusDisplayFailedLabel: 'Failed',
|
|
2742
|
-
statusDisplayInProgressLabel: 'In progress',
|
|
2743
|
-
statusDisplayTotalLabel: 'Total',
|
|
2744
|
-
statusDisplayQueuedLabel: 'Not started',
|
|
2745
|
-
// empty by default
|
|
2746
|
-
tableColumnCancelHeader: '',
|
|
2747
|
-
tableColumnStatusHeader: 'Status',
|
|
2748
|
-
tableColumnFolderHeader: 'Folder',
|
|
2749
|
-
tableColumnNameHeader: 'Name',
|
|
2750
|
-
tableColumnTypeHeader: 'Type',
|
|
2751
|
-
tableColumnSizeHeader: 'Size',
|
|
3084
|
+
const Navigation = ({ items }) => {
|
|
3085
|
+
return (React__namespace.createElement(uiReact.Breadcrumbs.Container, null, items.map((item, i) => {
|
|
3086
|
+
return (React__namespace.createElement(uiReact.Breadcrumbs.Item, { key: i },
|
|
3087
|
+
React__namespace.createElement(uiReact.Breadcrumbs.Link, { as: item.isCurrent ? 'span' : 'button', isCurrent: item.isCurrent, onClick: item.onNavigate }, item.name),
|
|
3088
|
+
item.isCurrent ? null : React__namespace.createElement(uiReact.Breadcrumbs.Separator, null)));
|
|
3089
|
+
})));
|
|
2752
3090
|
};
|
|
2753
|
-
const
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
getDateDisplayValue: (date) => new Intl.DateTimeFormat('en-US', {
|
|
2758
|
-
month: 'short',
|
|
2759
|
-
day: 'numeric',
|
|
2760
|
-
hour: 'numeric',
|
|
2761
|
-
year: 'numeric',
|
|
2762
|
-
minute: 'numeric',
|
|
2763
|
-
hourCycle: 'h12',
|
|
2764
|
-
}).format(date),
|
|
3091
|
+
const LoadingIndicator = ({ isLoading, }) => {
|
|
3092
|
+
if (isLoading) {
|
|
3093
|
+
return (React__namespace.createElement(uiReact.Loader, { className: "amplify-storage-browser__loader", variation: "linear", size: "small" }));
|
|
3094
|
+
}
|
|
2765
3095
|
};
|
|
2766
|
-
|
|
2767
|
-
const
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
3096
|
+
const FolderNameField = ({ onChange, label, placeholder, validationMessage, onValidate, }) => {
|
|
3097
|
+
const handleValidate = ({ target: { value }, }) => {
|
|
3098
|
+
onValidate?.(value);
|
|
3099
|
+
};
|
|
3100
|
+
return (React__namespace.createElement(uiReact.TextField, { label: label, placeholder: placeholder, errorMessage: validationMessage, hasError: !!validationMessage, onBlur: handleValidate, onChange: (event) => {
|
|
3101
|
+
const { value } = event.target;
|
|
3102
|
+
handleValidate?.(event);
|
|
3103
|
+
onChange?.(value);
|
|
3104
|
+
} }));
|
|
3105
|
+
};
|
|
3106
|
+
const DataRefresh = ({ onRefresh, }) => {
|
|
3107
|
+
return (React__namespace.createElement(uiReact.Button, { onClick: () => {
|
|
3108
|
+
onRefresh?.();
|
|
3109
|
+
}, "aria-label": "Refresh data" },
|
|
3110
|
+
React__namespace.createElement(IconElement, { className: "amplify-icon", variant: "refresh" })));
|
|
3111
|
+
};
|
|
3112
|
+
const ActionsList = ({ items, onActionSelect, isDisabled, }) => {
|
|
3113
|
+
return (React__namespace.createElement(uiReact.Menu, { isDisabled: isDisabled, trigger: React__namespace.createElement(uiReact.Button, { ariaLabel: "Menu Toggle" },
|
|
3114
|
+
React__namespace.createElement(IconElement, { className: "amplify-icon", variant: "menu" })) }, items
|
|
3115
|
+
.filter(({ isHidden }) => !isHidden)
|
|
3116
|
+
.map(({ actionType, icon, label, isDisabled }, i) => {
|
|
3117
|
+
return (React__namespace.createElement(uiReact.MenuItem, { key: i, size: "small", gap: "xs", isDisabled: isDisabled, onClick: () => {
|
|
3118
|
+
onActionSelect?.(actionType);
|
|
3119
|
+
} },
|
|
3120
|
+
icon && React__namespace.createElement(IconElement, { variant: icon }),
|
|
3121
|
+
label));
|
|
3122
|
+
})));
|
|
3123
|
+
};
|
|
3124
|
+
const StatusDisplay = ({ statuses, total, }) => {
|
|
3125
|
+
if (!statuses?.length) {
|
|
3126
|
+
return null;
|
|
3127
|
+
}
|
|
3128
|
+
return (React__namespace.createElement(uiReact.View, { as: "dl", className: `${STORAGE_BROWSER_BLOCK}__status-display` }, statuses.map(({ name, count }, i) => (React__namespace.createElement(uiReact.View, { as: "div", className: `${STORAGE_BROWSER_BLOCK}__status`, key: i },
|
|
3129
|
+
React__namespace.createElement(uiReact.View, { as: "dt", className: `${STORAGE_BROWSER_BLOCK}__status-label` }, name),
|
|
3130
|
+
React__namespace.createElement(uiReact.View, { as: "dd", className: `${STORAGE_BROWSER_BLOCK}__status-value` }, `${count}/${total}`))))));
|
|
3131
|
+
};
|
|
3132
|
+
const ActionDestination = ({ isNavigable, items, label, }) => {
|
|
3133
|
+
if (!items.length) {
|
|
3134
|
+
return null;
|
|
3135
|
+
}
|
|
3136
|
+
return (React__namespace.createElement(uiReact.View, { as: "dl", className: `${STORAGE_BROWSER_BLOCK}__destination` },
|
|
3137
|
+
React__namespace.createElement(uiReact.View, { as: "dt", className: `${STORAGE_BROWSER_BLOCK}__destination-label` }, label),
|
|
3138
|
+
React__namespace.createElement(uiReact.View, { as: "dd", className: `${STORAGE_BROWSER_BLOCK}__destination-value` },
|
|
3139
|
+
React__namespace.createElement(uiReact.Breadcrumbs.Container, null, items.map((item, i) => {
|
|
3140
|
+
return (React__namespace.createElement(uiReact.Breadcrumbs.Item, { key: i },
|
|
3141
|
+
isNavigable ? (React__namespace.createElement(uiReact.Breadcrumbs.Link, { as: item.isCurrent ? 'span' : 'button', isCurrent: item.isCurrent, onClick: item.onNavigate }, item.name)) : (item.name),
|
|
3142
|
+
item.isCurrent ? null : React__namespace.createElement(uiReact.Breadcrumbs.Separator, null)));
|
|
3143
|
+
})))));
|
|
3144
|
+
};
|
|
3145
|
+
const Title = ({ title }) => {
|
|
3146
|
+
return (React__namespace.createElement(uiReact.Heading, { className: `${STORAGE_BROWSER_BLOCK}__title`, level: 2 }, title));
|
|
3147
|
+
};
|
|
3148
|
+
const componentsDefault = {
|
|
3149
|
+
ActionDestination,
|
|
3150
|
+
ActionsList,
|
|
3151
|
+
DataRefresh,
|
|
3152
|
+
LoadingIndicator,
|
|
3153
|
+
Pagination,
|
|
3154
|
+
Navigation,
|
|
3155
|
+
OverwriteToggle,
|
|
3156
|
+
SearchField,
|
|
3157
|
+
SearchSubfoldersToggle,
|
|
3158
|
+
StatusDisplay,
|
|
3159
|
+
FolderNameField,
|
|
3160
|
+
Title,
|
|
2791
3161
|
};
|
|
2792
3162
|
|
|
2793
|
-
const
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
}
|
|
2807
|
-
if (message && !!query) {
|
|
2808
|
-
return { content: 'Error loading folders.', type: 'error' };
|
|
2809
|
-
}
|
|
3163
|
+
const Fallback = () => (React__namespace["default"].createElement("div", { className: STORAGE_BROWSER_BLOCK_TO_BE_UPDATED },
|
|
3164
|
+
React__namespace["default"].createElement("div", { className: `${STORAGE_BROWSER_BLOCK_TO_BE_UPDATED}__error-boundary` }, "Something went wrong.")));
|
|
3165
|
+
class ErrorBoundary extends React__namespace["default"].Component {
|
|
3166
|
+
constructor(props) {
|
|
3167
|
+
super(props);
|
|
3168
|
+
this.state = { hasError: false };
|
|
3169
|
+
}
|
|
3170
|
+
static getDerivedStateFromError(_error) {
|
|
3171
|
+
// Update state so the next render will show the fallback UI.
|
|
3172
|
+
return { hasError: true };
|
|
3173
|
+
}
|
|
3174
|
+
render() {
|
|
3175
|
+
const { hasError } = this.state;
|
|
3176
|
+
const { children } = this.props;
|
|
2810
3177
|
if (hasError) {
|
|
2811
|
-
return
|
|
2812
|
-
}
|
|
2813
|
-
if (hasExhaustedSearch) {
|
|
2814
|
-
return {
|
|
2815
|
-
content: 'Showing results for up to the first 10,000 items.',
|
|
2816
|
-
type: 'info',
|
|
2817
|
-
};
|
|
2818
|
-
}
|
|
2819
|
-
},
|
|
2820
|
-
loadingIndicatorLabel: 'Loading',
|
|
2821
|
-
overwriteWarningMessage: 'Copied files will overwrite existing files at selected destination.',
|
|
2822
|
-
searchPlaceholder: 'Search for folders',
|
|
2823
|
-
getActionCompleteMessage: (data) => {
|
|
2824
|
-
const { counts } = data ?? {};
|
|
2825
|
-
const { COMPLETE, FAILED, TOTAL } = counts ?? {};
|
|
2826
|
-
if (COMPLETE === TOTAL) {
|
|
2827
|
-
return {
|
|
2828
|
-
content: 'All files copied.',
|
|
2829
|
-
type: 'success',
|
|
2830
|
-
};
|
|
2831
|
-
}
|
|
2832
|
-
if (FAILED === TOTAL) {
|
|
2833
|
-
return { content: 'All files failed to copy.', type: 'error' };
|
|
3178
|
+
return React__namespace["default"].createElement(Fallback, null);
|
|
2834
3179
|
}
|
|
2835
|
-
return
|
|
2836
|
-
|
|
2837
|
-
|
|
3180
|
+
return children;
|
|
3181
|
+
}
|
|
3182
|
+
}
|
|
3183
|
+
|
|
3184
|
+
const defaultValue$5 = { data: {} };
|
|
3185
|
+
const { useControlsContext, ControlsContextProvider } = uiReactCore.createContextUtilities({
|
|
3186
|
+
contextName: 'ControlsContext',
|
|
3187
|
+
defaultValue: defaultValue$5,
|
|
3188
|
+
});
|
|
3189
|
+
|
|
3190
|
+
const useActionCancel = () => {
|
|
3191
|
+
const { data: { actionCancelLabel, isActionCancelDisabled }, onActionCancel, } = useControlsContext();
|
|
3192
|
+
return {
|
|
3193
|
+
onCancel: onActionCancel,
|
|
3194
|
+
isDisabled: isActionCancelDisabled,
|
|
3195
|
+
label: actionCancelLabel,
|
|
3196
|
+
};
|
|
3197
|
+
};
|
|
3198
|
+
|
|
3199
|
+
function useResolvedComposable(DefaultComposable, name) {
|
|
3200
|
+
const { composables } = useComposables();
|
|
3201
|
+
const Composable = React__namespace["default"].useMemo(() => {
|
|
3202
|
+
const ResolvedComposable = (props) => {
|
|
3203
|
+
const Resolved = composables?.[name] ?? DefaultComposable;
|
|
3204
|
+
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
2838
3205
|
};
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
3206
|
+
ResolvedComposable.displayName = name;
|
|
3207
|
+
return ResolvedComposable;
|
|
3208
|
+
}, [composables, DefaultComposable, name]);
|
|
3209
|
+
return Composable;
|
|
3210
|
+
}
|
|
3211
|
+
|
|
3212
|
+
const ActionCancelControl = () => {
|
|
3213
|
+
const props = useActionCancel();
|
|
3214
|
+
const Resolved = useResolvedComposable(ActionCancel, 'ActionCancel');
|
|
3215
|
+
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
2842
3216
|
};
|
|
2843
3217
|
|
|
2844
|
-
const
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
if (COMPLETE === TOTAL) {
|
|
2852
|
-
return { content: 'All files deleted.', type: 'success' };
|
|
2853
|
-
}
|
|
2854
|
-
if (FAILED === TOTAL) {
|
|
2855
|
-
return { content: 'All files failed to delete.', type: 'error' };
|
|
3218
|
+
const getNavigationItems = ({ destinationParts, location, onNavigate, }) => {
|
|
3219
|
+
const { bucket, permissions, prefix = '', type } = location;
|
|
3220
|
+
const destinationSubpaths = [];
|
|
3221
|
+
return destinationParts.map((part, index) => {
|
|
3222
|
+
const isCurrent = index === destinationParts.length - 1;
|
|
3223
|
+
if (index !== 0) {
|
|
3224
|
+
destinationSubpaths.push(part);
|
|
2856
3225
|
}
|
|
3226
|
+
const destinationPath = `${destinationSubpaths.concat('').join('/')}`;
|
|
3227
|
+
const destination = {
|
|
3228
|
+
id: crypto.randomUUID(),
|
|
3229
|
+
type,
|
|
3230
|
+
permissions,
|
|
3231
|
+
bucket,
|
|
3232
|
+
prefix,
|
|
3233
|
+
};
|
|
2857
3234
|
return {
|
|
2858
|
-
|
|
2859
|
-
|
|
3235
|
+
name: part,
|
|
3236
|
+
...(isCurrent && { isCurrent }),
|
|
3237
|
+
onNavigate: () => {
|
|
3238
|
+
onNavigate?.(destination, destinationPath);
|
|
3239
|
+
},
|
|
2860
3240
|
};
|
|
2861
|
-
}
|
|
3241
|
+
});
|
|
2862
3242
|
};
|
|
2863
3243
|
|
|
2864
|
-
const
|
|
2865
|
-
const
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
if (hasError) {
|
|
2873
|
-
return {
|
|
2874
|
-
type: 'error',
|
|
2875
|
-
content: message ?? DEFAULT_ERROR_MESSAGE$1,
|
|
2876
|
-
};
|
|
3244
|
+
const getNavigationParts = ({ location, path, includeBucketInPrefix, }) => {
|
|
3245
|
+
const { bucket, prefix = '', type } = location;
|
|
3246
|
+
const trimmedPrefix = prefix.endsWith('/') ? prefix.slice(0, -1) : prefix;
|
|
3247
|
+
const trimmedPath = path.endsWith('/') ? path.slice(0, -1) : path;
|
|
3248
|
+
const firstPrefixPart = [];
|
|
3249
|
+
if (type !== 'BUCKET') {
|
|
3250
|
+
if (includeBucketInPrefix) {
|
|
3251
|
+
firstPrefixPart.push(bucket);
|
|
2877
3252
|
}
|
|
2878
|
-
if (
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
3253
|
+
if (trimmedPrefix) {
|
|
3254
|
+
if (includeBucketInPrefix) {
|
|
3255
|
+
firstPrefixPart.push('/');
|
|
3256
|
+
}
|
|
3257
|
+
firstPrefixPart.push(trimmedPrefix);
|
|
2883
3258
|
}
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
return {
|
|
2892
|
-
type: 'info',
|
|
2893
|
-
content: `Showing results for up to the first 10,000 items.`,
|
|
2894
|
-
};
|
|
2895
|
-
}
|
|
2896
|
-
// TODO: add more cases as needed
|
|
2897
|
-
return undefined;
|
|
2898
|
-
},
|
|
2899
|
-
searchSubfoldersToggleLabel: 'Include subfolders',
|
|
2900
|
-
searchPlaceholder: 'Search current folder',
|
|
2901
|
-
tableColumnLastModifiedHeader: 'Last modified',
|
|
2902
|
-
tableColumnNameHeader: 'Name',
|
|
2903
|
-
tableColumnSizeHeader: 'Size',
|
|
2904
|
-
tableColumnTypeHeader: 'Type',
|
|
2905
|
-
selectFileLabel: 'Select file',
|
|
2906
|
-
selectAllFilesLabel: 'Select all files',
|
|
2907
|
-
getActionListItemLabel: (key = '') => {
|
|
2908
|
-
switch (key) {
|
|
2909
|
-
case 'Copy':
|
|
2910
|
-
return 'Copy';
|
|
2911
|
-
case 'Delete':
|
|
2912
|
-
return 'Delete';
|
|
2913
|
-
case 'Create folder':
|
|
2914
|
-
return 'Create folder';
|
|
2915
|
-
case 'Upload':
|
|
2916
|
-
return 'Upload';
|
|
2917
|
-
case 'Download':
|
|
2918
|
-
return 'Download';
|
|
2919
|
-
default:
|
|
2920
|
-
return key;
|
|
2921
|
-
}
|
|
2922
|
-
},
|
|
2923
|
-
getTitle: (location) => {
|
|
2924
|
-
const { current, key } = location;
|
|
2925
|
-
const { bucket = '' } = current ?? {};
|
|
2926
|
-
return key || bucket;
|
|
2927
|
-
},
|
|
3259
|
+
}
|
|
3260
|
+
const prefixParts = type === 'BUCKET' ? [bucket] : [firstPrefixPart.join('')];
|
|
3261
|
+
if (type === 'BUCKET' && trimmedPrefix) {
|
|
3262
|
+
prefixParts.push(trimmedPrefix);
|
|
3263
|
+
}
|
|
3264
|
+
const pathParts = trimmedPath ? trimmedPath.split('/') : [];
|
|
3265
|
+
return prefixParts.concat(pathParts);
|
|
2928
3266
|
};
|
|
2929
3267
|
|
|
2930
|
-
const
|
|
2931
|
-
const
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
const { isLoading, items, hasExhaustedSearch, hasError = false, message, } = data ?? {};
|
|
2937
|
-
if (isLoading) {
|
|
2938
|
-
return undefined;
|
|
2939
|
-
}
|
|
2940
|
-
if (hasError) {
|
|
2941
|
-
return {
|
|
2942
|
-
type: 'error',
|
|
2943
|
-
content: message ?? DEFAULT_ERROR_MESSAGE,
|
|
2944
|
-
};
|
|
2945
|
-
}
|
|
2946
|
-
if (items?.length === 0 && !hasExhaustedSearch) {
|
|
2947
|
-
return {
|
|
2948
|
-
type: 'info',
|
|
2949
|
-
content: 'No folders or files.',
|
|
2950
|
-
};
|
|
2951
|
-
}
|
|
2952
|
-
if (hasExhaustedSearch) {
|
|
2953
|
-
return {
|
|
2954
|
-
type: 'info',
|
|
2955
|
-
content: `Showing results for up to the first 10,000 items.`,
|
|
2956
|
-
};
|
|
2957
|
-
}
|
|
2958
|
-
// TODO: add more cases as needed
|
|
2959
|
-
return undefined;
|
|
2960
|
-
},
|
|
2961
|
-
getPermissionName: (permissions) => {
|
|
2962
|
-
let text = '';
|
|
2963
|
-
if (permissions.includes('get') || permissions.includes('list')) {
|
|
2964
|
-
text = 'Read';
|
|
2965
|
-
}
|
|
2966
|
-
if (permissions.includes('write') || permissions.includes('delete')) {
|
|
2967
|
-
text = text ? 'Read/Write' : 'Write';
|
|
2968
|
-
}
|
|
2969
|
-
if (!text) {
|
|
2970
|
-
text = permissions.join('/');
|
|
3268
|
+
const useActionDestination = () => {
|
|
3269
|
+
const { data, onSelectDestination } = useControlsContext();
|
|
3270
|
+
const { actionDestinationLabel, isActionDestinationNavigable, destination } = data;
|
|
3271
|
+
return React__namespace["default"].useMemo(() => {
|
|
3272
|
+
if (!destination?.current) {
|
|
3273
|
+
return { items: [] };
|
|
2971
3274
|
}
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
3275
|
+
const { current, path } = destination;
|
|
3276
|
+
const destinationParts = getNavigationParts({
|
|
3277
|
+
location: current,
|
|
3278
|
+
path,
|
|
3279
|
+
});
|
|
3280
|
+
return {
|
|
3281
|
+
label: actionDestinationLabel,
|
|
3282
|
+
items: getNavigationItems({
|
|
3283
|
+
location: current,
|
|
3284
|
+
destinationParts,
|
|
3285
|
+
onNavigate: onSelectDestination,
|
|
3286
|
+
}),
|
|
3287
|
+
isNavigable: isActionDestinationNavigable,
|
|
3288
|
+
};
|
|
3289
|
+
}, [
|
|
3290
|
+
actionDestinationLabel,
|
|
3291
|
+
isActionDestinationNavigable,
|
|
3292
|
+
destination,
|
|
3293
|
+
onSelectDestination,
|
|
3294
|
+
]);
|
|
2979
3295
|
};
|
|
2980
3296
|
|
|
2981
|
-
const
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3297
|
+
const ActionDestinationControl = () => {
|
|
3298
|
+
const props = useActionDestination();
|
|
3299
|
+
const Resolved = useResolvedComposable(ActionDestination$1, 'ActionDestination');
|
|
3300
|
+
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
3301
|
+
};
|
|
3302
|
+
|
|
3303
|
+
const useActionExit = () => {
|
|
3304
|
+
const { data: { actionExitLabel: label, isActionExitDisabled: isDisabled }, onActionExit: onExit, } = useControlsContext();
|
|
3305
|
+
return { label, isDisabled, onExit };
|
|
3306
|
+
};
|
|
3307
|
+
|
|
3308
|
+
const ActionExitControl = () => {
|
|
3309
|
+
const props = useActionExit();
|
|
3310
|
+
const Resolved = useResolvedComposable(ActionExit, 'ActionExit');
|
|
3311
|
+
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
3312
|
+
};
|
|
3313
|
+
|
|
3314
|
+
const useActionsList = () => {
|
|
3315
|
+
const { data: { actions, isActionsListDisabled }, onActionSelect, } = useControlsContext();
|
|
3316
|
+
return {
|
|
3317
|
+
isDisabled: isActionsListDisabled,
|
|
3318
|
+
items: actions ?? [],
|
|
3319
|
+
onActionSelect,
|
|
3320
|
+
};
|
|
3321
|
+
};
|
|
3322
|
+
|
|
3323
|
+
const ActionsListControl = () => {
|
|
3324
|
+
const props = useActionsList();
|
|
3325
|
+
const Resolved = useResolvedComposable(ActionsList$1, 'ActionsList');
|
|
3326
|
+
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
3327
|
+
};
|
|
3328
|
+
|
|
3329
|
+
const useActionStart = () => {
|
|
3330
|
+
const { data: { actionStartLabel, isActionStartDisabled }, onActionStart, } = useControlsContext();
|
|
3331
|
+
return {
|
|
3332
|
+
label: actionStartLabel,
|
|
3333
|
+
isDisabled: isActionStartDisabled,
|
|
3334
|
+
onStart: onActionStart,
|
|
3335
|
+
};
|
|
3336
|
+
};
|
|
3337
|
+
|
|
3338
|
+
const ActionStartControl = () => {
|
|
3339
|
+
const props = useActionStart();
|
|
3340
|
+
const Resolved = useResolvedComposable(ActionStart, 'ActionStart');
|
|
3341
|
+
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
3342
|
+
};
|
|
3343
|
+
|
|
3344
|
+
const useAddFiles = () => {
|
|
3345
|
+
const { data: { addFilesLabel, isAddFilesDisabled }, onAddFiles, } = useControlsContext();
|
|
3346
|
+
return {
|
|
3347
|
+
isDisabled: isAddFilesDisabled,
|
|
3348
|
+
label: addFilesLabel,
|
|
3349
|
+
onAddFiles,
|
|
3350
|
+
};
|
|
3351
|
+
};
|
|
3352
|
+
|
|
3353
|
+
const AddFilesControl = () => {
|
|
3354
|
+
const props = useAddFiles();
|
|
3355
|
+
const Resolved = useResolvedComposable(AddFiles, 'AddFiles');
|
|
3356
|
+
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
3357
|
+
};
|
|
3358
|
+
|
|
3359
|
+
const useAddFolder = () => {
|
|
3360
|
+
const { data: { addFolderLabel, isAddFolderDisabled }, onAddFolder, } = useControlsContext();
|
|
3361
|
+
return {
|
|
3362
|
+
isDisabled: isAddFolderDisabled,
|
|
3363
|
+
label: addFolderLabel,
|
|
3364
|
+
onAddFolder,
|
|
3365
|
+
};
|
|
3366
|
+
};
|
|
3367
|
+
|
|
3368
|
+
const AddFolderControl = () => {
|
|
3369
|
+
const props = useAddFolder();
|
|
3370
|
+
const Resolved = useResolvedComposable(AddFolder, 'AddFolder');
|
|
3371
|
+
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
3372
|
+
};
|
|
3373
|
+
|
|
3374
|
+
const useDataRefresh = () => {
|
|
3375
|
+
const { data: { isDataRefreshDisabled }, onRefresh, } = useControlsContext();
|
|
3376
|
+
return { isDisabled: isDataRefreshDisabled, onRefresh };
|
|
3377
|
+
};
|
|
3378
|
+
|
|
3379
|
+
const DataRefreshControl = () => {
|
|
3380
|
+
const props = useDataRefresh();
|
|
3381
|
+
const Resolved = useResolvedComposable(DataRefresh$1, 'DataRefresh');
|
|
3382
|
+
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
3383
|
+
};
|
|
3384
|
+
|
|
3385
|
+
const compareContent$3 = ({ label: a }, { label: b }) => {
|
|
3386
|
+
if (a === undefined) {
|
|
3387
|
+
return b === undefined ? 0 : 1;
|
|
3388
|
+
}
|
|
3389
|
+
return b === undefined ? -1 : a.localeCompare(b);
|
|
3390
|
+
};
|
|
3391
|
+
const compareButtonData = (a, b, direction) => direction === 'ascending'
|
|
3392
|
+
? compareContent$3(a.content, b.content)
|
|
3393
|
+
: compareContent$3(b.content, a.content);
|
|
3394
|
+
|
|
3395
|
+
const compareContent$2 = ({ value: a }, { value: b }) => {
|
|
3396
|
+
if (a === undefined) {
|
|
3397
|
+
return b === undefined ? 0 : 1;
|
|
3398
|
+
}
|
|
3399
|
+
return b === undefined ? -1 : a.getTime() - b.getTime();
|
|
3400
|
+
};
|
|
3401
|
+
const compareDateData = (a, b, direction) => direction === 'ascending'
|
|
3402
|
+
? compareContent$2(a.content, b.content)
|
|
3403
|
+
: compareContent$2(b.content, a.content);
|
|
3404
|
+
|
|
3405
|
+
const compareContent$1 = ({ value: a }, { value: b }) => {
|
|
3406
|
+
if (a === undefined) {
|
|
3407
|
+
return b === undefined ? 0 : 1;
|
|
3408
|
+
}
|
|
3409
|
+
return b === undefined ? -1 : a - b;
|
|
3410
|
+
};
|
|
3411
|
+
const compareNumberData = (a, b, direction) => direction === 'ascending'
|
|
3412
|
+
? compareContent$1(a.content, b.content)
|
|
3413
|
+
: compareContent$1(b.content, a.content);
|
|
3414
|
+
|
|
3415
|
+
const compareContent = ({ text: a }, { text: b }) => {
|
|
3416
|
+
if (a === undefined) {
|
|
3417
|
+
return b === undefined ? 0 : 1;
|
|
3418
|
+
}
|
|
3419
|
+
return b === undefined ? -1 : a.localeCompare(b);
|
|
3420
|
+
};
|
|
3421
|
+
const compareTextData = (a, b, direction) => direction === 'ascending'
|
|
3422
|
+
? compareContent(a.content, b.content)
|
|
3423
|
+
: compareContent(b.content, a.content);
|
|
3424
|
+
|
|
3425
|
+
const GROUP_ORDER = [
|
|
3426
|
+
'checkbox',
|
|
3427
|
+
'button',
|
|
3428
|
+
'date',
|
|
3429
|
+
'number',
|
|
3430
|
+
'text',
|
|
3431
|
+
];
|
|
3432
|
+
const UNSORTABLE_GROUPS = ['checkbox'];
|
|
3433
|
+
const useDataTable = () => {
|
|
3434
|
+
const { data } = useControlsContext();
|
|
3435
|
+
const { isLoading, tableData } = data;
|
|
3436
|
+
const defaultSortIndex = React__namespace["default"].useMemo(() => tableData?.headers?.findIndex(({ type }) => type === 'sort') ?? -1, [tableData]);
|
|
3437
|
+
const [sortState, setSortState] = React__namespace["default"].useState({
|
|
3438
|
+
index: defaultSortIndex,
|
|
3439
|
+
direction: 'ascending',
|
|
3440
|
+
});
|
|
3441
|
+
const mappedHeaders = React__namespace["default"].useMemo(() => tableData?.headers.map((header, index) => {
|
|
3442
|
+
const { type } = header;
|
|
3443
|
+
switch (type) {
|
|
3444
|
+
case 'sort': {
|
|
3445
|
+
return {
|
|
3446
|
+
...header,
|
|
3447
|
+
content: {
|
|
3448
|
+
...header.content,
|
|
3449
|
+
onSort: () => {
|
|
3450
|
+
setSortState({
|
|
3451
|
+
index,
|
|
3452
|
+
direction: sortState.index === index
|
|
3453
|
+
? sortState.direction === 'ascending'
|
|
3454
|
+
? 'descending'
|
|
3455
|
+
: 'ascending'
|
|
3456
|
+
: 'ascending',
|
|
3457
|
+
});
|
|
3458
|
+
},
|
|
3459
|
+
sortDirection: sortState.index === index ? sortState.direction : undefined,
|
|
3460
|
+
},
|
|
3461
|
+
};
|
|
3462
|
+
}
|
|
3463
|
+
case 'checkbox':
|
|
3464
|
+
case 'text':
|
|
3465
|
+
default: {
|
|
3466
|
+
return header;
|
|
3467
|
+
}
|
|
3039
3468
|
}
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
if (!
|
|
3044
|
-
return
|
|
3469
|
+
}), [sortState, tableData]);
|
|
3470
|
+
const sortedRows = React__namespace["default"].useMemo(() => {
|
|
3471
|
+
// Early return if there is no table data
|
|
3472
|
+
if (!tableData) {
|
|
3473
|
+
return;
|
|
3045
3474
|
}
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
.
|
|
3049
|
-
if (invalidFileNames) {
|
|
3050
|
-
return {
|
|
3051
|
-
content: `Files larger than 160GB cannot be added to the upload queue: ${invalidFileNames}`,
|
|
3052
|
-
type: 'warning',
|
|
3053
|
-
};
|
|
3475
|
+
// Return rows as is if there are no sortable columns
|
|
3476
|
+
if (sortState.index < 0) {
|
|
3477
|
+
return tableData.rows;
|
|
3054
3478
|
}
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3479
|
+
const { index, direction } = sortState;
|
|
3480
|
+
const groupedRows = {
|
|
3481
|
+
button: [],
|
|
3482
|
+
checkbox: [],
|
|
3483
|
+
date: [],
|
|
3484
|
+
number: [],
|
|
3485
|
+
text: [],
|
|
3486
|
+
};
|
|
3487
|
+
tableData.rows.forEach((row) => {
|
|
3488
|
+
const { type } = row.content[index];
|
|
3489
|
+
groupedRows[type].push(row);
|
|
3490
|
+
});
|
|
3491
|
+
const groupOrder = direction === 'ascending' ? GROUP_ORDER : [...GROUP_ORDER].reverse();
|
|
3492
|
+
return groupOrder
|
|
3493
|
+
.map((groupType) => {
|
|
3494
|
+
if (UNSORTABLE_GROUPS.includes(groupType)) {
|
|
3495
|
+
return groupedRows[groupType];
|
|
3496
|
+
}
|
|
3497
|
+
return groupedRows[groupType].sort((rowA, rowB) => {
|
|
3498
|
+
switch (groupType) {
|
|
3499
|
+
case 'button': {
|
|
3500
|
+
return compareButtonData(rowA.content[index], rowB.content[index], direction);
|
|
3501
|
+
}
|
|
3502
|
+
case 'date': {
|
|
3503
|
+
return compareDateData(rowA.content[index], rowB.content[index], direction);
|
|
3504
|
+
}
|
|
3505
|
+
case 'number': {
|
|
3506
|
+
return compareNumberData(rowA.content[index], rowB.content[index], direction);
|
|
3507
|
+
}
|
|
3508
|
+
case 'text':
|
|
3509
|
+
default: {
|
|
3510
|
+
return compareTextData(rowA.content[index], rowB.content[index], direction);
|
|
3511
|
+
}
|
|
3512
|
+
}
|
|
3513
|
+
});
|
|
3514
|
+
})
|
|
3515
|
+
.flat();
|
|
3516
|
+
}, [sortState, tableData]);
|
|
3517
|
+
return {
|
|
3518
|
+
headers: mappedHeaders ?? [],
|
|
3519
|
+
isLoading,
|
|
3520
|
+
rows: sortedRows ?? [],
|
|
3521
|
+
};
|
|
3061
3522
|
};
|
|
3062
3523
|
|
|
3063
|
-
const
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3524
|
+
const DataTableControl = () => {
|
|
3525
|
+
const props = useDataTable();
|
|
3526
|
+
const Resolved = useResolvedComposable(DataTable, 'DataTable');
|
|
3527
|
+
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
3528
|
+
};
|
|
3529
|
+
|
|
3530
|
+
/**
|
|
3531
|
+
* This hook, not to be confused with the useDropZone vended from @aws-amplify/ui-react-core, is only intended for use
|
|
3532
|
+
* with its corresponding DropZone control.
|
|
3533
|
+
*/
|
|
3534
|
+
const useDropZone = () => {
|
|
3535
|
+
const { onDropFiles } = useControlsContext();
|
|
3536
|
+
return { onDropFiles };
|
|
3537
|
+
};
|
|
3538
|
+
|
|
3539
|
+
const DropZoneControl = ({ children, }) => {
|
|
3540
|
+
const props = useDropZone();
|
|
3541
|
+
const Resolved = useResolvedComposable(DropZone, 'DropZone');
|
|
3542
|
+
return React__namespace["default"].createElement(Resolved, { ...props }, children);
|
|
3543
|
+
};
|
|
3544
|
+
|
|
3545
|
+
const useFolderNameField = () => {
|
|
3546
|
+
const { data, onValidateFolderName, onFolderNameChange } = useControlsContext();
|
|
3547
|
+
const { folderNameId, folderNameLabel, folderNamePlaceholder, folderNameValidationMessage, isFolderNameDisabled, } = data;
|
|
3548
|
+
return {
|
|
3549
|
+
id: folderNameId,
|
|
3550
|
+
isDisabled: isFolderNameDisabled,
|
|
3551
|
+
label: folderNameLabel,
|
|
3552
|
+
onChange: onFolderNameChange,
|
|
3553
|
+
onValidate: onValidateFolderName,
|
|
3554
|
+
placeholder: folderNamePlaceholder,
|
|
3555
|
+
validationMessage: folderNameValidationMessage,
|
|
3556
|
+
};
|
|
3557
|
+
};
|
|
3558
|
+
|
|
3559
|
+
const FolderNameFieldControl = () => {
|
|
3560
|
+
const props = useFolderNameField();
|
|
3561
|
+
const Resolved = useResolvedComposable(FolderNameField$1, 'FolderNameField');
|
|
3562
|
+
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
3563
|
+
};
|
|
3564
|
+
|
|
3565
|
+
const useLoadingIndicator = () => {
|
|
3566
|
+
const { data: { isLoading, loadingIndicatorLabel: label }, } = useControlsContext();
|
|
3567
|
+
return { isLoading, label };
|
|
3568
|
+
};
|
|
3569
|
+
|
|
3570
|
+
const LoadingIndicatorControl = () => {
|
|
3571
|
+
const props = useLoadingIndicator();
|
|
3572
|
+
const Resolved = useResolvedComposable(LoadingIndicator$1, 'LoadingIndicator');
|
|
3573
|
+
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
3574
|
+
};
|
|
3575
|
+
|
|
3576
|
+
const useMessage = () => {
|
|
3577
|
+
const { data: { message = {} }, } = useControlsContext();
|
|
3578
|
+
return message;
|
|
3579
|
+
};
|
|
3580
|
+
|
|
3581
|
+
const MessageControl = () => {
|
|
3582
|
+
const props = useMessage();
|
|
3583
|
+
const Resolved = useResolvedComposable(Message, 'Message');
|
|
3584
|
+
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
3585
|
+
};
|
|
3586
|
+
|
|
3587
|
+
const useNavigation = () => {
|
|
3588
|
+
const { data, onNavigate, onNavigateHome } = useControlsContext();
|
|
3589
|
+
const { location } = data;
|
|
3590
|
+
return React__namespace["default"].useMemo(() => {
|
|
3591
|
+
if (!location?.current) {
|
|
3592
|
+
return { items: [] };
|
|
3075
3593
|
}
|
|
3594
|
+
const { current, path } = location;
|
|
3595
|
+
const destinationParts = getNavigationParts({
|
|
3596
|
+
location: current,
|
|
3597
|
+
path,
|
|
3598
|
+
includeBucketInPrefix: true,
|
|
3599
|
+
});
|
|
3600
|
+
const homeItem = [
|
|
3601
|
+
{ name: 'Home', onNavigate: onNavigateHome },
|
|
3602
|
+
];
|
|
3076
3603
|
return {
|
|
3077
|
-
|
|
3078
|
-
type: 'error',
|
|
3604
|
+
items: homeItem.concat(getNavigationItems({ location: current, destinationParts, onNavigate })),
|
|
3079
3605
|
};
|
|
3080
|
-
},
|
|
3606
|
+
}, [location, onNavigate, onNavigateHome]);
|
|
3081
3607
|
};
|
|
3082
3608
|
|
|
3083
|
-
const
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
DownloadView: DEFAULT_DOWNLOAD_VIEW_DISPLAY_TEXT,
|
|
3088
|
-
LocationDetailView: DEFAULT_LOCATION_DETAIL_VIEW_DISPLAY_TEXT,
|
|
3089
|
-
LocationsView: DEFAULT_LOCATIONS_VIEW_DISPLAY_TEXT,
|
|
3090
|
-
UploadView: DEFAULT_UPLOAD_VIEW_DISPLAY_TEXT,
|
|
3609
|
+
const NavigationControl = () => {
|
|
3610
|
+
const props = useNavigation();
|
|
3611
|
+
const Resolved = useResolvedComposable(Navigation$1, 'Navigation');
|
|
3612
|
+
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
3091
3613
|
};
|
|
3092
3614
|
|
|
3093
|
-
const
|
|
3094
|
-
|
|
3095
|
-
errorMessage: '`useDisplayText` must be called inside `DisplayTextProvider`',
|
|
3096
|
-
});
|
|
3097
|
-
function resolveDisplayText(displayText) {
|
|
3098
|
-
if (!displayText)
|
|
3099
|
-
return DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT;
|
|
3100
|
-
// override
|
|
3101
|
-
const { CopyView, CreateFolderView, DeleteView, DownloadView, LocationDetailView, LocationsView, UploadView, } = displayText;
|
|
3615
|
+
const useOverwriteToggle = () => {
|
|
3616
|
+
const { data: { isOverwritingEnabled, isOverwriteToggleDisabled, overwriteToggleLabel, }, onToggleOverwrite, } = useControlsContext();
|
|
3102
3617
|
return {
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
},
|
|
3108
|
-
DeleteView: {
|
|
3109
|
-
...DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.DeleteView,
|
|
3110
|
-
...DeleteView,
|
|
3111
|
-
},
|
|
3112
|
-
DownloadView: {
|
|
3113
|
-
...DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.DownloadView,
|
|
3114
|
-
...DownloadView,
|
|
3115
|
-
},
|
|
3116
|
-
LocationDetailView: {
|
|
3117
|
-
...DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.LocationDetailView,
|
|
3118
|
-
...LocationDetailView,
|
|
3119
|
-
},
|
|
3120
|
-
LocationsView: {
|
|
3121
|
-
...DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.LocationsView,
|
|
3122
|
-
...LocationsView,
|
|
3123
|
-
},
|
|
3124
|
-
UploadView: {
|
|
3125
|
-
...DEFAULT_STORAGE_BROWSER_DISPLAY_TEXT.UploadView,
|
|
3126
|
-
...UploadView,
|
|
3127
|
-
},
|
|
3618
|
+
isDisabled: isOverwriteToggleDisabled,
|
|
3619
|
+
isOverwritingEnabled,
|
|
3620
|
+
label: overwriteToggleLabel,
|
|
3621
|
+
onToggle: onToggleOverwrite,
|
|
3128
3622
|
};
|
|
3129
|
-
}
|
|
3130
|
-
function DisplayTextProvider({ children, displayText: _override, }) {
|
|
3131
|
-
// do deep merge here of default and override here
|
|
3132
|
-
const resolvedDisplayText = React__namespace["default"].useMemo(() => resolveDisplayText(_override), [_override]);
|
|
3133
|
-
return (React__namespace["default"].createElement(DisplayTextContext.Provider, { value: resolvedDisplayText }, children));
|
|
3134
|
-
}
|
|
3623
|
+
};
|
|
3135
3624
|
|
|
3136
|
-
const
|
|
3137
|
-
const
|
|
3138
|
-
const
|
|
3625
|
+
const OverwriteToggleControl = () => {
|
|
3626
|
+
const props = useOverwriteToggle();
|
|
3627
|
+
const Resolved = useResolvedComposable(OverwriteToggle$1, 'OverwriteToggle');
|
|
3628
|
+
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
3629
|
+
};
|
|
3630
|
+
|
|
3631
|
+
const usePagination = () => {
|
|
3632
|
+
const { data, onPaginate } = useControlsContext();
|
|
3633
|
+
const { paginationData } = data;
|
|
3634
|
+
return { ...paginationData, onPaginate };
|
|
3635
|
+
};
|
|
3636
|
+
|
|
3637
|
+
const PaginationControl = () => {
|
|
3638
|
+
const props = usePagination();
|
|
3639
|
+
const Resolved = useResolvedComposable(Pagination$1, 'Pagination');
|
|
3640
|
+
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
3641
|
+
};
|
|
3642
|
+
|
|
3643
|
+
const useSearchField = () => {
|
|
3644
|
+
const { data, onSearch, onSearchClear, onSearchQueryChange } = useControlsContext();
|
|
3645
|
+
const { searchPlaceholder, searchClearLabel, searchQuery, searchSubmitLabel, } = data;
|
|
3646
|
+
return {
|
|
3647
|
+
clearLabel: searchClearLabel,
|
|
3648
|
+
placeholder: searchPlaceholder,
|
|
3649
|
+
query: searchQuery,
|
|
3650
|
+
submitLabel: searchSubmitLabel,
|
|
3651
|
+
onClear: onSearchClear,
|
|
3652
|
+
onQueryChange: onSearchQueryChange,
|
|
3653
|
+
onSearch,
|
|
3654
|
+
};
|
|
3655
|
+
};
|
|
3656
|
+
|
|
3657
|
+
const SearchFieldControl = () => {
|
|
3658
|
+
const props = useSearchField();
|
|
3659
|
+
const Resolved = useResolvedComposable(SearchField$1, 'SearchField');
|
|
3660
|
+
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
3661
|
+
};
|
|
3662
|
+
|
|
3663
|
+
const useSearchSubfoldersToggle = () => {
|
|
3664
|
+
const { data: { isSearchingSubfolders, searchSubfoldersToggleLabel }, onToggleSearchSubfolders, } = useControlsContext();
|
|
3665
|
+
return {
|
|
3666
|
+
isSearchingSubfolders,
|
|
3667
|
+
label: searchSubfoldersToggleLabel,
|
|
3668
|
+
onToggle: onToggleSearchSubfolders,
|
|
3669
|
+
};
|
|
3670
|
+
};
|
|
3671
|
+
|
|
3672
|
+
const SearchSubfoldersToggleControl = () => {
|
|
3673
|
+
const props = useSearchSubfoldersToggle();
|
|
3674
|
+
const Resolved = useResolvedComposable(SearchSubfoldersToggle$1, 'SearchSubfoldersToggle');
|
|
3675
|
+
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
3676
|
+
};
|
|
3677
|
+
|
|
3678
|
+
const useStatusDisplay = () => {
|
|
3679
|
+
const { data } = useControlsContext();
|
|
3680
|
+
const { statusCounts, statusDisplayCanceledLabel, statusDisplayCompletedLabel, statusDisplayFailedLabel, statusDisplayQueuedLabel, } = data;
|
|
3681
|
+
if (!statusCounts?.TOTAL) {
|
|
3682
|
+
return { statuses: [], total: 0 };
|
|
3683
|
+
}
|
|
3684
|
+
const statuses = [
|
|
3685
|
+
{ name: statusDisplayCompletedLabel ?? '', count: statusCounts.COMPLETE },
|
|
3686
|
+
{ name: statusDisplayFailedLabel ?? '', count: statusCounts.FAILED },
|
|
3687
|
+
{ name: statusDisplayCanceledLabel ?? '', count: statusCounts.CANCELED },
|
|
3688
|
+
{ name: statusDisplayQueuedLabel ?? '', count: statusCounts.QUEUED },
|
|
3689
|
+
];
|
|
3690
|
+
return { statuses, total: statusCounts.TOTAL };
|
|
3691
|
+
};
|
|
3692
|
+
|
|
3693
|
+
const StatusDisplayControl = () => {
|
|
3694
|
+
const props = useStatusDisplay();
|
|
3695
|
+
const Resolved = useResolvedComposable(StatusDisplay$1, 'StatusDisplay');
|
|
3696
|
+
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
3697
|
+
};
|
|
3698
|
+
|
|
3699
|
+
const useTitle = () => {
|
|
3700
|
+
const { data } = useControlsContext();
|
|
3701
|
+
return {
|
|
3702
|
+
title: data?.title,
|
|
3703
|
+
};
|
|
3704
|
+
};
|
|
3705
|
+
|
|
3706
|
+
const TitleControl = () => {
|
|
3707
|
+
const props = useTitle();
|
|
3708
|
+
const Resolved = useResolvedComposable(Title$1, 'Title');
|
|
3709
|
+
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
3710
|
+
};
|
|
3139
3711
|
|
|
3140
3712
|
function useResolveTableData(keys, { getCell, getHeader, getRowKey }, { items, props }) {
|
|
3141
3713
|
return React__namespace["default"].useMemo(() => {
|
|
@@ -4503,16 +5075,7 @@ const LocationActionView = ({ type, ...props }) => {
|
|
|
4503
5075
|
return null;
|
|
4504
5076
|
};
|
|
4505
5077
|
|
|
4506
|
-
const
|
|
4507
|
-
'checkbox',
|
|
4508
|
-
'name',
|
|
4509
|
-
'type',
|
|
4510
|
-
'last-modified',
|
|
4511
|
-
'size',
|
|
4512
|
-
'download',
|
|
4513
|
-
];
|
|
4514
|
-
|
|
4515
|
-
const getFileRowContent = ({ permissions, isSelected, itemLocationKey, getDateDisplayValue, lastModified, rowId, rowKey, selectFileLabel, size, onDownload, onSelect, }) => LOCATION_DETAIL_VIEW_HEADERS.map((columnKey) => {
|
|
5078
|
+
const getFileRowContent = ({ filePreviewEnabled, permissions, isSelected, itemLocationKey, getDateDisplayValue, lastModified, rowId, rowKey, selectFileLabel, size, onDownload, onSelect, onClick, }) => LOCATION_DETAIL_VIEW_HEADERS.map((columnKey) => {
|
|
4516
5079
|
const key = `${columnKey}-${rowId}`;
|
|
4517
5080
|
switch (columnKey) {
|
|
4518
5081
|
case 'checkbox': {
|
|
@@ -4530,11 +5093,13 @@ const getFileRowContent = ({ permissions, isSelected, itemLocationKey, getDateDi
|
|
|
4530
5093
|
case 'name': {
|
|
4531
5094
|
return {
|
|
4532
5095
|
key,
|
|
4533
|
-
type: 'text',
|
|
5096
|
+
type: filePreviewEnabled ? 'button' : 'text',
|
|
4534
5097
|
content: {
|
|
4535
|
-
icon:
|
|
4536
|
-
ariaLabel:
|
|
4537
|
-
|
|
5098
|
+
icon: getFileThumbnail(rowKey),
|
|
5099
|
+
ariaLabel: `${rowKey.slice(itemLocationKey.length)} file`,
|
|
5100
|
+
...(filePreviewEnabled
|
|
5101
|
+
? { label: rowKey.slice(itemLocationKey.length), onClick }
|
|
5102
|
+
: { text: rowKey.slice(itemLocationKey.length) }),
|
|
4538
5103
|
},
|
|
4539
5104
|
};
|
|
4540
5105
|
}
|
|
@@ -4678,7 +5243,7 @@ const getHeaders$1 = ({ tableColumnLastModifiedHeader, tableColumnNameHeader, ta
|
|
|
4678
5243
|
}
|
|
4679
5244
|
});
|
|
4680
5245
|
|
|
4681
|
-
const getLocationDetailViewTableData = ({ areAllFilesSelected, displayText, location, fileDataItems, hasFiles, pageItems, selectFileLabel, selectAllFilesLabel, getDateDisplayValue, onDownload, onNavigate, onSelect, onSelectAll, }) => {
|
|
5246
|
+
const getLocationDetailViewTableData = ({ filePreviewEnabled, activeFile, onSelectActiveFile, areAllFilesSelected, displayText, location, fileDataItems, hasFiles, pageItems, selectFileLabel, selectAllFilesLabel, getDateDisplayValue, onDownload, onNavigate, onSelect, onSelectAll, }) => {
|
|
4682
5247
|
const { tableColumnLastModifiedHeader, tableColumnNameHeader, tableColumnSizeHeader, tableColumnTypeHeader, } = displayText;
|
|
4683
5248
|
const headers = getHeaders$1({
|
|
4684
5249
|
areAllFilesSelected,
|
|
@@ -4703,9 +5268,14 @@ const getLocationDetailViewTableData = ({ areAllFilesSelected, displayText, loca
|
|
|
4703
5268
|
const onFileSelect = () => {
|
|
4704
5269
|
onSelect(isSelected, locationItem);
|
|
4705
5270
|
};
|
|
5271
|
+
const onClick = () => {
|
|
5272
|
+
onSelectActiveFile(locationItem);
|
|
5273
|
+
};
|
|
4706
5274
|
return {
|
|
4707
5275
|
key: id,
|
|
5276
|
+
active: activeFile?.id === id,
|
|
4708
5277
|
content: getFileRowContent({
|
|
5278
|
+
filePreviewEnabled,
|
|
4709
5279
|
permissions: current?.permissions ?? [],
|
|
4710
5280
|
isSelected,
|
|
4711
5281
|
itemLocationKey: `${current?.prefix ?? ''}${path}`,
|
|
@@ -4717,6 +5287,7 @@ const getLocationDetailViewTableData = ({ areAllFilesSelected, displayText, loca
|
|
|
4717
5287
|
size,
|
|
4718
5288
|
onDownload: onFileDownload,
|
|
4719
5289
|
onSelect: onFileSelect,
|
|
5290
|
+
onClick,
|
|
4720
5291
|
}),
|
|
4721
5292
|
};
|
|
4722
5293
|
}
|
|
@@ -4732,6 +5303,7 @@ const getLocationDetailViewTableData = ({ areAllFilesSelected, displayText, loca
|
|
|
4732
5303
|
};
|
|
4733
5304
|
return {
|
|
4734
5305
|
key: id,
|
|
5306
|
+
active: false,
|
|
4735
5307
|
content: getFolderRowContent({
|
|
4736
5308
|
itemSubPath,
|
|
4737
5309
|
rowId: id,
|
|
@@ -4747,7 +5319,7 @@ const getLocationDetailViewTableData = ({ areAllFilesSelected, displayText, loca
|
|
|
4747
5319
|
function LocationDetailViewProvider({ children, ...props }) {
|
|
4748
5320
|
const { LocationDetailView: displayText } = useDisplayText();
|
|
4749
5321
|
const { LocationDetailView: { loadingIndicatorLabel, searchSubfoldersToggleLabel, selectFileLabel, selectAllFilesLabel, searchPlaceholder, searchSubmitLabel, searchClearLabel, getActionListItemLabel, getDateDisplayValue, getTitle, getListItemsResultMessage, }, } = useDisplayText();
|
|
4750
|
-
const { actionItems, page, pageItems, hasNextPage, highestPageVisited, isLoading, isSearchSubfoldersEnabled, location, fileDataItems, hasError, hasDownloadError, message, downloadErrorMessage, searchQuery, hasExhaustedSearch, onActionSelect, onDropFiles, onRefresh, onPaginate, onDownload, onNavigate, onNavigateHome, onSelect, onToggleSelectAll, onSearch, onSearchQueryChange, onSearchClear, onToggleSearchSubfolders, } = props;
|
|
5322
|
+
const { actionItems, activeFile, activeFileHasNext, activeFileHasPrev, page, pageItems, hasNextPage, highestPageVisited, isLoading, isSearchSubfoldersEnabled, location, fileDataItems, hasError, hasDownloadError, message, downloadErrorMessage, searchQuery, hasExhaustedSearch, onActionSelect, onDropFiles, onRefresh, onPaginate, onDownload, onNavigate, onNavigateHome, onSelect, onSelectActiveFile, onToggleSelectAll, onSearch, onSearchQueryChange, onSearchClear, onToggleSearchSubfolders, filePreviewState, filePreviewEnabled, onRetryFilePreview, } = props;
|
|
4751
5323
|
const actionsWithDisplayText = actionItems.map((item) => ({
|
|
4752
5324
|
...item,
|
|
4753
5325
|
label: getActionListItemLabel(item.label),
|
|
@@ -4767,6 +5339,9 @@ function LocationDetailViewProvider({ children, ...props }) {
|
|
|
4767
5339
|
actionItems.every(({ isHidden }) => isHidden);
|
|
4768
5340
|
return (React__namespace["default"].createElement(ControlsContextProvider, { data: {
|
|
4769
5341
|
actions: actionsWithDisplayText,
|
|
5342
|
+
activeFile,
|
|
5343
|
+
activeFileHasNext,
|
|
5344
|
+
activeFileHasPrev,
|
|
4770
5345
|
isActionsListDisabled,
|
|
4771
5346
|
isDataRefreshDisabled: isLoading,
|
|
4772
5347
|
isLoading,
|
|
@@ -4783,7 +5358,11 @@ function LocationDetailViewProvider({ children, ...props }) {
|
|
|
4783
5358
|
searchSubmitLabel,
|
|
4784
5359
|
searchClearLabel,
|
|
4785
5360
|
searchQuery,
|
|
5361
|
+
filePreviewState,
|
|
4786
5362
|
tableData: getLocationDetailViewTableData({
|
|
5363
|
+
filePreviewEnabled,
|
|
5364
|
+
activeFile,
|
|
5365
|
+
onSelectActiveFile,
|
|
4787
5366
|
areAllFilesSelected,
|
|
4788
5367
|
displayText,
|
|
4789
5368
|
location,
|
|
@@ -4800,7 +5379,150 @@ function LocationDetailViewProvider({ children, ...props }) {
|
|
|
4800
5379
|
}),
|
|
4801
5380
|
title: getTitle(location),
|
|
4802
5381
|
message: messageControlContent,
|
|
4803
|
-
}, onActionSelect: onActionSelect, onDropFiles: onDropFiles, onNavigate: onNavigate, onNavigateHome: onNavigateHome, onPaginate: onPaginate, onRefresh: onRefresh, onSearch: onSearch, onSearchQueryChange: onSearchQueryChange, onSearchClear: onSearchClear, onToggleSearchSubfolders: onToggleSearchSubfolders }, children));
|
|
5382
|
+
}, onActionSelect: onActionSelect, onDropFiles: onDropFiles, onNavigate: onNavigate, onNavigateHome: onNavigateHome, onPaginate: onPaginate, onRefresh: onRefresh, onSearch: onSearch, onSelectActiveFile: onSelectActiveFile, onSearchQueryChange: onSearchQueryChange, onSearchClear: onSearchClear, onToggleSearchSubfolders: onToggleSearchSubfolders, onRetryFilePreview: onRetryFilePreview }, children));
|
|
5383
|
+
}
|
|
5384
|
+
|
|
5385
|
+
function resolveUrlOptions(options, fileType) {
|
|
5386
|
+
if (!options) {
|
|
5387
|
+
return DEFAULT_URL_OPTIONS;
|
|
5388
|
+
}
|
|
5389
|
+
if (typeof options === 'function' && fileType) {
|
|
5390
|
+
return options(fileType) ?? DEFAULT_URL_OPTIONS;
|
|
5391
|
+
}
|
|
5392
|
+
return {
|
|
5393
|
+
...DEFAULT_URL_OPTIONS,
|
|
5394
|
+
...options,
|
|
5395
|
+
};
|
|
5396
|
+
}
|
|
5397
|
+
|
|
5398
|
+
function resolveMaxFileSize(maxFileSize, fileType) {
|
|
5399
|
+
if (typeof maxFileSize === 'number') {
|
|
5400
|
+
return maxFileSize;
|
|
5401
|
+
}
|
|
5402
|
+
if (typeof maxFileSize === 'function' && fileType) {
|
|
5403
|
+
try {
|
|
5404
|
+
const result = maxFileSize(fileType);
|
|
5405
|
+
if (typeof result === 'number') {
|
|
5406
|
+
return result;
|
|
5407
|
+
}
|
|
5408
|
+
}
|
|
5409
|
+
catch (error) {
|
|
5410
|
+
//
|
|
5411
|
+
}
|
|
5412
|
+
}
|
|
5413
|
+
return fileType
|
|
5414
|
+
? DEFAULT_FILE_SIZE_LIMITS[fileType] || DEFAULT_FILE_SIZE_LIMIT
|
|
5415
|
+
: DEFAULT_FILE_SIZE_LIMIT;
|
|
5416
|
+
}
|
|
5417
|
+
|
|
5418
|
+
async function safeGetProperties(params) {
|
|
5419
|
+
try {
|
|
5420
|
+
return await storage.getProperties(params);
|
|
5421
|
+
}
|
|
5422
|
+
catch (error) {
|
|
5423
|
+
return {};
|
|
5424
|
+
}
|
|
5425
|
+
}
|
|
5426
|
+
|
|
5427
|
+
function useFilePreview({ activeFile, }) {
|
|
5428
|
+
const filePreviewContext = useFilePreviewContext();
|
|
5429
|
+
const [enabled, setEnabled] = React.useState(true);
|
|
5430
|
+
const getConfig = useGetActionInput();
|
|
5431
|
+
const [{ location }] = useStore();
|
|
5432
|
+
const [filePreviewContent, setFilePreviewContent] = React.useState({ isLoading: true });
|
|
5433
|
+
const { fileTypeResolver, urlOptions, maxFileSize } = (filePreviewContext ?? {}) || {};
|
|
5434
|
+
const getFilePreview = React.useCallback(async () => {
|
|
5435
|
+
if (!activeFile || !activeFile?.key || !location.current) {
|
|
5436
|
+
setEnabled(false);
|
|
5437
|
+
return;
|
|
5438
|
+
}
|
|
5439
|
+
const config = getConfig(location.current);
|
|
5440
|
+
const { accountId, customEndpoint, credentials } = config;
|
|
5441
|
+
const sharedOptions = {
|
|
5442
|
+
bucket: constructBucket(config),
|
|
5443
|
+
expectedBucketOwner: accountId,
|
|
5444
|
+
};
|
|
5445
|
+
try {
|
|
5446
|
+
setEnabled(true);
|
|
5447
|
+
setFilePreviewContent({
|
|
5448
|
+
isLoading: true,
|
|
5449
|
+
});
|
|
5450
|
+
const properties = await safeGetProperties({
|
|
5451
|
+
path: activeFile.key,
|
|
5452
|
+
options: sharedOptions,
|
|
5453
|
+
});
|
|
5454
|
+
const enrichedFile = {
|
|
5455
|
+
...activeFile,
|
|
5456
|
+
...properties,
|
|
5457
|
+
};
|
|
5458
|
+
const fileType = determineFileType({
|
|
5459
|
+
fileData: enrichedFile,
|
|
5460
|
+
fileTypeResolver,
|
|
5461
|
+
});
|
|
5462
|
+
const finalFile = {
|
|
5463
|
+
...enrichedFile,
|
|
5464
|
+
fileType,
|
|
5465
|
+
};
|
|
5466
|
+
const sizeLimit = resolveMaxFileSize(maxFileSize, fileType);
|
|
5467
|
+
const isLimitExceeded = ((finalFile.size || activeFile?.size) ?? 0) > sizeLimit;
|
|
5468
|
+
if (isLimitExceeded) {
|
|
5469
|
+
setFilePreviewContent({
|
|
5470
|
+
ok: false,
|
|
5471
|
+
isLoading: false,
|
|
5472
|
+
error: 'LIMIT_EXCEEDED',
|
|
5473
|
+
});
|
|
5474
|
+
return;
|
|
5475
|
+
}
|
|
5476
|
+
const { url } = await internals.getUrl({
|
|
5477
|
+
path: finalFile.key,
|
|
5478
|
+
options: {
|
|
5479
|
+
customEndpoint,
|
|
5480
|
+
locationCredentialsProvider: credentials,
|
|
5481
|
+
contentDisposition: 'attachment',
|
|
5482
|
+
...sharedOptions,
|
|
5483
|
+
...resolveUrlOptions(urlOptions, fileType),
|
|
5484
|
+
},
|
|
5485
|
+
});
|
|
5486
|
+
setFilePreviewContent({
|
|
5487
|
+
ok: true,
|
|
5488
|
+
isLoading: false,
|
|
5489
|
+
fileData: finalFile,
|
|
5490
|
+
url: url.toString(),
|
|
5491
|
+
});
|
|
5492
|
+
}
|
|
5493
|
+
catch (error) {
|
|
5494
|
+
setFilePreviewContent({
|
|
5495
|
+
isLoading: false,
|
|
5496
|
+
ok: false,
|
|
5497
|
+
error: 'GENERIC_ERROR',
|
|
5498
|
+
});
|
|
5499
|
+
}
|
|
5500
|
+
}, [
|
|
5501
|
+
location,
|
|
5502
|
+
getConfig,
|
|
5503
|
+
fileTypeResolver,
|
|
5504
|
+
maxFileSize,
|
|
5505
|
+
urlOptions,
|
|
5506
|
+
activeFile,
|
|
5507
|
+
]);
|
|
5508
|
+
React.useEffect(() => {
|
|
5509
|
+
getFilePreview();
|
|
5510
|
+
}, [getFilePreview, activeFile]);
|
|
5511
|
+
return React.useMemo(() => {
|
|
5512
|
+
if (filePreviewContext === false || !enabled) {
|
|
5513
|
+
return {
|
|
5514
|
+
optout: filePreviewContext === false,
|
|
5515
|
+
enabled: false,
|
|
5516
|
+
handleRetry: () => undefined,
|
|
5517
|
+
};
|
|
5518
|
+
}
|
|
5519
|
+
return {
|
|
5520
|
+
optout: false,
|
|
5521
|
+
enabled: true,
|
|
5522
|
+
handleRetry: () => getFilePreview(),
|
|
5523
|
+
...filePreviewContent,
|
|
5524
|
+
};
|
|
5525
|
+
}, [getFilePreview, filePreviewContext, filePreviewContent, enabled]);
|
|
4804
5526
|
}
|
|
4805
5527
|
|
|
4806
5528
|
const DEFAULT_PAGE_SIZE$1 = 100;
|
|
@@ -4823,6 +5545,7 @@ const useLocationDetailView = (options) => {
|
|
|
4823
5545
|
const [{ location, actionType }, storeDispatch] = useStore();
|
|
4824
5546
|
const [locationItems, locationItemsDispatch] = useLocationItems();
|
|
4825
5547
|
const fileItemsDispatch = useFileItems()[1];
|
|
5548
|
+
const [activeFile, setActiveFile] = React__namespace["default"].useState();
|
|
4826
5549
|
const { current, key } = location;
|
|
4827
5550
|
const { permissions, prefix } = current ?? {};
|
|
4828
5551
|
const { fileDataItems } = locationItems;
|
|
@@ -4861,7 +5584,62 @@ const useLocationDetailView = (options) => {
|
|
|
4861
5584
|
handleList({ prefix: key, options: searchOptions });
|
|
4862
5585
|
locationItemsDispatch({ type: 'RESET_LOCATION_ITEMS' });
|
|
4863
5586
|
};
|
|
5587
|
+
const { activeFileHasPrev, activeFileHasNext } = React__namespace["default"].useMemo(() => {
|
|
5588
|
+
if (!activeFile)
|
|
5589
|
+
return {
|
|
5590
|
+
activeFileHasNext: false,
|
|
5591
|
+
activeFileHasPrev: false,
|
|
5592
|
+
};
|
|
5593
|
+
const idx = pageItems.findIndex((item) => item.id === activeFile?.id);
|
|
5594
|
+
let pIdx = idx;
|
|
5595
|
+
do {
|
|
5596
|
+
--pIdx;
|
|
5597
|
+
} while (pIdx >= 0 && pageItems[pIdx].type !== 'FILE');
|
|
5598
|
+
let nIdx = idx;
|
|
5599
|
+
do {
|
|
5600
|
+
++nIdx;
|
|
5601
|
+
} while (nIdx <= pageItems.length - 1 && pageItems[nIdx].type !== 'FILE');
|
|
5602
|
+
return {
|
|
5603
|
+
activeFileHasPrev: pIdx >= 0,
|
|
5604
|
+
activeFileHasNext: nIdx <= pageItems.length - 1,
|
|
5605
|
+
};
|
|
5606
|
+
}, [activeFile, pageItems]);
|
|
5607
|
+
const getSuitableNextItem = React.useCallback((direction, type) => {
|
|
5608
|
+
// first find the position
|
|
5609
|
+
let newIdx = pageItems.findIndex((item) => item.id === activeFile?.id);
|
|
5610
|
+
if (direction === 'prev') {
|
|
5611
|
+
do {
|
|
5612
|
+
--newIdx;
|
|
5613
|
+
} while (newIdx >= 0 && pageItems[newIdx].type !== type);
|
|
5614
|
+
if (pageItems[newIdx].type === type) {
|
|
5615
|
+
return pageItems[newIdx];
|
|
5616
|
+
}
|
|
5617
|
+
}
|
|
5618
|
+
else {
|
|
5619
|
+
do {
|
|
5620
|
+
++newIdx;
|
|
5621
|
+
} while (newIdx <= pageItems.length - 1 &&
|
|
5622
|
+
pageItems[newIdx].type !== type);
|
|
5623
|
+
if (pageItems[newIdx].type === type) {
|
|
5624
|
+
return pageItems[newIdx];
|
|
5625
|
+
}
|
|
5626
|
+
}
|
|
5627
|
+
}, [activeFile, pageItems]);
|
|
5628
|
+
const onSelectActiveFile = (arg) => {
|
|
5629
|
+
if (arg === 'prev') {
|
|
5630
|
+
setActiveFile(getSuitableNextItem('prev', 'FILE'));
|
|
5631
|
+
}
|
|
5632
|
+
else if (arg === 'next') {
|
|
5633
|
+
setActiveFile(getSuitableNextItem('next', 'FILE'));
|
|
5634
|
+
}
|
|
5635
|
+
else {
|
|
5636
|
+
setActiveFile(arg);
|
|
5637
|
+
}
|
|
5638
|
+
};
|
|
4864
5639
|
const { searchQuery, isSearchingSubfolders: isSearchSubfoldersEnabled, onSearchQueryChange, onSearchSubmit, onToggleSearchSubfolders, resetSearch, } = useSearch({ onSearch });
|
|
5640
|
+
const { handleRetry, optout, ...filePreviewState } = useFilePreview({
|
|
5641
|
+
activeFile,
|
|
5642
|
+
});
|
|
4865
5643
|
const onRefresh = () => {
|
|
4866
5644
|
if (hasInvalidPrefix)
|
|
4867
5645
|
return;
|
|
@@ -4871,6 +5649,7 @@ const useLocationDetailView = (options) => {
|
|
|
4871
5649
|
prefix: key,
|
|
4872
5650
|
options: { ...listOptions, refresh: true },
|
|
4873
5651
|
});
|
|
5652
|
+
setActiveFile(undefined);
|
|
4874
5653
|
locationItemsDispatch({ type: 'RESET_LOCATION_ITEMS' });
|
|
4875
5654
|
};
|
|
4876
5655
|
React__namespace["default"].useEffect(() => {
|
|
@@ -4881,6 +5660,7 @@ const useLocationDetailView = (options) => {
|
|
|
4881
5660
|
options: { ...listOptions, refresh: true },
|
|
4882
5661
|
});
|
|
4883
5662
|
handleReset();
|
|
5663
|
+
setActiveFile(undefined);
|
|
4884
5664
|
}, [handleList, handleReset, listOptions, hasInvalidPrefix, key]);
|
|
4885
5665
|
const { actionConfigs } = useActionConfigs();
|
|
4886
5666
|
const actionItems = React__namespace["default"].useMemo(() => {
|
|
@@ -4905,6 +5685,10 @@ const useLocationDetailView = (options) => {
|
|
|
4905
5685
|
return {
|
|
4906
5686
|
actionItems,
|
|
4907
5687
|
actionType,
|
|
5688
|
+
activeFile,
|
|
5689
|
+
activeFileHasNext,
|
|
5690
|
+
activeFileHasPrev,
|
|
5691
|
+
onSelectActiveFile,
|
|
4908
5692
|
page: currentPage,
|
|
4909
5693
|
pageItems,
|
|
4910
5694
|
location,
|
|
@@ -4917,8 +5701,13 @@ const useLocationDetailView = (options) => {
|
|
|
4917
5701
|
downloadErrorMessage: getDownloadErrorMessageFromFailedDownloadTask(task),
|
|
4918
5702
|
isLoading,
|
|
4919
5703
|
isSearchSubfoldersEnabled,
|
|
4920
|
-
onPaginate:
|
|
5704
|
+
onPaginate: (p) => {
|
|
5705
|
+
handlePaginate(p);
|
|
5706
|
+
setActiveFile(undefined);
|
|
5707
|
+
},
|
|
4921
5708
|
searchQuery,
|
|
5709
|
+
filePreviewState,
|
|
5710
|
+
filePreviewEnabled: !optout,
|
|
4922
5711
|
hasExhaustedSearch,
|
|
4923
5712
|
onRefresh,
|
|
4924
5713
|
onActionExit: () => {
|
|
@@ -4936,6 +5725,7 @@ const useLocationDetailView = (options) => {
|
|
|
4936
5725
|
resetSearch();
|
|
4937
5726
|
storeDispatch({ type: 'CHANGE_LOCATION', location, path });
|
|
4938
5727
|
locationItemsDispatch({ type: 'RESET_LOCATION_ITEMS' });
|
|
5728
|
+
setActiveFile(undefined);
|
|
4939
5729
|
},
|
|
4940
5730
|
onDropFiles: (files) => {
|
|
4941
5731
|
fileItemsDispatch({ type: 'ADD_FILES', files });
|
|
@@ -4968,7 +5758,10 @@ const useLocationDetailView = (options) => {
|
|
|
4968
5758
|
? { type: 'RESET_LOCATION_ITEMS' }
|
|
4969
5759
|
: { type: 'SET_LOCATION_ITEMS', items: fileItems });
|
|
4970
5760
|
},
|
|
4971
|
-
onSearch:
|
|
5761
|
+
onSearch: () => {
|
|
5762
|
+
setActiveFile(undefined);
|
|
5763
|
+
onSearchSubmit();
|
|
5764
|
+
},
|
|
4972
5765
|
onSearchClear: () => {
|
|
4973
5766
|
resetSearch();
|
|
4974
5767
|
if (hasInvalidPrefix)
|
|
@@ -4977,10 +5770,29 @@ const useLocationDetailView = (options) => {
|
|
|
4977
5770
|
handleReset();
|
|
4978
5771
|
},
|
|
4979
5772
|
onSearchQueryChange,
|
|
5773
|
+
onRetryFilePreview: handleRetry,
|
|
4980
5774
|
onToggleSearchSubfolders,
|
|
4981
5775
|
};
|
|
4982
5776
|
};
|
|
4983
5777
|
|
|
5778
|
+
function FilePreviewControl() {
|
|
5779
|
+
const { data, onRetryFilePreview, onSelectActiveFile } = useControlsContext();
|
|
5780
|
+
const { filePreviewState, activeFile, activeFileHasNext, activeFileHasPrev } = data;
|
|
5781
|
+
const props = {
|
|
5782
|
+
filePreview: filePreviewState,
|
|
5783
|
+
activeFile,
|
|
5784
|
+
activeFileHasNext,
|
|
5785
|
+
activeFileHasPrev,
|
|
5786
|
+
onRetryFilePreview,
|
|
5787
|
+
onSelectActiveFile,
|
|
5788
|
+
};
|
|
5789
|
+
const Resolved = useResolvedComposable(FilePreview, 'FilePreview');
|
|
5790
|
+
if (!activeFile) {
|
|
5791
|
+
return null;
|
|
5792
|
+
}
|
|
5793
|
+
return React__namespace["default"].createElement(Resolved, { ...props });
|
|
5794
|
+
}
|
|
5795
|
+
|
|
4984
5796
|
const LocationDetailView = ({ className, ...props }) => {
|
|
4985
5797
|
const state = useLocationDetailView(props);
|
|
4986
5798
|
const { hasError } = state;
|
|
@@ -4995,10 +5807,12 @@ const LocationDetailView = ({ className, ...props }) => {
|
|
|
4995
5807
|
React__namespace["default"].createElement(PaginationControl, null),
|
|
4996
5808
|
React__namespace["default"].createElement(DataRefreshControl, null),
|
|
4997
5809
|
React__namespace["default"].createElement(ActionsListControl, null)),
|
|
4998
|
-
hasError ? null : (React__namespace["default"].createElement(
|
|
4999
|
-
React__namespace["default"].createElement(
|
|
5000
|
-
React__namespace["default"].createElement(
|
|
5001
|
-
|
|
5810
|
+
hasError ? null : (React__namespace["default"].createElement(ViewElement, { className: `${STORAGE_BROWSER_BLOCK}__content-with-preview` },
|
|
5811
|
+
React__namespace["default"].createElement(DropZoneControl, null,
|
|
5812
|
+
React__namespace["default"].createElement(ViewElement, { className: `${STORAGE_BROWSER_BLOCK}__data-table` },
|
|
5813
|
+
React__namespace["default"].createElement(LoadingIndicatorControl, null),
|
|
5814
|
+
React__namespace["default"].createElement(DataTableControl, null))),
|
|
5815
|
+
React__namespace["default"].createElement(FilePreviewControl, null))),
|
|
5002
5816
|
React__namespace["default"].createElement(ViewElement, { className: `${STORAGE_BROWSER_BLOCK}__footer` },
|
|
5003
5817
|
React__namespace["default"].createElement(MessageControl, null)))));
|
|
5004
5818
|
};
|
|
@@ -5015,6 +5829,7 @@ LocationDetailView.Refresh = DataRefreshControl;
|
|
|
5015
5829
|
LocationDetailView.Search = SearchFieldControl;
|
|
5016
5830
|
LocationDetailView.SearchSubfoldersToggle = SearchSubfoldersToggleControl;
|
|
5017
5831
|
LocationDetailView.Title = TitleControl;
|
|
5832
|
+
LocationDetailView.FilePreview = FilePreviewControl;
|
|
5018
5833
|
|
|
5019
5834
|
const getHeaders = ({ hasObjectLocations, tableColumnActionsHeader, tableColumnBucketHeader, tableColumnFolderHeader, tableColumnPermissionsHeader, }) => {
|
|
5020
5835
|
const headers = [
|
|
@@ -5343,7 +6158,7 @@ const useView = (type) => {
|
|
|
5343
6158
|
return USE_VIEW_HOOKS[type]();
|
|
5344
6159
|
};
|
|
5345
6160
|
|
|
5346
|
-
function createProvider({ actions, components, config, options, }) {
|
|
6161
|
+
function createProvider({ actions, components, config, options, filePreview = {}, }) {
|
|
5347
6162
|
const { accountId, customEndpoint, registerAuthListener, getLocationCredentials, region, listLocations, } = config;
|
|
5348
6163
|
const resolvedActions = {
|
|
5349
6164
|
default: {
|
|
@@ -5386,7 +6201,8 @@ function createProvider({ actions, components, config, options, }) {
|
|
|
5386
6201
|
React__namespace["default"].createElement(ViewsProvider, { actions: resolvedActions, views: views },
|
|
5387
6202
|
React__namespace["default"].createElement(ComponentsProvider, { composables: composables },
|
|
5388
6203
|
React__namespace["default"].createElement(LocationItemsProvider, null,
|
|
5389
|
-
React__namespace["default"].createElement(FileItemsProvider, { validateFile: validateFile },
|
|
6204
|
+
React__namespace["default"].createElement(FileItemsProvider, { validateFile: validateFile },
|
|
6205
|
+
React__namespace["default"].createElement(FilePreviewProvider, { filePreview: filePreview }, children)))))))))));
|
|
5390
6206
|
}
|
|
5391
6207
|
return Provider;
|
|
5392
6208
|
}
|