mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2024-11-25 15:06:55 +00:00
Migrate Notebook Upload File to React (#581)
Co-authored-by: Steve Faulkner <471400+southpolesteve@users.noreply.github.com>
This commit is contained in:
parent
c68e84a4b9
commit
5307f6bb5b
@ -144,7 +144,6 @@ src/Explorer/Panes/Tables/TableEntityPane.ts
|
||||
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/SplashScreen/SplashScreen.test.ts
|
||||
src/Explorer/Tables/Constants.ts
|
||||
src/Explorer/Tables/DataTable/CacheBase.ts
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 82 KiB |
Binary file not shown.
After Width: | Height: | Size: 87 KiB |
26487
package-lock.json
generated
26487
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -97,10 +97,6 @@ describe("Component Registerer", () => {
|
||||
expect(ko.components.isRegistered("graph-styling-pane")).toBe(true);
|
||||
});
|
||||
|
||||
it("should register upload-file-pane component", () => {
|
||||
expect(ko.components.isRegistered("upload-file-pane")).toBe(true);
|
||||
});
|
||||
|
||||
it("should register string-input-pane component", () => {
|
||||
expect(ko.components.isRegistered("string-input-pane")).toBe(true);
|
||||
});
|
||||
|
@ -78,7 +78,6 @@ ko.components.register("cassandra-add-collection-pane", new PaneComponents.Cassa
|
||||
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());
|
||||
ko.components.register("upload-file-pane", new PaneComponents.UploadFilePaneComponent());
|
||||
ko.components.register("string-input-pane", new PaneComponents.StringInputPaneComponent());
|
||||
ko.components.register("setup-notebooks-pane", new PaneComponents.SetupNotebooksPaneComponent());
|
||||
ko.components.register("github-repos-pane", new PaneComponents.GitHubReposPaneComponent());
|
||||
|
@ -434,23 +434,6 @@ exports[`SettingsComponent renders 1`] = `
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
UploadFilePane {
|
||||
"container": [Circular],
|
||||
"extensions": [Function],
|
||||
"files": [Function],
|
||||
"firstFieldHasFocus": [Function],
|
||||
"formErrors": [Function],
|
||||
"formErrorsDetails": [Function],
|
||||
"id": "uploadfilepane",
|
||||
"isExecuting": [Function],
|
||||
"isTemplateReady": [Function],
|
||||
"onImportLinkKeyPress": [Function],
|
||||
"selectFileInputLabel": [Function],
|
||||
"selectedFilesTitle": [Function],
|
||||
"submitButtonLabel": [Function],
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
StringInputPane {
|
||||
"container": [Circular],
|
||||
"firstFieldHasFocus": [Function],
|
||||
@ -1040,23 +1023,6 @@ exports[`SettingsComponent renders 1`] = `
|
||||
"openedTabs": [Function],
|
||||
},
|
||||
"toggleLeftPaneExpandedKeyPress": [Function],
|
||||
"uploadFilePane": UploadFilePane {
|
||||
"container": [Circular],
|
||||
"extensions": [Function],
|
||||
"files": [Function],
|
||||
"firstFieldHasFocus": [Function],
|
||||
"formErrors": [Function],
|
||||
"formErrorsDetails": [Function],
|
||||
"id": "uploadfilepane",
|
||||
"isExecuting": [Function],
|
||||
"isTemplateReady": [Function],
|
||||
"onImportLinkKeyPress": [Function],
|
||||
"selectFileInputLabel": [Function],
|
||||
"selectedFilesTitle": [Function],
|
||||
"submitButtonLabel": [Function],
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
},
|
||||
"databaseId": "test",
|
||||
"defaultTtl": [Function],
|
||||
@ -1484,23 +1450,6 @@ exports[`SettingsComponent renders 1`] = `
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
UploadFilePane {
|
||||
"container": [Circular],
|
||||
"extensions": [Function],
|
||||
"files": [Function],
|
||||
"firstFieldHasFocus": [Function],
|
||||
"formErrors": [Function],
|
||||
"formErrorsDetails": [Function],
|
||||
"id": "uploadfilepane",
|
||||
"isExecuting": [Function],
|
||||
"isTemplateReady": [Function],
|
||||
"onImportLinkKeyPress": [Function],
|
||||
"selectFileInputLabel": [Function],
|
||||
"selectedFilesTitle": [Function],
|
||||
"submitButtonLabel": [Function],
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
StringInputPane {
|
||||
"container": [Circular],
|
||||
"firstFieldHasFocus": [Function],
|
||||
@ -2090,23 +2039,6 @@ exports[`SettingsComponent renders 1`] = `
|
||||
"openedTabs": [Function],
|
||||
},
|
||||
"toggleLeftPaneExpandedKeyPress": [Function],
|
||||
"uploadFilePane": UploadFilePane {
|
||||
"container": [Circular],
|
||||
"extensions": [Function],
|
||||
"files": [Function],
|
||||
"firstFieldHasFocus": [Function],
|
||||
"formErrors": [Function],
|
||||
"formErrorsDetails": [Function],
|
||||
"id": "uploadfilepane",
|
||||
"isExecuting": [Function],
|
||||
"isTemplateReady": [Function],
|
||||
"onImportLinkKeyPress": [Function],
|
||||
"selectFileInputLabel": [Function],
|
||||
"selectedFilesTitle": [Function],
|
||||
"submitButtonLabel": [Function],
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
}
|
||||
}
|
||||
isAutoPilotSelected={false}
|
||||
@ -2547,23 +2479,6 @@ exports[`SettingsComponent renders 1`] = `
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
UploadFilePane {
|
||||
"container": [Circular],
|
||||
"extensions": [Function],
|
||||
"files": [Function],
|
||||
"firstFieldHasFocus": [Function],
|
||||
"formErrors": [Function],
|
||||
"formErrorsDetails": [Function],
|
||||
"id": "uploadfilepane",
|
||||
"isExecuting": [Function],
|
||||
"isTemplateReady": [Function],
|
||||
"onImportLinkKeyPress": [Function],
|
||||
"selectFileInputLabel": [Function],
|
||||
"selectedFilesTitle": [Function],
|
||||
"submitButtonLabel": [Function],
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
StringInputPane {
|
||||
"container": [Circular],
|
||||
"firstFieldHasFocus": [Function],
|
||||
@ -3153,23 +3068,6 @@ exports[`SettingsComponent renders 1`] = `
|
||||
"openedTabs": [Function],
|
||||
},
|
||||
"toggleLeftPaneExpandedKeyPress": [Function],
|
||||
"uploadFilePane": UploadFilePane {
|
||||
"container": [Circular],
|
||||
"extensions": [Function],
|
||||
"files": [Function],
|
||||
"firstFieldHasFocus": [Function],
|
||||
"formErrors": [Function],
|
||||
"formErrorsDetails": [Function],
|
||||
"id": "uploadfilepane",
|
||||
"isExecuting": [Function],
|
||||
"isTemplateReady": [Function],
|
||||
"onImportLinkKeyPress": [Function],
|
||||
"selectFileInputLabel": [Function],
|
||||
"selectedFilesTitle": [Function],
|
||||
"submitButtonLabel": [Function],
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
},
|
||||
"databaseId": "test",
|
||||
"defaultTtl": [Function],
|
||||
@ -3597,23 +3495,6 @@ exports[`SettingsComponent renders 1`] = `
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
UploadFilePane {
|
||||
"container": [Circular],
|
||||
"extensions": [Function],
|
||||
"files": [Function],
|
||||
"firstFieldHasFocus": [Function],
|
||||
"formErrors": [Function],
|
||||
"formErrorsDetails": [Function],
|
||||
"id": "uploadfilepane",
|
||||
"isExecuting": [Function],
|
||||
"isTemplateReady": [Function],
|
||||
"onImportLinkKeyPress": [Function],
|
||||
"selectFileInputLabel": [Function],
|
||||
"selectedFilesTitle": [Function],
|
||||
"submitButtonLabel": [Function],
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
StringInputPane {
|
||||
"container": [Circular],
|
||||
"firstFieldHasFocus": [Function],
|
||||
@ -4203,23 +4084,6 @@ exports[`SettingsComponent renders 1`] = `
|
||||
"openedTabs": [Function],
|
||||
},
|
||||
"toggleLeftPaneExpandedKeyPress": [Function],
|
||||
"uploadFilePane": UploadFilePane {
|
||||
"container": [Circular],
|
||||
"extensions": [Function],
|
||||
"files": [Function],
|
||||
"firstFieldHasFocus": [Function],
|
||||
"formErrors": [Function],
|
||||
"formErrorsDetails": [Function],
|
||||
"id": "uploadfilepane",
|
||||
"isExecuting": [Function],
|
||||
"isTemplateReady": [Function],
|
||||
"onImportLinkKeyPress": [Function],
|
||||
"selectFileInputLabel": [Function],
|
||||
"selectedFilesTitle": [Function],
|
||||
"submitButtonLabel": [Function],
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
}
|
||||
}
|
||||
geospatialConfigType="Geometry"
|
||||
|
@ -215,7 +215,6 @@ export default class Explorer {
|
||||
public loadQueryPane: LoadQueryPane;
|
||||
public saveQueryPane: ContextualPaneBase;
|
||||
public browseQueriesPane: BrowseQueriesPane;
|
||||
public uploadFilePane: UploadFilePane;
|
||||
public stringInputPane: StringInputPane;
|
||||
public setupNotebooksPane: SetupNotebooksPane;
|
||||
public gitHubReposPane: ContextualPaneBase;
|
||||
@ -642,13 +641,6 @@ export default class Explorer {
|
||||
container: this,
|
||||
});
|
||||
|
||||
this.uploadFilePane = new UploadFilePane({
|
||||
id: "uploadfilepane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
|
||||
container: this,
|
||||
});
|
||||
|
||||
this.stringInputPane = new StringInputPane({
|
||||
id: "stringinputpane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
@ -680,7 +672,6 @@ export default class Explorer {
|
||||
this.loadQueryPane,
|
||||
this.saveQueryPane,
|
||||
this.browseQueriesPane,
|
||||
this.uploadFilePane,
|
||||
this.stringInputPane,
|
||||
this.setupNotebooksPane,
|
||||
];
|
||||
@ -2098,38 +2089,6 @@ export default class Explorer {
|
||||
.finally(() => NotificationConsoleUtils.clearInProgressMessageWithId(notificationProgressId));
|
||||
}
|
||||
|
||||
public onUploadToNotebookServerClicked(parent?: NotebookContentItem): void {
|
||||
parent = parent || this.resourceTree.myNotebooksContentRoot;
|
||||
|
||||
this.uploadFilePane.openWithOptions({
|
||||
paneTitle: "Upload file to notebook server",
|
||||
selectFileInputLabel: "Select file to upload",
|
||||
errorMessage: "Could not upload file",
|
||||
inProgressMessage: "Uploading file to notebook server",
|
||||
successMessage: "Successfully uploaded file to notebook server",
|
||||
onSubmit: async (file: File): Promise<NotebookContentItem> => {
|
||||
const readFileAsText = (inputFile: File): Promise<string> => {
|
||||
const reader = new FileReader();
|
||||
return new Promise((resolve, reject) => {
|
||||
reader.onerror = () => {
|
||||
reader.abort();
|
||||
reject(`Problem parsing file: ${inputFile}`);
|
||||
};
|
||||
reader.onload = () => {
|
||||
resolve(reader.result as string);
|
||||
};
|
||||
reader.readAsText(inputFile);
|
||||
});
|
||||
};
|
||||
|
||||
const fileContent = await readFileAsText(file);
|
||||
return this.uploadFile(file.name, fileContent, parent);
|
||||
},
|
||||
extensions: undefined,
|
||||
submitButtonLabel: "Upload",
|
||||
});
|
||||
}
|
||||
|
||||
public refreshContentItem(item: NotebookContentItem): Promise<void> {
|
||||
if (!this.isNotebookEnabled() || !this.notebookManager?.notebookContentClient) {
|
||||
const error = "Attempt to refresh notebook list, but notebook is not enabled";
|
||||
@ -2476,4 +2435,15 @@ export default class Explorer {
|
||||
/>
|
||||
);
|
||||
}
|
||||
public openUploadFilePanel(parent?: NotebookContentItem): void {
|
||||
parent = parent || this.resourceTree.myNotebooksContentRoot;
|
||||
this.openSidePanel(
|
||||
"Upload File",
|
||||
<UploadFilePane
|
||||
explorer={this}
|
||||
closePanel={this.closeSidePanel}
|
||||
uploadFile={(name: string, content: string) => this.uploadFile(name, content, parent)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -407,7 +407,7 @@ function createuploadNotebookButton(container: Explorer): CommandButtonComponent
|
||||
return {
|
||||
iconSrc: NewNotebookIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => container.onUploadToNotebookServerClicked(),
|
||||
onCommandClick: () => container.openUploadFilePanel(),
|
||||
commandButtonLabel: label,
|
||||
hasPopup: false,
|
||||
disabled: false,
|
||||
|
@ -15,7 +15,6 @@ import TableAddEntityPaneTemplate from "./Tables/TableAddEntityPane.html";
|
||||
import TableColumnOptionsPaneTemplate from "./Tables/TableColumnOptionsPane.html";
|
||||
import TableEditEntityPaneTemplate from "./Tables/TableEditEntityPane.html";
|
||||
import TableQuerySelectPaneTemplate from "./Tables/TableQuerySelectPane.html";
|
||||
import UploadFilePaneTemplate from "./UploadFilePane.html";
|
||||
|
||||
export class PaneComponent {
|
||||
constructor(data: any) {
|
||||
@ -149,15 +148,6 @@ export class BrowseQueriesPaneComponent {
|
||||
}
|
||||
}
|
||||
|
||||
export class UploadFilePaneComponent {
|
||||
constructor() {
|
||||
return {
|
||||
viewModel: PaneComponent,
|
||||
template: UploadFilePaneTemplate,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class StringInputPaneComponent {
|
||||
constructor() {
|
||||
return {
|
||||
|
@ -410,23 +410,6 @@ exports[`Settings Pane should render Default properly 1`] = `
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
UploadFilePane {
|
||||
"container": [Circular],
|
||||
"extensions": [Function],
|
||||
"files": [Function],
|
||||
"firstFieldHasFocus": [Function],
|
||||
"formErrors": [Function],
|
||||
"formErrorsDetails": [Function],
|
||||
"id": "uploadfilepane",
|
||||
"isExecuting": [Function],
|
||||
"isTemplateReady": [Function],
|
||||
"onImportLinkKeyPress": [Function],
|
||||
"selectFileInputLabel": [Function],
|
||||
"selectedFilesTitle": [Function],
|
||||
"submitButtonLabel": [Function],
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
StringInputPane {
|
||||
"container": [Circular],
|
||||
"firstFieldHasFocus": [Function],
|
||||
@ -1016,23 +999,6 @@ exports[`Settings Pane should render Default properly 1`] = `
|
||||
"openedTabs": [Function],
|
||||
},
|
||||
"toggleLeftPaneExpandedKeyPress": [Function],
|
||||
"uploadFilePane": UploadFilePane {
|
||||
"container": [Circular],
|
||||
"extensions": [Function],
|
||||
"files": [Function],
|
||||
"firstFieldHasFocus": [Function],
|
||||
"formErrors": [Function],
|
||||
"formErrorsDetails": [Function],
|
||||
"id": "uploadfilepane",
|
||||
"isExecuting": [Function],
|
||||
"isTemplateReady": [Function],
|
||||
"onImportLinkKeyPress": [Function],
|
||||
"selectFileInputLabel": [Function],
|
||||
"selectedFilesTitle": [Function],
|
||||
"submitButtonLabel": [Function],
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
}
|
||||
}
|
||||
formError=""
|
||||
@ -1548,23 +1514,6 @@ exports[`Settings Pane should render Gremlin properly 1`] = `
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
UploadFilePane {
|
||||
"container": [Circular],
|
||||
"extensions": [Function],
|
||||
"files": [Function],
|
||||
"firstFieldHasFocus": [Function],
|
||||
"formErrors": [Function],
|
||||
"formErrorsDetails": [Function],
|
||||
"id": "uploadfilepane",
|
||||
"isExecuting": [Function],
|
||||
"isTemplateReady": [Function],
|
||||
"onImportLinkKeyPress": [Function],
|
||||
"selectFileInputLabel": [Function],
|
||||
"selectedFilesTitle": [Function],
|
||||
"submitButtonLabel": [Function],
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
StringInputPane {
|
||||
"container": [Circular],
|
||||
"firstFieldHasFocus": [Function],
|
||||
@ -2154,23 +2103,6 @@ exports[`Settings Pane should render Gremlin properly 1`] = `
|
||||
"openedTabs": [Function],
|
||||
},
|
||||
"toggleLeftPaneExpandedKeyPress": [Function],
|
||||
"uploadFilePane": UploadFilePane {
|
||||
"container": [Circular],
|
||||
"extensions": [Function],
|
||||
"files": [Function],
|
||||
"firstFieldHasFocus": [Function],
|
||||
"formErrors": [Function],
|
||||
"formErrorsDetails": [Function],
|
||||
"id": "uploadfilepane",
|
||||
"isExecuting": [Function],
|
||||
"isTemplateReady": [Function],
|
||||
"onImportLinkKeyPress": [Function],
|
||||
"selectFileInputLabel": [Function],
|
||||
"selectedFilesTitle": [Function],
|
||||
"submitButtonLabel": [Function],
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
}
|
||||
}
|
||||
formError=""
|
||||
|
@ -1,83 +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="uploadFilePane">
|
||||
<!-- Upload File form -- Start -->
|
||||
<div class="contextual-pane-in">
|
||||
<form class="paneContentContainer" data-bind="submit: submit">
|
||||
<!-- Upload File 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">
|
||||
<img src="../../../images/close-black.svg" title="Close" alt="Close" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- Upload File header - End -->
|
||||
|
||||
<!-- Upload File 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 File errors - End -->
|
||||
|
||||
<!-- Upload File inputs - Start -->
|
||||
<div class="paneMainContent">
|
||||
<div>
|
||||
<div class="renewUploadItemsHeader" data-bind="text: selectFileInputLabel"></div>
|
||||
<input class="importFilesTitle" type="text" disabled data-bind="value: selectedFilesTitle" />
|
||||
<input
|
||||
type="file"
|
||||
id="importFileInput"
|
||||
style="display: none"
|
||||
data-bind="event: { change: updateSelectedFiles }, attr: { accept: extensions }"
|
||||
/>
|
||||
<a
|
||||
href="#"
|
||||
id="fileImportLinkNotebook"
|
||||
data-bind="event: { click: onImportLinkClick, keypress: onImportLinkKeyPress }"
|
||||
>
|
||||
<img
|
||||
id="importFileButton"
|
||||
class="fileImportImg"
|
||||
src="/folder_16x16.svg"
|
||||
alt="upload files"
|
||||
title="Upload files"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paneFooter">
|
||||
<div class="leftpanel-okbut">
|
||||
<input
|
||||
id="uploadFileButton"
|
||||
type="submit"
|
||||
data-bind="attr: { value: submitButtonLabel }"
|
||||
class="btncreatecoll1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Upload File inputs - End -->
|
||||
</form>
|
||||
</div>
|
||||
<!-- Upload File 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,137 +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";
|
||||
|
||||
export interface UploadFilePaneOpenOptions {
|
||||
paneTitle: string;
|
||||
selectFileInputLabel: string;
|
||||
errorMessage: string; // Could not upload notebook
|
||||
inProgressMessage: string; // Uploading notebook
|
||||
successMessage: string; // Successfully uploaded notebook
|
||||
onSubmit: (file: File) => Promise<any>;
|
||||
extensions?: string; // input accept field. E.g: .ipynb
|
||||
submitButtonLabel?: string;
|
||||
}
|
||||
|
||||
export class UploadFilePane extends ContextualPaneBase {
|
||||
public selectedFilesTitle: ko.Observable<string>;
|
||||
public files: ko.Observable<FileList>;
|
||||
private openOptions: UploadFilePaneOpenOptions;
|
||||
private submitButtonLabel: ko.Observable<string>;
|
||||
private selectFileInputLabel: ko.Observable<string>;
|
||||
private extensions: ko.Observable<string>;
|
||||
|
||||
constructor(options: ViewModels.PaneOptions) {
|
||||
super(options);
|
||||
this.resetData();
|
||||
this.selectFileInputLabel = ko.observable("");
|
||||
this.selectedFilesTitle = ko.observable<string>("");
|
||||
this.extensions = ko.observable(null);
|
||||
this.submitButtonLabel = ko.observable("Load");
|
||||
this.files = ko.observable<FileList>();
|
||||
this.files.subscribe((newFiles: FileList) => this.updateSelectedFilesTitle(newFiles));
|
||||
}
|
||||
|
||||
public submit() {
|
||||
this.formErrors("");
|
||||
this.formErrorsDetails("");
|
||||
if (!this.files() || this.files().length === 0) {
|
||||
this.formErrors("No file specified");
|
||||
this.formErrorsDetails("No file specified. Please input a file.");
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`${this.openOptions.errorMessage} -- No file specified. Please input a file.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const file: File = this.files().item(0);
|
||||
const id: string = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
`${this.openOptions.inProgressMessage}: ${file.name}`
|
||||
);
|
||||
this.isExecuting(true);
|
||||
this.openOptions
|
||||
.onSubmit(this.files().item(0))
|
||||
.then(
|
||||
() => {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Info,
|
||||
`${this.openOptions.successMessage} ${file.name}`
|
||||
);
|
||||
this.close();
|
||||
},
|
||||
(error: any) => {
|
||||
this.formErrors(this.openOptions.errorMessage);
|
||||
this.formErrorsDetails(`${this.openOptions.errorMessage}: ${error}`);
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`${this.openOptions.errorMessage} ${file.name}: ${error}`
|
||||
);
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
this.isExecuting(false);
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(id);
|
||||
});
|
||||
}
|
||||
|
||||
public updateSelectedFiles(element: any, event: any): void {
|
||||
this.files(event.target.files);
|
||||
}
|
||||
|
||||
public close() {
|
||||
super.close();
|
||||
this.resetData();
|
||||
this.files(undefined);
|
||||
this.resetFileInput();
|
||||
}
|
||||
|
||||
public openWithOptions(options: UploadFilePaneOpenOptions): void {
|
||||
this.openOptions = options;
|
||||
this.title(this.openOptions.paneTitle);
|
||||
if (this.openOptions.submitButtonLabel) {
|
||||
this.submitButtonLabel(this.openOptions.submitButtonLabel);
|
||||
}
|
||||
this.selectFileInputLabel(this.openOptions.selectFileInputLabel);
|
||||
if (this.openOptions.extensions) {
|
||||
this.extensions(this.openOptions.extensions);
|
||||
}
|
||||
super.open();
|
||||
}
|
||||
|
||||
public onImportLinkClick(source: any, event: MouseEvent): boolean {
|
||||
document.getElementById("importFileInput").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;
|
||||
};
|
||||
|
||||
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 resetFileInput(): void {
|
||||
const inputElement = $("#importFileInput");
|
||||
inputElement.wrap("<form>").closest("form").get(0).reset();
|
||||
inputElement.unwrap();
|
||||
}
|
||||
}
|
111
src/Explorer/Panes/UploadFilePane/index.tsx
Normal file
111
src/Explorer/Panes/UploadFilePane/index.tsx
Normal file
@ -0,0 +1,111 @@
|
||||
import React, { ChangeEvent, FunctionComponent, useState } from "react";
|
||||
import { Upload } from "../../../Common/Upload";
|
||||
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../../../Utils/NotificationConsoleUtils";
|
||||
import Explorer from "../../Explorer";
|
||||
import { NotebookContentItem } from "../../Notebook/NotebookContentItem";
|
||||
import { GenericRightPaneComponent, GenericRightPaneProps } from "../GenericRightPaneComponent";
|
||||
|
||||
export interface UploadFilePanelProps {
|
||||
explorer: Explorer;
|
||||
closePanel: () => void;
|
||||
uploadFile: (name: string, content: string) => Promise<NotebookContentItem>;
|
||||
}
|
||||
|
||||
export const UploadFilePane: FunctionComponent<UploadFilePanelProps> = ({
|
||||
explorer: container,
|
||||
closePanel,
|
||||
uploadFile,
|
||||
}: UploadFilePanelProps) => {
|
||||
const title = "Upload file to notebook server";
|
||||
const submitButtonLabel = "Upload";
|
||||
const selectFileInputLabel = "Select file to upload";
|
||||
const extensions: string = undefined; //ex. ".ipynb"
|
||||
const errorMessage = "Could not upload file";
|
||||
const inProgressMessage = "Uploading file to notebook server";
|
||||
const successMessage = "Successfully uploaded file to notebook server";
|
||||
|
||||
const [files, setFiles] = useState<FileList>();
|
||||
const [formErrors, setFormErrors] = useState<string>("");
|
||||
const [formErrorsDetails, setFormErrorsDetails] = useState<string>("");
|
||||
const [isExecuting, setIsExecuting] = useState<boolean>(false);
|
||||
|
||||
const submit = () => {
|
||||
setFormErrors("");
|
||||
setFormErrorsDetails("");
|
||||
if (!files || files.length === 0) {
|
||||
setFormErrors("No file specified");
|
||||
setFormErrorsDetails("No file specified. Please input a file.");
|
||||
logConsoleError(`${errorMessage} -- No file specified. Please input a file.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const file: File = files.item(0);
|
||||
// const id: string = logConsoleProgress(
|
||||
// `${inProgressMessage}: ${file.name}`
|
||||
// );
|
||||
|
||||
logConsoleProgress(`${inProgressMessage}: ${file.name}`);
|
||||
|
||||
setIsExecuting(true);
|
||||
|
||||
onSubmit(files.item(0))
|
||||
.then(
|
||||
() => {
|
||||
logConsoleInfo(`${successMessage} ${file.name}`);
|
||||
closePanel();
|
||||
},
|
||||
(error: string) => {
|
||||
setFormErrors(errorMessage);
|
||||
setFormErrorsDetails(`${errorMessage}: ${error}`);
|
||||
logConsoleError(`${errorMessage} ${file.name}: ${error}`);
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
setIsExecuting(false);
|
||||
// clearInProgressMessageWithId(id);
|
||||
});
|
||||
};
|
||||
|
||||
const updateSelectedFiles = (event: ChangeEvent<HTMLInputElement>): void => {
|
||||
setFiles(event.target.files);
|
||||
};
|
||||
|
||||
const onSubmit = async (file: File): Promise<NotebookContentItem> => {
|
||||
const readFileAsText = (inputFile: File): Promise<string> => {
|
||||
const reader = new FileReader();
|
||||
return new Promise((resolve, reject) => {
|
||||
reader.onerror = () => {
|
||||
reader.abort();
|
||||
reject(`Problem parsing file: ${inputFile}`);
|
||||
};
|
||||
reader.onload = () => {
|
||||
resolve(reader.result as string);
|
||||
};
|
||||
reader.readAsText(inputFile);
|
||||
});
|
||||
};
|
||||
|
||||
const fileContent = await readFileAsText(file);
|
||||
return uploadFile(file.name, fileContent);
|
||||
};
|
||||
|
||||
const genericPaneProps: GenericRightPaneProps = {
|
||||
container: container,
|
||||
formError: formErrors,
|
||||
formErrorDetail: formErrorsDetails,
|
||||
id: "uploadFilePane",
|
||||
isExecuting: isExecuting,
|
||||
title,
|
||||
submitButtonText: submitButtonLabel,
|
||||
onClose: closePanel,
|
||||
onSubmit: submit,
|
||||
};
|
||||
|
||||
return (
|
||||
<GenericRightPaneComponent {...genericPaneProps}>
|
||||
<div className="paneMainContent">
|
||||
<Upload label={selectFileInputLabel} accept={extensions} onUpload={updateSelectedFiles} />
|
||||
</div>
|
||||
</GenericRightPaneComponent>
|
||||
);
|
||||
};
|
@ -410,23 +410,6 @@ exports[`Upload Items Pane should render Default properly 1`] = `
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
UploadFilePane {
|
||||
"container": [Circular],
|
||||
"extensions": [Function],
|
||||
"files": [Function],
|
||||
"firstFieldHasFocus": [Function],
|
||||
"formErrors": [Function],
|
||||
"formErrorsDetails": [Function],
|
||||
"id": "uploadfilepane",
|
||||
"isExecuting": [Function],
|
||||
"isTemplateReady": [Function],
|
||||
"onImportLinkKeyPress": [Function],
|
||||
"selectFileInputLabel": [Function],
|
||||
"selectedFilesTitle": [Function],
|
||||
"submitButtonLabel": [Function],
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
StringInputPane {
|
||||
"container": [Circular],
|
||||
"firstFieldHasFocus": [Function],
|
||||
@ -1016,23 +999,6 @@ exports[`Upload Items Pane should render Default properly 1`] = `
|
||||
"openedTabs": [Function],
|
||||
},
|
||||
"toggleLeftPaneExpandedKeyPress": [Function],
|
||||
"uploadFilePane": UploadFilePane {
|
||||
"container": [Circular],
|
||||
"extensions": [Function],
|
||||
"files": [Function],
|
||||
"firstFieldHasFocus": [Function],
|
||||
"formErrors": [Function],
|
||||
"formErrorsDetails": [Function],
|
||||
"id": "uploadfilepane",
|
||||
"isExecuting": [Function],
|
||||
"isTemplateReady": [Function],
|
||||
"onImportLinkKeyPress": [Function],
|
||||
"selectFileInputLabel": [Function],
|
||||
"selectedFilesTitle": [Function],
|
||||
"submitButtonLabel": [Function],
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
}
|
||||
}
|
||||
formError=""
|
||||
|
@ -411,23 +411,6 @@ exports[`Delete Database Confirmation Pane submit() Should call delete database
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
UploadFilePane {
|
||||
"container": [Circular],
|
||||
"extensions": [Function],
|
||||
"files": [Function],
|
||||
"firstFieldHasFocus": [Function],
|
||||
"formErrors": [Function],
|
||||
"formErrorsDetails": [Function],
|
||||
"id": "uploadfilepane",
|
||||
"isExecuting": [Function],
|
||||
"isTemplateReady": [Function],
|
||||
"onImportLinkKeyPress": [Function],
|
||||
"selectFileInputLabel": [Function],
|
||||
"selectedFilesTitle": [Function],
|
||||
"submitButtonLabel": [Function],
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
StringInputPane {
|
||||
"container": [Circular],
|
||||
"firstFieldHasFocus": [Function],
|
||||
@ -1021,23 +1004,6 @@ exports[`Delete Database Confirmation Pane submit() Should call delete database
|
||||
"openedTabs": [Function],
|
||||
},
|
||||
"toggleLeftPaneExpandedKeyPress": [Function],
|
||||
"uploadFilePane": UploadFilePane {
|
||||
"container": [Circular],
|
||||
"extensions": [Function],
|
||||
"files": [Function],
|
||||
"firstFieldHasFocus": [Function],
|
||||
"formErrors": [Function],
|
||||
"formErrorsDetails": [Function],
|
||||
"id": "uploadfilepane",
|
||||
"isExecuting": [Function],
|
||||
"isTemplateReady": [Function],
|
||||
"onImportLinkKeyPress": [Function],
|
||||
"selectFileInputLabel": [Function],
|
||||
"selectedFilesTitle": [Function],
|
||||
"submitButtonLabel": [Function],
|
||||
"title": [Function],
|
||||
"visible": [Function],
|
||||
},
|
||||
}
|
||||
}
|
||||
openNotificationConsole={[Function]}
|
||||
|
@ -765,7 +765,7 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
||||
{
|
||||
label: "Upload File",
|
||||
iconSrc: NewNotebookIcon,
|
||||
onClick: () => this.container.onUploadToNotebookServerClicked(item),
|
||||
onClick: () => this.container.openUploadFilePanel(item),
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -243,7 +243,6 @@ const App: React.FunctionComponent = () => {
|
||||
<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} }' />
|
||||
<div data-bind='component: { name: "upload-file-pane", params: { data: uploadFilePane} }' />
|
||||
<div data-bind='component: { name: "string-input-pane", params: { data: stringInputPane} }' />
|
||||
<div data-bind='component: { name: "setup-notebooks-pane", params: { data: setupNotebooksPane} }' />
|
||||
<KOCommentIfStart if="isGitHubPaneEnabled" />
|
||||
|
Loading…
Reference in New Issue
Block a user