web: start implementing provider list

This commit is contained in:
Jens Langhammer 2021-02-04 09:54:00 +01:00
parent 53f002a123
commit 178417fe67
7 changed files with 197 additions and 4 deletions

View File

@ -8758,6 +8758,14 @@ definitions:
enum:
- global
- per_provider
assigned_application_slug:
title: Assigned application slug
type: string
readOnly: true
assigned_application_name:
title: Assigned application name
type: string
readOnly: true
verbose_name:
title: Verbose name
type: string
@ -8819,6 +8827,14 @@ definitions:
description: User/Group Attribute used for the user part of the HTTP-Basic
Header. If not set, the user's Email address is used.
type: string
assigned_application_slug:
title: Assigned application slug
type: string
readOnly: true
assigned_application_name:
title: Assigned application name
type: string
readOnly: true
verbose_name:
title: Verbose name
type: string
@ -8919,6 +8935,14 @@ definitions:
type: string
format: uuid
x-nullable: true
assigned_application_slug:
title: Assigned application slug
type: string
readOnly: true
assigned_application_name:
title: Assigned application name
type: string
readOnly: true
verbose_name:
title: Verbose name
type: string

View File

@ -4,6 +4,10 @@ export class Provider {
pk: number;
name: string;
authorization_flow: string;
assigned_application_slug?: string;
assigned_application_name?: string;
verbose_name: string;
verbose_name_plural: string;
@ -11,11 +15,15 @@ export class Provider {
throw Error();
}
static get(slug: string): Promise<Provider> {
return DefaultClient.fetch<Provider>(["providers", "all", slug]);
static get(id: number): Promise<Provider> {
return DefaultClient.fetch<Provider>(["providers", "all", id]);
}
static list(filter?: QueryArguments): Promise<PBResponse<Provider>> {
return DefaultClient.fetch<PBResponse<Provider>>(["providers", "all"], filter);
}
static adminUrl(rest: string): string {
return `/administration/providers/${rest}`;
}
}

View File

@ -1,6 +1,7 @@
import { html, TemplateResult } from "lit-html";
export const SLUG_REGEX = "[-a-zA-Z0-9_]+";
export const ID_REGEX = "\d+";
export class Route {
url: RegExp;

View File

@ -26,7 +26,7 @@ export const SIDEBAR_ITEMS: SidebarItem[] = [
new SidebarItem("Sources", "/administration/sources/").activeWhen(
`^/sources/(?<slug>${SLUG_REGEX})$`,
),
new SidebarItem("Providers", "/administration/providers/"),
new SidebarItem("Providers", "/providers"),
new SidebarItem("Outposts", "/administration/outposts/"),
new SidebarItem("Outpost Service Connections", "/administration/outposts/service_connections/"),
).when((): Promise<boolean> => {

View File

@ -0,0 +1,128 @@
import { gettext } from "django";
import { customElement, html, property, TemplateResult } from "lit-element";
import { Provider } from "../../api/Providers";
import { PBResponse } from "../../api/Client";
import { TablePage } from "../../elements/table/TablePage";
import "../../elements/buttons/ModalButton";
import "../../elements/buttons/SpinnerButton";
import { TableColumn } from "../../elements/table/Table";
@customElement("ak-provider-list")
export class ProviderListPage extends TablePage<Provider> {
searchEnabled(): boolean {
return true;
}
pageTitle(): string {
return gettext("Provider");
}
pageDescription(): string {
return gettext("Provide support for protocols like SAML and OAuth to assigned applications.");
}
pageIcon(): string {
return gettext("pf-icon pf-icon-integration");
}
@property()
order = "name";
apiEndpoint(page: number): Promise<PBResponse<Provider>> {
return Provider.list({
ordering: this.order,
page: page,
search: this.search || "",
});
}
columns(): TableColumn[] {
return [
new TableColumn("Name", "name"),
new TableColumn("Application"),
new TableColumn("Type", "type"),
new TableColumn(""),
];
}
row(item: Provider): TemplateResult[] {
return [
html`<a href="#/providers/${item.pk}">
${item.name}
</a>`,
item.assigned_application_name ?
html`<i class="pf-icon pf-icon-ok"></i>
${gettext("Assigned to application ")}
<a href="#/applications/${item.assigned_application_slug}">${item.assigned_application_name}</a>` :
html`<i class="pf-icon pf-icon-warning-triangle"></i>
${gettext("Warning: Provider not assigned to any application.")}`,
html`${item.verbose_name}`,
html`
<ak-modal-button href="${Provider.adminUrl(`${item.pk}/update/`)}">
<ak-spinner-button slot="trigger" class="pf-m-secondary">
Edit
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>&nbsp;
<ak-modal-button href="${Provider.adminUrl(`${item.pk}/delete/`)}">
<ak-spinner-button slot="trigger" class="pf-m-danger">
Delete
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>
`,
];
}
renderToolbar(): TemplateResult {
return html`
<ak-dropdown class="pf-c-dropdown">
<button class="pf-m-primary pf-c-dropdown__toggle" type="button">
<span class="pf-c-dropdown__toggle-text">${gettext("Create")}</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>
<ak-modal-button href="${Provider.adminUrl(`/create/?type=OAuth2Provider`)}">
<button slot="trigger" class="pf-c-dropdown__menu-item">${gettext("OAuth2/OpenID Provider")}<br>
<small>
${gettext("OAuth2 Provider for generic OAuth and OpenID Connect Applications.")}
</small>
</button>
<div slot="modal"></div>
</ak-modal-button>
</li>
<li>
<ak-modal-button href="${Provider.adminUrl(`/create/?type=ProxyProvider`)}">
<button slot="trigger" class="pf-c-dropdown__menu-item">${gettext("Proxy Provider")}<br>
<small>
${gettext("Protect applications that don't support any of the other Protocols by using a Reverse-Proxy.")}
</small>
</button>
<div slot="modal"></div>
</ak-modal-button>
</li>
<li>
<ak-modal-button href="${Provider.adminUrl(`/create/?type=SAMLProvider`)}">
<button slot="trigger" class="pf-c-dropdown__menu-item">${gettext("SAML Provider")}<br>
<small>
${gettext("SAML 2.0 Endpoint for applications which support SAML.")}
</small>
</button>
<div slot="modal"></div>
</ak-modal-button>
</li>
<li>
<ak-modal-button href="${Provider.adminUrl(`/create/saml/from-metadata`)}/">
<button slot="trigger" class="pf-c-dropdown__menu-item">${gettext("SAML Provider from Metadata")}<br>
<small>
${gettext("Create a SAML Provider by importing its Metadata.")}
</small>
</button>
<div slot="modal"></div>
</ak-modal-button>
</li>
</ul>
</ak-dropdown>
${super.renderToolbar()}`;
}
}

View File

@ -0,0 +1,26 @@
import { gettext } from "django";
import { customElement, html, LitElement, property, TemplateResult } from "lit-element";
import { Provider } from "../../api/Providers";
import { PBResponse } from "../../api/Client";
import { TablePage } from "../../elements/table/TablePage";
import "../../elements/buttons/ModalButton";
import "../../elements/buttons/SpinnerButton";
import { TableColumn } from "../../elements/table/Table";
@customElement("ak-provider-view")
export class ProviderViewPage extends LitElement {
@property()
set args(value: { [key: string]: number }) {
this.providerID = value.id;
}
@property()
set providerID(value: number) {
Provider.get(value).then((app) => (this.provider = app));
}
@property({ attribute: false })
provider?: Provider;
}

View File

@ -1,5 +1,5 @@
import { html } from "lit-html";
import { Route, SLUG_REGEX } from "./elements/router/Route";
import { Route, SLUG_REGEX, ID_REGEX } from "./elements/router/Route";
import "./pages/LibraryPage";
import "./pages/admin-overview/AdminOverviewPage";
@ -10,6 +10,8 @@ import "./pages/flows/FlowViewPage";
import "./pages/events/EventListPage";
import "./pages/events/TransportListPage";
import "./pages/events/RuleListPage";
import "./pages/providers/ProviderListPage";
import "./pages/providers/ProviderViewPage";
import "./pages/property-mappings/PropertyMappingListPage";
export const ROUTES: Route[] = [
@ -18,6 +20,10 @@ export const ROUTES: Route[] = [
new Route(new RegExp("^#.*")).redirect("/library"),
new Route(new RegExp("^/library$"), html`<ak-library></ak-library>`),
new Route(new RegExp("^/administration/overview$"), html`<ak-admin-overview></ak-admin-overview>`),
new Route(new RegExp("^/providers$"), html`<ak-provider-list></ak-provider-list>`),
new Route(new RegExp(`^/providers/(?<id>${ID_REGEX})$`)).then((args) => {
return html`<ak-provider-view .args=${args}></ak-provider-view>`;
}),
new Route(new RegExp("^/applications$"), html`<ak-application-list></ak-application-list>`),
new Route(new RegExp(`^/applications/(?<slug>${SLUG_REGEX})$`)).then((args) => {
return html`<ak-application-view .args=${args}></ak-application-view>`;