refs #13856 Merge branch 'origin/13856-upload-component'
authorDaniel Kos <daniel.kos@contractors.roche.com>
Tue, 7 Aug 2018 11:34:15 +0000 (13:34 +0200)
committerDaniel Kos <daniel.kos@contractors.roche.com>
Tue, 7 Aug 2018 11:34:15 +0000 (13:34 +0200)
# Conflicts:
# src/services/services.ts
# src/views-components/dialog-create/dialog-collection-create.tsx
# src/views-components/dialog-update/dialog-collection-update.tsx

Arvados-DCO-1.1-Signed-off-by: Daniel Kos <daniel.kos@contractors.roche.com>

1  2 
src/services/services.ts
src/services/tag-service/tag-service.ts
src/views-components/dialog-create/dialog-collection-create.tsx
src/views-components/dialog-update/dialog-collection-update.tsx

diff --combined src/services/services.ts
index 87c668f2ae4ca3ff3e9b36e0f6bb16d3c51a96e8,6e8d0f94c4e330d8cc88ddfe23af79414c2df31f..e77b5d3aa89b18a5fa8d4e1f3b2de2826f93f523
@@@ -9,19 -9,19 +9,21 @@@ import { LinkService } from "./link-ser
  import { FavoriteService } from "./favorite-service/favorite-service";
  import { AxiosInstance } from "axios";
  import { CollectionService } from "./collection-service/collection-service";
 +import { TagService } from "./tag-service/tag-service";
  import Axios from "axios";
  import { CollectionFilesService } from "./collection-files-service/collection-files-service";
+ import { KeepService } from "./keep-service/keep-service";
  
  export interface ServiceRepository {
      apiClient: AxiosInstance;
  
      authService: AuthService;
+     keepService: KeepService;
      groupsService: GroupsService;
      projectService: ProjectService;
      linkService: LinkService;
      favoriteService: FavoriteService;
 +    tagService: TagService;
      collectionService: CollectionService;
      collectionFilesService: CollectionFilesService;
  }
@@@ -31,23 -31,23 +33,25 @@@ export const createServices = (baseUrl
      apiClient.defaults.baseURL = `${baseUrl}/arvados/v1`;
  
      const authService = new AuthService(apiClient, baseUrl);
+     const keepService = new KeepService(apiClient);
      const groupsService = new GroupsService(apiClient);
      const projectService = new ProjectService(apiClient);
      const linkService = new LinkService(apiClient);
      const favoriteService = new FavoriteService(linkService, groupsService);
-     const collectionService = new CollectionService(apiClient);
+     const collectionService = new CollectionService(apiClient, keepService);
 +    const tagService = new TagService(linkService);
      const collectionFilesService = new CollectionFilesService(collectionService);
  
      return {
          apiClient,
          authService,
+         keepService,
          groupsService,
          projectService,
          linkService,
          favoriteService,
          collectionService,
 +        tagService,
          collectionFilesService
      };
  };
index c3019a650e313b7b6f44bb19290199f0234972ff,0000000000000000000000000000000000000000..084603eb0833a9f64211598acc899e2d96a95288
mode 100644,000000..100644
--- /dev/null
@@@ -1,45 -1,0 +1,45 @@@
-             .create<TagResource>()
 +// Copyright (C) The Arvados Authors. All rights reserved.
 +//
 +// SPDX-License-Identifier: AGPL-3.0
 +
 +import { LinkService } from "../link-service/link-service";
 +import { LinkClass } from "../../models/link";
 +import { FilterBuilder } from "../../common/api/filter-builder";
 +import { TagTailType, TagResource } from "../../models/tag";
 +import { OrderBuilder } from "../../common/api/order-builder";
 +
 +export class TagService {
 +
 +    constructor(private linkService: LinkService) { }
 +
 +    create(uuid: string, data: { key: string; value: string } ) {
 +        return this.linkService
 +            .create({
 +                headUuid: uuid,
 +                tailUuid: TagTailType.COLLECTION,
 +                linkClass: LinkClass.TAG,
 +                name: '',
 +                properties: data
 +            })
 +            .then(tag => tag as TagResource );
 +    }
 +
 +    list(uuid: string) {
 +        const filters = FilterBuilder
- }
++            .create()
 +            .addEqual("headUuid", uuid)
 +            .addEqual("tailUuid", TagTailType.COLLECTION)
 +            .addEqual("linkClass", LinkClass.TAG);
 +
 +        const order = OrderBuilder
 +            .create<TagResource>()
 +            .addAsc('createdAt');
 +
 +        return this.linkService
 +            .list({ filters, order })
 +            .then(results => {
 +                return results.items.map((tag => tag as TagResource ));
 +            });
 +    }
 +
