mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Expand and collapse tree nodes
Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
This commit is contained in:
parent
e6ab47f1eb
commit
0ecf00ed03
@ -1,5 +1,211 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`<NamespaceTreeView /> once the subscribe resolves collapses item by clicking minus button 1`] = `
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
data-testid="namespace-tree-view"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="DrawerTitle title"
|
||||||
|
>
|
||||||
|
Tree View
|
||||||
|
</div>
|
||||||
|
<ul
|
||||||
|
aria-multiselectable="false"
|
||||||
|
class="MuiTreeView-root"
|
||||||
|
role="tree"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
aria-expanded="true"
|
||||||
|
class="MuiTreeItem-root Mui-expanded"
|
||||||
|
data-testid="namespace-levels-deep-1"
|
||||||
|
role="treeitem"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiTreeItem-content"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiTreeItem-iconContainer Component-iconContainer-22"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="MuiSvgIcon-root"
|
||||||
|
data-testid="minus-square"
|
||||||
|
focusable="false"
|
||||||
|
style="width: 14px; height: 14px;"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M22.047 22.074v0 0-20.147 0h-20.12v0 20.147 0h20.12zM22.047 24h-20.12q-.803 0-1.365-.562t-.562-1.365v-20.147q0-.776.562-1.351t1.365-.575h20.147q.776 0 1.351.575t.575 1.351v20.147q0 .803-.575 1.365t-1.378.562v0zM17.873 11.023h-11.826q-.375 0-.669.281t-.294.682v0q0 .401.294 .682t.669.281h11.826q.375 0 .669-.281t.294-.682v0q0-.401-.294-.682t-.669-.281z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="MuiTypography-root MuiTreeItem-label Component-label-24 MuiTypography-body1"
|
||||||
|
>
|
||||||
|
levels-deep
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ul
|
||||||
|
class="MuiCollapse-root MuiTreeItem-group Component-group-23 MuiCollapse-entered"
|
||||||
|
role="group"
|
||||||
|
style="min-height: 0px;"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiCollapse-wrapper"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiCollapse-wrapperInner"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="MuiTreeItem-root Mui-expanded"
|
||||||
|
data-testid="namespace-level-deep-child-a-1"
|
||||||
|
role="treeitem"
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiTreeItem-content"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiTreeItem-iconContainer Component-iconContainer-22"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="MuiSvgIcon-root close"
|
||||||
|
focusable="false"
|
||||||
|
style="width: 14px; height: 14px;"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M17.485 17.512q-.281.281-.682.281t-.696-.268l-4.12-4.147-4.12 4.147q-.294.268-.696.268t-.682-.281-.281-.682.294-.669l4.12-4.147-4.12-4.147q-.294-.268-.294-.669t.281-.682.682-.281.696 .268l4.12 4.147 4.12-4.147q.294-.268.696-.268t.682.281 .281.669-.294.682l-4.12 4.147 4.12 4.147q.294.268 .294.669t-.281.682zM22.047 22.074v0 0-20.147 0h-20.12v0 20.147 0h20.12zM22.047 24h-20.12q-.803 0-1.365-.562t-.562-1.365v-20.147q0-.776.562-1.351t1.365-.575h20.147q.776 0 1.351.575t.575 1.351v20.147q0 .803-.575 1.365t-1.378.562v0z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="MuiTypography-root MuiTreeItem-label Component-label-24 MuiTypography-body1"
|
||||||
|
>
|
||||||
|
level-deep-child-a
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ul
|
||||||
|
class="MuiCollapse-root MuiTreeItem-group Component-group-23 MuiCollapse-entered"
|
||||||
|
role="group"
|
||||||
|
style="min-height: 0px;"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiCollapse-wrapper"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiCollapse-wrapperInner"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
aria-expanded="false"
|
||||||
|
class="MuiTreeItem-root"
|
||||||
|
data-testid="namespace-level-deep-child-b-1"
|
||||||
|
role="treeitem"
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiTreeItem-content"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiTreeItem-iconContainer Component-iconContainer-22"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="MuiSvgIcon-root"
|
||||||
|
focusable="false"
|
||||||
|
style="width: 14px; height: 14px;"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M22.047 22.074v0 0-20.147 0h-20.12v0 20.147 0h20.12zM22.047 24h-20.12q-.803 0-1.365-.562t-.562-1.365v-20.147q0-.776.562-1.351t1.365-.575h20.147q.776 0 1.351.575t.575 1.351v20.147q0 .803-.575 1.365t-1.378.562v0zM17.873 12.977h-4.923v4.896q0 .401-.281.682t-.682.281v0q-.375 0-.669-.281t-.294-.682v-4.896h-4.923q-.401 0-.682-.294t-.281-.669v0q0-.401.281-.682t.682-.281h4.923v-4.896q0-.401.294-.682t.669-.281v0q.401 0 .682.281t.281.682v4.896h4.923q.401 0 .682.281t.281.682v0q0 .375-.281.669t-.682.294z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="MuiTypography-root MuiTreeItem-label Component-label-24 MuiTypography-body1"
|
||||||
|
>
|
||||||
|
level-deep-child-b
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ul
|
||||||
|
class="MuiCollapse-root MuiTreeItem-group Component-group-23"
|
||||||
|
role="group"
|
||||||
|
style="min-height: 0px; height: 0px; transition-duration: 300ms;"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiCollapse-wrapper"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiCollapse-wrapperInner"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="MuiTreeItem-root Mui-expanded"
|
||||||
|
data-testid="namespace-level-deep-subchild-a-1"
|
||||||
|
role="treeitem"
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiTreeItem-content"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiTreeItem-iconContainer Component-iconContainer-22"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="MuiSvgIcon-root close"
|
||||||
|
focusable="false"
|
||||||
|
style="width: 14px; height: 14px;"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M17.485 17.512q-.281.281-.682.281t-.696-.268l-4.12-4.147-4.12 4.147q-.294.268-.696.268t-.682-.281-.281-.682.294-.669l4.12-4.147-4.12-4.147q-.294-.268-.294-.669t.281-.682.682-.281.696 .268l4.12 4.147 4.12-4.147q.294-.268.696-.268t.682.281 .281.669-.294.682l-4.12 4.147 4.12 4.147q.294.268 .294.669t-.281.682zM22.047 22.074v0 0-20.147 0h-20.12v0 20.147 0h20.12zM22.047 24h-20.12q-.803 0-1.365-.562t-.562-1.365v-20.147q0-.776.562-1.351t1.365-.575h20.147q.776 0 1.351.575t.575 1.351v20.147q0 .803-.575 1.365t-1.378.562v0z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="MuiTypography-root MuiTreeItem-label Component-label-24 MuiTypography-body1"
|
||||||
|
>
|
||||||
|
level-deep-subchild-a
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ul
|
||||||
|
class="MuiCollapse-root MuiTreeItem-group Component-group-23 MuiCollapse-entered"
|
||||||
|
role="group"
|
||||||
|
style="min-height: 0px;"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiCollapse-wrapper"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiCollapse-wrapperInner"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`<NamespaceTreeView /> once the subscribe resolves renders 2 levels deep 1`] = `
|
exports[`<NamespaceTreeView /> once the subscribe resolves renders 2 levels deep 1`] = `
|
||||||
<body>
|
<body>
|
||||||
<div>
|
<div>
|
||||||
@ -32,6 +238,7 @@ exports[`<NamespaceTreeView /> once the subscribe resolves renders 2 levels deep
|
|||||||
<svg
|
<svg
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
class="MuiSvgIcon-root"
|
class="MuiSvgIcon-root"
|
||||||
|
data-testid="minus-square"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
style="width: 14px; height: 14px;"
|
style="width: 14px; height: 14px;"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
@ -119,6 +326,7 @@ exports[`<NamespaceTreeView /> once the subscribe resolves renders 2 levels deep
|
|||||||
<svg
|
<svg
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
class="MuiSvgIcon-root"
|
class="MuiSvgIcon-root"
|
||||||
|
data-testid="minus-square"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
style="width: 14px; height: 14px;"
|
style="width: 14px; height: 14px;"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
@ -237,6 +445,7 @@ exports[`<NamespaceTreeView /> once the subscribe resolves renders namespace wit
|
|||||||
<svg
|
<svg
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
class="MuiSvgIcon-root"
|
class="MuiSvgIcon-root"
|
||||||
|
data-testid="minus-square"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
style="width: 14px; height: 14px;"
|
style="width: 14px; height: 14px;"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
@ -395,6 +604,7 @@ exports[`<NamespaceTreeView /> once the subscribe resolves renders namespace wit
|
|||||||
<svg
|
<svg
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
class="MuiSvgIcon-root"
|
class="MuiSvgIcon-root"
|
||||||
|
data-testid="minus-square"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
style="width: 14px; height: 14px;"
|
style="width: 14px; height: 14px;"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import type { AsyncFnMock } from "@async-fn/jest";
|
import type { AsyncFnMock } from "@async-fn/jest";
|
||||||
import asyncFn from "@async-fn/jest";
|
import asyncFn from "@async-fn/jest";
|
||||||
import type { DiContainer } from "@ogre-tools/injectable";
|
import type { DiContainer } from "@ogre-tools/injectable";
|
||||||
|
import { fireEvent } from "@testing-library/react";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import directoryForKubeConfigsInjectable from "../../../common/app-paths/directory-for-kube-configs/directory-for-kube-configs.injectable";
|
import directoryForKubeConfigsInjectable from "../../../common/app-paths/directory-for-kube-configs/directory-for-kube-configs.injectable";
|
||||||
import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||||
@ -219,11 +220,21 @@ describe("<NamespaceTreeView />", () => {
|
|||||||
expect(result.baseElement).toMatchSnapshot();
|
expect(result.baseElement).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("expands children items", () => {
|
it("expands children items by default", () => {
|
||||||
const result = render(<NamespaceTreeView root={levelsDeep} />);
|
const result = render(<NamespaceTreeView root={levelsDeep} />);
|
||||||
const deepest = result.getByTestId("namespace-level-deep-child-b-1");
|
const deepest = result.getByTestId("namespace-level-deep-child-b-1");
|
||||||
|
|
||||||
expect(deepest).toHaveAttribute("aria-expanded", "true");
|
expect(deepest).toHaveAttribute("aria-expanded", "true");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("collapses item by clicking minus button", () => {
|
||||||
|
const result = render(<NamespaceTreeView root={levelsDeep} />);
|
||||||
|
const levelB = result.getByTestId("namespace-level-deep-child-b-1");
|
||||||
|
const minusButton = levelB.querySelector("[data-testid='minus-square']");
|
||||||
|
|
||||||
|
fireEvent.click(minusButton!);
|
||||||
|
|
||||||
|
expect(result.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -20,9 +20,15 @@ interface Dependencies {
|
|||||||
getDetailsUrl: GetDetailsUrl;
|
getDetailsUrl: GetDetailsUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isNamespaceControlledByHNC(namespace: Namespace) {
|
||||||
|
const hierarchicalNamesaceControllerLabel = "hnc.x-k8s.io/included-namespace=true";
|
||||||
|
|
||||||
|
return namespace.getLabels().find(label => label === hierarchicalNamesaceControllerLabel);
|
||||||
|
}
|
||||||
|
|
||||||
function NonInjectableNamespaceTreeView({ root, namespaceStore, getDetailsUrl }: Dependencies & NamespaceTreeViewProps) {
|
function NonInjectableNamespaceTreeView({ root, namespaceStore, getDetailsUrl }: Dependencies & NamespaceTreeViewProps) {
|
||||||
const hierarchicalNamespaces = namespaceStore.getByLabel(["hnc.x-k8s.io/included-namespace=true"]);
|
const hierarchicalNamespaces = namespaceStore.getByLabel(["hnc.x-k8s.io/included-namespace=true"]);
|
||||||
const expandedItems = hierarchicalNamespaces.map(ns => `namespace-${ns.getId()}`);
|
const [expandedItems, setExpandedItems] = React.useState<string[]>(hierarchicalNamespaces.map(ns => `namespace-${ns.getId()}`));
|
||||||
|
|
||||||
function renderChildren(parent: Namespace) {
|
function renderChildren(parent: Namespace) {
|
||||||
const children = hierarchicalNamespaces.filter(ns =>
|
const children = hierarchicalNamespaces.filter(ns =>
|
||||||
@ -34,6 +40,10 @@ function NonInjectableNamespaceTreeView({ root, namespaceStore, getDetailsUrl }:
|
|||||||
key={`namespace-${child.getId()}`}
|
key={`namespace-${child.getId()}`}
|
||||||
nodeId={`namespace-${child.getId()}`}
|
nodeId={`namespace-${child.getId()}`}
|
||||||
data-testid={`namespace-${child.getId()}`}
|
data-testid={`namespace-${child.getId()}`}
|
||||||
|
onIconClick={(evt) =>{
|
||||||
|
toggleNode(`namespace-${child.getId()}`)
|
||||||
|
evt.stopPropagation();
|
||||||
|
}}
|
||||||
label={(
|
label={(
|
||||||
<>
|
<>
|
||||||
<Link key={child.getId()} to={getDetailsUrl(child.selfLink)}>
|
<Link key={child.getId()} to={getDetailsUrl(child.selfLink)}>
|
||||||
@ -49,7 +59,15 @@ function NonInjectableNamespaceTreeView({ root, namespaceStore, getDetailsUrl }:
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!root.getLabels().find(label => label === "hnc.x-k8s.io/included-namespace=true")) {
|
function toggleNode(id: string) {
|
||||||
|
if (expandedItems.includes(id)) {
|
||||||
|
setExpandedItems(expandedItems.filter(item => item !== id));
|
||||||
|
} else {
|
||||||
|
setExpandedItems([...expandedItems, id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isNamespaceControlledByHNC(root)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,6 +85,10 @@ function NonInjectableNamespaceTreeView({ root, namespaceStore, getDetailsUrl }:
|
|||||||
nodeId={`namespace-${root.getId()}`}
|
nodeId={`namespace-${root.getId()}`}
|
||||||
label={root.getName()}
|
label={root.getName()}
|
||||||
data-testid={`namespace-${root.getId()}`}
|
data-testid={`namespace-${root.getId()}`}
|
||||||
|
onIconClick={(evt) => {
|
||||||
|
toggleNode(`namespace-${root.getId()}`);
|
||||||
|
evt.stopPropagation();
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{renderChildren(root)}
|
{renderChildren(root)}
|
||||||
</StyledTreeItem>
|
</StyledTreeItem>
|
||||||
@ -77,7 +99,7 @@ function NonInjectableNamespaceTreeView({ root, namespaceStore, getDetailsUrl }:
|
|||||||
|
|
||||||
function MinusSquare() {
|
function MinusSquare() {
|
||||||
return (
|
return (
|
||||||
<SvgIcon style={{ width: 14, height: 14 }}>
|
<SvgIcon style={{ width: 14, height: 14 }} data-testid="minus-square">
|
||||||
<path d="M22.047 22.074v0 0-20.147 0h-20.12v0 20.147 0h20.12zM22.047 24h-20.12q-.803 0-1.365-.562t-.562-1.365v-20.147q0-.776.562-1.351t1.365-.575h20.147q.776 0 1.351.575t.575 1.351v20.147q0 .803-.575 1.365t-1.378.562v0zM17.873 11.023h-11.826q-.375 0-.669.281t-.294.682v0q0 .401.294 .682t.669.281h11.826q.375 0 .669-.281t.294-.682v0q0-.401-.294-.682t-.669-.281z" />
|
<path d="M22.047 22.074v0 0-20.147 0h-20.12v0 20.147 0h20.12zM22.047 24h-20.12q-.803 0-1.365-.562t-.562-1.365v-20.147q0-.776.562-1.351t1.365-.575h20.147q.776 0 1.351.575t.575 1.351v20.147q0 .803-.575 1.365t-1.378.562v0zM17.873 11.023h-11.826q-.375 0-.669.281t-.294.682v0q0 .401.294 .682t.669.281h11.826q.375 0 .669-.281t.294-.682v0q0-.401-.294-.682t-.669-.281z" />
|
||||||
</SvgIcon>
|
</SvgIcon>
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user