web: re-add sync status cards

Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
This commit is contained in:
Marc 'risson' Schmitt
2025-06-26 16:31:23 +02:00
parent f3c0ca1a59
commit 49a9911271
17 changed files with 332 additions and 22 deletions

View File

@ -1,6 +1,5 @@
import "@goauthentik/admin/blueprints/BlueprintForm";
import "@goauthentik/admin/rbac/ObjectPermissionModal";
import "@goauthentik/admin/system-tasks/TaskList";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { EVENT_REFRESH } from "@goauthentik/common/constants";
import { formatElapsedTime } from "@goauthentik/common/temporal";
@ -12,6 +11,7 @@ import "@goauthentik/elements/forms/ModalForm";
import { PaginatedResponse } from "@goauthentik/elements/table/Table";
import { TableColumn } from "@goauthentik/elements/table/Table";
import { TablePage } from "@goauthentik/elements/table/TablePage";
import "@goauthentik/elements/tasks/TaskList";
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
import { msg } from "@lit/localize";

View File

@ -1,7 +1,6 @@
import "@goauthentik/admin/events/RuleForm";
import "@goauthentik/admin/policies/BoundPoliciesList";
import "@goauthentik/admin/rbac/ObjectPermissionModal";
import "@goauthentik/admin/system-tasks/TaskList";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { severityToLabel } from "@goauthentik/common/labels";
import "@goauthentik/components/ak-status-label";
@ -11,6 +10,7 @@ import "@goauthentik/elements/forms/ModalForm";
import { PaginatedResponse } from "@goauthentik/elements/table/Table";
import { TableColumn } from "@goauthentik/elements/table/Table";
import { TablePage } from "@goauthentik/elements/table/TablePage";
import "@goauthentik/elements/tasks/TaskList";
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
import { msg } from "@lit/localize";

View File

@ -1,6 +1,5 @@
import "@goauthentik/admin/events/TransportForm";
import "@goauthentik/admin/rbac/ObjectPermissionModal";
import "@goauthentik/admin/system-tasks/TaskList";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import "@goauthentik/elements/buttons/ActionButton";
import "@goauthentik/elements/buttons/SpinnerButton";
@ -9,6 +8,7 @@ import "@goauthentik/elements/forms/ModalForm";
import { PaginatedResponse } from "@goauthentik/elements/table/Table";
import { TableColumn } from "@goauthentik/elements/table/Table";
import { TablePage } from "@goauthentik/elements/table/TablePage";
import "@goauthentik/elements/tasks/TaskList";
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
import { msg } from "@lit/localize";

View File

@ -4,8 +4,6 @@ import "@goauthentik/admin/outposts/OutpostForm";
import "@goauthentik/admin/outposts/OutpostHealth";
import "@goauthentik/admin/outposts/OutpostHealthSimple";
import "@goauthentik/admin/rbac/ObjectPermissionModal";
import "@goauthentik/admin/system-tasks/ScheduleList";
import "@goauthentik/admin/system-tasks/TaskList";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { PFSize } from "@goauthentik/common/enums.js";
import { PFColor } from "@goauthentik/elements/Label";
@ -15,6 +13,8 @@ import "@goauthentik/elements/forms/ModalForm";
import { PaginatedResponse } from "@goauthentik/elements/table/Table";
import { TableColumn } from "@goauthentik/elements/table/Table";
import { TablePage } from "@goauthentik/elements/table/TablePage";
import "@goauthentik/elements/tasks/ScheduleList";
import "@goauthentik/elements/tasks/TaskList";
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
import { msg, str } from "@lit/localize";

View File

