This repository has been archived on 2024-05-31. You can view files and clone it, but cannot push or open issues or pull requests.
authentik/web/src/user/LibraryPage/ApplicationSearch.ts
gcp-cherry-pick-bot[bot] 70100fc105
web/user: fix search not updating app (cherry-pick #7825) (#7933)
web/user: fix search not updating app (#7825)

web/user: fix app not updating

so when using two classes in a classMap directive, the update fails (basically saying that each class must be separated), however this error only shows when directly calling requestUpdate and is swallowed somewhere when relying on the default render cycle

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens L <jens@goauthentik.io>
2023-12-19 18:30:23 +01:00

141 lines
3.8 KiB
TypeScript

import { AKElement } from "@goauthentik/elements/Base";
import { getURLParam, updateURLParams } from "@goauthentik/elements/router/RouteMatch";
import Fuse from "fuse.js";
import { FuseResult } from "fuse.js";
import { msg } from "@lit/localize";
import { css, html } from "lit";
import { customElement, property, query } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import PFDisplay from "@patternfly/patternfly/utilities/Display/display.css";
import type { Application } from "@goauthentik/api";
import { SEARCH_ITEM_SELECTED, SEARCH_UPDATED } from "./constants";
import { customEvent } from "./helpers";
@customElement("ak-library-list-search")
export class LibraryPageApplicationList extends AKElement {
static styles = [
PFBase,
PFDisplay,
css`
input {
width: 30ch;
box-sizing: border-box;
border: 0;
border-bottom: 1px solid;
border-bottom-color: var(--ak-accent);
background-color: transparent;
font-size: 1.5rem;
}
input:focus {
outline: 0;
}
`,
];
@property({ attribute: false })
set apps(value: Application[]) {
this.fuse.setCollection(value);
}
@property()
query = getURLParam<string | undefined>("search", undefined);
@query("input")
searchInput?: HTMLInputElement;
fuse: Fuse<Application>;
constructor() {
super();
this.fuse = new Fuse([], {
keys: [
{ name: "name", weight: 3 },
"slug",
"group",
{ name: "metaDescription", weight: 0.5 },
{ name: "metaPublisher", weight: 0.5 },
],
findAllMatches: true,
includeScore: true,
shouldSort: true,
ignoreFieldNorm: true,
useExtendedSearch: true,
threshold: 0.3,
});
}
onSelected(apps: FuseResult<Application>[]) {
this.dispatchEvent(
customEvent(SEARCH_UPDATED, {
apps: apps.map((app) => app.item),
}),
);
}
connectedCallback() {
super.connectedCallback();
if (!this.query) {
return;
}
const matchingApps = this.fuse.search(this.query);
if (matchingApps.length < 1) {
return;
}
this.onSelected(matchingApps);
}
resetSearch(): void {
if (this.searchInput) {
this.searchInput.value = "";
}
this.query = "";
updateURLParams({
search: this.query,
});
this.onSelected([]);
}
onInput(ev: InputEvent) {
this.query = (ev.target as HTMLInputElement).value;
if (this.query === "") {
return this.resetSearch();
}
updateURLParams({
search: this.query,
});
const apps = this.fuse.search(this.query);
if (apps.length < 1) return;
this.onSelected(apps);
}
onKeyDown(ev: KeyboardEvent) {
switch (ev.key) {
case "Escape": {
this.resetSearch();
return;
}
case "Enter": {
this.dispatchEvent(customEvent(SEARCH_ITEM_SELECTED));
return;
}
}
}
render() {
return html`<input
@input=${this.onInput}
@keydown=${this.onKeyDown}
type="text"
class="pf-u-display-none pf-u-display-block-on-md"
autofocus
placeholder=${msg("Search...")}
value=${ifDefined(this.query)}
/>`;
}
}