Skip to content

Commit

Permalink
improve repository tree performance, fix dissapearing node issue
Browse files Browse the repository at this point in the history
  • Loading branch information
karanpratapsingh committed Oct 6, 2020
1 parent 6bcdb0f commit b4fed61
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 32 deletions.
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import React from 'react';
import StyledTreeItem from './StyledTreeItem';
import TreeViewContents from './TreeViewContents';
import { eMetadata, eSystemObjectType } from '../../../../types/server';
import { getRepositoryTreeNodeId, getSortedTreeEntries, getTreeColorVariant, getTreeViewColumns } from '../../../../utils/repository';
import { useGetObjectChildren } from '../../hooks/useRepository';
import { AiOutlineFileText } from 'react-icons/ai';
import { RepositoryFilter } from '../..';
import { RepositoryIcon } from '../../../../components';
import { Colors } from '../../../../theme';
import { RepositoryColorVariant } from '../../../../theme/colors';
import { RepositoryIcon } from '../../../../components';
import { TreeViewColumn } from './StyledTreeItem';
import { RepositoryFilter } from '../..';
import { NavigationResultEntry } from '../../../../types/graphql';
import { eMetadata, eSystemObjectType } from '../../../../types/server';
import { getRepositoryTreeNodeId, getSortedTreeEntries, getTreeColorVariant, getTreeViewColumns } from '../../../../utils/repository';
import { useGetObjectChildren } from '../../hooks/useRepository';
import StyledTreeItem, { TreeViewColumn } from './StyledTreeItem';
import TreeViewContents from './TreeViewContents';

export type ExpandedNodeMap = Map<string, void>;

