web/admin: allow modification of users groups from user view

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2021-08-10 21:27:41 +02:00
parent ec95a2bddc
commit 7db3be604c
5 changed files with 174 additions and 9 deletions

View File

@ -134,6 +134,7 @@ msgid "Active"
msgstr "Active" msgstr "Active"
#: src/pages/groups/MemberSelectModal.ts #: src/pages/groups/MemberSelectModal.ts
#: src/pages/users/GroupSelectModal.ts
msgid "Add" msgid "Add"
msgstr "Add" msgstr "Add"
@ -515,6 +516,7 @@ msgstr "Can be in the format of 'unix://' when connecting to a local docker daem
#: src/elements/forms/DeleteForm.ts #: src/elements/forms/DeleteForm.ts
#: src/elements/forms/ModalForm.ts #: src/elements/forms/ModalForm.ts
#: src/pages/groups/MemberSelectModal.ts #: src/pages/groups/MemberSelectModal.ts
#: src/pages/users/GroupSelectModal.ts
#: src/pages/users/UserActiveForm.ts #: src/pages/users/UserActiveForm.ts
msgid "Cancel" msgid "Cancel"
msgstr "Cancel" msgstr "Cancel"
@ -1814,6 +1816,7 @@ msgstr "Group {0}"
#: src/interfaces/AdminInterface.ts #: src/interfaces/AdminInterface.ts
#: src/pages/admin-overview/AdminOverviewPage.ts #: src/pages/admin-overview/AdminOverviewPage.ts
#: src/pages/groups/GroupListPage.ts #: src/pages/groups/GroupListPage.ts
#: src/pages/users/UserForm.ts
msgid "Groups" msgid "Groups"
msgstr "Groups" msgstr "Groups"
@ -1858,7 +1861,6 @@ msgid "Hide service-accounts"
msgstr "Hide service-accounts" msgstr "Hide service-accounts"
#: src/pages/events/RuleForm.ts #: src/pages/events/RuleForm.ts
#: src/pages/groups/GroupForm.ts
#: src/pages/outposts/OutpostForm.ts #: src/pages/outposts/OutpostForm.ts
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts #: src/pages/providers/oauth2/OAuth2ProviderForm.ts
#: src/pages/providers/saml/SAMLProviderForm.ts #: src/pages/providers/saml/SAMLProviderForm.ts
@ -2246,6 +2248,7 @@ msgstr "Loading"
#: src/pages/tenants/TenantForm.ts #: src/pages/tenants/TenantForm.ts
#: src/pages/tenants/TenantForm.ts #: src/pages/tenants/TenantForm.ts
#: src/pages/tenants/TenantForm.ts #: src/pages/tenants/TenantForm.ts
#: src/pages/users/UserForm.ts
#: src/pages/users/UserResetEmailForm.ts #: src/pages/users/UserResetEmailForm.ts
msgid "Loading..." msgid "Loading..."
msgstr "Loading..." msgstr "Loading..."
@ -2335,6 +2338,7 @@ msgstr "Maximum age (in days)"
#: src/pages/groups/GroupForm.ts #: src/pages/groups/GroupForm.ts
#: src/pages/groups/GroupListPage.ts #: src/pages/groups/GroupListPage.ts
#: src/pages/users/GroupSelectModal.ts
msgid "Members" msgid "Members"
msgstr "Members" msgstr "Members"
@ -2474,6 +2478,7 @@ msgstr "My Applications"
#: src/pages/stages/user_logout/UserLogoutStageForm.ts #: src/pages/stages/user_logout/UserLogoutStageForm.ts
#: src/pages/stages/user_write/UserWriteStageForm.ts #: src/pages/stages/user_write/UserWriteStageForm.ts
#: src/pages/user-settings/UserSelfForm.ts #: src/pages/user-settings/UserSelfForm.ts
#: src/pages/users/GroupSelectModal.ts
#: src/pages/users/UserForm.ts #: src/pages/users/UserForm.ts
#: src/pages/users/UserListPage.ts #: src/pages/users/UserListPage.ts
#: src/pages/users/UserViewPage.ts #: src/pages/users/UserViewPage.ts
@ -2520,6 +2525,7 @@ msgstr "New version available!"
#: src/pages/tenants/TenantListPage.ts #: src/pages/tenants/TenantListPage.ts
#: src/pages/tokens/TokenListPage.ts #: src/pages/tokens/TokenListPage.ts
#: src/pages/user-settings/tokens/UserTokenList.ts #: src/pages/user-settings/tokens/UserTokenList.ts
#: src/pages/users/GroupSelectModal.ts
#: src/pages/users/UserListPage.ts #: src/pages/users/UserListPage.ts
msgid "No" msgid "No"
msgstr "No" msgstr "No"
@ -3367,6 +3373,10 @@ msgstr "Select an enrollment flow"
msgid "Select an identification method." msgid "Select an identification method."
msgstr "Select an identification method." msgstr "Select an identification method."
#: src/pages/users/GroupSelectModal.ts
msgid "Select groups to add user to"
msgstr "Select groups to add user to"
#: src/flows/stages/identification/IdentificationStage.ts #: src/flows/stages/identification/IdentificationStage.ts
msgid "Select one of the sources below to login." msgid "Select one of the sources below to login."
msgstr "Select one of the sources below to login." msgstr "Select one of the sources below to login."
@ -3986,6 +3996,7 @@ msgstr "Successfully updated user."
msgid "Successfully updated {0} {1}" msgid "Successfully updated {0} {1}"
msgstr "Successfully updated {0} {1}" msgstr "Successfully updated {0} {1}"
#: src/pages/users/GroupSelectModal.ts
#: src/pages/users/UserListPage.ts #: src/pages/users/UserListPage.ts
#: src/pages/users/UserViewPage.ts #: src/pages/users/UserViewPage.ts
msgid "Superuser" msgid "Superuser"
@ -4870,6 +4881,7 @@ msgstr "X509 Subject"
#: src/pages/tenants/TenantListPage.ts #: src/pages/tenants/TenantListPage.ts
#: src/pages/tokens/TokenListPage.ts #: src/pages/tokens/TokenListPage.ts
#: src/pages/user-settings/tokens/UserTokenList.ts #: src/pages/user-settings/tokens/UserTokenList.ts
#: src/pages/users/GroupSelectModal.ts
#: src/pages/users/UserListPage.ts #: src/pages/users/UserListPage.ts
msgid "Yes" msgid "Yes"
msgstr "Yes" msgstr "Yes"

