fix: Sort filtered collection page URLs (#2384)
Fixes https://github.com/webrecorder/browsertrix/issues/2383 - Fixes unpredictable sort order when typing in collection page URL - Fixes page URL results flickering in and out while typing --------- Co-authored-by: Tessa Walsh <tessa@bitarchivist.net>
This commit is contained in:
parent
5b02d81991
commit
f7b9b73a68
@ -755,7 +755,7 @@ class CollectionOps:
|
|||||||
page_size: int = DEFAULT_PAGE_SIZE,
|
page_size: int = DEFAULT_PAGE_SIZE,
|
||||||
page: int = 1,
|
page: int = 1,
|
||||||
) -> Tuple[List[PageUrlCount], int]:
|
) -> 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
|
# pylint: disable=duplicate-code, too-many-locals, too-many-branches, too-many-statements
|
||||||
# Zero-index page for query
|
# Zero-index page for query
|
||||||
page = page - 1
|
page = page - 1
|
||||||
@ -764,13 +764,15 @@ class CollectionOps:
|
|||||||
crawl_ids = await self.get_collection_crawl_ids(coll_id)
|
crawl_ids = await self.get_collection_crawl_ids(coll_id)
|
||||||
|
|
||||||
match_query: dict[str, object] = {"oid": oid, "crawl_id": {"$in": crawl_ids}}
|
match_query: dict[str, object] = {"oid": oid, "crawl_id": {"$in": crawl_ids}}
|
||||||
|
sort_query: dict[str, int] = {"count": -1, "_id": 1}
|
||||||
|
|
||||||
if url_prefix:
|
if url_prefix:
|
||||||
url_prefix = urllib.parse.unquote(url_prefix)
|
url_prefix = urllib.parse.unquote(url_prefix)
|
||||||
regex_pattern = f"^{re.escape(url_prefix)}"
|
regex_pattern = f"^{re.escape(url_prefix)}"
|
||||||
match_query["url"] = {"$regex": regex_pattern, "$options": "i"}
|
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(
|
aggregate.extend(
|
||||||
[
|
[
|
||||||
@ -781,7 +783,7 @@ class CollectionOps:
|
|||||||
"count": {"$sum": 1},
|
"count": {"$sum": 1},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{"$sort": {"count": -1}},
|
{"$sort": sort_query},
|
||||||
{"$set": {"url": "$_id"}},
|
{"$set": {"url": "$_id"}},
|
||||||
{
|
{
|
||||||
"$facet": {
|
"$facet": {
|
||||||
|
@ -357,45 +357,53 @@ export class SelectCollectionPage extends BtrixElement {
|
|||||||
|
|
||||||
private renderSearchResults() {
|
private renderSearchResults() {
|
||||||
return this.searchResults.render({
|
return this.searchResults.render({
|
||||||
pending: () => html`
|
pending: () =>
|
||||||
<sl-menu-item slot="menu-item" disabled>
|
this.renderItems(
|
||||||
<sl-spinner></sl-spinner>
|
// Render previous value so that dropdown doesn't shift while typing
|
||||||
</sl-menu-item>
|
this.searchResults.value,
|
||||||
`,
|
),
|
||||||
complete: ({ items }) => {
|
complete: this.renderItems,
|
||||||
if (!items.length) {
|
|
||||||
return html`
|
|
||||||
<sl-menu-item slot="menu-item" disabled>
|
|
||||||
${msg("No matching page found.")}
|
|
||||||
</sl-menu-item>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return html`
|
|
||||||
${items.map((item: Page) => {
|
|
||||||
return html`
|
|
||||||
<sl-menu-item
|
|
||||||
slot="menu-item"
|
|
||||||
@click=${async () => {
|
|
||||||
if (this.input) {
|
|
||||||
this.input.value = item.url;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.selectedPage = this.formatPage(item);
|
|
||||||
|
|
||||||
this.combobox?.hide();
|
|
||||||
|
|
||||||
this.selectedSnapshot = this.selectedPage.snapshots[0];
|
|
||||||
}}
|
|
||||||
>${item.url}
|
|
||||||
</sl-menu-item>
|
|
||||||
`;
|
|
||||||
})}
|
|
||||||
`;
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private readonly renderItems = (
|
||||||
|
results: SelectCollectionPage["searchResults"]["value"],
|
||||||
|
) => {
|
||||||
|
if (!results) return;
|
||||||
|
|
||||||
|
const { items } = results;
|
||||||
|
|
||||||
|
if (!items.length) {
|
||||||
|
return html`
|
||||||
|
<sl-menu-item slot="menu-item" disabled>
|
||||||
|
${msg("No matching page found.")}
|
||||||
|
</sl-menu-item>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
${items.map((item: Page) => {
|
||||||
|
return html`
|
||||||
|
<sl-menu-item
|
||||||
|
slot="menu-item"
|
||||||
|
@click=${async () => {
|
||||||
|
if (this.input) {
|
||||||
|
this.input.value = item.url;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.selectedPage = this.formatPage(item);
|
||||||
|
|
||||||
|
this.combobox?.hide();
|
||||||
|
|
||||||
|
this.selectedSnapshot = this.selectedPage.snapshots[0];
|
||||||
|
}}
|
||||||
|
>${item.url}
|
||||||
|
</sl-menu-item>
|
||||||
|
`;
|
||||||
|
})}
|
||||||
|
`;
|
||||||
|
};
|
||||||
|
|
||||||
private readonly onSearchInput = debounce(400)(() => {
|
private readonly onSearchInput = debounce(400)(() => {
|
||||||
const value = this.input?.value;
|
const value = this.input?.value;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user