diff --git a/backend/btrixcloud/colls.py b/backend/btrixcloud/colls.py index 468207ad..0ea137a0 100644 --- a/backend/btrixcloud/colls.py +++ b/backend/btrixcloud/colls.py @@ -755,7 +755,7 @@ class CollectionOps: page_size: int = DEFAULT_PAGE_SIZE, page: int = 1, ) -> Tuple[List[PageUrlCount], int]: - """List all URLs in collection sorted desc by snapshot count""" + """List all URLs in collection sorted desc by snapshot count unless prefix is specified""" # pylint: disable=duplicate-code, too-many-locals, too-many-branches, too-many-statements # Zero-index page for query page = page - 1 @@ -764,13 +764,15 @@ class CollectionOps: crawl_ids = await self.get_collection_crawl_ids(coll_id) match_query: dict[str, object] = {"oid": oid, "crawl_id": {"$in": crawl_ids}} + sort_query: dict[str, int] = {"count": -1, "_id": 1} if url_prefix: url_prefix = urllib.parse.unquote(url_prefix) regex_pattern = f"^{re.escape(url_prefix)}" match_query["url"] = {"$regex": regex_pattern, "$options": "i"} + sort_query = {"_id": 1} - aggregate = [{"$match": match_query}] + aggregate: List[Dict[str, Union[int, object]]] = [{"$match": match_query}] aggregate.extend( [ @@ -781,7 +783,7 @@ class CollectionOps: "count": {"$sum": 1}, }, }, - {"$sort": {"count": -1}}, + {"$sort": sort_query}, {"$set": {"url": "$_id"}}, { "$facet": { diff --git a/frontend/src/features/collections/select-collection-page.ts b/frontend/src/features/collections/select-collection-page.ts index efbd266b..6ff78849 100644 --- a/frontend/src/features/collections/select-collection-page.ts +++ b/frontend/src/features/collections/select-collection-page.ts @@ -357,45 +357,53 @@ export class SelectCollectionPage extends BtrixElement { private renderSearchResults() { return this.searchResults.render({ - pending: () => html` - - - - `, - complete: ({ items }) => { - if (!items.length) { - return html` - - ${msg("No matching page found.")} - - `; - } - - return html` - ${items.map((item: Page) => { - return html` - { - if (this.input) { - this.input.value = item.url; - } - - this.selectedPage = this.formatPage(item); - - this.combobox?.hide(); - - this.selectedSnapshot = this.selectedPage.snapshots[0]; - }} - >${item.url} - - `; - })} - `; - }, + pending: () => + this.renderItems( + // Render previous value so that dropdown doesn't shift while typing + this.searchResults.value, + ), + complete: this.renderItems, }); } + private readonly renderItems = ( + results: SelectCollectionPage["searchResults"]["value"], + ) => { + if (!results) return; + + const { items } = results; + + if (!items.length) { + return html` + + ${msg("No matching page found.")} + + `; + } + + return html` + ${items.map((item: Page) => { + return html` + { + if (this.input) { + this.input.value = item.url; + } + + this.selectedPage = this.formatPage(item); + + this.combobox?.hide(); + + this.selectedSnapshot = this.selectedPage.snapshots[0]; + }} + >${item.url} + + `; + })} + `; + }; + private readonly onSearchInput = debounce(400)(() => { const value = this.input?.value;