
* remove @goauthentik/authentik as TS path Signed-off-by: Jens Langhammer <jens@goauthentik.io> * initial implementation Signed-off-by: Jens Langhammer <jens@goauthentik.io> * oh yeah Signed-off-by: Jens Langhammer <jens@goauthentik.io> * format earlier changes Signed-off-by: Jens Langhammer <jens@goauthentik.io> * support plain alert Signed-off-by: Jens Langhammer <jens@goauthentik.io> * initial attempt at dedupe Signed-off-by: Jens Langhammer <jens@goauthentik.io> * make it a base class Signed-off-by: Jens Langhammer <jens@goauthentik.io> * migrate all wizards Signed-off-by: Jens Langhammer <jens@goauthentik.io> * create type create mixin to dedupe more, add icon to source create Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add ldap icon Signed-off-by: Jens Langhammer <jens@goauthentik.io> * Optimised images with calibre/image-actions * match inverting we should probably replace all icons with coloured ones so we don't need to invert them...I guess Signed-off-by: Jens Langhammer <jens@goauthentik.io> * format Signed-off-by: Jens Langhammer <jens@goauthentik.io> * make everything more explicit Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add icons to provider Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add remaining provider icons Signed-off-by: Jens Langhammer <jens@goauthentik.io> * rework to not use inheritance Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix unrelated typo Signed-off-by: Jens Langhammer <jens@goauthentik.io> * make app wizard use grid layout Signed-off-by: Jens Langhammer <jens@goauthentik.io> * keep wizard height consistent Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix tests Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io> Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
120 lines
4.2 KiB
TypeScript
120 lines
4.2 KiB
TypeScript
import { EVENT_REFRESH } from "@goauthentik/common/constants";
|
|
import { getRelativeTime } from "@goauthentik/common/utils";
|
|
import "@goauthentik/components/ak-status-label";
|
|
import { AKElement } from "@goauthentik/elements/Base";
|
|
import "@goauthentik/elements/EmptyState";
|
|
import "@goauthentik/elements/events/LogViewer";
|
|
|
|
import { msg, str } from "@lit/localize";
|
|
import { CSSResult, TemplateResult, html, nothing } from "lit";
|
|
import { customElement, property, state } from "lit/decorators.js";
|
|
|
|
import PFCard from "@patternfly/patternfly/components/Card/card.css";
|
|
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
|
|
|
import { SyncStatus, SystemTask, SystemTaskStatusEnum } 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>;
|
|
|
|
@property({ attribute: false })
|
|
triggerSync!: () => Promise<unknown>;
|
|
|
|
static get styles(): CSSResult[] {
|
|
return [PFBase, PFCard];
|
|
}
|
|
|
|
firstUpdated() {
|
|
this.loading = true;
|
|
this.fetch().then((status) => {
|
|
this.syncState = status;
|
|
this.loading = false;
|
|
});
|
|
}
|
|
|
|
renderSyncTask(task: SystemTask): TemplateResult {
|
|
return html`<li>
|
|
${(this.syncState?.tasks || []).length > 1 ? html`<span>${task.name}</span>` : nothing}
|
|
<span
|
|
><ak-status-label
|
|
?good=${task.status === SystemTaskStatusEnum.Successful}
|
|
good-label=${msg("Finished successfully")}
|
|
bad-label=${msg("Finished with errors")}
|
|
></ak-status-label
|
|
></span>
|
|
<span
|
|
>${msg(
|
|
str`Finished ${getRelativeTime(task.finishTimestamp)} (${task.finishTimestamp.toLocaleString()})`,
|
|
)}</span
|
|
>
|
|
<ak-log-viewer .logs=${task?.messages}></ak-log-viewer>
|
|
</li> `;
|
|
}
|
|
|
|
renderSyncStatus(): TemplateResult {
|
|
if (this.loading) {
|
|
return html`<ak-empty-state ?loading=${true}></ak-empty-state>`;
|
|
}
|
|
if (!this.syncState) {
|
|
return html`${msg("No sync status.")}`;
|
|
}
|
|
if (this.syncState.isRunning) {
|
|
return html`${msg("Sync currently running.")}`;
|
|
}
|
|
if (this.syncState.tasks.length < 1) {
|
|
return html`${msg("Not synced yet.")}`;
|
|
}
|
|
return html`
|
|
<ul class="pf-c-list">
|
|
${this.syncState.tasks.map((task) => {
|
|
return this.renderSyncTask(task);
|
|
})}
|
|
</ul>
|
|
`;
|
|
}
|
|
|
|
render(): TemplateResult {
|
|
return html`<div class="pf-c-card">
|
|
<div class="pf-c-card__title">${msg("Sync status")}</div>
|
|
<div class="pf-c-card__body">${this.renderSyncStatus()}</div>
|
|
<div class="pf-c-card__footer">
|
|
<ak-action-button
|
|
class="pf-m-secondary"
|
|
?disabled=${this.syncState?.isRunning}
|
|
.apiRequest=${() => {
|
|
if (this.syncState) {
|
|
// This is a bit of a UX cheat, we set isRunning to true to disable the button
|
|
// and change the text even before we hear back from the backend
|
|
this.syncState = {
|
|
...this.syncState,
|
|
isRunning: true,
|
|
};
|
|
}
|
|
this.triggerSync().then(() => {
|
|
this.dispatchEvent(
|
|
new CustomEvent(EVENT_REFRESH, {
|
|
bubbles: true,
|
|
composed: true,
|
|
}),
|
|
);
|
|
this.firstUpdated();
|
|
});
|
|
}}
|
|
>
|
|
${this.syncState?.isRunning
|
|
? msg("Sync currently running")
|
|
: msg("Run sync again")}
|
|
</ak-action-button>
|
|
</div>
|
|
</div>`;
|
|
}
|
|
}
|