web: add new sources view
This commit is contained in:
parent
ad91abe9de
commit
5dab198c47
|
@ -1,8 +0,0 @@
|
||||||
{% load humanize %}
|
|
||||||
{% load i18n %}
|
|
||||||
|
|
||||||
{% if last_sync %}
|
|
||||||
<i class="fas fa-check pf-m-success"></i> {% blocktrans with last_sync=last_sync|naturaltime %}Synced {{ last_sync }}.{% endblocktrans %}
|
|
||||||
{% else %}
|
|
||||||
<i class="fas fa-times pf-m-danger"></i> Not synced yet/Sync in Progress
|
|
||||||
{% endif %}
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
import { DefaultClient } from "../Client";
|
||||||
|
import { Source } from "../Sources";
|
||||||
|
|
||||||
|
export class LDAPSource extends Source {
|
||||||
|
server_uri: string;
|
||||||
|
bind_cn: string;
|
||||||
|
start_tls: boolean
|
||||||
|
base_dn: string;
|
||||||
|
additional_user_dn: string;
|
||||||
|
additional_group_dn: string;
|
||||||
|
user_object_filter: string;
|
||||||
|
group_object_filter: string;
|
||||||
|
group_membership_field: string;
|
||||||
|
object_uniqueness_field: string;
|
||||||
|
sync_users: boolean;
|
||||||
|
sync_users_password: boolean;
|
||||||
|
sync_groups: boolean;
|
||||||
|
sync_parent_group?: string;
|
||||||
|
property_mappings: string[];
|
||||||
|
property_mappings_group: string[];
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
throw Error();
|
||||||
|
}
|
||||||
|
|
||||||
|
static get(slug: string): Promise<LDAPSource> {
|
||||||
|
return DefaultClient.fetch<LDAPSource>(["sources", "ldap", slug]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static syncStatus(slug: string): Promise<{ last_sync?: number }> {
|
||||||
|
return DefaultClient.fetch(["sources", "ldap", slug, "sync_status"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -127,6 +127,7 @@ select[multiple] {
|
||||||
.pf-c-card {
|
.pf-c-card {
|
||||||
--pf-c-card--BackgroundColor: var(--ak-dark-background-light);
|
--pf-c-card--BackgroundColor: var(--ak-dark-background-light);
|
||||||
}
|
}
|
||||||
|
.pf-c-card__title,
|
||||||
.pf-c-card__header-main,
|
.pf-c-card__header-main,
|
||||||
.pf-c-card__body {
|
.pf-c-card__body {
|
||||||
color: var(--ak-dark-foreground);
|
color: var(--ak-dark-foreground);
|
||||||
|
|
|
@ -23,7 +23,7 @@ export const SIDEBAR_ITEMS: SidebarItem[] = [
|
||||||
new SidebarItem("Applications", "/applications").activeWhen(
|
new SidebarItem("Applications", "/applications").activeWhen(
|
||||||
`^/applications/(?<slug>${SLUG_REGEX})$`
|
`^/applications/(?<slug>${SLUG_REGEX})$`
|
||||||
),
|
),
|
||||||
new SidebarItem("Sources", "/administration/sources/").activeWhen(
|
new SidebarItem("Sources", "/sources").activeWhen(
|
||||||
`^/sources/(?<slug>${SLUG_REGEX})$`,
|
`^/sources/(?<slug>${SLUG_REGEX})$`,
|
||||||
),
|
),
|
||||||
new SidebarItem("Providers", "/providers"),
|
new SidebarItem("Providers", "/providers"),
|
||||||
|
|
|
@ -23,11 +23,6 @@ export class OAuth2ProviderViewPage extends Page {
|
||||||
return "pf-icon pf-icon-integration";
|
return "pf-icon pf-icon-integration";
|
||||||
}
|
}
|
||||||
|
|
||||||
@property()
|
|
||||||
set args(value: { [key: string]: number }) {
|
|
||||||
this.providerID = value.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
@property({type: Number})
|
@property({type: Number})
|
||||||
set providerID(value: number) {
|
set providerID(value: number) {
|
||||||
OAuth2Provider.get(value).then((app) => this.provider = app);
|
OAuth2Provider.get(value).then((app) => this.provider = app);
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
import { gettext } from "django";
|
||||||
|
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
|
||||||
|
import { COMMON_STYLES } from "../../common/styles";
|
||||||
|
|
||||||
|
import "../../elements/buttons/ModalButton";
|
||||||
|
import "../../elements/buttons/SpinnerButton";
|
||||||
|
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";
|
||||||
|
|
||||||
|
@customElement("ak-source-ldap-view")
|
||||||
|
export class LDAPSourceViewPage extends Page {
|
||||||
|
pageTitle(): string {
|
||||||
|
return gettext(`LDAP Source ${this.source?.name || ""}`);
|
||||||
|
}
|
||||||
|
pageDescription(): string | undefined {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pageIcon(): string {
|
||||||
|
return "pf-icon pf-icon-middleware";
|
||||||
|
}
|
||||||
|
|
||||||
|
@property({ type: String })
|
||||||
|
set sourceSlug(slug: string) {
|
||||||
|
LDAPSource.get(slug).then((s) => this.source = s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
source?: LDAPSource;
|
||||||
|
|
||||||
|
static get styles(): CSSResult[] {
|
||||||
|
return COMMON_STYLES;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.addEventListener("ak-refresh", () => {
|
||||||
|
if (!this.source?.slug) return;
|
||||||
|
this.sourceSlug = this.source?.slug;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderContent(): TemplateResult {
|
||||||
|
if (!this.source) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
return html`<ak-tabs>
|
||||||
|
<section slot="page-1" data-tab-title="${gettext("Overview")}" class="pf-c-page__main-section pf-m-no-padding-mobile">
|
||||||
|
<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__body">
|
||||||
|
<dl class="pf-c-description-list pf-m-2-col-on-lg">
|
||||||
|
<div class="pf-c-description-list__group">
|
||||||
|
<dt class="pf-c-description-list__term">
|
||||||
|
<span class="pf-c-description-list__text">${gettext("Name")}</span>
|
||||||
|
</dt>
|
||||||
|
<dd class="pf-c-description-list__description">
|
||||||
|
<div class="pf-c-description-list__text">${this.source.name}</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("Server URI")}</span>
|
||||||
|
</dt>
|
||||||
|
<dd class="pf-c-description-list__description">
|
||||||
|
<div class="pf-c-description-list__text">${this.source.server_uri}</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("Base DN")}</span>
|
||||||
|
</dt>
|
||||||
|
<dd class="pf-c-description-list__description">
|
||||||
|
<div class="pf-c-description-list__text">
|
||||||
|
<ul>
|
||||||
|
<li>${this.source.base_dn}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
<div class="pf-c-card__footer">
|
||||||
|
<ak-modal-button href="${Source.adminUrl(`${this.source.pk}/update/`)}">
|
||||||
|
<ak-spinner-button slot="trigger" class="pf-m-primary">
|
||||||
|
${gettext("Edit")}
|
||||||
|
</ak-spinner-button>
|
||||||
|
<div slot="modal"></div>
|
||||||
|
</ak-modal-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section slot="page-2" data-tab-title="${gettext("Sync")}" class="pf-c-page__main-section pf-m-no-padding-mobile">
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</ak-tabs>`;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,124 @@
|
||||||
|
import { gettext } from "django";
|
||||||
|
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
|
||||||
|
import { COMMON_STYLES } from "../../common/styles";
|
||||||
|
|
||||||
|
import "../../elements/buttons/ModalButton";
|
||||||
|
import "../../elements/buttons/SpinnerButton";
|
||||||
|
import "../../elements/CodeMirror";
|
||||||
|
import "../../elements/Tabs";
|
||||||
|
import { Page } from "../../elements/Page";
|
||||||
|
import { LDAPSource } from "../../api/sources/LDAP";
|
||||||
|
import { Source } from "../../api/Sources";
|
||||||
|
|
||||||
|
@customElement("ak-source-oauth-view")
|
||||||
|
export class OAuthSourceViewPage extends Page {
|
||||||
|
pageTitle(): string {
|
||||||
|
return gettext(`LDAP Source ${this.source?.name}`);
|
||||||
|
}
|
||||||
|
pageDescription(): string | undefined {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pageIcon(): string {
|
||||||
|
return "pf-icon pf-icon-middleware";
|
||||||
|
}
|
||||||
|
|
||||||
|
@property()
|
||||||
|
set args(value: { [key: string]: string }) {
|
||||||
|
this.sourceID = value.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property({ type: String })
|
||||||
|
set sourceID(value: string) {
|
||||||
|
LDAPSource.get(value).then((s) => this.source = s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
source?: LDAPSource;
|
||||||
|
|
||||||
|
static get styles(): CSSResult[] {
|
||||||
|
return COMMON_STYLES;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.addEventListener("ak-refresh", () => {
|
||||||
|
if (!this.source?.pk) return;
|
||||||
|
this.sourceID = this.source?.pk;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderContent(): TemplateResult {
|
||||||
|
if (!this.source) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
return html`<ak-tabs>
|
||||||
|
<section slot="page-1" data-tab-title="${gettext("Overview")}" class="pf-c-page__main-section pf-m-no-padding-mobile">
|
||||||
|
<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__body">
|
||||||
|
<dl class="pf-c-description-list pf-m-2-col-on-lg">
|
||||||
|
<div class="pf-c-description-list__group">
|
||||||
|
<dt class="pf-c-description-list__term">
|
||||||
|
<span class="pf-c-description-list__text">${gettext("Name")}</span>
|
||||||
|
</dt>
|
||||||
|
<dd class="pf-c-description-list__description">
|
||||||
|
<div class="pf-c-description-list__text">${this.source.name}</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("Server URI")}</span>
|
||||||
|
</dt>
|
||||||
|
<dd class="pf-c-description-list__description">
|
||||||
|
<div class="pf-c-description-list__text">${this.source.server_uri}</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("Base DN")}</span>
|
||||||
|
</dt>
|
||||||
|
<dd class="pf-c-description-list__description">
|
||||||
|
<div class="pf-c-description-list__text">
|
||||||
|
<ul>
|
||||||
|
<li>${this.source.base_dn}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
<div class="pf-c-card__footer">
|
||||||
|
<ak-modal-button href="${Source.adminUrl(`${this.source.pk}/update/`)}">
|
||||||
|
<ak-spinner-button slot="trigger" class="pf-m-primary">
|
||||||
|
${gettext("Edit")}
|
||||||
|
</ak-spinner-button>
|
||||||
|
<div slot="modal"></div>
|
||||||
|
</ak-modal-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pf-c-card pf-c-card-aggregate">
|
||||||
|
<div class="pf-c-card__title">
|
||||||
|
${gettext("Sync status")}
|
||||||
|
</div>
|
||||||
|
<div class="pf-c-card__body">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<div slot="page-2" data-tab-title="Policy Bindings" class="pf-c-page__main-section pf-m-no-padding-mobile">
|
||||||
|
<div class="pf-c-card">
|
||||||
|
<div class="pf-c-card__header">
|
||||||
|
<div class="pf-c-card__header-main">
|
||||||
|
${gettext("These policies control which users can authorize using these policies.")}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ak-bound-policies-list .target=${this.source.pk}>
|
||||||
|
</ak-bound-policies-list>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ak-tabs>`;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,12 @@
|
||||||
import { gettext } from "django";
|
import { CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
||||||
import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
|
||||||
import { COMMON_STYLES } from "../../common/styles";
|
import { COMMON_STYLES } from "../../common/styles";
|
||||||
|
|
||||||
import "../../elements/Tabs";
|
|
||||||
import "../../elements/AdminLoginsChart";
|
|
||||||
import "../../elements/buttons/ModalButton";
|
import "../../elements/buttons/ModalButton";
|
||||||
import "../../elements/buttons/SpinnerButton";
|
import "../../elements/buttons/SpinnerButton";
|
||||||
import "../../elements/policies/BoundPoliciesList";
|
import { SpinnerSize } from "../../elements/Spinner";
|
||||||
|
|
||||||
|
import "./LDAPSourceViewPage";
|
||||||
|
import "./OAuthSourceViewPage";
|
||||||
import { Source } from "../../api/Sources";
|
import { Source } from "../../api/Sources";
|
||||||
|
|
||||||
@customElement("ak-source-view")
|
@customElement("ak-source-view")
|
||||||
|
@ -16,48 +16,39 @@ export class SourceViewPage extends LitElement {
|
||||||
this.sourceSlug = value.slug;
|
this.sourceSlug = value.slug;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property()
|
@property({ type: String })
|
||||||
set sourceSlug(value: string) {
|
set sourceSlug(slug: string) {
|
||||||
Source.get(value).then((source) => (this.source = source));
|
Source.get(slug).then((app) => (this.source = app));
|
||||||
}
|
}
|
||||||
|
|
||||||
@property({attribute: false})
|
@property({ attribute: false })
|
||||||
source?: Source;
|
source?: Source;
|
||||||
|
|
||||||
static get styles(): CSSResult[] {
|
static get styles(): CSSResult[] {
|
||||||
return COMMON_STYLES.concat(
|
return COMMON_STYLES;
|
||||||
css`
|
|
||||||
img.pf-icon {
|
|
||||||
max-height: 24px;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render(): TemplateResult {
|
render(): TemplateResult {
|
||||||
if (!this.source) {
|
if (!this.source) {
|
||||||
return html``;
|
return html`<div class="pf-c-empty-state pf-m-full-height">
|
||||||
}
|
<div class="pf-c-empty-state__content">
|
||||||
return html`<section class="pf-c-page__main-section pf-m-light">
|
<div class="pf-l-bullseye">
|
||||||
<div class="pf-c-content">
|
<div class="pf-l-bullseye__item">
|
||||||
<h1>
|
<ak-spinner size="${SpinnerSize.XLarge}"></ak-spinner>
|
||||||
<i class="pf-icon pf-icon-middleware"></i>
|
|
||||||
${this.source?.name}
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<ak-tabs>
|
|
||||||
<div slot="page-2" data-tab-title="Policy Bindings" class="pf-c-page__main-section pf-m-no-padding-mobile">
|
|
||||||
<div class="pf-c-card">
|
|
||||||
<div class="pf-c-card__header">
|
|
||||||
<div class="pf-c-card__header-main">
|
|
||||||
${gettext("These policies control which users can access this application.")}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<ak-bound-policies-list .target=${this.source.pk}>
|
|
||||||
</ak-bound-policies-list>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ak-tabs>`;
|
</div>`;
|
||||||
|
}
|
||||||
|
switch (this.source?.object_type) {
|
||||||
|
case "ldap":
|
||||||
|
return html`<ak-source-ldap-view sourceSlug=${this.source.slug}></ak-source-ldap-view>`;
|
||||||
|
case "oauth2":
|
||||||
|
return html`<ak-source-oauth-view sourceSlug=${this.source.slug}></ak-source-oauth-view>`;
|
||||||
|
// case "proxy":
|
||||||
|
// return html`<ak-provider-proxy-view providerID=${this.source.pk}></ak-provider-proxy-view>`;
|
||||||
|
default:
|
||||||
|
return html`<p>Invalid source type ${this.source.object_type}</p>`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue