From ba72ecb0e3f57654382f207ca668a4bc3e37dd72 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Mon, 29 Jan 2018 22:31:49 -0800 Subject: [PATCH] issue-537 --- app/components/DropToImport/DropToImport.js | 35 +----- .../Sidebar/components/Collections.js | 8 -- app/menus/CollectionMenu.js | 104 ++++++++++++------ app/scenes/Collection/Collection.js | 5 +- app/utils/importFile.js | 36 ++++++ 5 files changed, 119 insertions(+), 69 deletions(-) create mode 100644 app/utils/importFile.js diff --git a/app/components/DropToImport/DropToImport.js b/app/components/DropToImport/DropToImport.js index d948b8d9..67a11277 100644 --- a/app/components/DropToImport/DropToImport.js +++ b/app/components/DropToImport/DropToImport.js @@ -4,10 +4,10 @@ import { observable } from 'mobx'; import { observer, inject } from 'mobx-react'; import { injectGlobal } from 'styled-components'; import { color } from 'shared/styles/constants'; +import importFile from 'utils/importFile'; import invariant from 'invariant'; import _ from 'lodash'; import Dropzone from 'react-dropzone'; -import Document from 'models/Document'; import DocumentsStore from 'stores/DocumentsStore'; import LoadingIndicator from 'components/LoadingIndicator'; @@ -19,7 +19,6 @@ type Props = { rejectClassName?: string, documents: DocumentsStore, disabled: boolean, - dropzoneRef: Function, history: Object, }; @@ -40,30 +39,6 @@ class DropToImport extends Component { @observable isImporting: boolean = false; props: Props; - importFile = async ({ file, documentId, collectionId, redirect }) => { - const reader = new FileReader(); - - reader.onload = async ev => { - const text = ev.target.result; - let data = { - parentDocument: undefined, - collection: { id: collectionId }, - text, - }; - - if (documentId) data.parentDocument = documentId; - - let document = new Document(data); - document = await document.save(); - this.props.documents.add(document); - - if (redirect && this.props.history) { - this.props.history.push(document.url); - } - }; - reader.readAsText(file); - }; - onDropAccepted = async (files = []) => { this.isImporting = true; @@ -79,7 +54,11 @@ class DropToImport extends Component { } for (const file of files) { - await this.importFile({ file, documentId, collectionId, redirect }); + await importFile({ file, documentId, collectionId, redirect }, doc => { + if (redirect) { + this.props.history.push(doc.url); + } + }); } } catch (err) { // TODO: show error alert. @@ -96,7 +75,6 @@ class DropToImport extends Component { 'collectionId', 'documents', 'disabled', - 'dropzoneRef', 'menuOpen' ); @@ -110,7 +88,6 @@ class DropToImport extends Component { disableClick disablePreview multiple - ref={this.props.dropzoneRef} {...props} > {this.isImporting && } diff --git a/app/components/Sidebar/components/Collections.js b/app/components/Sidebar/components/Collections.js index a4fdbcd0..2d99b958 100644 --- a/app/components/Sidebar/components/Collections.js +++ b/app/components/Sidebar/components/Collections.js @@ -76,14 +76,9 @@ type CollectionLinkProps = { @observer class CollectionLink extends Component { props: CollectionLinkProps; - dropzoneRef; @observable menuOpen = false; - handleImport = () => { - this.dropzoneRef.open(); - }; - renderDocuments() { const { history, @@ -119,7 +114,6 @@ class CollectionLink extends Component { collectionId={collection.id} activeClassName="activeDropZone" menuOpen={this.menuOpen} - dropzoneRef={ref => (this.dropzoneRef = ref)} > (this.menuOpen = true)} onClose={() => (this.menuOpen = false)} - onImport={this.handleImport} - open={this.menuOpen} /> diff --git a/app/menus/CollectionMenu.js b/app/menus/CollectionMenu.js index fb1d7e99..6cbb9426 100644 --- a/app/menus/CollectionMenu.js +++ b/app/menus/CollectionMenu.js @@ -1,24 +1,31 @@ // @flow import React, { Component } from 'react'; import { inject, observer } from 'mobx-react'; +import styled from 'styled-components'; +import getDataTransferFiles from 'utils/getDataTransferFiles'; +import importFile from 'utils/importFile'; import Collection from 'models/Collection'; import UiStore from 'stores/UiStore'; +import DocumentsStore from 'stores/DocumentsStore'; import MoreIcon from 'components/Icon/MoreIcon'; import Flex from 'shared/components/Flex'; import { DropdownMenu, DropdownMenuItem } from 'components/DropdownMenu'; +type Props = { + label?: React$Element<*>, + onOpen?: () => void, + onClose?: () => void, + history: Object, + ui: UiStore, + documents: DocumentsStore, + collection: Collection, +}; + @observer class CollectionMenu extends Component { - props: { - label?: React$Element<*>, - onOpen?: () => void, - onClose?: () => void, - onImport?: () => void, - history: Object, - ui: UiStore, - collection: Collection, - }; + props: Props; + file: HTMLInputElement; onNewDocument = (ev: SyntheticEvent) => { ev.preventDefault(); @@ -26,6 +33,26 @@ class CollectionMenu extends Component { history.push(`${collection.url}/new`); }; + onImportFile = (ev: SyntheticEvent) => { + // simulate a click on the file upload input element + this.file.click(); + }; + + onFilePicked = (ev: SyntheticEvent) => { + const files = getDataTransferFiles(ev); + + importFile( + { + file: files[0], + documents: this.props.documents, + collectionId: this.props.collection.id, + }, + document => { + this.props.history.push(document.url); + } + ); + }; + onEdit = (ev: SyntheticEvent) => { ev.preventDefault(); const { collection } = this.props; @@ -39,32 +66,47 @@ class CollectionMenu extends Component { }; render() { - const { collection, label, onOpen, onClose, onImport } = this.props; + const { collection, label, onOpen, onClose } = this.props; const { allowDelete } = collection; return ( - } - onOpen={onOpen} - onClose={onClose} - > - {collection && ( - - - New document - - - Import document - - Edit… - - )} - {allowDelete && ( - Delete… - )} - + + (this.file = ref)} + onChange={this.onFilePicked} + accept="text/markdown, text/plain" + /> + } + onOpen={onOpen} + onClose={onClose} + > + {collection && ( + + + New document + + + Import document + + Edit… + + )} + {allowDelete && ( + Delete… + )} + + ); } } -export default inject('ui')(CollectionMenu); +const HiddenInput = styled.input` + position: absolute; + top: -100px; + left: -100px; + visibility: hidden; +`; + +export default inject('ui', 'documents')(CollectionMenu); diff --git a/app/scenes/Collection/Collection.js b/app/scenes/Collection/Collection.js index 74bc1b4a..9736bcf1 100644 --- a/app/scenes/Collection/Collection.js +++ b/app/scenes/Collection/Collection.js @@ -133,7 +133,10 @@ class CollectionScene extends Component { /> - + diff --git a/app/utils/importFile.js b/app/utils/importFile.js new file mode 100644 index 00000000..c7847d0d --- /dev/null +++ b/app/utils/importFile.js @@ -0,0 +1,36 @@ +// @flow +import Document from '../models/Document'; +import DocumentsStore from '../stores/DocumentsStore'; + +type Options = { + file: File, + documents: DocumentsStore, + collectionId: string, + documentId?: string, +}; + +const importFile = async ( + { documents, file, documentId, collectionId }: Options, + callback: Document => * +) => { + const reader = new FileReader(); + + reader.onload = async ev => { + const text = ev.target.result; + let data = { + parentDocument: undefined, + collection: { id: collectionId }, + text, + }; + + if (documentId) data.parentDocument = documentId; + + let document = new Document(data); + document = await document.save(); + documents.add(document); + callback(document); + }; + reader.readAsText(file); +}; + +export default importFile;