web/user: rework user source connection UI

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2021-12-30 21:59:41 +01:00
parent fc19372709
commit 9154b9b85d
14 changed files with 155 additions and 105 deletions

View File

@ -29,3 +29,4 @@ class UserSettingSerializer(PassiveSerializer):
component = CharField() component = CharField()
title = CharField() title = CharField()
configure_url = CharField(required=False) configure_url = CharField(required=False)
icon_url = CharField()

View File

@ -75,14 +75,17 @@ class OAuthSource(Source):
) )
def ui_user_settings(self) -> Optional[UserSettingSerializer]: def ui_user_settings(self) -> Optional[UserSettingSerializer]:
provider_type = self.type
provider = provider_type()
return UserSettingSerializer( return UserSettingSerializer(
data={ data={
"title": f"OAuth {self.name}", "title": self.name,
"component": "ak-user-settings-source-oauth", "component": "ak-user-settings-source-oauth",
"configure_url": reverse( "configure_url": reverse(
"authentik_sources_oauth:oauth-client-login", "authentik_sources_oauth:oauth-client-login",
kwargs={"source_slug": self.slug}, kwargs={"source_slug": self.slug},
), ),
"icon_url": provider.icon_url(),
} }
) )

View File

@ -80,9 +80,10 @@ class PlexSource(Source):
def ui_user_settings(self) -> Optional[UserSettingSerializer]: def ui_user_settings(self) -> Optional[UserSettingSerializer]:
return UserSettingSerializer( return UserSettingSerializer(
data={ data={
"title": f"Plex {self.name}", "title": self.name,
"component": "ak-user-settings-source-plex", "component": "ak-user-settings-source-plex",
"configure_url": self.client_id, "configure_url": self.client_id,
"icon_url": static("authentik/sources/plex.svg"),
} }
) )

View File

@ -31275,8 +31275,11 @@ components:
type: string type: string
configure_url: configure_url:
type: string type: string
icon_url:
type: string
required: required:
- component - component
- icon_url
- object_uid - object_uid
- title - title
UserSourceConnection: UserSourceConnection:

View File

@ -339,9 +339,16 @@ html > form > input {
) !important; ) !important;
} }
/* data list */ /* data list */
.pf-c-data-list {
border-top-color: var(--ak-dark-background-lighter);
}
.pf-c-data-list__item { .pf-c-data-list__item {
--pf-c-data-list__item--BackgroundColor: var(--ak-dark-background-light); --pf-c-data-list__item--BackgroundColor: transparent;
--pf-c-data-list__item--BorderBottomColor: var(--ak-dark-background-lighter); --pf-c-data-list__item--BorderBottomColor: var(--ak-dark-background-lighter);
color: var(--ak-dark-foreground); color: var(--ak-dark-foreground);
} }
} }
.pf-c-data-list__item {
background-color: transparent;
}

View File

