add more tasks in ui

Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
This commit is contained in:
Marc 'risson' Schmitt
2025-06-24 15:38:30 +02:00
parent 2433ed1c9b
commit 031456629b
10 changed files with 136 additions and 191 deletions

View File

@ -55,5 +55,4 @@ class GoogleWorkspaceProviderViewSet(OutgoingSyncProviderStatusMixin, UsedByMixi
]
search_fields = ["name"]
ordering = ["name"]
sync_task = google_workspace_sync
sync_objects_task = google_workspace_sync_objects

View File

@ -53,5 +53,4 @@ class MicrosoftEntraProviderViewSet(OutgoingSyncProviderStatusMixin, UsedByMixin
]
search_fields = ["name"]
ordering = ["name"]
sync_task = microsoft_entra_sync
sync_objects_task = microsoft_entra_sync_objects

View File

@ -11,6 +11,7 @@ from authentik.events.logs import LogEvent, LogEventSerializer
from authentik.lib.sync.outgoing.models import OutgoingSyncProvider
from authentik.lib.utils.reflection import class_to_path
from authentik.rbac.filters import ObjectFilter
from authentik.tasks.models import Task
class SyncStatusSerializer(PassiveSerializer):
@ -41,27 +42,8 @@ class SyncObjectResultSerializer(PassiveSerializer):
class OutgoingSyncProviderStatusMixin:
"""Common API Endpoints for Outgoing sync providers"""
sync_task: type[Actor] = None
sync_objects_task: type[Actor] = None
@extend_schema(responses={200: SyncStatusSerializer()})
@action(
methods=["GET"],
detail=True,
pagination_class=None,
url_path="sync/status",
filter_backends=[ObjectFilter],
)
def sync_status(self, request: Request, pk: int) -> Response:
"""Get provider's sync status"""
provider: OutgoingSyncProvider = self.get_object()
with provider.sync_lock as lock_acquired:
status = {
# If we could not acquire the lock, it means a task is using it, and thus is running
"is_running": not lock_acquired,
}
return Response(SyncStatusSerializer(status).data)
@extend_schema(
request=SyncObjectSerializer,
responses={200: SyncObjectResultSerializer()},
@ -78,14 +60,20 @@ class OutgoingSyncProviderStatusMixin:
provider: OutgoingSyncProvider = self.get_object()
params = SyncObjectSerializer(data=request.data)
params.is_valid(raise_exception=True)
res: list[LogEvent] = self.sync_objects_task.send(
params.validated_data["sync_object_model"],
page=1,
provider_pk=provider.pk,
pk=params.validated_data["sync_object_id"],
override_dry_run=params.validated_data["override_dry_run"],
).get()
return Response(SyncObjectResultSerializer(instance={"messages": res}).data)
msg = self.sync_objects_task.send_with_options(
args=(params.validated_data["sync_object_model"],),
kwargs={
"page": 1,
"provider_pk": provider.pk,
"pk": params.validated_data["sync_object_id"],
"override_dry_run": params.validated_data["override_dry_run"],
},
rel_obj=provider,
)
msg.get_result(block=True)
task: Task = msg.options["task"]
task.refresh_from_db()
return Response(SyncObjectResultSerializer(instance={"messages": task._messages}).data)
class OutgoingSyncConnectionCreateMixin:

View File

@ -44,5 +44,4 @@ class SCIMProviderViewSet(OutgoingSyncProviderStatusMixin, UsedByMixin, ModelVie
filterset_fields = ["name", "exclude_users_service_account", "url", "filter_group"]
search_fields = ["name", "url"]
ordering = ["name", "url"]
sync_task = scim_sync
sync_objects_task = scim_sync_objects

View File

@ -45,7 +45,7 @@ def kerberos_sync(pk: str):
"Failed to acquire lock for Kerberos sync, skipping task", source=source.slug
)
return
syncer = KerberosSync(source)
syncer = KerberosSync(source, self)
syncer.sync()
except StopSync as exc:
LOGGER.warning(exception_to_string(exc))

View File

@ -2,6 +2,8 @@ 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";
@ -10,7 +12,6 @@ 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 { msg } from "@lit/localize";
import { CSSResult, PropertyValues, TemplateResult, html } from "lit";
@ -30,9 +31,9 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
import {
GoogleWorkspaceProvider,
ModelEnum,
ProvidersApi,
RbacPermissionsAssignedByUsersListModelEnum,
SyncStatus,
} from "@goauthentik/api";
@customElement("ak-provider-google-workspace-view")
@ -43,9 +44,6 @@ export class GoogleWorkspaceProviderViewPage extends AKElement {
@state()
provider?: GoogleWorkspaceProvider;
@state()
syncState?: SyncStatus;
static get styles(): CSSResult[] {
return [
PFBase,
@ -87,22 +85,7 @@ export class GoogleWorkspaceProviderViewPage extends AKElement {
return html``;
}
return html` <ak-tabs>
<section
slot="page-overview"
data-tab-title="${msg("Overview")}"
@activate=${() => {
new ProvidersApi(DEFAULT_CONFIG)
.providersGoogleWorkspaceSyncStatusRetrieve({
id: this.provider?.pk || 0,
})
.then((state) => {
this.syncState = state;
})
.catch(() => {
this.syncState = undefined;
});
}}
>
<section slot="page-overview" data-tab-title="${msg("Overview")}">
${this.renderTabOverview()}
</section>
<section
@ -155,6 +138,8 @@ export class GoogleWorkspaceProviderViewPage extends AKElement {
if (!this.provider) {
return html``;
}
const [appLabel, modelName] =
ModelEnum.AuthentikProvidersGoogleWorkspaceGoogleworkspaceprovider.split(".");
return html`${!this.provider?.assignedBackchannelApplicationName
? html`<div slot="header" class="pf-c-banner pf-m-warning">
${msg(
@ -211,23 +196,32 @@ export class GoogleWorkspaceProviderViewPage extends AKElement {
</div>
</div>
<div class="pf-l-grid__item pf-m-12-col pf-l-stack__item">
<ak-sync-status-card
.fetch=${() => {
return new ProvidersApi(
DEFAULT_CONFIG,
).providersGoogleWorkspaceSyncStatusRetrieve({
id: this.provider?.pk || 0,
});
}}
.triggerSync=${() => {
return new ProvidersApi(
DEFAULT_CONFIG,
).providersGoogleWorkspacePartialUpdate({
id: this.provider?.pk || 0,
patchedGoogleWorkspaceProviderRequest: {},
});
}}
></ak-sync-status-card>
<div class="pf-c-card">
<div class="pf-c-card__header">
<div class="pf-c-card__title">${msg("Schedules")}</div>
</div>
<div class="pf-c-card__body">
<ak-schedule-list
.relObjAppLabel=${appLabel}
.relObjModel=${modelName}
.relObjId="${this.provider.pk}"
></ak-schedule-list>
</div>
</div>
</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">
<div class="pf-c-card__title">${msg("Tasks")}</div>
</div>
<div class="pf-c-card__body">
<ak-task-list
.relObjAppLabel=${appLabel}
.relObjModel=${modelName}
.relObjId="${this.provider.pk}"
></ak-task-list>
</div>
</div>
</div>
</div>`;
}

View File

@ -2,6 +2,8 @@ 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";
@ -29,9 +31,9 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
import {
MicrosoftEntraProvider,
ModelEnum,
ProvidersApi,
RbacPermissionsAssignedByUsersListModelEnum,
SyncStatus,
} from "@goauthentik/api";
@customElement("ak-provider-microsoft-entra-view")
@ -42,9 +44,6 @@ export class MicrosoftEntraProviderViewPage extends AKElement {
@state()
provider?: MicrosoftEntraProvider;
@state()
syncState?: SyncStatus;
static get styles(): CSSResult[] {
return [
PFBase,
@ -86,22 +85,7 @@ export class MicrosoftEntraProviderViewPage extends AKElement {
return html``;
}
return html` <ak-tabs>
<section
slot="page-overview"
data-tab-title="${msg("Overview")}"
@activate=${() => {
new ProvidersApi(DEFAULT_CONFIG)
.providersMicrosoftEntraSyncStatusRetrieve({
id: this.provider?.pk || 0,
})
.then((state) => {
this.syncState = state;
})
.catch(() => {
this.syncState = undefined;
});
}}
>
<section slot="page-overview" data-tab-title="${msg("Overview")}">
${this.renderTabOverview()}
</section>
<section
@ -154,6 +138,8 @@ export class MicrosoftEntraProviderViewPage extends AKElement {
if (!this.provider) {
return html``;
}
const [appLabel, modelName] =
ModelEnum.AuthentikProvidersMicrosoftEntraMicrosoftentraprovider.split(".");
return html`${!this.provider?.assignedBackchannelApplicationName
? html`<div slot="header" class="pf-c-banner pf-m-warning">
${msg(
@ -211,23 +197,32 @@ export class MicrosoftEntraProviderViewPage extends AKElement {
</div>
<div class="pf-l-grid__item pf-m-12-col pf-l-stack__item">
<ak-sync-status-card
.fetch=${() => {
return new ProvidersApi(
DEFAULT_CONFIG,
).providersMicrosoftEntraSyncStatusRetrieve({
id: this.provider?.pk || 0,
});
}}
.triggerSync=${() => {
return new ProvidersApi(
DEFAULT_CONFIG,
).providersMicrosoftEntraPartialUpdate({
id: this.provider?.pk || 0,
patchedMicrosoftEntraProviderRequest: {},
});
}}
></ak-sync-status-card>
<div class="pf-c-card">
<div class="pf-c-card__header">
<div class="pf-c-card__title">${msg("Schedules")}</div>
</div>
<div class="pf-c-card__body">
<ak-schedule-list
.relObjAppLabel=${appLabel}
.relObjModel=${modelName}
.relObjId="${this.provider.pk}"
></ak-schedule-list>
</div>
</div>
</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">
<div class="pf-c-card__title">${msg("Tasks")}</div>
</div>
<div class="pf-c-card__body">
<ak-task-list
.relObjAppLabel=${appLabel}
.relObjModel=${modelName}
.relObjId="${this.provider.pk}"
></ak-task-list>
</div>
</div>
</div>
</div>`;
}

View File

@ -3,6 +3,8 @@ 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";
@ -12,7 +14,6 @@ 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 MDSCIMProvider from "~docs/add-secure-apps/providers/scim/index.md";
import { msg } from "@lit/localize";
@ -33,6 +34,7 @@ import PFStack from "@patternfly/patternfly/layouts/Stack/stack.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import {
ModelEnum,
ProvidersApi,
RbacPermissionsAssignedByUsersListModelEnum,
SCIMProvider,
@ -141,6 +143,7 @@ export class SCIMProviderViewPage extends AKElement {
if (!this.provider) {
return html``;
}
const [appLabel, modelName] = ModelEnum.AuthentikProvidersScimScimprovider.split(".");
return html` ${!this.provider?.assignedBackchannelApplicationName
? html`<div slot="header" class="pf-c-banner pf-m-warning">
${msg(
@ -224,21 +227,32 @@ export class SCIMProviderViewPage extends AKElement {
</div>
</div>
<div class="pf-l-grid__item pf-m-12-col pf-l-stack__item">
<ak-sync-status-card
.fetch=${() => {
return new ProvidersApi(
DEFAULT_CONFIG,
).providersScimSyncStatusRetrieve({
id: this.provider?.pk || 0,
});
}}
.triggerSync=${() => {
return new ProvidersApi(DEFAULT_CONFIG).providersScimPartialUpdate({
id: this.provider?.pk || 0,
patchedSCIMProviderRequest: {},
});
}}
></ak-sync-status-card>
<div class="pf-c-card">
<div class="pf-c-card__header">
<div class="pf-c-card__title">${msg("Schedules")}</div>
</div>
<div class="pf-c-card__body">
<ak-schedule-list
.relObjAppLabel=${appLabel}
.relObjModel=${modelName}
.relObjId="${this.provider.pk}"
></ak-schedule-list>
</div>
</div>
</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">
<div class="pf-c-card__title">${msg("Tasks")}</div>
</div>
<div class="pf-c-card__body">
<ak-task-list
.relObjAppLabel=${appLabel}
.relObjModel=${modelName}
.relObjId="${this.provider.pk}"
></ak-task-list>
</div>
</div>
</div>
</div>
<div class="pf-c-card pf-l-grid__item pf-m-5-col">

View File

@ -11,7 +11,6 @@ import "@goauthentik/elements/ak-mdx";
import "@goauthentik/elements/buttons/ActionButton";
import "@goauthentik/elements/buttons/SpinnerButton";
import "@goauthentik/elements/forms/ModalForm";
import "@goauthentik/elements/sync/SyncStatusCard";
import MDSourceKerberosBrowser from "~docs/users-sources/sources/protocols/kerberos/browser.md";
import { msg } from "@lit/localize";
@ -30,9 +29,9 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
import {
KerberosSource,
ModelEnum,
RbacPermissionsAssignedByUsersListModelEnum,
SourcesApi,
SyncStatus,
} from "@goauthentik/api";
@customElement("ak-source-kerberos-view")
@ -51,9 +50,6 @@ export class KerberosSourceViewPage extends AKElement {
@property({ attribute: false })
source!: KerberosSource;
@state()
syncState?: SyncStatus;
static get styles(): CSSResult[] {
return [
PFBase,
@ -76,53 +72,11 @@ export class KerberosSourceViewPage extends AKElement {
});
}
load(): void {
new SourcesApi(DEFAULT_CONFIG)
.sourcesKerberosSyncStatusRetrieve({
slug: this.source.slug,
})
.then((state) => {
this.syncState = state;
});
}
renderSyncCards(): TemplateResult {
if (!this.source.syncUsers) {
return html``;
}
return html`
<div class="pf-c-card pf-l-grid__item pf-m-2-col">
<div class="pf-c-card__title">
<p>${msg("Connectivity")}</p>
</div>
<div class="pf-c-card__body">
<ak-source-kerberos-connectivity
.connectivity=${this.source.connectivity}
></ak-source-kerberos-connectivity>
</div>
</div>
<div class="pf-l-grid__item pf-m-10-col">
<ak-sync-status-card
.fetch=${() => {
return new SourcesApi(DEFAULT_CONFIG).sourcesKerberosSyncStatusRetrieve({
slug: this.source?.slug,
});
}}
.triggerSync=${() => {
return new SourcesApi(DEFAULT_CONFIG).sourcesKerberosPartialUpdate({
slug: this.source?.slug || "",
patchedKerberosSourceRequest: {},
});
}}
></ak-sync-status-card>
</div>
`;
}
render(): TemplateResult {
if (!this.source) {
return html``;
}
const [appLabel, modelName] = ModelEnum.AuthentikSourcesKerberosKerberossource.split(".");
return html`<ak-tabs>
<section
slot="page-overview"
@ -139,7 +93,7 @@ export class KerberosSourceViewPage extends AKElement {
>
</div>
<div class="pf-l-grid pf-m-gutter">
<div class="pf-c-card pf-l-grid__item pf-m-12-col">
<div class="pf-c-card pf-l-grid__item pf-m-4-col">
<div class="pf-c-card__body">
<dl class="pf-c-description-list pf-m-2-col-on-lg">
<div class="pf-c-description-list__group">
@ -183,7 +137,28 @@ export class KerberosSourceViewPage extends AKElement {
</ak-forms-modal>
</div>
</div>
${this.renderSyncCards()}
<div class="pf-c-card pf-l-grid__item pf-m-8-col">
<div class="pf-c-card__title">
<p>${msg("Connectivity")}</p>
</div>
<div class="pf-c-card__body">
<ak-source-kerberos-connectivity
.connectivity=${this.source.connectivity}
></ak-source-kerberos-connectivity>
</div>
</div>
<div class="pf-c-card pf-l-grid__item pf-m-12-col">
<div class="pf-c-card__title">
<p>${msg("Schedules")}</p>
</div>
<div class="pf-c-card__body">
<ak-schedule-list
.relObjAppLabel=${appLabel}
.relObjModel=${modelName}
.relObjId="${this.source.pk}"
></ak-schedule-list>
</div>
</div>
<div class="pf-c-card pf-l-grid__item pf-m-12-col">
<div class="pf-c-card__body">
<ak-mdx .url=${MDSourceKerberosBrowser}></ak-mdx>

View File

@ -11,11 +11,10 @@ import "@goauthentik/elements/Tabs";
import "@goauthentik/elements/buttons/ActionButton";
import "@goauthentik/elements/buttons/SpinnerButton";
import "@goauthentik/elements/forms/ModalForm";
import "@goauthentik/elements/sync/SyncStatusCard";
import { msg } from "@lit/localize";
import { CSSResult, TemplateResult, html } from "lit";
import { customElement, property, state } from "lit/decorators.js";
import { customElement, property } from "lit/decorators.js";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFCard from "@patternfly/patternfly/components/Card/card.css";
@ -31,7 +30,6 @@ import {
ModelEnum,
RbacPermissionsAssignedByUsersListModelEnum,
SourcesApi,
SyncStatus,
} from "@goauthentik/api";
@customElement("ak-source-ldap-view")
@ -50,9 +48,6 @@ export class LDAPSourceViewPage extends AKElement {
@property({ attribute: false })
source!: LDAPSource;
@state()
syncState?: SyncStatus;
static get styles(): CSSResult[] {
return [PFBase, PFPage, PFButton, PFGrid, PFContent, PFCard, PFDescriptionList, PFList];
}
@ -65,16 +60,6 @@ export class LDAPSourceViewPage extends AKElement {
});
}
load(): void {
new SourcesApi(DEFAULT_CONFIG)
.sourcesLdapSyncStatusRetrieve({
slug: this.source.slug,
})
.then((state) => {
this.syncState = state;
});
}
render(): TemplateResult {
if (!this.source) {
return html``;
@ -85,9 +70,6 @@ export class LDAPSourceViewPage extends AKElement {
slot="page-overview"
data-tab-title="${msg("Overview")}"
class="pf-c-page__main-section pf-m-no-padding-mobile"
@activate=${() => {
this.load();
}}
>
<div class="pf-l-grid pf-m-gutter">
<div class="pf-c-card pf-l-grid__item pf-m-4-col">