View File

@ -134,6 +134,7 @@ msgid "Active"
msgstr "" msgstr ""
#: src/pages/groups/MemberSelectModal.ts #: src/pages/groups/MemberSelectModal.ts
#: src/pages/users/GroupSelectModal.ts
msgid "Add" msgid "Add"
msgstr "" msgstr ""
@ -511,6 +512,7 @@ msgstr ""
#: src/elements/forms/DeleteForm.ts #: src/elements/forms/DeleteForm.ts
#: src/elements/forms/ModalForm.ts #: src/elements/forms/ModalForm.ts
#: src/pages/groups/MemberSelectModal.ts #: src/pages/groups/MemberSelectModal.ts
#: src/pages/users/GroupSelectModal.ts
#: src/pages/users/UserActiveForm.ts #: src/pages/users/UserActiveForm.ts
msgid "Cancel" msgid "Cancel"
msgstr "" msgstr ""
@ -1806,6 +1808,7 @@ msgstr ""
#: src/interfaces/AdminInterface.ts #: src/interfaces/AdminInterface.ts
#: src/pages/admin-overview/AdminOverviewPage.ts #: src/pages/admin-overview/AdminOverviewPage.ts
#: src/pages/groups/GroupListPage.ts #: src/pages/groups/GroupListPage.ts
#: src/pages/users/UserForm.ts
msgid "Groups" msgid "Groups"
msgstr "" msgstr ""
@ -1850,7 +1853,6 @@ msgid "Hide service-accounts"
msgstr "" msgstr ""
#: src/pages/events/RuleForm.ts #: src/pages/events/RuleForm.ts
#: src/pages/groups/GroupForm.ts
#: src/pages/outposts/OutpostForm.ts #: src/pages/outposts/OutpostForm.ts
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts #: src/pages/providers/oauth2/OAuth2ProviderForm.ts
#: src/pages/providers/saml/SAMLProviderForm.ts #: src/pages/providers/saml/SAMLProviderForm.ts
@ -2238,6 +2240,7 @@ msgstr ""
#: src/pages/tenants/TenantForm.ts #: src/pages/tenants/TenantForm.ts
#: src/pages/tenants/TenantForm.ts #: src/pages/tenants/TenantForm.ts
#: src/pages/tenants/TenantForm.ts #: src/pages/tenants/TenantForm.ts
#: src/pages/users/UserForm.ts
#: src/pages/users/UserResetEmailForm.ts #: src/pages/users/UserResetEmailForm.ts
msgid "Loading..." msgid "Loading..."
msgstr "" msgstr ""
@ -2327,6 +2330,7 @@ msgstr ""
#: src/pages/groups/GroupForm.ts #: src/pages/groups/GroupForm.ts
#: src/pages/groups/GroupListPage.ts #: src/pages/groups/GroupListPage.ts
#: src/pages/users/GroupSelectModal.ts
msgid "Members" msgid "Members"
msgstr "" msgstr ""
@ -2466,6 +2470,7 @@ msgstr ""
#: src/pages/stages/user_logout/UserLogoutStageForm.ts #: src/pages/stages/user_logout/UserLogoutStageForm.ts
#: src/pages/stages/user_write/UserWriteStageForm.ts #: src/pages/stages/user_write/UserWriteStageForm.ts
#: src/pages/user-settings/UserSelfForm.ts #: src/pages/user-settings/UserSelfForm.ts
#: src/pages/users/GroupSelectModal.ts
#: src/pages/users/UserForm.ts #: src/pages/users/UserForm.ts
#: src/pages/users/UserListPage.ts #: src/pages/users/UserListPage.ts
#: src/pages/users/UserViewPage.ts #: src/pages/users/UserViewPage.ts
@ -2512,6 +2517,7 @@ msgstr ""
#: src/pages/tenants/TenantListPage.ts #: src/pages/tenants/TenantListPage.ts
#: src/pages/tokens/TokenListPage.ts #: src/pages/tokens/TokenListPage.ts
#: src/pages/user-settings/tokens/UserTokenList.ts #: src/pages/user-settings/tokens/UserTokenList.ts
#: src/pages/users/GroupSelectModal.ts
#: src/pages/users/UserListPage.ts #: src/pages/users/UserListPage.ts
msgid "No" msgid "No"
msgstr "" msgstr ""
@ -3359,6 +3365,10 @@ msgstr ""
msgid "Select an identification method." msgid "Select an identification method."
msgstr "" msgstr ""
#: src/pages/users/GroupSelectModal.ts
msgid "Select groups to add user to"
msgstr ""
#: src/flows/stages/identification/IdentificationStage.ts #: src/flows/stages/identification/IdentificationStage.ts
msgid "Select one of the sources below to login." msgid "Select one of the sources below to login."
msgstr "" msgstr ""
@ -3978,6 +3988,7 @@ msgstr ""
msgid "Successfully updated {0} {1}" msgid "Successfully updated {0} {1}"
msgstr "" msgstr ""
#: src/pages/users/GroupSelectModal.ts
#: src/pages/users/UserListPage.ts #: src/pages/users/UserListPage.ts
#: src/pages/users/UserViewPage.ts #: src/pages/users/UserViewPage.ts
msgid "Superuser" msgid "Superuser"
@ -4853,6 +4864,7 @@ msgstr ""
#: src/pages/tenants/TenantListPage.ts #: src/pages/tenants/TenantListPage.ts
#: src/pages/tokens/TokenListPage.ts #: src/pages/tokens/TokenListPage.ts
#: src/pages/user-settings/tokens/UserTokenList.ts #: src/pages/user-settings/tokens/UserTokenList.ts
#: src/pages/users/GroupSelectModal.ts
#: src/pages/users/UserListPage.ts #: src/pages/users/UserListPage.ts
msgid "Yes" msgid "Yes"
msgstr "" msgstr ""

