web: rewrite aggregate cards to separate components

This commit is contained in:
Jens Langhammer 2020-12-16 22:00:40 +01:00
parent 1179ba4ef2
commit 9e33b49d29
5 changed files with 128 additions and 67 deletions

View File

@ -1,9 +1,20 @@
import { DefaultClient, PBResponse, QueryArguments } from "./client"; import { DefaultClient, PBResponse, QueryArguments } from "./client";
export interface Policy { export class Policy {
pk: string; pk: string;
name: string; name: string;
[key: string]: unknown;
constructor() {
throw Error();
}
static get(pk: string): Promise<PolicyBinding> {
return DefaultClient.fetch<PolicyBinding>(["policies", "all", pk]);
}
static list(filter?: QueryArguments): Promise<PBResponse<PolicyBinding>> {
return DefaultClient.fetch<PBResponse<PolicyBinding>>(["policies", "all"], filter);
}
} }
export class PolicyBinding { export class PolicyBinding {

19
web/src/api/provider.ts Normal file
View File

@ -0,0 +1,19 @@
import { DefaultClient, PBResponse, QueryArguments } from "./client";
export class Provider {
pk: number;
name: string;
authorization_flow: string;
constructor() {
throw Error();
}
static get(slug: string): Promise<Provider> {
return DefaultClient.fetch<Provider>(["providers", "all", slug]);
}
static list(filter?: QueryArguments): Promise<PBResponse<Provider>> {
return DefaultClient.fetch<PBResponse<Provider>>(["providers", "all"], filter);
}
}

View File

@ -1,7 +1,7 @@
import { gettext } from "django"; import { gettext } from "django";
import { customElement, html, property, TemplateResult } from "lit-element"; import { customElement, html, property, TemplateResult } from "lit-element";
import { PBResponse } from "../../api/client"; import { PBResponse } from "../../api/client";
import { PolicyBinding } from "../../api/policy_binding"; import { PolicyBinding } from "../../api/policy";
import { Table } from "../../elements/table/Table"; import { Table } from "../../elements/table/Table";
import "../../elements/Tabs"; import "../../elements/Tabs";

View File

@ -4,50 +4,11 @@ import { AdminOverview } from "../../api/admin_overview";
import { DefaultClient } from "../../api/client"; import { DefaultClient } from "../../api/client";
import { User } from "../../api/user"; import { User } from "../../api/user";
import { COMMON_STYLES } from "../../common/styles"; import { COMMON_STYLES } from "../../common/styles";
import { AggregatePromiseCard } from "../../elements/cards/AggregatePromiseCard";
import { SpinnerSize } from "../../elements/Spinner"; import { SpinnerSize } from "../../elements/Spinner";
import "../../elements/AdminLoginsChart"; import "../../elements/AdminLoginsChart";
import "./TopApplicationsTable"; import "./TopApplicationsTable";
import "./OverviewCards";
@customElement("ak-admin-status-card")
export class AdminStatusCard extends AggregatePromiseCard {
@property({type: Number})
value?: number;
@property()
warningText?: string;
@property({type: Number})
lessThanThreshold?: number;
renderNone(): TemplateResult {
return html`<ak-spinner size=${SpinnerSize.Large}></ak-spinner>`;
}
renderGood(): TemplateResult {
return html`<p class="ak-aggregate-card">
<i class="fa fa-check-circle"></i> ${this.value}
</p>`;
}
renderBad(): TemplateResult {
return html`<p class="ak-aggregate-card">
<i class="fa fa-exclamation-triangle"></i> ${this.value}
</p>
<p class="subtext">${this.warningText ? gettext(this.warningText) : ""}</p>`;
}
renderInner(): TemplateResult {
if (!this.value) {
return this.renderNone();
}
return html``;
}
}
@customElement("ak-admin-overview") @customElement("ak-admin-overview")
export class AdminOverviewPage extends LitElement { export class AdminOverviewPage extends LitElement {
@ -92,30 +53,10 @@ export class AdminOverviewPage extends LitElement {
</p>` </p>`
: html`<ak-spinner size=${SpinnerSize.Large}></ak-spinner>`} : html`<ak-spinner size=${SpinnerSize.Large}></ak-spinner>`}
</ak-aggregate-card> </ak-aggregate-card>
<ak-aggregate-card class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-plugged" header="Providers" headerLink="#/administration/providers/"> <ak-admin-status-card-provider class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-plugged" header="Providers" headerLink="#/administration/providers/">
${this.data ? </ak-admin-status-card-provider>
this.data?.providers_without_application > 1 ? <ak-admin-status-card-policy class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-plugged" header="Policies" headerLink="#/administration/policies/">
html`<p class="ak-aggregate-card"> </ak-admin-status-card-policy>
<i class="fa fa-exclamation-triangle"></i> 0
</p>
<p class="subtext">${gettext("At least one Provider has no application assigned.")}</p>` :
html`<p class="ak-aggregate-card">
<i class="fa fa-check-circle"></i> 0
</p>`
: html`<ak-spinner size=${SpinnerSize.Large}></ak-spinner>`}
</ak-aggregate-card>
<ak-aggregate-card class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-plugged" header="Policies" headerLink="#/administration/policies/">
${this.data ?
this.data?.policies_without_binding > 1 ?
html`<p class="ak-aggregate-card">
<i class="fa fa-exclamation-triangle"></i> 0
</p>
<p class="subtext">${gettext("Policies without binding exist.")}</p>` :
html`<p class="ak-aggregate-card">
<i class="fa fa-check-circle"></i> 0
</p>`
: html`<ak-spinner size=${SpinnerSize.Large}></ak-spinner>`}
</ak-aggregate-card>
<ak-aggregate-card-promise <ak-aggregate-card-promise
icon="pf-icon pf-icon-user" icon="pf-icon pf-icon-user"
header="Users" header="Users"

View File

@ -0,0 +1,90 @@
import { gettext } from "django";
import { customElement, property } from "lit-element";
import { html, TemplateResult } from "lit-html";
import { until } from "lit-html/directives/until";
import { Policy } from "../../api/policy";
import { Provider } from "../../api/provider";
import { AggregateCard } from "../../elements/cards/AggregateCard";
import { SpinnerSize } from "../../elements/Spinner";
interface AdminStatus {
icon: string;
message?: string;
}
abstract class AdminStatusCard extends AggregateCard {
abstract getPrimaryCounter(): Promise<number>;
abstract getStatus(counter: number): Promise<AdminStatus>;
@property({type: Number})
counter = 0;
renderInner(): TemplateResult {
return html`<p class="center-value">
${until(this.getPrimaryCounter().then((c) => {
this.counter = c;
return this.getStatus(c);
}).then((status) => {
return html`<p class="ak-aggregate-card">
<i class="${status.icon}"></i> ${this.counter}
</p>
${status.message ? html`<p class="subtext">${status.message}</p>` : html``}`;
}), html`<ak-spinner size="${SpinnerSize.Large}"></ak-spinner>`)}
</p>`;
}
}
@customElement("ak-admin-status-card-provider")
export class ProviderStatusCard extends AdminStatusCard {
getPrimaryCounter(): Promise<number> {
return Provider.list({
"application__isnull": true
}).then((response) => {
return response.pagination.count;
});
}
getStatus(counter: number): Promise<AdminStatus> {
if (counter > 0) {
return Promise.resolve<AdminStatus>({
icon: "fa fa-exclamation-triangle",
message: gettext("Warning: At least one Provider has no application assigned."),
});
} else {
return Promise.resolve<AdminStatus>({
icon: "fa fa-check-circle"
});
}
}
}
@customElement("ak-admin-status-card-policy")
export class PolicyStatusCard extends AdminStatusCard {
getPrimaryCounter(): Promise<number> {
return Policy.list({
"bindings__isnull": true,
"promptstage__isnull": true,
}).then((response) => {
return response.pagination.count;
});
}
getStatus(counter: number): Promise<AdminStatus> {
if (counter > 0) {
return Promise.resolve<AdminStatus>({
icon: "fa fa-exclamation-triangle",
message: gettext("Policies without binding exist."),
});
} else {
return Promise.resolve<AdminStatus>({
icon: "fa fa-check-circle"
});
}
}
}