web: use generated API Client (#616)

* api: fix types for config API

* api: remove broken swagger UI

* admin: re-fix system task enum

* events: make event optional

* events: fix Schema for notification transport test

* flows: use APIView for Flow Executor

* core: fix schema for Metrics APIs

* web: rewrite to use generated API client

* web: generate API Client in CI

* admin: use x_cord and y_cord to prevent yaml issues

* events: fix linting errors

* web: don't lint generated code

* core: fix fields not being required in TypeSerializer

* flows: fix missing permission_classes

* web: cleanup

* web: fix rendering of graph on Overview page

* web: cleanup imports

* core: fix missing background image filter

* flows: fix flows not advancing properly

* stages/*: fix warnings during get_challenge

* web: send Flow response as JSON instead of FormData

* web: fix styles for horizontal tabs

* web: add base chart class and custom chart for application view

* root: generate ts client for e2e tests

* web: don't attempt to connect to websocket in selenium tests

* web: fix UserTokenList not being included in the build

* web: fix styling for static token list

* web: fix CSRF Token missing

* stages/authenticator_static: fix error when disable static tokens

* core: fix display issue when updating user info

* web: fix Flow executor not showing spinner when redirecting
This commit is contained in:
Jens L
2021-03-08 11:14:00 +01:00
committed by GitHub
parent 1c6d498621
commit 2852fa3c5e
146 changed files with 1593 additions and 1882 deletions

View File

@ -1,8 +1,9 @@
import { gettext } from "django";
import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
import { ifDefined } from "lit-html/directives/if-defined";
import { Application } from "../api/Applications";
import { Application, CoreApi } from "../api";
import { AKResponse } from "../api/Client";
import { DEFAULT_CONFIG } from "../api/Config";
import { COMMON_STYLES } from "../common/styles";
import { loading, truncate } from "../utils";
@ -31,19 +32,19 @@ export class LibraryApplication extends LitElement {
if (!this.application) {
return html`<ak-spinner></ak-spinner>`;
}
return html` <a href="${this.application.launch_url}" class="pf-c-card pf-m-hoverable pf-m-compact">
return html` <a href="${ifDefined(this.application.launchUrl)}" class="pf-c-card pf-m-hoverable pf-m-compact">
<div class="pf-c-card__header">
${this.application.meta_icon
? html`<img class="app-icon pf-c-avatar" src="${ifDefined(this.application.meta_icon)}" alt="Application Icon"/>`
${this.application.metaIcon
? html`<img class="app-icon pf-c-avatar" src="${ifDefined(this.application.metaIcon)}" alt="Application Icon"/>`
: html`<i class="pf-icon pf-icon-arrow"></i>`}
</div>
<div class="pf-c-card__title">
<p id="card-1-check-label">${this.application.name}</p>
<div class="pf-c-content">
<small>${this.application.meta_publisher}</small>
<small>${this.application.metaPublisher}</small>
</div>
</div>
<div class="pf-c-card__body">${truncate(this.application.meta_description, 35)}</div>
<div class="pf-c-card__body">${truncate(this.application.metaDescription, 35)}</div>
</a>`;
}
@ -64,7 +65,9 @@ export class LibraryPage extends LitElement {
}
firstUpdated(): void {
Application.list().then((r) => (this.apps = r));
new CoreApi(DEFAULT_CONFIG).coreApplicationsList({}).then((apps) => {
this.apps = apps;
});
}
renderEmptyState(): TemplateResult {

View File

@ -2,7 +2,7 @@ import { gettext } from "django";
import { CSSResult, customElement, html, LitElement, TemplateResult } from "lit-element";
import { COMMON_STYLES } from "../../common/styles";
import "../../elements/AdminLoginsChart";
import "../../elements/charts/AdminLoginsChart";
import "../../elements/cards/AggregatePromiseCard";
import "./TopApplicationsTable";
import "./cards/AdminStatusCard";
@ -30,7 +30,7 @@ export class AdminOverviewPage extends LitElement {
<section class="pf-c-page__main-section">
<div class="pf-l-gallery pf-m-gutter">
<ak-aggregate-card class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-server" header="Logins over the last 24 hours" style="grid-column-end: span 3;grid-row-end: span 2;">
<ak-admin-logins-chart .url="${["admin", "metrics"]}"></ak-admin-logins-chart>
<ak-charts-admin-login></ak-charts-admin-login>
</ak-aggregate-card>
<ak-aggregate-card class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-server" header="Apps with most usage" style="grid-column-end: span 2;grid-row-end: span 3;">
<ak-top-applications-table></ak-top-applications-table>

View File

@ -1,34 +1,39 @@
import { gettext } from "django";
import { CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
import { Event, TopNEvent } from "../../api/Events";
import { COMMON_STYLES } from "../../common/styles";
import { EventsApi, EventTopPerUser } from "../../api";
import "../../elements/Spinner";
import { DEFAULT_CONFIG } from "../../api/Config";
@customElement("ak-top-applications-table")
export class TopApplicationsTable extends LitElement {
@property({attribute: false})
topN?: TopNEvent[];
topN?: EventTopPerUser[];
static get styles(): CSSResult[] {
return COMMON_STYLES;
}
firstUpdated(): void {
Event.topForUser("authorize_application").then(events => this.topN = events);
new EventsApi(DEFAULT_CONFIG).eventsEventsTopPerUser({
action: "authorize_application",
}).then((events) => {
this.topN = events;
});
}
renderRow(event: TopNEvent): TemplateResult {
renderRow(event: EventTopPerUser): TemplateResult {
return html`<tr role="row">
<td role="cell">
${event.application.name}
</td>
<td role="cell">
${event.counted_events}
${event.countedEvents}
</td>
<td role="cell">
<progress value="${event.counted_events}" max="${this.topN ? this.topN[0].counted_events : 0}"></progress>
<progress value="${event.countedEvents}" max="${this.topN ? this.topN[0].countedEvents : 0}"></progress>
</td>
</tr>`;
}

View File

@ -23,14 +23,14 @@ export abstract class AdminStatusCard<T> extends AggregateCard {
renderInner(): TemplateResult {
return html`<p class="center-value">
${until(this.getPrimaryValue().then((v) => {
this.value = v;
return this.getStatus(v);
}).then((status) => {
return html`<p class="ak-aggregate-card">
<i class="${status.icon}"></i> ${this.renderValue()}
</p>
${status.message ? html`<p class="subtext">${status.message}</p>` : html``}`;
}), html`<ak-spinner size="${SpinnerSize.Large}"></ak-spinner>`)}
this.value = v;
return this.getStatus(v);
}).then((status) => {
return html`<p class="ak-aggregate-card">
<i class="${status.icon}"></i> ${this.renderValue()}
</p>
${status.message ? html`<p class="subtext">${status.message}</p>` : html``}`;
}), html`<ak-spinner size="${SpinnerSize.Large}"></ak-spinner>`)}
</p>`;
}
}

View File

@ -1,14 +1,17 @@
import { gettext } from "django";
import { customElement, html, TemplateResult } from "lit-element";
import { Flow } from "../../../api/Flows";
import { AdminStatus, AdminStatusCard } from "./AdminStatusCard";
import "../../../elements/buttons/ModalButton";
import { FlowsApi } from "../../../api";
import { DEFAULT_CONFIG } from "../../../api/Config";
@customElement("ak-admin-status-card-flow-cache")
export class FlowCacheStatusCard extends AdminStatusCard<number> {
getPrimaryValue(): Promise<number> {
return Flow.cached();
return new FlowsApi(DEFAULT_CONFIG).flowsInstancesCached({}).then((value) => {
return value.count || 0;
});
}
getStatus(value: number): Promise<AdminStatus> {

View File

@ -1,15 +1,18 @@
import { gettext } from "django";
import { customElement } from "lit-element";
import { TemplateResult, html } from "lit-html";
import { Policy } from "../../../api/Policies";
import { AdminStatusCard, AdminStatus } from "./AdminStatusCard";
import "../../../elements/buttons/ModalButton";
import { PoliciesApi } from "../../../api";
import { DEFAULT_CONFIG } from "../../../api/Config";
@customElement("ak-admin-status-card-policy-cache")
export class PolicyCacheStatusCard extends AdminStatusCard<number> {
getPrimaryValue(): Promise<number> {
return Policy.cached();
return new PoliciesApi(DEFAULT_CONFIG).policiesAllCached({}).then((value) => {
return value.count || 0;
});
}
getStatus(value: number): Promise<AdminStatus> {

View File

@ -1,17 +1,18 @@
import { gettext } from "django";
import { customElement } from "lit-element";
import { Policy } from "../../../api/Policies";
import { PoliciesApi } from "../../../api";
import { DEFAULT_CONFIG } from "../../../api/Config";
import { AdminStatusCard, AdminStatus } from "./AdminStatusCard";
@customElement("ak-admin-status-card-policy-unbound")
export class PolicyUnboundStatusCard extends AdminStatusCard<number> {
getPrimaryValue(): Promise<number> {
return Policy.list({
"bindings__isnull": true,
"promptstage__isnull": true,
}).then((response) => {
return response.pagination.count;
return new PoliciesApi(DEFAULT_CONFIG).policiesAllList({
bindingsIsnull: "true",
promptstageIsnull: "true",
}).then((value) => {
return value.pagination.count;
});
}

View File

@ -1,16 +1,17 @@
import { gettext } from "django";
import { customElement } from "lit-element";
import { Provider } from "../../../api/Providers";
import { ProvidersApi } from "../../../api";
import { DEFAULT_CONFIG } from "../../../api/Config";
import { AdminStatusCard, AdminStatus } from "./AdminStatusCard";
@customElement("ak-admin-status-card-provider")
export class ProviderStatusCard extends AdminStatusCard<number> {
getPrimaryValue(): Promise<number> {
return Provider.list({
"application__isnull": true
}).then((response) => {
return response.pagination.count;
return new ProvidersApi(DEFAULT_CONFIG).providersAllList({
applicationIsnull: "true"
}).then((value) => {
return value.pagination.count;
});
}

View File

@ -1,12 +1,17 @@
import { customElement } from "lit-element";
import { User } from "../../../api/Users";
import { CoreApi } from "../../../api";
import { DEFAULT_CONFIG } from "../../../api/Config";
import { AdminStatusCard, AdminStatus } from "./AdminStatusCard";
@customElement("ak-admin-status-card-user-count")
export class UserCountStatusCard extends AdminStatusCard<number> {
getPrimaryValue(): Promise<number> {
return User.count();
return new CoreApi(DEFAULT_CONFIG).coreUsersList({
pageSize: 1
}).then((value) => {
return value.pagination.count;
});
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars

View File

@ -1,20 +1,21 @@
import { gettext } from "django";
import { customElement, html, TemplateResult } from "lit-element";
import { Version } from "../../../api/Versions";
import { AdminApi, Version } from "../../../api";
import { DEFAULT_CONFIG } from "../../../api/Config";
import { AdminStatusCard, AdminStatus } from "./AdminStatusCard";
@customElement("ak-admin-status-version")
export class VersionStatusCard extends AdminStatusCard<Version> {
getPrimaryValue(): Promise<Version> {
return Version.get();
return new AdminApi(DEFAULT_CONFIG).adminVersionList({});
}
getStatus(value: Version): Promise<AdminStatus> {
if (value.outdated) {
return Promise.resolve<AdminStatus>({
icon: "fa fa-exclamation-triangle pf-m-warning",
message: gettext(`${value.version_latest} is available!`),
message: gettext(`${value.versionLatest} is available!`),
});
} else {
return Promise.resolve<AdminStatus>({
@ -25,7 +26,7 @@ export class VersionStatusCard extends AdminStatusCard<Version> {
}
renderValue(): TemplateResult {
return html`${this.value?.version_current}`;
return html`${this.value?.versionCurrent}`;
}
}

View File

@ -1,14 +1,15 @@
import { gettext } from "django";
import { customElement } from "lit-element";
import { DefaultClient, AKResponse } from "../../../api/Client";
import { AdminApi } from "../../../api";
import { DEFAULT_CONFIG } from "../../../api/Config";
import { AdminStatus, AdminStatusCard } from "./AdminStatusCard";
@customElement("ak-admin-status-card-workers")
export class WorkersStatusCard extends AdminStatusCard<number> {
getPrimaryValue(): Promise<number> {
return DefaultClient.fetch<AKResponse<number>>(["admin", "workers"]).then((r) => {
return r.pagination.count;
return new AdminApi(DEFAULT_CONFIG).adminWorkersList({}).then((workers) => {
return workers.pagination.count;
});
}

View File

@ -1,6 +1,5 @@
import { gettext } from "django";
import { customElement, html, property, TemplateResult } from "lit-element";
import { Application } from "../../api/Applications";
import { AKResponse } from "../../api/Client";
import { TablePage } from "../../elements/table/TablePage";
@ -8,6 +7,9 @@ import "../../elements/buttons/ModalButton";
import "../../elements/buttons/SpinnerButton";
import { TableColumn } from "../../elements/table/Table";
import { PAGE_SIZE } from "../../constants";
import { Application, CoreApi } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { AdminURLManager } from "../../api/legacy";
@customElement("ak-application-list")
export class ApplicationListPage extends TablePage<Application> {
@ -28,10 +30,10 @@ export class ApplicationListPage extends TablePage<Application> {
order = "name";
apiEndpoint(page: number): Promise<AKResponse<Application>> {
return Application.list({
return new CoreApi(DEFAULT_CONFIG).coreApplicationsList({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
pageSize: PAGE_SIZE,
search: this.search || "",
});
}
@ -49,26 +51,26 @@ export class ApplicationListPage extends TablePage<Application> {
row(item: Application): TemplateResult[] {
return [
item.meta_icon ?
html`<img class="app-icon pf-c-avatar" src="${item.meta_icon}" alt="${gettext("Application Icon")}">` :
item.metaIcon ?
html`<img class="app-icon pf-c-avatar" src="${item.metaIcon}" alt="${gettext("Application Icon")}">` :
html`<i class="pf-icon pf-icon-arrow"></i>`,
html`<a href="#/core/applications/${item.slug}">
<div>
${item.name}
</div>
${item.meta_publisher ? html`<small>${item.meta_publisher}</small>` : html``}
${item.metaPublisher ? html`<small>${item.metaPublisher}</small>` : html``}
</a>`,
html`<code>${item.slug}</code>`,
html`${item.provider?.name}`,
html`${item.provider?.verbose_name}`,
html`${item.provider?.verboseName}`,
html`
<ak-modal-button href="${Application.adminUrl(`${item.pk}/update/`)}">
<ak-modal-button href="${AdminURLManager.applications(`${item.pk}/update/`)}">
<ak-spinner-button slot="trigger" class="pf-m-secondary">
${gettext("Edit")}
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>
<ak-modal-button href="${Application.adminUrl(`${item.pk}/delete/`)}">
<ak-modal-button href="${AdminURLManager.applications(`${item.pk}/delete/`)}">
<ak-spinner-button slot="trigger" class="pf-m-danger">
${gettext("Delete")}
</ak-spinner-button>
@ -80,7 +82,7 @@ export class ApplicationListPage extends TablePage<Application> {
renderToolbar(): TemplateResult {
return html`
<ak-modal-button href=${Application.adminUrl("create/")}>
<ak-modal-button href=${AdminURLManager.applications("create/")}>
<ak-spinner-button slot="trigger" class="pf-m-primary">
${gettext("Create")}
</ak-spinner-button>

View File

@ -1,14 +1,15 @@
import { gettext } from "django";
import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
import { Application } from "../../api/Applications";
import { COMMON_STYLES } from "../../common/styles";
import "../../elements/Tabs";
import "../../elements/AdminLoginsChart";
import "../../elements/charts/ApplicationAuthorizeChart";
import "../../elements/buttons/ModalButton";
import "../../elements/buttons/SpinnerButton";
import "../../elements/policies/BoundPoliciesList";
import "../../elements/utils/LoadingState";
import { Application, CoreApi } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
@customElement("ak-application-view")
export class ApplicationViewPage extends LitElement {
@ -19,11 +20,15 @@ export class ApplicationViewPage extends LitElement {
@property()
set applicationSlug(value: string) {
Application.get(value).then((app) => (this.application = app));
new CoreApi(DEFAULT_CONFIG).coreApplicationsRead({
slug: value
}).then((app) => {
this.application = app;
});
}
@property({attribute: false})
application?: Application;
application!: Application;
static get styles(): CSSResult[] {
return COMMON_STYLES.concat(
@ -52,10 +57,10 @@ export class ApplicationViewPage extends LitElement {
return html`<section class="pf-c-page__main-section pf-m-light">
<div class="pf-c-content">
<h1>
<img class="pf-icon" src="${this.application?.meta_icon || ""}" />
<img class="pf-icon" src="${this.application?.metaIcon || ""}" />
${this.application?.name}
</h1>
<p>${this.application?.meta_publisher}</p>
<p>${this.application?.metaPublisher}</p>
</div>
</section>
<ak-tabs>
@ -69,9 +74,8 @@ export class ApplicationViewPage extends LitElement {
</div>
<div class="pf-c-card__body">
${this.application ? html`
<ak-admin-logins-chart
.url="${["core", "applications", this.application?.slug, "metrics"]}">
</ak-admin-logins-chart>`: ""}
<ak-charts-application-authorize applicationSlug=${this.application.slug}>
</ak-charts-application-authorize>`: ""}
</div>
</div>
<div class="pf-c-card pf-c-card-aggregate pf-l-gallery__item pf-m-2-col">

View File

@ -3,11 +3,14 @@ import { customElement, html, property, TemplateResult } from "lit-element";
import { AKResponse } from "../../api/Client";
import { TablePage } from "../../elements/table/TablePage";
import { CryptoApi, CertificateKeyPair } from "../../api";
import "../../elements/buttons/ModalButton";
import "../../elements/buttons/SpinnerButton";
import { TableColumn } from "../../elements/table/Table";
import { CertificateKeyPair } from "../../api/CertificateKeyPair";
import { PAGE_SIZE } from "../../constants";
import { AdminURLManager } from "../../api/legacy";
import { DEFAULT_CONFIG } from "../../api/Config";
@customElement("ak-crypto-certificatekeypair-list")
export class CertificateKeyPairListPage extends TablePage<CertificateKeyPair> {
@ -30,10 +33,10 @@ export class CertificateKeyPairListPage extends TablePage<CertificateKeyPair> {
order = "name";
apiEndpoint(page: number): Promise<AKResponse<CertificateKeyPair>> {
return CertificateKeyPair.list({
return new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsList({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
pageSize: PAGE_SIZE,
search: this.search || "",
});
}
@ -50,16 +53,16 @@ export class CertificateKeyPairListPage extends TablePage<CertificateKeyPair> {
row(item: CertificateKeyPair): TemplateResult[] {
return [
html`${item.name}`,
html`${gettext(item.private_key_available ? "Yes" : "No")}`,
html`${new Date(item.cert_expiry * 1000).toLocaleString()}`,
html`${gettext(item.privateKeyAvailable ? "Yes" : "No")}`,
html`${item.certExpiry?.toLocaleString()}`,
html`
<ak-modal-button href="${CertificateKeyPair.adminUrl(`${item.pk}/update/`)}">
<ak-modal-button href="${AdminURLManager.cryptoCertificates(`${item.pk}/update/`)}">
<ak-spinner-button slot="trigger" class="pf-m-secondary">
${gettext("Edit")}
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>
<ak-modal-button href="${CertificateKeyPair.adminUrl(`${item.pk}/delete/`)}">
<ak-modal-button href="${AdminURLManager.cryptoCertificates(`${item.pk}/delete/`)}">
<ak-spinner-button slot="trigger" class="pf-m-danger">
${gettext("Delete")}
</ak-spinner-button>
@ -73,24 +76,24 @@ export class CertificateKeyPairListPage extends TablePage<CertificateKeyPair> {
return html`
<td role="cell" colspan="3">
<div class="pf-c-table__expandable-row-content">
<dl class="pf-c-description-list pf-m-horizontal">
<div class="pf-c-description-list__group">
<dt class="pf-c-description-list__term">
<span class="pf-c-description-list__text">${gettext("Certificate Fingerprint")}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">${item.fingerprint}</div>
</dd>
</div>
<div class="pf-c-description-list__group">
<dt class="pf-c-description-list__term">
<span class="pf-c-description-list__text">${gettext("Certificate Subjet")}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">${item.cert_subject}</div>
</dd>
</div>
</dl>
<dl class="pf-c-description-list pf-m-horizontal">
<div class="pf-c-description-list__group">
<dt class="pf-c-description-list__term">
<span class="pf-c-description-list__text">${gettext("Certificate Fingerprint")}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">${item.fingerprint}</div>
</dd>
</div>
<div class="pf-c-description-list__group">
<dt class="pf-c-description-list__term">
<span class="pf-c-description-list__text">${gettext("Certificate Subjet")}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">${item.certSubject}</div>
</dd>
</div>
</dl>
</div>
</td>
<td></td>
@ -99,13 +102,13 @@ export class CertificateKeyPairListPage extends TablePage<CertificateKeyPair> {
renderToolbar(): TemplateResult {
return html`
<ak-modal-button href=${CertificateKeyPair.adminUrl("create/")}>
<ak-modal-button href=${AdminURLManager.cryptoCertificates("create/")}>
<ak-spinner-button slot="trigger" class="pf-m-primary">
${gettext("Create")}
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>
<ak-modal-button href=${CertificateKeyPair.adminUrl("generate/")}>
<ak-modal-button href=${AdminURLManager.cryptoCertificates("generate/")}>
<ak-spinner-button slot="trigger" class="pf-m-secondary">
${gettext("Generate")}
</ak-spinner-button>

View File

@ -1,18 +1,19 @@
import { gettext } from "django";
import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
import { until } from "lit-html/directives/until";
import { Event, EventContext } from "../../api/Events";
import { Flow } from "../../api/Flows";
import { FlowsApi } from "../../api";
import { COMMON_STYLES } from "../../common/styles";
import "../../elements/Spinner";
import "../../elements/Expand";
import { SpinnerSize } from "../../elements/Spinner";
import { EventContext, EventWithContext } from "../../api/Events";
import { DEFAULT_CONFIG } from "../../api/Config";
@customElement("ak-event-info")
export class EventInfo extends LitElement {
@property({attribute: false})
event?: Event;
event!: EventWithContext;
static get styles(): CSSResult[] {
return COMMON_STYLES.concat(
@ -73,15 +74,15 @@ export class EventInfo extends LitElement {
defaultResponse(): TemplateResult {
return html`<div class="pf-l-flex">
<div class="pf-l-flex__item">
<h3>${gettext("Context")}</h3>
<code>${JSON.stringify(this.event?.context, null, 4)}</code>
</div>
<div class="pf-l-flex__item">
<h3>${gettext("User")}</h3>
<code>${JSON.stringify(this.event?.user, null, 4)}</code>
</div>
</div>`;
<div class="pf-l-flex__item">
<h3>${gettext("Context")}</h3>
<code>${JSON.stringify(this.event?.context, null, 4)}</code>
</div>
<div class="pf-l-flex__item">
<h3>${gettext("User")}</h3>
<code>${JSON.stringify(this.event?.user, null, 4)}</code>
</div>
</div>`;
}
render(): TemplateResult {
@ -94,7 +95,7 @@ export class EventInfo extends LitElement {
case "model_deleted":
return html`
<h3>${gettext("Affected model:")}</h3>
${this.getModelInfo(this.event.context.model as EventContext)}
${this.getModelInfo(this.event.context?.model as EventContext)}
`;
case "authorize_application":
return html`<div class="pf-l-flex">
@ -104,8 +105,8 @@ export class EventInfo extends LitElement {
</div>
<div class="pf-l-flex__item">
<h3>${gettext("Using flow")}</h3>
<span>${until(Flow.list({
flow_uuid: this.event.context.flow as string,
<span>${until(new FlowsApi(DEFAULT_CONFIG).flowsInstancesList({
flowUuid: this.event.context.flow as string,
}).then(resp => {
return html`<a href="#/flow/flows/${resp.results[0].slug}">${resp.results[0].name}</a>`;
}), html`<ak-spinner size=${SpinnerSize.Medium}></ak-spinner>`)}

View File

@ -1,6 +1,8 @@
import { gettext } from "django";
import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
import { Event } from "../../api/Events";
import { EventsApi } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { EventWithContext } from "../../api/Events";
import { COMMON_STYLES } from "../../common/styles";
import "./EventInfo";
@ -13,11 +15,15 @@ export class EventInfoPage extends LitElement {
@property()
set eventID(value: string) {
Event.get(value).then((e) => (this.event = e));
new EventsApi(DEFAULT_CONFIG).eventsEventsRead({
eventUuid: value
}).then((ev) => {
this.event = ev as EventWithContext;
});
}
@property({ attribute: false })
event?: Event;
event!: EventWithContext;
static get styles(): CSSResult[] {
return COMMON_STYLES.concat(css`

View File

@ -1,11 +1,12 @@
import { gettext } from "django";
import { customElement, html, property, TemplateResult } from "lit-element";
import { Event, EventsApi } from "../../api";
import { AKResponse } from "../../api/Client";
import { Event } from "../../api/Events";
import { DEFAULT_CONFIG } from "../../api/Config";
import { EventWithContext } from "../../api/Events";
import { PAGE_SIZE } from "../../constants";
import { TableColumn } from "../../elements/table/Table";
import { TablePage } from "../../elements/table/TablePage";
import { time } from "../../utils";
import "./EventInfo";
@customElement("ak-event-list")
@ -29,10 +30,10 @@ export class EventListPage extends TablePage<Event> {
order = "-created";
apiEndpoint(page: number): Promise<AKResponse<Event>> {
return Event.list({
return new EventsApi(DEFAULT_CONFIG).eventsEventsList({
ordering: this.order,
page: page,
page_size: PAGE_SIZE * 3,
pageSize: PAGE_SIZE * 3,
search: this.search || "",
});
}
@ -45,16 +46,16 @@ export class EventListPage extends TablePage<Event> {
new TableColumn("Client IP", "client_ip"),
];
}
row(item: Event): TemplateResult[] {
row(item: EventWithContext): TemplateResult[] {
return [
html`<div>${item.action}</div>
<small>${item.app}</small>`,
html`<div>${item.user.username}</div>
html`<div>${item.user?.username}</div>
${item.user.on_behalf_of ? html`<small>
${gettext(`On behalf of ${item.user.on_behalf_of.username}`)}
</small>` : html``}`,
html`<span>${time(item.created).toLocaleString()}</span>`,
html`<span>${item.client_ip}</span>`,
html`<span>${item.created?.toLocaleString()}</span>`,
html`<span>${item.clientIp}</span>`,
];
}
@ -62,7 +63,7 @@ export class EventListPage extends TablePage<Event> {
return html`
<td role="cell" colspan="4">
<div class="pf-c-table__expandable-row-content">
<ak-event-info .event=${item}></ak-event-info>
<ak-event-info .event=${item as EventWithContext}></ak-event-info>
</div>
</td>
<td></td>

View File

@ -7,11 +7,13 @@ import "../../elements/policies/BoundPoliciesList";
import "../../elements/buttons/ModalButton";
import "../../elements/buttons/SpinnerButton";
import { TableColumn } from "../../elements/table/Table";
import { Rule } from "../../api/EventRules";
import { PAGE_SIZE } from "../../constants";
import { EventsApi, NotificationRule } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { AdminURLManager } from "../../api/legacy";
@customElement("ak-event-rule-list")
export class RuleListPage extends TablePage<Rule> {
export class RuleListPage extends TablePage<NotificationRule> {
expandable = true;
searchEnabled(): boolean {
@ -30,11 +32,11 @@ export class RuleListPage extends TablePage<Rule> {
@property()
order = "name";
apiEndpoint(page: number): Promise<AKResponse<Rule>> {
return Rule.list({
apiEndpoint(page: number): Promise<AKResponse<NotificationRule>> {
return new EventsApi(DEFAULT_CONFIG).eventsRulesList({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
pageSize: PAGE_SIZE,
search: this.search || "",
});
}
@ -48,19 +50,19 @@ export class RuleListPage extends TablePage<Rule> {
];
}
row(item: Rule): TemplateResult[] {
row(item: NotificationRule): TemplateResult[] {
return [
html`${item.name}`,
html`${item.severity}`,
html`${item.group?.name || gettext("None (rule disabled)")}`,
html`
<ak-modal-button href="${Rule.adminUrl(`${item.pk}/update/`)}">
<ak-modal-button href="${AdminURLManager.eventRules(`${item.pk}/update/`)}">
<ak-spinner-button slot="trigger" class="pf-m-secondary">
${gettext("Edit")}
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>
<ak-modal-button href="${Rule.adminUrl(`${item.pk}/delete/`)}">
<ak-modal-button href="${AdminURLManager.eventRules(`${item.pk}/delete/`)}">
<ak-spinner-button slot="trigger" class="pf-m-danger">
${gettext("Delete")}
</ak-spinner-button>
@ -72,7 +74,7 @@ export class RuleListPage extends TablePage<Rule> {
renderToolbar(): TemplateResult {
return html`
<ak-modal-button href=${Rule.adminUrl("create/")}>
<ak-modal-button href=${AdminURLManager.eventRules("create/")}>
<ak-spinner-button slot="trigger" class="pf-m-primary">
${gettext("Create")}
</ak-spinner-button>
@ -82,7 +84,7 @@ export class RuleListPage extends TablePage<Rule> {
`;
}
renderExpanded(item: Rule): TemplateResult {
renderExpanded(item: NotificationRule): TemplateResult {
return html`
<td role="cell" colspan="4">
<div class="pf-c-table__expandable-row-content">

View File

@ -1,17 +1,19 @@
import { gettext } from "django";
import { customElement, html, property, TemplateResult } from "lit-element";
import { DefaultClient, AKResponse } from "../../api/Client";
import { AKResponse } from "../../api/Client";
import { TablePage } from "../../elements/table/TablePage";
import "../../elements/buttons/ActionButton";
import "../../elements/buttons/ModalButton";
import "../../elements/buttons/SpinnerButton";
import { TableColumn } from "../../elements/table/Table";
import { Transport } from "../../api/EventTransports";
import { PAGE_SIZE } from "../../constants";
import { EventsApi, NotificationTransport } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { AdminURLManager } from "../../api/legacy";
@customElement("ak-event-transport-list")
export class TransportListPage extends TablePage<Transport> {
export class TransportListPage extends TablePage<NotificationTransport> {
searchEnabled(): boolean {
return true;
}
@ -28,11 +30,11 @@ export class TransportListPage extends TablePage<Transport> {
@property()
order = "name";
apiEndpoint(page: number): Promise<AKResponse<Transport>> {
return Transport.list({
apiEndpoint(page: number): Promise<AKResponse<NotificationTransport>> {
return new EventsApi(DEFAULT_CONFIG).eventsTransportsList({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
pageSize: PAGE_SIZE,
search: this.search || "",
});
}
@ -45,21 +47,26 @@ export class TransportListPage extends TablePage<Transport> {
];
}
row(item: Transport): TemplateResult[] {
row(item: NotificationTransport): TemplateResult[] {
return [
html`${item.name}`,
html`${item.mode_verbose}`,
html`${item.modeVerbose}`,
html`
<ak-action-button url="${DefaultClient.makeUrl(["events", "transports", item.pk, "test"])}">
<ak-action-button
.apiRequest=${() => {
return new EventsApi(DEFAULT_CONFIG).eventsTransportsTest({
uuid: item.pk || "",
});
}}>
${gettext("Test")}
</ak-action-button>
<ak-modal-button href="${Transport.adminUrl(`${item.pk}/update/`)}">
<ak-modal-button href="${AdminURLManager.eventTransports(`${item.pk}/update/`)}">
<ak-spinner-button slot="trigger" class="pf-m-secondary">
${gettext("Edit")}
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>
<ak-modal-button href="${Transport.adminUrl(`${item.pk}/delete/`)}">
<ak-modal-button href="${AdminURLManager.eventTransports(`${item.pk}/delete/`)}">
<ak-spinner-button slot="trigger" class="pf-m-danger">
${gettext("Delete")}
</ak-spinner-button>
@ -71,7 +78,7 @@ export class TransportListPage extends TablePage<Transport> {
renderToolbar(): TemplateResult {
return html`
<ak-modal-button href=${Transport.adminUrl("create/")}>
<ak-modal-button href=${AdminURLManager.eventTransports("create/")}>
<ak-spinner-button slot="trigger" class="pf-m-primary">
${gettext("Create")}
</ak-spinner-button>

View File

@ -4,14 +4,15 @@ import { AKResponse } from "../../api/Client";
import { Table, TableColumn } from "../../elements/table/Table";
import "../../elements/Tabs";
import "../../elements/AdminLoginsChart";
import "../../elements/buttons/ModalButton";
import "../../elements/buttons/SpinnerButton";
import "../../elements/buttons/Dropdown";
import "../../elements/policies/BoundPoliciesList";
import { FlowStageBinding, Stage } from "../../api/Flows";
import { until } from "lit-html/directives/until";
import { PAGE_SIZE } from "../../constants";
import { FlowsApi, FlowStageBinding, StagesApi } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { AdminURLManager } from "../../api/legacy";
@customElement("ak-bound-stages-list")
export class BoundStagesList extends Table<FlowStageBinding> {
@ -21,11 +22,11 @@ export class BoundStagesList extends Table<FlowStageBinding> {
target?: string;
apiEndpoint(page: number): Promise<AKResponse<FlowStageBinding>> {
return FlowStageBinding.list({
return new FlowsApi(DEFAULT_CONFIG).flowsBindingsList({
target: this.target || "",
ordering: "order",
page: page,
page_size: PAGE_SIZE,
pageSize: PAGE_SIZE,
});
}
@ -41,22 +42,22 @@ export class BoundStagesList extends Table<FlowStageBinding> {
row(item: FlowStageBinding): TemplateResult[] {
return [
html`${item.order}`,
html`${item.stage_obj.name}`,
html`${item.stage_obj.verbose_name}`,
html`${item.stageObj?.name}`,
html`${item.stageObj?.verboseName}`,
html`
<ak-modal-button href="${FlowStageBinding.adminUrl(`${item.pk}/update/`)}">
<ak-modal-button href="${AdminURLManager.stageBindings(`${item.pk}/update/`)}">
<ak-spinner-button slot="trigger" class="pf-m-secondary">
${gettext("Edit Binding")}
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>
<ak-modal-button href="${Stage.adminUrl(`${item.stage}/update/`)}">
<ak-modal-button href="${AdminURLManager.stages(`${item.stage}/update/`)}">
<ak-spinner-button slot="trigger" class="pf-m-secondary">
${gettext("Edit Stage")}
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>
<ak-modal-button href="${FlowStageBinding.adminUrl(`${item.pk}/delete/`)}">
<ak-modal-button href="${AdminURLManager.stages(`${item.pk}/delete/`)}">
<ak-spinner-button slot="trigger" class="pf-m-danger">
${gettext("Delete")}
</ak-spinner-button>
@ -73,7 +74,7 @@ export class BoundStagesList extends Table<FlowStageBinding> {
<div class="pf-c-table__expandable-row-content">
<div class="pf-c-content">
<p>${gettext("These policies control when this stage will be applied to the flow.")}</p>
<ak-bound-policies-list .target=${item.policybindingmodel_ptr_id}>
<ak-bound-policies-list .target=${item.policybindingmodelPtrId}>
</ak-bound-policies-list>
</div>
</div>
@ -88,7 +89,7 @@ export class BoundStagesList extends Table<FlowStageBinding> {
${gettext("No stages are currently bound to this flow.")}
</div>
<div slot="primary">
<ak-modal-button href="${FlowStageBinding.adminUrl(`create/?target=${this.target}`)}">
<ak-modal-button href="${AdminURLManager.stageBindings(`create/?target=${this.target}`)}">
<ak-spinner-button slot="trigger" class="pf-m-primary">
${gettext("Bind Stage")}
</ak-spinner-button>
@ -106,7 +107,7 @@ export class BoundStagesList extends Table<FlowStageBinding> {
<i class="fas fa-caret-down pf-c-dropdown__toggle-icon" aria-hidden="true"></i>
</button>
<ul class="pf-c-dropdown__menu" hidden>
${until(Stage.getTypes().then((types) => {
${until(new StagesApi(DEFAULT_CONFIG).stagesAllTypes({}).then((types) => {
return types.map((type) => {
return html`<li>
<ak-modal-button href="${type.link}">
@ -120,7 +121,7 @@ export class BoundStagesList extends Table<FlowStageBinding> {
}), html`<ak-spinner></ak-spinner>`)}
</ul>
</ak-dropdown>
<ak-modal-button href="${FlowStageBinding.adminUrl(`create/?target=${this.target}`)}">
<ak-modal-button href="${AdminURLManager.stageBindings(`create/?target=${this.target}`)}">
<ak-spinner-button slot="trigger" class="pf-m-primary">
${gettext("Bind Stage")}
</ak-spinner-button>

View File

@ -1,7 +1,8 @@
import { customElement, html, LitElement, property, TemplateResult } from "lit-element";
import FlowChart from "flowchart.js";
import { Flow } from "../../api/Flows";
import { loading } from "../../utils";
import { FlowsApi } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
export const FONT_COLOUR_DARK_MODE = "#fafafa";
export const FONT_COLOUR_LIGHT_MODE = "#151515";
@ -16,8 +17,10 @@ export class FlowDiagram extends LitElement {
@property()
set flowSlug(value: string) {
this._flowSlug = value;
Flow.diagram(value).then((data) => {
this.diagram = FlowChart.parse(data.diagram);
new FlowsApi(DEFAULT_CONFIG).flowsInstancesDiagram({
slug: value,
}).then((data) => {
this.diagram = FlowChart.parse(data.diagram || "");
});
}

View File

@ -1,6 +1,5 @@
import { gettext } from "django";
import { customElement, html, property, TemplateResult } from "lit-element";
import { Flow } from "../../api/Flows";
import { AKResponse } from "../../api/Client";
import { TablePage } from "../../elements/table/TablePage";
@ -8,6 +7,9 @@ import "../../elements/buttons/ModalButton";
import "../../elements/buttons/SpinnerButton";
import { TableColumn } from "../../elements/table/Table";
import { PAGE_SIZE } from "../../constants";
import { Flow, FlowsApi } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { AdminURLManager } from "../../api/legacy";
@customElement("ak-flow-list")
export class FlowListPage extends TablePage<Flow> {
@ -28,10 +30,10 @@ export class FlowListPage extends TablePage<Flow> {
order = "slug";
apiEndpoint(page: number): Promise<AKResponse<Flow>> {
return Flow.list({
return new FlowsApi(DEFAULT_CONFIG).flowsInstancesList({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
pageSize: PAGE_SIZE,
search: this.search || "",
});
}
@ -54,25 +56,25 @@ export class FlowListPage extends TablePage<Flow> {
</a>`,
html`${item.name}`,
html`${item.designation}`,
html`${item.stages.length}`,
html`${item.policies.length}`,
html`${item.stages?.size}`,
html`${item.policies?.size}`,
html`
<ak-modal-button href="${Flow.adminUrl(`${item.pk}/update/`)}">
<ak-modal-button href="${AdminURLManager.flows(`${item.pk}/update/`)}">
<ak-spinner-button slot="trigger" class="pf-m-secondary">
${gettext("Edit")}
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>
<ak-modal-button href="${Flow.adminUrl(`${item.pk}/delete/`)}">
<ak-modal-button href="${AdminURLManager.flows(`${item.pk}/delete/`)}">
<ak-spinner-button slot="trigger" class="pf-m-danger">
${gettext("Delete")}
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>
<a class="pf-c-button pf-m-secondary ak-root-link" href="${Flow.adminUrl(`${item.pk}/execute/?next=/%23${window.location.href}`)}">
<a class="pf-c-button pf-m-secondary ak-root-link" href="${AdminURLManager.flows(`${item.pk}/execute/?next=/%23${window.location.href}`)}">
${gettext("Execute")}
</a>
<a class="pf-c-button pf-m-secondary ak-root-link" href="${Flow.adminUrl(`${item.pk}/export/`)}">
<a class="pf-c-button pf-m-secondary ak-root-link" href="${AdminURLManager.flows(`${item.pk}/export/`)}">
${gettext("Export")}
</a>
`,
@ -81,13 +83,13 @@ export class FlowListPage extends TablePage<Flow> {
renderToolbar(): TemplateResult {
return html`
<ak-modal-button href=${Flow.adminUrl("create/")}>
<ak-modal-button href=${AdminURLManager.flows("create/")}>
<ak-spinner-button slot="trigger" class="pf-m-primary">
${gettext("Create")}
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>
<ak-modal-button href=${Flow.adminUrl("import/")}>
<ak-modal-button href=${AdminURLManager.flows("import/")}>
<ak-spinner-button slot="trigger" class="pf-m-secondary">
${gettext("Import")}
</ak-spinner-button>

View File

@ -1,25 +1,29 @@
import { gettext } from "django";
import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
import { COMMON_STYLES } from "../../common/styles";
import { Flow } from "../../api/Flows";
import "../../elements/Tabs";
import "../../elements/AdminLoginsChart";
import "../../elements/buttons/ModalButton";
import "../../elements/buttons/SpinnerButton";
import "../../elements/policies/BoundPoliciesList";
import "./BoundStagesList";
import "./FlowDiagram";
import { Flow, FlowsApi } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
@customElement("ak-flow-view")
export class FlowViewPage extends LitElement {
@property()
set flowSlug(value: string) {
Flow.get(value).then((flow) => (this.flow = flow));
new FlowsApi(DEFAULT_CONFIG).flowsInstancesRead({
slug: value
}).then((flow) => {
this.flow = flow;
});
}
@property({attribute: false})
flow?: Flow;
flow!: Flow;
static get styles(): CSSResult[] {
return COMMON_STYLES.concat(
@ -67,7 +71,7 @@ export class FlowViewPage extends LitElement {
${gettext("These policies control which users can access this flow.")}
</div>
</div>
<ak-bound-policies-list .target=${this.flow.policybindingmodel_ptr_id}>
<ak-bound-policies-list .target=${this.flow.policybindingmodelPtrId}>
</ak-bound-policies-list>
</div>
</div>

View File

@ -1,192 +0,0 @@
import { gettext } from "django";
import { LitElement, html, customElement, property, TemplateResult, CSSResult, css } from "lit-element";
import { unsafeHTML } from "lit-html/directives/unsafe-html";
import { getCookie } from "../../utils";
import "../../elements/stages/authenticator_static/AuthenticatorStaticStage";
import "../../elements/stages/authenticator_totp/AuthenticatorTOTPStage";
import "../../elements/stages/authenticator_validate/AuthenticatorValidateStage";
import "../../elements/stages/authenticator_webauthn/WebAuthnAuthenticatorRegisterStage";
import "../../elements/stages/autosubmit/AutosubmitStage";
import "../../elements/stages/captcha/CaptchaStage";
import "../../elements/stages/consent/ConsentStage";
import "../../elements/stages/email/EmailStage";
import "../../elements/stages/identification/IdentificationStage";
import "../../elements/stages/password/PasswordStage";
import "../../elements/stages/prompt/PromptStage";
import { ShellChallenge, Challenge, ChallengeTypes, Flow, RedirectChallenge } from "../../api/Flows";
import { DefaultClient } from "../../api/Client";
import { IdentificationChallenge } from "../../elements/stages/identification/IdentificationStage";
import { PasswordChallenge } from "../../elements/stages/password/PasswordStage";
import { ConsentChallenge } from "../../elements/stages/consent/ConsentStage";
import { EmailChallenge } from "../../elements/stages/email/EmailStage";
import { AutosubmitChallenge } from "../../elements/stages/autosubmit/AutosubmitStage";
import { PromptChallenge } from "../../elements/stages/prompt/PromptStage";
import { AuthenticatorTOTPChallenge } from "../../elements/stages/authenticator_totp/AuthenticatorTOTPStage";
import { AuthenticatorStaticChallenge } from "../../elements/stages/authenticator_static/AuthenticatorStaticStage";
import { AuthenticatorValidateStageChallenge } from "../../elements/stages/authenticator_validate/AuthenticatorValidateStage";
import { WebAuthnAuthenticatorRegisterChallenge } from "../../elements/stages/authenticator_webauthn/WebAuthnAuthenticatorRegisterStage";
import { CaptchaChallenge } from "../../elements/stages/captcha/CaptchaStage";
import { COMMON_STYLES } from "../../common/styles";
import { SpinnerSize } from "../../elements/Spinner";
import { StageHost } from "../../elements/stages/base";
@customElement("ak-flow-executor")
export class FlowExecutor extends LitElement implements StageHost {
@property()
flowSlug = "";
@property({attribute: false})
challenge?: Challenge;
@property({type: Boolean})
loading = false;
static get styles(): CSSResult[] {
return COMMON_STYLES.concat(css`
.ak-loading {
display: flex;
height: 100%;
width: 100%;
justify-content: center;
align-items: center;
position: absolute;
background-color: #0303039e;
}
.ak-hidden {
display: none;
}
:host {
position: relative;
}
`);
}
constructor() {
super();
this.addEventListener("ak-flow-submit", () => {
this.submit();
});
}
submit(formData?: FormData): Promise<void> {
const csrftoken = getCookie("authentik_csrf");
const request = new Request(DefaultClient.makeUrl(["flows", "executor", this.flowSlug]), {
headers: {
"X-CSRFToken": csrftoken,
},
});
this.loading = true;
return fetch(request, {
method: "POST",
mode: "same-origin",
body: formData,
})
.then((response) => {
return response.json();
})
.then((data) => {
this.challenge = data;
})
.catch((e) => {
this.errorMessage(e);
})
.finally(() => {
this.loading = false;
});
}
firstUpdated(): void {
this.loading = true;
Flow.executor(this.flowSlug).then((challenge) => {
this.challenge = challenge;
}).catch((e) => {
// Catch JSON or Update errors
this.errorMessage(e);
}).finally(() => {
this.loading = false;
});
}
errorMessage(error: string): void {
this.challenge = <ShellChallenge>{
type: ChallengeTypes.shell,
body: `<style>
.ak-exception {
font-family: monospace;
overflow-x: scroll;
}
</style>
<header class="pf-c-login__main-header">
<h1 class="pf-c-title pf-m-3xl">
${gettext("Whoops!")}
</h1>
</header>
<div class="pf-c-login__main-body">
<h3>${gettext("Something went wrong! Please try again later.")}</h3>
<pre class="ak-exception">${error}</pre>
</div>`
};
}
renderLoading(): TemplateResult {
return html`<div class="ak-loading">
<ak-spinner size=${SpinnerSize.XLarge}></ak-spinner>
</div>`;
}
renderChallenge(): TemplateResult {
if (!this.challenge) {
return this.renderLoading();
}
switch (this.challenge.type) {
case ChallengeTypes.redirect:
console.debug(`authentik/flows: redirecting to ${(this.challenge as RedirectChallenge).to}`);
window.location.assign((this.challenge as RedirectChallenge).to);
return this.renderLoading();
case ChallengeTypes.shell:
return html`${unsafeHTML((this.challenge as ShellChallenge).body)}`;
case ChallengeTypes.native:
switch (this.challenge.component) {
case "ak-stage-identification":
return html`<ak-stage-identification .host=${this} .challenge=${this.challenge as IdentificationChallenge}></ak-stage-identification>`;
case "ak-stage-password":
return html`<ak-stage-password .host=${this} .challenge=${this.challenge as PasswordChallenge}></ak-stage-password>`;
case "ak-stage-captcha":
return html`<ak-stage-captcha .host=${this} .challenge=${this.challenge as CaptchaChallenge}></ak-stage-captcha>`;
case "ak-stage-consent":
return html`<ak-stage-consent .host=${this} .challenge=${this.challenge as ConsentChallenge}></ak-stage-consent>`;
case "ak-stage-email":
return html`<ak-stage-email .host=${this} .challenge=${this.challenge as EmailChallenge}></ak-stage-email>`;
case "ak-stage-autosubmit":
return html`<ak-stage-autosubmit .host=${this} .challenge=${this.challenge as AutosubmitChallenge}></ak-stage-autosubmit>`;
case "ak-stage-prompt":
return html`<ak-stage-prompt .host=${this} .challenge=${this.challenge as PromptChallenge}></ak-stage-prompt>`;
case "ak-stage-authenticator-totp":
return html`<ak-stage-authenticator-totp .host=${this} .challenge=${this.challenge as AuthenticatorTOTPChallenge}></ak-stage-authenticator-totp>`;
case "ak-stage-authenticator-static":
return html`<ak-stage-authenticator-static .host=${this} .challenge=${this.challenge as AuthenticatorStaticChallenge}></ak-stage-authenticator-static>`;
case "ak-stage-authenticator-webauthn":
return html`<ak-stage-authenticator-webauthn .host=${this} .challenge=${this.challenge as WebAuthnAuthenticatorRegisterChallenge}></ak-stage-authenticator-webauthn>`;
case "ak-stage-authenticator-validate":
return html`<ak-stage-authenticator-validate .host=${this} .challenge=${this.challenge as AuthenticatorValidateStageChallenge}></ak-stage-authenticator-validate>`;
default:
break;
}
break;
default:
console.debug(`authentik/flows: unexpected data type ${this.challenge.type}`);
break;
}
return html``;
}
render(): TemplateResult {
if (!this.challenge) {
return this.renderLoading();
}
return html`
${this.loading ? this.renderLoading() : html``}
${this.renderChallenge()}
`;
}
}

View File

@ -6,8 +6,10 @@ import { TablePage } from "../../elements/table/TablePage";
import "../../elements/buttons/ModalButton";
import "../../elements/buttons/SpinnerButton";
import { TableColumn } from "../../elements/table/Table";
import { Group } from "../../api/Groups";
import { PAGE_SIZE } from "../../constants";
import { CoreApi, Group } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { AdminURLManager } from "../../api/legacy";
@customElement("ak-group-list")
export class GroupListPage extends TablePage<Group> {
@ -28,10 +30,10 @@ export class GroupListPage extends TablePage<Group> {
order = "slug";
apiEndpoint(page: number): Promise<AKResponse<Group>> {
return Group.list({
return new CoreApi(DEFAULT_CONFIG).coreGroupsList({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
pageSize: PAGE_SIZE,
search: this.search || "",
});
}
@ -50,16 +52,16 @@ export class GroupListPage extends TablePage<Group> {
return [
html`${item.name}`,
html`${item.parent || "-"}`,
html`${item.users.length}`,
html`${item.is_superuser ? "Yes" : "No"}`,
html`${item.users.keys.length}`,
html`${item.isSuperuser ? "Yes" : "No"}`,
html`
<ak-modal-button href="${Group.adminUrl(`${item.pk}/update/`)}">
<ak-modal-button href="${AdminURLManager.groups(`${item.pk}/update/`)}">
<ak-spinner-button slot="trigger" class="pf-m-secondary">
${gettext("Edit")}
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>
<ak-modal-button href="${Group.adminUrl(`${item.pk}/delete/`)}">
<ak-modal-button href="${AdminURLManager.groups(`${item.pk}/delete/`)}">
<ak-spinner-button slot="trigger" class="pf-m-danger">
${gettext("Delete")}
</ak-spinner-button>
@ -70,7 +72,7 @@ export class GroupListPage extends TablePage<Group> {
renderToolbar(): TemplateResult {
return html`
<ak-modal-button href=${Group.adminUrl("create/")}>
<ak-modal-button href=${AdminURLManager.groups("create/")}>
<ak-spinner-button slot="trigger" class="pf-m-primary">
${gettext("Create")}
</ak-spinner-button>

View File

@ -1,8 +1,10 @@
import { gettext } from "django";
import { CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
import { until } from "lit-html/directives/until";
import { Outpost } from "../../api/Outposts";
import { OutpostsApi } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { COMMON_STYLES } from "../../common/styles";
import "../../elements/Spinner";
@customElement("ak-outpost-health")
export class OutpostHealth extends LitElement {
@ -18,7 +20,9 @@ export class OutpostHealth extends LitElement {
if (!this.outpostId) {
return html`<ak-spinner></ak-spinner>`;
}
return html`<ul>${until(Outpost.health(this.outpostId).then((oh) => {
return html`<ul>${until(new OutpostsApi(DEFAULT_CONFIG).outpostsOutpostsHealth({
uuid: this.outpostId
}).then((oh) => {
if (oh.length === 0) {
return html`<li>
<ul>
@ -32,12 +36,12 @@ export class OutpostHealth extends LitElement {
return html`<li>
<ul>
<li role="cell">
<i class="fas fa-check pf-m-success"></i>${gettext(`Last seen: ${new Date(h.last_seen * 1000).toLocaleTimeString()}`)}
<i class="fas fa-check pf-m-success"></i>${gettext(`Last seen: ${h.lastSeen?.toLocaleTimeString()}`)}
</li>
<li role="cell">
${h.version_outdated ?
${h.versionOutdated ?
html`<i class="fas fa-times pf-m-danger"></i>
${gettext(`${h.version}, should be ${h.version_should}`)}` :
${gettext(`${h.version}, should be ${h.versionShould}`)}` :
html`<i class="fas fa-check pf-m-success"></i>${gettext(`Version: ${h.version}`)}`}
</li>
</ul>

View File

@ -2,7 +2,6 @@ import { gettext } from "django";
import { customElement, property } from "lit-element";
import { html, TemplateResult } from "lit-html";
import { AKResponse } from "../../api/Client";
import { Outpost } from "../../api/Outposts";
import { TableColumn } from "../../elements/table/Table";
import { TablePage } from "../../elements/table/TablePage";
@ -11,6 +10,10 @@ import "../../elements/buttons/SpinnerButton";
import "../../elements/buttons/ModalButton";
import "../../elements/buttons/TokenCopyButton";
import { PAGE_SIZE } from "../../constants";
import { Outpost, OutpostsApi } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { AdminURLManager } from "../../api/legacy";
import { ifDefined } from "lit-html/directives/if-defined";
@customElement("ak-outpost-list")
export class OutpostListPage extends TablePage<Outpost> {
@ -27,10 +30,10 @@ export class OutpostListPage extends TablePage<Outpost> {
return true;
}
apiEndpoint(page: number): Promise<AKResponse<Outpost>> {
return Outpost.list({
return new OutpostsApi(DEFAULT_CONFIG).outpostsOutpostsList({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
pageSize: PAGE_SIZE,
search: this.search || "",
});
}
@ -49,18 +52,18 @@ export class OutpostListPage extends TablePage<Outpost> {
row(item: Outpost): TemplateResult[] {
return [
html`${item.name}`,
html`<ul>${item.providers_obj.map((p) => {
html`<ul>${item.providersObj?.map((p) => {
return html`<li><a href="#/core/providers/${p.pk}">${p.name}</a></li>`;
})}</ul>`,
html`<ak-outpost-health outpostId=${item.pk}></ak-outpost-health>`,
html`<ak-outpost-health outpostId=${ifDefined(item.pk)}></ak-outpost-health>`,
html`
<ak-modal-button href="${Outpost.adminUrl(`${item.pk}/update/`)}">
<ak-modal-button href="${AdminURLManager.outposts(`${item.pk}/update/`)}">
<ak-spinner-button slot="trigger" class="pf-m-secondary">
${gettext("Edit")}
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>&nbsp;
<ak-modal-button href="${Outpost.adminUrl(`${item.pk}/delete/`)}">
<ak-modal-button href="${AdminURLManager.outposts(`${item.pk}/delete/`)}">
<ak-spinner-button slot="trigger" class="pf-m-danger">
${gettext("Delete")}
</ak-spinner-button>
@ -88,7 +91,7 @@ export class OutpostListPage extends TablePage<Outpost> {
<span class="pf-c-form__label-text">AUTHENTIK_TOKEN</span>
</label>
<div>
<ak-token-copy-button identifier="${item.token_identifier}">
<ak-token-copy-button identifier="${ifDefined(item.tokenIdentifier)}">
${gettext("Click to copy token")}
</ak-token-copy-button>
</div>
@ -112,7 +115,7 @@ export class OutpostListPage extends TablePage<Outpost> {
renderToolbar(): TemplateResult {
return html`
<ak-modal-button href=${Outpost.adminUrl("create/")}>
<ak-modal-button href=${AdminURLManager.outposts("create/")}>
<ak-spinner-button slot="trigger" class="pf-m-primary">
${gettext("Create")}
</ak-spinner-button>

View File

@ -2,7 +2,6 @@ import { gettext } from "django";
import { customElement, property } from "lit-element";
import { html, TemplateResult } from "lit-html";
import { AKResponse } from "../../api/Client";
import { OutpostServiceConnection } from "../../api/Outposts";
import { TableColumn } from "../../elements/table/Table";
import { TablePage } from "../../elements/table/TablePage";
@ -12,9 +11,12 @@ import "../../elements/buttons/ModalButton";
import "../../elements/buttons/Dropdown";
import { until } from "lit-html/directives/until";
import { PAGE_SIZE } from "../../constants";
import { OutpostsApi, ServiceConnection } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { AdminURLManager } from "../../api/legacy";
@customElement("ak-outpost-service-connection-list")
export class OutpostServiceConnectionListPage extends TablePage<OutpostServiceConnection> {
export class OutpostServiceConnectionListPage extends TablePage<ServiceConnection> {
pageTitle(): string {
return "Outpost Service-Connections";
}
@ -28,14 +30,15 @@ export class OutpostServiceConnectionListPage extends TablePage<OutpostServiceCo
return true;
}
apiEndpoint(page: number): Promise<AKResponse<OutpostServiceConnection>> {
return OutpostServiceConnection.list({
apiEndpoint(page: number): Promise<AKResponse<ServiceConnection>> {
return new OutpostsApi(DEFAULT_CONFIG).outpostsServiceConnectionsAllList({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
pageSize: PAGE_SIZE,
search: this.search || "",
});
}
columns(): TableColumn[] {
return [
new TableColumn("Name", "name"),
@ -49,25 +52,28 @@ export class OutpostServiceConnectionListPage extends TablePage<OutpostServiceCo
@property()
order = "name";
row(item: OutpostServiceConnection): TemplateResult[] {
row(item: ServiceConnection): TemplateResult[] {
return [
html`${item.name}`,
html`${item.verbose_name}`,
html`${item.verboseName}`,
html`${item.local ? "Yes" : "No"}`,
html`${until(OutpostServiceConnection.state(item.pk).then((state) => {
if (state.healthy) {
return html`<i class="fas fa-check pf-m-success"></i> ${state.version}`;
}
return html`<i class="fas fa-times pf-m-danger"></i> ${gettext("Unhealthy")}`;
}), html`<ak-spinner></ak-spinner>`)}`,
html`${until(
new OutpostsApi(DEFAULT_CONFIG).outpostsServiceConnectionsAllState({
uuid: item.pk || ""
}).then((state) => {
if (state.healthy) {
return html`<i class="fas fa-check pf-m-success"></i> ${state.version}`;
}
return html`<i class="fas fa-times pf-m-danger"></i> ${gettext("Unhealthy")}`;
}), html`<ak-spinner></ak-spinner>`)}`,
html`
<ak-modal-button href="${OutpostServiceConnection.adminUrl(`${item.pk}/update/`)}">
<ak-modal-button href="${AdminURLManager.outpostServiceConnections(`${item.pk}/update/`)}">
<ak-spinner-button slot="trigger" class="pf-m-secondary">
${gettext("Edit")}
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>
<ak-modal-button href="${OutpostServiceConnection.adminUrl(`${item.pk}/delete/`)}">
<ak-modal-button href="${AdminURLManager.outpostServiceConnections(`${item.pk}/delete/`)}">
<ak-spinner-button slot="trigger" class="pf-m-danger">
${gettext("Delete")}
</ak-spinner-button>
@ -84,7 +90,7 @@ export class OutpostServiceConnectionListPage extends TablePage<OutpostServiceCo
<i class="fas fa-caret-down pf-c-dropdown__toggle-icon" aria-hidden="true"></i>
</button>
<ul class="pf-c-dropdown__menu" hidden>
${until(OutpostServiceConnection.getTypes().then((types) => {
${until(new OutpostsApi(DEFAULT_CONFIG).outpostsServiceConnectionsAllTypes({}).then((types) => {
return types.map((type) => {
return html`<li>
<ak-modal-button href="${type.link}">

View File

@ -7,9 +7,11 @@ import "../../elements/buttons/ModalButton";
import "../../elements/buttons/Dropdown";
import "../../elements/buttons/SpinnerButton";
import { TableColumn } from "../../elements/table/Table";
import { Policy } from "../../api/Policies";
import { until } from "lit-html/directives/until";
import { PAGE_SIZE } from "../../constants";
import { PoliciesApi, Policy } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { AdminURLManager } from "../../api/legacy";
@customElement("ak-policy-list")
export class PolicyListPage extends TablePage<Policy> {
@ -30,10 +32,10 @@ export class PolicyListPage extends TablePage<Policy> {
order = "name";
apiEndpoint(page: number): Promise<AKResponse<Policy>> {
return Policy.list({
return new PoliciesApi(DEFAULT_CONFIG).policiesAllList({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
pageSize: PAGE_SIZE,
search: this.search || "",
});
}
@ -50,29 +52,29 @@ export class PolicyListPage extends TablePage<Policy> {
return [
html`<div>
<div>${item.name}</div>
${item.bound_to > 0 ?
${(item.boundTo || 0) > 0 ?
html`<i class="pf-icon pf-icon-ok"></i>
<small>
${gettext(`Assigned to ${item.bound_to} objects.`)}
${gettext(`Assigned to ${item.boundTo} objects.`)}
</small>`:
html`<i class="pf-icon pf-icon-warning-triangle"></i>
<small>${gettext("Warning: Policy is not assigned.")}</small>`}
</div>`,
html`${item.verbose_name}`,
html`${item.verboseName}`,
html`
<ak-modal-button href="${Policy.adminUrl(`${item.pk}/update/`)}">
<ak-modal-button href="${AdminURLManager.policies(`${item.pk}/update/`)}">
<ak-spinner-button slot="trigger" class="pf-m-secondary">
${gettext("Edit")}
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>
<ak-modal-button href="${Policy.adminUrl(`${item.pk}/test/`)}">
<ak-modal-button href="${AdminURLManager.policies(`${item.pk}/test/`)}">
<ak-spinner-button slot="trigger" class="pf-m-secondary">
${gettext("Test")}
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>
<ak-modal-button href="${Policy.adminUrl(`${item.pk}/delete/`)}">
<ak-modal-button href="${AdminURLManager.policies(`${item.pk}/delete/`)}">
<ak-spinner-button slot="trigger" class="pf-m-danger">
${gettext("Delete")}
</ak-spinner-button>
@ -90,7 +92,7 @@ export class PolicyListPage extends TablePage<Policy> {
<i class="fas fa-caret-down pf-c-dropdown__toggle-icon" aria-hidden="true"></i>
</button>
<ul class="pf-c-dropdown__menu" hidden>
${until(Policy.getTypes().then((types) => {
${until(new PoliciesApi(DEFAULT_CONFIG).policiesAllTypes({}).then((types) => {
return types.map((type) => {
return html`<li>
<ak-modal-button href="${type.link}">

View File

@ -1,6 +1,5 @@
import { gettext } from "django";
import { customElement, html, property, TemplateResult } from "lit-element";
import { PropertyMapping } from "../../api/PropertyMapping";
import { AKResponse } from "../../api/Client";
import { TablePage } from "../../elements/table/TablePage";
@ -10,6 +9,9 @@ import "../../elements/buttons/SpinnerButton";
import { TableColumn } from "../../elements/table/Table";
import { until } from "lit-html/directives/until";
import { PAGE_SIZE } from "../../constants";
import { PropertyMapping, PropertymappingsApi } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { AdminURLManager } from "../../api/legacy";
@customElement("ak-property-mapping-list")
export class PropertyMappingListPage extends TablePage<PropertyMapping> {
@ -33,12 +35,12 @@ export class PropertyMappingListPage extends TablePage<PropertyMapping> {
hideManaged = false;
apiEndpoint(page: number): Promise<AKResponse<PropertyMapping>> {
return PropertyMapping.list({
return new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsAllList({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
pageSize: PAGE_SIZE,
search: this.search || "",
managed__isnull: this.hideManaged,
managedIsnull: this.hideManaged.toString(),
});
}
@ -53,21 +55,21 @@ export class PropertyMappingListPage extends TablePage<PropertyMapping> {
row(item: PropertyMapping): TemplateResult[] {
return [
html`${item.name}`,
html`${item.verbose_name}`,
html`${item.verboseName}`,
html`
<ak-modal-button href="${PropertyMapping.adminUrl(`${item.pk}/update/`)}">
<ak-modal-button href="${AdminURLManager.propertyMappings(`${item.pk}/update/`)}">
<ak-spinner-button slot="trigger" class="pf-m-secondary">
${gettext("Edit")}
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>
<ak-modal-button href="${PropertyMapping.adminUrl(`${item.pk}/test/`)}">
<ak-modal-button href="${AdminURLManager.propertyMappings(`${item.pk}/test/`)}">
<ak-spinner-button slot="trigger" class="pf-m-secondary">
${gettext("Test")}
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>
<ak-modal-button href="${PropertyMapping.adminUrl(`${item.pk}/delete/`)}">
<ak-modal-button href="${AdminURLManager.propertyMappings(`${item.pk}/delete/`)}">
<ak-spinner-button slot="trigger" class="pf-m-danger">
${gettext("Delete")}
</ak-spinner-button>
@ -85,7 +87,7 @@ export class PropertyMappingListPage extends TablePage<PropertyMapping> {
<i class="fas fa-caret-down pf-c-dropdown__toggle-icon" aria-hidden="true"></i>
</button>
<ul class="pf-c-dropdown__menu" hidden>
${until(PropertyMapping.getTypes().then((types) => {
${until(new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsAllTypes({}).then((types) => {
return types.map((type) => {
return html`<li>
<ak-modal-button href="${type.link}">

View File

@ -1,7 +1,5 @@
import { gettext } from "django";
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
import { Provider } from "../../api/Providers";
import { OAuth2Provider, OAuth2SetupURLs } from "../../api/providers/OAuth2";
import { COMMON_STYLES } from "../../common/styles";
import "../../elements/buttons/ModalButton";
@ -11,6 +9,9 @@ import "../../elements/Tabs";
import { Page } from "../../elements/Page";
import { convertToTitle } from "../../utils";
import "./RelatedApplicationButton";
import { OAuth2Provider, OAuth2ProviderSetupURLs, ProvidersApi } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { AdminURLManager } from "../../api/legacy";
@customElement("ak-provider-oauth2-view")
export class OAuth2ProviderViewPage extends Page {
@ -26,15 +27,24 @@ export class OAuth2ProviderViewPage extends Page {
@property({type: Number})
set providerID(value: number) {
OAuth2Provider.get(value).then((app) => this.provider = app);
OAuth2Provider.getLaunchURls(value).then((urls) => this.providerUrls = urls);
const api = new ProvidersApi(DEFAULT_CONFIG);
api.providersOauth2Read({
id: value
}).then((prov) => {
this.provider = prov;
});
api.providersOauth2SetupUrls({
id: value
}).then((prov) => {
this.providerUrls = prov;
});
}
@property({ attribute: false })
provider?: OAuth2Provider;
@property({ attribute: false })
providerUrls?: OAuth2SetupURLs;
providerUrls?: OAuth2ProviderSetupURLs;
static get styles(): CSSResult[] {
return COMMON_STYLES;
@ -82,7 +92,7 @@ export class OAuth2ProviderViewPage extends Page {
<span class="pf-c-description-list__text">${gettext("Client type")}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">${convertToTitle(this.provider.client_type)}</div>
<div class="pf-c-description-list__text">${convertToTitle(this.provider.clientType || "")}</div>
</dd>
</div>
<div class="pf-c-description-list__group">
@ -90,7 +100,7 @@ export class OAuth2ProviderViewPage extends Page {
<span class="pf-c-description-list__text">${gettext("Client ID")}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">${this.provider.client_id}</div>
<div class="pf-c-description-list__text">${this.provider.clientId}</div>
</dd>
</div>
<div class="pf-c-description-list__group">
@ -98,13 +108,13 @@ export class OAuth2ProviderViewPage extends Page {
<span class="pf-c-description-list__text">${gettext("Redirect URIs")}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">${this.provider.redirect_uris}</div>
<div class="pf-c-description-list__text">${this.provider.redirectUris}</div>
</dd>
</div>
</dl>
</div>
<div class="pf-c-card__footer">
<ak-modal-button href="${Provider.adminUrl(`${this.provider.pk}/update/`)}">
<ak-modal-button href="${AdminURLManager.providers(`${this.provider.pk}/update/`)}">
<ak-spinner-button slot="trigger" class="pf-m-primary">
${gettext("Edit")}
</ak-spinner-button>
@ -125,7 +135,7 @@ export class OAuth2ProviderViewPage extends Page {
<label class="pf-c-form__label" for="help-text-simple-form-name">
<span class="pf-c-form__label-text">${gettext("OpenID Configuration URL")}</span>
</label>
<input class="pf-c-form-control" readonly type="text" value="${this.providerUrls?.provider_info || "-"}" />
<input class="pf-c-form-control" readonly type="text" value="${this.providerUrls?.providerInfo || "-"}" />
</div>
<div class="pf-c-form__group">
<label class="pf-c-form__label" for="help-text-simple-form-name">
@ -150,7 +160,7 @@ export class OAuth2ProviderViewPage extends Page {
<label class="pf-c-form__label" for="help-text-simple-form-name">
<span class="pf-c-form__label-text">${gettext("Userinfo URL")}</span>
</label>
<input class="pf-c-form-control" readonly type="text" value="${this.providerUrls?.user_info || "-"}" />
<input class="pf-c-form-control" readonly type="text" value="${this.providerUrls?.userInfo || "-"}" />
</div>
<div class="pf-c-form__group">
<label class="pf-c-form__label" for="help-text-simple-form-name">

View File

@ -1,6 +1,5 @@
import { gettext } from "django";
import { customElement, html, property, TemplateResult } from "lit-element";
import { Provider } from "../../api/Providers";
import { AKResponse } from "../../api/Client";
import { TablePage } from "../../elements/table/TablePage";
@ -10,6 +9,9 @@ import "../../elements/buttons/Dropdown";
import { TableColumn } from "../../elements/table/Table";
import { until } from "lit-html/directives/until";
import { PAGE_SIZE } from "../../constants";
import { Provider, ProvidersApi } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { AdminURLManager } from "../../api/legacy";
@customElement("ak-provider-list")
export class ProviderListPage extends TablePage<Provider> {
@ -30,10 +32,10 @@ export class ProviderListPage extends TablePage<Provider> {
order = "name";
apiEndpoint(page: number): Promise<AKResponse<Provider>> {
return Provider.list({
return new ProvidersApi(DEFAULT_CONFIG).providersAllList({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
pageSize: PAGE_SIZE,
search: this.search || "",
});
}
@ -52,21 +54,21 @@ export class ProviderListPage extends TablePage<Provider> {
html`<a href="#/core/providers/${item.pk}">
${item.name}
</a>`,
item.assigned_application_name ?
item.assignedApplicationName ?
html`<i class="pf-icon pf-icon-ok"></i>
${gettext("Assigned to application ")}
<a href="#/core/applications/${item.assigned_application_slug}">${item.assigned_application_name}</a>` :
<a href="#/core/applications/${item.assignedApplicationSlug}">${item.assignedApplicationName}</a>` :
html`<i class="pf-icon pf-icon-warning-triangle"></i>
${gettext("Warning: Provider not assigned to any application.")}`,
html`${item.verbose_name}`,
html`${item.verboseName}`,
html`
<ak-modal-button href="${Provider.adminUrl(`${item.pk}/update/`)}">
<ak-modal-button href="${AdminURLManager.providers(`${item.pk}/update/`)}">
<ak-spinner-button slot="trigger" class="pf-m-secondary">
${gettext("Edit")}
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>
<ak-modal-button href="${Provider.adminUrl(`${item.pk}/delete/`)}">
<ak-modal-button href="${AdminURLManager.providers(`${item.pk}/delete/`)}">
<ak-spinner-button slot="trigger" class="pf-m-danger">
${gettext("Delete")}
</ak-spinner-button>
@ -84,7 +86,7 @@ export class ProviderListPage extends TablePage<Provider> {
<i class="fas fa-caret-down pf-c-dropdown__toggle-icon" aria-hidden="true"></i>
</button>
<ul class="pf-c-dropdown__menu" hidden>
${until(Provider.getTypes().then((types) => {
${until(new ProvidersApi(DEFAULT_CONFIG).providersAllTypes({}).then((types) => {
return types.map((type) => {
return html`<li>
<ak-modal-button href="${type.link}">

View File

@ -1,5 +1,4 @@
import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
import { Provider } from "../../api/Providers";
import { COMMON_STYLES } from "../../common/styles";
import "../../elements/buttons/ModalButton";
@ -9,13 +8,18 @@ import "../../elements/utils/LoadingState";
import "./SAMLProviderViewPage";
import "./OAuth2ProviderViewPage";
import "./ProxyProviderViewPage";
import { Provider, ProvidersApi } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { ifDefined } from "lit-html/directives/if-defined";
@customElement("ak-provider-view")
export class ProviderViewPage extends LitElement {
@property({type: Number})
set providerID(value: number) {
Provider.get(value).then((app) => (this.provider = app));
new ProvidersApi(DEFAULT_CONFIG).providersAllRead({
id: value,
}).then((prov) => (this.provider = prov));
}
@property({ attribute: false })
@ -33,15 +37,15 @@ export class ProviderViewPage extends LitElement {
if (!this.provider) {
return html`<ak-loading-state></ak-loading-state>`;
}
switch (this.provider?.object_type) {
switch (this.provider?.objectType) {
case "saml":
return html`<ak-provider-saml-view providerID=${this.provider.pk}></ak-provider-saml-view>`;
return html`<ak-provider-saml-view providerID=${ifDefined(this.provider.pk)}></ak-provider-saml-view>`;
case "oauth2":
return html`<ak-provider-oauth2-view providerID=${this.provider.pk}></ak-provider-oauth2-view>`;
return html`<ak-provider-oauth2-view providerID=${ifDefined(this.provider.pk)}></ak-provider-oauth2-view>`;
case "proxy":
return html`<ak-provider-proxy-view providerID=${this.provider.pk}></ak-provider-proxy-view>`;
return html`<ak-provider-proxy-view providerID=${ifDefined(this.provider.pk)}></ak-provider-proxy-view>`;
default:
return html`<p>Invalid provider type ${this.provider?.object_type}</p>`;
return html`<p>Invalid provider type ${this.provider?.objectType}</p>`;
}
}
}

View File

@ -1,7 +1,5 @@
import { gettext } from "django";
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
import { Provider } from "../../api/Providers";
import { ProxyProvider } from "../../api/providers/Proxy";
import { COMMON_STYLES } from "../../common/styles";
import "../../elements/buttons/ModalButton";
@ -10,6 +8,9 @@ import "../../elements/CodeMirror";
import "../../elements/Tabs";
import { Page } from "../../elements/Page";
import "./RelatedApplicationButton";
import { ProvidersApi, ProxyProvider } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { AdminURLManager } from "../../api/legacy";
@customElement("ak-provider-proxy-view")
export class ProxyProviderViewPage extends Page {
@ -30,7 +31,9 @@ export class ProxyProviderViewPage extends Page {
@property({type: Number})
set providerID(value: number) {
ProxyProvider.get(value).then((app) => (this.provider = app));
new ProvidersApi(DEFAULT_CONFIG).providersProxyRead({
id: value,
}).then((prov) => (this.provider = prov));
}
@property({ attribute: false })
@ -82,7 +85,7 @@ export class ProxyProviderViewPage extends Page {
<span class="pf-c-description-list__text">${gettext("Internal Host")}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">${this.provider.internal_host}</div>
<div class="pf-c-description-list__text">${this.provider.internalHost}</div>
</dd>
</div>
<div class="pf-c-description-list__group">
@ -90,7 +93,7 @@ export class ProxyProviderViewPage extends Page {
<span class="pf-c-description-list__text">${gettext("External Host")}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">${this.provider.internal_host}</div>
<div class="pf-c-description-list__text">${this.provider.externalHost}</div>
</dd>
</div>
<div class="pf-c-description-list__group">
@ -99,7 +102,7 @@ export class ProxyProviderViewPage extends Page {
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">
${this.provider.basic_auth_enabled ?
${this.provider.basicAuthEnabled ?
html`<span class="pf-c-button__icon pf-m-start">
<i class="fas fa-check-circle" aria-hidden="true"></i>
</span>${gettext("Yes")}`:
@ -113,7 +116,7 @@ export class ProxyProviderViewPage extends Page {
</dl>
</div>
<div class="pf-c-card__footer">
<ak-modal-button href="${Provider.adminUrl(`${this.provider.pk}/update/`)}">
<ak-modal-button href="${AdminURLManager.providers(`${this.provider.pk}/update/`)}">
<ak-spinner-button slot="trigger" class="pf-m-primary">
${gettext("Edit")}
</ak-spinner-button>

View File

@ -1,7 +1,7 @@
import { gettext } from "django";
import { customElement, html, LitElement, property, TemplateResult } from "lit-element";
import { Application } from "../../api/Applications";
import { Provider } from "../../api/Providers";
import { Provider } from "../../api";
import { AdminURLManager } from "../../api/legacy";
import "../../elements/buttons/ModalButton";
import "../../elements/Spinner";
@ -13,12 +13,12 @@ export class RelatedApplicationButton extends LitElement {
provider?: Provider;
render(): TemplateResult {
if (this.provider?.assigned_application_slug) {
return html`<a href="#/core/applications/${this.provider.assigned_application_slug}">
${this.provider.assigned_application_name}
if (this.provider?.assignedApplicationSlug) {
return html`<a href="#/core/applications/${this.provider.assignedApplicationSlug}">
${this.provider.assignedApplicationName}
</a>`;
}
return html`<ak-modal-button href=${Application.adminUrl(`create/?provider=${this.provider ? this.provider.pk : ""}`)}>
return html`<ak-modal-button href=${AdminURLManager.applications(`create/?provider=${this.provider ? this.provider.pk : ""}`)}>
<ak-spinner-button slot="trigger" class="pf-m-primary">
${gettext("Create")}
</ak-spinner-button>

View File

@ -1,8 +1,6 @@
import { gettext } from "django";
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
import { until } from "lit-html/directives/until";
import { Provider } from "../../api/Providers";
import { SAMLProvider } from "../../api/providers/SAML";
import { COMMON_STYLES } from "../../common/styles";
import "../../elements/buttons/ModalButton";
@ -11,6 +9,9 @@ import "../../elements/CodeMirror";
import "../../elements/Tabs";
import { Page } from "../../elements/Page";
import "./RelatedApplicationButton";
import { ProvidersApi, SAMLProvider } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { AdminURLManager, AppURLManager } from "../../api/legacy";
@customElement("ak-provider-saml-view")
export class SAMLProviderViewPage extends Page {
@ -31,7 +32,9 @@ export class SAMLProviderViewPage extends Page {
@property({type: Number})
set providerID(value: number) {
SAMLProvider.get(value).then((app) => (this.provider = app));
new ProvidersApi(DEFAULT_CONFIG).providersSamlRead({
id: value,
}).then((prov) => (this.provider = prov));
}
@property({ attribute: false })
@ -83,7 +86,7 @@ export class SAMLProviderViewPage extends Page {
<span class="pf-c-description-list__text">${gettext("ACS URL")}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">${this.provider.acs_url}</div>
<div class="pf-c-description-list__text">${this.provider.acsUrl}</div>
</dd>
</div>
<div class="pf-c-description-list__group">
@ -105,7 +108,7 @@ export class SAMLProviderViewPage extends Page {
</dl>
</div>
<div class="pf-c-card__footer">
<ak-modal-button href="${Provider.adminUrl(`${this.provider.pk}/update/`)}">
<ak-modal-button href="${AdminURLManager.providers(`${this.provider.pk}/update/`)}">
<ak-spinner-button slot="trigger" class="pf-m-primary">
${gettext("Edit")}
</ak-spinner-button>
@ -122,13 +125,15 @@ export class SAMLProviderViewPage extends Page {
<div class="pf-c-card pf-c-card-aggregate">
<div class="pf-c-card__body">
${until(
SAMLProvider.getMetadata(this.provider.pk).then(m => {
new ProvidersApi(DEFAULT_CONFIG).providersSamlMetadata({
id: this.provider.pk || 0,
}).then(m => {
return html`<ak-codemirror mode="xml"><textarea class="pf-c-form-control" readonly>${m.metadata}</textarea></ak-codemirror>`;
})
)}
</div>
<div class="pf-c-card__footer">
<a class="pf-c-button pf-m-primary" target="_blank" href="${SAMLProvider.appUrl(`${this.provider.assigned_application_slug}/metadata/`)}">
<a class="pf-c-button pf-m-primary" target="_blank" href="${AppURLManager.providerSAML(`${this.provider.assignedApplicationSlug}/metadata/`)}">
${gettext("Download")}
</a>
</div>

View File

@ -8,10 +8,10 @@ import "../../elements/buttons/ActionButton";
import "../../elements/CodeMirror";
import "../../elements/Tabs";
import { Page } from "../../elements/Page";
import { LDAPSource } from "../../api/sources/LDAP";
import { Source } from "../../api/Sources";
import { until } from "lit-html/directives/until";
import { DefaultClient } from "../../api/Client";
import { LDAPSource, SourcesApi } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { AdminURLManager } from "../../api/legacy";
@customElement("ak-source-ldap-view")
export class LDAPSourceViewPage extends Page {
@ -27,11 +27,15 @@ export class LDAPSourceViewPage extends Page {
@property({ type: String })
set sourceSlug(slug: string) {
LDAPSource.get(slug).then((s) => this.source = s);
new SourcesApi(DEFAULT_CONFIG).sourcesLdapRead({
slug: slug
}).then((source) => {
this.source = source;
});
}
@property({ attribute: false })
source?: LDAPSource;
source!: LDAPSource;
static get styles(): CSSResult[] {
return COMMON_STYLES;
@ -69,7 +73,7 @@ export class LDAPSourceViewPage extends Page {
<span class="pf-c-description-list__text">${gettext("Server URI")}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">${this.source.server_uri}</div>
<div class="pf-c-description-list__text">${this.source.serverUri}</div>
</dd>
</div>
<div class="pf-c-description-list__group">
@ -79,7 +83,7 @@ export class LDAPSourceViewPage extends Page {
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">
<ul>
<li>${this.source.base_dn}</li>
<li>${this.source.baseDn}</li>
</ul>
</div>
</dd>
@ -87,7 +91,7 @@ export class LDAPSourceViewPage extends Page {
</dl>
</div>
<div class="pf-c-card__footer">
<ak-modal-button href="${Source.adminUrl(`${this.source.pk}/update/`)}">
<ak-modal-button href="${AdminURLManager.sources(`${this.source.pk}/update/`)}">
<ak-spinner-button slot="trigger" class="pf-m-primary">
${gettext("Edit")}
</ak-spinner-button>
@ -102,26 +106,31 @@ export class LDAPSourceViewPage extends Page {
<div class="pf-u-display-flex pf-u-justify-content-center">
<div class="pf-u-w-75">
<div class="pf-c-card pf-c-card-aggregate">
<div class="pf-c-card pf-c-card-aggregate">
<div class="pf-c-card__title">
<p>${gettext("Sync status")}</p>
</div>
<div class="pf-c-card__body">
<p>
${until(LDAPSource.syncStatus(this.source.slug).then((ls) => {
if (!ls.last_sync) {
return gettext("Not synced in the last hour, check System tasks.");
}
const syncDate = new Date(ls.last_sync * 1000);
return gettext(`Last sync: ${syncDate.toLocaleString()}`);
}), "loading")}
</p>
</div>
<div class="pf-c-card__footer">
<ak-action-button method="PATCH" url="${DefaultClient.makeUrl(["sources", "ldap", this.source.slug])}">
${gettext("Retry Task")}
</ak-action-button>
</div>
<div class="pf-c-card__title">
<p>${gettext("Sync status")}</p>
</div>
<div class="pf-c-card__body">
<p>
${until(new SourcesApi(DEFAULT_CONFIG).sourcesLdapSyncStatus({
slug: this.source.slug
}).then((ls) => {
if (!ls.lastSync) {
return gettext("Not synced in the last hour, check System tasks.");
}
return gettext(`Last sync: ${ls.lastSync.toLocaleString()}`);
}), "loading")}
</p>
</div>
<div class="pf-c-card__footer">
<ak-action-button
.apiRequest=${() => {
return new SourcesApi(DEFAULT_CONFIG).sourcesLdapPartialUpdate({
slug: this.source?.slug || "",
data: this.source,
});
}}>
${gettext("Retry Task")}
</ak-action-button>
</div>
</div>
</div>

View File

@ -7,8 +7,9 @@ import "../../elements/buttons/SpinnerButton";
import "../../elements/CodeMirror";
import "../../elements/Tabs";
import { Page } from "../../elements/Page";
import { OAuthSource } from "../../api/sources/OAuth";
import { Source } from "../../api/Sources";
import { OAuthSource, SourcesApi } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { AdminURLManager } from "../../api/legacy";
@customElement("ak-source-oauth-view")
export class OAuthSourceViewPage extends Page {
@ -24,7 +25,11 @@ export class OAuthSourceViewPage extends Page {
@property({ type: String })
set sourceSlug(value: string) {
OAuthSource.get(value).then((s) => this.source = s);
new SourcesApi(DEFAULT_CONFIG).sourcesOauthRead({
slug: value
}).then((source) => {
this.source = source;
});
}
@property({ attribute: false })
@ -66,7 +71,7 @@ export class OAuthSourceViewPage extends Page {
<span class="pf-c-description-list__text">${gettext("Provider Type")}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">${this.source.provider_type}</div>
<div class="pf-c-description-list__text">${this.source.providerType}</div>
</dd>
</div>
<div class="pf-c-description-list__group">
@ -74,7 +79,7 @@ export class OAuthSourceViewPage extends Page {
<span class="pf-c-description-list__text">${gettext("Callback URL")}</span>
</dt>
<dd class="pf-c-description-list__description">
<code class="pf-c-description-list__text">${this.source.callback_url}</code>
<code class="pf-c-description-list__text">${this.source.callbackUrl}</code>
</dd>
</div>
<div class="pf-c-description-list__group">
@ -82,7 +87,7 @@ export class OAuthSourceViewPage extends Page {
<span class="pf-c-description-list__text">${gettext("Access Key")}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">${this.source.consumer_key}</div>
<div class="pf-c-description-list__text">${this.source.consumerKey}</div>
</dd>
</div>
<div class="pf-c-description-list__group">
@ -90,7 +95,7 @@ export class OAuthSourceViewPage extends Page {
<span class="pf-c-description-list__text">${gettext("Authorization URL")}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">${this.source.authorization_url}</div>
<div class="pf-c-description-list__text">${this.source.authorizationUrl}</div>
</dd>
</div>
<div class="pf-c-description-list__group">
@ -98,13 +103,13 @@ export class OAuthSourceViewPage extends Page {
<span class="pf-c-description-list__text">${gettext("Token URL")}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">${this.source.access_token_url}</div>
<div class="pf-c-description-list__text">${this.source.accessTokenUrl}</div>
</dd>
</div>
</dl>
</div>
<div class="pf-c-card__footer">
<ak-modal-button href="${Source.adminUrl(`${this.source.pk}/update/`)}">
<ak-modal-button href="${AdminURLManager.sources(`${this.source.pk}/update/`)}">
<ak-spinner-button slot="trigger" class="pf-m-primary">
${gettext("Edit")}
</ak-spinner-button>

View File

@ -1,8 +1,6 @@
import { gettext } from "django";
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
import { until } from "lit-html/directives/until";
import { Source } from "../../api/Sources";
import { SAMLSource } from "../../api/sources/SAML";
import { COMMON_STYLES } from "../../common/styles";
import "../../elements/buttons/ModalButton";
@ -10,6 +8,9 @@ import "../../elements/buttons/SpinnerButton";
import "../../elements/CodeMirror";
import "../../elements/Tabs";
import { Page } from "../../elements/Page";
import { SAMLSource, SourcesApi } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { AdminURLManager, AppURLManager } from "../../api/legacy";
@customElement("ak-source-saml-view")
export class SAMLSourceViewPage extends Page {
@ -25,7 +26,11 @@ export class SAMLSourceViewPage extends Page {
@property({ type: String })
set sourceSlug(slug: string) {
SAMLSource.get(slug).then((s) => this.source = s);
new SourcesApi(DEFAULT_CONFIG).sourcesSamlRead({
slug: slug
}).then((source) => {
this.source = source;
});
}
@property({ attribute: false })
@ -67,7 +72,7 @@ export class SAMLSourceViewPage extends Page {
<span class="pf-c-description-list__text">${gettext("SSO URL")}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">${this.source.sso_url}</div>
<div class="pf-c-description-list__text">${this.source.ssoUrl}</div>
</dd>
</div>
<div class="pf-c-description-list__group">
@ -75,7 +80,7 @@ export class SAMLSourceViewPage extends Page {
<span class="pf-c-description-list__text">${gettext("SLO URL")}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">${this.source.slo_url}</div>
<div class="pf-c-description-list__text">${this.source.sloUrl}</div>
</dd>
</div>
<div class="pf-c-description-list__group">
@ -89,7 +94,7 @@ export class SAMLSourceViewPage extends Page {
</dl>
</div>
<div class="pf-c-card__footer">
<ak-modal-button href="${Source.adminUrl(`${this.source.pk}/update/`)}">
<ak-modal-button href="${AdminURLManager.sources(`${this.source.pk}/update/`)}">
<ak-spinner-button slot="trigger" class="pf-m-primary">
${gettext("Edit")}
</ak-spinner-button>
@ -105,14 +110,15 @@ export class SAMLSourceViewPage extends Page {
<div class="pf-u-w-75">
<div class="pf-c-card pf-c-card-aggregate">
<div class="pf-c-card__body">
${until(
SAMLSource.getMetadata(this.source.slug).then(m => {
${until(new SourcesApi(DEFAULT_CONFIG).sourcesSamlMetadata({
slug: this.source.slug,
}).then(m => {
return html`<ak-codemirror mode="xml"><textarea class="pf-c-form-control" readonly>${m.metadata}</textarea></ak-codemirror>`;
})
)}
</div>
<div class="pf-c-card__footer">
<a class="pf-c-button pf-m-primary" target="_blank" href="${SAMLSource.appUrl(this.source.slug, "metadata/")}">
<a class="pf-c-button pf-m-primary" target="_blank" href="${AppURLManager.sourceSAML(this.source.slug, "metadata/")}">
${gettext("Download")}
</a>
</div>

View File

@ -1,4 +1,6 @@
import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
import { Source, SourcesApi } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { COMMON_STYLES } from "../../common/styles";
import "../../elements/buttons/ModalButton";
@ -8,7 +10,6 @@ import { SpinnerSize } from "../../elements/Spinner";
import "./LDAPSourceViewPage";
import "./OAuthSourceViewPage";
import "./SAMLSourceViewPage";
import { Source } from "../../api/Sources";
@customElement("ak-source-view")
export class SourceViewPage extends LitElement {
@ -19,7 +20,11 @@ export class SourceViewPage extends LitElement {
@property({ type: String })
set sourceSlug(slug: string) {
Source.get(slug).then((app) => (this.source = app));
new SourcesApi(DEFAULT_CONFIG).sourcesAllRead({
slug: slug
}).then((source) => {
this.source = source;
});
}
@property({ attribute: false })
@ -45,7 +50,7 @@ export class SourceViewPage extends LitElement {
</div>
</div>`;
}
switch (this.source?.object_type) {
switch (this.source?.objectType) {
case "ldap":
return html`<ak-source-ldap-view sourceSlug=${this.source.slug}></ak-source-ldap-view>`;
case "oauth":
@ -53,7 +58,7 @@ export class SourceViewPage extends LitElement {
case "saml":
return html`<ak-source-saml-view sourceSlug=${this.source.slug}></ak-source-saml-view>`;
default:
return html`<p>Invalid source type ${this.source.object_type}</p>`;
return html`<p>Invalid source type ${this.source.objectType}</p>`;
}
}
}

View File

@ -1,7 +1,6 @@
import { gettext } from "django";
import { customElement, html, property, TemplateResult } from "lit-element";
import { AKResponse } from "../../api/Client";
import { Source } from "../../api/Sources";
import { TableColumn } from "../../elements/table/Table";
import { TablePage } from "../../elements/table/TablePage";
@ -10,6 +9,9 @@ import "../../elements/buttons/SpinnerButton";
import "../../elements/buttons/Dropdown";
import { until } from "lit-html/directives/until";
import { PAGE_SIZE } from "../../constants";
import { Source, SourcesApi } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { AdminURLManager } from "../../api/legacy";
@customElement("ak-source-list")
export class SourceListPage extends TablePage<Source> {
@ -30,10 +32,10 @@ export class SourceListPage extends TablePage<Source> {
order = "name";
apiEndpoint(page: number): Promise<AKResponse<Source>> {
return Source.list({
return new SourcesApi(DEFAULT_CONFIG).sourcesAllList({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
pageSize: PAGE_SIZE,
search: this.search || "",
});
}
@ -41,7 +43,7 @@ export class SourceListPage extends TablePage<Source> {
columns(): TableColumn[] {
return [
new TableColumn("Name", "name"),
new TableColumn("Type", "verbose_name"),
new TableColumn("Type", "verboseName"),
new TableColumn(""),
];
}
@ -52,15 +54,15 @@ export class SourceListPage extends TablePage<Source> {
<div>${item.name}</div>
${item.enabled ? html`` : html`<small>${gettext("Disabled")}</small>`}
</a>`,
html`${item.verbose_name}`,
html`${item.verboseName}`,
html`
<ak-modal-button href="${Source.adminUrl(`${item.pk}/update/`)}">
<ak-modal-button href="${AdminURLManager.sources(`${item.pk}/update/`)}">
<ak-spinner-button slot="trigger" class="pf-m-secondary">
${gettext("Edit")}
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>
<ak-modal-button href="${Source.adminUrl(`${item.pk}/delete/`)}">
<ak-modal-button href="${AdminURLManager.sources(`${item.pk}/delete/`)}">
<ak-spinner-button slot="trigger" class="pf-m-danger">
${gettext("Delete")}
</ak-spinner-button>
@ -78,7 +80,7 @@ export class SourceListPage extends TablePage<Source> {
<i class="fas fa-caret-down pf-c-dropdown__toggle-icon" aria-hidden="true"></i>
</button>
<ul class="pf-c-dropdown__menu" hidden>
${until(Source.getTypes().then((types) => {
${until(new SourcesApi(DEFAULT_CONFIG).sourcesAllTypes({}).then((types) => {
return types.map((type) => {
return html`<li>
<ak-modal-button href="${type.link}">

View File

@ -6,8 +6,10 @@ import { TablePage } from "../../elements/table/TablePage";
import "../../elements/buttons/ModalButton";
import "../../elements/buttons/SpinnerButton";
import { TableColumn } from "../../elements/table/Table";
import { Invitation } from "../../api/Invitations";
import { PAGE_SIZE } from "../../constants";
import { Invitation, StagesApi } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { AdminURLManager } from "../../api/legacy";
@customElement("ak-stage-invitation-list")
export class InvitationListPage extends TablePage<Invitation> {
@ -28,10 +30,10 @@ export class InvitationListPage extends TablePage<Invitation> {
order = "expires";
apiEndpoint(page: number): Promise<AKResponse<Invitation>> {
return Invitation.list({
return new StagesApi(DEFAULT_CONFIG).stagesInvitationInvitationsList({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
pageSize: PAGE_SIZE,
search: this.search || "",
});
}
@ -48,10 +50,10 @@ export class InvitationListPage extends TablePage<Invitation> {
row(item: Invitation): TemplateResult[] {
return [
html`${item.pk}`,
html`${item.created_by.username}`,
html`${new Date(item.expires * 1000).toLocaleString()}`,
html`${item.createdBy?.username}`,
html`${item.expires?.toLocaleString()}`,
html`
<ak-modal-button href="${Invitation.adminUrl(`${item.pk}/delete/`)}">
<ak-modal-button href="${AdminURLManager.stageInvitations(`${item.pk}/delete/`)}">
<ak-spinner-button slot="trigger" class="pf-m-danger">
${gettext("Delete")}
</ak-spinner-button>
@ -62,7 +64,7 @@ export class InvitationListPage extends TablePage<Invitation> {
renderToolbar(): TemplateResult {
return html`
<ak-modal-button href=${Invitation.adminUrl("create/")}>
<ak-modal-button href=${AdminURLManager.stageInvitations("create/")}>
<ak-spinner-button slot="trigger" class="pf-m-primary">
${gettext("Create")}
</ak-spinner-button>

View File

@ -6,8 +6,10 @@ import { TablePage } from "../../elements/table/TablePage";
import "../../elements/buttons/ModalButton";
import "../../elements/buttons/SpinnerButton";
import { TableColumn } from "../../elements/table/Table";
import { Prompt } from "../../api/Prompts";
import { PAGE_SIZE } from "../../constants";
import { Prompt, StagesApi } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { AdminURLManager } from "../../api/legacy";
@customElement("ak-stage-prompt-list")
export class PromptListPage extends TablePage<Prompt> {
@ -28,10 +30,10 @@ export class PromptListPage extends TablePage<Prompt> {
order = "order";
apiEndpoint(page: number): Promise<AKResponse<Prompt>> {
return Prompt.list({
return new StagesApi(DEFAULT_CONFIG).stagesPromptPromptsList({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
pageSize: PAGE_SIZE,
search: this.search || "",
});
}
@ -49,21 +51,21 @@ export class PromptListPage extends TablePage<Prompt> {
row(item: Prompt): TemplateResult[] {
return [
html`${item.field_key}`,
html`${item.fieldKey}`,
html`${item.label}`,
html`${item.type}`,
html`${item.order}`,
html`${item.promptstage_set.map((stage) => {
html`${item.promptstageSet?.map((stage) => {
return html`<li>${stage.name}</li>`;
})}`,
html`
<ak-modal-button href="${Prompt.adminUrl(`${item.pk}/update/`)}">
<ak-modal-button href="${AdminURLManager.stagePrompts(`${item.pk}/update/`)}">
<ak-spinner-button slot="trigger" class="pf-m-secondary">
${gettext("Edit")}
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>
<ak-modal-button href="${Prompt.adminUrl(`${item.pk}/delete/`)}">
<ak-modal-button href="${AdminURLManager.stagePrompts(`${item.pk}/delete/`)}">
<ak-spinner-button slot="trigger" class="pf-m-danger">
${gettext("Delete")}
</ak-spinner-button>
@ -74,7 +76,7 @@ export class PromptListPage extends TablePage<Prompt> {
renderToolbar(): TemplateResult {
return html`
<ak-modal-button href=${Prompt.adminUrl("create/")}>
<ak-modal-button href=${AdminURLManager.stagePrompts("create/")}>
<ak-spinner-button slot="trigger" class="pf-m-primary">
${gettext("Create")}
</ak-spinner-button>

View File

@ -8,8 +8,10 @@ import "../../elements/buttons/ModalButton";
import "../../elements/buttons/SpinnerButton";
import "../../elements/buttons/Dropdown";
import { until } from "lit-html/directives/until";
import { Stage } from "../../api/Flows";
import { PAGE_SIZE } from "../../constants";
import { Stage, StagesApi } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { AdminURLManager } from "../../api/legacy";
@customElement("ak-stage-list")
export class StageListPage extends TablePage<Stage> {
@ -30,10 +32,10 @@ export class StageListPage extends TablePage<Stage> {
order = "name";
apiEndpoint(page: number): Promise<AKResponse<Stage>> {
return Stage.list({
return new StagesApi(DEFAULT_CONFIG).stagesAllList({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
pageSize: PAGE_SIZE,
search: this.search || "",
});
}
@ -50,21 +52,21 @@ export class StageListPage extends TablePage<Stage> {
return [
html`<div>
<div>${item.name}</div>
<small>${item.verbose_name}</small>
<small>${item.verboseName}</small>
</div>`,
html`${item.flow_set.map((flow) => {
html`${item.flowSet?.map((flow) => {
return html`<a href="#/flow/flows/${flow.slug}">
<code>${flow.slug}</code>
</a>`;
})}`,
html`
<ak-modal-button href="${Stage.adminUrl(`${item.pk}/update/`)}">
<ak-modal-button href="${AdminURLManager.stages(`${item.pk}/update/`)}">
<ak-spinner-button slot="trigger" class="pf-m-secondary">
${gettext("Edit")}
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>
<ak-modal-button href="${Stage.adminUrl(`${item.pk}/delete/`)}">
<ak-modal-button href="${AdminURLManager.stages(`${item.pk}/delete/`)}">
<ak-spinner-button slot="trigger" class="pf-m-danger">
${gettext("Delete")}
</ak-spinner-button>
@ -82,7 +84,7 @@ export class StageListPage extends TablePage<Stage> {
<i class="fas fa-caret-down pf-c-dropdown__toggle-icon" aria-hidden="true"></i>
</button>
<ul class="pf-c-dropdown__menu" hidden>
${until(Stage.getTypes().then((types) => {
${until(new StagesApi(DEFAULT_CONFIG).stagesAllTypes({}).then((types) => {
return types.map((type) => {
return html`<li>
<ak-modal-button href="${type.link}">

View File

@ -7,10 +7,11 @@ import "../../elements/buttons/ModalButton";
import "../../elements/buttons/SpinnerButton";
import "../../elements/buttons/ActionButton";
import { TableColumn } from "../../elements/table/Table";
import { SystemTask, TaskStatus } from "../../api/SystemTask";
import { AdminApi, Task, TaskStatusEnum } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
@customElement("ak-system-task-list")
export class SystemTaskListPage extends TablePage<SystemTask> {
export class SystemTaskListPage extends TablePage<Task> {
searchEnabled(): boolean {
return false;
}
@ -27,18 +28,15 @@ export class SystemTaskListPage extends TablePage<SystemTask> {
@property()
order = "slug";
apiEndpoint(page: number): Promise<AKResponse<SystemTask>> {
return SystemTask.list({
ordering: this.order,
page: page,
}).then((tasks) => {
apiEndpoint(page: number): Promise<AKResponse<Task>> {
return new AdminApi(DEFAULT_CONFIG).adminSystemTasksList().then((tasks) => {
return {
pagination: {
count: tasks.length,
total_pages: 1,
start_index: 0,
end_index: tasks.length,
current: 1,
totalPages: 1,
startIndex: 0,
endIndex: tasks.length,
current: page,
},
results: tasks,
};
@ -56,29 +54,34 @@ export class SystemTaskListPage extends TablePage<SystemTask> {
];
}
taskStatus(task: SystemTask): TemplateResult {
taskStatus(task: Task): TemplateResult {
switch (task.status) {
case TaskStatus.SUCCESSFUL:
case TaskStatusEnum.Successful:
return html`<i class="fas fa-check pf-m-success" > </i> ${gettext("Successful")}`;
case TaskStatus.WARNING:
case TaskStatusEnum.Warning:
return html`<i class="fas fa-exclamation-triangle pf-m-warning" > </i> ${gettext("Warning")}`;
case TaskStatus.ERROR:
case TaskStatusEnum.Error:
return html`<i class="fas fa-times pf-m-danger" > </i> ${gettext("Error")}`;
default:
return html`<i class="fas fa-question-circle" > </i> ${gettext("Unknown")}`;
}
}
row(item: SystemTask): TemplateResult[] {
row(item: Task): TemplateResult[] {
return [
html`${item.task_name}`,
html`${item.task_description}`,
html`${new Date(item.task_finish_timestamp * 1000).toLocaleString()}`,
html`${item.taskName}`,
html`${item.taskDescription}`,
html`${item.taskFinishTimestamp.toLocaleString()}`,
this.taskStatus(item),
html`${item.messages.map(m => {
return html`<li>${m}</li>`;
})}`,
html`<ak-action-button url=${SystemTask.retry(item.task_name)}>
html`<ak-action-button
.apiRequest=${() => {
return new AdminApi(DEFAULT_CONFIG).adminSystemTasksRetry({
id: item.taskName
});
}}>
${gettext("Retry Task")}
</ak-action-button>`,
];

View File

@ -7,8 +7,10 @@ import "../../elements/buttons/ModalButton";
import "../../elements/buttons/Dropdown";
import "../../elements/buttons/TokenCopyButton";
import { TableColumn } from "../../elements/table/Table";
import { Token } from "../../api/Tokens";
import { PAGE_SIZE } from "../../constants";
import { CoreApi, Token } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { AdminURLManager } from "../../api/legacy";
@customElement("ak-token-list")
export class TokenListPage extends TablePage<Token> {
@ -29,10 +31,10 @@ export class TokenListPage extends TablePage<Token> {
order = "expires";
apiEndpoint(page: number): Promise<AKResponse<Token>> {
return Token.list({
return new CoreApi(DEFAULT_CONFIG).coreTokensList({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
pageSize: PAGE_SIZE,
search: this.search || "",
});
}
@ -52,9 +54,9 @@ export class TokenListPage extends TablePage<Token> {
html`${item.identifier}`,
html`${item.user.username}`,
html`${item.expiring ? "Yes" : "No"}`,
html`${item.expiring ? new Date(item.expires * 1000).toLocaleString() : "-"}`,
html`${item.expiring ? item.expires?.toLocaleString() : "-"}`,
html`
<ak-modal-button href="${Token.adminUrl(`${item.identifier}/delete/`)}">
<ak-modal-button href="${AdminURLManager.tokens(`${item.identifier}/delete/`)}">
<ak-spinner-button slot="trigger" class="pf-m-danger">
${gettext("Delete")}
</ak-spinner-button>

View File

@ -6,8 +6,10 @@ import "../../elements/buttons/ModalButton";
import "../../elements/buttons/Dropdown";
import "../../elements/buttons/TokenCopyButton";
import { Table, TableColumn } from "../../elements/table/Table";
import { Token } from "../../api/Tokens";
import { PAGE_SIZE } from "../../constants";
import { CoreApi, Token } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { AdminURLManager } from "../../api/legacy";
@customElement("ak-token-user-list")
export class UserTokenList extends Table<Token> {
@ -15,14 +17,16 @@ export class UserTokenList extends Table<Token> {
return true;
}
expandable = true;
@property()
order = "expires";
apiEndpoint(page: number): Promise<AKResponse<Token>> {
return Token.list({
return new CoreApi(DEFAULT_CONFIG).coreTokensList({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
pageSize: PAGE_SIZE,
search: this.search || "",
});
}
@ -30,9 +34,6 @@ export class UserTokenList extends Table<Token> {
columns(): TableColumn[] {
return [
new TableColumn("Identifier", "identifier"),
new TableColumn("User", "user"),
new TableColumn("Expires?", "expiring"),
new TableColumn("Expiry date", "expires"),
new TableColumn(""),
];
}
@ -49,20 +50,52 @@ export class UserTokenList extends Table<Token> {
`;
}
renderExpanded(item: Token): TemplateResult {
return html`
<td role="cell" colspan="3">
<div class="pf-c-table__expandable-row-content">
<dl class="pf-c-description-list pf-m-horizontal">
<div class="pf-c-description-list__group">
<dt class="pf-c-description-list__term">
<span class="pf-c-description-list__text">${gettext("User")}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">${item.user.username}</div>
</dd>
</div>
<div class="pf-c-description-list__group">
<dt class="pf-c-description-list__term">
<span class="pf-c-description-list__text">${gettext("Expiring")}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">${item.expiring ? "Yes" : "No"}</div>
</dd>
</div>
<div class="pf-c-description-list__group">
<dt class="pf-c-description-list__term">
<span class="pf-c-description-list__text">${gettext("Expiring")}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">${item.expiring ? item.expires?.toLocaleString() : "-"}</div>
</dd>
</div>
</dl>
</div>
</td>
<td></td>`;
}
row(item: Token): TemplateResult[] {
return [
html`${item.identifier}`,
html`${item.user.username}`,
html`${item.expiring ? "Yes" : "No"}`,
html`${item.expiring ? new Date(item.expires * 1000).toLocaleString() : "-"}`,
html`
<ak-modal-button href="${Token.userUrl(`${item.identifier}/update/`)}">
<ak-modal-button href="${AdminURLManager.tokens(`${item.identifier}/update/`)}">
<ak-spinner-button slot="trigger" class="pf-m-secondary">
${gettext("Edit")}
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>
<ak-modal-button href="${Token.userUrl(`${item.identifier}/delete/`)}">
<ak-modal-button href="${AdminURLManager.tokens(`${item.identifier}/delete/`)}">
<ak-spinner-button slot="trigger" class="pf-m-danger">
${gettext("Delete")}
</ak-spinner-button>

View File

@ -7,8 +7,10 @@ import "../../elements/buttons/ModalButton";
import "../../elements/buttons/Dropdown";
import "../../elements/buttons/ActionButton";
import { TableColumn } from "../../elements/table/Table";
import { User } from "../../api/Users";
import { PAGE_SIZE } from "../../constants";
import { CoreApi, User } from "../../api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { AdminURLManager } from "../../api/legacy";
@customElement("ak-user-list")
export class UserListPage extends TablePage<User> {
@ -29,10 +31,10 @@ export class UserListPage extends TablePage<User> {
order = "username";
apiEndpoint(page: number): Promise<AKResponse<User>> {
return User.list({
return new CoreApi(DEFAULT_CONFIG).coreUsersList({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
pageSize: PAGE_SIZE,
search: this.search || "",
});
}
@ -52,10 +54,10 @@ export class UserListPage extends TablePage<User> {
<div>${item.username}</div>
<small>${item.name}</small>
</div>`,
html`${item.is_active ? "Yes" : "No"}`,
html`${new Date(item.last_login * 1000).toLocaleString()}`,
html`${item.isActive ? "Yes" : "No"}`,
html`${item.lastLogin?.toLocaleString()}`,
html`
<ak-modal-button href="${User.adminUrl(`${item.pk}/update/`)}">
<ak-modal-button href="${AdminURLManager.users(`${item.pk}/update/`)}">
<ak-spinner-button slot="trigger" class="pf-m-secondary">
${gettext("Edit")}
</ak-spinner-button>
@ -63,19 +65,19 @@ export class UserListPage extends TablePage<User> {
</ak-modal-button>
<ak-dropdown class="pf-c-dropdown">
<button class="pf-c-dropdown__toggle pf-m-primary" type="button">
<span class="pf-c-dropdown__toggle-text">${gettext(item.is_active ? "Disable" : "Enable")}</span>
<span class="pf-c-dropdown__toggle-text">${gettext(item.isActive ? "Disable" : "Enable")}</span>
<i class="fas fa-caret-down pf-c-dropdown__toggle-icon" aria-hidden="true"></i>
</button>
<ul class="pf-c-dropdown__menu" hidden>
<li>
${item.is_active ?
html`<ak-modal-button href="${User.adminUrl(`${item.pk}/disable/`)}">
${item.isActive ?
html`<ak-modal-button href="${AdminURLManager.users(`${item.pk}/disable/`)}">
<button slot="trigger" class="pf-c-dropdown__menu-item">
${gettext("Disable")}
</button>
<div slot="modal"></div>
</ak-modal-button>`:
html`<ak-modal-button href="${User.adminUrl(`${item.pk}/enable/`)}">
html`<ak-modal-button href="${AdminURLManager.users(`${item.pk}/enable/`)}">
<button slot="trigger" class="pf-c-dropdown__menu-item">
${gettext("Enable")}
</button>
@ -84,7 +86,7 @@ export class UserListPage extends TablePage<User> {
</li>
<li class="pf-c-divider" role="separator"></li>
<li>
<ak-modal-button href="${User.adminUrl(`${item.pk}/delete/`)}">
<ak-modal-button href="${AdminURLManager.users(`${item.pk}/delete/`)}">
<button slot="trigger" class="pf-c-dropdown__menu-item">
${gettext("Delete")}
</button>
@ -93,7 +95,7 @@ export class UserListPage extends TablePage<User> {
</li>
</ul>
</ak-dropdown>
<ak-action-button method="GET" url="${User.adminUrl(`${item.pk}/reset/`)}">
<ak-action-button method="GET" url="${AdminURLManager.users(`${item.pk}/reset/`)}">
${gettext("Reset Password")}
</ak-action-button>
<a class="pf-c-button pf-m-tertiary" href="${`-/impersonation/${item.pk}/`}">
@ -104,7 +106,7 @@ export class UserListPage extends TablePage<User> {
renderToolbar(): TemplateResult {
return html`
<ak-modal-button href=${User.adminUrl("create/")}>
<ak-modal-button href=${AdminURLManager.users("create/")}>
<ak-spinner-button slot="trigger" class="pf-m-primary">
${gettext("Create")}
</ak-spinner-button>