//
// SPDX-License-Identifier: AGPL-3.0
- import { createTree, getNodeValue, getNodeChildren } from "~/models/tree";
+ import { createTree, getNodeValue, getNodeChildrenIds } from "~/models/tree";
import { TreePickerNode, createTreePickerNode } from "./tree-picker";
import { treePickerReducer } from "./tree-picker-reducer";
import { treePickerActions } from "./tree-picker-actions";
describe('TreePickerReducer', () => {
it('LOAD_TREE_PICKER_NODE - initial state', () => {
const tree = createTree<TreePickerNode>();
- const newTree = treePickerReducer(tree, treePickerActions.LOAD_TREE_PICKER_NODE({ id: '1' }));
- expect(newTree).toEqual(tree);
+ const newState = treePickerReducer({}, treePickerActions.LOAD_TREE_PICKER_NODE({ nodeId: '1', pickerId: "projects" }));
+ expect(newState).toEqual({ 'projects': tree });
});
it('LOAD_TREE_PICKER_NODE', () => {
- const tree = createTree<TreePickerNode>();
- const node = createTreePickerNode({ id: '1', value: '1' });
- const [newTree] = [tree]
- .map(tree => treePickerReducer(tree, treePickerActions.LOAD_TREE_PICKER_NODE_SUCCESS({ id: '', nodes: [node] })))
- .map(tree => treePickerReducer(tree, treePickerActions.LOAD_TREE_PICKER_NODE({ id: '1' })));
- expect(getNodeValue('1')(newTree)).toEqual({
- ...createTreePickerNode({ id: '1', value: '1' }),
+ const node = createTreePickerNode({ nodeId: '1', value: '1' });
+ const [newState] = [{
+ projects: createTree<TreePickerNode>()
+ }]
+ .map(state => treePickerReducer(state, treePickerActions.LOAD_TREE_PICKER_NODE_SUCCESS({ nodeId: '', nodes: [node], pickerId: "projects" })))
+ .map(state => treePickerReducer(state, treePickerActions.LOAD_TREE_PICKER_NODE({ nodeId: '1', pickerId: "projects" })));
+
+ expect(getNodeValue('1')(newState.projects)).toEqual({
+ ...createTreePickerNode({ nodeId: '1', value: '1' }),
status: TreeItemStatus.PENDING
});
});
it('LOAD_TREE_PICKER_NODE_SUCCESS - initial state', () => {
- const tree = createTree<TreePickerNode>();
- const subNode = createTreePickerNode({ id: '1.1', value: '1.1' });
- const newTree = treePickerReducer(tree, treePickerActions.LOAD_TREE_PICKER_NODE_SUCCESS({ id: '', nodes: [subNode] }));
- expect(getNodeChildrenIds('')(newTree)).toEqual(['1.1']);
+ const subNode = createTreePickerNode({ nodeId: '1.1', value: '1.1' });
+ const newState = treePickerReducer({}, treePickerActions.LOAD_TREE_PICKER_NODE_SUCCESS({ nodeId: '', nodes: [subNode], pickerId: "projects" }));
- expect(getNodeChildren('')(newState.projects)).toEqual(['1.1']);
++ expect(getNodeChildrenIds('')(newState.projects)).toEqual(['1.1']);
});
it('LOAD_TREE_PICKER_NODE_SUCCESS', () => {
- const tree = createTree<TreePickerNode>();
- const node = createTreePickerNode({ id: '1', value: '1' });
- const subNode = createTreePickerNode({ id: '1.1', value: '1.1' });
- const [newTree] = [tree]
- .map(tree => treePickerReducer(tree, treePickerActions.LOAD_TREE_PICKER_NODE_SUCCESS({ id: '', nodes: [node] })))
- .map(tree => treePickerReducer(tree, treePickerActions.LOAD_TREE_PICKER_NODE_SUCCESS({ id: '1', nodes: [subNode] })));
- expect(getNodeChildrenIds('1')(newTree)).toEqual(['1.1']);
- expect(getNodeValue('1')(newTree)).toEqual({
- ...createTreePickerNode({ id: '1', value: '1' }),
+ const node = createTreePickerNode({ nodeId: '1', value: '1' });
+ const subNode = createTreePickerNode({ nodeId: '1.1', value: '1.1' });
+ const [newState] = [{
+ projects: createTree<TreePickerNode>()
+ }]
+ .map(state => treePickerReducer(state, treePickerActions.LOAD_TREE_PICKER_NODE_SUCCESS({ nodeId: '', nodes: [node], pickerId: "projects" })))
+ .map(state => treePickerReducer(state, treePickerActions.LOAD_TREE_PICKER_NODE_SUCCESS({ nodeId: '1', nodes: [subNode], pickerId: "projects" })));
- expect(getNodeChildren('1')(newState.projects)).toEqual(['1.1']);
++ expect(getNodeChildrenIds('1')(newState.projects)).toEqual(['1.1']);
+ expect(getNodeValue('1')(newState.projects)).toEqual({
+ ...createTreePickerNode({ nodeId: '1', value: '1' }),
status: TreeItemStatus.LOADED
});
});
it('TOGGLE_TREE_PICKER_NODE_COLLAPSE - collapsed', () => {
- const tree = createTree<TreePickerNode>();
- const node = createTreePickerNode({ id: '1', value: '1' });
- const [newTree] = [tree]
- .map(tree => treePickerReducer(tree, treePickerActions.LOAD_TREE_PICKER_NODE_SUCCESS({ id: '', nodes: [node] })))
- .map(tree => treePickerReducer(tree, treePickerActions.TOGGLE_TREE_PICKER_NODE_COLLAPSE({ id: '1' })));
- expect(getNodeValue('1')(newTree)).toEqual({
- ...createTreePickerNode({ id: '1', value: '1' }),
+ const node = createTreePickerNode({ nodeId: '1', value: '1' });
+ const [newState] = [{
+ projects: createTree<TreePickerNode>()
+ }]
+ .map(state => treePickerReducer(state, treePickerActions.LOAD_TREE_PICKER_NODE_SUCCESS({ nodeId: '', nodes: [node], pickerId: "projects" })))
+ .map(state => treePickerReducer(state, treePickerActions.TOGGLE_TREE_PICKER_NODE_COLLAPSE({ nodeId: '1', pickerId: "projects" })));
+ expect(getNodeValue('1')(newState.projects)).toEqual({
+ ...createTreePickerNode({ nodeId: '1', value: '1' }),
collapsed: false
});
});
it('TOGGLE_TREE_PICKER_NODE_COLLAPSE - expanded', () => {
- const tree = createTree<TreePickerNode>();
- const node = createTreePickerNode({ id: '1', value: '1' });
- const [newTree] = [tree]
- .map(tree => treePickerReducer(tree, treePickerActions.LOAD_TREE_PICKER_NODE_SUCCESS({ id: '', nodes: [node] })))
- .map(tree => treePickerReducer(tree, treePickerActions.TOGGLE_TREE_PICKER_NODE_COLLAPSE({ id: '1' })))
- .map(tree => treePickerReducer(tree, treePickerActions.TOGGLE_TREE_PICKER_NODE_COLLAPSE({ id: '1' })));
- expect(getNodeValue('1')(newTree)).toEqual({
- ...createTreePickerNode({ id: '1', value: '1' }),
+ const node = createTreePickerNode({ nodeId: '1', value: '1' });
+ const [newState] = [{
+ projects: createTree<TreePickerNode>()
+ }]
+ .map(state => treePickerReducer(state, treePickerActions.LOAD_TREE_PICKER_NODE_SUCCESS({ nodeId: '', nodes: [node], pickerId: "projects" })))
+ .map(state => treePickerReducer(state, treePickerActions.TOGGLE_TREE_PICKER_NODE_COLLAPSE({ nodeId: '1', pickerId: "projects" })))
+ .map(state => treePickerReducer(state, treePickerActions.TOGGLE_TREE_PICKER_NODE_COLLAPSE({ nodeId: '1', pickerId: "projects" })));
+ expect(getNodeValue('1')(newState.projects)).toEqual({
+ ...createTreePickerNode({ nodeId: '1', value: '1' }),
collapsed: true
});
});
it('TOGGLE_TREE_PICKER_NODE_SELECT - selected', () => {
- const tree = createTree<TreePickerNode>();
- const node = createTreePickerNode({ id: '1', value: '1' });
- const [newTree] = [tree]
- .map(tree => treePickerReducer(tree, treePickerActions.LOAD_TREE_PICKER_NODE_SUCCESS({ id: '', nodes: [node] })))
- .map(tree => treePickerReducer(tree, treePickerActions.TOGGLE_TREE_PICKER_NODE_SELECT({ id: '1' })));
- expect(getNodeValue('1')(newTree)).toEqual({
- ...createTreePickerNode({ id: '1', value: '1' }),
+ const node = createTreePickerNode({ nodeId: '1', value: '1' });
+ const [newState] = [{
+ projects: createTree<TreePickerNode>()
+ }]
+ .map(state => treePickerReducer(state, treePickerActions.LOAD_TREE_PICKER_NODE_SUCCESS({ nodeId: '', nodes: [node], pickerId: "projects" })))
+ .map(state => treePickerReducer(state, treePickerActions.TOGGLE_TREE_PICKER_NODE_SELECT({ nodeId: '1', pickerId: "projects" })));
+ expect(getNodeValue('1')(newState.projects)).toEqual({
+ ...createTreePickerNode({ nodeId: '1', value: '1' }),
selected: true
});
});
it('TOGGLE_TREE_PICKER_NODE_SELECT - not selected', () => {
- const tree = createTree<TreePickerNode>();
- const node = createTreePickerNode({ id: '1', value: '1' });
- const [newTree] = [tree]
- .map(tree => treePickerReducer(tree, treePickerActions.LOAD_TREE_PICKER_NODE_SUCCESS({ id: '', nodes: [node] })))
- .map(tree => treePickerReducer(tree, treePickerActions.TOGGLE_TREE_PICKER_NODE_SELECT({ id: '1' })))
- .map(tree => treePickerReducer(tree, treePickerActions.TOGGLE_TREE_PICKER_NODE_SELECT({ id: '1' })));
- expect(getNodeValue('1')(newTree)).toEqual({
- ...createTreePickerNode({ id: '1', value: '1' }),
+ const node = createTreePickerNode({ nodeId: '1', value: '1' });
+ const [newState] = [{
+ projects: createTree<TreePickerNode>()
+ }]
+ .map(state => treePickerReducer(state, treePickerActions.LOAD_TREE_PICKER_NODE_SUCCESS({ nodeId: '', nodes: [node], pickerId: "projects" })))
+ .map(state => treePickerReducer(state, treePickerActions.TOGGLE_TREE_PICKER_NODE_SELECT({ nodeId: '1', pickerId: "projects" })))
+ .map(state => treePickerReducer(state, treePickerActions.TOGGLE_TREE_PICKER_NODE_SELECT({ nodeId: '1', pickerId: "projects" })));
+ expect(getNodeValue('1')(newState.projects)).toEqual({
+ ...createTreePickerNode({ nodeId: '1', value: '1' }),
selected: false
});
});
// SPDX-License-Identifier: AGPL-3.0
import { connect } from "react-redux";
-import { Tree, TreeProps, TreeItem } from "~/components/tree/tree";
+import { Tree, TreeProps, TreeItem, TreeItemStatus } from "~/components/tree/tree";
import { RootState } from "~/store/store";
-import { TreePicker as TTreePicker, TreePickerNode, createTreePickerNode } from "~/store/tree-picker/tree-picker";
-import { getNodeValue, getNodeChildrenIds } from "~/models/tree";
+import { createTreePickerNode, TreePickerNode } from "~/store/tree-picker/tree-picker";
- import { getNodeValue, getNodeChildren, Tree as Ttree, createTree } from "~/models/tree";
++import { getNodeValue, getNodeChildrenIds, Tree as Ttree, createTree } from "~/models/tree";
+import { Dispatch } from "redux";
-const memoizedMapStateToProps = () => {
- let prevState: TTreePicker;
- let prevTree: Array<TreeItem<any>>;
+export interface TreePickerProps {
+ pickerId: string;
+ toggleItemOpen: (nodeId: string, status: TreeItemStatus, pickerId: string) => void;
+ toggleItemActive: (nodeId: string, status: TreeItemStatus, pickerId: string) => void;
+}
- return (state: RootState): Pick<TreeProps<any>, 'items'> => {
- if (prevState !== state.treePicker) {
- prevState = state.treePicker;
- prevTree = getNodeChildrenIds('')(state.treePicker)
- .map(treePickerToTreeItems(state.treePicker));
- }
- return {
- items: prevTree
- };
+const mapStateToProps = (state: RootState, props: TreePickerProps): Pick<TreeProps<any>, 'items'> => {
+ const tree = state.treePicker[props.pickerId] || createTree();
+ return {
- items: getNodeChildren('')(tree)
++ items: getNodeChildrenIds('')(tree)
+ .map(treePickerToTreeItems(tree))
};
};
-const mapDispatchToProps = (): Pick<TreeProps<any>, 'onContextMenu'> => ({
+const mapDispatchToProps = (dispatch: Dispatch, props: TreePickerProps): Pick<TreeProps<any>, 'onContextMenu' | 'toggleItemOpen' | 'toggleItemActive'> => ({
onContextMenu: () => { return; },
+ toggleItemActive: (id, status) => props.toggleItemActive(id, status, props.pickerId),
+ toggleItemOpen: (id, status) => props.toggleItemOpen(id, status, props.pickerId)
});
-export const TreePicker = connect(memoizedMapStateToProps(), mapDispatchToProps)(Tree);
+export const TreePicker = connect(mapStateToProps, mapDispatchToProps)(Tree);
-const treePickerToTreeItems = (tree: TTreePicker) =>
+const treePickerToTreeItems = (tree: Ttree<TreePickerNode>) =>
(id: string): TreeItem<any> => {
- const node: TreePickerNode = getNodeValue(id)(tree) || createTreePickerNode({ id: '', value: 'InvalidNode' });
- const items = getNodeChildrenIds(node.id)(tree)
+ const node: TreePickerNode = getNodeValue(id)(tree) || createTreePickerNode({ nodeId: '', value: 'InvalidNode' });
- const items = getNodeChildren(node.nodeId)(tree)
++ const items = getNodeChildrenIds(node.nodeId)(tree)
.map(treePickerToTreeItems(tree));
return {
active: node.selected,
data: node.value,
- id: node.id,
+ id: node.nodeId,
items: items.length > 0 ? items : undefined,
open: !node.collapsed,
status: node.status
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';
import { ContextMenu, ContextMenuKind } from "~/views-components/context-menu/context-menu";
import { FileRemoveDialog } from '~/views-components/file-remove-dialog/file-remove-dialog';
import { MultipleFilesRemoveDialog } from '~/views-components/file-remove-dialog/multiple-files-remove-dialog';
import { DialogCollectionCreateWithSelectedFile } from '~/views-components/create-collection-dialog-with-selected/create-collection-dialog-with-selected';
+import { MoveToProjectDialog } from '../../views-components/move-to-dialog/move-to-dialog';
import { COLLECTION_CREATE_DIALOG } from '~/views-components/dialog-create/dialog-collection-create';
import { PROJECT_CREATE_DIALOG } from '~/views-components/dialog-create/dialog-project-create';
+ import { UploadCollectionFilesDialog } from '~/views-components/upload-collection-files-dialog/upload-collection-files-dialog';
const DRAWER_WITDH = 240;
const APP_BAR_HEIGHT = 100;
sidePanelItems: SidePanelItem[];
}
- interface WorkbenchServiceProps {
+ interface WorkbenchGeneralProps {
authService: AuthService;
+ buildInfo: string;
}
interface WorkbenchActionProps {
}
- type WorkbenchProps = WorkbenchDataProps & WorkbenchServiceProps & WorkbenchActionProps & DispatchProp<any> & WithStyles<CssRules>;
+ type WorkbenchProps = WorkbenchDataProps & WorkbenchGeneralProps & WorkbenchActionProps & DispatchProp<any> & WithStyles<CssRules>;
interface NavBreadcrumb extends Breadcrumb {
itemId: string;
searchText={this.state.searchText}
user={this.props.user}
menuItems={this.state.menuItems}
+ buildInfo={this.props.buildInfo}
{...this.mainAppBarActions} />
</div>
{user &&
toggleActive={itemId => {
this.props.dispatch(setProjectItem(itemId, ItemMode.ACTIVE));
this.props.dispatch(loadDetails(itemId, ResourceKind.PROJECT));
- this.props.dispatch(sidePanelActions.TOGGLE_SIDE_PANEL_ITEM_ACTIVE(SidePanelIdentifiers.PROJECTS));
}} />
</SidePanel>
</Drawer>}
<main className={classes.contentWrapper}>
<div className={classes.content}>
<Switch>
- <Route path='/' exact render={() => <Redirect to={`/projects/${this.props.authService.getUuid()}`} />} />
+ <Route path='/' exact render={() => <Redirect to={`/projects/${this.props.authService.getUuid()}`} />} />
<Route path="/projects/:id" render={this.renderProjectPanel} />
<Route path="/favorites" render={this.renderFavoritePanel} />
<Route path="/collections/:id" render={this.renderCollectionPanel} />
<CreateProjectDialog />
<CreateCollectionDialog />
<RenameFileDialog />
+ <MoveToProjectDialog />
<DialogCollectionCreateWithSelectedFile />
<FileRemoveDialog />
<MultipleFilesRemoveDialog />
<UpdateCollectionDialog />
+ <UploadCollectionFilesDialog />
<UpdateProjectDialog />
<CurrentTokenDialog
currentToken={this.props.currentToken}
default:
this.props.dispatch(loadDetails(item.uuid, ResourceKind.PROJECT));
this.props.dispatch(setProjectItem(item.uuid, ItemMode.ACTIVE));
- this.props.dispatch(sidePanelActions.TOGGLE_SIDE_PANEL_ITEM_ACTIVE(SidePanelIdentifiers.PROJECTS));
}
}}
}
toggleSidePanelActive = (itemId: string) => {
- this.props.dispatch(sidePanelActions.TOGGLE_SIDE_PANEL_ITEM_ACTIVE(itemId));
this.props.dispatch(projectActions.RESET_PROJECT_TREE_ACTIVITY(itemId));
const panelItem = this.props.sidePanelItems.find(it => it.id === itemId);