fix: Fix debounced inputs (#2191)

Fixes https://github.com/webrecorder/browsertrix/issues/2190

## Changes

- Fixes not being able to add live exclusion
- Fixes not being able to delete last exclusion
- Fixes collection list search
- Refactors exclusion form event name
This commit is contained in:
sua yoo 2024-12-02 17:04:40 -08:00 committed by GitHub
parent 99115473e5
commit 2c2b8227d9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 47 additions and 33 deletions

View File

@ -89,7 +89,17 @@ export class ExclusionEditor extends LiteElement {
? html`<btrix-queue-exclusion-table
?removable=${this.isActiveCrawl}
.exclusions=${this.config.exclude || []}
@btrix-remove=${this.deleteExclusion}
@btrix-change=${async (e: ExclusionRemoveEvent) => {
await this.updateComplete;
const { index, regex } = e.detail;
if (this.config?.exclude && index === 0 && !regex) {
void this.deleteExclusion({
regex: this.config.exclude[index],
});
}
}}
@btrix-remove=${(e: ExclusionRemoveEvent) =>
void this.deleteExclusion({ regex: e.detail.regex })}
>
</btrix-queue-exclusion-table>`
: html`
@ -102,8 +112,8 @@ export class ExclusionEditor extends LiteElement {
<btrix-queue-exclusion-form
?isSubmitting=${this.isSubmitting}
fieldErrorMessage=${this.exclusionFieldErrorMessage}
@on-change=${this.handleRegexChange}
@on-add=${this.handleAddRegex}
@btrix-change=${this.handleRegexChange}
@btrix-add=${this.handleAddRegex}
>
</btrix-queue-exclusion-form>
</div>`
@ -138,9 +148,7 @@ export class ExclusionEditor extends LiteElement {
}
}
private async deleteExclusion(e: ExclusionRemoveEvent) {
const { regex } = e.detail;
private async deleteExclusion({ regex }: { regex: string }) {
try {
const params = new URLSearchParams({ regex });
const data = await this.apiFetch<{ success: boolean }>(

View File

@ -1,7 +1,7 @@
import { localized, msg } from "@lit/localize";
import { type SlInput, type SlSelect } from "@shoelace-style/shoelace";
import { type PropertyValues } from "lit";
import { customElement, property, state } from "lit/decorators.js";
import { customElement, property, query, state } from "lit/decorators.js";
import debounce from "lodash/fp/debounce";
import type { UnderlyingFunction } from "@/types/utils";
@ -31,13 +31,13 @@ const MIN_LENGTH = 2;
* Usage example:
* ```ts
* <btrix-queue-exclusion-form
* @on-change=${this.handleExclusionChange}
* @on-add=${this.handleExclusionAdd}
* @btrix-change=${this.handleExclusionChange}
* @btrix-add=${this.handleExclusionAdd}
* ></btrix-queue-exclusion-form>
* ```
*
* @event on-change ExclusionChangeEvent
* @event on-add ExclusionAddEvent
* @fires btrix-change ExclusionChangeEvent
* @fires btrix-add ExclusionAddEvent
*/
@localized()
@customElement("btrix-queue-exclusion-form")
@ -52,18 +52,21 @@ export class QueueExclusionForm extends LiteElement {
private selectValue: Exclusion["type"] = "text";
@state()
private inputValue = "";
private regex = "";
@state()
private isRegexInvalid = false;
@query("sl-input")
private readonly input?: SlInput | null;
async willUpdate(
changedProperties: PropertyValues<this> & Map<string, unknown>,
) {
if (
changedProperties.get("selectValue") ||
(changedProperties.has("inputValue") &&
changedProperties.get("inputValue") !== undefined)
(changedProperties.has("regex") &&
changedProperties.get("regex") !== undefined)
) {
this.fieldErrorMessage = "";
this.checkInputValidity();
@ -107,7 +110,6 @@ export class QueueExclusionForm extends LiteElement {
placeholder=${this.selectValue === "text"
? "/skip-this-page"
: "example.com/skip.*"}
.value=${this.inputValue}
?disabled=${this.isSubmitting}
@keydown=${this.onKeyDown}
@sl-input=${this.onInput as UnderlyingFunction<
@ -151,7 +153,7 @@ export class QueueExclusionForm extends LiteElement {
<btrix-button
variant="neutral"
raised
?disabled=${!this.inputValue ||
?disabled=${!this.regex ||
this.isRegexInvalid ||
this.isSubmitting}
?loading=${this.isSubmitting}
@ -166,8 +168,8 @@ export class QueueExclusionForm extends LiteElement {
`;
}
private readonly onInput = debounce(200)((e: Event) => {
this.inputValue = (e.target as SlInput).value;
private readonly onInput = debounce(200)(() => {
this.regex = this.input?.value || "";
});
private onButtonClick() {
@ -184,12 +186,12 @@ export class QueueExclusionForm extends LiteElement {
private checkInputValidity(): void {
let isValid = true;
if (!this.inputValue || this.inputValue.length < MIN_LENGTH) {
if (!this.regex || this.regex.length < MIN_LENGTH) {
isValid = false;
} else if (this.selectValue === "regex") {
try {
// Check if valid regex
new RegExp(this.inputValue);
new RegExp(this.regex);
} catch (err) {
this.fieldErrorMessage = (err as Error).message;
isValid = false;
@ -202,12 +204,10 @@ export class QueueExclusionForm extends LiteElement {
private async dispatchChangeEvent() {
await this.updateComplete;
this.dispatchEvent(
new CustomEvent("on-change", {
new CustomEvent("btrix-change", {
detail: {
value:
this.selectValue === "text"
? regexEscape(this.inputValue)
: this.inputValue,
this.selectValue === "text" ? regexEscape(this.regex) : this.regex,
valid: !this.isRegexInvalid,
},
}) as ExclusionChangeEvent,
@ -217,19 +217,23 @@ export class QueueExclusionForm extends LiteElement {
private async handleAdd() {
this.onInput.flush();
await this.updateComplete;
if (!this.inputValue) return;
if (!this.regex) return;
let regex = this.inputValue;
if (this.input) {
this.input.value = "";
}
let regex = this.regex;
if (this.selectValue === "text") {
regex = regexEscape(this.inputValue);
regex = regexEscape(this.regex);
}
this.dispatchEvent(
new CustomEvent("on-add", {
new CustomEvent("btrix-add", {
detail: {
regex,
onSuccess: () => {
this.inputValue = "";
this.regex = "";
},
},
}) as ExclusionAddEvent,

View File

@ -2,7 +2,7 @@ import { localized, msg } from "@lit/localize";
import type { SlInput, SlMenuItem } from "@shoelace-style/shoelace";
import Fuse from "fuse.js";
import { html, type PropertyValues } from "lit";
import { customElement, property, state } from "lit/decorators.js";
import { customElement, property, query, state } from "lit/decorators.js";
import { guard } from "lit/directives/guard.js";
import { when } from "lit/directives/when.js";
import debounce from "lodash/fp/debounce";
@ -91,6 +91,9 @@ export class CollectionsList extends BtrixElement {
@state()
private fetchErrorStatusCode?: number;
@query("sl-input")
private readonly input?: SlInput | null;
// For fuzzy search:
private readonly fuse = new Fuse<{ key: "name"; value: string }>([], {
keys: ["value"],
@ -339,7 +342,6 @@ export class CollectionsList extends BtrixElement {
size="small"
placeholder=${msg("Search by Name")}
clearable
value=${this.searchByValue}
@sl-clear=${() => {
this.searchResultsOpen = false;
this.onSearchInput.cancel();
@ -627,8 +629,8 @@ export class CollectionsList extends BtrixElement {
</div>
`;
private readonly onSearchInput = debounce(150)((e: Event) => {
this.searchByValue = (e.target as SlInput).value.trim();
private readonly onSearchInput = debounce(150)(() => {
this.searchByValue = this.input?.value.trim() || "";
if (!this.searchResultsOpen && this.hasSearchStr) {
this.searchResultsOpen = true;