diff options
Diffstat (limited to 'src/client/util/Import & Export/DirectoryImportBox.tsx')
-rw-r--r-- | src/client/util/Import & Export/DirectoryImportBox.tsx | 70 |
1 files changed, 53 insertions, 17 deletions
diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx index 93ab5cb3b..7634d8234 100644 --- a/src/client/util/Import & Export/DirectoryImportBox.tsx +++ b/src/client/util/Import & Export/DirectoryImportBox.tsx @@ -1,9 +1,8 @@ import "fs"; import React = require("react"); -import { Doc, Opt, DocListCast, DocListCastAsync } from "../../../new_fields/Doc"; -import { DocServer } from "../../DocServer"; +import { Doc, DocListCast, DocListCastAsync, Opt } from "../../../new_fields/Doc"; import { RouteStore } from "../../../server/RouteStore"; -import { action, observable, autorun, runInAction, computed } from "mobx"; +import { action, observable, autorun, runInAction, computed, reaction, IReactionDisposer } from "mobx"; import { FieldViewProps, FieldView } from "../../views/nodes/FieldView"; import Measure, { ContentRect } from "react-measure"; import { library } from '@fortawesome/fontawesome-svg-core'; @@ -20,6 +19,7 @@ import { Cast, BoolCast, NumCast } from "../../../new_fields/Types"; import { listSpec } from "../../../new_fields/Schema"; import { GooglePhotos } from "../../apis/google_docs/GooglePhotosClientUtils"; import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; +import "./DirectoryImportBox.scss"; const unsupported = ["text/html", "text/plain"]; interface FileResponse { @@ -34,6 +34,8 @@ export default class DirectoryImportBox extends React.Component<FieldViewProps> @observable private top = 0; @observable private left = 0; private dimensions = 50; + @observable private phase = ""; + private disposer: Opt<IReactionDisposer>; @observable private entries: ImportMetadataEntry[] = []; @@ -73,7 +75,10 @@ export default class DirectoryImportBox extends React.Component<FieldViewProps> } handleSelection = async (e: React.ChangeEvent<HTMLInputElement>) => { - runInAction(() => this.uploading = true); + runInAction(() => { + this.uploading = true; + this.phase = "Initializing download..."; + }); let docs: Doc[] = []; @@ -108,8 +113,12 @@ export default class DirectoryImportBox extends React.Component<FieldViewProps> return (await fetch(Utils.prepend(RouteStore.upload), parameters)).json(); }; + runInAction(() => this.phase = `Internal: uploading ${this.quota - this.completed} files to Dash...`); + const uploads = await validated.convertInBatchesAsync<FileResponse>(15, uploadLocally); + runInAction(() => this.phase = `Creating documents from uploads...`); + await Promise.all(uploads.map(async upload => { const type = upload.type; const path = Utils.prepend(upload.path); @@ -151,8 +160,10 @@ export default class DirectoryImportBox extends React.Component<FieldViewProps> const headers = ["title", "size"].map(key => new SchemaHeaderField(key)); importContainer = Docs.Create.SchemaDocument(headers, docs, options); } - await GooglePhotos.Export.CollectionToAlbum({ collection: importContainer }); + runInAction(() => this.phase = 'External: uploading files to Google Photos...'); importContainer.singleColumn = false; + await GooglePhotos.Export.CollectionToAlbum({ collection: importContainer }); + runInAction(() => this.phase = 'All files uploaded to Google Photos...'); Doc.AddDocToList(Doc.GetProto(parent.props.Document), "data", importContainer); !this.persistent && this.props.removeDocument && this.props.removeDocument(doc); DocumentManager.Instance.jumpToDocument(importContainer, true); @@ -168,6 +179,14 @@ export default class DirectoryImportBox extends React.Component<FieldViewProps> componentDidMount() { this.selector.current!.setAttribute("directory", ""); this.selector.current!.setAttribute("webkitdirectory", ""); + this.disposer = reaction( + () => this.completed, + completed => runInAction(() => this.phase = `Internal: uploading ${this.quota - completed} files to Dash...`) + ); + } + + componentWillUnmount() { + this.disposer && this.disposer(); } @action @@ -218,10 +237,38 @@ export default class DirectoryImportBox extends React.Component<FieldViewProps> percent = percent.split(".")[0]; percent = percent.startsWith("100") ? "99" : percent; let marginOffset = (percent.length === 1 ? 5 : 0) - 1.6; + const message = <span className={"phase"}>{this.phase}</span>; + const centerPiece = this.phase.includes("Google Photos") ? + <img src={"/assets/google_photos.png"} style={{ + transition: "0.4s opacity ease", + width: 30, + height: 30, + opacity: uploading ? 1 : 0, + pointerEvents: "none", + position: "absolute", + left: 12, + top: this.top + 10, + fontSize: 18, + color: "white", + marginLeft: this.left + marginOffset + }} /> + : <div + style={{ + transition: "0.4s opacity ease", + opacity: uploading ? 1 : 0, + pointerEvents: "none", + position: "absolute", + left: 10, + top: this.top + 12.3, + fontSize: 18, + color: "white", + marginLeft: this.left + marginOffset + }}>{percent}%</div>; return ( <Measure offset onResize={this.preserveCentering}> {({ measureRef }) => <div ref={measureRef} style={{ width: "100%", height: "100%", pointerEvents: "all" }} > + {message} <input id={"selector"} ref={this.selector} @@ -294,18 +341,7 @@ export default class DirectoryImportBox extends React.Component<FieldViewProps> opacity: showRemoveLabel ? 1 : 0, transition: "0.4s opacity ease" }}>Template will be <span style={{ textDecoration: "underline", textDecorationColor: persistent ? "green" : "red", color: persistent ? "green" : "red" }}>{persistent ? "kept" : "removed"}</span> after upload</p> - <div - style={{ - transition: "0.4s opacity ease", - opacity: uploading ? 1 : 0, - pointerEvents: "none", - position: "absolute", - left: 10, - top: this.top + 12.3, - fontSize: 18, - color: "white", - marginLeft: this.left + marginOffset - }}>{percent}%</div> + {centerPiece} <div style={{ position: "absolute", |