Merge branch 'master'
authorMichal Klobukowski <michal.klobukowski@contractors.roche.com>
Fri, 3 Aug 2018 07:10:55 +0000 (09:10 +0200)
committerMichal Klobukowski <michal.klobukowski@contractors.roche.com>
Fri, 3 Aug 2018 07:10:55 +0000 (09:10 +0200)
Feature #13855

Arvados-DCO-1.1-Signed-off-by: Michal Klobukowski <michal.klobukowski@contractors.roche.com>

1  2 
src/index.tsx
src/services/services.ts
src/store/collection-panel/collection-panel-action.ts
src/store/details-panel/details-panel-action.ts
src/store/store.ts
src/views/collection-panel/collection-panel.tsx
src/views/workbench/workbench.tsx
yarn.lock

diff --cc src/index.tsx
Simple merge
index a05ad9c2288a7e415c37ce474e91468f6deeeeb8,1f0e23a3c4cad010c505fa24e693d5682ba72cf0..9e1adbf6e4e20d8a1f59637ae4a02f356905dc18
@@@ -7,14 -7,42 +7,43 @@@ import { GroupsService } from "./groups
  import { ProjectService } from "./project-service/project-service";
  import { LinkService } from "./link-service/link-service";
  import { FavoriteService } from "./favorite-service/favorite-service";
 -import { CommonResourceService } from "../common/api/common-resource-service";
 -import { CollectionResource } from "../models/collection";
 -import { Resource } from "../models/resource";
+ import { AxiosInstance } from "axios";
  import { CollectionService } from "./collection-service/collection-service";
+ import Axios from "axios";
 +import { CollectionFilesService } from "./collection-files-service/collection-files-service";
  
- export const authService = new AuthService(authClient, apiClient);
- export const groupsService = new GroupsService(apiClient);
- export const projectService = new ProjectService(apiClient);
- export const collectionService = new CollectionService(apiClient);
- export const collectionFilesService = new CollectionFilesService(collectionService);
- export const linkService = new LinkService(apiClient);
- export const favoriteService = new FavoriteService(linkService, groupsService);
+ export interface ServiceRepository {
+     apiClient: AxiosInstance;
+     authService: AuthService;
+     groupsService: GroupsService;
+     projectService: ProjectService;
+     linkService: LinkService;
+     favoriteService: FavoriteService;
 -    collectionService: CommonResourceService<Resource>;
++    collectionService: CollectionService;
++    collectionFilesService: CollectionFilesService;
+ }
+ export const createServices = (baseUrl: string): ServiceRepository => {
+     const apiClient = Axios.create();
+     apiClient.defaults.baseURL = `${baseUrl}/arvados/v1`;
+     const authService = new AuthService(apiClient, baseUrl);
+     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 collectionFilesService = new CollectionFilesService(collectionService);
+     return {
+         apiClient,
+         authService,
+         groupsService,
+         projectService,
+         linkService,
+         favoriteService,
 -        collectionService
++        collectionService,
++        collectionFilesService
+     };
+ };
index ab2db17d249852dc3b68ef162901dfe858e9f8b9,673f9f02e9ce59b631f336f94844b01d5f0278b2..419f04049b83ffaceff9f4c871c5319487163fa6
@@@ -6,11 -6,8 +6,10 @@@ import { unionize, ofType, UnionOf } fr
  import { Dispatch } from "redux";
  import { ResourceKind } from "../../models/resource";
  import { CollectionResource } from "../../models/collection";
- import { collectionService, collectionFilesService } from "../../services/services";
 +import { collectionPanelFilesAction } from "./collection-panel-files/collection-panel-files-actions";
 +import { createTree } from "../../models/tree";
