import { t } from "@lingui/macro"; import { CSSResult, LitElement, TemplateResult, html } from "lit"; import { customElement, property, state } from "lit/decorators.js"; import AKGlobal from "../authentik.css"; import PFTreeView from "@patternfly/patternfly/components/TreeView/tree-view.css"; import PFBase from "@patternfly/patternfly/patternfly-base.css"; import { EVENT_REFRESH } from "../constants"; import { setURLParams } from "./router/RouteMatch"; export interface TreeViewItem { id: string; label: string; childItems: TreeViewItem[]; parent?: TreeViewItem; level: number; } @customElement("ak-treeview-node") export class TreeViewNode extends LitElement { @property({ attribute: false }) item?: TreeViewItem; @property({ type: Boolean }) open = false; @property({ attribute: false }) host?: TreeView; @property() path = ""; @property() separator = ""; get openable(): boolean { return (this.item?.childItems || []).length > 0; } get fullPath(): string { const pathItems = []; let item = this.item; while (item) { pathItems.push(item.id); item = item.parent; } return pathItems.reverse().join(this.separator); } protected createRenderRoot(): Element { return this; } firstUpdated(): void { const pathSegments = this.path.split(this.separator); const level = this.item?.level || 0; // Ignore the last item as that shouldn't be expanded pathSegments.pop(); if (pathSegments[level] == this.item?.id) { this.open = true; } if (this.path === this.fullPath && this.host !== undefined) { this.host.activeNode = this; } } render(): TemplateResult { const shouldRenderChildren = (this.item?.childItems || []).length > 0 && this.open; return html`
  • ` : html``} ${this.item?.label}
  • `; } } @customElement("ak-treeview") export class TreeView extends LitElement { static get styles(): CSSResult[] { return [PFBase, PFTreeView, AKGlobal]; } @property({ type: Array }) items: string[] = []; @property() path = ""; @state() activeNode?: TreeViewNode; separator = "/"; createNode(path: string[], tree: TreeViewItem[], level: number): TreeViewItem { const id = path.shift(); const idx = tree.findIndex((e: TreeViewItem) => { return e.id == id; }); if (idx < 0) { const item: TreeViewItem = { id: id || "", label: id || "", childItems: [], level: level, }; tree.push(item); if (path.length !== 0) { const child = this.createNode(path, tree[tree.length - 1].childItems, level + 1); child.parent = item; } return item; } else { return this.createNode(path, tree[idx].childItems, level + 1); } } parse(data: string[]): TreeViewItem[] { const tree: TreeViewItem[] = []; for (let i = 0; i < data.length; i++) { const path: string = data[i]; const split: string[] = path.split(this.separator); this.createNode(split, tree, 0); } return tree; } render(): TemplateResult { const result = this.parse(this.items); return html`
    `; } }