[ARVADOS-WORKBENCH2] created: 1.1.4-291-g99d2472

Git user git at public.curoverse.com
Fri Jul 13 07:40:09 EDT 2018


        at  99d2472afc89ca78a4fef46ac08ce520b3bcf17b (commit)


commit 99d2472afc89ca78a4fef46ac08ce520b3bcf17b
Author: Michal Klobukowski <michal.klobukowski at contractors.roche.com>
Date:   Fri Jul 13 13:39:58 2018 +0200

    Extract context-menu view component
    
    Feature #13805
    
    Arvados-DCO-1.1-Signed-off-by: Michal Klobukowski <michal.klobukowski at contractors.roche.com>

diff --git a/src/components/context-menu/context-menu.tsx b/src/components/context-menu/context-menu.tsx
index c892ba2..5626181 100644
--- a/src/components/context-menu/context-menu.tsx
+++ b/src/components/context-menu/context-menu.tsx
@@ -13,14 +13,14 @@ export interface ContextMenuAction {
 
 export type ContextMenuActionGroup = ContextMenuAction[];
 
-export interface ContextMenuProps<T> {
+export interface ContextMenuProps {
     anchorEl?: HTMLElement;
     actions: ContextMenuActionGroup[];
     onActionClick: (action: ContextMenuAction) => void;
     onClose: () => void;
 }
 
-export default class ContextMenu<T> extends React.PureComponent<ContextMenuProps<T>> {
+export default class ContextMenu extends React.PureComponent<ContextMenuProps> {
     render() {
         const { anchorEl, actions, onClose, onActionClick } = this.props;
         return <Popover
diff --git a/src/components/popover/helpers.ts b/src/components/popover/helpers.ts
index 13f74a6..f2be98c 100644
--- a/src/components/popover/helpers.ts
+++ b/src/components/popover/helpers.ts
@@ -4,13 +4,13 @@
 
 import { PopoverOrigin } from "@material-ui/core/Popover";
 
-export const mockAnchorFromMouseEvent = (event: React.MouseEvent<HTMLElement>) => {
+export const createAnchorAt = (position: {x: number, y: number}) => {
     const el = document.createElement('div');
     const clientRect = {
-        left: event.clientX,
-        right: event.clientX,
-        top: event.clientY,
-        bottom: event.clientY,
+        left: position.x,
+        right: position.x,
+        top: position.y,
+        bottom: position.y,
         width: 0,
         height: 0
     };
diff --git a/src/store/context-menu/context-menu-actions.ts b/src/store/context-menu/context-menu-actions.ts
index 89d6524..8630f9c 100644
--- a/src/store/context-menu/context-menu-actions.ts
+++ b/src/store/context-menu/context-menu-actions.ts
@@ -2,14 +2,16 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-// import { default as unionize, ofType, UnionOf } from "unionize";
+import { default as unionize, ofType, UnionOf } from "unionize";
+import { ContextMenuPosition, ContextMenuResource } from "./context-menu-reducer";
 
-// const actions = unionize({
-//     OPEN_CONTEXT_MENU: ofType<{position: {x: number, y: number}}>()
-// }, {
-//     tag: 'type',
-//     value: 'payload'
-// });
+const actions = unionize({
+    OPEN_CONTEXT_MENU: ofType<{ position: ContextMenuPosition, resource: ContextMenuResource }>(),
+    CLOSE_CONTEXT_MENU: ofType<{}>()
+}, {
+        tag: 'type',
+        value: 'payload'
+    });
 
-// export type ContextMenuAction = UnionOf<typeof actions>;
-// export default actions;
\ No newline at end of file
+export type ContextMenuAction = UnionOf<typeof actions>;
+export default actions;
\ No newline at end of file
diff --git a/src/store/context-menu/context-menu-reducer.ts b/src/store/context-menu/context-menu-reducer.ts
index 9a825a5..69f9c9a 100644
--- a/src/store/context-menu/context-menu-reducer.ts
+++ b/src/store/context-menu/context-menu-reducer.ts
@@ -2,31 +2,33 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-// import actions, { DetailsPanelAction } from "./details-panel-action";
-// import { Resource, ResourceKind } from "../../models/resource";
+import { ResourceKind } from "../../models/resource";
+import actions, { ContextMenuAction } from "./context-menu-actions";
 
-// export interface ContextMenuState {
-//     position: {
-//         x: number;
-//         y: number;
-//     },
-//     resource: {
-//         uuid: string;
-//         kind: ResourceKind.
-//     }
-// }
+export interface ContextMenuState {
+    position: ContextMenuPosition;
+    resource?: ContextMenuResource;
+}
 
-// const initialState = {
-//     item: null,
-//     isOpened: false
-// };
+export interface ContextMenuPosition {
+    x: number;
+    y: number;
+}
 
-// const reducer = (state: DetailsPanelState = initialState, action: DetailsPanelAction) =>
-//     actions.match(action, {
-//         default: () => state,
-//         LOAD_DETAILS: () => state,
-//         LOAD_DETAILS_SUCCESS: ({ item }) => ({ ...state, item }),
-//         TOGGLE_DETAILS_PANEL: () => ({ ...state, isOpened: !state.isOpened })
-//     });
+export interface ContextMenuResource {
+    uuid: string;
+    kind: ResourceKind;
+}
 
-// export default reducer;
+const initialState = {
+    position: { x: 0, y: 0 }
+};
+
+const reducer = (state: ContextMenuState = initialState, action: ContextMenuAction) =>
+    actions.match(action, {
+        default: () => state,
+        OPEN_CONTEXT_MENU: ({resource, position}) => ({ resource, position }),
+        CLOSE_CONTEXT_MENU: () => ({ position: state.position })
+    });
+
+export default reducer;
diff --git a/src/store/store.ts b/src/store/store.ts
index 36f9203..130028a 100644
--- a/src/store/store.ts
+++ b/src/store/store.ts
@@ -13,6 +13,7 @@ import authReducer, { AuthState } from "./auth/auth-reducer";
 import dataExplorerReducer, { DataExplorerState } from './data-explorer/data-explorer-reducer';
 import { projectPanelMiddleware } from '../store/project-panel/project-panel-middleware';
 import detailsPanelReducer, { DetailsPanelState } from './details-panel/details-panel-reducer';
+import contextMenuReducer, { ContextMenuState } from './context-menu/context-menu-reducer';
 
 const composeEnhancers =
     (process.env.NODE_ENV === 'development' &&
@@ -26,6 +27,7 @@ export interface RootState {
     dataExplorer: DataExplorerState;
     sidePanel: SidePanelState;
     detailsPanel: DetailsPanelState;
+    contextMenu: ContextMenuState;
 }
 
 const rootReducer = combineReducers({
@@ -34,7 +36,8 @@ const rootReducer = combineReducers({
     router: routerReducer,
     dataExplorer: dataExplorerReducer,
     sidePanel: sidePanelReducer,
-    detailsPanel: detailsPanelReducer
+    detailsPanel: detailsPanelReducer,
+    contextMenu: contextMenuReducer
 });
 
 
diff --git a/src/views-components/context-menu/context-menu.tsx b/src/views-components/context-menu/context-menu.tsx
new file mode 100644
index 0000000..21d851d
--- /dev/null
+++ b/src/views-components/context-menu/context-menu.tsx
@@ -0,0 +1,74 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { connect, Dispatch, DispatchProp } from "react-redux";
+import { RootState } from "../../store/store";
+import actions from "../../store/context-menu/context-menu-actions";
+import ContextMenu, { ContextMenuAction, ContextMenuProps } from "../../components/context-menu/context-menu";
+import { createAnchorAt } from "../../components/popover/helpers";
+import projectActions from "../../store/project/project-action";
+import { ContextMenuResource } from "../../store/context-menu/context-menu-reducer";
+
+
+type DataProps = Pick<ContextMenuProps, "anchorEl" | "actions"> & { resource?: ContextMenuResource };
+const mapStateToProps = (state: RootState): DataProps => {
+    const { position, resource } = state.contextMenu;
+    return {
+        anchorEl: resource ? createAnchorAt(position) : undefined,
+        actions: contextMenuActions,
+        resource
+    };
+};
+
+type ActionProps = Pick<ContextMenuProps, "onClose"> & {onActionClick: (action: ContextMenuAction, resource?: ContextMenuResource) => void};
+const mapDispatchToProps = (dispatch: Dispatch): ActionProps => ({
+    onClose: () => {
+        dispatch(actions.CLOSE_CONTEXT_MENU());
+    },
+    onActionClick: (action: ContextMenuAction, resource?: ContextMenuResource) => {
+        dispatch(actions.CLOSE_CONTEXT_MENU());
+        if (resource) {
+            if (action.name === "New project") {
+                dispatch(projectActions.OPEN_PROJECT_CREATOR({ ownerUuid: resource.uuid }));
+            }
+        }
+    }
+});
+
+const mergeProps = ({ resource, ...dataProps }: DataProps, actionProps: ActionProps): ContextMenuProps => ({
+    ...dataProps,
+    ...actionProps,
+    onActionClick: (action: ContextMenuAction) => {
+        actionProps.onActionClick(action, resource);
+    }
+});
+
+export default connect(mapStateToProps, mapDispatchToProps, mergeProps)(ContextMenu);
+
+const contextMenuActions = [[{
+    icon: "fas fa-plus fa-fw",
+    name: "New project"
+}, {
+    icon: "fas fa-users fa-fw",
+    name: "Share"
+}, {
+    icon: "fas fa-sign-out-alt fa-fw",
+    name: "Move to"
+}, {
+    icon: "fas fa-star fa-fw",
+    name: "Add to favourite"
+}, {
+    icon: "fas fa-edit fa-fw",
+    name: "Rename"
+}, {
+    icon: "fas fa-copy fa-fw",
+    name: "Make a copy"
+}, {
+    icon: "fas fa-download fa-fw",
+    name: "Download"
+}], [{
+    icon: "fas fa-trash-alt fa-fw",
+    name: "Remove"
+}
+]];
\ No newline at end of file
diff --git a/src/views/workbench/workbench.tsx b/src/views/workbench/workbench.tsx
index 6972b2f..afd9dfd 100644
--- a/src/views/workbench/workbench.tsx
+++ b/src/views/workbench/workbench.tsx
@@ -26,12 +26,12 @@ import projectActions from "../../store/project/project-action";
 import ProjectPanel from "../project-panel/project-panel";
 import DetailsPanel from '../../views-components/details-panel/details-panel';
 import { ArvadosTheme } from '../../common/custom-theme';
-import ContextMenu, { ContextMenuAction } from '../../components/context-menu/context-menu';
-import { mockAnchorFromMouseEvent } from '../../components/popover/helpers';
+import ContextMenu from "../../views-components/context-menu/context-menu";
 import CreateProjectDialog from "../../views-components/create-project-dialog/create-project-dialog";
 import { authService } from '../../services/services';
 
 import detailsPanelActions, { loadDetails } from "../../store/details-panel/details-panel-action";
+import contextMenuActions from "../../store/context-menu/context-menu-actions";
 import { SidePanelIdentifiers } from '../../store/side-panel/side-panel-reducer';
 import { ProjectResource } from '../../models/project';
 import { ResourceKind } from '../../models/resource';
@@ -98,10 +98,6 @@ interface NavMenuItem extends MainAppBarMenuItem {
 }
 
 interface WorkbenchState {
-    contextMenu: {
-        anchorEl?: HTMLElement;
-        itemUuid?: string;
-    };
     anchorEl: any;
     searchText: string;
     menuItems: {
@@ -114,10 +110,6 @@ interface WorkbenchState {
 
 class Workbench extends React.Component<WorkbenchProps, WorkbenchState> {
     state = {
-        contextMenu: {
-            anchorEl: undefined,
-            itemUuid: undefined
-        },
         isCreationDialogOpen: false,
         anchorEl: null,
         searchText: "",
@@ -177,30 +169,18 @@ class Workbench extends React.Component<WorkbenchProps, WorkbenchState> {
     }
 
     handleCreationDialogOpen = (itemUuid: string) => {
-        this.closeContextMenu();
         this.props.dispatch(projectActions.OPEN_PROJECT_CREATOR({ ownerUuid: itemUuid }));
     }
 
 
     openContextMenu = (event: React.MouseEvent<HTMLElement>, itemUuid: string) => {
         event.preventDefault();
-        this.setState({
-            contextMenu: {
-                anchorEl: mockAnchorFromMouseEvent(event),
-                itemUuid
-            }
-        });
-    }
-
-    closeContextMenu = () => {
-        this.setState({ contextMenu: {} });
-    }
-
-    openCreateDialog = (item: ContextMenuAction) => {
-        const { itemUuid } = this.state.contextMenu;
-        if (item.openCreateDialog && itemUuid) {
-            this.handleCreationDialogOpen(itemUuid);
-        }
+        this.props.dispatch(
+            contextMenuActions.OPEN_CONTEXT_MENU({
+                position: { x: event.clientX, y: event.clientY },
+                resource: { uuid: itemUuid, kind: ResourceKind.Project }
+            })
+        );
     }
 
     render() {
@@ -253,11 +233,7 @@ class Workbench extends React.Component<WorkbenchProps, WorkbenchState> {
                     </div>
                     <DetailsPanel />
                 </main>
-                <ContextMenu
-                    anchorEl={this.state.contextMenu.anchorEl}
-                    actions={contextMenuActions}
-                    onActionClick={this.openCreateDialog}
-                    onClose={this.closeContextMenu} />
+                <ContextMenu />
                 <CreateProjectDialog />
             </div>
         );
@@ -277,34 +253,6 @@ class Workbench extends React.Component<WorkbenchProps, WorkbenchState> {
         {...props} />
 }
 
-const contextMenuActions = [[{
-    icon: "fas fa-plus fa-fw",
-    name: "New project",
-    openCreateDialog: true
-}, {
-    icon: "fas fa-users fa-fw",
-    name: "Share"
-}, {
-    icon: "fas fa-sign-out-alt fa-fw",
-    name: "Move to"
-}, {
-    icon: "fas fa-star fa-fw",
-    name: "Add to favourite"
-}, {
-    icon: "fas fa-edit fa-fw",
-    name: "Rename"
-}, {
-    icon: "fas fa-copy fa-fw",
-    name: "Make a copy"
-}, {
-    icon: "fas fa-download fa-fw",
-    name: "Download"
-}], [{
-    icon: "fas fa-trash-alt fa-fw",
-    name: "Remove"
-}
-]];
-
 export default connect<WorkbenchDataProps>(
     (state: RootState) => ({
         projects: state.projects.items,

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list