refs #13967 Merge branch 'origin/13967-collection-files-stringifier' into 13856-uploa...
authorDaniel Kos <daniel.kos@contractors.roche.com>
Mon, 6 Aug 2018 19:44:43 +0000 (21:44 +0200)
committerDaniel Kos <daniel.kos@contractors.roche.com>
Mon, 6 Aug 2018 19:45:11 +0000 (21:45 +0200)
Arvados-DCO-1.1-Signed-off-by: Daniel Kos <daniel.kos@contractors.roche.com>

15 files changed:
package.json
src/components/file-upload/file-upload.tsx [new file with mode: 0644]
src/components/icon/icon.tsx
src/store/collections/collections-reducer.ts
src/store/collections/creator/collection-creator-action.ts
src/store/collections/creator/collection-creator-reducer.test.ts
src/store/collections/creator/collection-creator-reducer.ts
src/store/collections/updater/collection-updater-action.ts [moved from src/store/collections/updator/collection-updator-action.ts with 72% similarity]
src/store/collections/updater/collection-updater-reducer.ts [new file with mode: 0644]
src/store/collections/updator/collection-updator-reducer.ts [deleted file]
src/views-components/context-menu/action-sets/collection-action-set.ts
src/views-components/dialog-create/dialog-collection-create.tsx
src/views-components/dialog-update/dialog-collection-update.tsx
src/views-components/update-collection-dialog/update-collection-dialog..tsx
yarn.lock

index f940e54ee3e4b138ee7000daf58eb41ca5e38d67..cd8a9c4d241356df33f60894c8ca23f2bf0fc1e4 100644 (file)
@@ -7,6 +7,7 @@
     "@material-ui/icons": "2.0.0",
     "@types/lodash": "4.14.116",
     "@types/react-copy-to-clipboard": "4.2.5",
+    "@types/react-dropzone": "4.2.1",
     "@types/redux-form": "7.4.4",
     "axios": "0.18.0",
     "classnames": "2.2.6",
@@ -14,6 +15,7 @@
     "react": "16.4.2",
     "react-copy-to-clipboard": "5.0.1",
     "react-dom": "16.4.2",
+    "react-dropzone": "4.2.13",
     "react-redux": "5.0.7",
     "react-router": "4.3.1",
     "react-router-dom": "4.3.1",
diff --git a/src/components/file-upload/file-upload.tsx b/src/components/file-upload/file-upload.tsx
new file mode 100644 (file)
index 0000000..3a98e27
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import { Grid, StyleRulesCallback, Typography, WithStyles } from '@material-ui/core';
+import { withStyles } from '@material-ui/core';
+import Dropzone from 'react-dropzone';
+import { CloudUploadIcon } from "../icon/icon";
+
+type CssRules = "root" | "dropzone" | "container" | "uploadIcon";
+
+const styles: StyleRulesCallback<CssRules> = theme => ({
+    root: {
+    },
+    dropzone: {
+        width: "100%",
+        height: "100px",
+        border: "1px dashed black",
+        borderRadius: "5px"
+    },
+    container: {
+        height: "100%"
+    },
+    uploadIcon: {
+        verticalAlign: "middle"
+    }
+});
+
+interface FileUploadProps {
+}
+
+export const FileUpload = withStyles(styles)(
+    ({ classes }: FileUploadProps & WithStyles<CssRules>) =>
+    <Grid container direction={"column"}>
+        <Typography variant={"subheading"}>
+            Upload data
+        </Typography>
+        <Dropzone className={classes.dropzone}>
+            <Grid container justify="center" alignItems="center" className={classes.container}>
+                <Grid item component={"span"}>
+                    <Typography variant={"subheading"}>
+                        <CloudUploadIcon className={classes.uploadIcon}/> Drag and drop data or <a>browse</a>
+                    </Typography>
+                </Grid>
+            </Grid>
+        </Dropzone>
+    </Grid>
+);
index 1dc8669ecfdc927f550459819fc1f9aae1561d16..0f0442a53ebd1b7be4b485694b45e86e3a99be7a 100644 (file)
@@ -7,6 +7,7 @@ import AccessTime from '@material-ui/icons/AccessTime';
 import ArrowDropDown from '@material-ui/icons/ArrowDropDown';
 import BubbleChart from '@material-ui/icons/BubbleChart';
 import Cached from '@material-ui/icons/Cached';
