1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Refactor: move tree build logic to store

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
This commit is contained in:
Alex Andreev 2023-02-08 17:23:36 +03:00
parent 0cf649de69
commit 690bef9597
6 changed files with 240 additions and 235 deletions

View File

@ -34,9 +34,19 @@ export class Namespace extends KubeObject<
return this.status?.phase ?? "-";
}
isSubnamespace(){
isSubnamespace() {
return this.getAnnotations().find(annotation => annotation.includes("hnc.x-k8s.io/subnamespace-of"));
}
isChildOf(parentName: string) {
this.getLabels().find(label => label === `${parentName}.tree.hnc.x-k8s.io/depth=1`);
}
isControlledByHNC() {
const hierarchicalNamesaceControllerLabel = "hnc.x-k8s.io/included-namespace=true";
return this.getLabels().find(label => label === hierarchicalNamesaceControllerLabel);
}
}
export class NamespaceApi extends KubeApi<Namespace> {

View File

@ -20,7 +20,7 @@ exports[`<NamespaceTreeView /> collapses item by clicking minus button 1`] = `
<li
aria-expanded="true"
class="MuiTreeItem-root Mui-expanded"
data-testid="namespace-levels-deep-1"
data-testid="namespace-levels-deep"
role="treeitem"
tabindex="0"
>
@ -47,6 +47,7 @@ exports[`<NamespaceTreeView /> collapses item by clicking minus button 1`] = `
class="MuiTypography-root MuiTreeItem-label label MuiTypography-body1"
>
levels-deep
</div>
</div>
<ul
@ -62,7 +63,7 @@ exports[`<NamespaceTreeView /> collapses item by clicking minus button 1`] = `
>
<li
class="MuiTreeItem-root Mui-expanded"
data-testid="namespace-level-deep-child-a-1"
data-testid="namespace-level-deep-child-a"
role="treeitem"
tabindex="-1"
>
@ -96,24 +97,11 @@ exports[`<NamespaceTreeView /> collapses item by clicking minus button 1`] = `
</div>
</div>
<ul
class="MuiCollapse-root MuiTreeItem-group group 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"
data-testid="namespace-level-deep-child-b"
role="treeitem"
tabindex="-1"
>
@ -156,7 +144,7 @@ exports[`<NamespaceTreeView /> collapses item by clicking minus button 1`] = `
>
<li
class="MuiTreeItem-root Mui-expanded"
data-testid="namespace-level-deep-subchild-a-1"
data-testid="namespace-level-deep-subchild-a"
role="treeitem"
tabindex="-1"
>
@ -190,19 +178,6 @@ exports[`<NamespaceTreeView /> collapses item by clicking minus button 1`] = `
</div>
</div>
<ul
class="MuiCollapse-root MuiTreeItem-group group MuiCollapse-entered"
role="group"
style="min-height: 0px;"
>
<div
class="MuiCollapse-wrapper"
>
<div
class="MuiCollapse-wrapperInner"
/>
</div>
</ul>
</li>
</div>
</div>
@ -238,7 +213,7 @@ exports[`<NamespaceTreeView /> expands item by clicking plus button 1`] = `
<li
aria-expanded="true"
class="MuiTreeItem-root Mui-expanded"
data-testid="namespace-levels-deep-1"
data-testid="namespace-levels-deep"
role="treeitem"
tabindex="0"
>
@ -265,6 +240,7 @@ exports[`<NamespaceTreeView /> expands item by clicking plus button 1`] = `
class="MuiTypography-root MuiTreeItem-label label MuiTypography-body1"
>
levels-deep
</div>
</div>
<ul
@ -280,7 +256,7 @@ exports[`<NamespaceTreeView /> expands item by clicking plus button 1`] = `
>
<li
class="MuiTreeItem-root Mui-expanded"
data-testid="namespace-level-deep-child-a-1"
data-testid="namespace-level-deep-child-a"
role="treeitem"
tabindex="-1"
>
@ -314,24 +290,11 @@ exports[`<NamespaceTreeView /> expands item by clicking plus button 1`] = `
</div>
</div>
<ul
class="MuiCollapse-root MuiTreeItem-group group MuiCollapse-entered"
role="group"
style="min-height: 0px;"
>
<div
class="MuiCollapse-wrapper"
>
<div
class="MuiCollapse-wrapperInner"
/>
</div>
</ul>
</li>
<li
aria-expanded="true"
class="MuiTreeItem-root Mui-expanded"
data-testid="namespace-level-deep-child-b-1"
data-testid="namespace-level-deep-child-b"
role="treeitem"
tabindex="-1"
>
@ -374,7 +337,7 @@ exports[`<NamespaceTreeView /> expands item by clicking plus button 1`] = `
>
<li
class="MuiTreeItem-root Mui-expanded"
data-testid="namespace-level-deep-subchild-a-1"
data-testid="namespace-level-deep-subchild-a"
role="treeitem"
tabindex="-1"
>
@ -408,19 +371,6 @@ exports[`<NamespaceTreeView /> expands item by clicking plus button 1`] = `
</div>
</div>
<ul
class="MuiCollapse-root MuiTreeItem-group group MuiCollapse-entered"
role="group"
style="min-height: 0px;"
>
<div
class="MuiCollapse-wrapper"
>
<div
class="MuiCollapse-wrapperInner"
/>
</div>
</ul>
</li>
</div>
</div>
@ -456,7 +406,7 @@ exports[`<NamespaceTreeView /> renders 2 levels deep 1`] = `
<li
aria-expanded="true"
class="MuiTreeItem-root Mui-expanded"
data-testid="namespace-levels-deep-1"
data-testid="namespace-levels-deep"
role="treeitem"
tabindex="0"
>
@ -483,6 +433,7 @@ exports[`<NamespaceTreeView /> renders 2 levels deep 1`] = `
class="MuiTypography-root MuiTreeItem-label label MuiTypography-body1"
>
levels-deep
</div>
</div>
<ul
@ -498,7 +449,7 @@ exports[`<NamespaceTreeView /> renders 2 levels deep 1`] = `
>
<li
class="MuiTreeItem-root Mui-expanded"
data-testid="namespace-level-deep-child-a-1"
data-testid="namespace-level-deep-child-a"
role="treeitem"
tabindex="-1"
>
@ -532,24 +483,11 @@ exports[`<NamespaceTreeView /> renders 2 levels deep 1`] = `
</div>
</div>
<ul
class="MuiCollapse-root MuiTreeItem-group group MuiCollapse-entered"
role="group"
style="min-height: 0px;"
>
<div
class="MuiCollapse-wrapper"
>
<div
class="MuiCollapse-wrapperInner"
/>
</div>
</ul>
</li>
<li
aria-expanded="true"
class="MuiTreeItem-root Mui-expanded"
data-testid="namespace-level-deep-child-b-1"
data-testid="namespace-level-deep-child-b"
role="treeitem"
tabindex="-1"
>
@ -592,7 +530,7 @@ exports[`<NamespaceTreeView /> renders 2 levels deep 1`] = `
>
<li
class="MuiTreeItem-root Mui-expanded"
data-testid="namespace-level-deep-subchild-a-1"
data-testid="namespace-level-deep-subchild-a"
role="treeitem"
tabindex="-1"
>
@ -626,19 +564,6 @@ exports[`<NamespaceTreeView /> renders 2 levels deep 1`] = `
</div>
</div>
<ul
class="MuiCollapse-root MuiTreeItem-group group MuiCollapse-entered"
role="group"
style="min-height: 0px;"
>
<div
class="MuiCollapse-wrapper"
>
<div
class="MuiCollapse-wrapperInner"
/>
</div>
</ul>
</li>
</div>
</div>
@ -674,7 +599,7 @@ exports[`<NamespaceTreeView /> renders namespace with 2 children namespaces 1`]
<li
aria-expanded="true"
class="MuiTreeItem-root Mui-expanded"
data-testid="namespace-acme-org-1"
data-testid="namespace-acme-org"
role="treeitem"
tabindex="0"
>
@ -701,6 +626,7 @@ exports[`<NamespaceTreeView /> renders namespace with 2 children namespaces 1`]
class="MuiTypography-root MuiTreeItem-label label MuiTypography-body1"
>
acme-org
</div>
</div>
<ul
@ -716,7 +642,7 @@ exports[`<NamespaceTreeView /> renders namespace with 2 children namespaces 1`]
>
<li
class="MuiTreeItem-root Mui-expanded"
data-testid="namespace-team-a-1"
data-testid="namespace-team-a"
role="treeitem"
tabindex="-1"
>
@ -750,23 +676,10 @@ exports[`<NamespaceTreeView /> renders namespace with 2 children namespaces 1`]
</div>
</div>
<ul
class="MuiCollapse-root MuiTreeItem-group group MuiCollapse-entered"
role="group"
style="min-height: 0px;"
>
<div
class="MuiCollapse-wrapper"
>
<div
class="MuiCollapse-wrapperInner"
/>
</div>
</ul>
</li>
<li
class="MuiTreeItem-root Mui-expanded"
data-testid="namespace-team-b-1"
data-testid="namespace-team-b"
role="treeitem"
tabindex="-1"
>
@ -800,19 +713,6 @@ exports[`<NamespaceTreeView /> renders namespace with 2 children namespaces 1`]
</div>
</div>
<ul
class="MuiCollapse-root MuiTreeItem-group group MuiCollapse-entered"
role="group"
style="min-height: 0px;"
>
<div
class="MuiCollapse-wrapper"
>
<div
class="MuiCollapse-wrapperInner"
/>
</div>
</ul>
</li>
</div>
</div>
@ -844,7 +744,7 @@ exports[`<NamespaceTreeView /> renders namespace with children namespaces and a
<li
aria-expanded="true"
class="MuiTreeItem-root Mui-expanded"
data-testid="namespace-org-a-1"
data-testid="namespace-org-a"
role="treeitem"
tabindex="0"
>
@ -871,6 +771,7 @@ exports[`<NamespaceTreeView /> renders namespace with children namespaces and a
class="MuiTypography-root MuiTreeItem-label label MuiTypography-body1"
>
org-a
</div>
</div>
<ul
@ -886,7 +787,7 @@ exports[`<NamespaceTreeView /> renders namespace with children namespaces and a
>
<li
class="MuiTreeItem-root Mui-expanded"
data-testid="namespace-team-c-1"
data-testid="namespace-team-c"
role="treeitem"
tabindex="-1"
>
@ -920,23 +821,10 @@ exports[`<NamespaceTreeView /> renders namespace with children namespaces and a
</div>
</div>
<ul
class="MuiCollapse-root MuiTreeItem-group group MuiCollapse-entered"
role="group"
style="min-height: 0px;"
>
<div
class="MuiCollapse-wrapper"
>
<div
class="MuiCollapse-wrapperInner"
/>
</div>
</ul>
</li>
<li
class="MuiTreeItem-root Mui-expanded"
data-testid="namespace-service-1-1"
data-testid="namespace-service-1"
role="treeitem"
tabindex="-1"
>
@ -970,26 +858,13 @@ exports[`<NamespaceTreeView /> renders namespace with children namespaces and a
<span
class="subnamespaceBadge"
data-testid="namespace-details-badge-for-service-1-1"
id="namespace-details-badge-for-service-1-1"
data-testid="namespace-details-badge-for-service-1"
id="namespace-details-badge-for-service-1"
>
S
</span>
</div>
</div>
<ul
class="MuiCollapse-root MuiTreeItem-group group MuiCollapse-entered"
role="group"
style="min-height: 0px;"
>
<div
class="MuiCollapse-wrapper"
>
<div
class="MuiCollapse-wrapperInner"
/>
</div>
</ul>
</li>
</div>
</div>
@ -1001,12 +876,6 @@ exports[`<NamespaceTreeView /> renders namespace with children namespaces and a
</body>
`;
exports[`<NamespaceTreeView /> renders null with regular namespace 1`] = `
<body>
<div />
</body>
`;
exports[`<NamespaceTreeView /> renders one namespace without children 1`] = `
<body>
<div>
@ -1026,7 +895,7 @@ exports[`<NamespaceTreeView /> renders one namespace without children 1`] = `
>
<li
class="MuiTreeItem-root"
data-testid="namespace-single-root-1"
data-testid="namespace-single-root"
role="treeitem"
tabindex="0"
>
@ -1057,6 +926,7 @@ exports[`<NamespaceTreeView /> renders one namespace without children 1`] = `
class="MuiTypography-root MuiTreeItem-label label MuiTypography-body1"
>
single-root
</div>
</div>
</li>

View File

@ -27,6 +27,8 @@ import resourceQuotaStoreInjectable from "../+config-resource-quotas/store.injec
import type { Logger } from "../../../common/logger";
import loggerInjectable from "../../../common/logger.injectable";
import { NamespaceTreeView } from "./namespace-tree-view";
import namespaceStoreInjectable from "./store.injectable";
import type { NamespaceStore } from "./store";
export interface NamespaceDetailsProps extends KubeObjectDetailsProps<Namespace> {
}
@ -36,6 +38,7 @@ interface Dependencies {
getDetailsUrl: GetDetailsUrl;
resourceQuotaStore: ResourceQuotaStore;
limitRangeStore: LimitRangeStore;
namespaceStore: NamespaceStore;
logger: Logger;
}
@ -105,7 +108,9 @@ class NonInjectedNamespaceDetails extends React.Component<NamespaceDetailsProps
))}
</DrawerItem>
<NamespaceTreeView root={namespace}/>
{namespace.isControlledByHNC() && (
<NamespaceTreeView tree={this.props.namespaceStore.getNamespaceTree(namespace)}/>
)}
</div>
);
}
@ -118,6 +123,7 @@ export const NamespaceDetails = withInjectables<Dependencies, NamespaceDetailsPr
getDetailsUrl: di.inject(getDetailsUrlInjectable),
limitRangeStore: di.inject(limitRangeStoreInjectable),
resourceQuotaStore: di.inject(resourceQuotaStoreInjectable),
namespaceStore: di.inject(namespaceStoreInjectable),
logger: di.inject(loggerInjectable),
}),
});

