web/admin: add toggle to hide deactivated users (#5419)

* web/admin: add toggle to hide deactivated users

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* make default user path configurable

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens L 2023-05-03 15:09:10 +03:00 committed by GitHub
parent a2994218e4
commit 4601864f94
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 66 additions and 15 deletions

View File

@ -266,11 +266,7 @@ export class AdminInterface extends Interface {
<ak-sidebar-item> <ak-sidebar-item>
<span slot="label">${t`Directory`}</span> <span slot="label">${t`Directory`}</span>
<ak-sidebar-item <ak-sidebar-item
path=${`/identity/users;${encodeURIComponent( path="/identity/users"
JSON.stringify({
path: "users",
}),
)}`}
.activeWhen=${[`^/identity/users/(?<id>${ID_REGEX})$`]} .activeWhen=${[`^/identity/users/(?<id>${ID_REGEX})$`]}
> >
<span slot="label">${t`Users`}</span> <span slot="label">${t`Users`}</span>

View File

@ -18,7 +18,7 @@ import { TablePage } from "@goauthentik/elements/table/TablePage";
import { t } from "@lingui/macro"; import { t } from "@lingui/macro";
import { TemplateResult, html } from "lit"; import { TemplateResult, html } from "lit";
import { customElement, property } from "lit/decorators.js"; import { customElement, property, state } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js"; import { ifDefined } from "lit/directives/if-defined.js";
import { PropertyMapping, PropertymappingsApi } from "@goauthentik/api"; import { PropertyMapping, PropertymappingsApi } from "@goauthentik/api";
@ -43,7 +43,7 @@ export class PropertyMappingListPage extends TablePage<PropertyMapping> {
@property() @property()
order = "name"; order = "name";
@property({ type: Boolean }) @state()
hideManaged = getURLParam<boolean>("hideManaged", true); hideManaged = getURLParam<boolean>("hideManaged", true);
async apiEndpoint(page: number): Promise<PaginatedResponse<PropertyMapping>> { async apiEndpoint(page: number): Promise<PaginatedResponse<PropertyMapping>> {

View File

@ -6,7 +6,7 @@ import "@goauthentik/admin/users/UserPasswordForm";
import "@goauthentik/admin/users/UserResetEmailForm"; import "@goauthentik/admin/users/UserResetEmailForm";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { MessageLevel } from "@goauthentik/common/messages"; import { MessageLevel } from "@goauthentik/common/messages";
import { uiConfig } from "@goauthentik/common/ui/config"; import { DefaultUIConfig, uiConfig } from "@goauthentik/common/ui/config";
import { first } from "@goauthentik/common/utils"; import { first } from "@goauthentik/common/utils";
import { rootInterface } from "@goauthentik/elements/Base"; import { rootInterface } from "@goauthentik/elements/Base";
import { PFColor } from "@goauthentik/elements/Label"; import { PFColor } from "@goauthentik/elements/Label";
@ -16,7 +16,7 @@ import "@goauthentik/elements/buttons/ActionButton";
import "@goauthentik/elements/forms/DeleteBulkForm"; import "@goauthentik/elements/forms/DeleteBulkForm";
import "@goauthentik/elements/forms/ModalForm"; import "@goauthentik/elements/forms/ModalForm";
import { showMessage } from "@goauthentik/elements/messages/MessageContainer"; import { showMessage } from "@goauthentik/elements/messages/MessageContainer";
import { getURLParam } from "@goauthentik/elements/router/RouteMatch"; import { getURLParam, updateURLParams } from "@goauthentik/elements/router/RouteMatch";
import { PaginatedResponse } from "@goauthentik/elements/table/Table"; import { PaginatedResponse } from "@goauthentik/elements/table/Table";
import { TableColumn } from "@goauthentik/elements/table/Table"; import { TableColumn } from "@goauthentik/elements/table/Table";
import { TablePage } from "@goauthentik/elements/table/TablePage"; import { TablePage } from "@goauthentik/elements/table/TablePage";
@ -54,7 +54,10 @@ export class UserListPage extends TablePage<User> {
order = "last_login"; order = "last_login";
@property() @property()
activePath = getURLParam<string>("path", "/"); activePath;
@state()
hideDeactivated = getURLParam<boolean>("hideDeactivated", false);
@state() @state()
userPaths?: UserPath; userPaths?: UserPath;
@ -63,6 +66,16 @@ export class UserListPage extends TablePage<User> {
return super.styles.concat(PFDescriptionList, PFCard, PFAlert); return super.styles.concat(PFDescriptionList, PFCard, PFAlert);
} }
constructor() {
super();
this.activePath = getURLParam<string>("path", "/");
uiConfig().then((c) => {
if (c.defaults.userPath !== new DefaultUIConfig().defaults.userPath) {
this.activePath = c.defaults.userPath;
}
});
}
async apiEndpoint(page: number): Promise<PaginatedResponse<User>> { async apiEndpoint(page: number): Promise<PaginatedResponse<User>> {
const users = await new CoreApi(DEFAULT_CONFIG).coreUsersList({ const users = await new CoreApi(DEFAULT_CONFIG).coreUsersList({
ordering: this.order, ordering: this.order,
@ -70,6 +83,7 @@ export class UserListPage extends TablePage<User> {
pageSize: (await uiConfig()).pagination.perPage, pageSize: (await uiConfig()).pagination.perPage,
search: this.search || "", search: this.search || "",
pathStartswith: getURLParam("path", ""), pathStartswith: getURLParam("path", ""),
isActive: this.hideDeactivated ? true : undefined,
}); });
this.userPaths = await new CoreApi(DEFAULT_CONFIG).coreUsersPathsRetrieve({ this.userPaths = await new CoreApi(DEFAULT_CONFIG).coreUsersPathsRetrieve({
search: this.search, search: this.search,
@ -131,6 +145,37 @@ export class UserListPage extends TablePage<User> {
</ak-forms-delete-bulk>`; </ak-forms-delete-bulk>`;
} }
renderToolbarAfter(): TemplateResult {
return html`&nbsp;
<div class="pf-c-toolbar__group pf-m-filter-group">
<div class="pf-c-toolbar__item pf-m-search-filter">
<div class="pf-c-input-group">
<label class="pf-c-switch">
<input
class="pf-c-switch__input"
type="checkbox"
?checked=${this.hideDeactivated}
@change=${() => {
this.hideDeactivated = !this.hideDeactivated;
this.page = 1;
this.fetch();
updateURLParams({
hideDeactivated: this.hideDeactivated,
});
}}
/>
<span class="pf-c-switch__toggle">
<span class="pf-c-switch__toggle-icon">
<i class="fas fa-check" aria-hidden="true"></i>
</span>
</span>
<span class="pf-c-switch__label">${t`Hide deactivated user`}</span>
</label>
</div>
</div>
</div>`;
}
row(item: User): TemplateResult[] { row(item: User): TemplateResult[] {
return [ return [
html`<a href="#/identity/users/${item.pk}"> html`<a href="#/identity/users/${item.pk}">

View File

@ -9,6 +9,8 @@ import {
ResponseContext, ResponseContext,
} from "@goauthentik/api"; } from "@goauthentik/api";
export const CSRFHeaderName = "X-authentik-CSRF";
export interface RequestInfo { export interface RequestInfo {
method: string; method: string;
path: string; path: string;
@ -32,7 +34,7 @@ export class LoggingMiddleware implements Middleware {
export class CSRFMiddleware implements Middleware { export class CSRFMiddleware implements Middleware {
pre?(context: RequestContext): Promise<FetchParams | void> { pre?(context: RequestContext): Promise<FetchParams | void> {
// @ts-ignore // @ts-ignore
context.init.headers["X-authentik-CSRF"] = getCookie("authentik_csrf"); context.init.headers[CSRFHeaderName] = getCookie("authentik_csrf");
return Promise.resolve(context); return Promise.resolve(context);
} }
} }

View File

@ -43,6 +43,9 @@ export interface UIConfig {
type: LayoutType; type: LayoutType;
}; };
locale: string; locale: string;
defaults: {
userPath: string,
},
} }
export class DefaultUIConfig implements UIConfig { export class DefaultUIConfig implements UIConfig {
@ -68,6 +71,9 @@ export class DefaultUIConfig implements UIConfig {
perPage: 20, perPage: 20,
}; };
locale = ""; locale = "";
defaults = {
userPath: "users",
};
constructor() { constructor() {
if (currentInterface() === "user") { if (currentInterface() === "user") {

View File

@ -1,3 +1,4 @@
import { CSRFHeaderName } from "@goauthentik/common/api/middleware";
import { EVENT_THEME_CHANGE } from "@goauthentik/common/constants"; import { EVENT_THEME_CHANGE } from "@goauthentik/common/constants";
import { globalAK } from "@goauthentik/common/global"; import { globalAK } from "@goauthentik/common/global";
import { first, getCookie } from "@goauthentik/common/utils"; import { first, getCookie } from "@goauthentik/common/utils";
@ -90,10 +91,7 @@ export class APIBrowser extends Interface {
}; };
}>, }>,
) => { ) => {
e.detail.request.headers.append( e.detail.request.headers.append(CSRFHeaderName, getCookie("authentik_csrf"));
"X-authentik-CSRF",
getCookie("authentik_csrf"),
);
}} }}
> >
<div slot="nav-logo"> <div slot="nav-logo">

View File

@ -4,6 +4,10 @@
How many items should be retrieved per page. Defaults to 20. How many items should be retrieved per page. Defaults to 20.
### `settings.defaults.userPath`
Default user path which is opened when opening the user list. Defaults to `users`.
### `settings.theme.base` ### `settings.theme.base`
Configure the base color scheme. Defaults to `automatic`, which switches between dark and light mode based on the users' browsers' preference. Choices: `automatic`, `dark`, `light`. Configure the base color scheme. Defaults to `automatic`, which switches between dark and light mode based on the users' browsers' preference. Choices: `automatic`, `dark`, `light`.