Add fuse-backed org search to superadmin org list (#2277)
Closes #2276 Adds a simple search bar to the superadmin interface that allows users to search for orgs by org name, id, users (names and emails), and subscriptions (subscription id and plan id). [Extended search](https://www.fusejs.io/examples.html#extended-search) is enabled, so exact search terms like `=stripe:sub_xxxxxxx` can be used to find a specific org directly. [See the docs](https://www.fusejs.io/examples.html#extended-search) for what operators are available. <img width="897" alt="Screenshot 2025-01-07 at 1 59 27 PM" src="https://github.com/user-attachments/assets/56c22fd0-5a61-4665-b904-d4534079158a" /> <img width="894" alt="Screenshot 2025-01-07 at 1 59 39 PM" src="https://github.com/user-attachments/assets/2a9fcee7-bcd0-4959-854c-e43daddbe7cf" />
This commit is contained in:
parent
3b6f63f030
commit
d6189eee9a
@ -7,7 +7,8 @@ import type {
|
||||
SlMenuItem,
|
||||
} from "@shoelace-style/shoelace";
|
||||
import { serialize } from "@shoelace-style/shoelace/dist/utilities/form.js";
|
||||
import { css, html, nothing } from "lit";
|
||||
import Fuse from "fuse.js";
|
||||
import { css, html, nothing, type PropertyValues } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators.js";
|
||||
import { when } from "lit/directives/when.js";
|
||||
|
||||
@ -56,12 +57,62 @@ export class OrgsList extends BtrixElement {
|
||||
@query("#orgDeleteButton")
|
||||
private readonly orgDeleteButton?: SlButton | null;
|
||||
|
||||
// For fuzzy search:
|
||||
private readonly fuse = new Fuse(this.orgList ?? [], {
|
||||
keys: [
|
||||
"id",
|
||||
"name",
|
||||
"slug",
|
||||
"users.name",
|
||||
"users.email",
|
||||
"subscription.subId",
|
||||
"subscription.planId",
|
||||
],
|
||||
useExtendedSearch: true,
|
||||
});
|
||||
|
||||
@state()
|
||||
private search = "";
|
||||
|
||||
protected willUpdate(changedProperties: PropertyValues<this>) {
|
||||
if (changedProperties.has("orgList")) {
|
||||
this.fuse.setCollection(this.orgList ?? []);
|
||||
}
|
||||
}
|
||||
|
||||
protected firstUpdated() {
|
||||
this.fuse.setCollection(this.orgList ?? []);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.skeleton) {
|
||||
return this.renderSkeleton();
|
||||
}
|
||||
|
||||
const orgs = this.search
|
||||
? this.fuse.search(this.search).map(({ item }) => item)
|
||||
: this.orgList;
|
||||
|
||||
return html`
|
||||
<sl-input
|
||||
value=${this.search}
|
||||
clearable
|
||||
size="small"
|
||||
class="mb-6"
|
||||
placeholder=${msg(
|
||||
"Search all orgs by name, id, slug, users, and subscriptions",
|
||||
)}
|
||||
@sl-input=${(e: Event) => {
|
||||
this.search = (e.target as SlInput).value.trim() || "";
|
||||
}}
|
||||
>
|
||||
<sl-icon
|
||||
name="search"
|
||||
slot="prefix"
|
||||
aria-hidden="true"
|
||||
library="default"
|
||||
></sl-icon
|
||||
></sl-input>
|
||||
<btrix-table>
|
||||
<btrix-table-head class="mb-2">
|
||||
<btrix-table-header-cell>
|
||||
@ -84,7 +135,7 @@ export class OrgsList extends BtrixElement {
|
||||
</btrix-table-header-cell>
|
||||
</btrix-table-head>
|
||||
<btrix-table-body class="rounded border">
|
||||
${this.orgList?.map(this.renderOrg)}
|
||||
${orgs?.map(this.renderOrg)}
|
||||
</btrix-table-body>
|
||||
</btrix-table>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user