++}
index 874ce138c76e456ff798e3d63edb88a4d3aa79e2,6083b640fe766f045673406565479487e145d1a9..804aae11f72f3e85f69eab01660b121d8a789b5f
@@@ -12,7 -12,11 +12,11 @@@ import DialogContent from '@material-ui
  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 { COLLECTION_NAME_VALIDATION, COLLECTION_DESCRIPTION_VALIDATION } from '../../validators/create-collection/create-collection-validator';
+ import { FileUpload } from "../../components/file-upload/file-upload";
+ import { connect, DispatchProp } from "react-redux";
+ import { RootState } from "../../store/store";
+ import { collectionUploaderActions, UploadFile } from "../../store/collections/uploader/collection-uploader-actions";
  
  type CssRules = "button" | "lastButton" | "formContainer" | "textField" | "createProgress" | "dialogActions";
  
@@@ -40,14 -44,16 +44,16 @@@ const styles: StyleRulesCallback<CssRul
          marginBottom: theme.spacing.unit * 3
      }
  });
  interface DialogCollectionCreateProps {
      open: boolean;
      handleClose: () => void;
-     onSubmit: (data: { name: string, description: string }) => void;
+     onSubmit: (data: { name: string, description: string }, files: UploadFile[]) => void;
      handleSubmit: any;
      submitting: boolean;
      invalid: boolean;
      pristine: boolean;
+     files: UploadFile[];
  }
  
  interface TextFieldProps {
  }
  
  export const DialogCollectionCreate = compose(
+     connect((state: RootState) => ({
+         files: state.collections.uploader
+     })),
      reduxForm({ form: 'collectionCreateDialog' }),
      withStyles(styles))(
-     class DialogCollectionCreate extends React.Component<DialogCollectionCreateProps & WithStyles<CssRules>> {
+     class DialogCollectionCreate extends React.Component<DialogCollectionCreateProps & DispatchProp & WithStyles<CssRules>> {
          render() {
-             const { classes, open, handleClose, handleSubmit, onSubmit, submitting, invalid, pristine } = this.props;
+             const { classes, open, handleClose, handleSubmit, onSubmit, submitting, invalid, pristine, files } = this.props;
+             const busy = submitting || files.reduce(
+                 (prev, curr) => prev + (curr.loaded > 0 && curr.loaded < curr.total ? 1 : 0), 0
+             ) > 0;
              return (
                  <Dialog
                      open={open}
@@@ -73,7 -84,7 +84,7 @@@
                      maxWidth='sm'
                      disableBackdropClick={true}
                      disableEscapeKeyDown={true}>
-                     <form onSubmit={handleSubmit((data: any) => onSubmit(data))}>
+                     <form onSubmit={handleSubmit((data: any) => onSubmit(data, files))}>
                          <DialogTitle id="form-dialog-title">Create a collection</DialogTitle>
                          <DialogContent className={classes.formContainer}>
                              <Field name="name"
                                      validate={COLLECTION_DESCRIPTION_VALIDATION}
                                      className={classes.textField}
                                      label="Description - optional"/>
+                             <FileUpload
+                                 files={files}
+                                 disabled={busy}
+                                 onDrop={files => this.props.dispatch(collectionUploaderActions.SET_UPLOAD_FILES(files))}/>
                          </DialogContent>
                          <DialogActions className={classes.dialogActions}>
                              <Button onClick={handleClose} className={classes.button} color="primary"
-                                     disabled={submitting}>CANCEL</Button>
+                                     disabled={busy}>CANCEL</Button>
                              <Button type="submit"
                                      className={classes.lastButton}
                                      color="primary"
-                                     disabled={invalid || submitting || pristine}
+                                     disabled={invalid || busy || pristine}
                                      variant="contained">
                                  CREATE A COLLECTION
                              </Button>
-                             {submitting && <CircularProgress size={20} className={classes.createProgress}/>}
+                             {busy && <CircularProgress size={20} className={classes.createProgress}/>}
                          </DialogActions>
                      </form>
                  </Dialog>
index 08eee418bdc1f2bf016c0e575e0d751b3d96137c,dc278018e1841ec5ca1b1363db44272251cacc3b..febe1124b2f9f00ca1087086322eb5f1bfcb9ce8
@@@ -7,8 -7,8 +7,8 @@@ import { reduxForm, Field } from 'redux
  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_NAME_VALIDATION, COLLECTION_DESCRIPTION_VALIDATION } from '../../validators/create-collection/create-collection-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 +128,4 @@@ export const DialogCollectionUpdate = c
                  />
              )
          }
-     );
+     );