mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2024-11-24 22:46:40 +00:00
Move upload items panel to react (#558)
Co-authored-by: Steve Faulkner <471400+southpolesteve@users.noreply.github.com>
This commit is contained in:
parent
458cca8e01
commit
6a69d3a77b
@ -145,7 +145,6 @@ src/Explorer/Panes/Tables/Validators/EntityPropertyNameValidator.ts
|
||||
src/Explorer/Panes/Tables/Validators/EntityPropertyValidationCommon.ts
|
||||
src/Explorer/Panes/Tables/Validators/EntityPropertyValueValidator.ts
|
||||
src/Explorer/Panes/UploadFilePane.ts
|
||||
src/Explorer/Panes/UploadItemsPane.ts
|
||||
src/Explorer/SplashScreen/SplashScreen.test.ts
|
||||
src/Explorer/Tables/Constants.ts
|
||||
src/Explorer/Tables/DataTable/CacheBase.ts
|
||||
|
75
src/Common/Upload/index.tsx
Normal file
75
src/Common/Upload/index.tsx
Normal file
@ -0,0 +1,75 @@
|
||||
import { Image, Stack, TextField } from "office-ui-fabric-react";
|
||||
import React, { ChangeEvent, FunctionComponent, KeyboardEvent, useRef, useState } from "react";
|
||||
import FolderIcon from "../../../images/folder_16x16.svg";
|
||||
import * as Constants from "../../Common/Constants";
|
||||
import { Tooltip } from "../Tooltip";
|
||||
|
||||
interface UploadProps {
|
||||
label: string;
|
||||
accept?: string;
|
||||
tooltip?: string;
|
||||
multiple?: boolean;
|
||||
tabIndex?: number;
|
||||
onUpload: (event: ChangeEvent<HTMLInputElement>) => void;
|
||||
}
|
||||
|
||||
export const Upload: FunctionComponent<UploadProps> = ({
|
||||
label,
|
||||
accept,
|
||||
tooltip,
|
||||
multiple,
|
||||
tabIndex,
|
||||
...props
|
||||
}: UploadProps) => {
|
||||
const [selectedFilesTitle, setSelectedFilesTitle] = useState<string[]>([]);
|
||||
|
||||
const fileRef = useRef<HTMLInputElement>();
|
||||
|
||||
const onImportLinkKeyPress = (event: KeyboardEvent<HTMLAnchorElement>): void => {
|
||||
if (event.keyCode === Constants.KeyCodes.Enter || event.keyCode === Constants.KeyCodes.Space) {
|
||||
onImportLinkClick();
|
||||
}
|
||||
};
|
||||
|
||||
const onImportLinkClick = (): void => {
|
||||
fileRef?.current?.click();
|
||||
};
|
||||
|
||||
const onUpload = (event: ChangeEvent<HTMLInputElement>): void => {
|
||||
const { files } = event.target;
|
||||
|
||||
const newFileList = [];
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
newFileList.push(files.item(i).name);
|
||||
}
|
||||
if (newFileList) {
|
||||
setSelectedFilesTitle(newFileList);
|
||||
props.onUpload(event);
|
||||
}
|
||||
};
|
||||
const title = label + " to upload";
|
||||
return (
|
||||
<div>
|
||||
<span className="renewUploadItemsHeader">{label}</span>
|
||||
<Tooltip>{tooltip}</Tooltip>
|
||||
<Stack horizontal>
|
||||
<TextField styles={{ fieldGroup: { width: 300 } }} readOnly value={selectedFilesTitle.toString()} />
|
||||
<input
|
||||
type="file"
|
||||
id="importFileInput"
|
||||
style={{ display: "none" }}
|
||||
ref={fileRef}
|
||||
accept={accept}
|
||||
tabIndex={tabIndex}
|
||||
multiple={multiple}
|
||||
title="Upload Icon"
|
||||
onChange={onUpload}
|
||||
role="button"
|
||||
/>
|
||||
<a href="#" id="fileImportLinkNotebook" onClick={onImportLinkClick} onKeyPress={onImportLinkKeyPress}>
|
||||
<Image className="fileImportImg" src={FolderIcon} alt={title} title={title} />
|
||||
</a>
|
||||
</Stack>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -75,7 +75,6 @@ ko.components.register("table-edit-entity-pane", new PaneComponents.TableEditEnt
|
||||
ko.components.register("table-column-options-pane", new PaneComponents.TableColumnOptionsPaneComponent());
|
||||
ko.components.register("table-query-select-pane", new PaneComponents.TableQuerySelectPaneComponent());
|
||||
ko.components.register("cassandra-add-collection-pane", new PaneComponents.CassandraAddCollectionPaneComponent());
|
||||
ko.components.register("upload-items-pane", new PaneComponents.UploadItemsPaneComponent());
|
||||
ko.components.register("load-query-pane", new PaneComponents.LoadQueryPaneComponent());
|
||||
ko.components.register("save-query-pane", new PaneComponents.SaveQueryPaneComponent());
|
||||
ko.components.register("browse-queries-pane", new PaneComponents.BrowseQueriesPaneComponent());
|
||||
|
@ -386,23 +386,6 @@ exports[`SettingsComponent renders 1`] = `
|
||||
"userTableQuery": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
UploadItemsPane {
|
||||
"container": [Circular],
|
||||
"fileUploadSummaryText": [Function],
|
||||
"files": [Function],
|
||||
"firstFieldHasFocus": [Function],
|
||||
"formErrors": [Function],
|
||||
"formErrorsDetails": [Function],
|
||||
"id": "uploaditemspane",
|
||||
"isExecuting": [Function],
|
||||
"isTemplateReady": [Function],
|
||||
"onImportLinkKeyPress": [Function],
|
||||
"selectedFilesTitle": [Function],
|
||||
"title": [Function],
|
||||
"uploadFileData": [Function],
|
||||
"uploadFileDataVisible": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
LoadQueryPane {
|
||||
"container": [Circular],
|
||||
"files": [Function],
|
||||
@ -1074,37 +1057,6 @@ exports[`SettingsComponent renders 1`] = `
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
"uploadItemsPane": UploadItemsPane {
|
||||
"container": [Circular],
|
||||
"fileUploadSummaryText": [Function],
|
||||
"files": [Function],
|
||||
"firstFieldHasFocus": [Function],
|
||||
"formErrors": [Function],
|
||||
"formErrorsDetails": [Function],
|
||||
"id": "uploaditemspane",
|
||||
"isExecuting": [Function],
|
||||
"isTemplateReady": [Function],
|
||||
"onImportLinkKeyPress": [Function],
|
||||
"selectedFilesTitle": [Function],
|
||||
"title": [Function],
|
||||
"uploadFileData": [Function],
|
||||
"uploadFileDataVisible": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
"uploadItemsPaneAdapter": UploadItemsPaneAdapter {
|
||||
"_updateSelectedFilesTitle": [Function],
|
||||
"container": [Circular],
|
||||
"formError": "",
|
||||
"formErrorDetail": "",
|
||||
"isExecuting": false,
|
||||
"isOpened": false,
|
||||
"parameters": [Function],
|
||||
"reset": [Function],
|
||||
"selectedFiles": undefined,
|
||||
"selectedFilesTitle": "",
|
||||
"updateSelectedFiles": [Function],
|
||||
"uploadFileData": Array [],
|
||||
},
|
||||
},
|
||||
"databaseId": "test",
|
||||
"defaultTtl": [Function],
|
||||
@ -1484,23 +1436,6 @@ exports[`SettingsComponent renders 1`] = `
|
||||
"userTableQuery": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
UploadItemsPane {
|
||||
"container": [Circular],
|
||||
"fileUploadSummaryText": [Function],
|
||||
"files": [Function],
|
||||
"firstFieldHasFocus": [Function],
|
||||
"formErrors": [Function],
|
||||
"formErrorsDetails": [Function],
|
||||
"id": "uploaditemspane",
|
||||
"isExecuting": [Function],
|
||||
"isTemplateReady": [Function],
|
||||
"onImportLinkKeyPress": [Function],
|
||||
"selectedFilesTitle": [Function],
|
||||
"title": [Function],
|
||||
"uploadFileData": [Function],
|
||||
"uploadFileDataVisible": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
LoadQueryPane {
|
||||
"container": [Circular],
|
||||
"files": [Function],
|
||||
@ -2172,37 +2107,6 @@ exports[`SettingsComponent renders 1`] = `
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
"uploadItemsPane": UploadItemsPane {
|
||||
"container": [Circular],
|
||||
"fileUploadSummaryText": [Function],
|
||||
"files": [Function],
|
||||
"firstFieldHasFocus": [Function],
|
||||
"formErrors": [Function],
|
||||
"formErrorsDetails": [Function],
|
||||
"id": "uploaditemspane",
|
||||
"isExecuting": [Function],
|
||||
"isTemplateReady": [Function],
|
||||
"onImportLinkKeyPress": [Function],
|
||||
"selectedFilesTitle": [Function],
|
||||
"title": [Function],
|
||||
"uploadFileData": [Function],
|
||||
"uploadFileDataVisible": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
"uploadItemsPaneAdapter": UploadItemsPaneAdapter {
|
||||
"_updateSelectedFilesTitle": [Function],
|
||||
"container": [Circular],
|
||||
"formError": "",
|
||||
"formErrorDetail": "",
|
||||
"isExecuting": false,
|
||||
"isOpened": false,
|
||||
"parameters": [Function],
|
||||
"reset": [Function],
|
||||
"selectedFiles": undefined,
|
||||
"selectedFilesTitle": "",
|
||||
"updateSelectedFiles": [Function],
|
||||
"uploadFileData": Array [],
|
||||
},
|
||||
}
|
||||
}
|
||||
isAutoPilotSelected={false}
|
||||
@ -2595,23 +2499,6 @@ exports[`SettingsComponent renders 1`] = `
|
||||
"userTableQuery": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
UploadItemsPane {
|
||||
"container": [Circular],
|
||||
"fileUploadSummaryText": [Function],
|
||||
"files": [Function],
|
||||
"firstFieldHasFocus": [Function],
|
||||
"formErrors": [Function],
|
||||
"formErrorsDetails": [Function],
|
||||
"id": "uploaditemspane",
|
||||
"isExecuting": [Function],
|
||||
"isTemplateReady": [Function],
|
||||
"onImportLinkKeyPress": [Function],
|
||||
"selectedFilesTitle": [Function],
|
||||
"title": [Function],
|
||||
"uploadFileData": [Function],
|
||||
"uploadFileDataVisible": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
LoadQueryPane {
|
||||
"container": [Circular],
|
||||
"files": [Function],
|
||||
@ -3283,37 +3170,6 @@ exports[`SettingsComponent renders 1`] = `
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
"uploadItemsPane": UploadItemsPane {
|
||||
"container": [Circular],
|
||||
"fileUploadSummaryText": [Function],
|
||||
"files": [Function],
|
||||
"firstFieldHasFocus": [Function],
|
||||
"formErrors": [Function],
|
||||
"formErrorsDetails": [Function],
|
||||
"id": "uploaditemspane",
|
||||
"isExecuting": [Function],
|
||||
"isTemplateReady": [Function],
|
||||
"onImportLinkKeyPress": [Function],
|
||||
"selectedFilesTitle": [Function],
|
||||
"title": [Function],
|
||||
"uploadFileData": [Function],
|
||||
"uploadFileDataVisible": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
"uploadItemsPaneAdapter": UploadItemsPaneAdapter {
|
||||
"_updateSelectedFilesTitle": [Function],
|
||||
"container": [Circular],
|
||||
"formError": "",
|
||||
"formErrorDetail": "",
|
||||
"isExecuting": false,
|
||||
"isOpened": false,
|
||||
"parameters": [Function],
|
||||
"reset": [Function],
|
||||
"selectedFiles": undefined,
|
||||
"selectedFilesTitle": "",
|
||||
"updateSelectedFiles": [Function],
|
||||
"uploadFileData": Array [],
|
||||
},
|
||||
},
|
||||
"databaseId": "test",
|
||||
"defaultTtl": [Function],
|
||||
@ -3693,23 +3549,6 @@ exports[`SettingsComponent renders 1`] = `
|
||||
"userTableQuery": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
UploadItemsPane {
|
||||
"container": [Circular],
|
||||
"fileUploadSummaryText": [Function],
|
||||
"files": [Function],
|
||||
"firstFieldHasFocus": [Function],
|
||||
"formErrors": [Function],
|
||||
"formErrorsDetails": [Function],
|
||||
"id": "uploaditemspane",
|
||||
"isExecuting": [Function],
|
||||
"isTemplateReady": [Function],
|
||||
"onImportLinkKeyPress": [Function],
|
||||
"selectedFilesTitle": [Function],
|
||||
"title": [Function],
|
||||
"uploadFileData": [Function],
|
||||
"uploadFileDataVisible": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
LoadQueryPane {
|
||||
"container": [Circular],
|
||||
"files": [Function],
|
||||
@ -4381,37 +4220,6 @@ exports[`SettingsComponent renders 1`] = `
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
"uploadItemsPane": UploadItemsPane {
|
||||
"container": [Circular],
|
||||
"fileUploadSummaryText": [Function],
|
||||
"files": [Function],
|
||||
"firstFieldHasFocus": [Function],
|
||||
"formErrors": [Function],
|
||||
"formErrorsDetails": [Function],
|
||||
"id": "uploaditemspane",
|
||||
"isExecuting": [Function],
|
||||
"isTemplateReady": [Function],
|
||||
"onImportLinkKeyPress": [Function],
|
||||
"selectedFilesTitle": [Function],
|
||||
"title": [Function],
|
||||
"uploadFileData": [Function],
|
||||
"uploadFileDataVisible": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
"uploadItemsPaneAdapter": UploadItemsPaneAdapter {
|
||||
"_updateSelectedFilesTitle": [Function],
|
||||
"container": [Circular],
|
||||
"formError": "",
|
||||
"formErrorDetail": "",
|
||||
"isExecuting": false,
|
||||
"isOpened": false,
|
||||
"parameters": [Function],
|
||||
"reset": [Function],
|
||||
"selectedFiles": undefined,
|
||||
"selectedFilesTitle": "",
|
||||
"updateSelectedFiles": [Function],
|
||||
"uploadFileData": Array [],
|
||||
},
|
||||
}
|
||||
}
|
||||
geospatialConfigType="Geometry"
|
||||
|
@ -70,7 +70,6 @@ import { QuerySelectPane } from "./Panes/Tables/QuerySelectPane";
|
||||
import { TableColumnOptionsPane } from "./Panes/Tables/TableColumnOptionsPane";
|
||||
import { UploadFilePane } from "./Panes/UploadFilePane";
|
||||
import { UploadItemsPane } from "./Panes/UploadItemsPane";
|
||||
import { UploadItemsPaneAdapter } from "./Panes/UploadItemsPaneAdapter";
|
||||
import { CassandraAPIDataClient, TableDataClient, TablesAPIDataClient } from "./Tables/TableDataClient";
|
||||
import NotebookV2Tab, { NotebookTabOptions } from "./Tabs/NotebookV2Tab";
|
||||
import TabsBase from "./Tabs/TabsBase";
|
||||
@ -212,8 +211,6 @@ export default class Explorer {
|
||||
public querySelectPane: QuerySelectPane;
|
||||
public newVertexPane: NewVertexPane;
|
||||
public cassandraAddCollectionPane: CassandraAddCollectionPane;
|
||||
public uploadItemsPane: UploadItemsPane;
|
||||
public uploadItemsPaneAdapter: UploadItemsPaneAdapter;
|
||||
public loadQueryPane: LoadQueryPane;
|
||||
public saveQueryPane: ContextualPaneBase;
|
||||
public browseQueriesPane: BrowseQueriesPane;
|
||||
@ -623,15 +620,6 @@ export default class Explorer {
|
||||
container: this,
|
||||
});
|
||||
|
||||
this.uploadItemsPane = new UploadItemsPane({
|
||||
id: "uploaditemspane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
|
||||
container: this,
|
||||
});
|
||||
|
||||
this.uploadItemsPaneAdapter = new UploadItemsPaneAdapter(this);
|
||||
|
||||
this.loadQueryPane = new LoadQueryPane({
|
||||
id: "loadquerypane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
@ -688,7 +676,6 @@ export default class Explorer {
|
||||
this.querySelectPane,
|
||||
this.newVertexPane,
|
||||
this.cassandraAddCollectionPane,
|
||||
this.uploadItemsPane,
|
||||
this.loadQueryPane,
|
||||
this.saveQueryPane,
|
||||
this.browseQueriesPane,
|
||||
@ -2445,6 +2432,10 @@ export default class Explorer {
|
||||
);
|
||||
}
|
||||
|
||||
public openUploadItemsPanePane(): void {
|
||||
this.openSidePanel("Upload", <UploadItemsPane explorer={this} closePanel={this.closeSidePanel} />);
|
||||
}
|
||||
|
||||
public openSettingPane(): void {
|
||||
this.openSidePanel("Settings", <SettingsPane explorer={this} closePanel={this.closeSidePanel} />);
|
||||
}
|
||||
|
@ -16,7 +16,6 @@ import TableColumnOptionsPaneTemplate from "./Tables/TableColumnOptionsPane.html
|
||||
import TableEditEntityPaneTemplate from "./Tables/TableEditEntityPane.html";
|
||||
import TableQuerySelectPaneTemplate from "./Tables/TableQuerySelectPane.html";
|
||||
import UploadFilePaneTemplate from "./UploadFilePane.html";
|
||||
import UploadItemsPaneTemplate from "./UploadItemsPane.html";
|
||||
|
||||
export class PaneComponent {
|
||||
constructor(data: any) {
|
||||
@ -123,15 +122,6 @@ export class CassandraAddCollectionPaneComponent {
|
||||
}
|
||||
}
|
||||
|
||||
export class UploadItemsPaneComponent {
|
||||
constructor() {
|
||||
return {
|
||||
viewModel: PaneComponent,
|
||||
template: UploadItemsPaneTemplate,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class LoadQueryPaneComponent {
|
||||
constructor() {
|
||||
return {
|
||||
|
@ -362,23 +362,6 @@ exports[`Settings Pane should render Default properly 1`] = `
|
||||
"userTableQuery": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
UploadItemsPane {
|
||||
"container": [Circular],
|
||||
"fileUploadSummaryText": [Function],
|
||||
"files": [Function],
|
||||
"firstFieldHasFocus": [Function],
|
||||
"formErrors": [Function],
|
||||
"formErrorsDetails": [Function],
|
||||
"id": "uploaditemspane",
|
||||
"isExecuting": [Function],
|
||||
"isTemplateReady": [Function],
|
||||
"onImportLinkKeyPress": [Function],
|
||||
"selectedFilesTitle": [Function],
|
||||
"title": [Function],
|
||||
"uploadFileData": [Function],
|
||||
"uploadFileDataVisible": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
LoadQueryPane {
|
||||
"container": [Circular],
|
||||
"files": [Function],
|
||||
@ -1050,37 +1033,6 @@ exports[`Settings Pane should render Default properly 1`] = `
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
"uploadItemsPane": UploadItemsPane {
|
||||
"container": [Circular],
|
||||
"fileUploadSummaryText": [Function],
|
||||
"files": [Function],
|
||||
"firstFieldHasFocus": [Function],
|
||||
"formErrors": [Function],
|
||||
"formErrorsDetails": [Function],
|
||||
"id": "uploaditemspane",
|
||||
"isExecuting": [Function],
|
||||
"isTemplateReady": [Function],
|
||||
"onImportLinkKeyPress": [Function],
|
||||
"selectedFilesTitle": [Function],
|
||||
"title": [Function],
|
||||
"uploadFileData": [Function],
|
||||
"uploadFileDataVisible": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
"uploadItemsPaneAdapter": UploadItemsPaneAdapter {
|
||||
"_updateSelectedFilesTitle": [Function],
|
||||
"container": [Circular],
|
||||
"formError": "",
|
||||
"formErrorDetail": "",
|
||||
"isExecuting": false,
|
||||
"isOpened": false,
|
||||
"parameters": [Function],
|
||||
"reset": [Function],
|
||||
"selectedFiles": undefined,
|
||||
"selectedFilesTitle": "",
|
||||
"updateSelectedFiles": [Function],
|
||||
"uploadFileData": Array [],
|
||||
},
|
||||
}
|
||||
}
|
||||
formError=""
|
||||
@ -1548,23 +1500,6 @@ exports[`Settings Pane should render Gremlin properly 1`] = `
|
||||
"userTableQuery": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
UploadItemsPane {
|
||||
"container": [Circular],
|
||||
"fileUploadSummaryText": [Function],
|
||||
"files": [Function],
|
||||
"firstFieldHasFocus": [Function],
|
||||
"formErrors": [Function],
|
||||
"formErrorsDetails": [Function],
|
||||
"id": "uploaditemspane",
|
||||
"isExecuting": [Function],
|
||||
"isTemplateReady": [Function],
|
||||
"onImportLinkKeyPress": [Function],
|
||||
"selectedFilesTitle": [Function],
|
||||
"title": [Function],
|
||||
"uploadFileData": [Function],
|
||||
"uploadFileDataVisible": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
LoadQueryPane {
|
||||
"container": [Circular],
|
||||
"files": [Function],
|
||||
@ -2236,37 +2171,6 @@ exports[`Settings Pane should render Gremlin properly 1`] = `
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
"uploadItemsPane": UploadItemsPane {
|
||||
"container": [Circular],
|
||||
"fileUploadSummaryText": [Function],
|
||||
"files": [Function],
|
||||
"firstFieldHasFocus": [Function],
|
||||
"formErrors": [Function],
|
||||
"formErrorsDetails": [Function],
|
||||
"id": "uploaditemspane",
|
||||
"isExecuting": [Function],
|
||||
"isTemplateReady": [Function],
|
||||
"onImportLinkKeyPress": [Function],
|
||||
"selectedFilesTitle": [Function],
|
||||
"title": [Function],
|
||||
"uploadFileData": [Function],
|
||||
"uploadFileDataVisible": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
"uploadItemsPaneAdapter": UploadItemsPaneAdapter {
|
||||
"_updateSelectedFilesTitle": [Function],
|
||||
"container": [Circular],
|
||||
"formError": "",
|
||||
"formErrorDetail": "",
|
||||
"isExecuting": false,
|
||||
"isOpened": false,
|
||||
"parameters": [Function],
|
||||
"reset": [Function],
|
||||
"selectedFiles": undefined,
|
||||
"selectedFilesTitle": "",
|
||||
"updateSelectedFiles": [Function],
|
||||
"uploadFileData": Array [],
|
||||
},
|
||||
}
|
||||
}
|
||||
formError=""
|
||||
|
@ -1,130 +0,0 @@
|
||||
<div data-bind="visible: visible, event: { keydown: onPaneKeyDown }">
|
||||
<div
|
||||
class="contextual-pane-out"
|
||||
data-bind="
|
||||
click: cancel,
|
||||
clickBubble: false"
|
||||
></div>
|
||||
<div class="contextual-pane" id="uploaditemspane">
|
||||
<!-- Upload items form -- Start -->
|
||||
<div class="contextual-pane-in">
|
||||
<form class="paneContentContainer" data-bind="submit: submit">
|
||||
<!-- Upload items header - Start -->
|
||||
<div class="firstdivbg headerline">
|
||||
<span role="heading" aria-level="2" data-bind="text: title"></span>
|
||||
<div
|
||||
class="closeImg"
|
||||
role="button"
|
||||
aria-label="Close pane"
|
||||
tabindex="0"
|
||||
data-bind="
|
||||
click: cancel, event: { keydown: onCloseKeyPress }"
|
||||
>
|
||||
<img src="../../../images/close-black.svg" title="Close" alt="Close" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- Upload items header - End -->
|
||||
|
||||
<!-- Upload items errors - Start -->
|
||||
<div
|
||||
class="warningErrorContainer"
|
||||
aria-live="assertive"
|
||||
data-bind="visible: formErrors() && formErrors() !== ''"
|
||||
>
|
||||
<div class="warningErrorContent">
|
||||
<span><img class="paneErrorIcon" src="/error_red.svg" alt="Error" /></span>
|
||||
<span class="warningErrorDetailsLinkContainer">
|
||||
<span class="formErrors" data-bind="text: formErrors, attr: { title: formErrors }"></span>
|
||||
<a
|
||||
class="errorLink"
|
||||
role="link"
|
||||
data-bind="
|
||||
visible: formErrorsDetails() && formErrorsDetails() !== '',
|
||||
click: showErrorDetails"
|
||||
>More details</a
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Upload items errors - End -->
|
||||
|
||||
<!-- Upload item inputs - Start -->
|
||||
<div class="paneMainContent">
|
||||
<div>
|
||||
<div class="renewUploadItemsHeader">
|
||||
<span> Select JSON Files </span>
|
||||
<span class="infoTooltip" role="tooltip" tabindex="0">
|
||||
<img class="infoImg" src="/info-bubble.svg" alt="More information" />
|
||||
<span class="tooltiptext infoTooltipWidth"
|
||||
>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.</span
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
<input
|
||||
class="importFilesTitle"
|
||||
type="text"
|
||||
disabled
|
||||
data-bind="value: selectedFilesTitle"
|
||||
aria-label="Select JSON Files"
|
||||
/>
|
||||
<input
|
||||
type="file"
|
||||
id="importDocsInput"
|
||||
title="Upload Icon"
|
||||
multiple
|
||||
accept="application/json"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
style="display: none"
|
||||
data-bind="event: { change: updateSelectedFiles }"
|
||||
/>
|
||||
<a
|
||||
href="#"
|
||||
id="fileImportLink"
|
||||
data-bind="event: { click: onImportLinkClick, keypress: onImportLinkKeyPress }"
|
||||
autofocus
|
||||
>
|
||||
<img
|
||||
class="fileImportImg"
|
||||
src="/folder_16x16.svg"
|
||||
alt="Select JSON files to upload"
|
||||
title="Select JSON files to upload"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<div class="fileUploadSummaryContainer" data-bind="visible: uploadFileDataVisible">
|
||||
<b>File upload status</b>
|
||||
<table class="fileUploadSummary">
|
||||
<thead>
|
||||
<tr class="fileUploadSummaryHeader fileUploadSummaryTuple">
|
||||
<th>FILE NAME</th>
|
||||
<th>STATUS</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- ko foreach: uploadFileData -->
|
||||
<tr class="fileUploadSummaryTuple">
|
||||
<td data-bind="text: $data.fileName"></td>
|
||||
<td data-bind="text: $parent.fileUploadSummaryText($data.numSucceeded, $data.numFailed)"></td>
|
||||
</tr>
|
||||
<!-- /ko -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paneFooter">
|
||||
<div class="leftpanel-okbut"><input type="submit" value="Upload" class="btncreatecoll1" /></div>
|
||||
</div>
|
||||
<!-- Upload item inputs - End -->
|
||||
</form>
|
||||
</div>
|
||||
<!-- Upload items form - Start -->
|
||||
<!-- Loader - Start -->
|
||||
<div class="dataExplorerLoaderContainer dataExplorerPaneLoaderContainer" data-bind="visible: isExecuting">
|
||||
<img class="dataExplorerLoader" src="/LoadingIndicator_3Squares.gif" />
|
||||
</div>
|
||||
<!-- Loader - End -->
|
||||
</div>
|
||||
</div>
|
@ -1,143 +0,0 @@
|
||||
import * as ko from "knockout";
|
||||
import * as Constants from "../../Common/Constants";
|
||||
import * as ViewModels from "../../Contracts/ViewModels";
|
||||
import { ContextualPaneBase } from "./ContextualPaneBase";
|
||||
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
|
||||
import * as NotificationConsoleUtils from "../../Utils/NotificationConsoleUtils";
|
||||
import { UploadDetailsRecord, UploadDetails } from "../../workers/upload/definitions";
|
||||
import { getErrorMessage } from "../../Common/ErrorHandlingUtils";
|
||||
|
||||
const UPLOAD_FILE_SIZE_LIMIT = 2097152;
|
||||
|
||||
export class UploadItemsPane extends ContextualPaneBase {
|
||||
public selectedFilesTitle: ko.Observable<string>;
|
||||
public files: ko.Observable<FileList>;
|
||||
public uploadFileDataVisible: ko.Computed<boolean>;
|
||||
public uploadFileData: ko.ObservableArray<UploadDetailsRecord>;
|
||||
|
||||
constructor(options: ViewModels.PaneOptions) {
|
||||
super(options);
|
||||
this._initTitle();
|
||||
this.resetData();
|
||||
|
||||
this.selectedFilesTitle = ko.observable<string>("");
|
||||
this.uploadFileData = ko.observableArray<UploadDetailsRecord>();
|
||||
this.uploadFileDataVisible = ko.computed<boolean>(
|
||||
() => !!this.uploadFileData() && this.uploadFileData().length > 0
|
||||
);
|
||||
this.files = ko.observable<FileList>();
|
||||
this.files.subscribe((newFiles: FileList) => this._updateSelectedFilesTitle(newFiles));
|
||||
}
|
||||
|
||||
public submit() {
|
||||
this.formErrors("");
|
||||
if (!this.files() || this.files().length === 0) {
|
||||
this.formErrors("No files specified");
|
||||
this.formErrorsDetails("No files were specified. Please input at least one file.");
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
"Could not upload items -- No files were specified. Please input at least one file."
|
||||
);
|
||||
return;
|
||||
} else if (this._totalFileSizeForFileList(this.files()) > UPLOAD_FILE_SIZE_LIMIT) {
|
||||
this.formErrors("Upload file size limit exceeded");
|
||||
this.formErrorsDetails("Total file upload size exceeds the 2 MB file size limit.");
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
"Could not upload items -- Total file upload size exceeds the 2 MB file size limit."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedCollection: ViewModels.Collection = this.container.findSelectedCollection();
|
||||
this.isExecuting(true);
|
||||
selectedCollection &&
|
||||
selectedCollection
|
||||
.uploadFiles(this.files())
|
||||
.then(
|
||||
(uploadDetails: UploadDetails) => {
|
||||
this.uploadFileData(uploadDetails.data);
|
||||
this.files(undefined);
|
||||
this._resetFileInput();
|
||||
},
|
||||
(error: any) => {
|
||||
const errorMessage = getErrorMessage(error);
|
||||
this.formErrors(errorMessage);
|
||||
this.formErrorsDetails(errorMessage);
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
this.isExecuting(false);
|
||||
});
|
||||
}
|
||||
|
||||
public updateSelectedFiles(element: any, event: any): void {
|
||||
this.files(event.target.files);
|
||||
}
|
||||
|
||||
public close() {
|
||||
super.close();
|
||||
this.resetData();
|
||||
this.files(undefined);
|
||||
this.uploadFileData([]);
|
||||
this._resetFileInput();
|
||||
}
|
||||
|
||||
public onImportLinkClick(source: any, event: MouseEvent): boolean {
|
||||
document.getElementById("importDocsInput").click();
|
||||
return false;
|
||||
}
|
||||
|
||||
public onImportLinkKeyPress = (source: any, event: KeyboardEvent): boolean => {
|
||||
if (event.keyCode === Constants.KeyCodes.Enter || event.keyCode === Constants.KeyCodes.Space) {
|
||||
this.onImportLinkClick(source, null);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
public fileUploadSummaryText = (numSucceeded: number, numFailed: number): string => {
|
||||
return `${numSucceeded} items created, ${numFailed} errors`;
|
||||
};
|
||||
|
||||
private _totalFileSizeForFileList(fileList: FileList): number {
|
||||
let totalFileSize: number = 0;
|
||||
if (!fileList) {
|
||||
return totalFileSize;
|
||||
}
|
||||
for (let i = 0; i < fileList.length; i++) {
|
||||
totalFileSize = totalFileSize + fileList.item(i).size;
|
||||
}
|
||||
|
||||
return totalFileSize;
|
||||
}
|
||||
|
||||
private _updateSelectedFilesTitle(fileList: FileList) {
|
||||
this.selectedFilesTitle("");
|
||||
|
||||
if (!fileList || fileList.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < fileList.length; i++) {
|
||||
const originalTitle = this.selectedFilesTitle();
|
||||
this.selectedFilesTitle(originalTitle + `"${fileList.item(i).name}"`);
|
||||
}
|
||||
}
|
||||
|
||||
private _initTitle(): void {
|
||||
if (this.container.isPreferredApiCassandra() || this.container.isPreferredApiTable()) {
|
||||
this.title("Upload Tables");
|
||||
} else if (this.container.isPreferredApiGraph()) {
|
||||
this.title("Upload Graph");
|
||||
} else {
|
||||
this.title("Upload Items");
|
||||
}
|
||||
}
|
||||
|
||||
private _resetFileInput(): void {
|
||||
const inputElement = $("#importDocsInput");
|
||||
inputElement.wrap("<form>").closest("form").get(0).reset();
|
||||
inputElement.unwrap();
|
||||
}
|
||||
}
|
1059
src/Explorer/Panes/UploadItemsPane/__snapshots__/index.test.tsx.snap
Normal file
1059
src/Explorer/Panes/UploadItemsPane/__snapshots__/index.test.tsx.snap
Normal file
File diff suppressed because it is too large
Load Diff
14
src/Explorer/Panes/UploadItemsPane/index.test.tsx
Normal file
14
src/Explorer/Panes/UploadItemsPane/index.test.tsx
Normal file
@ -0,0 +1,14 @@
|
||||
import { shallow } from "enzyme";
|
||||
import React from "react";
|
||||
import { UploadItemsPane } from ".";
|
||||
import Explorer from "../../Explorer";
|
||||
const props = {
|
||||
explorer: new Explorer(),
|
||||
closePanel: (): void => undefined,
|
||||
};
|
||||
describe("Upload Items Pane", () => {
|
||||
it("should render Default properly", () => {
|
||||
const wrapper = shallow(<UploadItemsPane {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
160
src/Explorer/Panes/UploadItemsPane/index.tsx
Normal file
160
src/Explorer/Panes/UploadItemsPane/index.tsx
Normal file
@ -0,0 +1,160 @@
|
||||
import { DetailsList, DetailsListLayoutMode, IColumn, SelectionMode } from "office-ui-fabric-react";
|
||||
import React, { ChangeEvent, FunctionComponent, useState } from "react";
|
||||
import { Upload } from "../../../Common/Upload";
|
||||
import { userContext } from "../../../UserContext";
|
||||
import { logConsoleError } from "../../../Utils/NotificationConsoleUtils";
|
||||
import { UploadDetails, UploadDetailsRecord } from "../../../workers/upload/definitions";
|
||||
import Explorer from "../../Explorer";
|
||||
import { getErrorMessage } from "../../Tables/Utilities";
|
||||
import { GenericRightPaneComponent, GenericRightPaneProps } from "../GenericRightPaneComponent";
|
||||
|
||||
const UPLOAD_FILE_SIZE_LIMIT_KB = 2097152;
|
||||
|
||||
export interface UploadItemsPaneProps {
|
||||
explorer: Explorer;
|
||||
closePanel: () => void;
|
||||
}
|
||||
|
||||
interface IUploadFileData {
|
||||
numSucceeded: number;
|
||||
numFailed: number;
|
||||
fileName: string;
|
||||
}
|
||||
|
||||
const getTitle = (): string => {
|
||||
if (userContext.apiType === "Cassandra" || userContext.apiType === "Tables") {
|
||||
return "Upload Tables";
|
||||
} else if (userContext.apiType === "Gremlin") {
|
||||
return "Upload Graph";
|
||||
} else {
|
||||
return "Upload Items";
|
||||
}
|
||||
};
|
||||
|
||||
export const UploadItemsPane: FunctionComponent<UploadItemsPaneProps> = ({
|
||||
explorer,
|
||||
closePanel,
|
||||
}: UploadItemsPaneProps) => {
|
||||
const [files, setFiles] = useState<FileList>();
|
||||
const [uploadFileData, setUploadFileData] = useState<UploadDetailsRecord[]>([]);
|
||||
const [formError, setFormError] = useState<string>("");
|
||||
const [formErrorDetail, setFormErrorDetail] = useState<string>("");
|
||||
const [isExecuting, setIsExecuting] = useState<boolean>();
|
||||
|
||||
const onSubmit = () => {
|
||||
setFormError("");
|
||||
if (!files || files.length === 0) {
|
||||
setFormError("No files specified");
|
||||
setFormErrorDetail("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.");
|
||||
} else if (_totalFileSizeForFileList(files) > UPLOAD_FILE_SIZE_LIMIT_KB) {
|
||||
setFormError("Upload file size limit exceeded");
|
||||
setFormErrorDetail("Total file upload size exceeds the 2 MB file size limit.");
|
||||
logConsoleError("Could not upload items -- Total file upload size exceeds the 2 MB file size limit.");
|
||||
}
|
||||
|
||||
const selectedCollection = explorer.findSelectedCollection();
|
||||
|
||||
setIsExecuting(true);
|
||||
|
||||
selectedCollection
|
||||
?.uploadFiles(files)
|
||||
.then(
|
||||
(uploadDetails: UploadDetails) => {
|
||||
setUploadFileData(uploadDetails.data);
|
||||
setFiles(undefined);
|
||||
},
|
||||
(error: Error) => {
|
||||
const errorMessage = getErrorMessage(error);
|
||||
setFormError(errorMessage);
|
||||
setFormErrorDetail(errorMessage);
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
setIsExecuting(false);
|
||||
});
|
||||
};
|
||||
|
||||
const updateSelectedFiles = (event: ChangeEvent<HTMLInputElement>): void => {
|
||||
setFiles(event.target.files);
|
||||
};
|
||||
|
||||
const _totalFileSizeForFileList = (fileList: FileList): number => {
|
||||
let totalFileSize = 0;
|
||||
for (let i = 0; i < fileList?.length; i++) {
|
||||
totalFileSize += fileList.item(i).size;
|
||||
}
|
||||
return totalFileSize;
|
||||
};
|
||||
|
||||
const genericPaneProps: GenericRightPaneProps = {
|
||||
container: explorer,
|
||||
formError,
|
||||
formErrorDetail,
|
||||
id: "uploaditemspane",
|
||||
isExecuting: isExecuting,
|
||||
title: getTitle(),
|
||||
submitButtonText: "Upload",
|
||||
onClose: closePanel,
|
||||
onSubmit,
|
||||
};
|
||||
const columns: IColumn[] = [
|
||||
{
|
||||
key: "fileName",
|
||||
name: "FILE NAME",
|
||||
fieldName: "fileName",
|
||||
minWidth: 140,
|
||||
maxWidth: 140,
|
||||
},
|
||||
{
|
||||
key: "status",
|
||||
name: "STATUS",
|
||||
fieldName: "numSucceeded",
|
||||
minWidth: 140,
|
||||
maxWidth: 140,
|
||||
isRowHeader: true,
|
||||
isResizable: true,
|
||||
data: "string",
|
||||
isPadded: true,
|
||||
},
|
||||
];
|
||||
|
||||
const _renderItemColumn = (item: IUploadFileData, index: number, column: IColumn) => {
|
||||
switch (column.key) {
|
||||
case "status":
|
||||
return <span>{item.numSucceeded + " items created, " + item.numFailed + " errors"}</span>;
|
||||
default:
|
||||
return <span>{item.fileName}</span>;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<GenericRightPaneComponent {...genericPaneProps}>
|
||||
<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}
|
||||
onRenderItemColumn={_renderItemColumn}
|
||||
selectionMode={SelectionMode.none}
|
||||
layoutMode={DetailsListLayoutMode.justified}
|
||||
isHeaderVisible={true}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</GenericRightPaneComponent>
|
||||
);
|
||||
};
|
@ -1,161 +0,0 @@
|
||||
import * as ko from "knockout";
|
||||
import * as NotificationConsoleUtils from "../../Utils/NotificationConsoleUtils";
|
||||
import * as React from "react";
|
||||
import * as ViewModels from "../../Contracts/ViewModels";
|
||||
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
|
||||
import { GenericRightPaneComponent, GenericRightPaneProps } from "./GenericRightPaneComponent";
|
||||
import { ReactAdapter } from "../../Bindings/ReactBindingHandler";
|
||||
import { UploadDetailsRecord, UploadDetails } from "../../workers/upload/definitions";
|
||||
import { UploadItemsPaneComponent, UploadItemsPaneProps } from "./UploadItemsPaneComponent";
|
||||
import Explorer from "../Explorer";
|
||||
import { getErrorMessage } from "../../Common/ErrorHandlingUtils";
|
||||
|
||||
const UPLOAD_FILE_SIZE_LIMIT = 2097152;
|
||||
|
||||
export class UploadItemsPaneAdapter implements ReactAdapter {
|
||||
public parameters: ko.Observable<number>;
|
||||
private isOpened: boolean;
|
||||
private isExecuting: boolean;
|
||||
private formError: string;
|
||||
private formErrorDetail: string;
|
||||
private selectedFiles: FileList;
|
||||
private selectedFilesTitle: string;
|
||||
private uploadFileData: UploadDetailsRecord[];
|
||||
|
||||
public constructor(private container: Explorer) {
|
||||
this.parameters = ko.observable(Date.now());
|
||||
this.reset();
|
||||
this.triggerRender();
|
||||
}
|
||||
|
||||
public renderComponent(): JSX.Element {
|
||||
if (!this.isOpened) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const genericPaneProps: GenericRightPaneProps = {
|
||||
container: this.container,
|
||||
formError: this.formError,
|
||||
formErrorDetail: this.formErrorDetail,
|
||||
id: "uploaditemspane",
|
||||
isExecuting: this.isExecuting,
|
||||
title: "Upload Items",
|
||||
submitButtonText: "Upload",
|
||||
onClose: () => this.close(),
|
||||
onSubmit: () => this.submit(),
|
||||
};
|
||||
|
||||
const uploadItemsPaneProps: UploadItemsPaneProps = {
|
||||
selectedFilesTitle: this.selectedFilesTitle,
|
||||
updateSelectedFiles: this.updateSelectedFiles,
|
||||
uploadFileData: this.uploadFileData,
|
||||
};
|
||||
|
||||
return (
|
||||
<GenericRightPaneComponent {...genericPaneProps}>
|
||||
<UploadItemsPaneComponent {...uploadItemsPaneProps} />
|
||||
</GenericRightPaneComponent>
|
||||
);
|
||||
}
|
||||
|
||||
public triggerRender(): void {
|
||||
window.requestAnimationFrame(() => this.parameters(Date.now()));
|
||||
}
|
||||
|
||||
public open(): void {
|
||||
this.isOpened = true;
|
||||
this.triggerRender();
|
||||
}
|
||||
|
||||
public close(): void {
|
||||
this.reset();
|
||||
this.triggerRender();
|
||||
}
|
||||
|
||||
public submit(): void {
|
||||
this.formError = "";
|
||||
if (!this.selectedFiles || this.selectedFiles.length === 0) {
|
||||
this.formError = "No files specified";
|
||||
this.formErrorDetail = "No files were specified. Please input at least one file.";
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
"Could not upload items -- No files were specified. Please input at least one file."
|
||||
);
|
||||
this.triggerRender();
|
||||
return;
|
||||
} else if (this._totalFileSizeForFileList() > UPLOAD_FILE_SIZE_LIMIT) {
|
||||
this.formError = "Upload file size limit exceeded";
|
||||
this.formErrorDetail = "Total file upload size exceeds the 2 MB file size limit.";
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
"Could not upload items -- Total file upload size exceeds the 2 MB file size limit."
|
||||
);
|
||||
this.triggerRender();
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedCollection: ViewModels.Collection = this.container.findSelectedCollection();
|
||||
this.isExecuting = true;
|
||||
this.triggerRender();
|
||||
selectedCollection &&
|
||||
selectedCollection
|
||||
.uploadFiles(this.selectedFiles)
|
||||
.then(
|
||||
(uploadDetails: UploadDetails) => {
|
||||
this.uploadFileData = uploadDetails.data;
|
||||
this.selectedFiles = undefined;
|
||||
this.selectedFilesTitle = "";
|
||||
},
|
||||
(error) => {
|
||||
const errorMessage = getErrorMessage(error);
|
||||
this.formError = errorMessage;
|
||||
this.formErrorDetail = errorMessage;
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
this.triggerRender();
|
||||
this.isExecuting = false;
|
||||
});
|
||||
}
|
||||
|
||||
private updateSelectedFiles = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
this.selectedFiles = event.target.files;
|
||||
this._updateSelectedFilesTitle();
|
||||
this.triggerRender();
|
||||
};
|
||||
|
||||
private _updateSelectedFilesTitle = (): void => {
|
||||
this.selectedFilesTitle = "";
|
||||
|
||||
if (!this.selectedFiles || this.selectedFiles.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.selectedFiles.length; i++) {
|
||||
this.selectedFilesTitle += `"${this.selectedFiles.item(i).name}"`;
|
||||
}
|
||||
};
|
||||
|
||||
private _totalFileSizeForFileList(): number {
|
||||
let totalFileSize = 0;
|
||||
if (!this.selectedFiles) {
|
||||
return totalFileSize;
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.selectedFiles.length; i++) {
|
||||
totalFileSize += this.selectedFiles.item(i).size;
|
||||
}
|
||||
|
||||
return totalFileSize;
|
||||
}
|
||||
|
||||
private reset = (): void => {
|
||||
this.isOpened = false;
|
||||
this.isExecuting = false;
|
||||
this.formError = "";
|
||||
this.formErrorDetail = "";
|
||||
this.selectedFiles = undefined;
|
||||
this.selectedFilesTitle = "";
|
||||
this.uploadFileData = [];
|
||||
};
|
||||
}
|
@ -1,97 +0,0 @@
|
||||
import * as Constants from "../../Common/Constants";
|
||||
import * as React from "react";
|
||||
import { IconButton } from "office-ui-fabric-react/lib/Button";
|
||||
import { UploadDetailsRecord } from "../../workers/upload/definitions";
|
||||
import InfoBubbleIcon from "../../../images/info-bubble.svg";
|
||||
|
||||
export interface UploadItemsPaneProps {
|
||||
selectedFilesTitle: string;
|
||||
updateSelectedFiles: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
uploadFileData: UploadDetailsRecord[];
|
||||
}
|
||||
|
||||
export class UploadItemsPaneComponent extends React.Component<UploadItemsPaneProps> {
|
||||
public render(): JSX.Element {
|
||||
return (
|
||||
<div className="panelContent">
|
||||
<div className="paneMainContent">
|
||||
<div className="renewUploadItemsHeader">
|
||||
<span> Select JSON Files </span>
|
||||
<span className="infoTooltip" role="tooltip" tabIndex={0}>
|
||||
<img className="infoImg" src={InfoBubbleIcon} alt="More information" />
|
||||
<span className="tooltiptext infoTooltipWidth">
|
||||
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.
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<input
|
||||
className="importFilesTitle"
|
||||
type="text"
|
||||
disabled
|
||||
value={this.props.selectedFilesTitle}
|
||||
aria-label="Select JSON Files"
|
||||
/>
|
||||
<input
|
||||
type="file"
|
||||
id="importDocsInput"
|
||||
title="Upload Icon"
|
||||
multiple
|
||||
accept="application/json"
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
style={{ display: "none" }}
|
||||
onChange={this.props.updateSelectedFiles}
|
||||
/>
|
||||
<IconButton
|
||||
iconProps={{ iconName: "FolderHorizontal" }}
|
||||
className="fileImportButton"
|
||||
alt="Select JSON files to upload"
|
||||
title="Select JSON files to upload"
|
||||
onClick={this.onImportButtonClick}
|
||||
onKeyPress={this.onImportButtonKeyPress}
|
||||
/>
|
||||
<div className="fileUploadSummaryContainer" hidden={this.props.uploadFileData.length === 0}>
|
||||
<b>File upload status</b>
|
||||
<table className="fileUploadSummary">
|
||||
<thead>
|
||||
<tr className="fileUploadSummaryHeader fileUploadSummaryTuple">
|
||||
<th>FILE NAME</th>
|
||||
<th>STATUS</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{this.props.uploadFileData.map(
|
||||
(data: UploadDetailsRecord): JSX.Element => {
|
||||
return (
|
||||
<tr className="fileUploadSummaryTuple" key={data.fileName}>
|
||||
<td>{data.fileName}</td>
|
||||
<td>{this.fileUploadSummaryText(data.numSucceeded, data.numFailed)}</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private fileUploadSummaryText = (numSucceeded: number, numFailed: number): string => {
|
||||
return `${numSucceeded} items created, ${numFailed} errors`;
|
||||
};
|
||||
|
||||
private onImportButtonClick = (): void => {
|
||||
document.getElementById("importDocsInput").click();
|
||||
};
|
||||
|
||||
private onImportButtonKeyPress = (event: React.KeyboardEvent<HTMLButtonElement>): void => {
|
||||
if (event.charCode === Constants.KeyCodes.Enter || event.charCode === Constants.KeyCodes.Space) {
|
||||
this.onImportButtonClick();
|
||||
event.stopPropagation();
|
||||
}
|
||||
};
|
||||
}
|
@ -1,43 +1,35 @@
|
||||
import { extractPartitionKey, ItemDefinition, PartitionKeyDefinition, QueryIterator, Resource } from "@azure/cosmos";
|
||||
import * as ko from "knockout";
|
||||
import Q from "q";
|
||||
import DeleteDocumentIcon from "../../../images/DeleteDocument.svg";
|
||||
import DiscardIcon from "../../../images/discard.svg";
|
||||
import NewDocumentIcon from "../../../images/NewDocument.svg";
|
||||
import SaveIcon from "../../../images/save-cosmos.svg";
|
||||
import UploadIcon from "../../../images/Upload_16x16.svg";
|
||||
import * as Constants from "../../Common/Constants";
|
||||
import { DocumentsGridMetrics, KeyCodes } from "../../Common/Constants";
|
||||
import { createDocument } from "../../Common/dataAccess/createDocument";
|
||||
import { deleteDocument } from "../../Common/dataAccess/deleteDocument";
|
||||
import { queryDocuments } from "../../Common/dataAccess/queryDocuments";
|
||||
import { readDocument } from "../../Common/dataAccess/readDocument";
|
||||
import { updateDocument } from "../../Common/dataAccess/updateDocument";
|
||||
import editable from "../../Common/EditableUtility";
|
||||
import { getErrorMessage, getErrorStack } from "../../Common/ErrorHandlingUtils";
|
||||
import * as HeadersUtility from "../../Common/HeadersUtility";
|
||||
import { Splitter, SplitterBounds, SplitterDirection } from "../../Common/Splitter";
|
||||
import * as DataModels from "../../Contracts/DataModels";
|
||||
import * as ViewModels from "../../Contracts/ViewModels";
|
||||
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
|
||||
import { AccessibleVerticalList } from "../Tree/AccessibleVerticalList";
|
||||
import { KeyCodes } from "../../Common/Constants";
|
||||
import DocumentId from "../Tree/DocumentId";
|
||||
import editable from "../../Common/EditableUtility";
|
||||
import * as HeadersUtility from "../../Common/HeadersUtility";
|
||||
import TabsBase from "./TabsBase";
|
||||
import { DocumentsGridMetrics } from "../../Common/Constants";
|
||||
import * as QueryUtils from "../../Utils/QueryUtils";
|
||||
import { Splitter, SplitterBounds, SplitterDirection } from "../../Common/Splitter";
|
||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||
import NewDocumentIcon from "../../../images/NewDocument.svg";
|
||||
import SaveIcon from "../../../images/save-cosmos.svg";
|
||||
import DiscardIcon from "../../../images/discard.svg";
|
||||
import DeleteDocumentIcon from "../../../images/DeleteDocument.svg";
|
||||
import UploadIcon from "../../../images/Upload_16x16.svg";
|
||||
import {
|
||||
extractPartitionKey,
|
||||
PartitionKeyDefinition,
|
||||
QueryIterator,
|
||||
ItemDefinition,
|
||||
Resource,
|
||||
Item,
|
||||
} from "@azure/cosmos";
|
||||
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
|
||||
import * as NotificationConsoleUtils from "../../Utils/NotificationConsoleUtils";
|
||||
import Explorer from "../Explorer";
|
||||
import * as QueryUtils from "../../Utils/QueryUtils";
|
||||
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
|
||||
import { getErrorMessage, getErrorStack } from "../../Common/ErrorHandlingUtils";
|
||||
import { queryDocuments } from "../../Common/dataAccess/queryDocuments";
|
||||
import { readDocument } from "../../Common/dataAccess/readDocument";
|
||||
import { deleteDocument } from "../../Common/dataAccess/deleteDocument";
|
||||
import { updateDocument } from "../../Common/dataAccess/updateDocument";
|
||||
import { createDocument } from "../../Common/dataAccess/createDocument";
|
||||
import Explorer from "../Explorer";
|
||||
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
|
||||
import { AccessibleVerticalList } from "../Tree/AccessibleVerticalList";
|
||||
import DocumentId from "../Tree/DocumentId";
|
||||
import template from "./DocumentsTab.html";
|
||||
import TabsBase from "./TabsBase";
|
||||
|
||||
export default class DocumentsTab extends TabsBase {
|
||||
public static readonly component = { name: "documents-tab", template };
|
||||
@ -922,12 +914,7 @@ export default class DocumentsTab extends TabsBase {
|
||||
iconAlt: label,
|
||||
onCommandClick: () => {
|
||||
const selectedCollection: ViewModels.Collection = container.findSelectedCollection();
|
||||
const focusElement = document.getElementById("itemImportLink");
|
||||
const uploadItemsPane = container.isRightPanelV2Enabled()
|
||||
? container.uploadItemsPaneAdapter
|
||||
: container.uploadItemsPane;
|
||||
selectedCollection && uploadItemsPane.open();
|
||||
focusElement && focusElement.focus();
|
||||
selectedCollection && container.openUploadItemsPanePane();
|
||||
},
|
||||
commandButtonLabel: label,
|
||||
ariaLabel: label,
|
||||
|
@ -229,7 +229,6 @@ const App: React.FunctionComponent = () => {
|
||||
closePanel={closeSidePanel}
|
||||
isConsoleExpanded={isNotificationConsoleExpanded}
|
||||
/>
|
||||
<div data-bind="react:uploadItemsPaneAdapter" />
|
||||
<div data-bind='component: { name: "add-database-pane", params: {data: addDatabasePane} }' />
|
||||
<div data-bind='component: { name: "add-collection-pane", params: { data: addCollectionPane} }' />
|
||||
<div data-bind='component: { name: "delete-collection-confirmation-pane", params: { data: deleteCollectionConfirmationPane} }' />
|
||||
@ -241,7 +240,6 @@ const App: React.FunctionComponent = () => {
|
||||
<div data-bind='component: { name: "table-column-options-pane", params: { data: tableColumnOptionsPane} }' />
|
||||
<div data-bind='component: { name: "table-query-select-pane", params: { data: querySelectPane} }' />
|
||||
<div data-bind='component: { name: "cassandra-add-collection-pane", params: { data: cassandraAddCollectionPane} }' />
|
||||
<div data-bind='component: { name: "upload-items-pane", params: { data: uploadItemsPane} }' />
|
||||
<div data-bind='component: { name: "load-query-pane", params: { data: loadQueryPane} }' />
|
||||
<div data-bind='component: { name: "save-query-pane", params: { data: saveQueryPane} }' />
|
||||
<div data-bind='component: { name: "browse-queries-pane", params: { data: browseQueriesPane} }' />
|
||||
|
Loading…
Reference in New Issue
Block a user