Skip to content

Show page titles in page selection dropdown #2433

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions backend/btrixcloud/colls.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,9 +341,11 @@ async def get_collection_out(
result = await self.get_collection_raw(coll_id, public_or_unlisted_only)

if resources:
result["resources"], crawl_ids, pages_optimized = (
await self.get_collection_crawl_resources(coll_id)
)
(
result["resources"],
crawl_ids,
pages_optimized,
) = await self.get_collection_crawl_resources(coll_id)

initial_pages, _ = await self.page_ops.list_pages(
crawl_ids=crawl_ids,
Expand Down Expand Up @@ -965,9 +967,11 @@ async def get_collection_all(org: Organization = Depends(org_viewer_dep)):
try:
all_collections, _ = await colls.list_collections(org, page_size=10_000)
for collection in all_collections:
results[collection.name], _, _ = (
await colls.get_collection_crawl_resources(collection.id)
)
(
results[collection.name],
_,
_,
) = await colls.get_collection_crawl_resources(collection.id)
except Exception as exc:
# pylint: disable=raise-missing-from
raise HTTPException(
Expand Down
1 change: 1 addition & 0 deletions backend/btrixcloud/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1376,6 +1376,7 @@ class PageUrlCount(BaseModel):
"""Model for counting pages by URL"""

url: AnyHttpUrl
title: Optional[str] = None
count: int = 0
snapshots: List[PageIdTimestamp] = []

Expand Down
26 changes: 21 additions & 5 deletions frontend/src/components/ui/combobox.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { consume } from "@lit/context";
import type { SlMenu, SlMenuItem, SlPopup } from "@shoelace-style/shoelace";
import { css, html, LitElement, type PropertyValues } from "lit";
import { css, html, type PropertyValues } from "lit";
import {
customElement,
property,
Expand All @@ -8,6 +9,8 @@ import {
state,
} from "lit/decorators.js";

import { TailwindElement } from "@/classes/TailwindElement";
import { popupBoundary } from "@/context/popup-boundary";
import { dropdown } from "@/utils/css";

/**
Expand All @@ -20,7 +23,7 @@ import { dropdown } from "@/utils/css";
* @event request-close
*/
@customElement("btrix-combobox")
export class Combobox extends LitElement {
export class Combobox extends TailwindElement {
static styles = [
dropdown,
css`
Expand All @@ -34,6 +37,13 @@ export class Combobox extends LitElement {
@property({ type: Boolean })
open = false;

@property({ type: Boolean })
loading = false;

@consume({ context: popupBoundary })
@state()
autoSizeBoundary?: Element | Element[] | undefined;

@state()
isActive = true;

Expand Down Expand Up @@ -69,22 +79,25 @@ export class Combobox extends LitElement {
}

render() {
console.log(this.autoSizeBoundary);
return html`
<sl-popup
placement="bottom-start"
shift
strategy="fixed"
autoSize="both"
.autoSizeBoundary=${this.autoSizeBoundary}
?active=${this.isActive}
@keydown=${this.onKeydown}
@keyup=${this.onKeyup}
@focusout=${this.onFocusout}
>
<div slot="anchor">
<div slot="anchor" class="relative z-20">
<slot></slot>
</div>
<div
id="dropdown"
class="dropdown hidden"
class="dropdown z-10 -mt-2 hidden"
@animationend=${(e: AnimationEvent) => {
const el = e.target as HTMLDivElement;
if (e.animationName === "dropdownShow") {
Expand All @@ -97,7 +110,10 @@ export class Combobox extends LitElement {
}
}}
>
<sl-menu role="listbox">
<sl-menu role="listbox" class="border-t-0 pt-4">
<!-- <div class="fixed inset-0 bg-neutral-50 opacity-25">
<sl-spinner></sl-spinner>
</div> -->
<slot name="menu-item"></slot>
</sl-menu>
</div>
Expand Down
1 change: 1 addition & 0 deletions frontend/src/components/ui/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,4 @@ import("./tag-input");
import("./tag");
import("./time-input");
import("./user-language-select");
import("./menu-item-without-focus");
22 changes: 22 additions & 0 deletions frontend/src/components/ui/menu-item-without-focus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/** A version of <sl-menu-item> that doesn't steal focus on mouseover */

import { SlMenuItem } from "@shoelace-style/shoelace";
import { customElement } from "lit/decorators.js";

@customElement("btrix-menu-item")
// @ts-expect-error this shouldn't be allowed, but idk of an easier way without
// forking the whole component
export class BtrixMenuItem extends SlMenuItem {
private readonly handleMouseOver = (event: MouseEvent) => {
// NOT doing this.focus();
event.stopPropagation();
};

connectedCallback() {
super.connectedCallback();
}

disconnectedCallback() {
super.disconnectedCallback();
}
}
8 changes: 8 additions & 0 deletions frontend/src/context/popup-boundary.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { createContext } from "@lit/context";

/**
* Boundary for custom <sl-popup> instances to use, e.g. when inside a dialog
*/
export const popupBoundary = createContext<Element | Element[] | undefined>(
"popup-boundary",
);
6 changes: 6 additions & 0 deletions frontend/src/features/collections/collection-edit-dialog.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { provide } from "@lit/context";
import { localized, msg, str } from "@lit/localize";
import { Task, TaskStatus } from "@lit/task";
import { type SlRequestCloseEvent } from "@shoelace-style/shoelace";
Expand All @@ -22,6 +23,7 @@ import { type SelectCollectionPage } from "./select-collection-page";
import { BtrixElement } from "@/classes/BtrixElement";
import type { Dialog } from "@/components/ui/dialog";
import { type TabGroupPanel } from "@/components/ui/tab-group/tab-panel";
import { popupBoundary } from "@/context/popup-boundary";
import {
type Collection,
type CollectionThumbnailSource,
Expand Down Expand Up @@ -118,6 +120,9 @@ export class CollectionEdit extends BtrixElement {
@query("btrix-collection-snapshot-preview")
public readonly thumbnailPreview?: CollectionSnapshotPreview | null;

@provide({ context: popupBoundary })
private popupBoundary: Element | Element[] | undefined;

protected willUpdate(changedProperties: PropertyValues<this>): void {
if (changedProperties.has("collectionId") && this.collectionId) {
void this.fetchCollection(this.collectionId);
Expand All @@ -135,6 +140,7 @@ export class CollectionEdit extends BtrixElement {
null;
this.selectedSnapshot = this.collection?.thumbnailSource ?? null;
}
this.popupBoundary = this.dialog;
}

readonly checkChanged = checkChanged.bind(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export default function renderPresentation(this: CollectionEdit) {
</sl-tooltip>`
: this.thumbnailPreview?.blobTask.status === TaskStatus.PENDING &&
!this.blobIsLoaded
? html`<sl-spinner slot="prefix"></sl-spinner>`
? html`<sl-spinner class="size-4" slot="prefix"></sl-spinner>`
: nothing}
</btrix-select-collection-page>
<sl-checkbox
Expand Down
46 changes: 32 additions & 14 deletions frontend/src/features/collections/select-collection-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import type { APIPaginationQuery } from "@/types/api";
import type { Collection } from "@/types/collection";
import type { UnderlyingFunction } from "@/types/utils";
import { tw } from "@/utils/tailwind";
import { timeoutCache } from "@/utils/timeoutCache";
import { cached } from "@/utils/weakCache";

type Snapshot = {
pageId: string;
Expand All @@ -31,6 +33,7 @@ type Snapshot = {

type Page = {
url: string;
title?: string;
count: number;
snapshots: Snapshot[];
};
Expand Down Expand Up @@ -179,17 +182,20 @@ export class SelectCollectionPage extends BtrixElement {
}

private readonly searchResults = new Task(this, {
task: async ([searchValue], { signal }) => {
const pageUrls = await this.getPageUrls(
{
id: this.collectionId!,
urlPrefix: searchValue,
},
signal,
);
task: cached(
async ([searchValue], { signal }) => {
const pageUrls = await this.getPageUrls(
{
id: this.collectionId!,
urlPrefix: searchValue,
},
signal,
);

return pageUrls;
},
return pageUrls;
},
{ cacheConstructor: timeoutCache(300) },
),
args: () => [this.searchQuery] as const,
});

Expand Down Expand Up @@ -365,19 +371,21 @@ export class SelectCollectionPage extends BtrixElement {
this.renderItems(
// Render previous value so that dropdown doesn't shift while typing
this.searchResults.value,
true,
),
complete: this.renderItems,
});
}

private readonly renderItems = (
results: SelectCollectionPage["searchResults"]["value"],
loading = false,
) => {
if (!results) return;

const { items } = results;

if (!items.length) {
if (!loading && !items.length) {
return html`
<sl-menu-item slot="menu-item" disabled>
${msg("No matching page found.")}
Expand All @@ -388,7 +396,7 @@ export class SelectCollectionPage extends BtrixElement {
return html`
${items.map((item: Page) => {
return html`
<sl-menu-item
<btrix-menu-item
slot="menu-item"
@click=${async () => {
if (this.input) {
Expand All @@ -401,8 +409,18 @@ export class SelectCollectionPage extends BtrixElement {

this.selectedSnapshot = this.selectedPage.snapshots[0];
}}
>${item.url}
</sl-menu-item>
>${item.title
? html`<div class="text-sm font-semibold">${item.title}</div>
<div class="text-xs leading-4 text-blue-600">
${item.url}
</div>`
: html`<div class="text-sm font-semibold opacity-50">
${msg("No page title")}
</div>
<div class="text-xs leading-4 text-blue-600">
${item.url}
</div>`}
</btrix-menu-item>
`;
})}
`;
Expand Down
13 changes: 6 additions & 7 deletions frontend/src/utils/css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ export const animatePulse = css`
export const dropdown = css`
.dropdown {
contain: content;
transform-origin: top left;
box-shadow: var(--sl-shadow-medium);
}

Expand All @@ -111,34 +110,34 @@ export const dropdown = css`
}

.animateShow {
animation: dropdownShow 100ms ease forwards;
animation: dropdownShow 150ms cubic-bezier(0, 0, 0.2, 1) forwards;
}

.animateHide {
animation: dropdownHide 100ms ease forwards;
animation: dropdownHide 150ms cubic-bezier(0.4, 0, 1, 1) forwards;
}

@keyframes dropdownShow {
from {
opacity: 0;
transform: scale(0.9);
transform: translateY(-8px);
}

to {
opacity: 1;
transform: scale(1);
transform: translateY(0);
}
}

@keyframes dropdownHide {
from {
opacity: 1;
transform: scale(1);
transform: translateY(0);
}

to {
opacity: 0;
transform: scale(0.9);
transform: translateY(-8px);
}
}
`;
Loading