View File

@ -33,7 +33,7 @@ export class GroupForm extends ModelForm<Group, string> {
send = (data: Group): Promise<Group> => { send = (data: Group): Promise<Group> => {
if (this.instance?.pk) { if (this.instance?.pk) {
return new CoreApi(DEFAULT_CONFIG).coreGroupsUpdate({ return new CoreApi(DEFAULT_CONFIG).coreGroupsUpdate({
groupUuid: this.instance.pk || "", groupUuid: this.instance.pk,
groupRequest: data, groupRequest: data,
}); });
} else { } else {
@ -143,9 +143,6 @@ export class GroupForm extends ModelForm<Group, string> {
</ak-chip-group> </ak-chip-group>
</div> </div>
</div> </div>
<p class="pf-c-form__helper-text">
${t`Hold control/command to select multiple items.`}
</p>
</ak-form-element-horizontal> </ak-form-element-horizontal>
<ak-form-element-horizontal label=${t`Attributes`} ?required=${true} name="attributes"> <ak-form-element-horizontal label=${t`Attributes`} ?required=${true} name="attributes">
<ak-codemirror <ak-codemirror

View File

@ -0,0 +1,85 @@
import { t } from "@lingui/macro";
import { CoreApi, Group } from "authentik-api";
import { customElement, property } from "lit-element";
import { TemplateResult, html } from "lit-html";
import { AKResponse } from "../../api/Client";
import { DEFAULT_CONFIG } from "../../api/Config";
import { PAGE_SIZE } from "../../constants";
import { TableColumn } from "../../elements/table/Table";
import { TableModal } from "../../elements/table/TableModal";
import "../../elements/buttons/SpinnerButton";
@customElement("ak-user-group-select-table")
export class GroupSelectModal extends TableModal<Group> {
checkbox = true;
checkboxChip = true;
searchEnabled(): boolean {
return true;
}
@property()
confirm!: (selectedItems: Group[]) => Promise<unknown>;
order = "name";
apiEndpoint(page: number): Promise<AKResponse<Group>> {
return new CoreApi(DEFAULT_CONFIG).coreGroupsList({
ordering: this.order,
page: page,
pageSize: PAGE_SIZE / 2,
search: this.search || "",
});
}
columns(): TableColumn[] {
return [
new TableColumn(t`Name`, "username"),
new TableColumn(t`Superuser`, "is_superuser"),
new TableColumn(t`Members`, ""),
];
}
row(item: Group): TemplateResult[] {
return [
html`<div>
<div>${item.name}</div>
</div>`,
html`${item.isSuperuser ? t`Yes` : t`No`}`,
html`${item.users.length}`,
];
}
renderSelectedChip(item: Group): TemplateResult {
return html`${item.name}`;
}
renderModalInner(): TemplateResult {
return html`<section class="pf-c-page__main-section pf-m-light">
<div class="pf-c-content">
<h1 class="pf-c-title pf-m-2xl">${t`Select groups to add user to`}</h1>
</div>
</section>
<section class="pf-c-page__main-section pf-m-light">${this.renderTable()}</section>
<footer class="pf-c-modal-box__footer">
<ak-spinner-button
.callAction=${() => {
return this.confirm(this.selectedElements).then(() => {
this.open = false;
});
}}
class="pf-m-primary"
>
${t`Add`} </ak-spinner-button
>&nbsp;
<ak-spinner-button
.callAction=${async () => {
this.open = false;
}}
class="pf-m-secondary"
>
${t`Cancel`}
</ak-spinner-button>
</footer>`;
}
}

View File

@ -1,4 +1,4 @@
import { CoreApi, User } from "authentik-api"; import { CoreApi, Group, User } from "authentik-api";
import { t } from "@lingui/macro"; import { t } from "@lingui/macro";
import { customElement } from "lit-element"; import { customElement } from "lit-element";
import { html, TemplateResult } from "lit-html"; import { html, TemplateResult } from "lit-html";
@ -6,9 +6,11 @@ import { DEFAULT_CONFIG } from "../../api/Config";
import { ifDefined } from "lit-html/directives/if-defined"; import { ifDefined } from "lit-html/directives/if-defined";
import "../../elements/forms/HorizontalFormElement"; import "../../elements/forms/HorizontalFormElement";
import "../../elements/CodeMirror"; import "../../elements/CodeMirror";
import "./GroupSelectModal";
import YAML from "yaml"; import YAML from "yaml";
import { first } from "../../utils"; import { first } from "../../utils";
import { ModelForm } from "../../elements/forms/ModelForm"; import { ModelForm } from "../../elements/forms/ModelForm";
import { until } from "lit-html/directives/until";
@customElement("ak-user-form") @customElement("ak-user-form")
export class UserForm extends ModelForm<User, number> { export class UserForm extends ModelForm<User, number> {
@ -27,9 +29,9 @@ export class UserForm extends ModelForm<User, number> {
} }
send = (data: User): Promise<User> => { send = (data: User): Promise<User> => {
if (this.instance) { if (this.instance?.pk) {
return new CoreApi(DEFAULT_CONFIG).coreUsersUpdate({ return new CoreApi(DEFAULT_CONFIG).coreUsersUpdate({
id: this.instance.pk || 0, id: this.instance.pk,
userRequest: data, userRequest: data,
}); });
} else { } else {
@ -82,6 +84,63 @@ export class UserForm extends ModelForm<User, number> {
${t`Designates whether this user should be treated as active. Unselect this instead of deleting accounts.`} ${t`Designates whether this user should be treated as active. Unselect this instead of deleting accounts.`}
</p> </p>
</ak-form-element-horizontal> </ak-form-element-horizontal>
<ak-form-element-horizontal label=${t`Groups`} name="groups">
<div class="pf-c-input-group">
<ak-user-group-select-table
.confirm=${(items: Group[]) => {
// Because the model only has the IDs, map the group list to IDs
const ids = items.map((g) => g.pk);
if (!this.instance) this.instance = {} as User;
this.instance.groups = Array.from(this.instance?.groups || []).concat(
ids,
);
this.requestUpdate();
return Promise.resolve();
}}
>
<button slot="trigger" class="pf-c-button pf-m-control" type="button">
<i class="fas fa-plus" aria-hidden="true"></i>
</button>
</ak-user-group-select-table>
<div class="pf-c-form-control">
<ak-chip-group>
${until(
new CoreApi(DEFAULT_CONFIG)
.coreGroupsList({
ordering: "name",
})
.then((groups) => {
return groups.results.map((group) => {
const selected = Array.from(
this.instance?.groups || [],
).some((sg) => {
return sg == group.pk;
});
if (!selected) return;
return html`<ak-chip
.removable=${true}
value=${ifDefined(group.pk)}
@remove=${() => {
if (!this.instance) return;
const groups = Array.from(
this.instance?.groups || [],
);
const idx = groups.indexOf(group.pk);
groups.splice(idx, 1);
this.instance.groups = groups;
this.requestUpdate();
}}
>
${group.name}
</ak-chip>`;
});
}),
html`<option>${t`Loading...`}</option>`,
)}
</ak-chip-group>
</div>
</div>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${t`Attributes`} ?required=${true} name="attributes"> <ak-form-element-horizontal label=${t`Attributes`} ?required=${true} name="attributes">
<ak-codemirror <ak-codemirror
mode="yaml" mode="yaml"