interface split (#943)
This commit is contained in:
		
							
								
								
									
										100
									
								
								web/src/user/user-settings/UserSelfForm.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								web/src/user/user-settings/UserSelfForm.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,100 @@
 | 
			
		||||
import { t } from "@lingui/macro";
 | 
			
		||||
import { customElement, html, TemplateResult } from "lit-element";
 | 
			
		||||
import { CoreApi, UserSelf } from "@goauthentik/api";
 | 
			
		||||
import { ifDefined } from "lit-html/directives/if-defined";
 | 
			
		||||
import { DEFAULT_CONFIG, tenant } from "../../api/Config";
 | 
			
		||||
import "../../elements/forms/FormElement";
 | 
			
		||||
import "../../elements/EmptyState";
 | 
			
		||||
import "../../elements/forms/Form";
 | 
			
		||||
import "../../elements/forms/HorizontalFormElement";
 | 
			
		||||
import { until } from "lit-html/directives/until";
 | 
			
		||||
import { ModelForm } from "../../elements/forms/ModelForm";
 | 
			
		||||
 | 
			
		||||
@customElement("ak-user-self-form")
 | 
			
		||||
export class UserSelfForm extends ModelForm<UserSelf, number> {
 | 
			
		||||
    viewportCheck = false;
 | 
			
		||||
 | 
			
		||||
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | 
			
		||||
    loadInstance(pk: number): Promise<UserSelf> {
 | 
			
		||||
        return new CoreApi(DEFAULT_CONFIG).coreUsersMeRetrieve().then((su) => {
 | 
			
		||||
            return su.user;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getSuccessMessage(): string {
 | 
			
		||||
        return t`Successfully updated details.`;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    send = (data: UserSelf): Promise<UserSelf> => {
 | 
			
		||||
        return new CoreApi(DEFAULT_CONFIG)
 | 
			
		||||
            .coreUsersUpdateSelfUpdate({
 | 
			
		||||
                userSelfRequest: data,
 | 
			
		||||
            })
 | 
			
		||||
            .then((su) => {
 | 
			
		||||
                return su.user;
 | 
			
		||||
            });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    renderForm(): TemplateResult {
 | 
			
		||||
        if (!this.instance) {
 | 
			
		||||
            return html`<ak-empty-state ?loading="${true}" header=${t`Loading`}> </ak-empty-state>`;
 | 
			
		||||
        }
 | 
			
		||||
        return html`<form class="pf-c-form pf-m-horizontal">
 | 
			
		||||
            <ak-form-element-horizontal label=${t`Username`} ?required=${true} name="username">
 | 
			
		||||
                <input
 | 
			
		||||
                    type="text"
 | 
			
		||||
                    value="${ifDefined(this.instance?.username)}"
 | 
			
		||||
                    class="pf-c-form-control"
 | 
			
		||||
                    required
 | 
			
		||||
                />
 | 
			
		||||
                <p class="pf-c-form__helper-text">
 | 
			
		||||
                    ${t`Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.`}
 | 
			
		||||
                </p>
 | 
			
		||||
            </ak-form-element-horizontal>
 | 
			
		||||
            <ak-form-element-horizontal label=${t`Name`} ?required=${true} name="name">
 | 
			
		||||
                <input
 | 
			
		||||
                    type="text"
 | 
			
		||||
                    value="${ifDefined(this.instance?.name)}"
 | 
			
		||||
                    class="pf-c-form-control"
 | 
			
		||||
                    required
 | 
			
		||||
                />
 | 
			
		||||
                <p class="pf-c-form__helper-text">${t`User's display name.`}</p>
 | 
			
		||||
            </ak-form-element-horizontal>
 | 
			
		||||
            <ak-form-element-horizontal label=${t`Email`} name="email">
 | 
			
		||||
                <input
 | 
			
		||||
                    type="email"
 | 
			
		||||
                    value="${ifDefined(this.instance?.email)}"
 | 
			
		||||
                    class="pf-c-form-control"
 | 
			
		||||
                />
 | 
			
		||||
            </ak-form-element-horizontal>
 | 
			
		||||
 | 
			
		||||
            <div class="pf-c-form__group pf-m-action">
 | 
			
		||||
                <div class="pf-c-form__horizontal-group">
 | 
			
		||||
                    <div class="pf-c-form__actions">
 | 
			
		||||
                        <button
 | 
			
		||||
                            @click=${(ev: Event) => {
 | 
			
		||||
                                return this.submit(ev);
 | 
			
		||||
                            }}
 | 
			
		||||
                            class="pf-c-button pf-m-primary"
 | 
			
		||||
                        >
 | 
			
		||||
                            ${t`Update`}
 | 
			
		||||
                        </button>
 | 
			
		||||
                        ${until(
 | 
			
		||||
                            tenant().then((tenant) => {
 | 
			
		||||
                                if (tenant.flowUnenrollment) {
 | 
			
		||||
                                    return html`<a
 | 
			
		||||
                                        class="pf-c-button pf-m-danger"
 | 
			
		||||
                                        href="/if/flow/${tenant.flowUnenrollment}"
 | 
			
		||||
                                    >
 | 
			
		||||
                                        ${t`Delete account`}
 | 
			
		||||
                                    </a>`;
 | 
			
		||||
                                }
 | 
			
		||||
                                return html``;
 | 
			
		||||
                            }),
 | 
			
		||||
                        )}
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </form>`;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										186
									
								
								web/src/user/user-settings/UserSettingsPage.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										186
									
								
								web/src/user/user-settings/UserSettingsPage.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,186 @@
 | 
			
		||||
import { t } from "@lingui/macro";
 | 
			
		||||
import { CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
 | 
			
		||||
 | 
			
		||||
import PFPage from "@patternfly/patternfly/components/Page/page.css";
 | 
			
		||||
import PFContent from "@patternfly/patternfly/components/Content/content.css";
 | 
			
		||||
import PFGallery from "@patternfly/patternfly/layouts/Gallery/gallery.css";
 | 
			
		||||
import PFCard from "@patternfly/patternfly/components/Card/card.css";
 | 
			
		||||
import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css";
 | 
			
		||||
import PFSizing from "@patternfly/patternfly/utilities/Sizing/sizing.css";
 | 
			
		||||
import PFFlex from "@patternfly/patternfly/utilities/Flex/flex.css";
 | 
			
		||||
import PFDisplay from "@patternfly/patternfly/utilities/Display/display.css";
 | 
			
		||||
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 "./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";
 | 
			
		||||
 | 
			
		||||
@customElement("ak-user-settings")
 | 
			
		||||
export class UserSettingsPage extends LitElement {
 | 
			
		||||
    static get styles(): CSSResult[] {
 | 
			
		||||
        return [
 | 
			
		||||
            PFBase,
 | 
			
		||||
            PFPage,
 | 
			
		||||
            PFFlex,
 | 
			
		||||
            PFDisplay,
 | 
			
		||||
            PFGallery,
 | 
			
		||||
            PFContent,
 | 
			
		||||
            PFCard,
 | 
			
		||||
            PFDescriptionList,
 | 
			
		||||
            PFSizing,
 | 
			
		||||
            PFForm,
 | 
			
		||||
            PFFormControl,
 | 
			
		||||
            AKGlobal,
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @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%;">
 | 
			
		||||
                    <section
 | 
			
		||||
                        slot="page-details"
 | 
			
		||||
                        data-tab-title="${t`User details`}"
 | 
			
		||||
                        class="pf-c-page__main-section pf-m-no-padding-mobile"
 | 
			
		||||
                    >
 | 
			
		||||
                        <div class="pf-c-card">
 | 
			
		||||
                            <div class="pf-c-card__title">${t`Update details`}</div>
 | 
			
		||||
                            <div class="pf-c-card__body">
 | 
			
		||||
                                <ak-user-self-form .instancePk=${1}></ak-user-self-form>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </section>
 | 
			
		||||
                    <section
 | 
			
		||||
                        slot="page-tokens"
 | 
			
		||||
                        data-tab-title="${t`Tokens and App passwords`}"
 | 
			
		||||
                        class="pf-c-page__main-section pf-m-no-padding-mobile"
 | 
			
		||||
                    >
 | 
			
		||||
                        <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>`;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								web/src/user/user-settings/settings/BaseUserSettings.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								web/src/user/user-settings/settings/BaseUserSettings.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
			
		||||
import { CSSResult, LitElement, property } from "lit-element";
 | 
			
		||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
 | 
			
		||||
import PFCard from "@patternfly/patternfly/components/Card/card.css";
 | 
			
		||||
import PFButton from "@patternfly/patternfly/components/Button/button.css";
 | 
			
		||||
import AKGlobal from "../../../authentik.css";
 | 
			
		||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
 | 
			
		||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
 | 
			
		||||
 | 
			
		||||
export abstract class BaseUserSettings extends LitElement {
 | 
			
		||||
    @property()
 | 
			
		||||
    objectId!: string;
 | 
			
		||||
 | 
			
		||||
    @property()
 | 
			
		||||
    configureUrl?: string;
 | 
			
		||||
 | 
			
		||||
    static get styles(): CSSResult[] {
 | 
			
		||||
        return [PFBase, PFCard, PFButton, PFForm, PFFormControl, AKGlobal];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										50
									
								
								web/src/user/user-settings/settings/SourceSettingsOAuth.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								web/src/user/user-settings/settings/SourceSettingsOAuth.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,50 @@
 | 
			
		||||
import { customElement, html, property, TemplateResult } from "lit-element";
 | 
			
		||||
import { BaseUserSettings } from "./BaseUserSettings";
 | 
			
		||||
import { SourcesApi } from "@goauthentik/api";
 | 
			
		||||
import { until } from "lit-html/directives/until";
 | 
			
		||||
import { DEFAULT_CONFIG } from "../../../api/Config";
 | 
			
		||||
import { t } from "@lingui/macro";
 | 
			
		||||
import { ifDefined } from "lit-html/directives/if-defined";
 | 
			
		||||
 | 
			
		||||
@customElement("ak-user-settings-source-oauth")
 | 
			
		||||
export class SourceSettingsOAuth extends BaseUserSettings {
 | 
			
		||||
    @property()
 | 
			
		||||
    title!: string;
 | 
			
		||||
 | 
			
		||||
    render(): TemplateResult {
 | 
			
		||||
        return html`<div class="pf-c-card">
 | 
			
		||||
            <div class="pf-c-card__title">${t`Source ${this.title}`}</div>
 | 
			
		||||
            <div class="pf-c-card__body">${this.renderInner()}</div>
 | 
			
		||||
        </div>`;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    renderInner(): TemplateResult {
 | 
			
		||||
        return html`${until(
 | 
			
		||||
            new SourcesApi(DEFAULT_CONFIG)
 | 
			
		||||
                .sourcesUserConnectionsOauthList({
 | 
			
		||||
                    sourceSlug: this.objectId,
 | 
			
		||||
                })
 | 
			
		||||
                .then((connection) => {
 | 
			
		||||
                    if (connection.results.length > 0) {
 | 
			
		||||
                        return html`<p>${t`Connected.`}</p>
 | 
			
		||||
                            <button
 | 
			
		||||
                                class="pf-c-button pf-m-danger"
 | 
			
		||||
                                @click=${() => {
 | 
			
		||||
                                    return new SourcesApi(
 | 
			
		||||
                                        DEFAULT_CONFIG,
 | 
			
		||||
                                    ).sourcesUserConnectionsOauthDestroy({
 | 
			
		||||
                                        id: connection.results[0].pk || 0,
 | 
			
		||||
                                    });
 | 
			
		||||
                                }}
 | 
			
		||||
                            >
 | 
			
		||||
                                ${t`Disconnect`}
 | 
			
		||||
                            </button>`;
 | 
			
		||||
                    }
 | 
			
		||||
                    return html`<p>${t`Not connected.`}</p>
 | 
			
		||||
                        <a class="pf-c-button pf-m-primary" href=${ifDefined(this.configureUrl)}>
 | 
			
		||||
                            ${t`Connect`}
 | 
			
		||||
                        </a>`;
 | 
			
		||||
                }),
 | 
			
		||||
        )}`;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										46
									
								
								web/src/user/user-settings/settings/SourceSettingsPlex.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								web/src/user/user-settings/settings/SourceSettingsPlex.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
			
		||||
import { customElement, html, property, TemplateResult } from "lit-element";
 | 
			
		||||
import { BaseUserSettings } from "./BaseUserSettings";
 | 
			
		||||
import { SourcesApi } from "@goauthentik/api";
 | 
			
		||||
import { until } from "lit-html/directives/until";
 | 
			
		||||
import { DEFAULT_CONFIG } from "../../../api/Config";
 | 
			
		||||
import { t } from "@lingui/macro";
 | 
			
		||||
 | 
			
		||||
@customElement("ak-user-settings-source-plex")
 | 
			
		||||
export class SourceSettingsPlex extends BaseUserSettings {
 | 
			
		||||
    @property()
 | 
			
		||||
    title!: string;
 | 
			
		||||
 | 
			
		||||
    render(): TemplateResult {
 | 
			
		||||
        return html`<div class="pf-c-card">
 | 
			
		||||
            <div class="pf-c-card__title">${t`Source ${this.title}`}</div>
 | 
			
		||||
            <div class="pf-c-card__body">${this.renderInner()}</div>
 | 
			
		||||
        </div>`;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    renderInner(): TemplateResult {
 | 
			
		||||
        return html`${until(
 | 
			
		||||
            new SourcesApi(DEFAULT_CONFIG)
 | 
			
		||||
                .sourcesUserConnectionsPlexList({
 | 
			
		||||
                    sourceSlug: this.objectId,
 | 
			
		||||
                })
 | 
			
		||||
                .then((connection) => {
 | 
			
		||||
                    if (connection.results.length > 0) {
 | 
			
		||||
                        return html`<p>${t`Connected.`}</p>
 | 
			
		||||
                            <button
 | 
			
		||||
                                class="pf-c-button pf-m-danger"
 | 
			
		||||
                                @click=${() => {
 | 
			
		||||
                                    return new SourcesApi(
 | 
			
		||||
                                        DEFAULT_CONFIG,
 | 
			
		||||
                                    ).sourcesUserConnectionsPlexDestroy({
 | 
			
		||||
                                        id: connection.results[0].pk || 0,
 | 
			
		||||
                                    });
 | 
			
		||||
                                }}
 | 
			
		||||
                            >
 | 
			
		||||
                                ${t`Disconnect`}
 | 
			
		||||
                            </button>`;
 | 
			
		||||
                    }
 | 
			
		||||
                    return html`<p>${t`Not connected.`}</p>`;
 | 
			
		||||
                }),
 | 
			
		||||
        )}`;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,79 @@
 | 
			
		||||
import { AuthenticatorsApi } from "@goauthentik/api";
 | 
			
		||||
import { t } from "@lingui/macro";
 | 
			
		||||
import { customElement, html, TemplateResult } from "lit-element";
 | 
			
		||||
import { until } from "lit-html/directives/until";
 | 
			
		||||
import { DEFAULT_CONFIG } from "../../../api/Config";
 | 
			
		||||
import { BaseUserSettings } from "./BaseUserSettings";
 | 
			
		||||
import { EVENT_REFRESH } from "../../../constants";
 | 
			
		||||
 | 
			
		||||
@customElement("ak-user-settings-authenticator-duo")
 | 
			
		||||
export class UserSettingsAuthenticatorDuo extends BaseUserSettings {
 | 
			
		||||
    renderEnabled(): TemplateResult {
 | 
			
		||||
        return html`<div class="pf-c-card__body">
 | 
			
		||||
                <p>
 | 
			
		||||
                    ${t`Status: Enabled`}
 | 
			
		||||
                    <i class="pf-icon pf-icon-ok"></i>
 | 
			
		||||
                </p>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="pf-c-card__footer">
 | 
			
		||||
                <button
 | 
			
		||||
                    class="pf-c-button pf-m-danger"
 | 
			
		||||
                    @click=${() => {
 | 
			
		||||
                        return new AuthenticatorsApi(DEFAULT_CONFIG)
 | 
			
		||||
                            .authenticatorsDuoList({})
 | 
			
		||||
                            .then((devices) => {
 | 
			
		||||
                                if (devices.results.length < 1) {
 | 
			
		||||
                                    return;
 | 
			
		||||
                                }
 | 
			
		||||
                                // TODO: Handle multiple devices, currently we assume only one TOTP Device
 | 
			
		||||
                                return new AuthenticatorsApi(DEFAULT_CONFIG)
 | 
			
		||||
                                    .authenticatorsDuoDestroy({
 | 
			
		||||
                                        id: devices.results[0].pk || 0,
 | 
			
		||||
                                    })
 | 
			
		||||
                                    .then(() => {
 | 
			
		||||
                                        this.dispatchEvent(
 | 
			
		||||
                                            new CustomEvent(EVENT_REFRESH, {
 | 
			
		||||
                                                bubbles: true,
 | 
			
		||||
                                                composed: true,
 | 
			
		||||
                                            }),
 | 
			
		||||
                                        );
 | 
			
		||||
                                    });
 | 
			
		||||
                            });
 | 
			
		||||
                    }}
 | 
			
		||||
                >
 | 
			
		||||
                    ${t`Disable Duo authenticator`}
 | 
			
		||||
                </button>
 | 
			
		||||
            </div>`;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    renderDisabled(): TemplateResult {
 | 
			
		||||
        return html` <div class="pf-c-card__body">
 | 
			
		||||
                <p>
 | 
			
		||||
                    ${t`Status: Disabled`}
 | 
			
		||||
                    <i class="pf-icon pf-icon-error-circle-o"></i>
 | 
			
		||||
                </p>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="pf-c-card__footer">
 | 
			
		||||
                ${this.configureUrl
 | 
			
		||||
                    ? html`<a
 | 
			
		||||
                          href="${this.configureUrl}?next=/%23%2Fuser"
 | 
			
		||||
                          class="pf-c-button pf-m-primary"
 | 
			
		||||
                          >${t`Enable Duo authenticator`}
 | 
			
		||||
                      </a>`
 | 
			
		||||
                    : html``}
 | 
			
		||||
            </div>`;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render(): TemplateResult {
 | 
			
		||||
        return html`<div class="pf-c-card">
 | 
			
		||||
            <div class="pf-c-card__title">${t`Duo`}</div>
 | 
			
		||||
            ${until(
 | 
			
		||||
                new AuthenticatorsApi(DEFAULT_CONFIG).authenticatorsDuoList({}).then((devices) => {
 | 
			
		||||
                    return devices.results.length > 0
 | 
			
		||||
                        ? this.renderEnabled()
 | 
			
		||||
                        : this.renderDisabled();
 | 
			
		||||
                }),
 | 
			
		||||
            )}
 | 
			
		||||
        </div>`;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,100 @@
 | 
			
		||||
import { AuthenticatorsApi } from "@goauthentik/api";
 | 
			
		||||
import { t } from "@lingui/macro";
 | 
			
		||||
import { CSSResult, customElement, html, TemplateResult } from "lit-element";
 | 
			
		||||
import { until } from "lit-html/directives/until";
 | 
			
		||||
import { DEFAULT_CONFIG } from "../../../api/Config";
 | 
			
		||||
import { STATIC_TOKEN_STYLE } from "../../../flows/stages/authenticator_static/AuthenticatorStaticStage";
 | 
			
		||||
import { BaseUserSettings } from "./BaseUserSettings";
 | 
			
		||||
import { EVENT_REFRESH } from "../../../constants";
 | 
			
		||||
 | 
			
		||||
@customElement("ak-user-settings-authenticator-static")
 | 
			
		||||
export class UserSettingsAuthenticatorStatic extends BaseUserSettings {
 | 
			
		||||
    static get styles(): CSSResult[] {
 | 
			
		||||
        return super.styles.concat(STATIC_TOKEN_STYLE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    renderEnabled(): TemplateResult {
 | 
			
		||||
        return html`<div class="pf-c-card__body">
 | 
			
		||||
                <p>
 | 
			
		||||
                    ${t`Status: Enabled`}
 | 
			
		||||
                    <i class="pf-icon pf-icon-ok"></i>
 | 
			
		||||
                </p>
 | 
			
		||||
                <ul class="ak-otp-tokens">
 | 
			
		||||
                    ${until(
 | 
			
		||||
                        new AuthenticatorsApi(DEFAULT_CONFIG)
 | 
			
		||||
                            .authenticatorsStaticList({})
 | 
			
		||||
                            .then((devices) => {
 | 
			
		||||
                                if (devices.results.length < 1) {
 | 
			
		||||
                                    return;
 | 
			
		||||
                                }
 | 
			
		||||
                                return devices.results[0].tokenSet?.map((token) => {
 | 
			
		||||
                                    return html`<li>${token.token}</li>`;
 | 
			
		||||
                                });
 | 
			
		||||
                            }),
 | 
			
		||||
                    )}
 | 
			
		||||
                </ul>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="pf-c-card__footer">
 | 
			
		||||
                <button
 | 
			
		||||
                    class="pf-c-button pf-m-danger"
 | 
			
		||||
                    @click=${() => {
 | 
			
		||||
                        return new AuthenticatorsApi(DEFAULT_CONFIG)
 | 
			
		||||
                            .authenticatorsStaticList({})
 | 
			
		||||
                            .then((devices) => {
 | 
			
		||||
                                if (devices.results.length < 1) {
 | 
			
		||||
                                    return;
 | 
			
		||||
                                }
 | 
			
		||||
                                // TODO: Handle multiple devices, currently we assume only one TOTP Device
 | 
			
		||||
                                return new AuthenticatorsApi(DEFAULT_CONFIG)
 | 
			
		||||
                                    .authenticatorsStaticDestroy({
 | 
			
		||||
                                        id: devices.results[0].pk || 0,
 | 
			
		||||
                                    })
 | 
			
		||||
                                    .then(() => {
 | 
			
		||||
                                        this.dispatchEvent(
 | 
			
		||||
                                            new CustomEvent(EVENT_REFRESH, {
 | 
			
		||||
                                                bubbles: true,
 | 
			
		||||
                                                composed: true,
 | 
			
		||||
                                            }),
 | 
			
		||||
                                        );
 | 
			
		||||
                                    });
 | 
			
		||||
                            });
 | 
			
		||||
                    }}
 | 
			
		||||
                >
 | 
			
		||||
                    ${t`Disable Static Tokens`}
 | 
			
		||||
                </button>
 | 
			
		||||
            </div>`;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    renderDisabled(): TemplateResult {
 | 
			
		||||
        return html` <div class="pf-c-card__body">
 | 
			
		||||
                <p>
 | 
			
		||||
                    ${t`Status: Disabled`}
 | 
			
		||||
                    <i class="pf-icon pf-icon-error-circle-o"></i>
 | 
			
		||||
                </p>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="pf-c-card__footer">
 | 
			
		||||
                ${this.configureUrl
 | 
			
		||||
                    ? html`<a
 | 
			
		||||
                          href="${this.configureUrl}?next=/%23%2Fuser"
 | 
			
		||||
                          class="pf-c-button pf-m-primary"
 | 
			
		||||
                          >${t`Enable Static Tokens`}
 | 
			
		||||
                      </a>`
 | 
			
		||||
                    : html``}
 | 
			
		||||
            </div>`;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render(): TemplateResult {
 | 
			
		||||
        return html`<div class="pf-c-card">
 | 
			
		||||
            <div class="pf-c-card__title">${t`Static tokens`}</div>
 | 
			
		||||
            ${until(
 | 
			
		||||
                new AuthenticatorsApi(DEFAULT_CONFIG)
 | 
			
		||||
                    .authenticatorsStaticList({})
 | 
			
		||||
                    .then((devices) => {
 | 
			
		||||
                        return devices.results.length > 0
 | 
			
		||||
                            ? this.renderEnabled()
 | 
			
		||||
                            : this.renderDisabled();
 | 
			
		||||
                    }),
 | 
			
		||||
            )}
 | 
			
		||||
        </div>`;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,79 @@
 | 
			
		||||
import { AuthenticatorsApi } from "@goauthentik/api";
 | 
			
		||||
import { t } from "@lingui/macro";
 | 
			
		||||
import { customElement, html, TemplateResult } from "lit-element";
 | 
			
		||||
import { until } from "lit-html/directives/until";
 | 
			
		||||
import { DEFAULT_CONFIG } from "../../../api/Config";
 | 
			
		||||
import { BaseUserSettings } from "./BaseUserSettings";
 | 
			
		||||
import { EVENT_REFRESH } from "../../../constants";
 | 
			
		||||
 | 
			
		||||
@customElement("ak-user-settings-authenticator-totp")
 | 
			
		||||
export class UserSettingsAuthenticatorTOTP extends BaseUserSettings {
 | 
			
		||||
    renderEnabled(): TemplateResult {
 | 
			
		||||
        return html`<div class="pf-c-card__body">
 | 
			
		||||
                <p>
 | 
			
		||||
                    ${t`Status: Enabled`}
 | 
			
		||||
                    <i class="pf-icon pf-icon-ok"></i>
 | 
			
		||||
                </p>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="pf-c-card__footer">
 | 
			
		||||
                <button
 | 
			
		||||
                    class="pf-c-button pf-m-danger"
 | 
			
		||||
                    @click=${() => {
 | 
			
		||||
                        return new AuthenticatorsApi(DEFAULT_CONFIG)
 | 
			
		||||
                            .authenticatorsTotpList({})
 | 
			
		||||
                            .then((devices) => {
 | 
			
		||||
                                if (devices.results.length < 1) {
 | 
			
		||||
                                    return;
 | 
			
		||||
                                }
 | 
			
		||||
                                // TODO: Handle multiple devices, currently we assume only one TOTP Device
 | 
			
		||||
                                return new AuthenticatorsApi(DEFAULT_CONFIG)
 | 
			
		||||
                                    .authenticatorsTotpDestroy({
 | 
			
		||||
                                        id: devices.results[0].pk || 0,
 | 
			
		||||
                                    })
 | 
			
		||||
                                    .then(() => {
 | 
			
		||||
                                        this.dispatchEvent(
 | 
			
		||||
                                            new CustomEvent(EVENT_REFRESH, {
 | 
			
		||||
                                                bubbles: true,
 | 
			
		||||
                                                composed: true,
 | 
			
		||||
                                            }),
 | 
			
		||||
                                        );
 | 
			
		||||
                                    });
 | 
			
		||||
                            });
 | 
			
		||||
                    }}
 | 
			
		||||
                >
 | 
			
		||||
                    ${t`Disable Time-based OTP`}
 | 
			
		||||
                </button>
 | 
			
		||||
            </div>`;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    renderDisabled(): TemplateResult {
 | 
			
		||||
        return html` <div class="pf-c-card__body">
 | 
			
		||||
                <p>
 | 
			
		||||
                    ${t`Status: Disabled`}
 | 
			
		||||
                    <i class="pf-icon pf-icon-error-circle-o"></i>
 | 
			
		||||
                </p>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="pf-c-card__footer">
 | 
			
		||||
                ${this.configureUrl
 | 
			
		||||
                    ? html`<a
 | 
			
		||||
                          href="${this.configureUrl}?next=/%23%2Fuser"
 | 
			
		||||
                          class="pf-c-button pf-m-primary"
 | 
			
		||||
                          >${t`Enable TOTP`}
 | 
			
		||||
                      </a>`
 | 
			
		||||
                    : html``}
 | 
			
		||||
            </div>`;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render(): TemplateResult {
 | 
			
		||||
        return html`<div class="pf-c-card">
 | 
			
		||||
            <div class="pf-c-card__title">${t`Time-based One-Time Passwords`}</div>
 | 
			
		||||
            ${until(
 | 
			
		||||
                new AuthenticatorsApi(DEFAULT_CONFIG).authenticatorsTotpList({}).then((devices) => {
 | 
			
		||||
                    return devices.results.length > 0
 | 
			
		||||
                        ? this.renderEnabled()
 | 
			
		||||
                        : this.renderDisabled();
 | 
			
		||||
                }),
 | 
			
		||||
            )}
 | 
			
		||||
        </div>`;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,125 @@
 | 
			
		||||
import { CSSResult, customElement, html, TemplateResult } from "lit-element";
 | 
			
		||||
import { t } from "@lingui/macro";
 | 
			
		||||
import { AuthenticatorsApi, WebAuthnDevice } from "@goauthentik/api";
 | 
			
		||||
import { until } from "lit-html/directives/until";
 | 
			
		||||
import { DEFAULT_CONFIG } from "../../../api/Config";
 | 
			
		||||
import { BaseUserSettings } from "./BaseUserSettings";
 | 
			
		||||
import PFDataList from "@patternfly/patternfly/components/DataList/data-list.css";
 | 
			
		||||
import "../../../elements/buttons/ModalButton";
 | 
			
		||||
import "../../../elements/buttons/SpinnerButton";
 | 
			
		||||
import "../../../elements/forms/DeleteForm";
 | 
			
		||||
import "../../../elements/forms/Form";
 | 
			
		||||
import "../../../elements/forms/ModalForm";
 | 
			
		||||
import "../../../elements/forms/HorizontalFormElement";
 | 
			
		||||
import { ifDefined } from "lit-html/directives/if-defined";
 | 
			
		||||
import { EVENT_REFRESH } from "../../../constants";
 | 
			
		||||
 | 
			
		||||
@customElement("ak-user-settings-authenticator-webauthn")
 | 
			
		||||
export class UserSettingsAuthenticatorWebAuthn extends BaseUserSettings {
 | 
			
		||||
    static get styles(): CSSResult[] {
 | 
			
		||||
        return super.styles.concat(PFDataList);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    renderDelete(device: WebAuthnDevice): TemplateResult {
 | 
			
		||||
        return html`<ak-forms-delete
 | 
			
		||||
            .obj=${device}
 | 
			
		||||
            objectLabel=${t`Authenticator`}
 | 
			
		||||
            .delete=${() => {
 | 
			
		||||
                return new AuthenticatorsApi(DEFAULT_CONFIG)
 | 
			
		||||
                    .authenticatorsWebauthnDestroy({
 | 
			
		||||
                        id: device.pk || 0,
 | 
			
		||||
                    })
 | 
			
		||||
                    .then(() => {
 | 
			
		||||
                        this.dispatchEvent(
 | 
			
		||||
                            new CustomEvent(EVENT_REFRESH, {
 | 
			
		||||
                                bubbles: true,
 | 
			
		||||
                                composed: true,
 | 
			
		||||
                            }),
 | 
			
		||||
                        );
 | 
			
		||||
                    });
 | 
			
		||||
            }}
 | 
			
		||||
        >
 | 
			
		||||
            <button slot="trigger" class="pf-c-button pf-m-danger">${t`Delete`}</button>
 | 
			
		||||
        </ak-forms-delete>`;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    renderUpdate(device: WebAuthnDevice): TemplateResult {
 | 
			
		||||
        return html`<ak-forms-modal>
 | 
			
		||||
            <span slot="submit"> ${t`Update`} </span>
 | 
			
		||||
            <span slot="header"> ${t`Update`} </span>
 | 
			
		||||
            <ak-form
 | 
			
		||||
                slot="form"
 | 
			
		||||
                successMessage=${t`Successfully updated device.`}
 | 
			
		||||
                .send=${(data: unknown) => {
 | 
			
		||||
                    return new AuthenticatorsApi(DEFAULT_CONFIG)
 | 
			
		||||
                        .authenticatorsWebauthnUpdate({
 | 
			
		||||
                            id: device.pk || 0,
 | 
			
		||||
                            webAuthnDeviceRequest: data as WebAuthnDevice,
 | 
			
		||||
                        })
 | 
			
		||||
                        .then(() => {
 | 
			
		||||
                            this.requestUpdate();
 | 
			
		||||
                        });
 | 
			
		||||
                }}
 | 
			
		||||
            >
 | 
			
		||||
                <form class="pf-c-form pf-m-horizontal">
 | 
			
		||||
                    <ak-form-element-horizontal
 | 
			
		||||
                        label=${t`Device name`}
 | 
			
		||||
                        ?required=${true}
 | 
			
		||||
                        name="name"
 | 
			
		||||
                    >
 | 
			
		||||
                        <input
 | 
			
		||||
                            type="text"
 | 
			
		||||
                            value="${ifDefined(device.name)}"
 | 
			
		||||
                            class="pf-c-form-control"
 | 
			
		||||
                            required
 | 
			
		||||
                        />
 | 
			
		||||
                    </ak-form-element-horizontal>
 | 
			
		||||
                </form>
 | 
			
		||||
            </ak-form>
 | 
			
		||||
            <button slot="trigger" class="pf-c-button pf-m-primary">${t`Update`}</button>
 | 
			
		||||
        </ak-forms-modal>`;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render(): TemplateResult {
 | 
			
		||||
        return html`<div class="pf-c-card">
 | 
			
		||||
            <div class="pf-c-card__title">${t`WebAuthn Devices`}</div>
 | 
			
		||||
            <div class="pf-c-card__body">
 | 
			
		||||
                <ul class="pf-c-data-list" role="list">
 | 
			
		||||
                    ${until(
 | 
			
		||||
                        new AuthenticatorsApi(DEFAULT_CONFIG)
 | 
			
		||||
                            .authenticatorsWebauthnList({})
 | 
			
		||||
                            .then((devices) => {
 | 
			
		||||
                                return devices.results.map((device) => {
 | 
			
		||||
                                    return html`<li class="pf-c-data-list__item">
 | 
			
		||||
                                        <div class="pf-c-data-list__item-row">
 | 
			
		||||
                                            <div class="pf-c-data-list__item-content">
 | 
			
		||||
                                                <div class="pf-c-data-list__cell">
 | 
			
		||||
                                                    ${device.name || "-"}
 | 
			
		||||
                                                </div>
 | 
			
		||||
                                                <div class="pf-c-data-list__cell">
 | 
			
		||||
                                                    ${t`Created ${device.createdOn?.toLocaleString()}`}
 | 
			
		||||
                                                </div>
 | 
			
		||||
                                                <div class="pf-c-data-list__cell">
 | 
			
		||||
                                                    ${this.renderUpdate(device)}
 | 
			
		||||
                                                    ${this.renderDelete(device)}
 | 
			
		||||
                                                </div>
 | 
			
		||||
                                            </div>
 | 
			
		||||
                                        </div>
 | 
			
		||||
                                    </li>`;
 | 
			
		||||
                                });
 | 
			
		||||
                            }),
 | 
			
		||||
                    )}
 | 
			
		||||
                </ul>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="pf-c-card__footer">
 | 
			
		||||
                ${this.configureUrl
 | 
			
		||||
                    ? html`<a
 | 
			
		||||
                          href="${this.configureUrl}?next=/%23%2Fuser"
 | 
			
		||||
                          class="pf-c-button pf-m-primary"
 | 
			
		||||
                          >${t`Configure WebAuthn`}
 | 
			
		||||
                      </a>`
 | 
			
		||||
                    : html``}
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>`;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								web/src/user/user-settings/settings/UserSettingsPassword.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								web/src/user/user-settings/settings/UserSettingsPassword.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
			
		||||
import { customElement, html, TemplateResult } from "lit-element";
 | 
			
		||||
import { t } from "@lingui/macro";
 | 
			
		||||
import { BaseUserSettings } from "./BaseUserSettings";
 | 
			
		||||
import { ifDefined } from "lit-html/directives/if-defined";
 | 
			
		||||
 | 
			
		||||
@customElement("ak-user-settings-password")
 | 
			
		||||
export class UserSettingsPassword extends BaseUserSettings {
 | 
			
		||||
    render(): TemplateResult {
 | 
			
		||||
        // For this stage we don't need to check for a configureFlow,
 | 
			
		||||
        // as the stage won't return any UI Elements if no configureFlow is set.
 | 
			
		||||
        return html`<div class="pf-c-card">
 | 
			
		||||
            <div class="pf-c-card__title">${t`Change your password`}</div>
 | 
			
		||||
            <div class="pf-c-card__body">
 | 
			
		||||
                <a href="${ifDefined(this.configureUrl)}" class="pf-c-button pf-m-primary">
 | 
			
		||||
                    ${t`Change password`}
 | 
			
		||||
                </a>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>`;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										62
									
								
								web/src/user/user-settings/tokens/UserTokenForm.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								web/src/user/user-settings/tokens/UserTokenForm.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,62 @@
 | 
			
		||||
import { CoreApi, IntentEnum, Token } from "@goauthentik/api";
 | 
			
		||||
import { t } from "@lingui/macro";
 | 
			
		||||
import { customElement, property } from "lit-element";
 | 
			
		||||
import { html, TemplateResult } from "lit-html";
 | 
			
		||||
import { DEFAULT_CONFIG } from "../../../api/Config";
 | 
			
		||||
import { ifDefined } from "lit-html/directives/if-defined";
 | 
			
		||||
import "../../../elements/forms/HorizontalFormElement";
 | 
			
		||||
import { ModelForm } from "../../../elements/forms/ModelForm";
 | 
			
		||||
 | 
			
		||||
@customElement("ak-user-token-form")
 | 
			
		||||
export class UserTokenForm extends ModelForm<Token, string> {
 | 
			
		||||
    @property()
 | 
			
		||||
    intent: IntentEnum = IntentEnum.Api;
 | 
			
		||||
 | 
			
		||||
    loadInstance(pk: string): Promise<Token> {
 | 
			
		||||
        return new CoreApi(DEFAULT_CONFIG).coreTokensRetrieve({
 | 
			
		||||
            identifier: pk,
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getSuccessMessage(): string {
 | 
			
		||||
        if (this.instance) {
 | 
			
		||||
            return t`Successfully updated token.`;
 | 
			
		||||
        } else {
 | 
			
		||||
            return t`Successfully created token.`;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    send = (data: Token): Promise<Token> => {
 | 
			
		||||
        if (this.instance) {
 | 
			
		||||
            return new CoreApi(DEFAULT_CONFIG).coreTokensUpdate({
 | 
			
		||||
                identifier: this.instance.identifier,
 | 
			
		||||
                tokenRequest: data,
 | 
			
		||||
            });
 | 
			
		||||
        } else {
 | 
			
		||||
            data.intent = this.intent;
 | 
			
		||||
            return new CoreApi(DEFAULT_CONFIG).coreTokensCreate({
 | 
			
		||||
                tokenRequest: data,
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    renderForm(): TemplateResult {
 | 
			
		||||
        return html`<form class="pf-c-form pf-m-horizontal">
 | 
			
		||||
            <ak-form-element-horizontal label=${t`Identifier`} ?required=${true} name="identifier">
 | 
			
		||||
                <input
 | 
			
		||||
                    type="text"
 | 
			
		||||
                    value="${ifDefined(this.instance?.identifier)}"
 | 
			
		||||
                    class="pf-c-form-control"
 | 
			
		||||
                    required
 | 
			
		||||
                />
 | 
			
		||||
            </ak-form-element-horizontal>
 | 
			
		||||
            <ak-form-element-horizontal label=${t`Description`} name="description">
 | 
			
		||||
                <input
 | 
			
		||||
                    type="text"
 | 
			
		||||
                    value="${ifDefined(this.instance?.description)}"
 | 
			
		||||
                    class="pf-c-form-control"
 | 
			
		||||
                />
 | 
			
		||||
            </ak-form-element-horizontal>
 | 
			
		||||
        </form>`;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										156
									
								
								web/src/user/user-settings/tokens/UserTokenList.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								web/src/user/user-settings/tokens/UserTokenList.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,156 @@
 | 
			
		||||
import { t } from "@lingui/macro";
 | 
			
		||||
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
 | 
			
		||||
import { AKResponse } from "../../../api/Client";
 | 
			
		||||
import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css";
 | 
			
		||||
 | 
			
		||||
import "../../../elements/forms/DeleteBulkForm";
 | 
			
		||||
import "../../../elements/forms/ModalForm";
 | 
			
		||||
import "../../../elements/buttons/ModalButton";
 | 
			
		||||
import "../../../elements/buttons/Dropdown";
 | 
			
		||||
import "../../../elements/buttons/TokenCopyButton";
 | 
			
		||||
import { Table, TableColumn } from "../../../elements/table/Table";
 | 
			
		||||
import { PAGE_SIZE } from "../../../constants";
 | 
			
		||||
import { CoreApi, IntentEnum, Token } from "@goauthentik/api";
 | 
			
		||||
import { DEFAULT_CONFIG } from "../../../api/Config";
 | 
			
		||||
import "./UserTokenForm";
 | 
			
		||||
import { IntentToLabel } from "../../../pages/tokens/TokenListPage";
 | 
			
		||||
 | 
			
		||||
@customElement("ak-user-token-list")
 | 
			
		||||
export class UserTokenList extends Table<Token> {
 | 
			
		||||
    searchEnabled(): boolean {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    expandable = true;
 | 
			
		||||
    checkbox = true;
 | 
			
		||||
 | 
			
		||||
    @property()
 | 
			
		||||
    order = "expires";
 | 
			
		||||
 | 
			
		||||
    apiEndpoint(page: number): Promise<AKResponse<Token>> {
 | 
			
		||||
        return new CoreApi(DEFAULT_CONFIG).coreTokensList({
 | 
			
		||||
            ordering: this.order,
 | 
			
		||||
            page: page,
 | 
			
		||||
            pageSize: PAGE_SIZE,
 | 
			
		||||
            search: this.search || "",
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    columns(): TableColumn[] {
 | 
			
		||||
        return [new TableColumn(t`Identifier`, "identifier"), new TableColumn("")];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static get styles(): CSSResult[] {
 | 
			
		||||
        return super.styles.concat(PFDescriptionList);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    renderToolbar(): TemplateResult {
 | 
			
		||||
        return html`
 | 
			
		||||
            <ak-forms-modal>
 | 
			
		||||
                <span slot="submit"> ${t`Create`} </span>
 | 
			
		||||
                <span slot="header"> ${t`Create Token`} </span>
 | 
			
		||||
                <ak-user-token-form intent=${IntentEnum.Api} slot="form"> </ak-user-token-form>
 | 
			
		||||
                <button slot="trigger" class="pf-c-button pf-m-secondary">
 | 
			
		||||
                    ${t`Create Token`}
 | 
			
		||||
                </button>
 | 
			
		||||
            </ak-forms-modal>
 | 
			
		||||
            <ak-forms-modal>
 | 
			
		||||
                <span slot="submit"> ${t`Create`} </span>
 | 
			
		||||
                <span slot="header"> ${t`Create App password`} </span>
 | 
			
		||||
                <ak-user-token-form intent=${IntentEnum.AppPassword} slot="form">
 | 
			
		||||
                </ak-user-token-form>
 | 
			
		||||
                <button slot="trigger" class="pf-c-button pf-m-secondary">
 | 
			
		||||
                    ${t`Create App password`}
 | 
			
		||||
                </button>
 | 
			
		||||
            </ak-forms-modal>
 | 
			
		||||
            ${super.renderToolbar()}
 | 
			
		||||
        `;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    renderExpanded(item: Token): TemplateResult {
 | 
			
		||||
        return html` <td role="cell" colspan="3">
 | 
			
		||||
                <div class="pf-c-table__expandable-row-content">
 | 
			
		||||
                    <dl class="pf-c-description-list pf-m-horizontal">
 | 
			
		||||
                        <div class="pf-c-description-list__group">
 | 
			
		||||
                            <dt class="pf-c-description-list__term">
 | 
			
		||||
                                <span class="pf-c-description-list__text">${t`User`}</span>
 | 
			
		||||
                            </dt>
 | 
			
		||||
                            <dd class="pf-c-description-list__description">
 | 
			
		||||
                                <div class="pf-c-description-list__text">
 | 
			
		||||
                                    ${item.user?.username}
 | 
			
		||||
                                </div>
 | 
			
		||||
                            </dd>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="pf-c-description-list__group">
 | 
			
		||||
                            <dt class="pf-c-description-list__term">
 | 
			
		||||
                                <span class="pf-c-description-list__text">${t`Expiring`}</span>
 | 
			
		||||
                            </dt>
 | 
			
		||||
                            <dd class="pf-c-description-list__description">
 | 
			
		||||
                                <div class="pf-c-description-list__text">
 | 
			
		||||
                                    ${item.expiring ? t`Yes` : t`No`}
 | 
			
		||||
                                </div>
 | 
			
		||||
                            </dd>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="pf-c-description-list__group">
 | 
			
		||||
                            <dt class="pf-c-description-list__term">
 | 
			
		||||
                                <span class="pf-c-description-list__text">${t`Expiring`}</span>
 | 
			
		||||
                            </dt>
 | 
			
		||||
                            <dd class="pf-c-description-list__description">
 | 
			
		||||
                                <div class="pf-c-description-list__text">
 | 
			
		||||
                                    ${item.expiring ? item.expires?.toLocaleString() : "-"}
 | 
			
		||||
                                </div>
 | 
			
		||||
                            </dd>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="pf-c-description-list__group">
 | 
			
		||||
                            <dt class="pf-c-description-list__term">
 | 
			
		||||
                                <span class="pf-c-description-list__text">${t`Intent`}</span>
 | 
			
		||||
                            </dt>
 | 
			
		||||
                            <dd class="pf-c-description-list__description">
 | 
			
		||||
                                <div class="pf-c-description-list__text">
 | 
			
		||||
                                    ${IntentToLabel(item.intent || IntentEnum.Api)}
 | 
			
		||||
                                </div>
 | 
			
		||||
                            </dd>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </dl>
 | 
			
		||||
                </div>
 | 
			
		||||
            </td>
 | 
			
		||||
            <td></td>`;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    renderToolbarSelected(): TemplateResult {
 | 
			
		||||
        const disabled = this.selectedElements.length < 1;
 | 
			
		||||
        return html`<ak-forms-delete-bulk
 | 
			
		||||
            objectLabel=${t`Token(s)`}
 | 
			
		||||
            .objects=${this.selectedElements}
 | 
			
		||||
            .delete=${(item: Token) => {
 | 
			
		||||
                return new CoreApi(DEFAULT_CONFIG).coreTokensDestroy({
 | 
			
		||||
                    identifier: item.identifier,
 | 
			
		||||
                });
 | 
			
		||||
            }}
 | 
			
		||||
        >
 | 
			
		||||
            <button ?disabled=${disabled} slot="trigger" class="pf-c-button pf-m-danger">
 | 
			
		||||
                ${t`Delete`}
 | 
			
		||||
            </button>
 | 
			
		||||
        </ak-forms-delete-bulk>`;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    row(item: Token): TemplateResult[] {
 | 
			
		||||
        return [
 | 
			
		||||
            html`${item.identifier}`,
 | 
			
		||||
            html`
 | 
			
		||||
                <ak-forms-modal>
 | 
			
		||||
                    <span slot="submit"> ${t`Update`} </span>
 | 
			
		||||
                    <span slot="header"> ${t`Update Token`} </span>
 | 
			
		||||
                    <ak-user-token-form slot="form" .instancePk=${item.identifier}>
 | 
			
		||||
                    </ak-user-token-form>
 | 
			
		||||
                    <button slot="trigger" class="pf-c-button pf-m-plain">
 | 
			
		||||
                        <i class="fas fa-edit"></i>
 | 
			
		||||
                    </button>
 | 
			
		||||
                </ak-forms-modal>
 | 
			
		||||
                <ak-token-copy-button identifier="${item.identifier}">
 | 
			
		||||
                    ${t`Copy Key`}
 | 
			
		||||
                </ak-token-copy-button>
 | 
			
		||||
            `,
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user