[ARVADOS-WORKBENCH2] updated: 1.2.0-132-g1e32e61
Git user
git at public.curoverse.com
Sat Aug 25 16:48:35 EDT 2018
Summary of changes:
src/store/breadcrumbs/breadcrumbs-actions.ts | 46 ++++++++++++++++++++++
src/store/navigation/navigation-action.ts | 25 ++++++++----
.../side-panel-tree/side-panel-tree-actions.ts | 26 +++++++++---
src/store/side-panel/side-panel-action.ts | 4 +-
src/store/tree-picker/tree-picker.ts | 7 ++--
src/views-components/breadcrumbs/breadcrumbs.ts | 43 +++++---------------
src/views-components/main-app-bar/main-app-bar.tsx | 15 +++----
src/views/favorite-panel/favorite-panel.tsx | 4 +-
src/views/project-panel/project-panel.tsx | 6 +--
src/views/workbench/workbench.tsx | 14 ++++---
10 files changed, 115 insertions(+), 75 deletions(-)
create mode 100644 src/store/breadcrumbs/breadcrumbs-actions.ts
via 1e32e6134cd53c30cd8a9410572a443b37f76f2e (commit)
from 1c0f11ed17dea5be97e8ca63385f979925f1fb08 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
commit 1e32e6134cd53c30cd8a9410572a443b37f76f2e
Author: Michal Klobukowski <michal.klobukowski at contractors.roche.com>
Date: Sat Aug 25 22:48:14 2018 +0200
Create breadcrumbs actions
Feature #14102
Arvados-DCO-1.1-Signed-off-by: Michal Klobukowski <michal.klobukowski at contractors.roche.com>
diff --git a/src/store/breadcrumbs/breadcrumbs-actions.ts b/src/store/breadcrumbs/breadcrumbs-actions.ts
new file mode 100644
index 0000000..254a8d3
--- /dev/null
+++ b/src/store/breadcrumbs/breadcrumbs-actions.ts
@@ -0,0 +1,46 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { Dispatch } from 'redux';
+import { RootState } from '~/store/store';
+import { Breadcrumb } from '~/components/breadcrumbs/breadcrumbs';
+import { getResource } from '~/store/resources/resources';
+import { TreePicker } from '../tree-picker/tree-picker';
+import { getSidePanelTreeBranch } from '../side-panel-tree/side-panel-tree-actions';
+import { propertiesActions } from '../properties/properties-actions';
+
+export const BREADCRUMBS = 'breadcrumbs';
+
+export interface ResourceBreadcrumb extends Breadcrumb {
+ uuid: string;
+}
+
+export const setBreadcrumbs = (breadcrumbs: Breadcrumb[]) =>
+ propertiesActions.SET_PROPERTY({ key: BREADCRUMBS, value: breadcrumbs });
+
+const getSidePanelTreeBreadcrumbs = (uuid: string) => (treePicker: TreePicker): ResourceBreadcrumb[] => {
+ const nodes = getSidePanelTreeBranch(uuid)(treePicker);
+ return nodes.map(node =>
+ typeof node.value === 'string'
+ ? { label: node.value, uuid: node.nodeId }
+ : { label: node.value.name, uuid: node.value.uuid });
+};
+
+export const setSidePanelBreadcrumbs = (uuid: string) =>
+ (dispatch: Dispatch, getState: () => RootState) => {
+ const { treePicker } = getState();
+ const breadcrumbs = getSidePanelTreeBreadcrumbs(uuid)(treePicker);
+ dispatch(setBreadcrumbs(breadcrumbs));
+ };
+
+export const setProjectBreadcrumbs = setSidePanelBreadcrumbs;
+
+export const setCollectionBreadcrumbs = (collectionUuid: string) =>
+ (dispatch: Dispatch, getState: () => RootState) => {
+ const { resources } = getState();
+ const collection = getResource(collectionUuid)(resources);
+ if (collection) {
+ dispatch<any>(setProjectBreadcrumbs(collection.ownerUuid));
+ }
+ };
diff --git a/src/store/navigation/navigation-action.ts b/src/store/navigation/navigation-action.ts
index db8efbf..b5dc5e9 100644
--- a/src/store/navigation/navigation-action.ts
+++ b/src/store/navigation/navigation-action.ts
@@ -5,7 +5,7 @@
import { Dispatch, compose } from 'redux';
import { push } from "react-router-redux";
import { RootState } from "../store";
-import { ResourceKind, Resource } from '~/models/resource';
+import { ResourceKind, Resource, extractUuidKind } from '~/models/resource';
import { getCollectionUrl } from "~/models/collection";
import { getProjectUrl } from "~/models/project";
import { getResource } from '~/store/resources/resources';
@@ -23,12 +23,18 @@ import { favoritePanelActions } from '~/store/favorite-panel/favorite-panel-acti
import { projectPanelColumns } from '~/views/project-panel/project-panel';
import { favoritePanelColumns } from '~/views/favorite-panel/favorite-panel';
import { matchRootRoute } from '~/routes/routes';
+import { setCollectionBreadcrumbs, setProjectBreadcrumbs, setSidePanelBreadcrumbs } from '../breadcrumbs/breadcrumbs-actions';
-export const navigateToResource = (uuid: string) =>
+export const navigateTo = (uuid: string) =>
async (dispatch: Dispatch, getState: () => RootState) => {
- const resource = getResource(uuid)(getState().resources);
- if (resource) {
- dispatch<any>(getResourceNavigationAction(resource));
+ const kind = extractUuidKind(uuid);
+ if (kind === ResourceKind.PROJECT || kind === ResourceKind.USER) {
+ dispatch<any>(navigateToProject(uuid));
+ } else if (kind === ResourceKind.COLLECTION) {
+ dispatch<any>(navigateToCollection(uuid));
+ }
+ if (uuid === SidePanelTreeCategory.FAVORITES) {
+ dispatch<any>(navigateToFavorites);
}
};
@@ -74,14 +80,16 @@ export const loadFavorites = () =>
async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
dispatch<any>(activateSidePanelTreeItem(SidePanelTreeCategory.FAVORITES));
dispatch<any>(loadFavoritePanel());
+ dispatch<any>(setSidePanelBreadcrumbs(SidePanelTreeCategory.FAVORITES));
};
export const navigateToProject = compose(push, getProjectUrl);
export const loadProject = (uuid: string) =>
- (dispatch: Dispatch) => {
- dispatch<any>(activateSidePanelTreeItem(uuid));
+ async (dispatch: Dispatch) => {
+ await dispatch<any>(activateSidePanelTreeItem(uuid));
+ dispatch<any>(setProjectBreadcrumbs(uuid));
dispatch<any>(openProjectPanel(uuid));
dispatch(loadDetailsPanel(uuid));
};
@@ -91,7 +99,8 @@ export const navigateToCollection = compose(push, getCollectionUrl);
export const loadCollection = (uuid: string) =>
async (dispatch: Dispatch) => {
const collection = await dispatch<any>(loadCollectionPanel(uuid));
- dispatch<any>(activateSidePanelTreeItem(collection.ownerUuid));
+ await dispatch<any>(activateSidePanelTreeItem(collection.ownerUuid));
+ dispatch<any>(setCollectionBreadcrumbs(collection.uuid));
dispatch(loadDetailsPanel(uuid));
};
diff --git a/src/store/side-panel-tree/side-panel-tree-actions.ts b/src/store/side-panel-tree/side-panel-tree-actions.ts
index 268f1e6..2fe5aba 100644
--- a/src/store/side-panel-tree/side-panel-tree-actions.ts
+++ b/src/store/side-panel-tree/side-panel-tree-actions.ts
@@ -4,14 +4,15 @@
import { Dispatch } from 'redux';
import { treePickerActions } from "~/store/tree-picker/tree-picker-actions";
-import { createTreePickerNode } from '~/store/tree-picker/tree-picker';
+import { createTreePickerNode, TreePickerNode } from '~/store/tree-picker/tree-picker';
import { RootState } from '../store';
import { ServiceRepository } from '~/services/services';
import { FilterBuilder } from '~/common/api/filter-builder';
import { resourcesActions } from '../resources/resources-actions';
-import { getNodeValue } from '../../models/tree';
-import { getTreePicker } from '../tree-picker/tree-picker';
+import { getTreePicker, TreePicker } from '../tree-picker/tree-picker';
import { TreeItemStatus } from "~/components/tree/tree";
+import { getNodeAncestors, getNodeValue } from '~/models/tree';
+import { ProjectResource } from '~/models/project';
export enum SidePanelTreeCategory {
PROJECTS = 'Projects',
@@ -24,6 +25,21 @@ export enum SidePanelTreeCategory {
export const SIDE_PANEL_TREE = 'sidePanelTree';
+export const getSidePanelTree = (treePicker: TreePicker) =>
+ getTreePicker<ProjectResource | string>(SIDE_PANEL_TREE)(treePicker);
+
+export const getSidePanelTreeBranch = (uuid: string) => (treePicker: TreePicker): Array<TreePickerNode<ProjectResource | string>> => {
+ const tree = getSidePanelTree(treePicker);
+ if (tree) {
+ const ancestors = getNodeAncestors(uuid)(tree).map(node => node.value);
+ const node = getNodeValue(uuid)(tree);
+ if (node) {
+ return [...ancestors, node];
+ }
+ }
+ return [];
+};
+
const SIDE_PANEL_CATEGORIES = [
SidePanelTreeCategory.SHARED_WITH_ME,
SidePanelTreeCategory.WORKFLOWS,
@@ -77,7 +93,7 @@ export const activateSidePanelTreeItem = (nodeId: string) =>
dispatch(treePickerActions.TOGGLE_TREE_PICKER_NODE_SELECT({ nodeId, pickerId: SIDE_PANEL_TREE }));
}
if (!isSidePanelTreeCategory(nodeId)) {
- dispatch<any>(activateSidePanelTreeProject(nodeId));
+ await dispatch<any>(activateSidePanelTreeProject(nodeId));
}
};
@@ -90,7 +106,7 @@ export const activateSidePanelTreeProject = (nodeId: string) =>
dispatch<any>(toggleSidePanelTreeItemCollapse(nodeId));
}
} else if (node === undefined) {
- dispatch<any>(activateSidePanelTreeBranch(nodeId));
+ await dispatch<any>(activateSidePanelTreeBranch(nodeId));
}
};
diff --git a/src/store/side-panel/side-panel-action.ts b/src/store/side-panel/side-panel-action.ts
index 4fc745b..8c7ef4a 100644
--- a/src/store/side-panel/side-panel-action.ts
+++ b/src/store/side-panel/side-panel-action.ts
@@ -4,7 +4,7 @@
import { Dispatch } from 'redux';
import { isSidePanelTreeCategory, SidePanelTreeCategory } from '~/store/side-panel-tree/side-panel-tree-actions';
-import { navigateToFavorites, navigateToResource } from '../navigation/navigation-action';
+import { navigateToFavorites, navigateTo } from '../navigation/navigation-action';
import { snackbarActions } from '~/store/snackbar/snackbar-actions';
export const navigateFromSidePanel = (id: string) =>
@@ -12,7 +12,7 @@ export const navigateFromSidePanel = (id: string) =>
if (isSidePanelTreeCategory(id)) {
dispatch<any>(getSidePanelTreeCategoryAction(id));
} else {
- dispatch<any>(navigateToResource(id));
+ dispatch<any>(navigateTo(id));
}
};
diff --git a/src/store/tree-picker/tree-picker.ts b/src/store/tree-picker/tree-picker.ts
index fd104fe..259a4b8 100644
--- a/src/store/tree-picker/tree-picker.ts
+++ b/src/store/tree-picker/tree-picker.ts
@@ -4,13 +4,12 @@
import { Tree } from "~/models/tree";
import { TreeItemStatus } from "~/components/tree/tree";
-import { RootState } from '~/store/store';
export type TreePicker = { [key: string]: Tree<TreePickerNode> };
-export interface TreePickerNode {
+export interface TreePickerNode<Value = any> {
nodeId: string;
- value: any;
+ value: Value;
selected: boolean;
collapsed: boolean;
status: TreeItemStatus;
@@ -23,4 +22,4 @@ export const createTreePickerNode = (data: { nodeId: string, value: any }) => ({
status: TreeItemStatus.INITIAL
});
-export const getTreePicker = (id: string) => (state: TreePicker): Tree<TreePickerNode> | undefined => state[id];
\ No newline at end of file
+export const getTreePicker = <Value = {}>(id: string) => (state: TreePicker): Tree<TreePickerNode<Value>> | undefined => state[id];
\ No newline at end of file
diff --git a/src/views-components/breadcrumbs/breadcrumbs.ts b/src/views-components/breadcrumbs/breadcrumbs.ts
index 306b29e..69eb9e3 100644
--- a/src/views-components/breadcrumbs/breadcrumbs.ts
+++ b/src/views-components/breadcrumbs/breadcrumbs.ts
@@ -5,50 +5,25 @@
import { connect } from "react-redux";
import { Breadcrumbs as BreadcrumbsComponent, BreadcrumbsProps } from '~/components/breadcrumbs/breadcrumbs';
import { RootState } from '~/store/store';
-import { Breadcrumb } from '~/components/breadcrumbs/breadcrumbs';
-import { matchProjectRoute } from '~/routes/routes';
-import { getTreePicker } from '~/store/tree-picker/tree-picker';
-import { SIDE_PANEL_TREE } from '~/store/side-panel-tree/side-panel-tree-actions';
-import { getNodeAncestors, getNode } from '~/models/tree';
import { Dispatch } from 'redux';
-import { navigateToResource } from '~/store/navigation/navigation-action';
+import { navigateTo } from '~/store/navigation/navigation-action';
+import { getProperty } from '../../store/properties/properties';
+import { ResourceBreadcrumb, BREADCRUMBS } from '../../store/breadcrumbs/breadcrumbs-actions';
+
-interface ResourceBreadcrumb extends Breadcrumb {
- uuid: string;
-}
type BreadcrumbsDataProps = Pick<BreadcrumbsProps, 'items'>;
type BreadcrumbsActionProps = Pick<BreadcrumbsProps, 'onClick' | 'onContextMenu'>;
-const memoizedMapStateToProps = () => {
- let items: ResourceBreadcrumb[] = [];
- return ({ router, treePicker }: RootState): BreadcrumbsDataProps => {
- if (router.location) {
- const projectMatch = matchProjectRoute(location.pathname);
- const collectionMatch = matchProjectRoute(location.pathname);
- const uuid = projectMatch && projectMatch.params.id
- || collectionMatch && collectionMatch.params.id
- || '';
- const tree = getTreePicker(SIDE_PANEL_TREE)(treePicker);
- if (tree) {
- const ancestors = getNodeAncestors(uuid)(tree);
- const node = getNode(uuid)(tree);
- const nodes = node ? [...ancestors, node] : ancestors;
- items = nodes.map(({ value }) =>
- typeof value.value === 'string'
- ? { label: value.value, uuid: value.nodeId }
- : { label: value.value.name, uuid: value.value.uuid });
- }
- }
- return { items };
- };
-};
+const mapStateToProps = () => ({ properties }: RootState): BreadcrumbsDataProps => ({
+ items: getProperty<ResourceBreadcrumb[]>(BREADCRUMBS)(properties) || []
+});
const mapDispatchToProps = (dispatch: Dispatch): BreadcrumbsActionProps => ({
onClick: ({ uuid }: ResourceBreadcrumb) => {
- dispatch<any>(navigateToResource(uuid));
+ dispatch<any>(navigateTo(uuid));
},
onContextMenu: () => { return; }
});
-export const Breadcrumbs = connect(memoizedMapStateToProps(), mapDispatchToProps)(BreadcrumbsComponent);
\ No newline at end of file
+export const Breadcrumbs = connect(mapStateToProps(), mapDispatchToProps)(BreadcrumbsComponent);
\ No newline at end of file
diff --git a/src/views-components/main-app-bar/main-app-bar.tsx b/src/views-components/main-app-bar/main-app-bar.tsx
index 54d6a5d..4c16754 100644
--- a/src/views-components/main-app-bar/main-app-bar.tsx
+++ b/src/views-components/main-app-bar/main-app-bar.tsx
@@ -23,7 +23,7 @@ export interface MainAppBarMenuItems {
interface MainAppBarDataProps {
searchText: string;
searchDebounce?: number;
- breadcrumbs: Breadcrumb[];
+ breadcrumbs: React.ComponentType<any>;
user?: User;
menuItems: MainAppBarMenuItems;
buildInfo: string;
@@ -68,15 +68,10 @@ export const MainAppBar: React.SFC<MainAppBarProps> = (props) => {
</Grid>
</Toolbar>
<Toolbar >
- {
- props.user && <Breadcrumbs
- items={props.breadcrumbs}
- onClick={props.onBreadcrumbClick}
- onContextMenu={props.onContextMenu} />
- }
- { props.user && <IconButton color="inherit" onClick={props.onDetailsPanelToggle}>
- <DetailsIcon />
- </IconButton>
+ {props.user && <props.breadcrumbs />}
+ {props.user && <IconButton color="inherit" onClick={props.onDetailsPanelToggle}>
+ <DetailsIcon />
+ </IconButton>
}
</Toolbar>
</AppBar>;
diff --git a/src/views/favorite-panel/favorite-panel.tsx b/src/views/favorite-panel/favorite-panel.tsx
index cdfe970..3fd33ae 100644
--- a/src/views/favorite-panel/favorite-panel.tsx
+++ b/src/views/favorite-panel/favorite-panel.tsx
@@ -22,7 +22,7 @@ import { Dispatch } from 'redux';
import { contextMenuActions } from '~/store/context-menu/context-menu-actions';
import { ContextMenuKind } from '~/views-components/context-menu/context-menu';
import { loadDetailsPanel } from '../../store/details-panel/details-panel-action';
-import { navigateToResource } from '~/store/navigation/navigation-action';
+import { navigateTo } from '~/store/navigation/navigation-action';
type CssRules = "toolbar" | "button";
@@ -164,7 +164,7 @@ const mapDispatchToProps = (dispatch: Dispatch): FavoritePanelActionProps => ({
dispatch<any>(loadDetailsPanel(resourceUuid));
},
onItemDoubleClick: uuid => {
- dispatch<any>(navigateToResource(uuid));
+ dispatch<any>(navigateTo(uuid));
}
});
diff --git a/src/views/project-panel/project-panel.tsx b/src/views/project-panel/project-panel.tsx
index e1c9d83..f9dcc39 100644
--- a/src/views/project-panel/project-panel.tsx
+++ b/src/views/project-panel/project-panel.tsx
@@ -28,10 +28,9 @@ import { openProjectCreator } from '~/store/project/project-action';
import { reset } from 'redux-form';
import { COLLECTION_CREATE_DIALOG } from '~/views-components/dialog-create/dialog-collection-create';
import { collectionCreateActions } from '~/store/collections/creator/collection-creator-action';
-import { navigateToResource } from '~/store/navigation/navigation-action';
+import { navigateTo } from '~/store/navigation/navigation-action';
import { getProperty } from '~/store/properties/properties';
import { PROJECT_PANEL_CURRENT_UUID } from '~/store/project-panel/project-panel-action';
-import { Breadcrumbs } from '~/views-components/breadcrumbs/breadcrumbs';
type CssRules = 'root' | "toolbar" | "button";
@@ -182,7 +181,6 @@ export const ProjectPanel = withStyles(styles)(
New project
</Button>
</div>
- <Breadcrumbs />
<DataExplorer
id={PROJECT_PANEL_ID}
onRowClick={this.handleRowClick}
@@ -232,7 +230,7 @@ export const ProjectPanel = withStyles(styles)(
}
handleRowDoubleClick = (uuid: string) => {
- this.props.dispatch<any>(navigateToResource(uuid));
+ this.props.dispatch<any>(navigateTo(uuid));
}
handleRowClick = (uuid: string) => {
diff --git a/src/views/workbench/workbench.tsx b/src/views/workbench/workbench.tsx
index 8d8d937..a4defc1 100644
--- a/src/views/workbench/workbench.tsx
+++ b/src/views/workbench/workbench.tsx
@@ -5,7 +5,7 @@
import * as React from 'react';
import { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core/styles';
import { connect, DispatchProp } from "react-redux";
-import { Route, Switch, Redirect } from "react-router";
+import { Route, Switch } from "react-router";
import { login, logout } from "~/store/auth/auth-action";
import { User } from "~/models/user";
import { RootState } from "~/store/store";
@@ -18,9 +18,9 @@ import { ProjectPanel } from "~/views/project-panel/project-panel";
import { DetailsPanel } from '~/views-components/details-panel/details-panel';
import { ArvadosTheme } from '~/common/custom-theme';
import { CreateProjectDialog } from "~/views-components/create-project-dialog/create-project-dialog";
-import { detailsPanelActions, loadDetailsPanel } from "~/store/details-panel/details-panel-action";
+import { detailsPanelActions } from "~/store/details-panel/details-panel-action";
import { openContextMenu } from '~/store/context-menu/context-menu-actions';
-import { ProjectResource, getProjectUrl } from '~/models/project';
+import { ProjectResource } from '~/models/project';
import { ContextMenu, ContextMenuKind } from "~/views-components/context-menu/context-menu";
import { FavoritePanel } from "../favorite-panel/favorite-panel";
import { CurrentTokenDialog } from '~/views-components/current-token-dialog/current-token-dialog';
@@ -41,7 +41,9 @@ import { MoveProjectDialog } from '~/views-components/move-project-dialog/move-p
import { MoveCollectionDialog } from '~/views-components/move-collection-dialog/move-collection-dialog';
import { SidePanel } from '~/views-components/side-panel/side-panel';
import { Routes } from '~/routes/routes';
-import { navigateToResource } from '~/store/navigation/navigation-action';
+import { navigateTo } from '~/store/navigation/navigation-action';
+import { Breadcrumbs } from '~/views-components/breadcrumbs/breadcrumbs';
+
const APP_BAR_HEIGHT = 100;
@@ -173,7 +175,7 @@ export const Workbench = withStyles(styles)(
<div className={classes.root}>
<div className={classes.appBar}>
<MainAppBar
- breadcrumbs={breadcrumbs}
+ breadcrumbs={Breadcrumbs}
searchText={this.state.searchText}
user={this.props.user}
menuItems={this.state.menuItems}
@@ -216,7 +218,7 @@ export const Workbench = withStyles(styles)(
mainAppBarActions: MainAppBarActionProps = {
onBreadcrumbClick: ({ itemId }: NavBreadcrumb) => {
- this.props.dispatch(navigateToResource(itemId));
+ this.props.dispatch(navigateTo(itemId));
},
onSearch: searchText => {
this.setState({ searchText });
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list