1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00
lens/src/renderer/components/tree-view/tree-view.tsx
2021-11-01 08:45:45 -04:00

122 lines
3.5 KiB
TypeScript

/**
* Copyright (c) 2021 OpenLens Authors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
import "./tree-view.scss";
import React, { useEffect, useRef } from "react";
import { Icon } from "../icon";
import TreeView from "@material-ui/lab/TreeView";
import TreeItem from "@material-ui/lab/TreeItem";
import { cssNames } from "../../utils";
import _ from "lodash";
import getDeepDash from "deepdash";
const deepDash = getDeepDash(_);
export interface NavigationTree {
id: string;
parentId: string;
name: string;
selected?: boolean;
children?: NavigationTree[];
}
interface Props {
data: NavigationTree[]
}
function scrollToItem(id: string) {
document.getElementById(id)?.scrollIntoView();
}
function getSelectedNode(data: NavigationTree[]) {
return deepDash.findDeep(data, (value, key) => key === "selected" && value === true)?.parent;
}
export function RecursiveTreeView({ data }: Props) {
const [expanded, setExpanded] = React.useState<string[]>([]);
const prevData = useRef<NavigationTree[]>(data);
const handleToggle = (event: React.ChangeEvent<{}>, nodeIds: string[]) => {
setExpanded(nodeIds);
};
const expandTopLevelNodes = () => {
setExpanded(data.map(node => node.id));
};
const expandParentNode = () => {
const node = getSelectedNode(data) as any as NavigationTree;
const id = node?.parentId;
if (id && !expanded.includes(id)) {
setExpanded([...expanded, id]);
}
};
const onLabelClick = (event: React.MouseEvent, nodeId: string) => {
event.preventDefault();
scrollToItem(nodeId);
};
const renderTree = (nodes: NavigationTree[]) => {
return nodes.map(node => (
<TreeItem
key={node.id}
nodeId={node.id}
label={node.name}
onLabelClick={(event) => onLabelClick(event, node.id)}
className={cssNames({ selected: node.selected })}
title={node.name}
>
{Array.isArray(node.children) ? node.children.map((node) => renderTree([node])) : null}
</TreeItem>
));
};
useEffect(() => {
if (!prevData.current.length) {
expandTopLevelNodes();
} else {
expandParentNode();
}
prevData.current = data;
}, [data]);
if (!data.length) {
return null;
}
return (
<TreeView
data-testid="TreeView"
className="TreeView"
expanded={expanded}
onNodeToggle={handleToggle}
defaultCollapseIcon={<Icon material="expand_more"/>}
defaultExpandIcon={<Icon material="chevron_right" />}
>
{renderTree(data)}
</TreeView>
);
}