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--BackgroundColor: var(--ak-dark-background-light);
|
||||
}
|
||||
.pf-c-card__title,
|
||||
.pf-c-card__header-main,
|
||||
.pf-c-card__body {
|
||||
color: var(--ak-dark-foreground);
|
||||
|
|
|
@ -23,7 +23,7 @@ export const SIDEBAR_ITEMS: SidebarItem[] = [
|
|||
new SidebarItem("Applications", "/applications").activeWhen(
|
||||
`^/applications/(?<slug>${SLUG_REGEX})$`
|
||||
),
|
||||
new SidebarItem("Sources", "/administration/sources/").activeWhen(
|
||||
new SidebarItem("Sources", "/sources").activeWhen(
|
||||
`^/sources/(?<slug>${SLUG_REGEX})$`,
|
||||
),
|
||||
new SidebarItem("Providers", "/providers"),
|
||||
|
|
|
@ -23,11 +23,6 @@ export class OAuth2ProviderViewPage extends Page {
|
|||
return "pf-icon pf-icon-integration";
|
||||
}
|
||||
|
||||
@property()
|
||||
set args(value: { [key: string]: number }) {
|
||||
this.providerID = value.id;
|
||||
}
|
||||
|
||||
@property({type: Number})
|
||||
set providerID(value: number) {
|
||||
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 { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
||||
import { CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
||||
import { COMMON_STYLES } from "../../common/styles";
|
||||
|
||||
import "../../elements/Tabs";
|
||||
import "../../elements/AdminLoginsChart";
|
||||
import "../../elements/buttons/ModalButton";
|
||||
import "../../elements/buttons/SpinnerButton";
|
||||
import "../../elements/policies/BoundPoliciesList";
|
||||
import { SpinnerSize } from "../../elements/Spinner";
|
||||
|
||||
import "./LDAPSourceViewPage";
|
||||
import "./OAuthSourceViewPage";
|
||||
import { Source } from "../../api/Sources";
|
||||
|
||||
@customElement("ak-source-view")
|
||||
|
@ -16,48 +16,39 @@ export class SourceViewPage extends LitElement {
|
|||
this.sourceSlug = value.slug;
|
||||
}
|
||||
|
||||
@property()
|
||||
set sourceSlug(value: string) {
|
||||
Source.get(value).then((source) => (this.source = source));
|
||||
@property({ type: String })
|
||||
set sourceSlug(slug: string) {
|
||||
Source.get(slug).then((app) => (this.source = app));
|
||||
}
|
||||
|
||||
@property({ attribute: false })
|
||||
source?: Source;
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return COMMON_STYLES.concat(
|
||||
css`
|
||||
img.pf-icon {
|
||||
max-height: 24px;
|
||||
}
|
||||
`
|
||||
);
|
||||
return COMMON_STYLES;
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
if (!this.source) {
|
||||
return html``;
|
||||
return html`<div class="pf-c-empty-state pf-m-full-height">
|
||||
<div class="pf-c-empty-state__content">
|
||||
<div class="pf-l-bullseye">
|
||||
<div class="pf-l-bullseye__item">
|
||||
<ak-spinner size="${SpinnerSize.XLarge}"></ak-spinner>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</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>`;
|
||||
}
|
||||
return html`<section class="pf-c-page__main-section pf-m-light">
|
||||
<div class="pf-c-content">
|
||||
<h1>
|
||||
<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>
|
||||
<ak-bound-policies-list .target=${this.source.pk}>
|
||||
</ak-bound-policies-list>
|
||||
</div>
|
||||
</div>
|
||||
</ak-tabs>`;
|
||||
}
|
||||
}
|
||||
|
|
Reference in New Issue