From e96d2fa66617332a52e6932e489892392202b222 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Mon, 29 Mar 2021 22:24:46 +0200 Subject: [PATCH] web/admin: migrate flows to web forms Signed-off-by: Jens Langhammer --- web/src/api/legacy.ts | 4 - web/src/pages/applications/ApplicationForm.ts | 2 +- web/src/pages/flows/FlowForm.ts | 115 ++++++++++++++++++ web/src/pages/flows/FlowImportForm.ts | 38 ++++++ web/src/pages/flows/FlowListPage.ts | 72 +++++++---- 5 files changed, 205 insertions(+), 26 deletions(-) create mode 100644 web/src/pages/flows/FlowForm.ts create mode 100644 web/src/pages/flows/FlowImportForm.ts diff --git a/web/src/api/legacy.ts b/web/src/api/legacy.ts index ae8462b14..d38d9610e 100644 --- a/web/src/api/legacy.ts +++ b/web/src/api/legacy.ts @@ -24,10 +24,6 @@ export class AdminURLManager { return `/administration/outpost_service_connections/${rest}`; } - static flows(rest: string): string { - return `/administration/flows/${rest}`; - } - static stages(rest: string): string { return `/administration/stages/${rest}`; } diff --git a/web/src/pages/applications/ApplicationForm.ts b/web/src/pages/applications/ApplicationForm.ts index 25a1bd943..e194566ea 100644 --- a/web/src/pages/applications/ApplicationForm.ts +++ b/web/src/pages/applications/ApplicationForm.ts @@ -63,7 +63,7 @@ export class ApplicationForm extends Form { ${Array.from(m).map(([group, providers]) => { return html` ${providers.map(p => { - const selected = (this.application?.provider?.pk === p.pk) || (this.provider === p.pk) + const selected = (this.application?.provider?.pk === p.pk) || (this.provider === p.pk); return html``; })} `; diff --git a/web/src/pages/flows/FlowForm.ts b/web/src/pages/flows/FlowForm.ts new file mode 100644 index 000000000..ba32c6af1 --- /dev/null +++ b/web/src/pages/flows/FlowForm.ts @@ -0,0 +1,115 @@ +import { Flow, FlowDesignationEnum, FlowsApi } from "authentik-api"; +import { gettext } from "django"; +import { customElement, property } from "lit-element"; +import { html, TemplateResult } from "lit-html"; +import { DEFAULT_CONFIG } from "../../api/Config"; +import { Form } from "../../elements/forms/Form"; +import { ifDefined } from "lit-html/directives/if-defined"; +import "../../elements/forms/HorizontalFormElement"; + +@customElement("ak-flow-form") +export class FlowForm extends Form { + + @property({attribute: false}) + flow?: Flow; + + getSuccessMessage(): string { + if (this.flow) { + return gettext("Successfully updated flow."); + } else { + return gettext("Successfully created flow."); + } + } + + send = (data: Flow): Promise => { + let writeOp: Promise; + if (this.flow) { + writeOp = new FlowsApi(DEFAULT_CONFIG).flowsInstancesUpdate({ + slug: this.flow.slug, + data: data + }); + } else { + writeOp = new FlowsApi(DEFAULT_CONFIG).flowsInstancesCreate({ + data: data + }); + } + const background = this.getFormFile(); + if (background) { + return writeOp.then(flow => { + return new FlowsApi(DEFAULT_CONFIG).flowsInstancesSetBackground({ + slug: flow.slug, + file: background + }); + }); + } + return writeOp; + }; + + renderDesignations(): TemplateResult { + return html` + + + + + + + + `; + } + + renderForm(): TemplateResult { + return html`
+ + + + + +

${gettext("Shown as the Title in Flow pages.")}

+
+ + +

${gettext("Visible in the URL.")}

+
+ + +

${gettext("Decides what this Flow is used for. For example, the Authentication flow is redirect to when an un-authenticated user visits authentik.")}

+
+ + +

${gettext("Background shown during execution.")}

+
+
`; + } + +} diff --git a/web/src/pages/flows/FlowImportForm.ts b/web/src/pages/flows/FlowImportForm.ts new file mode 100644 index 000000000..48161ef8a --- /dev/null +++ b/web/src/pages/flows/FlowImportForm.ts @@ -0,0 +1,38 @@ +import { Flow, FlowsApi } from "authentik-api"; +import { gettext } from "django"; +import { customElement } from "lit-element"; +import { html, TemplateResult } from "lit-html"; +import { DEFAULT_CONFIG } from "../../api/Config"; +import { Form } from "../../elements/forms/Form"; +import "../../elements/forms/HorizontalFormElement"; + +@customElement("ak-flow-import-form") +export class FlowImportForm extends Form { + + getSuccessMessage(): string { + return gettext("Successfully imported flow."); + } + + // eslint-disable-next-line + send = (data: Flow): Promise => { + const file = this.getFormFile(); + if (!file) { + throw new Error("No form data"); + } + return new FlowsApi(DEFAULT_CONFIG).flowsInstancesImportFlow({ + file: file + }); + }; + + renderForm(): TemplateResult { + return html`
+ + +

${gettext("Background shown during execution.")}

+
+
`; + } + +} diff --git a/web/src/pages/flows/FlowListPage.ts b/web/src/pages/flows/FlowListPage.ts index 1dc88d311..41d15f02e 100644 --- a/web/src/pages/flows/FlowListPage.ts +++ b/web/src/pages/flows/FlowListPage.ts @@ -6,11 +6,13 @@ import { TablePage } from "../../elements/table/TablePage"; import "../../elements/buttons/ModalButton"; import "../../elements/buttons/SpinnerButton"; import "../../elements/forms/DeleteForm"; +import "../../elements/forms/ModalForm"; +import "./FlowForm"; +import "./FlowImportForm"; import { TableColumn } from "../../elements/table/Table"; import { PAGE_SIZE } from "../../constants"; import { Flow, FlowsApi } from "authentik-api"; import { DEFAULT_CONFIG } from "../../api/Config"; -import { AdminURLManager } from "../../api/legacy"; @customElement("ak-flow-list") export class FlowListPage extends TablePage { @@ -60,48 +62,76 @@ export class FlowListPage extends TablePage { html`${Array.from(item.stages || []).length}`, html`${Array.from(item.policies || []).length}`, html` - - + + + ${gettext("Update")} + + + ${gettext("Update Flow")} + + + + + { return new FlowsApi(DEFAULT_CONFIG).flowsInstancesDelete({ - slug: item.slug || "" + slug: item.slug }); }}> - + ${gettext("Export")} - - `, + `, ]; } renderToolbar(): TemplateResult { return html` - - + + ${gettext("Create")} - -
-
- - + + + ${gettext("Create Flow")} + + + + + + + ${gettext("Import")} - -
-
+ + + ${gettext("Import Flow")} + + + + + ${super.renderToolbar()} `; }