- import { mapManifestToCollectionFilesTree } from "../../services/collection-files-service/collection-manifest-mapper";
- import { parseKeepManifestText } from "../../services/collection-files-service/collection-manifest-parser";
+ import { RootState } from "../store";
+ import { ServiceRepository } from "../../services/services";
  
  export const collectionPanelActions = unionize({
      LOAD_COLLECTION: ofType<{ uuid: string, kind: ResourceKind }>(),
  export type CollectionPanelAction = UnionOf<typeof collectionPanelActions>;
  
  export const loadCollection = (uuid: string, kind: ResourceKind) =>
-     (dispatch: Dispatch) => {
+     (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
          dispatch(collectionPanelActions.LOAD_COLLECTION({ uuid, kind }));
-         return collectionService
 +        dispatch(collectionPanelFilesAction.SET_COLLECTION_FILES({ files: createTree() }));
+         return services.collectionService
              .get(uuid)
              .then(item => {
 -                dispatch(collectionPanelActions.LOAD_COLLECTION_SUCCESS({ item: item as CollectionResource }));
 +                dispatch(collectionPanelActions.LOAD_COLLECTION_SUCCESS({ item }));
-                 return collectionFilesService.getFiles(item.uuid);
++                return services.collectionFilesService.getFiles(item.uuid);
 +            })
 +            .then(files => {
 +                dispatch(collectionPanelFilesAction.SET_COLLECTION_FILES({ files }));
              });
      };
  
index 03212b9fc915bacfbc08f22d367d393b1f26b14b,cb5a709e3ffe861c36656b84f726b25cc367cf0e..c4acf5aa9b3710fac0a3f61a905132651f8709da
@@@ -3,10 -3,11 +3,10 @@@
  // SPDX-License-Identifier: AGPL-3.0
  
  import { unionize, ofType, UnionOf } from "unionize";
--import { CommonResourceService } from "../../common/api/common-resource-service";
  import { Dispatch } from "redux";
- import { apiClient } from "../../common/api/server-api";
  import { Resource, ResourceKind } from "../../models/resource";
+ import { RootState } from "../store";
+ import { ServiceRepository } from "../../services/services";
  
  export const detailsPanelActions = unionize({
      TOGGLE_DETAILS_PANEL: ofType<{}>(),
  export type DetailsPanelAction = UnionOf<typeof detailsPanelActions>;
  
  export const loadDetails = (uuid: string, kind: ResourceKind) =>
-     (dispatch: Dispatch) => {
 -    (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
++    async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
          dispatch(detailsPanelActions.LOAD_DETAILS({ uuid, kind }));
-         getService(kind)
 -        getService(services, kind)
--            .get(uuid)
--            .then(project => {
--                dispatch(detailsPanelActions.LOAD_DETAILS_SUCCESS({ item: project }));
--            });
++        const item = await getService(services, kind).get(uuid);
++        dispatch(detailsPanelActions.LOAD_DETAILS_SUCCESS({ item }));
      };
  
- const getService = (kind: ResourceKind) => {
+ const getService = (services: ServiceRepository, kind: ResourceKind) => {
      switch (kind) {
          case ResourceKind.PROJECT:
-             return new CommonResourceService(apiClient, "groups");
+             return services.projectService;
          case ResourceKind.COLLECTION:
-             return new CommonResourceService(apiClient, "collections");
+             return services.collectionService;
          default:
-             return new CommonResourceService(apiClient, "");
+             return services.projectService;
      }
  };
  
index 3eda005484124dd14b3955f17f2d49ccb4c8764d,02dcc9b27d6c1dba16404890134920866a948c2a..6e57465cc388a8e3e83d720ff9b9606918482a50
@@@ -23,9 -21,9 +23,10 @@@ import { FAVORITE_PANEL_ID } from "./fa
  import { PROJECT_PANEL_ID } from "./project-panel/project-panel-action";
  import { ProjectPanelMiddlewareService } from "./project-panel/project-panel-middleware-service";
  import { FavoritePanelMiddlewareService } from "./favorite-panel/favorite-panel-middleware-service";
- import { CollectionCreatorState, collectionCreationReducer } from './collections/creator/collection-creator-reducer';
  import { CollectionPanelState, collectionPanelReducer } from './collection-panel/collection-panel-reducer';
 +import { DialogState, dialogReducer } from './dialog/dialog-reducer';
+ import { CollectionsState, collectionsReducer } from './collections/collections-reducer';
+ import { ServiceRepository } from "../services/services";
  
  const composeEnhancers =
      (process.env.NODE_ENV === 'development' &&
@@@ -44,33 -42,31 +45,35 @@@ export interface RootState 
      contextMenu: ContextMenuState;
      favorites: FavoritesState;
      snackbar: SnackbarState;
 +    collectionPanelFiles: CollectionPanelFilesState;
 +    dialog: DialogState;
  }
  
- const rootReducer = combineReducers({
-     auth: authReducer,
-     projects: projectsReducer,
-     collectionCreation: collectionCreationReducer,
-     router: routerReducer,
-     dataExplorer: dataExplorerReducer,
-     sidePanel: sidePanelReducer,
-     collectionPanel: collectionPanelReducer,
-     detailsPanel: detailsPanelReducer,
-     contextMenu: contextMenuReducer,
-     form: formReducer,
-     favorites: favoritesReducer,
-     snackbar: snackbarReducer,
-     collectionPanelFiles: collectionPanelFilesReducer,
-     dialog: dialogReducer
- });
+ export type RootStore = Store<RootState, Action> & { dispatch: Dispatch<any> };
+ export function configureStore(history: History, services: ServiceRepository): RootStore {
 -      const rootReducer = combineReducers({
 -          auth: authReducer(services),
 -          projects: projectsReducer,
++    const rootReducer = combineReducers({
++        auth: authReducer(services),
++        projects: projectsReducer,
+         collections: collectionsReducer,
 -          router: routerReducer,
 -          dataExplorer: dataExplorerReducer,
 -          sidePanel: sidePanelReducer,
 -          collectionPanel: collectionPanelReducer,
 -          detailsPanel: detailsPanelReducer,
 -          contextMenu: contextMenuReducer,
 -          form: formReducer,
 -          favorites: favoritesReducer,
 -          snackbar: snackbarReducer,
 -      });
++        router: routerReducer,
++        dataExplorer: dataExplorerReducer,
++        sidePanel: sidePanelReducer,
++        collectionPanel: collectionPanelReducer,
++        detailsPanel: detailsPanelReducer,
++        contextMenu: contextMenuReducer,
++        form: formReducer,
++        favorites: favoritesReducer,
++        snackbar: snackbarReducer,
++        collectionPanelFiles: collectionPanelFilesReducer,
++        dialog: dialogReducer
++    });
  
- export function configureStore(history: History) {
      const projectPanelMiddleware = dataExplorerMiddleware(
-         new ProjectPanelMiddlewareService(PROJECT_PANEL_ID)
+         new ProjectPanelMiddlewareService(services, PROJECT_PANEL_ID)
      );
      const favoritePanelMiddleware = dataExplorerMiddleware(
-         new FavoritePanelMiddlewareService(FAVORITE_PANEL_ID)
+         new FavoritePanelMiddlewareService(services, FAVORITE_PANEL_ID)
      );
  
      const middlewares: Middleware[] = [
index a7d2682ae61015403ed0b8a10b84f1127fae9c86,21d28b97aa80848b3c58cb808b6a893e138ef41a..05104eecbb2616d149fc54010e39f963d2c9e1c4
@@@ -11,12 -11,12 +11,13 @@@ import { connect } from 'react-redux'
  import { RouteComponentProps } from 'react-router';
  import { ArvadosTheme } from '../../common/custom-theme';
  import { RootState } from '../../store/store';
- import { MoreOptionsIcon, CollectionIcon } from '../../components/icon/icon';
+ import { MoreOptionsIcon, CollectionIcon, CopyIcon } from '../../components/icon/icon';
  import { DetailsAttribute } from '../../components/details-attribute/details-attribute';
  import { CollectionResource } from '../../models/collection';
 +import { CollectionPanelFiles } from '../../views-components/collection-panel-files/collection-panel-files';
+ import * as CopyToClipboard from 'react-copy-to-clipboard';
  
- type CssRules = 'card' | 'iconHeader';
+ type CssRules = 'card' | 'iconHeader' | 'tag' | 'copyIcon';
  
  const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
      card: {
index b543bef7f20cc220cd743c1532925a46239723c0,dcce725b8cbbb213c08ed1f70ca902438d0d87a4..3611d7b10fb12210f9573f9ebf2df41476d62693
@@@ -42,11 -41,11 +41,13 @@@ import { CreateCollectionDialog } from 
  import { CollectionPanel } from '../collection-panel/collection-panel';
  import { loadCollection } from '../../store/collection-panel/collection-panel-action';
  import { getCollectionUrl } from '../../models/collection';
 +import { RemoveDialog } from '../../views-components/remove-dialog/remove-dialog';
 +import { RenameDialog } from '../../views-components/rename-dialog/rename-dialog';
+ import { UpdateCollectionDialog } from '../../views-components/update-collection-dialog/update-collection-dialog.';
+ import { AuthService } from "../../services/auth-service/auth-service";
  
- const drawerWidth = 240;
- const appBarHeight = 100;
+ const DRAWER_WITDH = 240;
+ const APP_BAR_HEIGHT = 100;
  
  type CssRules = 'root' | 'appBar' | 'drawerPaper' | 'content' | 'contentWrapper' | 'toolbar';
  
@@@ -229,8 -232,7 +234,9 @@@ export const Workbench = withStyles(sty
                          <Snackbar />
                          <CreateProjectDialog />
                          <CreateCollectionDialog />
 +                        <RemoveDialog />
 +                        <RenameDialog />
+                         <UpdateCollectionDialog />
                          <CurrentTokenDialog
                              currentToken={this.props.currentToken}
                              open={this.state.isCurrentTokenDialogOpen}
diff --cc yarn.lock
index 1eed5d2fda1e5adb4dff764d193c58d4e664a708,1eed5d2fda1e5adb4dff764d193c58d4e664a708..968562f7d160ce3a154ec11cb965bafdecb26f0f
+++ b/yarn.lock
    version "10.5.2"
    resolved "https://registry.yarnpkg.com/@types/node/-/node-10.5.2.tgz#f19f05314d5421fe37e74153254201a7bf00a707"
  
++"@types/react-copy-to-clipboard@4.2.5":
++  version "4.2.5"
++  resolved "https://registry.yarnpkg.com/@types/react-copy-to-clipboard/-/react-copy-to-clipboard-4.2.5.tgz#bda288b4256288676019b75ca86f1714bbd206d4"
++  dependencies:
++    "@types/react" "*"
++
  "@types/react-dom@16.0.6":
    version "16.0.6"
    resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.0.6.tgz#f1a65a4e7be8ed5d123f8b3b9eacc913e35a1a3c"
@@@ -1817,6 -1817,6 +1823,12 @@@ copy-descriptor@^0.1.0
    version "0.1.1"
    resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
  
++copy-to-clipboard@^3:
++  version "3.0.8"
++  resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.0.8.tgz#f4e82f4a8830dce4666b7eb8ded0c9bcc313aba9"
++  dependencies:
++    toggle-selection "^1.0.3"
++
  core-js@^1.0.0:
    version "1.2.7"
    resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
@@@ -6098,6 -6098,6 +6110,13 @@@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7
      minimist "^1.2.0"
      strip-json-comments "~2.0.1"
  
++react-copy-to-clipboard@5.0.1:
++  version "5.0.1"
++  resolved "https://registry.yarnpkg.com/react-copy-to-clipboard/-/react-copy-to-clipboard-5.0.1.tgz#8eae107bb400be73132ed3b6a7b4fb156090208e"
++  dependencies:
++    copy-to-clipboard "^3"
++    prop-types "^15.5.8"
++
  react-dev-utils@^5.0.1:
    version "5.0.1"
    resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-5.0.1.tgz#1f396e161fe44b595db1b186a40067289bf06613"
@@@ -7406,6 -7406,6 +7425,10 @@@ to-regex@^3.0.1, to-regex@^3.0.2
      regex-not "^1.0.2"
      safe-regex "^1.1.0"
  
++toggle-selection@^1.0.3:
++  version "1.0.6"
++  resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32"
++
  toposort@^1.0.0:
    version "1.0.7"
    resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.7.tgz#2e68442d9f64ec720b8cc89e6443ac6caa950029"