web: migrate admin overview cards to separate files
This commit is contained in:
parent
48438e28fd
commit
2d9efe035e
|
@ -1,20 +0,0 @@
|
||||||
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;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
throw Error();
|
|
||||||
}
|
|
||||||
|
|
||||||
static get(): Promise<AdminOverview> {
|
|
||||||
return DefaultClient.fetch<AdminOverview>(["admin", "overview"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { DefaultClient } from "./client";
|
||||||
|
|
||||||
|
export class Version {
|
||||||
|
|
||||||
|
version_current: string;
|
||||||
|
version_latest: string;
|
||||||
|
outdated: boolean;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
throw Error();
|
||||||
|
}
|
||||||
|
|
||||||
|
static get(): Promise<Version> {
|
||||||
|
return DefaultClient.fetch<Version>(["admin", "version"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
toString(): string {
|
||||||
|
return this.version_current;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -75,10 +75,10 @@ export class SidebarItem {
|
||||||
}
|
}
|
||||||
return html` <li class="pf-c-nav__item ${this.hasChildren() ? "pf-m-expandable pf-m-expanded" : ""}">
|
return html` <li class="pf-c-nav__item ${this.hasChildren() ? "pf-m-expandable pf-m-expanded" : ""}">
|
||||||
${this.path ?
|
${this.path ?
|
||||||
html`<a href="#${this.path}" class="pf-c-nav__link ${this.isActive(activePath) ? "pf-m-current" : ""}">
|
html`<a href="#${this.path}" class="pf-c-nav__link ${this.isActive(activePath) ? "pf-m-current" : ""}">
|
||||||
${this.name}
|
${this.name}
|
||||||
</a>` :
|
</a>` :
|
||||||
html`<a class="pf-c-nav__link" aria-expanded="true">
|
html`<a class="pf-c-nav__link" aria-expanded="true">
|
||||||
${this.name}
|
${this.name}
|
||||||
<span class="pf-c-nav__toggle">
|
<span class="pf-c-nav__toggle">
|
||||||
<i class="fas fa-angle-right" aria-hidden="true"></i>
|
<i class="fas fa-angle-right" aria-hidden="true"></i>
|
||||||
|
|
|
@ -1,20 +1,22 @@
|
||||||
import { gettext } from "django";
|
import { gettext } from "django";
|
||||||
import { CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
import { CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
||||||
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 { SpinnerSize } from "../../elements/Spinner";
|
|
||||||
|
|
||||||
import "../../elements/AdminLoginsChart";
|
import "../../elements/AdminLoginsChart";
|
||||||
|
import "../../elements/cards/AggregatePromiseCard";
|
||||||
import "./TopApplicationsTable";
|
import "./TopApplicationsTable";
|
||||||
import "./OverviewCards";
|
import "./cards/AdminStatusCard";
|
||||||
|
import "./cards/FlowCacheStatusCard";
|
||||||
|
import "./cards/PolicyCacheStatusCard";
|
||||||
|
import "./cards/PolicyUnboundStatusCard";
|
||||||
|
import "./cards/ProviderStatusCard";
|
||||||
|
import "./cards/VersionStatusCard";
|
||||||
|
import "./cards/WorkerStatusCard";
|
||||||
|
|
||||||
@customElement("ak-admin-overview")
|
@customElement("ak-admin-overview")
|
||||||
export class AdminOverviewPage extends LitElement {
|
export class AdminOverviewPage extends LitElement {
|
||||||
@property({attribute: false})
|
|
||||||
data?: AdminOverview;
|
|
||||||
|
|
||||||
@property({attribute: false})
|
@property({attribute: false})
|
||||||
users?: Promise<number>;
|
users?: Promise<number>;
|
||||||
|
|
||||||
|
@ -23,7 +25,6 @@ export class AdminOverviewPage extends LitElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated(): void {
|
firstUpdated(): void {
|
||||||
AdminOverview.get().then(value => this.data = value);
|
|
||||||
this.users = User.count();
|
this.users = User.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,19 +52,10 @@ export class AdminOverviewPage extends LitElement {
|
||||||
headerLink="#/administration/users/"
|
headerLink="#/administration/users/"
|
||||||
.promise=${this.users}>
|
.promise=${this.users}>
|
||||||
</ak-aggregate-card-promise>
|
</ak-aggregate-card-promise>
|
||||||
<!-- Version card -->
|
<ak-admin-status-version class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-bundle" header="Version">
|
||||||
<ak-aggregate-card class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-server" header="Workers">
|
</ak-admin-status-version>
|
||||||
${this.data ?
|
<ak-admin-status-card-workers class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-server" header="Workers">
|
||||||
this.data?.worker_count < 1 ?
|
</ak-admin-status-card-workers>
|
||||||
html`<p class="ak-aggregate-card">
|
|
||||||
<i class="fa fa-exclamation-triangle"></i> ${this.data?.worker_count}
|
|
||||||
</p>
|
|
||||||
<p class="subtext">${gettext("No workers connected.")}</p>` :
|
|
||||||
html`<p class="ak-aggregate-card">
|
|
||||||
<i class="fa fa-check-circle"></i> ${this.data?.worker_count}
|
|
||||||
</p>`
|
|
||||||
: html`<ak-spinner size=${SpinnerSize.Large}></ak-spinner>`}
|
|
||||||
</ak-aggregate-card>
|
|
||||||
<ak-admin-status-card-policy-cache class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-server" header="Cached Policies">
|
<ak-admin-status-card-policy-cache class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-server" header="Cached Policies">
|
||||||
</ak-admin-status-card-policy-cache>
|
</ak-admin-status-card-policy-cache>
|
||||||
<ak-admin-status-card-flow-cache class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-server" header="Cached Flows">
|
<ak-admin-status-card-flow-cache class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-server" header="Cached Flows">
|
||||||
|
|
|
@ -1,153 +0,0 @@
|
||||||
import { gettext } from "django";
|
|
||||||
import { customElement, property } from "lit-element";
|
|
||||||
import { html, TemplateResult } from "lit-html";
|
|
||||||
import { until } from "lit-html/directives/until";
|
|
||||||
import { Flow } from "../../api/flow";
|
|
||||||
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-unbound")
|
|
||||||
export class PolicyUnboundStatusCard 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"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@customElement("ak-admin-status-card-policy-cache")
|
|
||||||
export class PolicyCacheStatusCard extends AdminStatusCard {
|
|
||||||
|
|
||||||
getPrimaryCounter(): Promise<number> {
|
|
||||||
return Policy.cached();
|
|
||||||
}
|
|
||||||
|
|
||||||
getStatus(counter: number): Promise<AdminStatus> {
|
|
||||||
if (counter < 1) {
|
|
||||||
return Promise.resolve<AdminStatus>({
|
|
||||||
icon: "fa fa-exclamation-triangle",
|
|
||||||
message: gettext("No policies cached. Users may experience slow response times."),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return Promise.resolve<AdminStatus>({
|
|
||||||
icon: "fa fa-check-circle"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
renderHeaderLink(): TemplateResult {
|
|
||||||
return html`<ak-modal-button href="/administration/overview/cache/policy/">
|
|
||||||
<a slot="trigger">
|
|
||||||
<i class="fa fa-trash"> </i>
|
|
||||||
</a>
|
|
||||||
<div slot="modal"></div>
|
|
||||||
</ak-modal-button>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@customElement("ak-admin-status-card-flow-cache")
|
|
||||||
export class FlowCacheStatusCard extends AdminStatusCard {
|
|
||||||
|
|
||||||
getPrimaryCounter(): Promise<number> {
|
|
||||||
return Flow.cached();
|
|
||||||
}
|
|
||||||
|
|
||||||
getStatus(counter: number): Promise<AdminStatus> {
|
|
||||||
if (counter < 1) {
|
|
||||||
return Promise.resolve<AdminStatus>({
|
|
||||||
icon: "fa fa-exclamation-triangle",
|
|
||||||
message: gettext("No flows cached."),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return Promise.resolve<AdminStatus>({
|
|
||||||
icon: "fa fa-check-circle"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
renderHeaderLink(): TemplateResult {
|
|
||||||
return html`<ak-modal-button href="/administration/overview/cache/flow/">
|
|
||||||
<a slot="trigger">
|
|
||||||
<i class="fa fa-trash"> </i>
|
|
||||||
</a>
|
|
||||||
<div slot="modal"></div>
|
|
||||||
</ak-modal-button>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { html, TemplateResult } from "lit-html";
|
||||||
|
import { until } from "lit-html/directives/until";
|
||||||
|
import { AggregateCard } from "../../../elements/cards/AggregateCard";
|
||||||
|
import { SpinnerSize } from "../../../elements/Spinner";
|
||||||
|
|
||||||
|
export interface AdminStatus {
|
||||||
|
icon: string;
|
||||||
|
message?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class AdminStatusCard<T> extends AggregateCard {
|
||||||
|
|
||||||
|
abstract getPrimaryValue(): Promise<T>;
|
||||||
|
|
||||||
|
abstract getStatus(value: T): Promise<AdminStatus>;
|
||||||
|
|
||||||
|
value?: T;
|
||||||
|
|
||||||
|
renderInner(): TemplateResult {
|
||||||
|
return html`<p class="center-value">
|
||||||
|
${until(this.getPrimaryValue().then((v) => {
|
||||||
|
this.value = v;
|
||||||
|
return this.getStatus(v);
|
||||||
|
}).then((status) => {
|
||||||
|
return html`<p class="ak-aggregate-card">
|
||||||
|
<i class="${status.icon}"></i> ${this.value}
|
||||||
|
</p>
|
||||||
|
${status.message ? html`<p class="subtext">${status.message}</p>` : html``}`;
|
||||||
|
}), html`<ak-spinner size="${SpinnerSize.Large}"></ak-spinner>`)}
|
||||||
|
</p>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { gettext } from "django";
|
||||||
|
import { customElement, html, TemplateResult } from "lit-element";
|
||||||
|
import { Flow } from "../../../api/flow";
|
||||||
|
import { AdminStatus, AdminStatusCard } from "./AdminStatusCard";
|
||||||
|
import "../../../elements/buttons/ModalButton";
|
||||||
|
|
||||||
|
@customElement("ak-admin-status-card-flow-cache")
|
||||||
|
export class FlowCacheStatusCard extends AdminStatusCard<number> {
|
||||||
|
|
||||||
|
getPrimaryValue(): Promise<number> {
|
||||||
|
return Flow.cached();
|
||||||
|
}
|
||||||
|
|
||||||
|
getStatus(value: number): Promise<AdminStatus> {
|
||||||
|
if (value < 1) {
|
||||||
|
return Promise.resolve<AdminStatus>({
|
||||||
|
icon: "fa fa-exclamation-triangle",
|
||||||
|
message: gettext("No flows cached."),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return Promise.resolve<AdminStatus>({
|
||||||
|
icon: "fa fa-check-circle"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderHeaderLink(): TemplateResult {
|
||||||
|
return html`<ak-modal-button href="/administration/overview/cache/flow/">
|
||||||
|
<a slot="trigger">
|
||||||
|
<i class="fa fa-trash"> </i>
|
||||||
|
</a>
|
||||||
|
<div slot="modal"></div>
|
||||||
|
</ak-modal-button>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
import { gettext } from "django";
|
||||||
|
import { customElement } from "lit-element";
|
||||||
|
import { TemplateResult, html } from "lit-html";
|
||||||
|
import { Policy } from "../../../api/policy";
|
||||||
|
import { AdminStatusCard, AdminStatus } from "./AdminStatusCard";
|
||||||
|
import "../../../elements/buttons/ModalButton";
|
||||||
|
|
||||||
|
@customElement("ak-admin-status-card-policy-cache")
|
||||||
|
export class PolicyCacheStatusCard extends AdminStatusCard<number> {
|
||||||
|
|
||||||
|
getPrimaryValue(): Promise<number> {
|
||||||
|
return Policy.cached();
|
||||||
|
}
|
||||||
|
|
||||||
|
getStatus(value: number): Promise<AdminStatus> {
|
||||||
|
if (value < 1) {
|
||||||
|
return Promise.resolve<AdminStatus>({
|
||||||
|
icon: "fa fa-exclamation-triangle",
|
||||||
|
message: gettext("No policies cached. Users may experience slow response times."),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return Promise.resolve<AdminStatus>({
|
||||||
|
icon: "fa fa-check-circle"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderHeaderLink(): TemplateResult {
|
||||||
|
return html`<ak-modal-button href="/administration/overview/cache/policy/">
|
||||||
|
<a slot="trigger">
|
||||||
|
<i class="fa fa-trash"> </i>
|
||||||
|
</a>
|
||||||
|
<div slot="modal"></div>
|
||||||
|
</ak-modal-button>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
import { gettext } from "django";
|
||||||
|
import { customElement } from "lit-element";
|
||||||
|
import { Policy } from "../../../api/policy";
|
||||||
|
import { AdminStatusCard, AdminStatus } from "./AdminStatusCard";
|
||||||
|
|
||||||
|
@customElement("ak-admin-status-card-policy-unbound")
|
||||||
|
export class PolicyUnboundStatusCard extends AdminStatusCard<number> {
|
||||||
|
|
||||||
|
getPrimaryValue(): Promise<number> {
|
||||||
|
return Policy.list({
|
||||||
|
"bindings__isnull": true,
|
||||||
|
"promptstage__isnull": true,
|
||||||
|
}).then((response) => {
|
||||||
|
return response.pagination.count;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getStatus(value: number): Promise<AdminStatus> {
|
||||||
|
if (value > 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"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { gettext } from "django";
|
||||||
|
import { customElement } from "lit-element";
|
||||||
|
import { Provider } from "../../../api/provider";
|
||||||
|
import { AdminStatusCard, AdminStatus } from "./AdminStatusCard";
|
||||||
|
|
||||||
|
@customElement("ak-admin-status-card-provider")
|
||||||
|
export class ProviderStatusCard extends AdminStatusCard<number> {
|
||||||
|
|
||||||
|
getPrimaryValue(): Promise<number> {
|
||||||
|
return Provider.list({
|
||||||
|
"application__isnull": true
|
||||||
|
}).then((response) => {
|
||||||
|
return response.pagination.count;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getStatus(value: number): Promise<AdminStatus> {
|
||||||
|
if (value > 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"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { gettext } from "django";
|
||||||
|
import { customElement } from "lit-element";
|
||||||
|
import { Version } from "../../../api/version";
|
||||||
|
import { AdminStatusCard, AdminStatus } from "./AdminStatusCard";
|
||||||
|
|
||||||
|
@customElement("ak-admin-status-version")
|
||||||
|
export class VersionStatusCard extends AdminStatusCard<Version> {
|
||||||
|
|
||||||
|
getPrimaryValue(): Promise<Version> {
|
||||||
|
return Version.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
getStatus(value: Version): Promise<AdminStatus> {
|
||||||
|
if (value.outdated) {
|
||||||
|
return Promise.resolve<AdminStatus>({
|
||||||
|
icon: "fa fa-exclamation-triangle",
|
||||||
|
message: gettext(`${value.version_latest} is available!`),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return Promise.resolve<AdminStatus>({
|
||||||
|
icon: "fa fa-check-circle",
|
||||||
|
message: gettext("Up-to-date!")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { gettext } from "django";
|
||||||
|
import { customElement } from "lit-element";
|
||||||
|
import { DefaultClient, PBResponse } from "../../../api/client";
|
||||||
|
import { AdminStatus, AdminStatusCard } from "./AdminStatusCard";
|
||||||
|
|
||||||
|
@customElement("ak-admin-status-card-workers")
|
||||||
|
export class WorkersStatusCard extends AdminStatusCard<number> {
|
||||||
|
|
||||||
|
getPrimaryValue(): Promise<number> {
|
||||||
|
return DefaultClient.fetch<PBResponse<number>>(["admins", "workers"]).then((r) => {
|
||||||
|
return r.pagination.count;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getStatus(value: number): Promise<AdminStatus> {
|
||||||
|
if (value < 1) {
|
||||||
|
return Promise.resolve<AdminStatus>({
|
||||||
|
icon: "fa fa-exclamation-triangle",
|
||||||
|
message: gettext("No workers connected. Background tasks will not run."),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return Promise.resolve<AdminStatus>({
|
||||||
|
icon: "fa fa-check-circle"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in New Issue