web/admin: show users and groups as chart
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
49bf82a0a4
commit
9538ad5710
|
@ -7,14 +7,14 @@ import "./TopApplicationsTable";
|
||||||
|
|
||||||
import "./cards/AdminStatusCard";
|
import "./cards/AdminStatusCard";
|
||||||
import "./cards/BackupStatusCard";
|
import "./cards/BackupStatusCard";
|
||||||
import "./cards/ProviderStatusCard";
|
|
||||||
import "./cards/UserCountStatusCard";
|
|
||||||
import "./cards/VersionStatusCard";
|
import "./cards/VersionStatusCard";
|
||||||
import "./cards/WorkerStatusCard";
|
import "./cards/WorkerStatusCard";
|
||||||
|
|
||||||
import "./graphs/FlowStatusCard";
|
import "./graphs/FlowStatusCard";
|
||||||
import "./graphs/LDAPSyncStatusCard";
|
import "./graphs/LDAPSyncStatusCard";
|
||||||
import "./graphs/OutpostStatusCard";
|
import "./graphs/OutpostStatusCard";
|
||||||
|
import "./graphs/UserCountStatusCard";
|
||||||
|
import "./graphs/GroupCountStatusCard";
|
||||||
import "./graphs/PolicyStatusCard";
|
import "./graphs/PolicyStatusCard";
|
||||||
|
|
||||||
import PFPage from "@patternfly/patternfly/components/Page/page.css";
|
import PFPage from "@patternfly/patternfly/components/Page/page.css";
|
||||||
|
@ -54,43 +54,49 @@ export class AdminOverviewPage extends LitElement {
|
||||||
<section class="pf-c-page__main-section">
|
<section class="pf-c-page__main-section">
|
||||||
<div class="pf-l-grid pf-m-gutter">
|
<div class="pf-l-grid pf-m-gutter">
|
||||||
<!-- row 1 -->
|
<!-- row 1 -->
|
||||||
<div class="pf-l-grid__item pf-m-6-col pf-m-4-col-on-md pf-m-3-col-on-xl graph-container">
|
<div class="pf-l-grid__item pf-m-6-col pf-m-4-col-on-xl pf-m-2-col-on-xl2 graph-container">
|
||||||
<ak-aggregate-card icon="pf-icon pf-icon-infrastructure" header=${t`Policies`} headerLink="#/policy/policies">
|
<ak-aggregate-card icon="pf-icon pf-icon-infrastructure" header=${t`Policies`} headerLink="#/policy/policies">
|
||||||
<ak-admin-status-card-policy></ak-admin-status-card-policy>
|
<ak-admin-status-card-policy></ak-admin-status-card-policy>
|
||||||
</ak-aggregate-card>
|
</ak-aggregate-card>
|
||||||
</div>
|
</div>
|
||||||
<div class="pf-l-grid__item pf-m-6-col pf-m-4-col-on-md pf-m-3-col-on-xl graph-container">
|
<div class="pf-l-grid__item pf-m-6-col pf-m-4-col-on-xl pf-m-2-col-on-xl2 graph-container">
|
||||||
<ak-aggregate-card icon="pf-icon pf-icon-server" header=${t`Flows`} headerLink="#/flow/flows">
|
<ak-aggregate-card icon="pf-icon pf-icon-server" header=${t`Flows`} headerLink="#/flow/flows">
|
||||||
<ak-admin-status-card-flow></ak-admin-status-card-flow>
|
<ak-admin-status-card-flow></ak-admin-status-card-flow>
|
||||||
</ak-aggregate-card>
|
</ak-aggregate-card>
|
||||||
</div>
|
</div>
|
||||||
<div class="pf-l-grid__item pf-m-6-col pf-m-4-col-on-md pf-m-3-col-on-xl graph-container">
|
<div class="pf-l-grid__item pf-m-6-col pf-m-4-col-on-xl pf-m-2-col-on-xl2 graph-container">
|
||||||
<ak-aggregate-card icon="fa fa-sync-alt" header=${t`LDAP Sync status`} headerLink="#/core/sources">
|
|
||||||
<ak-admin-status-card-ldap-sync></ak-admin-status-card-ldap-sync>
|
|
||||||
</ak-aggregate-card>
|
|
||||||
</div>
|
|
||||||
<div class="pf-l-grid__item pf-m-6-col pf-m-4-col-on-md pf-m-3-col-on-xl graph-container">
|
|
||||||
<ak-aggregate-card icon="fa fa-sync-alt" header=${t`Outpost status`} headerLink="#/outpost/outposts">
|
<ak-aggregate-card icon="fa fa-sync-alt" header=${t`Outpost status`} headerLink="#/outpost/outposts">
|
||||||
<ak-admin-status-card-outpost></ak-admin-status-card-outpost>
|
<ak-admin-status-card-outpost></ak-admin-status-card-outpost>
|
||||||
</ak-aggregate-card>
|
</ak-aggregate-card>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="pf-l-grid__item pf-m-6-col pf-m-4-col-on-xl pf-m-2-col-on-xl2 graph-container">
|
||||||
|
<ak-aggregate-card icon="fa fa-sync-alt" header=${t`Users`} headerLink="#/identity/users">
|
||||||
|
<ak-admin-status-card-user-count></ak-admin-status-card-user-count>
|
||||||
|
</ak-aggregate-card>
|
||||||
|
</div>
|
||||||
|
<div class="pf-l-grid__item pf-m-6-col pf-m-4-col-on-xl pf-m-2-col-on-xl2 graph-container">
|
||||||
|
<ak-aggregate-card icon="fa fa-sync-alt" header=${t`Groups`} headerLink="#/identity/groups">
|
||||||
|
<ak-admin-status-card-group-count></ak-admin-status-card-group-count>
|
||||||
|
</ak-aggregate-card>
|
||||||
|
</div>
|
||||||
|
<div class="pf-l-grid__item pf-m-6-col pf-m-4-col-on-xl pf-m-2-col-on-xl2 graph-container">
|
||||||
|
<ak-aggregate-card icon="fa fa-sync-alt" header=${t`LDAP Sync status`} headerLink="#/core/sources">
|
||||||
|
<ak-admin-status-card-ldap-sync></ak-admin-status-card-ldap-sync>
|
||||||
|
</ak-aggregate-card>
|
||||||
|
</div>
|
||||||
<div class="pf-l-grid__item pf-m-12-col row-divider">
|
<div class="pf-l-grid__item pf-m-12-col row-divider">
|
||||||
<hr>
|
<hr>
|
||||||
</div>
|
</div>
|
||||||
<!-- row 2 -->
|
<!-- row 2 -->
|
||||||
<div class="pf-l-grid__item pf-m-6-col pf-m-4-col-on-md pf-m-3-col-on-xl card-container">
|
<div class="pf-l-grid__item pf-m-6-col pf-m-4-col-on-md pf-m-4-col-on-xl card-container">
|
||||||
<ak-admin-status-version icon="pf-icon pf-icon-bundle" header=${t`Version`} headerLink="https://github.com/goauthentik/authentik/releases">
|
<ak-admin-status-version icon="pf-icon pf-icon-bundle" header=${t`Version`} headerLink="https://github.com/goauthentik/authentik/releases">
|
||||||
</ak-admin-status-version>
|
</ak-admin-status-version>
|
||||||
</div>
|
</div>
|
||||||
<div class="pf-l-grid__item pf-m-6-col pf-m-4-col-on-md pf-m-3-col-on-xl card-container">
|
<div class="pf-l-grid__item pf-m-6-col pf-m-4-col-on-md pf-m-4-col-on-xl card-container">
|
||||||
<ak-admin-status-card-backup icon="fa fa-database" header=${t`Backup status`} headerLink="#/administration/system-tasks">
|
<ak-admin-status-card-backup icon="fa fa-database" header=${t`Backup status`} headerLink="#/administration/system-tasks">
|
||||||
</ak-admin-status-card-backup>
|
</ak-admin-status-card-backup>
|
||||||
</div>
|
</div>
|
||||||
<div class="pf-l-grid__item pf-m-6-col pf-m-4-col-on-md pf-m-3-col-on-xl card-container">
|
<div class="pf-l-grid__item pf-m-6-col pf-m-4-col-on-md pf-m-4-col-on-xl card-container">
|
||||||
<ak-admin-status-card-user-count icon="pf-icon pf-icon-user" header=${t`Users`} headerLink="#/identity/users">
|
|
||||||
</ak-admin-status-card-user-count>
|
|
||||||
</div>
|
|
||||||
<div class="pf-l-grid__item pf-m-6-col pf-m-4-col-on-md pf-m-3-col-on-xl card-container">
|
|
||||||
<ak-admin-status-card-workers icon="pf-icon pf-icon-server" header=${t`Workers`}>
|
<ak-admin-status-card-workers icon="pf-icon pf-icon-server" header=${t`Workers`}>
|
||||||
</ak-admin-status-card-workers>
|
</ak-admin-status-card-workers>
|
||||||
</div>
|
</div>
|
||||||
|
@ -98,12 +104,12 @@ export class AdminOverviewPage extends LitElement {
|
||||||
<hr>
|
<hr>
|
||||||
</div>
|
</div>
|
||||||
<!-- row 3 -->
|
<!-- row 3 -->
|
||||||
<div class="pf-l-grid__item pf-m-12-col pf-m-6-col-on-md pf-m-6-col-on-xl big-graph-container">
|
<div class="pf-l-grid__item pf-m-12-col pf-m-6-col-on-xl pf-m-9-col-on-xl2 big-graph-container">
|
||||||
<ak-aggregate-card icon="pf-icon pf-icon-server" header=${t`Logins over the last 24 hours`}>
|
<ak-aggregate-card icon="pf-icon pf-icon-server" header=${t`Logins over the last 24 hours`}>
|
||||||
<ak-charts-admin-login></ak-charts-admin-login>
|
<ak-charts-admin-login></ak-charts-admin-login>
|
||||||
</ak-aggregate-card>
|
</ak-aggregate-card>
|
||||||
</div>
|
</div>
|
||||||
<div class="pf-l-grid__item pf-m-12-col pf-m-6-col-on-md pf-m-6-col-on-xl big-graph-container">
|
<div class="pf-l-grid__item pf-m-12-col pf-m-6-col-on-xl pf-m-3-col-on-xl2 big-graph-container">
|
||||||
<ak-aggregate-card icon="pf-icon pf-icon-server" header=${t`Apps with most usage`}>
|
<ak-aggregate-card icon="pf-icon pf-icon-server" header=${t`Apps with most usage`}>
|
||||||
<ak-top-applications-table></ak-top-applications-table>
|
<ak-top-applications-table></ak-top-applications-table>
|
||||||
</ak-aggregate-card>
|
</ak-aggregate-card>
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
import { t } from "@lingui/macro";
|
|
||||||
import { customElement } from "lit-element";
|
|
||||||
import { ProvidersApi } from "authentik-api";
|
|
||||||
import { DEFAULT_CONFIG } from "../../../api/Config";
|
|
||||||
import { AdminStatusCard, AdminStatus } from "./AdminStatusCard";
|
|
||||||
|
|
||||||
@customElement("ak-admin-status-card-provider")
|
|
||||||
export class ProviderStatusCard extends AdminStatusCard<number> {
|
|
||||||
|
|
||||||
getPrimaryValue(): Promise<number> {
|
|
||||||
return new ProvidersApi(DEFAULT_CONFIG).providersAllList({
|
|
||||||
applicationIsnull: "true"
|
|
||||||
}).then((value) => {
|
|
||||||
return value.pagination.count;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getStatus(value: number): Promise<AdminStatus> {
|
|
||||||
if (value > 0) {
|
|
||||||
return Promise.resolve<AdminStatus>({
|
|
||||||
icon: "fa fa-exclamation-triangle pf-m-warning",
|
|
||||||
message: t`Warning: At least one Provider has no application assigned.`,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return Promise.resolve<AdminStatus>({
|
|
||||||
icon: "fa fa-check-circle pf-m-success"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
import { customElement } from "lit-element";
|
|
||||||
import { CoreApi } from "authentik-api";
|
|
||||||
import { DEFAULT_CONFIG } from "../../../api/Config";
|
|
||||||
import { AdminStatusCard, AdminStatus } from "./AdminStatusCard";
|
|
||||||
|
|
||||||
@customElement("ak-admin-status-card-user-count")
|
|
||||||
export class UserCountStatusCard extends AdminStatusCard<number> {
|
|
||||||
|
|
||||||
getPrimaryValue(): Promise<number> {
|
|
||||||
return new CoreApi(DEFAULT_CONFIG).coreUsersList({
|
|
||||||
pageSize: 1
|
|
||||||
}).then((value) => {
|
|
||||||
return value.pagination.count;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
getStatus(value: number): Promise<AdminStatus> {
|
|
||||||
return Promise.resolve<AdminStatus>({
|
|
||||||
icon: "fa fa-check-circle pf-m-success"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
import { customElement } from "lit-element";
|
||||||
|
import { CoreApi } from "authentik-api";
|
||||||
|
import { DEFAULT_CONFIG } from "../../../api/Config";
|
||||||
|
import { AKChart } from "../../../elements/charts/Chart";
|
||||||
|
import { t } from "@lingui/macro";
|
||||||
|
import { ChartOptions, ChartData } from "chart.js";
|
||||||
|
|
||||||
|
interface GroupMetrics {
|
||||||
|
count: number;
|
||||||
|
superusers: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement("ak-admin-status-card-group-count")
|
||||||
|
export class GroupCountStatusCard extends AKChart<GroupMetrics> {
|
||||||
|
|
||||||
|
getChartType(): string {
|
||||||
|
return "doughnut";
|
||||||
|
}
|
||||||
|
|
||||||
|
getOptions(): ChartOptions {
|
||||||
|
return {
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
display: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async apiRequest(): Promise<GroupMetrics> {
|
||||||
|
const api = new CoreApi(DEFAULT_CONFIG);
|
||||||
|
const count = (await api.coreGroupsList({
|
||||||
|
pageSize: 1
|
||||||
|
})).pagination.count;
|
||||||
|
const superusers = (await api.coreGroupsList({
|
||||||
|
isSuperuser: "true"
|
||||||
|
})).pagination.count;
|
||||||
|
this.centerText = count.toString();
|
||||||
|
return {
|
||||||
|
count: count - superusers,
|
||||||
|
superusers,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
getChartData(data: GroupMetrics): ChartData {
|
||||||
|
return {
|
||||||
|
labels: [
|
||||||
|
t`Total groups`,
|
||||||
|
t`Superuser-groups`,
|
||||||
|
],
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
backgroundColor: [
|
||||||
|
"#2b9af3",
|
||||||
|
"#3e8635",
|
||||||
|
],
|
||||||
|
spanGaps: true,
|
||||||
|
data: [
|
||||||
|
data.count,
|
||||||
|
data.superusers,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
import { customElement } from "lit-element";
|
||||||
|
import { CoreApi } from "authentik-api";
|
||||||
|
import { DEFAULT_CONFIG } from "../../../api/Config";
|
||||||
|
import { AKChart } from "../../../elements/charts/Chart";
|
||||||
|
import { t } from "@lingui/macro";
|
||||||
|
import { ChartOptions, ChartData } from "chart.js";
|
||||||
|
|
||||||
|
interface UserMetrics {
|
||||||
|
count: number;
|
||||||
|
superusers: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement("ak-admin-status-card-user-count")
|
||||||
|
export class UserCountStatusCard extends AKChart<UserMetrics> {
|
||||||
|
|
||||||
|
getChartType(): string {
|
||||||
|
return "doughnut";
|
||||||
|
}
|
||||||
|
|
||||||
|
getOptions(): ChartOptions {
|
||||||
|
return {
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
display: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async apiRequest(): Promise<UserMetrics> {
|
||||||
|
const api = new CoreApi(DEFAULT_CONFIG);
|
||||||
|
const count = (await api.coreUsersList({
|
||||||
|
pageSize: 1
|
||||||
|
})).pagination.count;
|
||||||
|
const superusers = (await api.coreUsersList({
|
||||||
|
isSuperuser: "true"
|
||||||
|
})).pagination.count;
|
||||||
|
this.centerText = count.toString();
|
||||||
|
return {
|
||||||
|
count: count - superusers,
|
||||||
|
superusers,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
getChartData(data: UserMetrics): ChartData {
|
||||||
|
return {
|
||||||
|
labels: [
|
||||||
|
t`Total users`,
|
||||||
|
t`Superusers`,
|
||||||
|
],
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
backgroundColor: [
|
||||||
|
"#2b9af3",
|
||||||
|
"#3e8635",
|
||||||
|
],
|
||||||
|
spanGaps: true,
|
||||||
|
data: [
|
||||||
|
data.count,
|
||||||
|
data.superusers,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in New Issue