From cf1592a809697a8de15fa96ac08c49f76b496aa2 Mon Sep 17 00:00:00 2001 From: Henry Wilkinson Date: Fri, 3 May 2024 13:48:18 -0400 Subject: [PATCH] Fix truncation for long workflow / item names (#1773) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #1771 ### Changes - Previously these would either get cut off or overflow, now they get truncated! - Titles also have a tooltip now ### Screenshots (after, see issue for before) Screenshot 2024-05-02 at 1 25 00 PM Screenshot 2024-05-02 at 1 58 21 PM **Before** Screenshot 2024-05-02 at 1 59 26 PM **After** Screenshot 2024-05-02 at 2 46 49 PM ### Caveats - Doesn't replace the in-page dialog. Added a TODO note. --------- Co-authored-by: emma --- frontend/src/components/detail-page-title.ts | 76 +++++++++++++++++++ frontend/src/components/index.ts | 1 + .../src/features/archived-items/crawl-list.ts | 1 + .../archived-item-detail.ts | 38 ++++------ frontend/src/pages/org/workflow-detail.ts | 58 +++++++------- frontend/src/utils/pluralize.ts | 26 +++++++ 6 files changed, 151 insertions(+), 49 deletions(-) create mode 100644 frontend/src/components/detail-page-title.ts diff --git a/frontend/src/components/detail-page-title.ts b/frontend/src/components/detail-page-title.ts new file mode 100644 index 00000000..dbf70808 --- /dev/null +++ b/frontend/src/components/detail-page-title.ts @@ -0,0 +1,76 @@ +import { localized } from "@lit/localize"; +import { css, html, nothing } from "lit"; +import { customElement, property } from "lit/decorators.js"; + +import { TailwindElement } from "@/classes/TailwindElement"; +import { type ArchivedItem, type Workflow } from "@/types/crawler"; +import { formatNumber } from "@/utils/localization"; +import { pluralOf } from "@/utils/pluralize"; + +enum TitleSource { + Name, + ID, + FirstSeed, +} + +type Item = Pick< + ArchivedItem & Workflow, + "name" | "firstSeed" | "seedCount" | "id" +>; + +@localized() +@customElement("btrix-detail-page-title") +export class DetailPageTitle extends TailwindElement { + @property({ type: Object }) + item: Item | undefined; + + static styles = css` + :host { + display: contents; + } + + sl-tooltip::part(body) { + word-break: break-all; + max-width: min(var(--max-width), calc(100vw - 0.5rem)); + } + `; + + private primaryTitle(item: Item): { + title: string; + source: TitleSource; + } { + if (item.name) return { title: item.name, source: TitleSource.Name }; + if (!item.firstSeed || !item.seedCount) + return { title: item.id, source: TitleSource.ID }; + return { title: item.firstSeed, source: TitleSource.FirstSeed }; + } + + private renderTitle(item: Item) { + const { title, source } = this.primaryTitle(item); + + if (source !== TitleSource.FirstSeed) + return html`${title}`; + + const remainder = item.seedCount - 1; + + return html`${item.firstSeed}${remainder + ? html` +${formatNumber(remainder)} ${pluralOf("URLs", remainder)}` + : nothing}`; + } + + render() { + if (!this.item) + return html``; + + return html` +

+ ${this.renderTitle(this.item)} +

+
`; + } +} diff --git a/frontend/src/components/index.ts b/frontend/src/components/index.ts index 7ea08b96..25a6dcd5 100644 --- a/frontend/src/components/index.ts +++ b/frontend/src/components/index.ts @@ -5,3 +5,4 @@ import("./orgs-list"); import("./not-found"); import("./screencast"); import("./beta-badges"); +import("./detail-page-title"); diff --git a/frontend/src/features/archived-items/crawl-list.ts b/frontend/src/features/archived-items/crawl-list.ts index 1fc94bce..9174ccf3 100644 --- a/frontend/src/features/archived-items/crawl-list.ts +++ b/frontend/src/features/archived-items/crawl-list.ts @@ -139,6 +139,7 @@ export class CrawlListItem extends TailwindElement { `, )} diff --git a/frontend/src/pages/org/archived-item-detail/archived-item-detail.ts b/frontend/src/pages/org/archived-item-detail/archived-item-detail.ts index 8aa4d50a..8e0382a2 100644 --- a/frontend/src/pages/org/archived-item-detail/archived-item-detail.ts +++ b/frontend/src/pages/org/archived-item-detail/archived-item-detail.ts @@ -420,22 +420,27 @@ export class ArchivedItemDetail extends TailwindElement { if (!this.crawl) return html``; - if (this.crawl.name) return this.crawl.name; + if (this.crawl.name) + return html`${this.crawl.name}`; if (!this.crawl.firstSeed || !this.crawl.seedCount) return this.crawl.id; const remainder = this.crawl.seedCount - 1; - let crawlName: TemplateResult = html`${this.crawl.firstSeed}`; if (remainder) { if (remainder === 1) { crawlName = msg( - html`${this.crawl.firstSeed} - +${remainder} URL`, + html`${this.crawl.firstSeed} + +${remainder} URL`, ); } else { crawlName = msg( - html`${this.crawl.firstSeed} - +${remainder} URLs`, + html`${this.crawl.firstSeed} + +${remainder} URLs`, ); } } @@ -534,17 +539,9 @@ export class ArchivedItemDetail extends TailwindElement { private renderHeader() { return html` -
-

- ${this.renderName()} -

-
+
+ +
${this.isActive ? html` @@ -1296,13 +1293,10 @@ ${this.crawl?.description} return !formEl.querySelector("[data-invalid]"); } + // TODO replace with in-page dialog private async deleteCrawl() { if ( - !window.confirm( - msg( - str`Are you sure you want to delete crawl of ${this.renderName()}?`, - ), - ) + !window.confirm(msg(str`Are you sure you want to delete this crawl?`)) ) { return; } diff --git a/frontend/src/pages/org/workflow-detail.ts b/frontend/src/pages/org/workflow-detail.ts index 38056315..b4b842a2 100644 --- a/frontend/src/pages/org/workflow-detail.ts +++ b/frontend/src/pages/org/workflow-detail.ts @@ -282,22 +282,20 @@ export class WorkflowDetail extends LiteElement {
${this.renderHeader()} -
-

- ${this.renderName()} - ${when( - this.workflow?.inactive, - () => html` - ${msg("Inactive")} - `, - )} -

-
+
+ + ${when( + this.workflow?.inactive, + () => html` + ${msg("Inactive")} + `, + )} + +
${when( this.isCrawler && this.workflow && !this.workflow.inactive, this.renderActions, @@ -559,7 +557,9 @@ export class WorkflowDetail extends LiteElement { ${this.renderHeader(this.workflow!.id)}
-

${this.renderName()}

+

+ ${this.renderName()} +

${when( @@ -593,7 +593,7 @@ export class WorkflowDetail extends LiteElement { ${when( this.workflow.isCrawlRunning, () => html` - + (this.openDialogName = "stop")} @@ -629,7 +629,6 @@ export class WorkflowDetail extends LiteElement { void this.runNow()} @@ -798,22 +797,28 @@ export class WorkflowDetail extends LiteElement { } private renderName() { - if (!this.workflow) return ""; - if (this.workflow.name) return this.workflow.name; + if (!this.workflow) + return html``; + if (this.workflow.name) + return html`${this.workflow.name}`; const { seedCount, firstSeed } = this.workflow; if (seedCount === 1) { - return firstSeed; + return html`${firstSeed}`; } const remainderCount = seedCount - 1; if (remainderCount === 1) { return msg( - html`${firstSeed} - +${remainderCount} URL`, + html` ${firstSeed} + +${remainderCount} URL`, ); } return msg( - html`${firstSeed} - +${remainderCount} URLs`, + html` ${firstSeed} + +${remainderCount} URLs`, ); } @@ -1050,7 +1055,6 @@ export class WorkflowDetail extends LiteElement { this.workflow?.lastCrawlId, () => html` {