web/user: new end-user interface (#1404)

* web/user: migrate to top navbar

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* web/user: prepare config from server

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* re-sort

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* remove old interface

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* update issue template

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* use notification badge

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* web/user: re-add go-to-admin button

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* *: fix remaining redirects directly to admin

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* make settings better

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* api: ensure sources and stages are sorted

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* web/user: add sessions and consent

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* providers/oauth2: add post wrapper to stage

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* website/docs: add new interface to release notes

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens L
2021-09-16 22:17:05 +02:00
committed by GitHub
parent 9441be1ee2
commit 13e2eea72f
51 changed files with 660 additions and 1708 deletions

View File

@ -1,5 +1,5 @@
import { t } from "@lingui/macro";
import { CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
import { CSSResult, customElement, html, LitElement, TemplateResult } from "lit-element";
import PFPage from "@patternfly/patternfly/components/Page/page.css";
import PFContent from "@patternfly/patternfly/components/Content/content.css";
@ -13,22 +13,15 @@ import AKGlobal from "../../authentik.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import PFForm from "@patternfly/patternfly/components/Form/form.css";
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
import { SourcesApi, StagesApi, UserSetting } from "@goauthentik/api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { until } from "lit-html/directives/until";
import { ifDefined } from "lit-html/directives/if-defined";
import "../../elements/Tabs";
import "../../elements/PageHeader";
import "../../elements/user/SessionList";
import "../../elements/user/UserConsentList";
import "./tokens/UserTokenList";
import "./UserSelfForm";
import "./settings/UserSettingsAuthenticatorDuo";
import "./settings/UserSettingsAuthenticatorStatic";
import "./settings/UserSettingsAuthenticatorTOTP";
import "./settings/UserSettingsAuthenticatorWebAuthn";
import "./settings/UserSettingsPassword";
import "./settings/SourceSettingsOAuth";
import "./settings/SourceSettingsPlex";
import { EVENT_REFRESH } from "../../constants";
import "./sources/SourceSettings";
import "./stages/StageSettings";
import { until } from "lit-html/directives/until";
import { me } from "../../api/Users";
@customElement("ak-user-settings")
export class UserSettingsPage extends LitElement {
@ -49,91 +42,10 @@ export class UserSettingsPage extends LitElement {
];
}
@property({ attribute: false })
userSettings?: Promise<UserSetting[]>;
@property({ attribute: false })
sourceSettings?: Promise<UserSetting[]>;
constructor() {
super();
this.addEventListener(EVENT_REFRESH, () => {
this.firstUpdated();
});
}
firstUpdated(): void {
this.userSettings = new StagesApi(DEFAULT_CONFIG).stagesAllUserSettingsList();
this.sourceSettings = new SourcesApi(DEFAULT_CONFIG).sourcesAllUserSettingsList();
}
renderStageSettings(stage: UserSetting): TemplateResult {
switch (stage.component) {
case "ak-user-settings-authenticator-webauthn":
return html`<ak-user-settings-authenticator-webauthn
objectId=${stage.objectUid}
.configureUrl=${stage.configureUrl}
>
</ak-user-settings-authenticator-webauthn>`;
case "ak-user-settings-password":
return html`<ak-user-settings-password
objectId=${stage.objectUid}
.configureUrl=${stage.configureUrl}
>
</ak-user-settings-password>`;
case "ak-user-settings-authenticator-totp":
return html`<ak-user-settings-authenticator-totp
objectId=${stage.objectUid}
.configureUrl=${stage.configureUrl}
>
</ak-user-settings-authenticator-totp>`;
case "ak-user-settings-authenticator-static":
return html`<ak-user-settings-authenticator-static
objectId=${stage.objectUid}
.configureUrl=${stage.configureUrl}
>
</ak-user-settings-authenticator-static>`;
case "ak-user-settings-authenticator-duo":
return html`<ak-user-settings-authenticator-duo
objectId=${stage.objectUid}
.configureUrl=${stage.configureUrl}
>
</ak-user-settings-authenticator-duo>`;
default:
return html`<p>${t`Error: unsupported stage settings: ${stage.component}`}</p>`;
}
}
renderSourceSettings(source: UserSetting): TemplateResult {
switch (source.component) {
case "ak-user-settings-source-oauth":
return html`<ak-user-settings-source-oauth
objectId=${source.objectUid}
title=${source.title}
.configureUrl=${source.configureUrl}
>
</ak-user-settings-source-oauth>`;
case "ak-user-settings-source-plex":
return html`<ak-user-settings-source-plex
objectId=${source.objectUid}
title=${source.title}
>
</ak-user-settings-source-plex>`;
default:
return html`<p>${t`Error: unsupported source settings: ${source.component}`}</p>`;
}
}
render(): TemplateResult {
return html`<div class="pf-c-page">
<main role="main" class="pf-c-page__main" tabindex="-1">
<ak-page-header
icon="pf-icon pf-icon-user"
header=${t`User Settings`}
description=${t`Configure settings relevant to your user profile.`}
>
</ak-page-header>
<ak-tabs ?vertical="${true}" style="height: 100%;">
<ak-tabs ?vertical="${true}">
<section
slot="page-details"
data-tab-title="${t`User details`}"
@ -146,6 +58,46 @@ export class UserSettingsPage extends LitElement {
</div>
</div>
</section>
<section
slot="page-sessions"
data-tab-title="${t`Sessions`}"
class="pf-c-page__main-section pf-m-no-padding-mobile"
>
${until(
me().then((u) => {
return html`<ak-user-session-list
targetUser=${u.user.username}
></ak-user-session-list>`;
}),
)}
</section>
<section
slot="page-consents"
data-tab-title="${t`Consent`}"
class="pf-c-page__main-section pf-m-no-padding-mobile"
>
${until(
me().then((u) => {
return html`<ak-user-consent-list
userId=${u.user.pk}
></ak-user-consent-list>`;
}),
)}
</section>
<section
slot="page-stages"
data-tab-title="${t`Password, 2FA, etc`}"
class="pf-c-page__main-section pf-m-no-padding-mobile"
>
<ak-user-settings-stage></ak-user-settings-stage>
</section>
<section
slot="page-sources"
data-tab-title="${t`Connected services`}"
class="pf-c-page__main-section pf-m-no-padding-mobile"
>
<ak-user-settings-source></ak-user-settings-source>
</section>
<section
slot="page-tokens"
data-tab-title="${t`Tokens and App passwords`}"
@ -153,32 +105,6 @@ export class UserSettingsPage extends LitElement {
>
<ak-user-token-list></ak-user-token-list>
</section>
${until(
this.userSettings?.then((stages) => {
return stages.map((stage) => {
return html`<section
slot="page-${stage.objectUid}"
data-tab-title="${ifDefined(stage.title)}"
class="pf-c-page__main-section pf-m-no-padding-mobile"
>
${this.renderStageSettings(stage)}
</section>`;
});
}),
)}
${until(
this.sourceSettings?.then((source) => {
return source.map((stage) => {
return html`<section
slot="page-${stage.objectUid}"
data-tab-title="${ifDefined(stage.title)}"
class="pf-c-page__main-section pf-m-no-padding-mobile"
>
${this.renderSourceSettings(stage)}
</section>`;
});
}),
)}
</ak-tabs>
</main>
</div>`;