+import CloudUpload from '@material-ui/icons/CloudUpload';
 import Code from '@material-ui/icons/Code';
 import ChevronLeft from '@material-ui/icons/ChevronLeft';
 import ChevronRight from '@material-ui/icons/ChevronRight';
@@ -44,6 +45,7 @@ export const CustomizeTableIcon: IconType = (props) => <Menu {...props} />;
 export const CopyIcon: IconType = (props) => <ContentCopy {...props} />;
 export const CollectionIcon: IconType = (props) => <LibraryBooks {...props} />;
 export const CloseIcon: IconType = (props) => <Close {...props} />;
+export const CloudUploadIcon: IconType = (props) => <CloudUpload {...props} />;
 export const DefaultIcon: IconType = (props) => <RateReview {...props} />;
 export const DetailsIcon: IconType = (props) => <Info {...props} />;
 export const DownloadIcon: IconType = (props) => <GetApp {...props} />;
index 966cf29d515a90ed4d3d8d1f7bfe4742c0855a6e..e1982d28b73a99236a75bc71c460b2e77e3ca6c4 100644 (file)
@@ -4,14 +4,14 @@
 
 import { combineReducers } from 'redux';
 import * as creator from "./creator/collection-creator-reducer";
-import * as updator from "./updator/collection-updator-reducer";
+import * as updater from "./updater/collection-updater-reducer";
 
 export type CollectionsState = {
     creator: creator.CollectionCreatorState;
-    updator: updator.CollectionUpdatorState;
+    updater: updater.CollectionUpdaterState;
 };
 
 export const collectionsReducer = combineReducers({
-    creator: creator.collectionCreationReducer,
-    updator: updator.collectionCreationReducer
-});
\ No newline at end of file
+    creator: creator.collectionCreatorReducer,
+    updater: updater.collectionUpdaterReducer
+});
index 2f2b83850e5f226aeb9e3a857e1c5f937aa5e3e8..b06cf0f5970346ffe22d74cf0f3454f20c20fe3a 100644 (file)
@@ -15,9 +15,9 @@ export const collectionCreateActions = unionize({
     CREATE_COLLECTION: ofType<{}>(),
     CREATE_COLLECTION_SUCCESS: ofType<{}>(),
 }, {
-        tag: 'type',
-        value: 'payload'
-    });
+    tag: 'type',
+    value: 'payload'
+});
 
 export const createCollection = (collection: Partial<CollectionResource>) =>
     (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
index fde58c433602aea0725ce09cb59f3006483bc4b2..5aa9dcfe5a86f6c6cc51f6bf987f1ad42bacb6d0 100644 (file)
@@ -2,7 +2,7 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-import { collectionCreationReducer } from "./collection-creator-reducer";
+import { collectionCreatorReducer } from "./collection-creator-reducer";
 import { collectionCreateActions } from "./collection-creator-action";
 
 describe('collection-reducer', () => {
@@ -11,7 +11,7 @@ describe('collection-reducer', () => {
         const initialState = { opened: false, ownerUuid: "" };
         const collection = { opened: true, ownerUuid: "" };
 
-        const state = collectionCreationReducer(initialState, collectionCreateActions.OPEN_COLLECTION_CREATOR(initialState));
+        const state = collectionCreatorReducer(initialState, collectionCreateActions.OPEN_COLLECTION_CREATOR(initialState));
         expect(state).toEqual(collection);
     });
 
@@ -19,7 +19,7 @@ describe('collection-reducer', () => {
         const initialState = { opened: true, ownerUuid: "" };
         const collection = { opened: false, ownerUuid: "" };
 
-        const state = collectionCreationReducer(initialState, collectionCreateActions.CLOSE_COLLECTION_CREATOR());
+        const state = collectionCreatorReducer(initialState, collectionCreateActions.CLOSE_COLLECTION_CREATOR());
         expect(state).toEqual(collection);
     });
 
@@ -27,7 +27,7 @@ describe('collection-reducer', () => {
         const initialState = { opened: true, ownerUuid: "test" };
         const collection = { opened: false, ownerUuid: "" };
 
-        const state = collectionCreationReducer(initialState, collectionCreateActions.CREATE_COLLECTION_SUCCESS());
+        const state = collectionCreatorReducer(initialState, collectionCreateActions.CREATE_COLLECTION_SUCCESS());
         expect(state).toEqual(collection);
     });
-});
\ No newline at end of file
+});
index 1a3cb0d2ea5f1082de69e0c796321df6295f6d07..140cbbea45e4bf423eda511d9a393133507f0334 100644 (file)
@@ -21,7 +21,7 @@ const initialState: CollectionCreatorState = {
     ownerUuid: ''
 };
 