interface RepositoryTreeNodeProps {
idSystemObject: number;
Expand All @@ -21,37 +22,51 @@ interface RepositoryTreeNodeProps {
icon: React.ReactNode;
treeColumns: TreeViewColumn[];
filter: RepositoryFilter;
expandedNodes: ExpandedNodeMap;
}

function RepositoryTreeNode(props: RepositoryTreeNodeProps): React.ReactElement {
const { idSystemObject, idObject, name, objectType, icon, color, treeColumns, filter } = props;
const { idSystemObject, idObject, name, objectType, icon, color, treeColumns, filter, expandedNodes } = props;
const {
getObjectChildren,
getObjectChildrenData,
getObjectChildrenLoading,
getObjectChildrenError,
} = useGetObjectChildren(idSystemObject, filter);

const { getObjectChildren, getObjectChildrenData, getObjectChildrenLoading, getObjectChildrenError } = useGetObjectChildren(idSystemObject, filter);
const queryData = getObjectChildrenData?.getObjectChildren;

const nodeId = getRepositoryTreeNodeId(idSystemObject, idObject, objectType);
const isEmpty = !getObjectChildrenData?.getObjectChildren?.entries.length ?? false;
const entries = getSortedTreeEntries(getObjectChildrenData?.getObjectChildren?.entries ?? []);
const metadataColumns = getObjectChildrenData?.getObjectChildren?.metadataColumns ?? [];
const isEmpty = !queryData?.entries.length ?? true;
const entries = getSortedTreeEntries(queryData?.entries ?? []);
const metadataColumns = queryData?.metadataColumns ?? [];
const loading = getObjectChildrenLoading && !getObjectChildrenError;

const loadData = expandedNodes.has(nodeId);

React.useEffect(() => {
if (loadData) {
getObjectChildren();
}
}, [loadData, getObjectChildren]);

return (
<StyledTreeItem
icon={icon}
color={color}
onLabelClick={getObjectChildren}
onIconClick={getObjectChildren}
objectType={objectType}
nodeId={nodeId}
label={name}
treeColumns={treeColumns}
>
<TreeViewContents name={name} loading={getObjectChildrenLoading && !getObjectChildrenError} isEmpty={isEmpty} objectType={objectType}>
{renderTreeNodes(filter, entries, metadataColumns)}
<TreeViewContents name={name} loading={loading} isEmpty={isEmpty} objectType={objectType}>
{renderTreeNodes(expandedNodes, filter, entries, metadataColumns)}
</TreeViewContents>
</StyledTreeItem>
);
}

export const renderTreeNodes = (filter: RepositoryFilter, entries: NavigationResultEntry[], metadataColumns: eMetadata[]): React.ReactNode =>
export const renderTreeNodes = (expandedNodes: ExpandedNodeMap, filter: RepositoryFilter, entries: NavigationResultEntry[], metadataColumns: eMetadata[]): React.ReactNode =>
entries.map((entry, index: number) => {
const { idSystemObject, name, objectType, idObject, metadata } = entry;
const variant = getTreeColorVariant(index);
Expand All @@ -69,6 +84,7 @@ export const renderTreeNodes = (filter: RepositoryFilter, entries: NavigationRes
idObject={idObject}
treeColumns={treeColumns}
filter={filter}
expandedNodes={expandedNodes}
/>
);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,11 @@ function TreeLabel(props: TreeLabelProps): React.ReactElement {
return (
<Box display='flex'>
<Box className={classes.label}>
<Tooltip title={objectTitle} placement='bottom-start'>
<Box className={classes.labelText}>
{label}
</Box>
</Tooltip>
<Box className={classes.labelText}>
<Tooltip title={objectTitle} placement='bottom-start'>
<span>{label}</span>
</Tooltip>
</Box>
</Box>
<MetadataView header={false} treeColumns={treeColumns} />
</Box>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { Box, Typography } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import { TreeView } from '@material-ui/lab';
import React from 'react';
import lodash from 'lodash';
import React, { useState } from 'react';
import { BsChevronDown, BsChevronRight } from 'react-icons/bs';
import { Loader } from '../../../../components';
import { getSortedTreeEntries, getSystemObjectTypesForFilter, getTreeWidth } from '../../../../utils/repository';
import { useGetRootObjects } from '../../hooks/useRepository';
import { RepositoryFilter } from '../../index';
import RepositoryTreeHeader from './RepositoryTreeHeader';
import { renderTreeNodes } from './RepositoryTreeNode';
import { ExpandedNodeMap, renderTreeNodes } from './RepositoryTreeNode';

const useStyles = makeStyles(({ palette, breakpoints }) => ({
container: {
Expand Down Expand Up @@ -45,6 +46,7 @@ interface RepositoryTreeViewProps {
function RepositoryTreeView(props: RepositoryTreeViewProps): React.ReactElement {
const { filter } = props;
const classes = useStyles();
const [expandedNodes, setExpandedNodes] = useState<ExpandedNodeMap>(new Map() as ExpandedNodeMap);

const objectTypes = getSystemObjectTypesForFilter(filter);
const { getRootObjectsData, getRootObjectsLoading, getRootObjectsError } = useGetRootObjects(objectTypes, filter);
Expand All @@ -58,14 +60,26 @@ function RepositoryTreeView(props: RepositoryTreeViewProps): React.ReactElement
let content: React.ReactNode = null;

if (!getRootObjectsLoading && !getRootObjectsError) {
content = renderTreeNodes(filter, entries, metadataColumns);
content = renderTreeNodes(expandedNodes, filter, entries, metadataColumns);
} else if (!noFilter) {
content = <Loader maxWidth='83.5vw' size={30} />;
}

const onNodeToggle = (_, nodeIds: string[]) => {
const keyValueArray: [string, undefined][] = lodash.map(nodeIds, (id: string) => [id, undefined]);
const updatedMap: ExpandedNodeMap = new Map(keyValueArray);
setExpandedNodes(updatedMap);
};

return (
<Box className={classes.container}>
<TreeView className={classes.tree} style={{ width }} defaultCollapseIcon={<BsChevronDown />} defaultExpandIcon={<BsChevronRight />}>
<TreeView
onNodeToggle={onNodeToggle}
className={classes.tree}
style={{ width }}
defaultCollapseIcon={<BsChevronDown />}
defaultExpandIcon={<BsChevronRight />}
>
<RepositoryTreeHeader metadataColumns={metadataColumns} />
{noFilter && (
<Box className={classes.fullView}>
Expand Down
7 changes: 3 additions & 4 deletions client/src/pages/Repository/hooks/useRepository.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { eSystemObjectType, eMetadata } from '../../../types/server';
import { useQuery, useLazyQuery, ApolloError } from '@apollo/client';
import { ApolloError, useLazyQuery, useQuery } from '@apollo/client';
import { RepositoryFilter } from '../index';
import { GetObjectChildrenDocument, GetObjectChildrenQuery, GetObjectChildrenQueryVariables } from '../../../types/graphql';
import { RepositoryFilter } from '..';
import { eMetadata, eSystemObjectType } from '../../../types/server';

interface UseGetRootObjects {
getRootObjectsData: GetObjectChildrenQuery | undefined;
getRootObjectsLoading: boolean;
getRootObjectsError: ApolloError | undefined;
}


function useGetRootObjects(objectTypes: eSystemObjectType[], filter: RepositoryFilter): UseGetRootObjects {
const { data: getRootObjectsData, loading: getRootObjectsLoading, error: getRootObjectsError } = useQuery<GetObjectChildrenQuery, GetObjectChildrenQueryVariables>(
GetObjectChildrenDocument,
Expand Down
2 changes: 1 addition & 1 deletion client/src/pages/Repository/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ function Repository(): React.ReactElement {

const queries = parseRepositoryUrl(search);

const initialFilterState = {
const initialFilterState: RepositoryFilter = {
units: true,
projects: false
};
Expand Down

0 comments on commit b4fed61

Please sign in to comment.