static: add RouterOutlet, render sidebar clientside

This commit is contained in:
Jens Langhammer
2020-11-22 00:06:25 +01:00
parent a8669ffe40
commit 7dac6841fb
9 changed files with 274 additions and 226 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,16 +1,125 @@
import { customElement, html, LitElement, property } from "lit-element";
import {
customElement,
html,
LitElement,
property,
TemplateResult,
} from "lit-element";
// @ts-ignore
import PageStyle from "@patternfly/patternfly/components/Page/page.css";
// @ts-ignore
import NavStyle from "@patternfly/patternfly/components/Nav/nav.css";
// @ts-ignore
import GlobalsStyle from "@patternfly/patternfly/base/patternfly-globals.css";
interface RegexAnchor {
anchor: HTMLAnchorElement;
match: RegExp;
export interface SidebarItem {
name: string;
path?: string;
children?: SidebarItem[];
}
export const SIDEBAR_ITEMS: SidebarItem[] = [
{
name: "Overview",
path: "overview",
},
{
name: "Applications",
path: "applications",
},
{
name: "Sources",
path: "sources",
},
{
name: "Providers",
path: "providers",
},
{
name: "Outposts",
children: [
{
name: "Outposts",
path: "outposts",
},
{
name: "Service Connections",
path: "outposts/service_connections",
},
],
},
{
name: "Property Mappings",
path: "property_mappings",
},
{
name: "Flows",
children: [
{
name: "Flows",
path: "flows",
},
{
name: "Bindings",
path: "stages/bindings",
},
{
name: "Stages",
path: "stages",
},
{
name: "Prompts",
path: "stages/prompts",
},
{
name: "Invitations",
path: "stages/invitations",
},
],
},
{
name: "Policies",
children: [
{
name: "Policies",
path: "policies",
},
{
name: "Bindings",
path: "policies/bindings",
},
],
},
{
name: "Certificates",
path: "crypto/certificates",
},
{
name: "Tokens",
path: "tokens",
},
{
name: "User",
path: "users",
},
{
name: "Groups",
path: "groups",
},
{
name: "System Tasks",
path: "tasks",
},
];
@customElement("pb-admin-sidebar")
export class AdminSideBar extends LitElement {
@property()
activePath: string;
paths: RegexAnchor[] = [];
static get styles() {
return [GlobalsStyle, PageStyle, NavStyle];
}
constructor() {
super();
@ -18,32 +127,47 @@ export class AdminSideBar extends LitElement {
window.addEventListener("hashchange", (e) => {
this.activePath = window.location.hash.slice(1, Infinity);
});
this.querySelectorAll<HTMLAnchorElement>(".pf-c-nav__link").forEach(
(a) => {
let rawValue = a.attributes.getNamedItem("pb-url-prefix")
?.value;
if (!rawValue) {
const parsedURL = new URL(a.href);
if (parsedURL.hash === "") {
console.log(`Ignoring ${a}`);
return;
}
rawValue = `^${parsedURL.hash.slice(1, Infinity)}`;
}
const regexp = RegExp(rawValue);
this.paths.push({ anchor: a, match: regexp });
}
);
}
renderItem(item: SidebarItem): TemplateResult {
return html` <li
class="pf-c-nav__item ${item.children
? "pf-m-expandable pf-m-expanded"
: ""}"
>
${item.path
? html`<a
href="#${item.path}"
class="pf-c-nav__link ${item.path === this.activePath
? "pf-m-current"
: ""}"
>
${item.name}
</a>`
: html`<a class="pf-c-nav__link" aria-expanded="true"
>${item.name}
<span class="pf-c-nav__toggle">
<i
class="fas fa-angle-right"
aria-hidden="true"
></i>
</span>
</a>
<section class="pf-c-nav__subnav">
<ul class="pf-c-nav__simple-list">
${item.children?.map((i) => this.renderItem(i))}
</ul>
</section>`}
</li>`;
}
render() {
this.paths.forEach((path) => {
if (path.match.exec(this.activePath)) {
path.anchor.classList.add("pf-m-current");
} else {
path.anchor.classList.remove("pf-m-current");
}
});
return html`<slot></slot>`;
return html`<div class="pf-c-page__sidebar-body">
<nav class="pf-c-nav" aria-label="Global">
<ul class="pf-c-nav__list">
${SIDEBAR_ITEMS.map((i) => this.renderItem(i))}
</ul>
</nav>
</div>`;
}
}

View File

@ -5,7 +5,7 @@ export class DropdownButton extends LitElement {
constructor() {
super();
const menu = <HTMLElement>this.querySelector(".pf-c-dropdown__menu")!;
this.querySelectorAll("button").forEach((btn) => {
this.querySelectorAll("button.pf-c-dropdown__toggle").forEach((btn) => {
btn.addEventListener("click", (e) => {
menu.hidden = !menu.hidden;
});

View File

@ -5,6 +5,11 @@ import ModalBoxStyle from "@patternfly/patternfly/components/ModalBox/modal-box.
import BullseyeStyle from "@patternfly/patternfly/layouts/Bullseye/bullseye.css";
// @ts-ignore
import BackdropStyle from "@patternfly/patternfly/components/Backdrop/backdrop.css";
// @ts-ignore
import ButtonStyle from "@patternfly/patternfly/components/Button/button.css";
// @ts-ignore
import fa from "@patternfly/patternfly/assets/icons/fontawesome.css";
import { updateMessages } from "../elements/Messages";
import { convertToSlug } from "../utils";
@ -17,7 +22,7 @@ export class ModalButton extends LitElement {
open: boolean = false;
static get styles() {
return [ModalBoxStyle, BullseyeStyle, BackdropStyle];
return [ModalBoxStyle, BullseyeStyle, BackdropStyle, ButtonStyle, fa];
}
constructor() {

View File

@ -8,6 +8,7 @@ import "./elements/FetchFillSlot";
import "./elements/Messages";
import "./elements/ModalButton";
import "./elements/Tabs";
import "./pages/AdminSiteShell";
import "./pages/SiteShell";
import "./pages/FlowShellCard";
import "./pages/RouterOutlet";
import "./elements/AdminLoginsChart";

View File

@ -0,0 +1,71 @@
import {
customElement,
html,
LitElement,
property,
TemplateResult,
} from "lit-element";
// @ts-ignore
import PF from "@patternfly/patternfly/patternfly.css";
// @ts-ignore
import PFAddons from "@patternfly/patternfly/patternfly-addons.css";
export interface Route {
url: RegExp;
element: TemplateResult;
}
export const ROUTES: Route[] = [
{
url: new RegExp("^overview$"),
element: html`<pb-site-shell url="/overview/"
><div slot="body"></div
></pb-site-shell>`,
},
// {
// url: new RegExp("^applications$"),
// element: html`<h1>test2</h1>`,
// },
];
@customElement("pb-router-outlet")
export class RouterOutlet extends LitElement {
@property()
activeRoute?: Route;
static get styles() {
return [PF, PFAddons];
}
constructor() {
super();
this.navigate();
window.addEventListener("hashchange", (e) => this.navigate());
}
navigate() {
const activeUrl = window.location.hash.slice(1, Infinity);
ROUTES.forEach((route) => {
let selectedRoute: Route | null = null;
if (route.url.exec(activeUrl)) {
selectedRoute = route;
}
if (!selectedRoute) {
console.log(
`passbook/router: route "${activeUrl}" not defined, defaulting to shell`
);
selectedRoute = {
url: RegExp(""),
element: html`<pb-site-shell url=${activeUrl}
><div slot="body"></div
></pb-site-shell>`,
};
}
this.activeRoute = selectedRoute;
});
}
render() {
return this.activeRoute?.element;
}
}

View File

@ -1,20 +1,15 @@
import {
css,
customElement,
html,
LitElement,
property,
TemplateResult,
} from "lit-element";
import { css, customElement, html, LitElement, property } from "lit-element";
// @ts-ignore
import BullseyeStyle from "@patternfly/patternfly/layouts/Bullseye/bullseye.css";
// @ts-ignore
import SpinnerStyle from "@patternfly/patternfly/components/Spinner/spinner.css";
// @ts-ignore
import BackdropStyle from "@patternfly/patternfly/components/Backdrop/backdrop.css";
@customElement("pb-admin-shell")
export class AdminSiteShell extends LitElement {
@customElement("pb-site-shell")
export class SiteShell extends LitElement {
@property()
set defaultUrl(value: string) {
set url(value: string) {
if (window.location.hash === "" && value !== undefined) {
window.location.hash = `#${value}`;
}
@ -38,6 +33,7 @@ export class AdminSiteShell extends LitElement {
z-index: 2000;
}
`,
BackdropStyle,
BullseyeStyle,
SpinnerStyle,
];
@ -101,17 +97,19 @@ export class AdminSiteShell extends LitElement {
render() {
return html` ${this.loading
? html` <div class="pf-l-bullseye">
<div class="pf-l-bullseye__item">
<span
class="pf-c-spinner pf-m-xl"
role="progressbar"
aria-valuetext="Loading..."
>
<span class="pf-c-spinner__clipper"></span>
<span class="pf-c-spinner__lead-ball"></span>
<span class="pf-c-spinner__tail-ball"></span>
</span>
? html` <div class="pf-c-backdrop">
<div class="pf-l-bullseye">
<div class="pf-l-bullseye__item">
<span
class="pf-c-spinner pf-m-xl"
role="progressbar"
aria-valuetext="Loading..."
>
<span class="pf-c-spinner__clipper"></span>
<span class="pf-c-spinner__lead-ball"></span>
<span class="pf-c-spinner__tail-ball"></span>
</span>
</div>
</div>
</div>`
: ""}