@ -168,13 +168,13 @@ export class IdentificationStage extends BaseStage<
} }
return html`<div class="pf-c-login__main-footer-band"> return html`<div class="pf-c-login__main-footer-band">
${this.challenge.enrollUrl ${this.challenge.enrollUrl
? html` <p class="pf-c-login__main-footer-band-item"> ? html`<p class="pf-c-login__main-footer-band-item">
${t`Need an account?`} ${t`Need an account?`}
<a id="enroll" href="${this.challenge.enrollUrl}">${t`Sign up.`}</a> <a id="enroll" href="${this.challenge.enrollUrl}">${t`Sign up.`}</a>
</p>` </p>`
: html``} : html``}
${this.challenge.recoveryUrl ${this.challenge.recoveryUrl
? html` <p class="pf-c-login__main-footer-band-item"> ? html`<p class="pf-c-login__main-footer-band-item">
<a id="recovery" href="${this.challenge.recoveryUrl}" <a id="recovery" href="${this.challenge.recoveryUrl}"
>${t`Forgot username or password?`}</a >${t`Forgot username or password?`}</a
> >

View File

@ -988,14 +988,18 @@ msgstr "Connect"
msgid "Connect to the LDAP Server on port 389:" msgid "Connect to the LDAP Server on port 389:"
msgstr "Connect to the LDAP Server on port 389:" msgstr "Connect to the LDAP Server on port 389:"
#: src/user/user-settings/sources/SourceSettings.ts
msgid "Connect your user account to the services listed below, to allow you to login using the service instead of traditional credentials."
msgstr "Connect your user account to the services listed below, to allow you to login using the service instead of traditional credentials."
#: src/user/user-settings/UserSettingsPage.ts #: src/user/user-settings/UserSettingsPage.ts
msgid "Connected services" msgid "Connected services"
msgstr "Connected services" msgstr "Connected services"
#: src/user/user-settings/sources/SourceSettingsOAuth.ts #: src/user/user-settings/sources/SourceSettingsOAuth.ts
#: src/user/user-settings/sources/SourceSettingsPlex.ts #: src/user/user-settings/sources/SourceSettingsPlex.ts
msgid "Connected." #~ msgid "Connected."
msgstr "Connected." #~ msgstr "Connected."
#: src/common/ws.ts #: src/common/ws.ts
msgid "Connection error, reconnecting..." msgid "Connection error, reconnecting..."
@ -3138,8 +3142,8 @@ msgstr "Not configured action"
#: src/user/user-settings/sources/SourceSettingsOAuth.ts #: src/user/user-settings/sources/SourceSettingsOAuth.ts
#: src/user/user-settings/sources/SourceSettingsPlex.ts #: src/user/user-settings/sources/SourceSettingsPlex.ts
msgid "Not connected." #~ msgid "Not connected."
msgstr "Not connected." #~ msgstr "Not connected."
#: src/elements/router/Router404.ts #: src/elements/router/Router404.ts
msgid "Not found" msgid "Not found"
@ -4329,8 +4333,8 @@ msgstr "Source linked"
#: src/user/user-settings/sources/SourceSettingsOAuth.ts #: src/user/user-settings/sources/SourceSettingsOAuth.ts
#: src/user/user-settings/sources/SourceSettingsPlex.ts #: src/user/user-settings/sources/SourceSettingsPlex.ts
msgid "Source {0}" #~ msgid "Source {0}"
msgstr "Source {0}" #~ msgstr "Source {0}"
#: src/pages/sources/SourcesListPage.ts #: src/pages/sources/SourcesListPage.ts
msgid "Source(s)" msgid "Source(s)"

View File

@ -987,14 +987,18 @@ msgstr "Connecter"
msgid "Connect to the LDAP Server on port 389:" msgid "Connect to the LDAP Server on port 389:"
msgstr "" msgstr ""
#: src/user/user-settings/sources/SourceSettings.ts
msgid "Connect your user account to the services listed below, to allow you to login using the service instead of traditional credentials."
msgstr ""
#: src/user/user-settings/UserSettingsPage.ts #: src/user/user-settings/UserSettingsPage.ts
msgid "Connected services" msgid "Connected services"
msgstr "Services connectés" msgstr "Services connectés"
#: src/user/user-settings/sources/SourceSettingsOAuth.ts #: src/user/user-settings/sources/SourceSettingsOAuth.ts
#: src/user/user-settings/sources/SourceSettingsPlex.ts #: src/user/user-settings/sources/SourceSettingsPlex.ts
msgid "Connected." #~ msgid "Connected."
msgstr "Connecté." #~ msgstr "Connecté."
#: src/common/ws.ts #: src/common/ws.ts
msgid "Connection error, reconnecting..." msgid "Connection error, reconnecting..."
@ -3117,8 +3121,8 @@ msgstr "Action non configurée"
#: src/user/user-settings/sources/SourceSettingsOAuth.ts #: src/user/user-settings/sources/SourceSettingsOAuth.ts
#: src/user/user-settings/sources/SourceSettingsPlex.ts #: src/user/user-settings/sources/SourceSettingsPlex.ts
msgid "Not connected." #~ msgid "Not connected."
msgstr "Déconnecté." #~ msgstr "Déconnecté."
#: src/elements/router/Router404.ts #: src/elements/router/Router404.ts
msgid "Not found" msgid "Not found"
@ -4292,8 +4296,8 @@ msgstr "Source liée"
#: src/user/user-settings/sources/SourceSettingsOAuth.ts #: src/user/user-settings/sources/SourceSettingsOAuth.ts
#: src/user/user-settings/sources/SourceSettingsPlex.ts #: src/user/user-settings/sources/SourceSettingsPlex.ts
msgid "Source {0}" #~ msgid "Source {0}"
msgstr "Source {0}" #~ msgstr "Source {0}"
#: src/pages/sources/SourcesListPage.ts #: src/pages/sources/SourcesListPage.ts
msgid "Source(s)" msgid "Source(s)"

View File

@ -982,14 +982,18 @@ msgstr ""
msgid "Connect to the LDAP Server on port 389:" msgid "Connect to the LDAP Server on port 389:"
msgstr "" msgstr ""
#: src/user/user-settings/sources/SourceSettings.ts
msgid "Connect your user account to the services listed below, to allow you to login using the service instead of traditional credentials."
msgstr ""
#: src/user/user-settings/UserSettingsPage.ts #: src/user/user-settings/UserSettingsPage.ts
msgid "Connected services" msgid "Connected services"
msgstr "" msgstr ""
#: src/user/user-settings/sources/SourceSettingsOAuth.ts #: src/user/user-settings/sources/SourceSettingsOAuth.ts
#: src/user/user-settings/sources/SourceSettingsPlex.ts #: src/user/user-settings/sources/SourceSettingsPlex.ts
msgid "Connected." #~ msgid "Connected."
msgstr "" #~ msgstr ""
#: src/common/ws.ts #: src/common/ws.ts
msgid "Connection error, reconnecting..." msgid "Connection error, reconnecting..."
@ -3128,8 +3132,8 @@ msgstr ""
#: src/user/user-settings/sources/SourceSettingsOAuth.ts #: src/user/user-settings/sources/SourceSettingsOAuth.ts
#: src/user/user-settings/sources/SourceSettingsPlex.ts #: src/user/user-settings/sources/SourceSettingsPlex.ts
msgid "Not connected." #~ msgid "Not connected."
msgstr "" #~ msgstr ""
#: src/elements/router/Router404.ts #: src/elements/router/Router404.ts
msgid "Not found" msgid "Not found"
@ -4319,8 +4323,8 @@ msgstr ""
#: src/user/user-settings/sources/SourceSettingsOAuth.ts #: src/user/user-settings/sources/SourceSettingsOAuth.ts
#: src/user/user-settings/sources/SourceSettingsPlex.ts #: src/user/user-settings/sources/SourceSettingsPlex.ts
msgid "Source {0}" #~ msgid "Source {0}"
msgstr "" #~ msgstr ""
#: src/pages/sources/SourcesListPage.ts #: src/pages/sources/SourcesListPage.ts
msgid "Source(s)" msgid "Source(s)"

View File

@ -978,14 +978,18 @@ msgstr "Bağlan"
msgid "Connect to the LDAP Server on port 389:" msgid "Connect to the LDAP Server on port 389:"
msgstr "Bağlantı noktası 389 LDAP sunucusuna bağlanın:" msgstr "Bağlantı noktası 389 LDAP sunucusuna bağlanın:"
#: src/user/user-settings/sources/SourceSettings.ts
msgid "Connect your user account to the services listed below, to allow you to login using the service instead of traditional credentials."
msgstr ""
#: src/user/user-settings/UserSettingsPage.ts #: src/user/user-settings/UserSettingsPage.ts
msgid "Connected services" msgid "Connected services"
msgstr "Bağlı hizmetler" msgstr "Bağlı hizmetler"
#: src/user/user-settings/sources/SourceSettingsOAuth.ts #: src/user/user-settings/sources/SourceSettingsOAuth.ts
#: src/user/user-settings/sources/SourceSettingsPlex.ts #: src/user/user-settings/sources/SourceSettingsPlex.ts
msgid "Connected." #~ msgid "Connected."
msgstr "Bağlantılı." #~ msgstr "Bağlantılı."
#: src/common/ws.ts #: src/common/ws.ts
msgid "Connection error, reconnecting..." msgid "Connection error, reconnecting..."
@ -3091,8 +3095,8 @@ msgstr "Yapılandırılmış eylem"
#: src/user/user-settings/sources/SourceSettingsOAuth.ts #: src/user/user-settings/sources/SourceSettingsOAuth.ts
#: src/user/user-settings/sources/SourceSettingsPlex.ts #: src/user/user-settings/sources/SourceSettingsPlex.ts
msgid "Not connected." #~ msgid "Not connected."
msgstr "Bağlantılı değil." #~ msgstr "Bağlantılı değil."
#: src/elements/router/Router404.ts #: src/elements/router/Router404.ts
msgid "Not found" msgid "Not found"
@ -4253,8 +4257,8 @@ msgstr "Kaynak bağlantılı"
#: src/user/user-settings/sources/SourceSettingsOAuth.ts #: src/user/user-settings/sources/SourceSettingsOAuth.ts
#: src/user/user-settings/sources/SourceSettingsPlex.ts #: src/user/user-settings/sources/SourceSettingsPlex.ts
msgid "Source {0}" #~ msgid "Source {0}"
msgstr "Kaynak {0}" #~ msgstr "Kaynak {0}"
#: src/pages/sources/SourcesListPage.ts #: src/pages/sources/SourcesListPage.ts
msgid "Source(s)" msgid "Source(s)"

View File

@ -3,7 +3,6 @@ import { property } from "lit/decorators.js";
import AKGlobal from "../../authentik.css"; import AKGlobal from "../../authentik.css";
import PFButton from "@patternfly/patternfly/components/Button/button.css"; import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFCard from "@patternfly/patternfly/components/Card/card.css";
import PFForm from "@patternfly/patternfly/components/Form/form.css"; import PFForm from "@patternfly/patternfly/components/Form/form.css";
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css"; import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css"; import PFBase from "@patternfly/patternfly/patternfly-base.css";
@ -16,6 +15,6 @@ export abstract class BaseUserSettings extends LitElement {
configureUrl?: string; configureUrl?: string;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
return [PFBase, PFCard, PFButton, PFForm, PFFormControl, AKGlobal]; return [PFBase, PFButton, PFForm, PFFormControl, AKGlobal];
} }
} }

