diff --git a/frontend/src/features/archived-items/archived-item-state-filter.ts b/frontend/src/features/archived-items/archived-item-state-filter.ts index ce75a5a6d6..296ecb3544 100644 --- a/frontend/src/features/archived-items/archived-item-state-filter.ts +++ b/frontend/src/features/archived-items/archived-item-state-filter.ts @@ -15,6 +15,7 @@ import { state, } from "lit/decorators.js"; import { repeat } from "lit/directives/repeat.js"; +import { isEqual } from "lodash"; import { isFocusable } from "tabbable"; import { CrawlStatus } from "./crawl-status"; @@ -52,14 +53,8 @@ export class ArchivedItemStateFilter extends BtrixElement { private readonly fuse = new Fuse(finishedCrawlStates); - @state() - private get selectedStates() { - return Array.from(this.selected.entries()) - .filter(([_tag, selected]) => selected) - .map(([tag]) => tag); - } - - private selected = new Map(); + @state({ hasChanged: isEqual }) + selected = new Map(); protected willUpdate(changedProperties: PropertyValues): void { if (changedProperties.has("states")) { @@ -71,6 +66,22 @@ export class ArchivedItemStateFilter extends BtrixElement { } } + protected updated(changedProperties: PropertyValues): void { + if (changedProperties.has("selected")) { + this.dispatchEvent( + new CustomEvent< + BtrixChangeEvent["detail"] + >("btrix-change", { + detail: { + value: Array.from(this.selected.entries()) + .filter(([_tag, selected]) => selected) + .map(([tag]) => tag), + }, + }), + ); + } + } + render() { const options = this.searchString ? this.fuse.search(this.searchString) @@ -87,14 +98,6 @@ export class ArchivedItemStateFilter extends BtrixElement { }} @sl-after-hide=${() => { this.searchString = ""; - - this.dispatchEvent( - new CustomEvent< - BtrixChangeEvent["detail"] - >("btrix-change", { - detail: { value: this.selectedStates }, - }), - ); }} > ${this.states?.length @@ -250,8 +253,9 @@ export class ArchivedItemStateFilter extends BtrixElement { @sl-change=${async (e: SlChangeEvent) => { const { checked, value } = e.target as SlCheckbox; - this.selected.set(value as CrawlState, checked); - this.requestUpdate("selectedStates"); + this.selected = new Map( + this.selected.set(value as CrawlState, checked), + ); }} > ${repeat( diff --git a/frontend/src/features/archived-items/archived-item-tag-filter.ts b/frontend/src/features/archived-items/archived-item-tag-filter.ts index fff98772ed..5f0b73d1a3 100644 --- a/frontend/src/features/archived-items/archived-item-tag-filter.ts +++ b/frontend/src/features/archived-items/archived-item-tag-filter.ts @@ -17,6 +17,7 @@ import { state, } from "lit/decorators.js"; import { repeat } from "lit/directives/repeat.js"; +import { isEqual } from "lodash"; import { isFocusable } from "tabbable"; import { BtrixElement } from "@/classes/BtrixElement"; @@ -56,17 +57,11 @@ export class ArchivedItemTagFilter extends BtrixElement { keys: ["tag"], }); - @state() - private get selectedTags() { - return Array.from(this.selected.entries()) - .filter(([_tag, selected]) => selected) - .map(([tag]) => tag); - } - - private selected = new Map(); + @state({ hasChanged: isEqual }) + selected = new Map(); @state() - private type: "and" | "or" = "or"; + type: "and" | "or" = "or"; protected willUpdate(changedProperties: PropertyValues): void { if (changedProperties.has("tags")) { @@ -78,6 +73,25 @@ export class ArchivedItemTagFilter extends BtrixElement { } } + protected updated(changedProperties: PropertyValues): void { + if (changedProperties.has("selected") || changedProperties.has("type")) { + const selectedTags = Array.from(this.selected.entries()) + .filter(([_tag, selected]) => selected) + .map(([tag]) => tag); + this.dispatchEvent( + new CustomEvent< + BtrixChangeEvent["detail"] + >("btrix-change", { + detail: { + value: selectedTags.length + ? { tags: selectedTags, type: this.type } + : undefined, + }, + }), + ); + } + } + private readonly orgTagsTask = new Task(this, { task: async () => { const { tags } = await this.api.fetch( @@ -105,18 +119,6 @@ export class ArchivedItemTagFilter extends BtrixElement { }} @sl-after-hide=${() => { this.searchString = ""; - - this.dispatchEvent( - new CustomEvent< - BtrixChangeEvent["detail"] - >("btrix-change", { - detail: { - value: this.selectedTags.length - ? { tags: this.selectedTags, type: this.type } - : undefined, - }, - }), - ); }} > ${this.tags?.length @@ -304,8 +306,7 @@ export class ArchivedItemTagFilter extends BtrixElement { @sl-change=${async (e: SlChangeEvent) => { const { checked, value } = e.target as SlCheckbox; - this.selected.set(value, checked); - this.requestUpdate("selectedTags"); + this.selected = new Map(this.selected.set(value, checked)); }} > ${repeat( diff --git a/frontend/src/features/crawl-workflows/workflow-profile-filter.ts b/frontend/src/features/crawl-workflows/workflow-profile-filter.ts index f433c39cd1..fb6d9950d1 100644 --- a/frontend/src/features/crawl-workflows/workflow-profile-filter.ts +++ b/frontend/src/features/crawl-workflows/workflow-profile-filter.ts @@ -17,6 +17,7 @@ import { state, } from "lit/decorators.js"; import { repeat } from "lit/directives/repeat.js"; +import { isEqual } from "lodash"; import queryString from "query-string"; import { isFocusable } from "tabbable"; @@ -57,7 +58,8 @@ export class WorkflowProfileFilter extends BtrixElement { keys: ["id", "name", "description", "origins"], }); - private selected = new Map(); + @state({ hasChanged: isEqual }) + selected = new Map(); protected willUpdate(changedProperties: PropertyValues): void { if (changedProperties.has("profiles")) { @@ -69,6 +71,26 @@ export class WorkflowProfileFilter extends BtrixElement { } } + protected updated(changedProperties: PropertyValues): void { + if (changedProperties.has("selected")) { + const selectedProfiles = []; + + for (const [profile, value] of this.selected) { + if (value) { + selectedProfiles.push(profile); + } + } + + this.dispatchEvent( + new CustomEvent("btrix-change", { + detail: { + value: selectedProfiles.length ? selectedProfiles : undefined, + }, + }), + ); + } + } + private readonly profilesTask = new Task(this, { task: async () => { const query = queryString.stringify( @@ -105,22 +127,6 @@ export class WorkflowProfileFilter extends BtrixElement { }} @sl-after-hide=${() => { this.searchString = ""; - - const selectedProfiles = []; - - for (const [profile, value] of this.selected) { - if (value) { - selectedProfiles.push(profile); - } - } - - this.dispatchEvent( - new CustomEvent("btrix-change", { - detail: { - value: selectedProfiles.length ? selectedProfiles : undefined, - }, - }), - ); }} > ${this.profiles?.length @@ -160,17 +166,7 @@ export class WorkflowProfileFilter extends BtrixElement { this.checkboxes.forEach((checkbox) => { checkbox.checked = false; }); - - this.dispatchEvent( - new CustomEvent( - "btrix-change", - { - detail: { - value: undefined, - }, - }, - ), - ); + this.selected = new Map(); }} >${msg("Clear")}` @@ -343,7 +339,7 @@ export class WorkflowProfileFilter extends BtrixElement { @sl-change=${async (e: SlChangeEvent) => { const { checked, value } = e.target as SlCheckbox; - this.selected.set(value, checked); + this.selected = new Map(this.selected.set(value, checked)); }} > ${repeat( diff --git a/frontend/src/features/crawl-workflows/workflow-schedule-filter.ts b/frontend/src/features/crawl-workflows/workflow-schedule-filter.ts index dc2f67adbd..dc1515921a 100644 --- a/frontend/src/features/crawl-workflows/workflow-schedule-filter.ts +++ b/frontend/src/features/crawl-workflows/workflow-schedule-filter.ts @@ -1,5 +1,5 @@ import { localized, msg } from "@lit/localize"; -import type { SlSelectEvent } from "@shoelace-style/shoelace"; +import type { SlChangeEvent, SlRadioGroup } from "@shoelace-style/shoelace"; import { html, nothing, type PropertyValues } from "lit"; import { customElement, property } from "lit/decorators.js"; @@ -25,35 +25,24 @@ export class WorkflowScheduleFilter extends BtrixElement { @property({ type: Boolean }) schedule?: boolean; - #schedule?: boolean; - - protected willUpdate(changedProperties: PropertyValues): void { + protected updated(changedProperties: PropertyValues): void { if (changedProperties.has("schedule")) { - this.#schedule = this.schedule; + this.dispatchEvent( + new CustomEvent( + "btrix-change", + { + detail: { value: this.schedule }, + }, + ), + ); } } render() { - const option = (label: string, value: string) => html` - ${label} - `; - return html` { - if (this.#schedule !== this.schedule) { - this.dispatchEvent( - new CustomEvent( - "btrix-change", - { - detail: { value: this.#schedule }, - }, - ), - ); - } - }} > ${this.schedule === undefined ? msg("Schedule") @@ -61,59 +50,71 @@ export class WorkflowScheduleFilter extends BtrixElement { >${this.schedule ? msg("Scheduled") : msg("No Schedule")}`} - { - const { item } = e.detail; - - switch (item.value as ScheduleType) { - case ScheduleType.Scheduled: - this.#schedule = true; - break; - case ScheduleType.None: - this.#schedule = false; - break; - default: - this.#schedule = undefined; - break; - } - }} + class="flex max-h-[var(--auto-size-available-height)] max-w-[var(--auto-size-available-width)] flex-col overflow-hidden rounded border bg-white text-left" > - -
- ${msg("Filter by Schedule Type")} -
- ${this.schedule !== undefined - ? html` { - this.dispatchEvent( - new CustomEvent( - "btrix-change", - { - detail: { - value: undefined, - }, - }, - ), - ); - }} - >${msg("Clear")}` - : nothing} -
+
+ ${msg("Filter by Schedule Type")} +
+ ${this.schedule !== undefined + ? html` { + this.schedule = undefined; + }} + >${msg("Clear")}` + : nothing} + + - ${option(msg("Scheduled"), ScheduleType.Scheduled)} - ${option(msg("No Schedule"), ScheduleType.None)} -
+ { + const target = e.target as SlRadioGroup; + + switch (target.value as ScheduleType) { + case ScheduleType.Scheduled: + this.schedule = true; + break; + case ScheduleType.None: + this.schedule = false; + break; + default: + this.schedule = undefined; + break; + } + }} + > + ${msg("Scheduled")} + ${msg("No Schedule")} + +
`; } diff --git a/frontend/src/features/crawl-workflows/workflow-tag-filter.ts b/frontend/src/features/crawl-workflows/workflow-tag-filter.ts index 08bfa8fec5..398e0d7088 100644 --- a/frontend/src/features/crawl-workflows/workflow-tag-filter.ts +++ b/frontend/src/features/crawl-workflows/workflow-tag-filter.ts @@ -17,6 +17,7 @@ import { state, } from "lit/decorators.js"; import { repeat } from "lit/directives/repeat.js"; +import { isEqual } from "lodash"; import { isFocusable } from "tabbable"; import { BtrixElement } from "@/classes/BtrixElement"; @@ -56,17 +57,11 @@ export class WorkflowTagFilter extends BtrixElement { keys: ["tag"], }); - @state() - private get selectedTags() { - return Array.from(this.selected.entries()) - .filter(([_tag, selected]) => selected) - .map(([tag]) => tag); - } - - private selected = new Map(); + @state({ hasChanged: isEqual }) + selected = new Map(); @state() - private type: "and" | "or" = "or"; + type: "and" | "or" = "or"; protected willUpdate(changedProperties: PropertyValues): void { if (changedProperties.has("tags")) { @@ -78,6 +73,25 @@ export class WorkflowTagFilter extends BtrixElement { } } + protected updated(changedProperties: PropertyValues): void { + if (changedProperties.has("selected") || changedProperties.has("type")) { + const selectedTags = Array.from(this.selected.entries()) + .filter(([_tag, selected]) => selected) + .map(([tag]) => tag); + this.dispatchEvent( + new CustomEvent< + BtrixChangeEvent["detail"] + >("btrix-change", { + detail: { + value: selectedTags.length + ? { tags: selectedTags, type: this.type } + : undefined, + }, + }), + ); + } + } + private readonly orgTagsTask = new Task(this, { task: async () => { const { tags } = await this.api.fetch( @@ -105,18 +119,6 @@ export class WorkflowTagFilter extends BtrixElement { }} @sl-after-hide=${() => { this.searchString = ""; - - this.dispatchEvent( - new CustomEvent< - BtrixChangeEvent["detail"] - >("btrix-change", { - detail: { - value: this.selectedTags.length - ? { tags: this.selectedTags, type: this.type } - : undefined, - }, - }), - ); }} > ${this.tags?.length @@ -152,18 +154,9 @@ export class WorkflowTagFilter extends BtrixElement { this.checkboxes.forEach((checkbox) => { checkbox.checked = false; }); + this.selected = new Map(); this.type = "or"; - - this.dispatchEvent( - new CustomEvent< - BtrixChangeEvent["detail"] - >("btrix-change", { - detail: { - value: undefined, - }, - }), - ); }} >${msg("Clear")}` @@ -304,8 +297,7 @@ export class WorkflowTagFilter extends BtrixElement { @sl-change=${async (e: SlChangeEvent) => { const { checked, value } = e.target as SlCheckbox; - this.selected.set(value, checked); - this.requestUpdate("selectedTags"); + this.selected = new Map(this.selected.set(value, checked)); }} > ${repeat( diff --git a/frontend/src/pages/org/archived-items.ts b/frontend/src/pages/org/archived-items.ts index 8210c1a695..cc8949fd0c 100644 --- a/frontend/src/pages/org/archived-items.ts +++ b/frontend/src/pages/org/archived-items.ts @@ -301,6 +301,10 @@ export class CrawlsList extends BtrixElement { signal, ); + if (this.getArchivedItemsTimeout) { + window.clearTimeout(this.getArchivedItemsTimeout); + } + this.getArchivedItemsTimeout = window.setTimeout(() => { void this.archivedItemsTask.run(); }, POLL_INTERVAL_SECONDS * 1000); diff --git a/frontend/src/pages/org/workflows-list.ts b/frontend/src/pages/org/workflows-list.ts index 6a9108fc7e..23bcaa50e4 100644 --- a/frontend/src/pages/org/workflows-list.ts +++ b/frontend/src/pages/org/workflows-list.ts @@ -669,6 +669,7 @@ export class WorkflowsList extends BtrixElement { { this.filterByTags = e.detail.value?.tags; this.filterByTagsType = e.detail.value?.type || "or";