feat: add Authentik access widgets

This commit is contained in:
Developer
2026-07-14 21:41:24 +00:00
parent 4562a9dfca
commit 17976eab80
21 changed files with 1082 additions and 214 deletions
+17 -4
View File
@@ -12,6 +12,7 @@ describe("service registry", () => {
it("registers the backend service types", () => {
expect(Object.keys(SERVICE_REGISTRY).sort()).toEqual([
"alertmanager",
"authentik",
"jellyfin",
"nextcloud",
"prometheus",
@@ -30,6 +31,11 @@ describe("service registry", () => {
expect(SERVICE_REGISTRY.alertmanager.widgets.map((w) => w.kind)).toEqual([
"active_alerts",
]);
expect(SERVICE_REGISTRY.authentik.widgets.map((w) => w.kind)).toEqual([
"access_summary",
"groups",
"applications",
]);
expect(SERVICE_REGISTRY.remote_machine.widgets.map((w) => w.kind)).toEqual([
"task_output",
]);
@@ -41,10 +47,17 @@ describe("service registry", () => {
});
it("exposes unit/scale options on graph widget kinds", () => {
const propsOf = (binding: { configSchema: Record<string, unknown> } | undefined) =>
(binding?.configSchema as { properties?: Record<string, { enum?: string[] }> } | undefined)
?.properties ?? {};
const chart = getServiceBinding("prometheus")?.widgets.find((w) => w.kind === "chart");
const propsOf = (
binding: { configSchema: Record<string, unknown> } | undefined,
) =>
(
binding?.configSchema as
| { properties?: Record<string, { enum?: string[] }> }
| undefined
)?.properties ?? {};
const chart = getServiceBinding("prometheus")?.widgets.find(
(w) => w.kind === "chart",
);
const speed = getServiceBinding("qbittorrent")?.widgets.find(
(w) => w.kind === "speed",
);
+50
View File
@@ -1,5 +1,8 @@
import type { ComponentType } from "react";
import { AlertmanagerAlertsWidget } from "../widgets/AlertmanagerAlertsWidget";
import { AuthentikAccessSummaryWidget } from "../widgets/AuthentikAccessSummaryWidget";
import { AuthentikApplicationsWidget } from "../widgets/AuthentikApplicationsWidget";
import { AuthentikGroupsWidget } from "../widgets/AuthentikGroupsWidget";
import { BackupsWidget } from "../widgets/BackupsWidget";
import { MetricChartWidget } from "../widgets/MetricChartWidget";
import { MetricGaugeWidget } from "../widgets/MetricGaugeWidget";
@@ -76,6 +79,53 @@ const AXIS_FORMAT_PROPERTIES = {
};
export const SERVICE_REGISTRY: Record<string, ServiceBinding> = {
authentik: {
serviceType: "authentik",
name: "Authentik",
description: "Read-only user directory, group, and application metadata.",
widgets: [
{
kind: "access_summary",
name: "User access summary",
description:
"Group membership and explicit privileged flags; not effective authorization.",
refreshIntervalMs: 60_000,
defaultConfig: { limit: 10 },
configSchema: {
type: "object",
properties: { limit: { type: "integer", minimum: 1, maximum: 50 } },
required: [],
},
component: AuthentikAccessSummaryWidget,
},
{
kind: "groups",
name: "Groups",
description: "Read-only Authentik group list.",
refreshIntervalMs: 60_000,
defaultConfig: { limit: 10 },
configSchema: {
type: "object",
properties: { limit: { type: "integer", minimum: 1, maximum: 50 } },
required: [],
},
component: AuthentikGroupsWidget,
},
{
kind: "applications",
name: "Applications",
description: "Read-only Authentik application list.",
refreshIntervalMs: 60_000,
defaultConfig: { limit: 10 },
configSchema: {
type: "object",
properties: { limit: { type: "integer", minimum: 1, maximum: 50 } },
required: [],
},
component: AuthentikApplicationsWidget,
},
],
},
alertmanager: {
serviceType: "alertmanager",
name: "Alertmanager",