@ -3,8 +3,6 @@ import "@goauthentik/admin/outposts/ServiceConnectionDockerForm";
import "@goauthentik/admin/outposts/ServiceConnectionKubernetesForm";
import "@goauthentik/admin/outposts/ServiceConnectionWizard";
import "@goauthentik/admin/rbac/ObjectPermissionModal";
import "@goauthentik/admin/system-tasks/ScheduleList";
import "@goauthentik/admin/system-tasks/TaskList";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import "@goauthentik/components/ak-status-label";
import { PFColor } from "@goauthentik/elements/Label";
@ -15,6 +13,8 @@ import "@goauthentik/elements/forms/ProxyForm";
import { PaginatedResponse } from "@goauthentik/elements/table/Table";
import { TableColumn } from "@goauthentik/elements/table/Table";
import { TablePage } from "@goauthentik/elements/table/TablePage";
import "@goauthentik/elements/tasks/ScheduleList";
import "@goauthentik/elements/tasks/TaskList";
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
import { msg, str } from "@lit/localize";

View File

@ -2,8 +2,6 @@ import "@goauthentik/admin/providers/google_workspace/GoogleWorkspaceProviderFor
import "@goauthentik/admin/providers/google_workspace/GoogleWorkspaceProviderGroupList";
import "@goauthentik/admin/providers/google_workspace/GoogleWorkspaceProviderUserList";
import "@goauthentik/admin/rbac/ObjectPermissionsPage";
import "@goauthentik/admin/system-tasks/ScheduleList";
import "@goauthentik/admin/system-tasks/TaskList";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { EVENT_REFRESH } from "@goauthentik/common/constants";
import "@goauthentik/components/ak-status-label";
@ -12,6 +10,9 @@ import { AKElement } from "@goauthentik/elements/Base";
import "@goauthentik/elements/Tabs";
import "@goauthentik/elements/buttons/ActionButton";
import "@goauthentik/elements/buttons/ModalButton";
import "@goauthentik/elements/sync/SyncStatusCard";
import "@goauthentik/elements/tasks/ScheduleList";
import "@goauthentik/elements/tasks/TaskList";
import { msg } from "@lit/localize";
import { CSSResult, PropertyValues, TemplateResult, html } from "lit";
@ -148,7 +149,9 @@ export class GoogleWorkspaceProviderViewPage extends AKElement {
</div>`
: html``}
<div class="pf-c-page__main-section pf-m-no-padding-mobile pf-l-grid pf-m-gutter">
<div class="pf-c-card pf-m-12-col pf-l-stack__item">
<div
class="pf-c-card pf-l-grid__item pf-m-12-col pf-m-6-col-on-xl pf-m-6-col-on-2xl"
>
<div class="pf-c-card__body">
<dl class="pf-c-description-list pf-m-3-col-on-lg">
<div class="pf-c-description-list__group">
@ -195,6 +198,19 @@ export class GoogleWorkspaceProviderViewPage extends AKElement {
</ak-forms-modal>
</div>
</div>
<div
class="pf-c-card pf-l-grid__item pf-m-12-col pf-m-6-col-on-xl pf-m-6-col-on-2xl"
>
<ak-sync-status-card
.fetch=${() => {
return new ProvidersApi(
DEFAULT_CONFIG,
).providersGoogleWorkspaceSyncStatusRetrieve({
id: this.provider?.pk || 0,
});
}}
></ak-sync-status-card>
</div>
<div class="pf-l-grid__item pf-m-12-col pf-l-stack__item">
<div class="pf-c-card">
<div class="pf-c-card__header">

View File

@ -2,8 +2,6 @@ import "@goauthentik/admin/providers/microsoft_entra/MicrosoftEntraProviderForm"
import "@goauthentik/admin/providers/microsoft_entra/MicrosoftEntraProviderGroupList";
import "@goauthentik/admin/providers/microsoft_entra/MicrosoftEntraProviderUserList";
import "@goauthentik/admin/rbac/ObjectPermissionsPage";
import "@goauthentik/admin/system-tasks/ScheduleList";
import "@goauthentik/admin/system-tasks/TaskList";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { EVENT_REFRESH } from "@goauthentik/common/constants";
import "@goauthentik/components/events/ObjectChangelog";
@ -12,6 +10,9 @@ import "@goauthentik/elements/Tabs";
import "@goauthentik/elements/buttons/ActionButton";
import "@goauthentik/elements/buttons/ModalButton";
import "@goauthentik/elements/events/LogViewer";
import "@goauthentik/elements/sync/SyncStatusCard";
import "@goauthentik/elements/tasks/ScheduleList";
import "@goauthentik/elements/tasks/TaskList";
import { msg } from "@lit/localize";
import { CSSResult, PropertyValues, TemplateResult, html } from "lit";
@ -148,7 +149,9 @@ export class MicrosoftEntraProviderViewPage extends AKElement {
</div>`
: html``}
<div class="pf-c-page__main-section pf-m-no-padding-mobile pf-l-grid pf-m-gutter">
<div class="pf-c-card pf-m-12-col pf-l-stack__item">
<div
class="pf-c-card pf-l-grid__item pf-m-12-col pf-m-6-col-on-xl pf-m-6-col-on-2xl"
>
<div class="pf-c-card__body">
<dl class="pf-c-description-list pf-m-3-col-on-lg">
<div class="pf-c-description-list__group">
@ -195,6 +198,19 @@ export class MicrosoftEntraProviderViewPage extends AKElement {
</ak-forms-modal>
</div>
</div>
<div
class="pf-c-card pf-l-grid__item pf-m-12-col pf-m-6-col-on-xl pf-m-6-col-on-2xl"
>
<ak-sync-status-card
.fetch=${() => {
return new ProvidersApi(
DEFAULT_CONFIG,
).providersMicrosoftEntraSyncStatusRetrieve({
id: this.provider?.pk || 0,
});
}}
></ak-sync-status-card>
</div>
<div class="pf-l-grid__item pf-m-12-col pf-l-stack__item">
<div class="pf-c-card">

View File

@ -3,8 +3,6 @@ import "@goauthentik/admin/providers/scim/SCIMProviderForm";
import "@goauthentik/admin/providers/scim/SCIMProviderGroupList";
import "@goauthentik/admin/providers/scim/SCIMProviderUserList";
import "@goauthentik/admin/rbac/ObjectPermissionsPage";
import "@goauthentik/admin/system-tasks/ScheduleList";
import "@goauthentik/admin/system-tasks/TaskList";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { EVENT_REFRESH } from "@goauthentik/common/constants";
import "@goauthentik/components/ak-status-label";
@ -14,6 +12,9 @@ import "@goauthentik/elements/Tabs";
import "@goauthentik/elements/ak-mdx";
import "@goauthentik/elements/buttons/ActionButton";
import "@goauthentik/elements/buttons/ModalButton";
import "@goauthentik/elements/sync/SyncStatusCard";
import "@goauthentik/elements/tasks/ScheduleList";
import "@goauthentik/elements/tasks/TaskList";
import MDSCIMProvider from "~docs/add-secure-apps/providers/scim/index.md";
import { msg } from "@lit/localize";
@ -223,6 +224,19 @@ export class SCIMProviderViewPage extends AKElement {
</ak-forms-modal>
</div>
</div>
<div
class="pf-c-card pf-l-grid__item pf-m-12-col pf-m-6-col-on-xl pf-m-6-col-on-2xl"
>
<ak-sync-status-card
.fetch=${() => {
return new ProvidersApi(DEFAULT_CONFIG).providersScimSyncStatusRetrieve(
{
id: this.provider?.pk || 0,
},
);
}}
></ak-sync-status-card>
</div>
<div class="pf-l-grid__item pf-m-12-col pf-l-stack__item">
<div class="pf-c-card">
<div class="pf-c-card__header">

View File

@ -1,7 +1,6 @@
import "@goauthentik/admin/providers/RelatedApplicationButton";
import "@goauthentik/admin/providers/ssf/SSFProviderFormPage";
import "@goauthentik/admin/providers/ssf/StreamTable";
import "@goauthentik/admin/system-tasks/TaskList";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { EVENT_REFRESH } from "@goauthentik/common/constants";
import "@goauthentik/components/events/ObjectChangelog";
@ -11,6 +10,7 @@ import "@goauthentik/elements/EmptyState";
import "@goauthentik/elements/Tabs";
import "@goauthentik/elements/buttons/ModalButton";
import "@goauthentik/elements/buttons/SpinnerButton";
import "@goauthentik/elements/tasks/TaskList";
import { msg } from "@lit/localize";
import { CSSResult, TemplateResult, html } from "lit";

View File

@ -1,7 +1,6 @@
import "@goauthentik/admin/rbac/ObjectPermissionsPage";
import "@goauthentik/admin/sources/ldap/LDAPSourceConnectivity";
import "@goauthentik/admin/sources/ldap/LDAPSourceForm";
import "@goauthentik/admin/system-tasks/ScheduleList";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { EVENT_REFRESH } from "@goauthentik/common/constants";
import "@goauthentik/components/events/ObjectChangelog";
@ -11,6 +10,7 @@ import "@goauthentik/elements/Tabs";
import "@goauthentik/elements/buttons/ActionButton";
import "@goauthentik/elements/buttons/SpinnerButton";
import "@goauthentik/elements/forms/ModalForm";
import "@goauthentik/elements/tasks/ScheduleList";
import { msg } from "@lit/localize";
import { CSSResult, TemplateResult, html } from "lit";

View File

@ -1,11 +1,11 @@
import "#components/ak-page-header";
import "@goauthentik/admin/system-tasks/ScheduleList";
import "@goauthentik/admin/system-tasks/TaskList";
import { AKElement } from "@goauthentik/elements/Base";
import "@goauthentik/elements/Tabs";
import "@goauthentik/elements/buttons/ActionButton";
import "@goauthentik/elements/buttons/SpinnerButton";
import "@goauthentik/elements/events/LogViewer";
import "@goauthentik/elements/tasks/ScheduleList";
import "@goauthentik/elements/tasks/TaskList";
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
import { msg } from "@lit/localize";

View File

@ -0,0 +1,89 @@
import type { Meta, StoryObj } from "@storybook/web-components";
import { html } from "lit";
import { SyncStatus, TaskAggregatedStatusEnum } from "@goauthentik/api";
import "./SyncStatusCard";
const metadata: Meta<SyncStatus> = {
title: "Elements/<ak-sync-status-card>",
component: "ak-sync-status-card",
};
export default metadata;
export const Running: StoryObj = {
args: {
status: {
isRunning: true,
} as SyncStatus,
},
// @ts-ignore
render: ({ status }: SyncStatus) => {
return html` <div style="background-color: #f0f0f0; padding: 1rem;">
<ak-sync-status-card
.fetch=${async () => {
return status;
}}
></ak-sync-status-card>
</div>`;
},
};
export const LastSyncDone: StoryObj = {
args: {
status: {
isRunning: false,
lastSyncStatus: TaskAggregatedStatusEnum.Done,
} as SyncStatus,
},
// @ts-ignore
render: ({ status }: SyncStatus) => {
return html` <div style="background-color: #f0f0f0; padding: 1rem;">
<ak-sync-status-card
.fetch=${async () => {
return status;
}}
></ak-sync-status-card>
</div>`;
},
};
export const LastSyncError: StoryObj = {
args: {
status: {
isRunning: false,
lastSyncStatus: TaskAggregatedStatusEnum.Error,
} as SyncStatus,
},
// @ts-ignore
render: ({ status }: SyncStatus) => {
return html` <div style="background-color: #f0f0f0; padding: 1rem;">
<ak-sync-status-card
.fetch=${async () => {
return status;
}}
></ak-sync-status-card>
</div>`;
},
};
export const LastSuccessfulSync: StoryObj = {
args: {
status: {
isRunning: false,
lastSuccessfulSync: new Date(),
} as SyncStatus,
},
// @ts-ignore
render: ({ status }: SyncStatus) => {
return html` <div style="background-color: #f0f0f0; padding: 1rem;">
<ak-sync-status-card
.fetch=${async () => {
return status;
}}
></ak-sync-status-card>
</div>`;
},
};

View File

@ -0,0 +1,119 @@
import { formatElapsedTime } from "@goauthentik/common/temporal";
import "@goauthentik/components/ak-status-label";
import { AKElement } from "@goauthentik/elements/Base";
import "@goauthentik/elements/EmptyState";
import "@goauthentik/elements/buttons/ActionButton";
import "@goauthentik/elements/events/LogViewer";
import "@goauthentik/elements/tasks/TaskStatus";
import { msg } from "@lit/localize";
import { CSSResult, TemplateResult, html } from "lit";
import { customElement, property, state } from "lit/decorators.js";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFCard from "@patternfly/patternfly/components/Card/card.css";
import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css";
import PFStack from "@patternfly/patternfly/layouts/Stack/stack.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import { SyncStatus } from "@goauthentik/api";
@customElement("ak-sync-status-card")
export class SyncStatusCard extends AKElement {
@state()
syncState?: SyncStatus;
@state()
loading = false;
@property({ attribute: false })
fetch!: () => Promise<SyncStatus>;
static get styles(): CSSResult[] {
return [PFBase, PFButton, PFCard, PFDescriptionList, PFStack];
}
firstUpdated() {
this.loading = true;
this.fetch().then((status) => {
this.syncState = status;
this.loading = false;
});
}
renderSyncStatus(): TemplateResult {
if (this.loading) {
return html`<ak-empty-state loading></ak-empty-state>`;
}
return html`
<dl class="pf-c-description-list">
<div class="pf-c-description-list__group">
<dt class="pf-c-description-list__term">
<span class="pf-c-description-list__text">${msg("Current status")}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">
${this.syncState?.isRunning
? html`${msg("Sync is currently running.")}`
: html`${msg("Sync is not currently running.")}`}
</div>
</dd>
</div>
<div class="pf-c-description-list__group">
<dt class="pf-c-description-list__term">
<span class="pf-c-description-list__text"
>${msg("Last successful sync")}</span
>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">
${this.syncState?.lastSuccessfulSync
? html`${formatElapsedTime(this.syncState?.lastSuccessfulSync)}`
: html`${msg("No successful sync found.")}`}
</div>
</dd>
</div>
<div class="pf-c-description-list__group">
<dt class="pf-c-description-list__term">
<span class="pf-c-description-list__text">${msg("Last sync status")}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">
<ak-task-status
.status=${this.syncState?.lastSyncStatus}
></ak-task-status>
</div>
</dd>
</div>
</dl>
`;
}
render(): TemplateResult {
return html`<div class="pf-c-card">
<div class="pf-c-card__header">
<div class="pf-c-card__actions">
<button
class="pf-c-button pf-m-plain"
type="button"
@click=${() => {
this.fetch().then((status) => {
this.syncState = status;
});
}}
>
<i class="fa fa-sync"></i>
</button>
</div>
<div class="pf-c-card__title">${msg("Sync status")}</div>
</div>
<div class="pf-c-card__body">${this.renderSyncStatus()}</div>
</div>`;
}
}
declare global {
interface HTMLElementTagNameMap {
"ak-sync-status-card": SyncStatusCard;
}
}

View File

@ -1,6 +1,4 @@
import { formatElapsedTime } from "#common/temporal";
import "@goauthentik/admin/system-tasks/ScheduleForm";
import "@goauthentik/admin/system-tasks/TaskList";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { EVENT_REFRESH } from "@goauthentik/common/constants";
import "@goauthentik/elements/buttons/ActionButton";
@ -9,6 +7,8 @@ import "@goauthentik/elements/forms/DeleteBulkForm";
import "@goauthentik/elements/forms/ModalForm";
import { PaginatedResponse, Table } from "@goauthentik/elements/table/Table";
import { TableColumn } from "@goauthentik/elements/table/Table";
import "@goauthentik/elements/tasks/ScheduleForm";
import "@goauthentik/elements/tasks/TaskList";
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
import { msg } from "@lit/localize";

View File

@ -10,6 +10,7 @@ import "@goauthentik/elements/forms/DeleteBulkForm";
import "@goauthentik/elements/forms/ModalForm";
import { PaginatedResponse, Table } from "@goauthentik/elements/table/Table";
import { TableColumn } from "@goauthentik/elements/table/Table";
import "@goauthentik/elements/tasks/TaskStatus";
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
import { msg } from "@lit/localize";
@ -147,6 +148,7 @@ export class TaskList extends Table<Task> {
}
taskState(task: Task): TemplateResult {
return;
switch (task.aggregatedStatus) {
case TasksTasksListAggregatedStatusEnum.Queued:
return html`<ak-label color=${PFColor.Grey}>${msg("Waiting to run")}</ak-label>`;
@ -172,7 +174,7 @@ export class TaskList extends Table<Task> {
html`${item.queueName}`,
html`<div>${formatElapsedTime(item.mtime || new Date())}</div>
<small>${item.mtime.toLocaleString()}</small>`,
this.taskState(item),
html`<ak-task-status .status=${item.aggregatedStatus}></ak-task-status>`,
[TasksTasksListStateEnum.Rejected, TasksTasksListStateEnum.Done].includes(item.state)
? html`<ak-action-button
class="pf-m-plain"

View File

@ -0,0 +1,54 @@
import { AKElement } from "@goauthentik/elements/Base";
import { PFColor } from "@goauthentik/elements/Label";
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
import { msg } from "@lit/localize";
import { CSSResult, TemplateResult, html } from "lit";
import { customElement, property } from "lit/decorators.js";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import { TaskAggregatedStatusEnum, TasksTasksListAggregatedStatusEnum } from "@goauthentik/api";
@customElement("ak-task-status")
export class TaskStatus extends AKElement {
@property()
status?: TaskAggregatedStatusEnum | TasksTasksListAggregatedStatusEnum;
static get styles(): CSSResult[] {
return [PFBase, PFButton];
}
render(): TemplateResult {
switch (this.status) {
case TasksTasksListAggregatedStatusEnum.Queued:
case TaskAggregatedStatusEnum.Queued:
return html`<ak-label color=${PFColor.Grey}>${msg("Waiting to run")}</ak-label>`;
case TasksTasksListAggregatedStatusEnum.Consumed:
case TaskAggregatedStatusEnum.Consumed:
return html`<ak-label color=${PFColor.Blue}>${msg("Running")}</ak-label>`;
case TasksTasksListAggregatedStatusEnum.Done:
case TaskAggregatedStatusEnum.Done:
case TasksTasksListAggregatedStatusEnum.Info:
case TaskAggregatedStatusEnum.Info:
return html`<ak-label color=${PFColor.Green}>${msg("Successful")}</ak-label>`;
case TasksTasksListAggregatedStatusEnum.Warning:
case TaskAggregatedStatusEnum.Warning:
return html`<ak-label color=${PFColor.Orange}>${msg("Warning")}</ak-label>`;
case TasksTasksListAggregatedStatusEnum.Rejected:
case TaskAggregatedStatusEnum.Rejected:
case TasksTasksListAggregatedStatusEnum.Error:
case TaskAggregatedStatusEnum.Error:
return html`<ak-label color=${PFColor.Red}>${msg("Error")}</ak-label>`;
default:
return html`<ak-label color=${PFColor.Grey}>${msg("Unknown")}</ak-label>`;
}
}
}
declare global {
interface HTMLElementTagNameMap {
"ak-task-status": TaskStatus;
}
}