View File

@ -1,10 +1,12 @@
import { t } from "@lingui/macro"; import { t } from "@lingui/macro";
import { CSSResult, LitElement, TemplateResult, html } from "lit"; import { CSSResult, LitElement, TemplateResult, css, html } from "lit";
import { customElement, property } from "lit/decorators.js"; import { customElement, property } from "lit/decorators.js";
import { until } from "lit/directives/until.js"; import { until } from "lit/directives/until.js";
import PFGrid from "@patternfly/patternfly/layouts/Grid/grid.css"; import AKGlobal from "../../../authentik.css";
import PFContent from "@patternfly/patternfly/components/Content/content.css";
import PFDataList from "@patternfly/patternfly/components/DataList/data-list.css";
import { SourcesApi, UserSetting } from "@goauthentik/api"; import { SourcesApi, UserSetting } from "@goauthentik/api";
@ -20,7 +22,27 @@ export class UserSourceSettingsPage extends LitElement {
sourceSettings?: Promise<UserSetting[]>; sourceSettings?: Promise<UserSetting[]>;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
return [PFGrid]; return [
PFDataList,
PFContent,
AKGlobal,
css`
.pf-c-data-list__cell {
display: flex;
align-items: center;
}
.pf-c-data-list__cell img {
max-width: 48px;
width: 48px;
margin-right: 16px;
}
@media (prefers-color-scheme: dark) {
.pf-c-data-list__cell img {
filter: invert(1);
}
}
`,
];
} }
constructor() { constructor() {
@ -38,6 +60,7 @@ export class UserSourceSettingsPage extends LitElement {
switch (source.component) { switch (source.component) {
case "ak-user-settings-source-oauth": case "ak-user-settings-source-oauth":
return html`<ak-user-settings-source-oauth return html`<ak-user-settings-source-oauth
class="pf-c-data-list__item-row"
objectId=${source.objectUid} objectId=${source.objectUid}
title=${source.title} title=${source.title}
.configureUrl=${source.configureUrl} .configureUrl=${source.configureUrl}
@ -45,6 +68,7 @@ export class UserSourceSettingsPage extends LitElement {
</ak-user-settings-source-oauth>`; </ak-user-settings-source-oauth>`;
case "ak-user-settings-source-plex": case "ak-user-settings-source-plex":
return html`<ak-user-settings-source-plex return html`<ak-user-settings-source-plex
class="pf-c-data-list__item-row"
objectId=${source.objectUid} objectId=${source.objectUid}
title=${source.title} title=${source.title}
.configureUrl=${source.configureUrl} .configureUrl=${source.configureUrl}
@ -56,22 +80,36 @@ export class UserSourceSettingsPage extends LitElement {
} }
render(): TemplateResult { render(): TemplateResult {
return html`<div class="pf-l-grid pf-m-gutter"> return html` <div class="pf-c-content">
${until( <p>
this.sourceSettings?.then((source) => { ${t`Connect your user account to the services listed below, to allow you to login using the service instead of traditional credentials.`}
if (source.length < 1) { </p>
return html`<ak-empty-state </div>
header=${t`No services available.`} <ul class="pf-c-data-list" role="list">
></ak-empty-state>`; ${until(
} this.sourceSettings?.then((source) => {
return source.map((stage) => { if (source.length < 1) {
return html`<div class="pf-l-grid__item pf-m-6-col pf-m-4-col-on-xl"> return html`<ak-empty-state
${this.renderSourceSettings(stage)} header=${t`No services available.`}
</div>`; ></ak-empty-state>`;
}); }
}), return source.map((stage) => {
html`<ak-empty-state ?loading="${true}" header=${t`Loading`}> </ak-empty-state>`, return html`<li class="pf-c-data-list__item">
)} <div class="pf-c-data-list__item-content">
</div>`; <div class="pf-c-data-list__cell">
<img src="${stage.iconUrl}" />
${stage.title}
</div>
<div class="pf-c-data-list__cell">
${this.renderSourceSettings(stage)}
</div>
</div>
</li>`;
});
}),
html`<ak-empty-state ?loading="${true}" header=${t`Loading`}>
</ak-empty-state>`,
)}
</ul>`;
} }
} }

View File

@ -16,13 +16,6 @@ export class SourceSettingsOAuth extends BaseUserSettings {
title!: string; title!: string;
render(): TemplateResult { 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( return html`${until(
new SourcesApi(DEFAULT_CONFIG) new SourcesApi(DEFAULT_CONFIG)
.sourcesUserConnectionsOauthList({ .sourcesUserConnectionsOauthList({
@ -30,29 +23,27 @@ export class SourceSettingsOAuth extends BaseUserSettings {
}) })
.then((connection) => { .then((connection) => {
if (connection.results.length > 0) { if (connection.results.length > 0) {
return html`<p>${t`Connected.`}</p> return html` <button
<button class="pf-c-button pf-m-danger"
class="pf-c-button pf-m-danger" @click=${() => {
@click=${() => { return new SourcesApi(
return new SourcesApi( DEFAULT_CONFIG,
DEFAULT_CONFIG, ).sourcesUserConnectionsOauthDestroy({
).sourcesUserConnectionsOauthDestroy({ id: connection.results[0].pk || 0,
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)}${AndNext(
"/if/user/#/settings;page-sources",
)}"
> >
${t`Connect`} ${t`Disconnect`}
</a>`; </button>`;
}
return html` <a
class="pf-c-button pf-m-primary"
href="${ifDefined(this.configureUrl)}${AndNext(
"/if/user/#/settings;page-sources",
)}"
>
${t`Connect`}
</a>`;
}), }),
)}`; )}`;
} }

View File

@ -16,13 +16,6 @@ export class SourceSettingsPlex extends BaseUserSettings {
@property() @property()
title!: string; 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>`;
}
async doPlex(): Promise<void> { async doPlex(): Promise<void> {
const authInfo = await PlexAPIClient.getPin(this.configureUrl || ""); const authInfo = await PlexAPIClient.getPin(this.configureUrl || "");
const authWindow = popupCenterScreen(authInfo.authUrl, "plex auth", 550, 700); const authWindow = popupCenterScreen(authInfo.authUrl, "plex auth", 550, 700);
@ -43,7 +36,7 @@ export class SourceSettingsPlex extends BaseUserSettings {
); );
} }
renderInner(): TemplateResult { render(): TemplateResult {
return html`${until( return html`${until(
new SourcesApi(DEFAULT_CONFIG) new SourcesApi(DEFAULT_CONFIG)
.sourcesUserConnectionsPlexList({ .sourcesUserConnectionsPlexList({
@ -51,24 +44,22 @@ export class SourceSettingsPlex extends BaseUserSettings {
}) })
.then((connection) => { .then((connection) => {
if (connection.results.length > 0) { if (connection.results.length > 0) {
return html`<p>${t`Connected.`}</p> return html` <button
<button class="pf-c-button pf-m-danger"
class="pf-c-button pf-m-danger" @click=${() => {
@click=${() => { return new SourcesApi(
return new SourcesApi( DEFAULT_CONFIG,
DEFAULT_CONFIG, ).sourcesUserConnectionsPlexDestroy({
).sourcesUserConnectionsPlexDestroy({ id: connection.results[0].pk || 0,
id: connection.results[0].pk || 0, });
}); }}
}} >
> ${t`Disconnect`}
${t`Disconnect`}
</button>`;
}
return html`<p>${t`Not connected.`}</p>
<button @click=${this.doPlex} class="pf-c-button pf-m-primary">
${t`Connect`}
</button>`; </button>`;
}
return html` <button @click=${this.doPlex} class="pf-c-button pf-m-primary">
${t`Connect`}
</button>`;
}), }),
)}`; )}`;
} }