View File

@ -11,6 +11,7 @@ import type { DiRender } from "../test-utils/renderFor";
import { renderFor } from "../test-utils/renderFor";
import hierarchicalNamespacesInjectable from "./hierarchical-namespaces.injectable";
import { NamespaceTreeView } from "./namespace-tree-view";
import type { NamespaceTree } from "./store";
jest.mock("react-router-dom", () => ({
Link: ({ children }: { children: React.ReactNode }) => children,
@ -24,7 +25,7 @@ function createNamespace(name: string, labels?: Record<string, string>, annotati
name,
resourceVersion: "1",
selfLink: `/api/v1/namespaces/${name}`,
uid: `${name}-1`,
uid: `${name}`,
labels: {
...labels,
},
@ -123,59 +124,169 @@ describe("<NamespaceTreeView />", () => {
render = renderFor(di);
});
it("renders null with regular namespace", () => {
const result = render(<NamespaceTreeView root={createNamespace("tree-1")} />);
expect(result.baseElement).toMatchSnapshot();
});
it("renders one namespace without children", () => {
const result = render(<NamespaceTreeView root={singleRoot} />);
const tree: NamespaceTree = {
id: "single-root",
namespace: singleRoot
}
const result = render(<NamespaceTreeView tree={tree} />);
expect(result.baseElement).toMatchSnapshot();
});
it("renders namespace with 2 children namespaces", () => {
const result = render(<NamespaceTreeView root={acmeGroup} />);
const tree: NamespaceTree = {
id: "acme-org",
namespace: acmeGroup,
children: [
{
id: "team-a",
namespace: teamA
},
{
id: "team-b",
namespace: teamB
}
]
}
const result = render(<NamespaceTreeView tree={tree} />);
expect(result.baseElement).toMatchSnapshot();
});
it("renders namespace with children namespaces and a subnamespace", () => {
const result = render(<NamespaceTreeView root={orgA} />);
const tree: NamespaceTree = {
id: "org-a",
namespace: orgA,
children: [
{
id: "team-c",
namespace: teamC
},
{
id: "service-1",
namespace: service1
}
]
}
const result = render(<NamespaceTreeView tree={tree} />);
expect(result.baseElement).toMatchSnapshot();
});
it("renders an indicator badge for the subnamespace", () => {
const result = render(<NamespaceTreeView root={orgA} />);
const tree: NamespaceTree = {
id: "org-a",
namespace: orgA,
children: [
{
id: "team-c",
namespace: teamC
},
{
id: "service-1",
namespace: service1
}
]
}
const result = render(<NamespaceTreeView tree={tree} />);
expect(result.getByTestId("namespace-details-badge-for-service-1-1")).toBeInTheDocument();
expect(result.getByTestId("namespace-details-badge-for-service-1")).toBeInTheDocument();
});
it("does not render an indicator badge for the true namespace", () => {
const result = render(<NamespaceTreeView root={orgA} />);
const trueNamespace = result.getByTestId("namespace-team-c-1");
const tree: NamespaceTree = {
id: "org-a",
namespace: orgA,
children: [
{
id: "team-c",
namespace: teamC
},
{
id: "service-1",
namespace: service1
}
]
}
const result = render(<NamespaceTreeView tree={tree} />);
const trueNamespace = result.getByTestId("namespace-team-c");
expect(trueNamespace.querySelector("[data-testid='namespace-details-badge-for-team-c-1']")).toBeNull();
expect(trueNamespace.querySelector("[data-testid='namespace-details-badge-for-team-c']")).toBeNull();
});
it("renders 2 levels deep", () => {
const result = render(<NamespaceTreeView root={levelsDeep} />);
const tree: NamespaceTree = {
id: "levels-deep",
namespace: levelsDeep,
children: [
{
id: "level-deep-child-a",
namespace: levelDeepChildA
},
{
id: "level-deep-child-b",
namespace: levelDeepChildB,
children: [{
id: "level-deep-subchild-a",
namespace: levelDeepSubChildA
}]
}
]
}
const result = render(<NamespaceTreeView tree={tree} />);
expect(result.baseElement).toMatchSnapshot();
});
it("expands children items by default", () => {
const result = render(<NamespaceTreeView root={levelsDeep} />);
const deepest = result.getByTestId("namespace-level-deep-child-b-1");
const tree: NamespaceTree = {
id: "levels-deep",
namespace: levelsDeep,
children: [
{
id: "level-deep-child-a",
namespace: levelDeepChildA
},
{
id: "level-deep-child-b",
namespace: levelDeepChildB,
children: [{
id: "level-deep-subchild-a",
namespace: levelDeepSubChildA
}]
}
]
}
const result = render(<NamespaceTreeView tree={tree} />);
const deepest = result.getByTestId("namespace-level-deep-child-b");
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 tree: NamespaceTree = {
id: "levels-deep",
namespace: levelsDeep,
children: [
{
id: "level-deep-child-a",
namespace: levelDeepChildA
},
{
id: "level-deep-child-b",
namespace: levelDeepChildB,
children: [{
id: "level-deep-subchild-a",
namespace: levelDeepSubChildA
}]
}
]
}
const result = render(<NamespaceTreeView tree={tree} />);
const levelB = result.getByTestId("namespace-level-deep-child-b");
const minusButton = levelB.querySelector("[data-testid='minus-square']");
if (minusButton) {
@ -186,8 +297,26 @@ describe("<NamespaceTreeView />", () => {
});
it("expands item by clicking plus button", () => {
const result = render(<NamespaceTreeView root={levelsDeep} />);
const levelB = result.getByTestId("namespace-level-deep-child-b-1");
const tree: NamespaceTree = {
id: "levels-deep",
namespace: levelsDeep,
children: [
{
id: "level-deep-child-a",
namespace: levelDeepChildA
},
{
id: "level-deep-child-b",
namespace: levelDeepChildB,
children: [{
id: "level-deep-subchild-a",
namespace: levelDeepSubChildA
}]
}
]
}
const result = render(<NamespaceTreeView tree={tree} />);
const levelB = result.getByTestId("namespace-level-deep-child-b");
const minusButton = levelB.querySelector("[data-testid='minus-square']");
if (minusButton) {

View File

@ -17,9 +17,10 @@ import getDetailsUrlInjectable from "../kube-detail-params/get-details-url.injec
import { SubnamespaceBadge } from "./subnamespace-badge";
import hierarchicalNamespacesInjectable from "./hierarchical-namespaces.injectable";
import { prevDefault } from "../../utils";
import type { NamespaceTree } from "./store";
interface NamespaceTreeViewProps {
root: Namespace;
tree: NamespaceTree;
}
interface Dependencies {
@ -27,48 +28,33 @@ interface Dependencies {
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, namespaces, getDetailsUrl }: Dependencies & NamespaceTreeViewProps) {
const [expandedItems, setExpandedItems] = React.useState<string[]>(namespaces.map(ns => `namespace-${ns.getId()}`));
function NonInjectableNamespaceTreeView({ tree, namespaces, getDetailsUrl }: Dependencies & NamespaceTreeViewProps) {
const [expandedItems, setExpandedItems] = React.useState<string[]>(namespaces.map(ns => ns.getId()));
const classes = { group: styles.group, label: styles.label };
const nodeId = `namespace-${root.getId()}`;
function renderChildren(parent: Namespace) {
const children = namespaces.filter(ns =>
ns.getLabels().find(label => label === `${parent.getName()}.tree.hnc.x-k8s.io/depth=1`),
);
return children.map(child => {
const childId = `namespace-${child.getId()}`;
return (
<TreeItem
key={childId}
nodeId={childId}
data-testid={childId}
classes={classes}
onIconClick={prevDefault(() => toggleNode(childId))}
label={(
<>
<Link key={child.getId()} to={getDetailsUrl(child.selfLink)}>
{child.getName()}
</Link>
{" "}
{child.isSubnamespace() && (
<SubnamespaceBadge id={`namespace-details-badge-for-${child.getId()}`} />
)}
</>
)}
function renderTree(nodes: NamespaceTree) {
return (
<TreeItem
key={nodes.id}
nodeId={nodes.id}
data-testid={`namespace-${nodes.id}`}
classes={classes}
onIconClick={prevDefault(() => toggleNode(nodes.id))}
label={(
<>
<Link key={nodes.namespace.getId()} to={getDetailsUrl(nodes.namespace.selfLink)}>
{nodes.namespace.getName()}
</Link>
{" "}
{nodes.namespace.isSubnamespace() && (
<SubnamespaceBadge id={`namespace-details-badge-for-${nodes.namespace.getId()}`} />
)}
</>
)}
>
{renderChildren(child)}
</TreeItem>
);
});
{Array.isArray(nodes.children) ? nodes.children.map((node) => renderTree(node)) : null}
</TreeItem>
)
}
function toggleNode(id: string) {
@ -79,29 +65,17 @@ function NonInjectableNamespaceTreeView({ root, namespaces, getDetailsUrl }: Dep
}
}
if (!isNamespaceControlledByHNC(root)) {
return null;
}
return (
<div data-testid="namespace-tree-view" className={styles.TreeView}>
<DrawerTitle>Tree View</DrawerTitle>
<TreeView
defaultExpanded={[nodeId]}
defaultExpanded={[tree.id]}
defaultCollapseIcon={<MinusSquareIcon />}
defaultExpandIcon={<PlusSquareIcon />}
defaultEndIcon={(<div style={{ opacity: 0.3 }}><MinusSquareIcon /></div>)}
expanded={expandedItems}
>
<TreeItem
nodeId={nodeId}
label={root.getName()}
data-testid={nodeId}
classes={classes}
onIconClick={prevDefault(() => toggleNode(nodeId))}
>
{renderChildren(root)}
</TreeItem>
{renderTree(tree)}
</TreeView>
</div>
);

View File

@ -12,6 +12,12 @@ import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store";
import type { NamespaceApi } from "../../../common/k8s-api/endpoints/namespace.api";
import { Namespace } from "../../../common/k8s-api/endpoints/namespace.api";
export type NamespaceTree = {
id: string,
namespace: Namespace,
children?: NamespaceTree[]
}
interface Dependencies extends KubeObjectStoreDependencies {
readonly storage: StorageLayer<string[] | undefined>;
readonly clusterConfiguredAccessibleNamespaces: IComputedValue<string[]>;
@ -202,6 +208,16 @@ export class NamespaceStore extends KubeObjectStore<Namespace, NamespaceApi> {
this.selectAll();
}
getNamespaceTree(root: Namespace): NamespaceTree {
const children = this.items.filter(namespace => namespace.isChildOf(root.getName()));
return {
id: root.getId(),
namespace: root,
children: children.map(this.getNamespaceTree)
}
}
@action
async remove(item: Namespace) {
await super.remove(item);