diff --git a/frontend/src/features/collections/collection-replay-dialog.ts b/frontend/src/features/collections/collection-replay-dialog.ts index c2bc246ba4..61ae21050d 100644 --- a/frontend/src/features/collections/collection-replay-dialog.ts +++ b/frontend/src/features/collections/collection-replay-dialog.ts @@ -14,6 +14,7 @@ import type { SelectSnapshotDetail } from "./select-collection-start-page"; import { BtrixElement } from "@/classes/BtrixElement"; import type { Dialog } from "@/components/ui/dialog"; +import type { Collection } from "@/types/collection"; /** * @fires btrix-change @@ -40,14 +41,8 @@ export class CollectionStartPageDialog extends BtrixElement { @property({ type: String }) collectionId?: string; - @property({ type: String }) - homeUrl?: string | null = null; - - @property({ type: String }) - homePageId?: string | null = null; - - @property({ type: String }) - homeTs?: string | null = null; + @property({ type: Object }) + collection?: Collection; @property({ type: Boolean }) open = false; @@ -77,8 +72,8 @@ export class CollectionStartPageDialog extends BtrixElement { private readonly thumbnailPreview?: CollectionSnapshotPreview | null; willUpdate(changedProperties: PropertyValues) { - if (changedProperties.has("homeUrl")) { - this.homeView = this.homeUrl ? HomeView.URL : HomeView.Pages; + if (changedProperties.has("collection") && this.collection) { + this.homeView = this.collection.homeUrl ? HomeView.URL : HomeView.Pages; } } @@ -92,7 +87,12 @@ export class CollectionStartPageDialog extends BtrixElement { class="[--width:60rem]" @sl-show=${() => (this.showContent = true)} @sl-after-hide=${() => { - this.homeView = this.homeUrl ? HomeView.URL : HomeView.Pages; + if (this.collection) { + this.homeView = this.collection.homeUrl + ? HomeView.URL + : HomeView.Pages; + } + this.isSubmitting = false; this.selectedSnapshot = null; this.showContent = false; @@ -142,11 +142,11 @@ export class CollectionStartPageDialog extends BtrixElement { private renderPreview() { const snapshot = this.selectedSnapshot || - (this.homeUrl + (this.collection?.homeUrl ? { - url: this.homeUrl, - ts: this.homeTs, - pageId: this.homePageId, + url: this.collection.homeUrl, + ts: this.collection.homeUrlTs, + pageId: this.collection.homeUrlPageId, status: 200, } : null); @@ -207,8 +207,8 @@ export class CollectionStartPageDialog extends BtrixElement { if (this.homeView === HomeView.Pages) { if ( - !this.homePageId || - this.homePageId !== this.selectedSnapshot?.pageId + !this.collection?.homeUrlPageId || + this.collection.homeUrlPageId !== this.selectedSnapshot?.pageId ) { // Reset unsaved selected snapshot this.selectedSnapshot = null; @@ -244,8 +244,7 @@ export class CollectionStartPageDialog extends BtrixElement {
, ) => { @@ -280,10 +279,10 @@ export class CollectionStartPageDialog extends BtrixElement { const { homeView, useThumbnail } = serialize(form); if ( - (homeView === HomeView.Pages && !this.homePageId) || + (homeView === HomeView.Pages && !this.collection?.homeUrlPageId) || (homeView === HomeView.URL && this.selectedSnapshot && - this.homePageId === this.selectedSnapshot.pageId) + this.collection?.homeUrlPageId === this.selectedSnapshot.pageId) ) { // No changes to save this.open = false; @@ -302,7 +301,7 @@ export class CollectionStartPageDialog extends BtrixElement { homeView === HomeView.URL && useThumbnail === "on" && this.selectedSnapshot && - this.homePageId !== this.selectedSnapshot.pageId; + this.collection?.homeUrlPageId !== this.selectedSnapshot.pageId; // TODO get filename from rwp? const fileName = `page-thumbnail_${this.selectedSnapshot?.pageId}.jpeg`; let file: File | undefined; diff --git a/frontend/src/features/collections/select-collection-start-page.ts b/frontend/src/features/collections/select-collection-start-page.ts index 2515fcf6af..fb04a53b48 100644 --- a/frontend/src/features/collections/select-collection-start-page.ts +++ b/frontend/src/features/collections/select-collection-start-page.ts @@ -10,12 +10,15 @@ import { html, type PropertyValues } from "lit"; import { customElement, property, query, state } from "lit/decorators.js"; import { when } from "lit/directives/when.js"; import debounce from "lodash/fp/debounce"; -import sortBy from "lodash/fp/sortBy"; +import filter from "lodash/fp/filter"; +import flow from "lodash/fp/flow"; +import orderBy from "lodash/fp/orderBy"; import queryString from "query-string"; import { BtrixElement } from "@/classes/BtrixElement"; import type { Combobox } from "@/components/ui/combobox"; import type { APIPaginatedList, APIPaginationQuery } from "@/types/api"; +import type { Collection } from "@/types/collection"; import type { UnderlyingFunction } from "@/types/utils"; import { tw } from "@/utils/tailwind"; @@ -39,7 +42,11 @@ export type SelectSnapshotDetail = { const DEFAULT_PROTOCOL = "http"; -const sortByTs = sortBy("ts"); +// TODO Check if backend can sort and filter snapshots instead +const sortByTs = flow( + filter(({ status }) => status < 300), + orderBy("ts")("desc"), +) as (snapshots: Snapshot[]) => Snapshot[]; /** * @fires btrix-select @@ -50,11 +57,8 @@ export class SelectCollectionStartPage extends BtrixElement { @property({ type: String }) collectionId?: string; - @property({ type: String }) - homeUrl?: string | null = null; - - @property({ type: String }) - homeTs?: string | null = null; + @property({ type: Object }) + collection?: Collection; @state() private searchQuery = ""; @@ -82,14 +86,13 @@ export class SelectCollectionStartPage extends BtrixElement { return this.selectedSnapshot; } - updated(changedProperties: PropertyValues) { - if (changedProperties.has("homeUrl") && this.homeUrl) { - if (this.input) { - this.input.value = this.homeUrl; - } - this.searchQuery = this.homeUrl; - void this.initSelection(); + protected willUpdate(changedProperties: PropertyValues) { + if (changedProperties.has("collection") && this.collection) { + void this.initSelection(this.collection); } + } + + updated(changedProperties: PropertyValues) { if (changedProperties.has("selectedSnapshot")) { this.dispatchEvent( new CustomEvent("btrix-select", { @@ -106,26 +109,50 @@ export class SelectCollectionStartPage extends BtrixElement { } } - private async initSelection() { - await this.updateComplete; - await this.searchResults.taskComplete; + private async initSelection(collection: Collection) { + if (!collection.homeUrl && collection.pageCount !== 1) { + return; + } - if (this.homeUrl && this.searchResults.value) { - this.selectedPage = this.searchResults.value.items.find( - ({ url }) => url === this.homeUrl, - ); + const pageUrls = await this.getPageUrls({ + id: collection.id, + urlPrefix: collection.homeUrl || "", + pageSize: 1, + }); - if (this.selectedPage && this.homeTs) { - this.selectedSnapshot = this.selectedPage.snapshots.find( - ({ ts }) => ts === this.homeTs, - ); - } + if (!pageUrls.total) { + return; + } + + const startPage = pageUrls.items[0]; + + if (this.input) { + this.input.value = startPage.url; } + + this.selectedPage = this.formatPage(startPage); + + const homeTs = collection.homeUrlTs; + + this.selectedSnapshot = homeTs + ? this.selectedPage.snapshots.find(({ ts }) => ts === homeTs) + : this.selectedPage.snapshots[0]; + } + + /** + * Format page for display + * @TODO Check if backend can sort and filter snapshots instead + */ + private formatPage(page: Page) { + return { + ...page, + snapshots: sortByTs(page.snapshots), + }; } private readonly searchResults = new Task(this, { task: async ([searchValue], { signal }) => { - const searchResults = await this.getPageUrls( + const pageUrls = await this.getPageUrls( { id: this.collectionId!, urlPrefix: searchValue, @@ -133,7 +160,7 @@ export class SelectCollectionStartPage extends BtrixElement { signal, ); - return searchResults; + return pageUrls; }, args: () => [this.searchQuery] as const, }); @@ -150,6 +177,7 @@ export class SelectCollectionStartPage extends BtrixElement { value=${this.selectedSnapshot?.pageId || ""} ?required=${this.selectedPage && !this.selectedSnapshot} ?disabled=${!this.selectedPage} + hoist @sl-change=${async (e: SlChangeEvent) => { const { value } = e.currentTarget as SlSelect; @@ -160,35 +188,22 @@ export class SelectCollectionStartPage extends BtrixElement { ); }} > - ${when( - this.selectedSnapshot, - (snapshot) => html` - ${snapshot.status} - `, - )} - ${when(this.selectedPage, (item) => - item.snapshots.map( - ({ pageId, ts, status }) => html` - - ${this.localize.date(ts)} - ${status} - - `, - ), - )} + ${when(this.selectedPage, this.renderSnapshotOptions)} `; } + private readonly renderSnapshotOptions = ({ snapshots }: Page) => { + return html` + ${snapshots.map( + ({ pageId, ts }) => html` + ${this.localize.date(ts)} + `, + )} + `; + }; + private renderPageSearch() { let prefix: { icon: string; @@ -223,7 +238,7 @@ export class SelectCollectionStartPage extends BtrixElement { id="pageUrlInput" label=${msg("Page URL")} placeholder=${msg("Start typing a URL...")} - clearable + ?clearable=${this.collection && this.collection.pageCount > 1} @sl-focus=${() => { this.resetInputValidity(); this.combobox?.show(); @@ -295,7 +310,7 @@ export class SelectCollectionStartPage extends BtrixElement { this.selectedSnapshot = undefined; } else if (results.total === 1) { // Choose only option, e.g. for copy-paste - this.selectedPage = this.searchResults.value.items[0]; + this.selectedPage = this.formatPage(this.searchResults.value.items[0]); this.selectedSnapshot = this.selectedPage.snapshots[0]; } }; @@ -326,11 +341,7 @@ export class SelectCollectionStartPage extends BtrixElement { this.input.value = item.url; } - this.selectedPage = { - ...item, - // TODO check if backend can sort - snapshots: sortByTs(item.snapshots).reverse(), - }; + this.selectedPage = this.formatPage(item); this.combobox?.hide(); diff --git a/frontend/src/pages/org/collection-detail.ts b/frontend/src/pages/org/collection-detail.ts index 9073a47284..54aa53377b 100644 --- a/frontend/src/pages/org/collection-detail.ts +++ b/frontend/src/pages/org/collection-detail.ts @@ -254,9 +254,7 @@ export class CollectionDetail extends BtrixElement { }} @sl-hide=${async () => (this.openDialogName = undefined)} collectionId=${this.collectionId} - .homeUrl=${this.collection?.homeUrl} - .homePageId=${this.collection?.homeUrlPageId} - .homeTs=${this.collection?.homeUrlTs} + .collection=${this.collection} ?replayLoaded=${this.isRwpLoaded} >