mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-05-11 02:44:21 +01:00
212 lines
6.3 KiB
TypeScript
212 lines
6.3 KiB
TypeScript
import {
|
|
DetailsList,
|
|
DetailsListLayoutMode,
|
|
DirectionalHint,
|
|
FontIcon,
|
|
IColumn,
|
|
SelectionMode,
|
|
TooltipHost,
|
|
getTheme,
|
|
mergeStyles,
|
|
mergeStyleSets,
|
|
} from "@fluentui/react";
|
|
import { Upload } from "Common/Upload/Upload";
|
|
import { UploadDetailsRecord } from "Contracts/ViewModels";
|
|
import { logConsoleError } from "Utils/NotificationConsoleUtils";
|
|
import React, { ChangeEvent, FunctionComponent, useState } from "react";
|
|
import { getErrorMessage } from "../../Tables/Utilities";
|
|
import { useSelectedNode } from "../../useSelectedNode";
|
|
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
|
|
|
|
const theme = getTheme();
|
|
const iconClass = mergeStyles({
|
|
verticalAlign: "middle",
|
|
maxHeight: "16px",
|
|
maxWidth: "16px",
|
|
});
|
|
|
|
const classNames = mergeStyleSets({
|
|
fileIconHeaderIcon: {
|
|
padding: 0,
|
|
fontSize: "16px",
|
|
},
|
|
fileIconCell: {
|
|
textAlign: "center",
|
|
selectors: {
|
|
"&:before": {
|
|
content: ".",
|
|
display: "inline-block",
|
|
verticalAlign: "middle",
|
|
height: "100%",
|
|
width: "0px",
|
|
visibility: "hidden",
|
|
},
|
|
},
|
|
},
|
|
error: [{ color: theme.semanticColors.errorIcon }, iconClass],
|
|
accept: [{ color: theme.semanticColors.successIcon }, iconClass],
|
|
warning: [{ color: theme.semanticColors.warningIcon }, iconClass],
|
|
});
|
|
|
|
export const UploadItemsPane: FunctionComponent = () => {
|
|
const [files, setFiles] = useState<FileList>();
|
|
const [uploadFileData, setUploadFileData] = useState<UploadDetailsRecord[]>([]);
|
|
const [formError, setFormError] = useState<string>("");
|
|
const [isExecuting, setIsExecuting] = useState<boolean>();
|
|
|
|
const onSubmit = () => {
|
|
setFormError("");
|
|
if (!files || files.length === 0) {
|
|
setFormError("No files were specified. Please input at least one file.");
|
|
logConsoleError("Could not upload items -- No files were specified. Please input at least one file.");
|
|
return;
|
|
}
|
|
|
|
const selectedCollection = useSelectedNode.getState().findSelectedCollection();
|
|
setIsExecuting(true);
|
|
|
|
selectedCollection
|
|
?.uploadFiles(files)
|
|
.then(
|
|
(uploadDetails) => {
|
|
setUploadFileData(uploadDetails.data);
|
|
setFiles(undefined);
|
|
},
|
|
(error: Error) => {
|
|
const errorMessage = getErrorMessage(error);
|
|
setFormError(errorMessage);
|
|
},
|
|
)
|
|
.finally(() => {
|
|
setIsExecuting(false);
|
|
});
|
|
};
|
|
|
|
const updateSelectedFiles = (event: ChangeEvent<HTMLInputElement>): void => {
|
|
setFiles(event.target.files);
|
|
};
|
|
|
|
const props: RightPaneFormProps = {
|
|
formError,
|
|
isExecuting: isExecuting,
|
|
submitButtonText: "Upload",
|
|
onSubmit,
|
|
};
|
|
|
|
const columns: IColumn[] = [
|
|
{
|
|
key: "icons",
|
|
name: "",
|
|
fieldName: "",
|
|
className: classNames.fileIconCell,
|
|
iconClassName: classNames.fileIconHeaderIcon,
|
|
isIconOnly: true,
|
|
minWidth: 16,
|
|
maxWidth: 16,
|
|
onRender: (item: UploadDetailsRecord, index: number, column: IColumn) => {
|
|
if (item.numFailed) {
|
|
const errorList = (
|
|
<ul
|
|
aria-label={"error list"}
|
|
style={{
|
|
margin: "5px 0",
|
|
paddingLeft: "20px",
|
|
listStyleType: "disc", // Explicitly set to use bullets (dots)
|
|
}}
|
|
>
|
|
{item.errors.map((error, i) => (
|
|
<li key={i} style={{ display: "list-item" }}>
|
|
{error}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
);
|
|
|
|
return (
|
|
<TooltipHost
|
|
content={errorList}
|
|
id={`tooltip-${index}-${column.key}`}
|
|
directionalHint={DirectionalHint.bottomAutoEdge}
|
|
>
|
|
<FontIcon iconName="Error" className={classNames.error} aria-label="error" />
|
|
</TooltipHost>
|
|
);
|
|
} else if (item.numThrottled) {
|
|
return <FontIcon iconName="Warning" className={classNames.warning} aria-label="warning" />;
|
|
} else {
|
|
return <FontIcon iconName="Accept" className={classNames.accept} aria-label="accept" />;
|
|
}
|
|
},
|
|
},
|
|
{
|
|
key: "fileName",
|
|
name: "FILE NAME",
|
|
fieldName: "fileName",
|
|
minWidth: 120,
|
|
maxWidth: 140,
|
|
onRender: (item: UploadDetailsRecord, index: number, column: IColumn) => {
|
|
const fieldContent = item.fileName;
|
|
return (
|
|
<TooltipHost
|
|
content={fieldContent}
|
|
id={`tooltip-${index}-${column.key}`}
|
|
directionalHint={DirectionalHint.bottomAutoEdge}
|
|
>
|
|
{fieldContent}
|
|
</TooltipHost>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
key: "status",
|
|
name: "STATUS",
|
|
fieldName: "numSucceeded",
|
|
minWidth: 120,
|
|
maxWidth: 140,
|
|
isRowHeader: true,
|
|
isResizable: true,
|
|
data: "string",
|
|
isPadded: true,
|
|
onRender: (item: UploadDetailsRecord, index: number, column: IColumn) => {
|
|
const fieldContent = `${item.numSucceeded} created, ${item.numThrottled} throttled, ${item.numFailed} errors`;
|
|
return (
|
|
<TooltipHost
|
|
content={fieldContent}
|
|
id={`tooltip-${index}-${column.key}`}
|
|
directionalHint={DirectionalHint.bottomAutoEdge}
|
|
>
|
|
{fieldContent}
|
|
</TooltipHost>
|
|
);
|
|
},
|
|
},
|
|
];
|
|
|
|
return (
|
|
<RightPaneForm {...props}>
|
|
<div className="paneMainContent">
|
|
<Upload
|
|
label="Select JSON Files"
|
|
onUpload={updateSelectedFiles}
|
|
accept="application/json"
|
|
multiple
|
|
tabIndex={0}
|
|
tooltip="Select one or more JSON files to upload. Each file can contain a single JSON document or an array of JSON documents. The combined size of all files in an individual upload operation must be less than 2 MB. You can perform multiple upload operations for larger data sets."
|
|
/>
|
|
{uploadFileData?.length > 0 && (
|
|
<div className="fileUploadSummaryContainer">
|
|
<b>File upload status</b>
|
|
<DetailsList
|
|
items={uploadFileData}
|
|
columns={columns}
|
|
selectionMode={SelectionMode.none}
|
|
layoutMode={DetailsListLayoutMode.justified}
|
|
isHeaderVisible={true}
|
|
/>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</RightPaneForm>
|
|
);
|
|
};
|