diff options
| author | Sam Wilkins <samwilkins333@gmail.com> | 2019-09-14 05:06:59 -0400 |
|---|---|---|
| committer | Sam Wilkins <samwilkins333@gmail.com> | 2019-09-14 05:06:59 -0400 |
| commit | e2e642dfb3d71ea37c4d521d93ab16f166cc63cf (patch) | |
| tree | f8f9e8de7f3d9e3129184c61d2305710d59933b6 /src/client/util | |
| parent | 4f382d9629fbfdf6502782bbb8f39dba06ae51fa (diff) | |
update routine
Diffstat (limited to 'src/client/util')
| -rw-r--r-- | src/client/util/Import & Export/DirectoryImportBox.scss | 6 | ||||
| -rw-r--r-- | src/client/util/Import & Export/DirectoryImportBox.tsx | 70 | ||||
| -rw-r--r-- | src/client/util/UtilExtensions.ts | 20 |
3 files changed, 73 insertions, 23 deletions
diff --git a/src/client/util/Import & Export/DirectoryImportBox.scss b/src/client/util/Import & Export/DirectoryImportBox.scss new file mode 100644 index 000000000..d33cb524b --- /dev/null +++ b/src/client/util/Import & Export/DirectoryImportBox.scss @@ -0,0 +1,6 @@ +.phase { + position: absolute; + top: 15px; + left: 15px; + font-style: italic; +}
\ No newline at end of file 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", diff --git a/src/client/util/UtilExtensions.ts b/src/client/util/UtilExtensions.ts index eca10c3b1..0b325bc51 100644 --- a/src/client/util/UtilExtensions.ts +++ b/src/client/util/UtilExtensions.ts @@ -12,7 +12,8 @@ module.exports.Batch = function <T>(batchSize: number): T[][] { module.exports.ExecuteBatches = function <I, O>(batchSize: number, handler: BatchHandlerSync<I>): void { if (this.length) { for (let batch of this.batch(batchSize)) { - handler(batch); + const isFullBatch = batch.length === batchSize; + handler(batch, isFullBatch); } } }; @@ -23,7 +24,8 @@ module.exports.ConvertInBatches = function <I, O>(batchSize: number, handler: Ba } let collector: O[] = []; for (let batch of this.batch(batchSize)) { - collector.push(...handler(batch)); + const isFullBatch = batch.length === batchSize; + collector.push(...handler(batch, isFullBatch)); } return collector; }; @@ -31,7 +33,8 @@ module.exports.ConvertInBatches = function <I, O>(batchSize: number, handler: Ba module.exports.ExecuteInBatchesAsync = async function <I>(batchSize: number, handler: BatchHandler<I>): Promise<void> { if (this.length) { for (let batch of this.batch(batchSize)) { - await handler(batch); + const isFullBatch = batch.length === batchSize; + await handler(batch, isFullBatch); } } }; @@ -42,7 +45,8 @@ module.exports.ConvertInBatchesAsync = async function <I, O>(batchSize: number, } let collector: O[] = []; for (let batch of this.batch(batchSize)) { - collector.push(...(await handler(batch))); + const isFullBatch = batch.length === batchSize; + collector.push(...(await handler(batch, isFullBatch))); } return collector; }; @@ -59,7 +63,9 @@ module.exports.ExecuteInBatchesAtInterval = async function <I>(batchSize: number const next = iterator.next(); await new Promise<void>(resolve => { setTimeout(async () => { - await handler(next.value); + const batch = next.value; + const isFullBatch = batch.length === batchSize; + await handler(batch, isFullBatch); resolve(); }, interval * 1000); }); @@ -84,7 +90,9 @@ module.exports.ConvertInBatchesAtInterval = async function <I, O>(batchSize: num const next = iterator.next(); await new Promise<void>(resolve => { setTimeout(async () => { - collector.push(...(await handler(next.value))); + const batch = next.value; + const isFullBatch = batch.length === batchSize; + collector.push(...(await handler(batch, isFullBatch))); resolve(); }, interval * 1000); }); |
