web: start implementing admin overview page
This commit is contained in:
parent
760dca0f76
commit
93bf977709
|
@ -3,7 +3,7 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "rollup -c ./rollup.config.js",
|
"build": "rollup -c ./rollup.config.js",
|
||||||
"watch": "rollup -c -w",
|
"watch": "rollup -c -w",
|
||||||
"format": "prettier --write ."
|
"lint": "eslint . --ext .js,.jsx,.ts,.tsx --fix"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-free": "^5.15.1",
|
"@fortawesome/fontawesome-free": "^5.15.1",
|
||||||
|
|
|
@ -43,6 +43,6 @@ export default [
|
||||||
watch: {
|
watch: {
|
||||||
clearScreen: false,
|
clearScreen: false,
|
||||||
},
|
},
|
||||||
external: ['django']
|
external: ["django"]
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { DefaultClient } from "./client";
|
||||||
|
|
||||||
|
export class AdminOverview {
|
||||||
|
version?: string;
|
||||||
|
version_latest?: string;
|
||||||
|
worker_count?: number;
|
||||||
|
providers_without_application?: number;
|
||||||
|
policies_without_binding?: number;
|
||||||
|
cached_policies?: number;
|
||||||
|
cached_flows?: number;
|
||||||
|
|
||||||
|
static get(): Promise<AdminOverview> {
|
||||||
|
return DefaultClient.fetch<AdminOverview>(["admin", "overview"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
declare module 'django' {
|
declare module "django" {
|
||||||
export = django;
|
export = django;
|
||||||
}
|
}
|
||||||
declare namespace django {
|
declare namespace django {
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { gettext } from "django";
|
||||||
|
import { customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
||||||
|
// @ts-ignore
|
||||||
|
import SpinnerStyle from "@patternfly/patternfly/components/Spinner/spinner.css";
|
||||||
|
|
||||||
|
export enum SpinnerSize {
|
||||||
|
Small = "pf-m-sm",
|
||||||
|
Medium = "pf-m-md",
|
||||||
|
Large = "pf-m-lg",
|
||||||
|
XLarge = "pf-m-xl",
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement("pb-spinner")
|
||||||
|
export class Spinner extends LitElement {
|
||||||
|
@property()
|
||||||
|
size: SpinnerSize = SpinnerSize.Medium;
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return [SpinnerStyle];
|
||||||
|
}
|
||||||
|
|
||||||
|
render(): TemplateResult {
|
||||||
|
return html`<span
|
||||||
|
class="pf-c-spinner ${this.size.toString()}"
|
||||||
|
role="progressbar"
|
||||||
|
aria-valuetext="${gettext("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>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -86,8 +86,8 @@ export abstract class Table<T> extends LitElement {
|
||||||
<thead>
|
<thead>
|
||||||
<tr role="row">
|
<tr role="row">
|
||||||
${this.columns().map(
|
${this.columns().map(
|
||||||
(col) => html`<th role="columnheader" scope="col">${gettext(col)}</th>`
|
(col) => html`<th role="columnheader" scope="col">${gettext(col)}</th>`
|
||||||
)}
|
)}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody role="rowgroup">
|
<tbody role="rowgroup">
|
||||||
|
|
|
@ -13,9 +13,11 @@ import "./elements/sidebar/Sidebar";
|
||||||
import "./elements/sidebar/SidebarBrand";
|
import "./elements/sidebar/SidebarBrand";
|
||||||
import "./elements/sidebar/SidebarUser";
|
import "./elements/sidebar/SidebarUser";
|
||||||
import "./elements/Tabs";
|
import "./elements/Tabs";
|
||||||
|
import "./elements/Spinner";
|
||||||
import "./elements/table/TablePagination";
|
import "./elements/table/TablePagination";
|
||||||
import "./pages/applications/ApplicationViewPage";
|
import "./pages/applications/ApplicationViewPage";
|
||||||
import "./pages/applications/ApplicationListPage";
|
import "./pages/applications/ApplicationListPage";
|
||||||
|
import "./pages/AdminOverviewPage";
|
||||||
import "./pages/LibraryPage";
|
import "./pages/LibraryPage";
|
||||||
import "./pages/FlowShellCard";
|
import "./pages/FlowShellCard";
|
||||||
import "./pages/RouterOutlet";
|
import "./pages/RouterOutlet";
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
import { gettext } from "django";
|
||||||
|
import { customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
||||||
|
import { AdminOverview } from "../api/admin_overview";
|
||||||
|
import { DefaultClient } from "../api/client";
|
||||||
|
import { COMMON_STYLES } from "../common/styles";
|
||||||
|
|
||||||
|
@customElement("pb-aggregate-card")
|
||||||
|
export class AggregateCard extends LitElement {
|
||||||
|
@property()
|
||||||
|
icon?: string;
|
||||||
|
|
||||||
|
@property()
|
||||||
|
header?: string;
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return COMMON_STYLES;
|
||||||
|
}
|
||||||
|
|
||||||
|
render(): TemplateResult {
|
||||||
|
return html`<div class="pf-c-card pf-c-card-aggregate pf-l-gallery__item pf-m-4-col" >
|
||||||
|
<div class="pf-c-card__header">
|
||||||
|
<div class="pf-c-card__header-main">
|
||||||
|
<i class="${this.icon}"></i> ${this.header ? gettext(this.header) : ""}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pf-c-card__body">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement("pb-admin-overview")
|
||||||
|
export class AdminOverviewPage extends LitElement {
|
||||||
|
@property()
|
||||||
|
data?: AdminOverview;
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return COMMON_STYLES;
|
||||||
|
}
|
||||||
|
|
||||||
|
firstUpdated(): void {
|
||||||
|
AdminOverview.get().then(value => this.data = value);
|
||||||
|
}
|
||||||
|
|
||||||
|
render(): TemplateResult {
|
||||||
|
return html`<section class="pf-c-page__main-section pf-m-light">
|
||||||
|
<div class="pf-c-content">
|
||||||
|
<h1>${gettext("System Overview")}</h1>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="pf-c-page__main-section">
|
||||||
|
<div class="pf-l-gallery pf-m-gutter">
|
||||||
|
<pb-aggregate-card icon="pf-icon pf-icon-server" header="Logins over the last 24 hours" style="grid-column-end: span 3;grid-row-end: span 2;">
|
||||||
|
<pb-admin-logins-chart url="${DefaultClient.makeUrl(["admin", "metrics"])}"></pb-admin-logins-chart>
|
||||||
|
</pb-aggregate-card>
|
||||||
|
<pb-aggregate-card icon="pf-icon pf-icon-server" header="Workers">
|
||||||
|
${this.data ?
|
||||||
|
this.data?.worker_count! < 1 ?
|
||||||
|
html`<p class="pb-aggregate-card">
|
||||||
|
<i class="fa fa-exclamation-triangle"></i> ${this.data.worker_count}
|
||||||
|
</p>
|
||||||
|
<p>${gettext("No workers connected.")}</p>` :
|
||||||
|
html`<p class="pb-aggregate-card">
|
||||||
|
<i class="fa fa-check-circle"></i> ${this.data.worker_count}
|
||||||
|
</p>`
|
||||||
|
: html`<pb-spinner></pb-spinner>`}
|
||||||
|
</pb-aggregate-card>
|
||||||
|
</div>
|
||||||
|
</section>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -52,6 +52,7 @@ export const ROUTES: Route[] = [
|
||||||
new Route(new RegExp("^/$")).redirect("/library/"),
|
new Route(new RegExp("^/$")).redirect("/library/"),
|
||||||
new Route(new RegExp("^#.*")).redirect("/library/"),
|
new Route(new RegExp("^#.*")).redirect("/library/"),
|
||||||
new Route(new RegExp("^/library/$"), html`<pb-library></pb-library>`),
|
new Route(new RegExp("^/library/$"), html`<pb-library></pb-library>`),
|
||||||
|
new Route(new RegExp("^/administration/overview/$"), html`<pb-admin-overview></pb-admin-overview>`),
|
||||||
new Route(new RegExp("^/applications/$"), html`<pb-application-list></pb-application-list>`),
|
new Route(new RegExp("^/applications/$"), html`<pb-application-list></pb-application-list>`),
|
||||||
new Route(new RegExp(`^/applications/(?<slug>${SLUG_REGEX})/$`)).then((args) => {
|
new Route(new RegExp(`^/applications/(?<slug>${SLUG_REGEX})/$`)).then((args) => {
|
||||||
return html`<pb-application-view .args=${args}></pb-application-view>`;
|
return html`<pb-application-view .args=${args}></pb-application-view>`;
|
||||||
|
|
|
@ -98,23 +98,15 @@ export class SiteShell extends LitElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html` ${this.loading
|
return html` ${this.loading ?
|
||||||
? html`<div class="pf-c-backdrop">
|
html`<div class="pf-c-backdrop">
|
||||||
<div class="pf-l-bullseye">
|
<div class="pf-l-bullseye">
|
||||||
<div class="pf-l-bullseye__item">
|
<div class="pf-l-bullseye__item">
|
||||||
<span
|
<pb-spinner></pb-spinner>
|
||||||
class="pf-c-spinner pf-m-xl"
|
</div>
|
||||||
role="progressbar"
|
</div>
|
||||||
aria-valuetext="Loading..."
|
</div>`
|
||||||
>
|
|
||||||
<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>`
|
|
||||||
: ""}
|
: ""}
|
||||||
<slot name="body"> </slot>`;
|
<slot name="body"></slot>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue