const history = createBrowserHistory();
const store = configureStore({
- projects: [
+ projects: {
+ items: [],
+ currentItemId: ""
+ },
+ collections: [
],
router: {
location: null
},
auth: {
user: undefined
- }
+ },
+ sidePanel: []
}, history);
store.dispatch(authActions.INIT());
--- /dev/null
- dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM(resource.uuid));
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { Dispatch } from "redux";
+import projectActions, { getProjectList } from "../project/project-action";
+import { push } from "react-router-redux";
+import { TreeItem, TreeItemStatus } from "../../components/tree/tree";
+import { getCollectionList } from "../collection/collection-action";
+import { findTreeItem } from "../project/project-reducer";
+import { Project } from "../../models/project";
+import { Resource, ResourceKind } from "../../models/resource";
++import sidePanelActions from "../side-panel/side-panel-action";
+
+export const getResourceUrl = (resource: Resource): string => {
+ switch (resource.kind) {
+ case ResourceKind.LEVEL_UP: return `/projects/${resource.ownerUuid}`;
+ case ResourceKind.PROJECT: return `/projects/${resource.uuid}`;
+ case ResourceKind.COLLECTION: return `/collections/${resource.uuid}`;
+ default:
+ return "#";
+ }
+};
+
+export const setProjectItem = (projects: Array<TreeItem<Project>>, itemId: string, itemKind: ResourceKind) => (dispatch: Dispatch) => {
+
+ const openProjectItem = (resource: Resource) => {
++ dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_OPEN(resource.uuid));
++ dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(resource.uuid));
++ dispatch(sidePanelActions.RESET_SIDE_PANEL_ACTIVITY(resource.uuid));
+ dispatch(push(getResourceUrl({...resource, kind: itemKind})));
+ };
+ const treeItem = findTreeItem(projects, itemId);
+
+ if (treeItem) {
+ if (treeItem.status === TreeItemStatus.Loaded) {
+ openProjectItem(treeItem.data);
+ } else {
+ dispatch<any>(getProjectList(itemId))
+ .then(() => openProjectItem(treeItem.data));
+ }
+ dispatch<any>(getCollectionList(itemId));
+
+ // if (item.type === ResourceKind.PROJECT || item.type === ResourceKind.LEVEL_UP) {
+ // this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM(item.uuid));
+ // }
+ // this.props.dispatch<any>(getCollectionList(item.uuid));
+
+ }
+};
++
++ // toggleProjectTreeItemActive = (itemId: string, status: TreeItemStatus) => {
++ // if (status === TreeItemStatus.Loaded) {
++ // this.openProjectItem(itemId);
++ // this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(itemId));
++ // this.props.dispatch(sidePanelActions.RESET_SIDE_PANEL_ACTIVITY(itemId));
++ // } else {
++ // this.props.dispatch<any>(getProjectList(itemId))
++ // .then(() => {
++ // this.openProjectItem(itemId);
++ // this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(itemId));
++ // this.props.dispatch(sidePanelActions.RESET_SIDE_PANEL_ACTIVITY(itemId));
++ // });
++ // }
++ // }
import projectsReducer, { getTreePath } from "./project-reducer";
import actions from "./project-action";
import { TreeItem, TreeItemStatus } from "../../components/tree/tree";
+import { ResourceKind } from "../../models/resource";
describe('project-reducer', () => {
it('should add new project to the list', () => {
modifiedAt: '2018-01-01',
ownerUuid: 'owner-test123',
uuid: 'test123',
- kind: ""
+ kind: ResourceKind.PROJECT
};
const state = projectsReducer(initialState, actions.CREATE_PROJECT(project));
modifiedAt: '2018-01-01',
ownerUuid: 'owner-test123',
uuid: 'test123',
- kind: ""
+ kind: ResourceKind.PROJECT
};
const projects = [project, project];
const state = projectsReducer(initialState, actions.PROJECTS_SUCCESS({ projects, parentItemId: undefined }));
expect(state).toEqual([{
- const initialState = [
- {
+ active: false,
+ open: false,
+ id: "test123",
+ items: [],
+ data: project,
+ status: 0
+ }, {
+ active: false,
+ open: false,
+ id: "test123",
+ items: [],
+ data: project,
+ status: 0
+ }
+ ]);
+ });
+
+ it('should remove activity on projects list', () => {
- kind: 'example'
++ const initialState = {
++ items: [{
+ data: {
+ name: 'test',
+ href: 'href',
+ createdAt: '2018-01-01',
+ modifiedAt: '2018-01-01',
+ ownerUuid: 'owner-test123',
+ uuid: 'test123',
- }
- ];
- const project = [
- {
++ kind: ResourceKind.PROJECT
+ },
+ id: "1",
+ open: true,
+ active: true,
+ status: 1
- kind: 'example'
++ }],
++ currentItemId: "1"
++ };
++ const project = {
++ items: [{
+ data: {
+ name: 'test',
+ href: 'href',
+ createdAt: '2018-01-01',
+ modifiedAt: '2018-01-01',
+ ownerUuid: 'owner-test123',
+ uuid: 'test123',
++ kind: ResourceKind.PROJECT
+ },
+ id: "1",
+ open: true,
active: false,
- open: false,
- id: "test123",
- items: [],
- data: project,
- status: 0
- }, {
+ status: 1
- }
- ];
++ }],
++ currentItemId: "1"
++ };
+
+ const state = projectsReducer(initialState, actions.RESET_PROJECT_TREE_ACTIVITY(initialState[0].id));
+ expect(state).toEqual(project);
+ });
+
+ it('should toggle project tree item activity', () => {
- const initialState = [
- {
++ const initialState = {
++ items: [{
+ data: {
+ name: 'test',
+ href: 'href',
+ createdAt: '2018-01-01',
+ modifiedAt: '2018-01-01',
+ ownerUuid: 'owner-test123',
+ uuid: 'test123',
- kind: 'example'
++ kind: ResourceKind.PROJECT
+ },
+ id: "1",
+ open: true,
active: false,
- }
- ];
- const project = [
- {
+ status: 1
- kind: 'example'
++ }],
++ currentItemId: "1"
++ };
++ const project = {
++ items: [{
+ data: {
+ name: 'test',
+ href: 'href',
+ createdAt: '2018-01-01',
+ modifiedAt: '2018-01-01',
+ ownerUuid: 'owner-test123',
+ uuid: 'test123',
- }
- ];
++ kind: ResourceKind.PROJECT
+ },
+ id: "1",
+ open: true,
+ active: true,
+ status: 1
- const initialState = [
- {
++ }],
++ currentItemId: "1"
++ };
+
+ const state = projectsReducer(initialState, actions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(initialState[0].id));
+ expect(state).toEqual(project);
+ });
+
+
+ it('should close project tree item ', () => {
- kind: 'example'
++ const initialState = {
++ items: [{
+ data: {
+ name: 'test',
+ href: 'href',
+ createdAt: '2018-01-01',
+ modifiedAt: '2018-01-01',
+ ownerUuid: 'owner-test123',
+ uuid: 'test123',
- }
- ];
- const project = [
- {
++ kind: ResourceKind.PROJECT
+ },
+ id: "1",
+ open: true,
+ active: false,
+ status: 1,
+ toggled: false,
- kind: 'example'
++ }],
++ currentItemId: "1"
++ };
++ const project = {
++ items: [{
+ data: {
+ name: 'test',
+ href: 'href',
+ createdAt: '2018-01-01',
+ modifiedAt: '2018-01-01',
+ ownerUuid: 'owner-test123',
+ uuid: 'test123',
++ kind: ResourceKind.PROJECT
+ },
+ id: "1",
open: false,
- id: "test123",
- items: [],
- data: project,
- status: 0
- }
- ]);
+ active: false,
+ status: 1,
+ toggled: true
- }
- ];
++ }],
++ currentItemId: "1"
++ };
+
+ const state = projectsReducer(initialState, actions.TOGGLE_PROJECT_TREE_ITEM_OPEN(initialState[0].id));
+ expect(state).toEqual(project);
});
});
describe("findTreeBranch", () => {
--
const createTreeItem = (id: string, items?: Array<TreeItem<string>>): TreeItem<string> => ({
id,
items,
//
// SPDX-License-Identifier: AGPL-3.0
+ import * as _ from "lodash";
+
import { Project } from "../../models/project";
import actions, { ProjectAction } from "./project-action";
import { TreeItem, TreeItemStatus } from "../../components/tree/tree";
- import * as _ from "lodash";
-export type ProjectState = Array<TreeItem<Project>>;
+export type ProjectState = {
+ items: Array<TreeItem<Project>>,
+ currentItemId: string
+};
export function findTreeItem<T>(tree: Array<TreeItem<T>>, itemId: string): TreeItem<T> | undefined {
let item;
return item;
}
+export function getActiveTreeItem<T>(tree: Array<TreeItem<T>>): TreeItem<T> | undefined {
+ let item;
+ for (const t of tree) {
+ item = t.active
+ ? t
+ : getActiveTreeItem(t.items ? t.items : []);
+ if (item) {
+ break;
+ }
+ }
+ return item;
+}
+
export function getTreePath<T>(tree: Array<TreeItem<T>>, itemId: string): Array<TreeItem<T>> {
- for(const item of tree){
+ for (const item of tree){
if(item.id === itemId){
return [item];
} else {
treeItem.status = TreeItemStatus.Loaded;
}
}
- const items = projects.map((p, idx) => ({
+ const items = projects.map(p => ({
id: p.uuid,
open: false,
active: false,
return items;
}
-const projectsReducer = (state: ProjectState = [], action: ProjectAction) => {
+const projectsReducer = (state: ProjectState = { items: [], currentItemId: "" }, action: ProjectAction) => {
return actions.match(action, {
- CREATE_PROJECT: project => [...state, project],
+ CREATE_PROJECT: project => ({
+ ...state,
+ items: state.items.concat({
+ id: project.uuid,
+ open: false,
+ active: false,
+ status: TreeItemStatus.Loaded,
+ toggled: false,
+ items: [],
+ data: project
+ })
+ }),
REMOVE_PROJECT: () => state,
PROJECTS_REQUEST: itemId => {
- const tree = _.cloneDeep(state);
- const item = findTreeItem(tree, itemId);
+ const items = _.cloneDeep(state.items);
+ const item = findTreeItem(items, itemId);
if (item) {
item.status = TreeItemStatus.Pending;
+ state.items = items;
}
- return tree;
+ return state;
},
PROJECTS_SUCCESS: ({ projects, parentItemId }) => {
- return updateProjectTree(state, projects, parentItemId);
+ return {
+ ...state,
+ items: updateProjectTree(state.items, projects, parentItemId)
+ };
},
- TOGGLE_PROJECT_TREE_ITEM: itemId => {
+ TOGGLE_PROJECT_TREE_ITEM_OPEN: itemId => {
- const tree = _.cloneDeep(state);
- const item = findTreeItem(tree, itemId);
+ const items = _.cloneDeep(state.items);
- resetTreeActivity(items);
+ const item = findTreeItem(items, itemId);
if (item) {
+ item.toggled = true;
item.open = !item.open;
- return tree;
+ }
- const tree = _.cloneDeep(state);
- resetTreeActivity(tree);
- const item = findTreeItem(tree, itemId);
++ return {
++ ...state,
++ items
++ };
+ },
+ TOGGLE_PROJECT_TREE_ITEM_ACTIVE: itemId => {
++ const items = _.cloneDeep(state.items);
++ resetTreeActivity(items);
++ const item = findTreeItem(items, itemId);
+ if (item) {
item.active = true;
- item.toggled = true;
}
- return tree;
+ return {
+ items,
+ currentItemId: itemId
+ };
},
- const tree = _.cloneDeep(state);
- resetTreeActivity(tree);
- return tree;
+ RESET_PROJECT_TREE_ACTIVITY: () => {
++ const items = _.cloneDeep(state.items);
++ resetTreeActivity(items);
++ return {
++ ...state,
++ items
++ };
+ },
default: () => state
});
};
import { routerMiddleware, routerReducer, RouterState } from "react-router-redux";
import thunkMiddleware from 'redux-thunk';
import { History } from "history";
+
import projectsReducer, { ProjectState } from "./project/project-reducer";
+ import sidePanelReducer, { SidePanelState } from './side-panel/side-panel-reducer';
import authReducer, { AuthState } from "./auth/auth-reducer";
-import collectionsReducer from "./collection/collection-reducer";
+import collectionsReducer, { CollectionState } from "./collection/collection-reducer";
const composeEnhancers =
(process.env.NODE_ENV === 'development' &&
- window && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) ||
+ window && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) ||
compose;
export interface RootState {
auth: AuthState;
projects: ProjectState;
+ collections: CollectionState;
router: RouterState;
+ sidePanel: SidePanelState;
}
const rootReducer = combineReducers({
auth: authReducer,
projects: projectsReducer,
collections: collectionsReducer,
- router: routerReducer
+ router: routerReducer,
+ sidePanel: sidePanelReducer
});
//
// SPDX-License-Identifier: AGPL-3.0
- export interface DataItem {
+import { getResourceKind, Resource, ResourceKind } from "../../models/resource";
+
+ export interface ProjectExplorerItem {
uuid: string;
name: string;
- type: string;
+ kind: ResourceKind;
+ url: string;
owner: string;
lastModified: string;
fileSize?: number;
status?: string;
}
+
+function resourceToDataItem(r: Resource, kind?: ResourceKind) {
+ return {
+ uuid: r.uuid,
+ name: r.name,
+ kind: kind ? kind : getResourceKind(r.kind),
+ owner: r.ownerUuid,
+ lastModified: r.modifiedAt
+ };
+}
+
--- /dev/null
- render: item => renderType(item.type)
+ // Copyright (C) The Arvados Authors. All rights reserved.
+ //
+ // SPDX-License-Identifier: AGPL-3.0
+
+ import * as React from 'react';
+ import { ProjectExplorerItem } from './project-explorer-item';
+ import { Grid, Typography } from '@material-ui/core';
+ import { formatDate, formatFileSize } from '../../common/formatters';
+ import DataExplorer from '../../components/data-explorer/data-explorer';
+ import { DataColumn, toggleSortDirection, resetSortDirection } from '../../components/data-table/data-column';
+ import { DataTableFilterItem } from '../../components/data-table-filters/data-table-filters';
+ import { ContextMenuAction } from '../../components/context-menu/context-menu';
++import { ResourceKind } from "../../models/resource";
+
+ export interface ProjectExplorerContextActions {
+ onAddToFavourite: (item: ProjectExplorerItem) => void;
+ onCopy: (item: ProjectExplorerItem) => void;
+ onDownload: (item: ProjectExplorerItem) => void;
+ onMoveTo: (item: ProjectExplorerItem) => void;
+ onRemove: (item: ProjectExplorerItem) => void;
+ onRename: (item: ProjectExplorerItem) => void;
+ onShare: (item: ProjectExplorerItem) => void;
+ }
+
+ interface ProjectExplorerProps {
+ items: ProjectExplorerItem[];
++ onRowClick: (item: ProjectExplorerItem) => void;
+ }
+
+ interface ProjectExplorerState {
+ columns: Array<DataColumn<ProjectExplorerItem>>;
+ searchValue: string;
+ page: number;
+ rowsPerPage: number;
+ }
+
+ class ProjectExplorer extends React.Component<ProjectExplorerProps, ProjectExplorerState> {
+ state: ProjectExplorerState = {
+ searchValue: "",
+ page: 0,
+ rowsPerPage: 10,
+ columns: [{
+ name: "Name",
+ selected: true,
+ sortDirection: "asc",
+ render: renderName
+ }, {
+ name: "Status",
+ selected: true,
+ filters: [{
+ name: "In progress",
+ selected: true
+ }, {
+ name: "Complete",
+ selected: true
+ }],
+ render: renderStatus
+ }, {
+ name: "Type",
+ selected: true,
+ filters: [{
+ name: "Collection",
+ selected: true
+ }, {
+ name: "Group",
+ selected: true
+ }],
- onRowClick={console.log}
++ render: item => renderType(item.kind)
+ }, {
+ name: "Owner",
+ selected: true,
+ render: item => renderOwner(item.owner)
+ }, {
+ name: "File size",
+ selected: true,
+ sortDirection: "none",
+ render: item => renderFileSize(item.fileSize)
+ }, {
+ name: "Last modified",
+ selected: true,
+ render: item => renderDate(item.lastModified)
+ }]
+ };
+
+ contextMenuActions = [[{
+ 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"
+ }
+ ]];
+
+ render() {
+ return <DataExplorer
+ items={this.props.items}
+ columns={this.state.columns}
+ contextActions={this.contextMenuActions}
+ searchValue={this.state.searchValue}
+ page={this.state.page}
+ rowsPerPage={this.state.rowsPerPage}
+ onColumnToggle={this.toggleColumn}
+ onFiltersChange={this.changeFilters}
- switch (item.type) {
- case "arvados#group":
- return <i className="fas fa-folder fa-lg" />;
- case "arvados#groupList":
- return <i className="fas fa-th fa-lg" />;
++ onRowClick={this.props.onRowClick}
+ onSortToggle={this.toggleSort}
+ onSearch={this.search}
+ onContextAction={this.executeAction}
+ onChangePage={this.changePage}
+ onChangeRowsPerPage={this.changeRowsPerPage} />;
+ }
+
+ toggleColumn = (toggledColumn: DataColumn<ProjectExplorerItem>) => {
+ this.setState({
+ columns: this.state.columns.map(column =>
+ column.name === toggledColumn.name
+ ? { ...column, selected: !column.selected }
+ : column
+ )
+ });
+ }
+
+ toggleSort = (toggledColumn: DataColumn<ProjectExplorerItem>) => {
+ this.setState({
+ columns: this.state.columns.map(column =>
+ column.name === toggledColumn.name
+ ? toggleSortDirection(column)
+ : resetSortDirection(column)
+ )
+ });
+ }
+
+ changeFilters = (filters: DataTableFilterItem[], updatedColumn: DataColumn<ProjectExplorerItem>) => {
+ this.setState({
+ columns: this.state.columns.map(column =>
+ column.name === updatedColumn.name
+ ? { ...column, filters }
+ : column
+ )
+ });
+ }
+
+ executeAction = (action: ContextMenuAction, item: ProjectExplorerItem) => {
+ alert(`Executing ${action.name} on ${item.name}`);
+ }
+
+ search = (searchValue: string) => {
+ this.setState({ searchValue });
+ }
+
+ changePage = (page: number) => {
+ this.setState({ page });
+ }
+
+ changeRowsPerPage = (rowsPerPage: number) => {
+ this.setState({ rowsPerPage });
+ }
+ }
+
+ const renderName = (item: ProjectExplorerItem) =>
+ <Grid
+ container
+ alignItems="center"
+ wrap="nowrap"
+ spacing={16}>
+ <Grid item>
+ {renderIcon(item)}
+ </Grid>
+ <Grid item>
+ <Typography color="primary">
+ {item.name}
+ </Typography>
+ </Grid>
+ </Grid>;
+
++
+ const renderIcon = (item: ProjectExplorerItem) => {
++ switch (item.kind) {
++ case ResourceKind.LEVEL_UP:
++ return <i className="icon-level-up" style={{fontSize: "1rem"}}/>;
++ case ResourceKind.PROJECT:
++ return <i className="fas fa-folder fa-lg"/>;
++ case ResourceKind.COLLECTION:
++ return <i className="fas fa-th fa-lg"/>;
+ default:
+ return <i />;
+ }
+ };
+
+ const renderDate = (date: string) =>
+ <Typography noWrap>
+ {formatDate(date)}
+ </Typography>;
+
+ const renderFileSize = (fileSize?: number) =>
+ <Typography noWrap>
+ {formatFileSize(fileSize)}
+ </Typography>;
+
+ const renderOwner = (owner: string) =>
+ <Typography noWrap color="primary">
+ {owner}
+ </Typography>;
+
+ const renderType = (type: string) =>
+ <Typography noWrap>
+ {type}
+ </Typography>;
+
+ const renderStatus = (item: ProjectExplorerItem) =>
+ <Typography noWrap align="center">
+ {item.status || "-"}
+ </Typography>;
+
+ export default ProjectExplorer;
import { TreeItem } from "../../components/tree/tree";
import { Project } from "../../models/project";
- import { DataItem } from "../../views-components/data-explorer/data-item";
+import { findTreeItem } from "../../store/project/project-reducer";
+import { ResourceKind } from "../../models/resource";
+import { Collection } from "../../models/collection";
+import { getResourceUrl } from "../../store/navigation/navigation-action";
+ import { ProjectExplorerItem } from "../../views-components/project-explorer/project-explorer-item";
- export const projectExplorerItems = (projects: Array<TreeItem<Project>>, treeItemId: string, collections: Array<Collection>): DataItem[] => {
- const dataItems: DataItem[] = [];
-export const mapProjectTreeItem = (item: TreeItem<Project>): ProjectExplorerItem => ({
- name: item.data.name,
- type: item.data.kind,
- owner: item.data.ownerUuid,
- lastModified: item.data.modifiedAt,
- uuid: item.data.uuid
-});
++export const projectExplorerItems = (projects: Array<TreeItem<Project>>, treeItemId: string, collections: Array<Collection>): ProjectExplorerItem[] => {
++ const dataItems: ProjectExplorerItem[] = [];
+
+ const treeItem = findTreeItem(projects, treeItemId);
+ if (treeItem) {
+ dataItems.push({
+ name: "..",
+ url: getResourceUrl(treeItem.data),
+ kind: ResourceKind.LEVEL_UP,
+ owner: treeItem.data.ownerUuid,
+ uuid: treeItem.data.uuid,
+ lastModified: treeItem.data.modifiedAt
+ });
+
+ if (treeItem.items) {
+ treeItem.items.forEach(p => {
+ const item = {
+ name: p.data.name,
+ kind: ResourceKind.PROJECT,
+ url: getResourceUrl(treeItem.data),
+ owner: p.data.ownerUuid,
+ uuid: p.data.uuid,
+ lastModified: p.data.modifiedAt
- } as DataItem;
++ } as ProjectExplorerItem;
+
+ dataItems.push(item);
+ });
+ }
+ }
+
+ collections.forEach(c => {
+ const item = {
+ name: c.name,
+ kind: ResourceKind.COLLECTION,
+ url: getResourceUrl(c),
+ owner: c.ownerUuid,
+ uuid: c.uuid,
+ lastModified: c.modifiedAt
- } as DataItem;
++ } as ProjectExplorerItem;
+
+ dataItems.push(item);
+ });
+
+ return dataItems;
+};
+
--- /dev/null
-import { RouteComponentProps } from 'react-router-dom';
-import { DispatchProp, connect } from 'react-redux';
-import { ProjectState, findTreeItem } from '../../store/project/project-reducer';
-import ProjectExplorer from '../../views-components/project-explorer/project-explorer';
+ // Copyright (C) The Arvados Authors. All rights reserved.
+ //
+ // SPDX-License-Identifier: AGPL-3.0
+
+ import * as React from 'react';
-import { mapProjectTreeItem } from './project-panel-selectors';
++import { RouteComponentProps } from 'react-router';
++import { ProjectState } from '../../store/project/project-reducer';
+ import { RootState } from '../../store/store';
-
++import { connect, DispatchProp } from 'react-redux';
++import { CollectionState } from "../../store/collection/collection-reducer";
++import { setProjectItem } from "../../store/navigation/navigation-action";
++import ProjectExplorer, { ProjectExplorerContextActions } from "../../views-components/project-explorer/project-explorer";
++import { projectExplorerItems } from "./project-panel-selectors";
++import { ProjectExplorerItem } from "../../views-components/project-explorer/project-explorer-item";
+
+ interface ProjectPanelDataProps {
+ projects: ProjectState;
++ collections: CollectionState;
+ }
+
+ type ProjectPanelProps = ProjectPanelDataProps & RouteComponentProps<{ name: string }> & DispatchProp;
+
+ class ProjectPanel extends React.Component<ProjectPanelProps> {
- const project = findTreeItem(this.props.projects, this.props.match.params.name);
- const projectItems = project && project.items || [];
+ render() {
- <ProjectExplorer items={projectItems.map(mapProjectTreeItem)} />
++ const items = projectExplorerItems(
++ this.props.projects.items,
++ this.props.projects.currentItemId,
++ this.props.collections
++ );
+ return (
- projects: state.projects
++ <ProjectExplorer
++ items={items}
++ onRowClick={this.goToItem}
++ />
+ );
+ }
++
++ goToItem = (item: ProjectExplorerItem) => {
++ this.props.dispatch<any>(setProjectItem(this.props.projects.items, item.uuid, item.kind));
++ }
+ }
+
+ export default connect(
+ (state: RootState) => ({
++ projects: state.projects,
++ collections: state.collections
+ })
+ )(ProjectPanel);
// SPDX-License-Identifier: AGPL-3.0
import * as React from 'react';
-
import { StyleRulesCallback, Theme, WithStyles, withStyles } from '@material-ui/core/styles';
import Drawer from '@material-ui/core/Drawer';
import { connect, DispatchProp } from "react-redux";
import authActions from "../../store/auth/auth-action";
import { User } from "../../models/user";
import { RootState } from "../../store/store";
-import MainAppBar, { MainAppBarActionProps, MainAppBarMenuItem } from '../../views-components/main-app-bar/main-app-bar';
+import MainAppBar, {
+ MainAppBarActionProps,
+ MainAppBarMenuItem
+} from '../../views-components/main-app-bar/main-app-bar';
import { Breadcrumb } from '../../components/breadcrumbs/breadcrumbs';
import { push } from 'react-router-redux';
-import projectActions, { getProjectList } from "../../store/project/project-action";
import ProjectTree from '../../views-components/project-tree/project-tree';
-import { TreeItem, TreeItemStatus } from "../../components/tree/tree";
+import { TreeItem } from "../../components/tree/tree";
import { Project } from "../../models/project";
import { getTreePath } from '../../store/project/project-reducer';
- import DataExplorer from '../data-explorer/data-explorer';
- import { setProjectItem } from "../../store/navigation/navigation-action";
+ import ProjectPanel from '../project-panel/project-panel';
+ import sidePanelActions from '../../store/side-panel/side-panel-action';
-import { projectService } from '../../services/services';
+ import SidePanel, { SidePanelItem } from '../../components/side-panel/side-panel';
+import { ResourceKind } from "../../models/resource";
++import { setProjectItem } from "../../store/navigation/navigation-action";
const drawerWidth = 240;
const appBarHeight = 102;
drawerPaper: {
position: 'relative',
width: drawerWidth,
+ display: 'flex',
+ flexDirection: 'column',
},
contentWrapper: {
backgroundColor: theme.palette.background.default,
interface WorkbenchDataProps {
projects: Array<TreeItem<Project>>;
+ currentProjectId: string;
user?: User;
+ sidePanelItems: SidePanelItem[];
}
interface WorkbenchActionProps {
interface NavBreadcrumb extends Breadcrumb {
itemId: string;
- status: TreeItemStatus;
}
interface NavMenuItem extends MainAppBarMenuItem {
interface WorkbenchState {
anchorEl: any;
- breadcrumbs: NavBreadcrumb[];
searchText: string;
menuItems: {
accountMenu: NavMenuItem[],
}
};
-
mainAppBarActions: MainAppBarActionProps = {
- onBreadcrumbClick: ({ itemId, status }: NavBreadcrumb) => {
- this.toggleProjectTreeItemOpen(itemId, status);
+ onBreadcrumbClick: ({ itemId }: NavBreadcrumb) => {
+ // this.toggleProjectTreeItem(itemId, status);
},
onSearch: searchText => {
this.setState({ searchText });
onMenuItemClick: (menuItem: NavMenuItem) => menuItem.action()
};
- toggleProjectTreeItemOpen = (itemId: string, status: TreeItemStatus) => {
- if (status === TreeItemStatus.Loaded) {
- this.openProjectItem(itemId);
- this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_OPEN(itemId));
- this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(itemId));
- } else {
- this.props.dispatch<any>(getProjectList(itemId))
- .then(() => {
- this.openProjectItem(itemId);
- this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_OPEN(itemId));
- this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(itemId));
- });
- }
- }
-
- toggleProjectTreeItemActive = (itemId: string, status: TreeItemStatus) => {
- if (status === TreeItemStatus.Loaded) {
- this.openProjectItem(itemId);
- this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(itemId));
- this.props.dispatch(sidePanelActions.RESET_SIDE_PANEL_ACTIVITY(itemId));
- } else {
- this.props.dispatch<any>(getProjectList(itemId))
- .then(() => {
- this.openProjectItem(itemId);
- this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(itemId));
- this.props.dispatch(sidePanelActions.RESET_SIDE_PANEL_ACTIVITY(itemId));
- });
- }
- }
-
+ toggleSidePanelOpen = (itemId: string) => {
+ this.props.dispatch(sidePanelActions.TOGGLE_SIDE_PANEL_ITEM_OPEN(itemId));
+ }
+
+ toggleSidePanelActive = (itemId: string) => {
+ this.props.dispatch(sidePanelActions.TOGGLE_SIDE_PANEL_ITEM_ACTIVE(itemId));
- this.props.dispatch(projectActions.RESET_PROJECT_TREE_ACTIVITY(itemId));
- }
-
- openProjectItem = (itemId: string) => {
- const branch = getTreePath(this.props.projects, itemId);
- this.setState({
- breadcrumbs: branch.map(item => ({
- label: item.data.name,
- itemId: item.data.uuid,
- status: item.status
- }))
- });
- this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(itemId));
- this.props.dispatch(push(`/project/${itemId}`));
++ // this.props.dispatch(projectActions.RESET_PROJECT_TREE_ACTIVITY(itemId));
+ }
+
render() {
- const { classes, user, projects, sidePanelItems } = this.props;
+ const branch = getTreePath(this.props.projects, this.props.currentProjectId);
+ const breadcrumbs = branch.map(item => ({
+ label: item.data.name,
+ itemId: item.data.uuid,
+ status: item.status
+ }));
+
+ const { classes, user } = this.props;
return (
<div className={classes.root}>
<div className={classes.appBar}>
<MainAppBar
- breadcrumbs={this.state.breadcrumbs}
+ breadcrumbs={breadcrumbs}
searchText={this.state.searchText}
user={this.props.user}
menuItems={this.state.menuItems}
{...this.mainAppBarActions}
/>
</div>
- {user && <Drawer
- variant="permanent"
- classes={{
- paper: classes.drawerPaper,
- }}>
- <div className={classes.toolbar} />
- <ProjectTree
- projects={this.props.projects}
- toggleProjectTreeItem={itemId =>
- this.props.dispatch<any>(
- setProjectItem(this.props.projects, itemId, ResourceKind.PROJECT)
- )}/>
- </Drawer>}
+ {user &&
+ <Drawer
+ variant="permanent"
+ classes={{
+ paper: classes.drawerPaper,
+ }}>
+ <div className={classes.toolbar} />
+ <SidePanel
+ toggleOpen={this.toggleSidePanelOpen}
+ toggleActive={this.toggleSidePanelActive}
- sidePanelItems={sidePanelItems}>
++ sidePanelItems={this.props.sidePanelItems}>
+ <ProjectTree
- projects={projects}
- toggleOpen={this.toggleProjectTreeItemOpen}
- toggleActive={this.toggleProjectTreeItemActive} />
++ projects={this.props.projects}
++ toggleOpen={itemId =>
++ this.props.dispatch<any>(
++ setProjectItem(this.props.projects, itemId, ResourceKind.PROJECT)
++ )}
++ toggleActive={itemId =>
++ this.props.dispatch<any>(
++ setProjectItem(this.props.projects, itemId, ResourceKind.PROJECT)
++ )}
++ />
+ </SidePanel>
+ </Drawer>}
<main className={classes.contentWrapper}>
<div className={classes.content}>
<Switch>
- <Route path="/projects/:uuid" component={DataExplorer} />
+ <Route path="/project/:name" component={ProjectPanel} />
</Switch>
</div>
</main>
);
}
}
++/*
++ <ProjectTree
++ projects={this.props.projects}
++ toggleProjectTreeItem={itemId =>
++ this.props.dispatch<any>(
++ setProjectItem(this.props.projects, itemId, ResourceKind.PROJECT)
++ )}/>
++*/
export default connect<WorkbenchDataProps>(
(state: RootState) => ({
- projects: state.projects,
+ projects: state.projects.items,
+ currentProjectId: state.projects.currentItemId,
- user: state.auth.user
+ user: state.auth.user,
- sidePanelItems: state.sidePanel,
++ sidePanelItems: state.sidePanel
})
)(
withStyles(styles)(Workbench)