-export const collectionCreationReducer = (state: CollectionCreatorState = initialState, action: CollectionCreateAction) => {
+export const collectionCreatorReducer = (state: CollectionCreatorState = initialState, action: CollectionCreateAction) => {
     return collectionCreateActions.match(action, {
         OPEN_COLLECTION_CREATOR: ({ ownerUuid }) => updateCreator(state, { ownerUuid, opened: true }),
         CLOSE_COLLECTION_CREATOR: () => updateCreator(state, { opened: false }),
similarity index 72%
rename from src/store/collections/updator/collection-updator-action.ts
rename to src/store/collections/updater/collection-updater-action.ts
index e12bfe548c01e69c874dc001c5533d398013a1b0..a7a354ad1c31940b733711c7dd27a92a6296ffca 100644 (file)
@@ -11,21 +11,21 @@ import { CollectionResource } from '../../../models/collection';
 import { initialize } from 'redux-form';
 import { collectionPanelActions } from "../../collection-panel/collection-panel-action";
 
-export const collectionUpdatorActions = unionize({
-    OPEN_COLLECTION_UPDATOR: ofType<{ uuid: string }>(),
-    CLOSE_COLLECTION_UPDATOR: ofType<{}>(),
+export const collectionUpdaterActions = unionize({
+    OPEN_COLLECTION_UPDATER: ofType<{ uuid: string }>(),
+    CLOSE_COLLECTION_UPDATER: ofType<{}>(),
     UPDATE_COLLECTION_SUCCESS: ofType<{}>(),
 }, {
-        tag: 'type',
-        value: 'payload'
-    });
+    tag: 'type',
+    value: 'payload'
+});
 
 
 export const COLLECTION_FORM_NAME = 'collectionEditDialog';
-    
-export const openUpdator = (uuid: string) =>
+
+export const openUpdater = (uuid: string) =>
     (dispatch: Dispatch, getState: () => RootState) => {
-        dispatch(collectionUpdatorActions.OPEN_COLLECTION_UPDATOR({ uuid }));
+        dispatch(collectionUpdaterActions.OPEN_COLLECTION_UPDATER({ uuid }));
         const item = getState().collectionPanel.item;
         if(item) {
             dispatch(initialize(COLLECTION_FORM_NAME, { name: item.name, description: item.description }));
@@ -34,14 +34,14 @@ export const openUpdator = (uuid: string) =>
 
 export const updateCollection = (collection: Partial<CollectionResource>) =>
     (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
-        const { uuid } = getState().collections.updator;
+        const { uuid } = getState().collections.updater;
         return services.collectionService
             .update(uuid, collection)
             .then(collection => {
                     dispatch(collectionPanelActions.LOAD_COLLECTION_SUCCESS({ item: collection as CollectionResource }));
-                    dispatch(collectionUpdatorActions.UPDATE_COLLECTION_SUCCESS());
+                    dispatch(collectionUpdaterActions.UPDATE_COLLECTION_SUCCESS());
                 }
             );
     };
 
-export type CollectionUpdatorAction = UnionOf<typeof collectionUpdatorActions>;
\ No newline at end of file
+export type CollectionUpdaterAction = UnionOf<typeof collectionUpdaterActions>;
diff --git a/src/store/collections/updater/collection-updater-reducer.ts b/src/store/collections/updater/collection-updater-reducer.ts
new file mode 100644 (file)
index 0000000..432aa27
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { collectionUpdaterActions, CollectionUpdaterAction } from './collection-updater-action';
+
+export interface CollectionUpdaterState {
+    opened: boolean;
+    uuid: string;
+}
+
+const updateCollection = (state: CollectionUpdaterState, updater?: Partial<CollectionUpdaterState>) => ({
+    ...state,
+    ...updater
+});
+
+const initialState: CollectionUpdaterState = {
+    opened: false,
+    uuid: ''
+};
+
+export const collectionUpdaterReducer = (state: CollectionUpdaterState = initialState, action: CollectionUpdaterAction) => {
+    return collectionUpdaterActions.match(action, {
+        OPEN_COLLECTION_UPDATER: ({ uuid }) => updateCollection(state, { uuid, opened: true }),
+        CLOSE_COLLECTION_UPDATER: () => updateCollection(state, { opened: false }),
+        UPDATE_COLLECTION_SUCCESS: () => updateCollection(state, { opened: false, uuid: "" }),
+        default: () => state
+    });
+};
diff --git a/src/store/collections/updator/collection-updator-reducer.ts b/src/store/collections/updator/collection-updator-reducer.ts
deleted file mode 100644 (file)
index b9d0250..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright (C) The Arvados Authors. All rights reserved.
-//
-// SPDX-License-Identifier: AGPL-3.0
-
-import { collectionUpdatorActions, CollectionUpdatorAction } from './collection-updator-action';
-
-export type CollectionUpdatorState = CollectionUpdator;
-
-interface CollectionUpdator {
-    opened: boolean;
-    uuid: string;
-}
-
-const updateCollection = (state: CollectionUpdatorState, updator?: Partial<CollectionUpdator>) => ({
-    ...state,
-    ...updator
-});
-
-const initialState: CollectionUpdatorState = {
-    opened: false,
-    uuid: ''
-};
-
-export const collectionCreationReducer = (state: CollectionUpdatorState = initialState, action: CollectionUpdatorAction) => {
-    return collectionUpdatorActions.match(action, {
-        OPEN_COLLECTION_UPDATOR: ({ uuid }) => updateCollection(state, { uuid, opened: true }),
-        CLOSE_COLLECTION_UPDATOR: () => updateCollection(state, { opened: false }),
-        UPDATE_COLLECTION_SUCCESS: () => updateCollection(state, { opened: false, uuid: "" }),
-        default: () => state
-    });
-};
index 566f8f12e41c85cef26b7b945544b8c050811996..513cb5fc08647a8c419f38d5a8f6afc8822679a1 100644 (file)
@@ -6,7 +6,7 @@ import { ContextMenuActionSet } from "../context-menu-action-set";
 import { ToggleFavoriteAction } from "../actions/favorite-action";
 import { toggleFavorite } from "../../../store/favorites/favorites-actions";
 import { RenameIcon, ShareIcon, MoveToIcon, CopyIcon, DetailsIcon, ProvenanceGraphIcon, AdvancedIcon, RemoveIcon } from "../../../components/icon/icon";
-import { openUpdator } from "../../../store/collections/updator/collection-updator-action";
+import { openUpdater } from "../../../store/collections/updater/collection-updater-action";
 import { favoritePanelActions } from "../../../store/favorite-panel/favorite-panel-action";
 
 export const collectionActionSet: ContextMenuActionSet = [[
@@ -14,7 +14,7 @@ export const collectionActionSet: ContextMenuActionSet = [[
         icon: RenameIcon,
         name: "Edit collection",
         execute: (dispatch, resource) => {
-            dispatch<any>(openUpdator(resource.uuid));
+            dispatch<any>(openUpdater(resource.uuid));
         }
     },
     {
@@ -35,7 +35,7 @@ export const collectionActionSet: ContextMenuActionSet = [[
         component: ToggleFavoriteAction,
         execute: (dispatch, resource) => {
             dispatch<any>(toggleFavorite(resource)).then(() => {
-                dispatch<any>(favoritePanelActions.REQUEST_ITEMS());           
+                dispatch<any>(favoritePanelActions.REQUEST_ITEMS());
             });
         }
     },
index 3e3b74aa92747d9adf5053d543097a1110ee3ace..f59728b6e8205644cbab01711d2bc0345b1a5e84 100644 (file)
@@ -13,6 +13,7 @@ import DialogTitle from '@material-ui/core/DialogTitle';
 import { Button, StyleRulesCallback, WithStyles, withStyles, CircularProgress } from '@material-ui/core';
 
 import { COLLECTION_NAME_VALIDATION, COLLECTION_DESCRIPTION_VALIDATION } from '../../validators/create-project/create-project-validator';
+import { FileUpload } from "../../components/file-upload/file-upload";
 
 type CssRules = "button" | "lastButton" | "formContainer" | "textField" | "createProgress" | "dialogActions";
 
@@ -90,6 +91,7 @@ export const DialogCollectionCreate = compose(
                                     validate={COLLECTION_DESCRIPTION_VALIDATION}
                                     className={classes.textField}
                                     label="Description - optional"/>
+                            <FileUpload/>
                         </DialogContent>
                         <DialogActions className={classes.dialogActions}>
                             <Button onClick={handleClose} className={classes.button} color="primary"
index 80a82b27fd97bb27a65dd954603e1cb7c2a965d8..dc278018e1841ec5ca1b1363db44272251cacc3b 100644 (file)
@@ -8,7 +8,7 @@ import { compose } from 'redux';
 import { ArvadosTheme } from '../../common/custom-theme';
 import { Dialog, DialogActions, DialogContent, DialogTitle, TextField, StyleRulesCallback, withStyles, WithStyles, Button, CircularProgress } from '../../../node_modules/@material-ui/core';
 import { COLLECTION_NAME_VALIDATION, COLLECTION_DESCRIPTION_VALIDATION } from '../../validators/create-project/create-project-validator';
-import { COLLECTION_FORM_NAME } from '../../store/collections/updator/collection-updator-action';
+import { COLLECTION_FORM_NAME } from '../../store/collections/updater/collection-updater-action';
 
 type CssRules = 'content' | 'actions' | 'textField' | 'buttonWrapper' | 'saveButton' | 'circularProgress';
 
@@ -128,4 +128,4 @@ export const DialogCollectionUpdate = compose(
                 />
             )
         }
-    );
\ No newline at end of file
+    );
index a91277e996d6fbdecac7617597f6f5c80df48dcc..1374ac41bad7feb8f827b1055d63e5c56b50ff80 100644 (file)
@@ -7,18 +7,18 @@ import { Dispatch } from "redux";
 import { SubmissionError } from "redux-form";
 import { RootState } from "../../store/store";
 import { snackbarActions } from "../../store/snackbar/snackbar-actions";
-import { collectionUpdatorActions, updateCollection } from "../../store/collections/updator/collection-updator-action";
+import { collectionUpdaterActions, updateCollection } from "../../store/collections/updater/collection-updater-action";
 import { dataExplorerActions } from "../../store/data-explorer/data-explorer-action";
 import { PROJECT_PANEL_ID } from "../../views/project-panel/project-panel";
 import { DialogCollectionUpdate } from "../dialog-update/dialog-collection-update";
 
 const mapStateToProps = (state: RootState) => ({
-    open: state.collections.updator.opened
+    open: state.collections.updater.opened
 });
 
 const mapDispatchToProps = (dispatch: Dispatch) => ({
     handleClose: () => {
-        dispatch(collectionUpdatorActions.CLOSE_COLLECTION_UPDATOR());
+        dispatch(collectionUpdaterActions.CLOSE_COLLECTION_UPDATER());
     },
     onSubmit: (data: { name: string, description: string }) => {
         return dispatch<any>(editCollection(data))
@@ -41,4 +41,4 @@ const editCollection = (data: { name: string, description: string }) =>
         });
     };
 
-export const UpdateCollectionDialog = connect(mapStateToProps, mapDispatchToProps)(DialogCollectionUpdate);
\ No newline at end of file
+export const UpdateCollectionDialog = connect(mapStateToProps, mapDispatchToProps)(DialogCollectionUpdate);
index ee49986a76142a6638e0bc529c858221153c6e3b..700f4ad2b107eaa3d5ce8f1728a448d64f157343 100644 (file)
--- a/yarn.lock
+++ b/yarn.lock
     "@types/node" "*"
     "@types/react" "*"
 
+"@types/react-dropzone@4.2.1":
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/@types/react-dropzone/-/react-dropzone-4.2.1.tgz#4a973b63a8a227e263ff4eece053f643220f28fc"
+  dependencies:
+    "@types/react" "*"
+
 "@types/react-redux@6.0.6":
   version "6.0.6"
   resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-6.0.6.tgz#87f1d0a6ea901b93fcaf95fa57641ff64079d277"
@@ -465,6 +471,12 @@ atob@^2.1.1:
   version "2.1.1"
   resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a"
 
+attr-accept@^1.0.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-1.1.3.tgz#48230c79f93790ef2775fcec4f0db0f5db41ca52"
+  dependencies:
+    core-js "^2.5.0"
+
 autoprefixer@7.1.6:
   version "7.1.6"
   resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-7.1.6.tgz#fb933039f74af74a83e71225ce78d9fd58ba84d7"
@@ -6126,6 +6138,13 @@ react-dom@16.4.2:
     object-assign "^4.1.1"
     prop-types "^15.6.0"
 
+react-dropzone@4.2.13:
+  version "4.2.13"
+  resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-4.2.13.tgz#31393c079b4e5ddcc176c095cebc3545d1248b9d"
+  dependencies:
+    attr-accept "^1.0.3"
+    prop-types "^15.5.7"
+
 react-error-overlay@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-4.0.0.tgz#d198408a85b4070937a98667f500c832f86bd5d4"