web/admin: rework admin dashboard, add more links, remove user and group graphs (#4399)
This commit is contained in:
		| @ -1,15 +1,13 @@ | ||||
| import "@goauthentik/admin/admin-overview/TopApplicationsTable"; | ||||
| import "@goauthentik/admin/admin-overview/cards/AdminStatusCard"; | ||||
| import "@goauthentik/admin/admin-overview/cards/RecentEventsCard"; | ||||
| import "@goauthentik/admin/admin-overview/cards/SystemStatusCard"; | ||||
| import "@goauthentik/admin/admin-overview/cards/VersionStatusCard"; | ||||
| import "@goauthentik/admin/admin-overview/cards/WorkerStatusCard"; | ||||
| import "@goauthentik/admin/admin-overview/charts/AdminLoginAuthorizeChart"; | ||||
| import "@goauthentik/admin/admin-overview/charts/FlowStatusChart"; | ||||
| import "@goauthentik/admin/admin-overview/charts/GroupCountStatusChart"; | ||||
| import "@goauthentik/admin/admin-overview/charts/LDAPSyncStatusChart"; | ||||
| import "@goauthentik/admin/admin-overview/charts/OutpostStatusChart"; | ||||
| import "@goauthentik/admin/admin-overview/charts/PolicyStatusChart"; | ||||
| import "@goauthentik/admin/admin-overview/charts/UserCountStatusChart"; | ||||
| import { VERSION } from "@goauthentik/common/constants"; | ||||
| import { me } from "@goauthentik/common/users"; | ||||
| import { AKElement } from "@goauthentik/elements/Base"; | ||||
| import "@goauthentik/elements/PageHeader"; | ||||
| @ -28,6 +26,12 @@ import PFList from "@patternfly/patternfly/components/List/list.css"; | ||||
| import PFPage from "@patternfly/patternfly/components/Page/page.css"; | ||||
| import PFGrid from "@patternfly/patternfly/layouts/Grid/grid.css"; | ||||
|  | ||||
| export function versionFamily(): string { | ||||
|     const parts = VERSION.split("."); | ||||
|     parts.pop(); | ||||
|     return parts.join("."); | ||||
| } | ||||
|  | ||||
| @customElement("ak-admin-overview") | ||||
| export class AdminOverviewPage extends AKElement { | ||||
|     static get styles(): CSSResult[] { | ||||
| @ -72,113 +76,100 @@ export class AdminOverviewPage extends AKElement { | ||||
|             <section class="pf-c-page__main-section"> | ||||
|                 <div class="pf-l-grid pf-m-gutter"> | ||||
|                     <!-- row 1 --> | ||||
|                     <div | ||||
|                         class="pf-l-grid__item pf-m-6-col pf-m-4-col-on-xl pf-m-2-col-on-2xl graph-container" | ||||
|                     > | ||||
|                         <ak-aggregate-card | ||||
|                             icon="fa fa-share" | ||||
|                             header=${t`Quick actions`} | ||||
|                             .isCenter=${false} | ||||
|                     <div class="pf-l-grid__item pf-m-6-col pf-l-grid pf-m-gutter"> | ||||
|                         <div | ||||
|                             class="pf-l-grid__item pf-m-12-col pf-m-8-col-on-xl pf-m-4-col-on-2xl graph-container" | ||||
|                         > | ||||
|                             <ul class="pf-c-list"> | ||||
|                                 <li> | ||||
|                                     <a | ||||
|                                         class="pf-u-mb-xl" | ||||
|                                         href=${paramURL("/core/applications", { | ||||
|                                             createForm: true, | ||||
|                                         })} | ||||
|                                         >${t`Create a new application`}</a | ||||
|                                     > | ||||
|                                 </li> | ||||
|                                 <li> | ||||
|                                     <a class="pf-u-mb-xl" href=${paramURL("/events/log")} | ||||
|                                         >${t`Check the logs`}</a | ||||
|                                     > | ||||
|                                 </li> | ||||
|                                 <li> | ||||
|                                     <a | ||||
|                                         class="pf-u-mb-xl" | ||||
|                                         target="_blank" | ||||
|                                         href="https://goauthentik.io/integrations/" | ||||
|                                         >${t`Explore integrations`}</a | ||||
|                                     > | ||||
|                                 </li> | ||||
|                             </ul> | ||||
|                         </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-2xl graph-container" | ||||
|                     > | ||||
|                         <ak-aggregate-card | ||||
|                             icon="pf-icon pf-icon-process-automation" | ||||
|                             header=${t`Flows`} | ||||
|                             headerLink="#/flow/flows" | ||||
|                             <ak-aggregate-card | ||||
|                                 icon="fa fa-share" | ||||
|                                 header=${t`Quick actions`} | ||||
|                                 .isCenter=${false} | ||||
|                             > | ||||
|                                 <ul class="pf-c-list"> | ||||
|                                     <li> | ||||
|                                         <a | ||||
|                                             class="pf-u-mb-xl" | ||||
|                                             href=${paramURL("/core/applications", { | ||||
|                                                 createForm: true, | ||||
|                                             })} | ||||
|                                             >${t`Create a new application`}</a | ||||
|                                         > | ||||
|                                     </li> | ||||
|                                     <li> | ||||
|                                         <a class="pf-u-mb-xl" href=${paramURL("/events/log")} | ||||
|                                             >${t`Check the logs`}</a | ||||
|                                         > | ||||
|                                     </li> | ||||
|                                     <li> | ||||
|                                         <a | ||||
|                                             class="pf-u-mb-xl" | ||||
|                                             target="_blank" | ||||
|                                             href="https://goauthentik.io/integrations/" | ||||
|                                             >${t`Explore integrations`}</a | ||||
|                                         > | ||||
|                                     </li> | ||||
|                                     <li> | ||||
|                                         <a class="pf-u-mb-xl" href=${paramURL("/identity/users")} | ||||
|                                             >${t`Manage users`}</a | ||||
|                                         > | ||||
|                                     </li> | ||||
|                                     <li> | ||||
|                                         <a | ||||
|                                             class="pf-u-mb-xl" | ||||
|                                             target="_blank" | ||||
|                                             href="https://goauthentik.io/docs/releases/${versionFamily()}#fixed-in-${VERSION.replaceAll( | ||||
|                                                 ".", | ||||
|                                                 "", | ||||
|                                             )}" | ||||
|                                             >${t`Check release notes`}</a | ||||
|                                         > | ||||
|                                     </li> | ||||
|                                 </ul> | ||||
|                             </ak-aggregate-card> | ||||
|                         </div> | ||||
|                         <div | ||||
|                             class="pf-l-grid__item pf-m-12-col pf-m-8-col-on-xl pf-m-4-col-on-2xl graph-container" | ||||
|                         > | ||||
|                             <ak-admin-status-chart-flow></ak-admin-status-chart-flow> | ||||
|                         </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-2xl graph-container" | ||||
|                     > | ||||
|                         <ak-aggregate-card | ||||
|                             icon="pf-icon pf-icon-zone" | ||||
|                             header=${t`Outpost status`} | ||||
|                             headerLink="#/outpost/outposts" | ||||
|                             <ak-aggregate-card | ||||
|                                 icon="pf-icon pf-icon-zone" | ||||
|                                 header=${t`Outpost status`} | ||||
|                                 headerLink="#/outpost/outposts" | ||||
|                             > | ||||
|                                 <ak-admin-status-chart-outpost></ak-admin-status-chart-outpost> | ||||
|                             </ak-aggregate-card> | ||||
|                         </div> | ||||
|                         <div | ||||
|                             class="pf-l-grid__item pf-m-12-col pf-m-8-col-on-xl pf-m-4-col-on-2xl graph-container" | ||||
|                         > | ||||
|                             <ak-admin-status-chart-outpost></ak-admin-status-chart-outpost> | ||||
|                         </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-2xl graph-container" | ||||
|                     > | ||||
|                         <ak-aggregate-card | ||||
|                             icon="pf-icon pf-icon-user" | ||||
|                             header=${t`Users`} | ||||
|                             headerLink="#/identity/users" | ||||
|                             <ak-aggregate-card | ||||
|                                 icon="fa fa-sync-alt" | ||||
|                                 header=${t`LDAP Sync status`} | ||||
|                                 headerLink="#/core/sources" | ||||
|                             > | ||||
|                                 <ak-admin-status-chart-ldap-sync></ak-admin-status-chart-ldap-sync> | ||||
|                             </ak-aggregate-card> | ||||
|                         </div> | ||||
|                         <div class="pf-l-grid__item pf-m-12-col row-divider"> | ||||
|                             <hr /> | ||||
|                         </div> | ||||
|                         <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-chart-user-count></ak-admin-status-chart-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-2xl graph-container" | ||||
|                     > | ||||
|                         <ak-aggregate-card | ||||
|                             icon="pf-icon pf-icon-users" | ||||
|                             header=${t`Groups`} | ||||
|                             headerLink="#/identity/groups" | ||||
|                             <ak-admin-status-system> </ak-admin-status-system> | ||||
|                         </div> | ||||
|                         <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-chart-group-count></ak-admin-status-chart-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-2xl graph-container" | ||||
|                     > | ||||
|                         <ak-aggregate-card | ||||
|                             icon="fa fa-sync-alt" | ||||
|                             header=${t`LDAP Sync status`} | ||||
|                             headerLink="#/core/sources" | ||||
|                             <ak-admin-status-version> </ak-admin-status-version> | ||||
|                         </div> | ||||
|                         <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-chart-ldap-sync></ak-admin-status-chart-ldap-sync> | ||||
|                         </ak-aggregate-card> | ||||
|                             <ak-admin-status-card-workers> </ak-admin-status-card-workers> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                     <div class="pf-l-grid__item pf-m-12-col row-divider"> | ||||
|                         <hr /> | ||||
|                     </div> | ||||
|                     <!-- row 2 --> | ||||
|                     <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-system> </ak-admin-status-system> | ||||
|                     </div> | ||||
|                     <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> </ak-admin-status-version> | ||||
|                     </div> | ||||
|                     <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-workers> </ak-admin-status-card-workers> | ||||
|                     <div class="pf-l-grid__item pf-m-6-col"> | ||||
|                         <ak-recent-events pageSize="6"></ak-recent-events> | ||||
|                     </div> | ||||
|                     <div class="pf-l-grid__item pf-m-12-col row-divider"> | ||||
|                         <hr /> | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| import "@goauthentik/admin/admin-overview/charts/AdminModelPerDay"; | ||||
| import { AKElement } from "@goauthentik/elements/Base"; | ||||
| import "@goauthentik/elements/PageHeader"; | ||||
| import "@goauthentik/elements/cards/AggregatePromiseCard"; | ||||
| import "@goauthentik/elements/charts/AdminModelPerDay"; | ||||
|  | ||||
| import { t } from "@lingui/macro"; | ||||
|  | ||||
|  | ||||
							
								
								
									
										104
									
								
								web/src/admin/admin-overview/cards/RecentEventsCard.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								web/src/admin/admin-overview/cards/RecentEventsCard.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,104 @@ | ||||
| import "@goauthentik/admin/events/EventInfo"; | ||||
| import { ActionToLabel } from "@goauthentik/admin/events/utils"; | ||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||
| import { EventWithContext } from "@goauthentik/common/events"; | ||||
| import "@goauthentik/elements/Tabs"; | ||||
| import "@goauthentik/elements/buttons/Dropdown"; | ||||
| import "@goauthentik/elements/buttons/ModalButton"; | ||||
| import "@goauthentik/elements/buttons/SpinnerButton"; | ||||
| import { KeyUnknown } from "@goauthentik/elements/forms/Form"; | ||||
| import { PaginatedResponse } from "@goauthentik/elements/table/Table"; | ||||
| import { Table, TableColumn } from "@goauthentik/elements/table/Table"; | ||||
|  | ||||
| import { t } from "@lingui/macro"; | ||||
|  | ||||
| import { CSSResult, TemplateResult, css, html } from "lit"; | ||||
| import { customElement, property } from "lit/decorators.js"; | ||||
|  | ||||
| import PFCard from "@patternfly/patternfly/components/Card/card.css"; | ||||
|  | ||||
| import { Event, EventsApi } from "@goauthentik/api"; | ||||
|  | ||||
| @customElement("ak-recent-events") | ||||
| export class RecentEventsCard extends Table<Event> { | ||||
|     @property() | ||||
|     order = "-created"; | ||||
|  | ||||
|     @property() | ||||
|     pageSize = 10; | ||||
|  | ||||
|     async apiEndpoint(page: number): Promise<PaginatedResponse<Event>> { | ||||
|         return new EventsApi(DEFAULT_CONFIG).eventsEventsList({ | ||||
|             ordering: this.order, | ||||
|             page: page, | ||||
|             pageSize: this.pageSize, | ||||
|             search: this.search || "", | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     static get styles(): CSSResult[] { | ||||
|         return super.styles.concat( | ||||
|             PFCard, | ||||
|             css` | ||||
|                 .pf-c-card__title { | ||||
|                     --pf-c-card__title--FontFamily: var( | ||||
|                         --pf-global--FontFamily--heading--sans-serif | ||||
|                     ); | ||||
|                     --pf-c-card__title--FontSize: var(--pf-global--FontSize--md); | ||||
|                     --pf-c-card__title--FontWeight: var(--pf-global--FontWeight--bold); | ||||
|                 } | ||||
|             `, | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     columns(): TableColumn[] { | ||||
|         return [ | ||||
|             new TableColumn(t`Action`, "action"), | ||||
|             new TableColumn(t`User`, "user"), | ||||
|             new TableColumn(t`Creation Date`, "created"), | ||||
|             new TableColumn(t`Client IP`, "client_ip"), | ||||
|             new TableColumn(t`Tenant`, "tenant_name"), | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     renderToolbar(): TemplateResult { | ||||
|         return html`<div class="pf-c-card__title"> | ||||
|             <i class="pf-icon pf-icon-catalog"></i> ${t`Recent events`} | ||||
|         </div>`; | ||||
|     } | ||||
|  | ||||
|     row(item: EventWithContext): TemplateResult[] { | ||||
|         let geo: KeyUnknown | undefined = undefined; | ||||
|         if (Object.hasOwn(item.context, "geo")) { | ||||
|             geo = item.context.geo as KeyUnknown; | ||||
|         } | ||||
|         return [ | ||||
|             html`<div><a href="${`#/events/log/${item.pk}`}">${ActionToLabel(item.action)}</a></div> | ||||
|                 <small>${item.app}</small>`, | ||||
|             item.user?.username | ||||
|                 ? html`<div> | ||||
|                           <a href="#/identity/users/${item.user.pk}" | ||||
|                               >${item.user?.username.substring(0, 15)}</a | ||||
|                           > | ||||
|                       </div> | ||||
|                       ${item.user.on_behalf_of | ||||
|                           ? html`<small> | ||||
|                                 <a href="#/identity/users/${item.user.on_behalf_of.pk}" | ||||
|                                     >${t`On behalf of ${item.user.on_behalf_of.username}`}</a | ||||
|                                 > | ||||
|                             </small>` | ||||
|                           : html``}` | ||||
|                 : html`-`, | ||||
|             html`<span>${item.created?.toLocaleString()}</span>`, | ||||
|             html` <div>${item.clientIp || t`-`}</div> | ||||
|                 ${geo ? html`<small>${geo.city}, ${geo.country}</small> ` : html``}`, | ||||
|             html`<span>${item.tenant?.name || t`-`}</span>`, | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     renderEmpty(): TemplateResult { | ||||
|         return super.renderEmpty(html`<ak-empty-state header=${t`No Events found.`}> | ||||
|             <div slot="body">${t`No matching events could be found.`}</div> | ||||
|         </ak-empty-state>`); | ||||
|     } | ||||
| } | ||||
| @ -72,6 +72,7 @@ export class SystemStatusCard extends AdminStatusCard<System> { | ||||
|                 message: html`${t`Server and client are further than 5 seconds apart.`}`, | ||||
|             }); | ||||
|         } | ||||
|         this.header = t`OK`; | ||||
|         return Promise.resolve<AdminStatus>({ | ||||
|             icon: "fa fa-check-circle pf-m-success", | ||||
|             message: html`${t`Everything is ok.`}`, | ||||
|  | ||||
							
								
								
									
										51
									
								
								web/src/admin/admin-overview/charts/AdminModelPerDay.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								web/src/admin/admin-overview/charts/AdminModelPerDay.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | ||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||
| import { AKChart } from "@goauthentik/elements/charts/Chart"; | ||||
| import { ChartData, Tick } from "chart.js"; | ||||
|  | ||||
| import { t } from "@lingui/macro"; | ||||
|  | ||||
| import { customElement, property } from "lit/decorators.js"; | ||||
|  | ||||
| import { Coordinate, EventActions, EventsApi } from "@goauthentik/api"; | ||||
|  | ||||
| @customElement("ak-charts-admin-model-per-day") | ||||
| export class AdminModelPerDay extends AKChart<Coordinate[]> { | ||||
|     @property() | ||||
|     action: EventActions = EventActions.ModelCreated; | ||||
|  | ||||
|     @property({ attribute: false }) | ||||
|     query?: { [key: string]: unknown } | undefined; | ||||
|  | ||||
|     async apiRequest(): Promise<Coordinate[]> { | ||||
|         return new EventsApi(DEFAULT_CONFIG).eventsEventsPerMonthList({ | ||||
|             action: this.action, | ||||
|             query: JSON.stringify(this.query || {}), | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     timeTickCallback(tickValue: string | number, index: number, ticks: Tick[]): string { | ||||
|         const valueStamp = ticks[index]; | ||||
|         const delta = Date.now() - valueStamp.value; | ||||
|         const ago = Math.round(delta / 1000 / 3600 / 24); | ||||
|         return t`${ago} days ago`; | ||||
|     } | ||||
|  | ||||
|     getChartData(data: Coordinate[]): ChartData { | ||||
|         return { | ||||
|             datasets: [ | ||||
|                 { | ||||
|                     label: t`Objects created`, | ||||
|                     backgroundColor: "rgba(189, 229, 184, .5)", | ||||
|                     spanGaps: true, | ||||
|                     data: | ||||
|                         data.map((cord) => { | ||||
|                             return { | ||||
|                                 x: cord.xCord || 0, | ||||
|                                 y: cord.yCord || 0, | ||||
|                             }; | ||||
|                         }) || [], | ||||
|                 }, | ||||
|             ], | ||||
|         }; | ||||
|     } | ||||
| } | ||||
| @ -1,61 +0,0 @@ | ||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||
| import { AKChart } from "@goauthentik/elements/charts/Chart"; | ||||
| import "@goauthentik/elements/forms/ConfirmationForm"; | ||||
| import { ChartData, ChartOptions } from "chart.js"; | ||||
|  | ||||
| import { t } from "@lingui/macro"; | ||||
|  | ||||
| import { customElement } from "lit/decorators.js"; | ||||
|  | ||||
| import { FlowsApi } from "@goauthentik/api"; | ||||
|  | ||||
| interface FlowMetrics { | ||||
|     count: number; | ||||
|     cached: number; | ||||
| } | ||||
|  | ||||
| @customElement("ak-admin-status-chart-flow") | ||||
| export class PolicyStatusChart extends AKChart<FlowMetrics> { | ||||
|     getChartType(): string { | ||||
|         return "doughnut"; | ||||
|     } | ||||
|  | ||||
|     getOptions(): ChartOptions { | ||||
|         return { | ||||
|             plugins: { | ||||
|                 legend: { | ||||
|                     display: false, | ||||
|                 }, | ||||
|             }, | ||||
|             maintainAspectRatio: false, | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     async apiRequest(): Promise<FlowMetrics> { | ||||
|         const api = new FlowsApi(DEFAULT_CONFIG); | ||||
|         const cached = (await api.flowsInstancesCacheInfoRetrieve()).count || 0; | ||||
|         const count = ( | ||||
|             await api.flowsInstancesList({ | ||||
|                 pageSize: 1, | ||||
|             }) | ||||
|         ).pagination.count; | ||||
|         this.centerText = count.toString(); | ||||
|         return { | ||||
|             count: count - cached, | ||||
|             cached: cached, | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     getChartData(data: FlowMetrics): ChartData { | ||||
|         return { | ||||
|             labels: [t`Total flows`, t`Cached flows`], | ||||
|             datasets: [ | ||||
|                 { | ||||
|                     backgroundColor: ["#2b9af3", "#3e8635"], | ||||
|                     spanGaps: true, | ||||
|                     data: [data.count, data.cached], | ||||
|                 }, | ||||
|             ], | ||||
|         }; | ||||
|     } | ||||
| } | ||||
| @ -1,64 +0,0 @@ | ||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||
| import { AKChart } from "@goauthentik/elements/charts/Chart"; | ||||
| import { ChartData, ChartOptions } from "chart.js"; | ||||
|  | ||||
| import { t } from "@lingui/macro"; | ||||
|  | ||||
| import { customElement } from "lit/decorators.js"; | ||||
|  | ||||
| import { CoreApi } from "@goauthentik/api"; | ||||
|  | ||||
| interface GroupMetrics { | ||||
|     count: number; | ||||
|     superusers: number; | ||||
| } | ||||
|  | ||||
| @customElement("ak-admin-status-chart-group-count") | ||||
| export class GroupCountStatusChart 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], | ||||
|                 }, | ||||
|             ], | ||||
|         }; | ||||
|     } | ||||
| } | ||||
| @ -1,71 +0,0 @@ | ||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||
| import { AKChart } from "@goauthentik/elements/charts/Chart"; | ||||
| import "@goauthentik/elements/forms/ConfirmationForm"; | ||||
| import { ChartData, ChartOptions } from "chart.js"; | ||||
|  | ||||
| import { t } from "@lingui/macro"; | ||||
|  | ||||
| import { customElement } from "lit/decorators.js"; | ||||
|  | ||||
| import { PoliciesApi } from "@goauthentik/api"; | ||||
|  | ||||
| interface PolicyMetrics { | ||||
|     count: number; | ||||
|     cached: number; | ||||
|     unbound: number; | ||||
| } | ||||
|  | ||||
| @customElement("ak-admin-status-chart-policy") | ||||
| export class PolicyStatusChart extends AKChart<PolicyMetrics> { | ||||
|     getChartType(): string { | ||||
|         return "doughnut"; | ||||
|     } | ||||
|  | ||||
|     getOptions(): ChartOptions { | ||||
|         return { | ||||
|             plugins: { | ||||
|                 legend: { | ||||
|                     display: false, | ||||
|                 }, | ||||
|             }, | ||||
|             maintainAspectRatio: false, | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     async apiRequest(): Promise<PolicyMetrics> { | ||||
|         const api = new PoliciesApi(DEFAULT_CONFIG); | ||||
|         const cached = (await api.policiesAllCacheInfoRetrieve()).count || 0; | ||||
|         const count = ( | ||||
|             await api.policiesAllList({ | ||||
|                 pageSize: 1, | ||||
|             }) | ||||
|         ).pagination.count; | ||||
|         const unbound = ( | ||||
|             await api.policiesAllList({ | ||||
|                 bindingsIsnull: true, | ||||
|                 promptstageIsnull: true, | ||||
|             }) | ||||
|         ).pagination.count; | ||||
|         this.centerText = count.toString(); | ||||
|         return { | ||||
|             // If we have more cache than total policies, only show that | ||||
|             // otherwise show count without unbound | ||||
|             count: cached >= count ? cached : count - unbound, | ||||
|             cached: cached, | ||||
|             unbound: unbound, | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     getChartData(data: PolicyMetrics): ChartData { | ||||
|         return { | ||||
|             labels: [t`Total policies`, t`Cached policies`, t`Unbound policies`], | ||||
|             datasets: [ | ||||
|                 { | ||||
|                     backgroundColor: ["#2b9af3", "#3e8635", "#f0ab00"], | ||||
|                     spanGaps: true, | ||||
|                     data: [data.count, data.cached, data.unbound], | ||||
|                 }, | ||||
|             ], | ||||
|         }; | ||||
|     } | ||||
| } | ||||
| @ -1,64 +0,0 @@ | ||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||
| import { AKChart } from "@goauthentik/elements/charts/Chart"; | ||||
| import { ChartData, ChartOptions } from "chart.js"; | ||||
|  | ||||
| import { t } from "@lingui/macro"; | ||||
|  | ||||
| import { customElement } from "lit/decorators.js"; | ||||
|  | ||||
| import { CoreApi } from "@goauthentik/api"; | ||||
|  | ||||
| interface UserMetrics { | ||||
|     count: number; | ||||
|     superusers: number; | ||||
| } | ||||
|  | ||||
| @customElement("ak-admin-status-chart-user-count") | ||||
| export class UserCountStatusChart 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
	
	Block a user
	 Jens L
					Jens L