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:
parent
99115473e5
commit
2c2b8227d9
@ -89,7 +89,17 @@ export class ExclusionEditor extends LiteElement {
|
|||||||
? html`<btrix-queue-exclusion-table
|
? html`<btrix-queue-exclusion-table
|
||||||
?removable=${this.isActiveCrawl}
|
?removable=${this.isActiveCrawl}
|
||||||
.exclusions=${this.config.exclude || []}
|
.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>`
|
</btrix-queue-exclusion-table>`
|
||||||
: html`
|
: html`
|
||||||
@ -102,8 +112,8 @@ export class ExclusionEditor extends LiteElement {
|
|||||||
<btrix-queue-exclusion-form
|
<btrix-queue-exclusion-form
|
||||||
?isSubmitting=${this.isSubmitting}
|
?isSubmitting=${this.isSubmitting}
|
||||||
fieldErrorMessage=${this.exclusionFieldErrorMessage}
|
fieldErrorMessage=${this.exclusionFieldErrorMessage}
|
||||||
@on-change=${this.handleRegexChange}
|
@btrix-change=${this.handleRegexChange}
|
||||||
@on-add=${this.handleAddRegex}
|
@btrix-add=${this.handleAddRegex}
|
||||||
>
|
>
|
||||||
</btrix-queue-exclusion-form>
|
</btrix-queue-exclusion-form>
|
||||||
</div>`
|
</div>`
|
||||||
@ -138,9 +148,7 @@ export class ExclusionEditor extends LiteElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async deleteExclusion(e: ExclusionRemoveEvent) {
|
private async deleteExclusion({ regex }: { regex: string }) {
|
||||||
const { regex } = e.detail;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const params = new URLSearchParams({ regex });
|
const params = new URLSearchParams({ regex });
|
||||||
const data = await this.apiFetch<{ success: boolean }>(
|
const data = await this.apiFetch<{ success: boolean }>(
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { localized, msg } from "@lit/localize";
|
import { localized, msg } from "@lit/localize";
|
||||||
import { type SlInput, type SlSelect } from "@shoelace-style/shoelace";
|
import { type SlInput, type SlSelect } from "@shoelace-style/shoelace";
|
||||||
import { type PropertyValues } from "lit";
|
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 debounce from "lodash/fp/debounce";
|
||||||
|
|
||||||
import type { UnderlyingFunction } from "@/types/utils";
|
import type { UnderlyingFunction } from "@/types/utils";
|
||||||
@ -31,13 +31,13 @@ const MIN_LENGTH = 2;
|
|||||||
* Usage example:
|
* Usage example:
|
||||||
* ```ts
|
* ```ts
|
||||||
* <btrix-queue-exclusion-form
|
* <btrix-queue-exclusion-form
|
||||||
* @on-change=${this.handleExclusionChange}
|
* @btrix-change=${this.handleExclusionChange}
|
||||||
* @on-add=${this.handleExclusionAdd}
|
* @btrix-add=${this.handleExclusionAdd}
|
||||||
* ></btrix-queue-exclusion-form>
|
* ></btrix-queue-exclusion-form>
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* @event on-change ExclusionChangeEvent
|
* @fires btrix-change ExclusionChangeEvent
|
||||||
* @event on-add ExclusionAddEvent
|
* @fires btrix-add ExclusionAddEvent
|
||||||
*/
|
*/
|
||||||
@localized()
|
@localized()
|
||||||
@customElement("btrix-queue-exclusion-form")
|
@customElement("btrix-queue-exclusion-form")
|
||||||
@ -52,18 +52,21 @@ export class QueueExclusionForm extends LiteElement {
|
|||||||
private selectValue: Exclusion["type"] = "text";
|
private selectValue: Exclusion["type"] = "text";
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
private inputValue = "";
|
private regex = "";
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
private isRegexInvalid = false;
|
private isRegexInvalid = false;
|
||||||
|
|
||||||
|
@query("sl-input")
|
||||||
|
private readonly input?: SlInput | null;
|
||||||
|
|
||||||
async willUpdate(
|
async willUpdate(
|
||||||
changedProperties: PropertyValues<this> & Map<string, unknown>,
|
changedProperties: PropertyValues<this> & Map<string, unknown>,
|
||||||
) {
|
) {
|
||||||
if (
|
if (
|
||||||
changedProperties.get("selectValue") ||
|
changedProperties.get("selectValue") ||
|
||||||
(changedProperties.has("inputValue") &&
|
(changedProperties.has("regex") &&
|
||||||
changedProperties.get("inputValue") !== undefined)
|
changedProperties.get("regex") !== undefined)
|
||||||
) {
|
) {
|
||||||
this.fieldErrorMessage = "";
|
this.fieldErrorMessage = "";
|
||||||
this.checkInputValidity();
|
this.checkInputValidity();
|
||||||
@ -107,7 +110,6 @@ export class QueueExclusionForm extends LiteElement {
|
|||||||
placeholder=${this.selectValue === "text"
|
placeholder=${this.selectValue === "text"
|
||||||
? "/skip-this-page"
|
? "/skip-this-page"
|
||||||
: "example.com/skip.*"}
|
: "example.com/skip.*"}
|
||||||
.value=${this.inputValue}
|
|
||||||
?disabled=${this.isSubmitting}
|
?disabled=${this.isSubmitting}
|
||||||
@keydown=${this.onKeyDown}
|
@keydown=${this.onKeyDown}
|
||||||
@sl-input=${this.onInput as UnderlyingFunction<
|
@sl-input=${this.onInput as UnderlyingFunction<
|
||||||
@ -151,7 +153,7 @@ export class QueueExclusionForm extends LiteElement {
|
|||||||
<btrix-button
|
<btrix-button
|
||||||
variant="neutral"
|
variant="neutral"
|
||||||
raised
|
raised
|
||||||
?disabled=${!this.inputValue ||
|
?disabled=${!this.regex ||
|
||||||
this.isRegexInvalid ||
|
this.isRegexInvalid ||
|
||||||
this.isSubmitting}
|
this.isSubmitting}
|
||||||
?loading=${this.isSubmitting}
|
?loading=${this.isSubmitting}
|
||||||
@ -166,8 +168,8 @@ export class QueueExclusionForm extends LiteElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly onInput = debounce(200)((e: Event) => {
|
private readonly onInput = debounce(200)(() => {
|
||||||
this.inputValue = (e.target as SlInput).value;
|
this.regex = this.input?.value || "";
|
||||||
});
|
});
|
||||||
|
|
||||||
private onButtonClick() {
|
private onButtonClick() {
|
||||||
@ -184,12 +186,12 @@ export class QueueExclusionForm extends LiteElement {
|
|||||||
private checkInputValidity(): void {
|
private checkInputValidity(): void {
|
||||||
let isValid = true;
|
let isValid = true;
|
||||||
|
|
||||||
if (!this.inputValue || this.inputValue.length < MIN_LENGTH) {
|
if (!this.regex || this.regex.length < MIN_LENGTH) {
|
||||||
isValid = false;
|
isValid = false;
|
||||||
} else if (this.selectValue === "regex") {
|
} else if (this.selectValue === "regex") {
|
||||||
try {
|
try {
|
||||||
// Check if valid regex
|
// Check if valid regex
|
||||||
new RegExp(this.inputValue);
|
new RegExp(this.regex);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.fieldErrorMessage = (err as Error).message;
|
this.fieldErrorMessage = (err as Error).message;
|
||||||
isValid = false;
|
isValid = false;
|
||||||
@ -202,12 +204,10 @@ export class QueueExclusionForm extends LiteElement {
|
|||||||
private async dispatchChangeEvent() {
|
private async dispatchChangeEvent() {
|
||||||
await this.updateComplete;
|
await this.updateComplete;
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new CustomEvent("on-change", {
|
new CustomEvent("btrix-change", {
|
||||||
detail: {
|
detail: {
|
||||||
value:
|
value:
|
||||||
this.selectValue === "text"
|
this.selectValue === "text" ? regexEscape(this.regex) : this.regex,
|
||||||
? regexEscape(this.inputValue)
|
|
||||||
: this.inputValue,
|
|
||||||
valid: !this.isRegexInvalid,
|
valid: !this.isRegexInvalid,
|
||||||
},
|
},
|
||||||
}) as ExclusionChangeEvent,
|
}) as ExclusionChangeEvent,
|
||||||
@ -217,19 +217,23 @@ export class QueueExclusionForm extends LiteElement {
|
|||||||
private async handleAdd() {
|
private async handleAdd() {
|
||||||
this.onInput.flush();
|
this.onInput.flush();
|
||||||
await this.updateComplete;
|
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") {
|
if (this.selectValue === "text") {
|
||||||
regex = regexEscape(this.inputValue);
|
regex = regexEscape(this.regex);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new CustomEvent("on-add", {
|
new CustomEvent("btrix-add", {
|
||||||
detail: {
|
detail: {
|
||||||
regex,
|
regex,
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
this.inputValue = "";
|
this.regex = "";
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}) as ExclusionAddEvent,
|
}) as ExclusionAddEvent,
|
||||||
|
@ -2,7 +2,7 @@ import { localized, msg } from "@lit/localize";
|
|||||||
import type { SlInput, SlMenuItem } from "@shoelace-style/shoelace";
|
import type { SlInput, SlMenuItem } from "@shoelace-style/shoelace";
|
||||||
import Fuse from "fuse.js";
|
import Fuse from "fuse.js";
|
||||||
import { html, type PropertyValues } from "lit";
|
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 { guard } from "lit/directives/guard.js";
|
||||||
import { when } from "lit/directives/when.js";
|
import { when } from "lit/directives/when.js";
|
||||||
import debounce from "lodash/fp/debounce";
|
import debounce from "lodash/fp/debounce";
|
||||||
@ -91,6 +91,9 @@ export class CollectionsList extends BtrixElement {
|
|||||||
@state()
|
@state()
|
||||||
private fetchErrorStatusCode?: number;
|
private fetchErrorStatusCode?: number;
|
||||||
|
|
||||||
|
@query("sl-input")
|
||||||
|
private readonly input?: SlInput | null;
|
||||||
|
|
||||||
// For fuzzy search:
|
// For fuzzy search:
|
||||||
private readonly fuse = new Fuse<{ key: "name"; value: string }>([], {
|
private readonly fuse = new Fuse<{ key: "name"; value: string }>([], {
|
||||||
keys: ["value"],
|
keys: ["value"],
|
||||||
@ -339,7 +342,6 @@ export class CollectionsList extends BtrixElement {
|
|||||||
size="small"
|
size="small"
|
||||||
placeholder=${msg("Search by Name")}
|
placeholder=${msg("Search by Name")}
|
||||||
clearable
|
clearable
|
||||||
value=${this.searchByValue}
|
|
||||||
@sl-clear=${() => {
|
@sl-clear=${() => {
|
||||||
this.searchResultsOpen = false;
|
this.searchResultsOpen = false;
|
||||||
this.onSearchInput.cancel();
|
this.onSearchInput.cancel();
|
||||||
@ -627,8 +629,8 @@ export class CollectionsList extends BtrixElement {
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
private readonly onSearchInput = debounce(150)((e: Event) => {
|
private readonly onSearchInput = debounce(150)(() => {
|
||||||
this.searchByValue = (e.target as SlInput).value.trim();
|
this.searchByValue = this.input?.value.trim() || "";
|
||||||
|
|
||||||
if (!this.searchResultsOpen && this.hasSearchStr) {
|
if (!this.searchResultsOpen && this.hasSearchStr) {
|
||||||
this.searchResultsOpen = true;
|
this.searchResultsOpen = true;
|
||||||
|
Loading…
Reference in New Issue
Block a user