Add "Copy <item type> ID" to a bunch of menus (#2426)

Addresses feedback from here
https://discord.com/channels/895426029194207262/910966759165657161/1344367205004873819
by @tw4l.

Add "Copy <item type> ID" to a bunch of menus, including all list and
detail pages, as well as all other item/crawl/page lists.

| Screenshots |
|--------|
| <img width="323" alt="Screenshot 2025-02-26 at 3 56 48 PM"
src="https://github.com/user-attachments/assets/32044c47-65f3-4e80-8f39-df5fd2101324"
/> |
| <img width="246" alt="Screenshot 2025-02-26 at 4 02 06 PM"
src="https://github.com/user-attachments/assets/8f2d6272-f450-4923-b5c9-751a2eea9a26"
/> |
| <img width="419" alt="Screenshot 2025-02-26 at 4 02 55 PM"
src="https://github.com/user-attachments/assets/0c005a33-055d-4fb7-a79e-9bedae57b785"
/> |
| <img width="1104" alt="Screenshot 2025-02-26 at 1 57 01 PM"
src="https://github.com/user-attachments/assets/7ee43400-1b30-4c78-89a0-3ddb89ef90ca"
/> |
| <img width="292" alt="Screenshot 2025-02-26 at 4 01 10 PM"
src="https://github.com/user-attachments/assets/929f7870-aa83-4f3c-947a-efad377e0b49"
/> |
| <img width="240" alt="Screenshot 2025-02-26 at 4 03 19 PM"
src="https://github.com/user-attachments/assets/45bff838-f741-45ce-b1a7-a8cfefa9656b"
/> |

---------

Co-authored-by: Henry Wilkinson <henry@wilkinson.graphics>
This commit is contained in:
Emma Segal-Grossman 2025-02-26 16:58:00 -05:00 committed by GitHub
parent e67708bd4f
commit 00e85c3e94
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 176 additions and 60 deletions

View File

@ -47,7 +47,10 @@ export class MenuItemLink extends TailwindElement {
download=${this.download} download=${this.download}
aria-disabled=${this.disabled} aria-disabled=${this.disabled}
@click=${(e: MouseEvent) => { @click=${(e: MouseEvent) => {
if (this.disabled || this.loading) return; if (this.disabled || this.loading) {
e.preventDefault();
return;
}
if (this.download) { if (this.download) {
const dropdown = this.shadowRoot!.host.closest< const dropdown = this.shadowRoot!.host.closest<

View File

@ -630,6 +630,26 @@ export class ArchivedItemDetail extends BtrixElement {
<sl-divider></sl-divider> <sl-divider></sl-divider>
`, `,
)} )}
${when(
isSuccessfullyFinished(this.item),
() => html`
<btrix-menu-item-link
href=${`/api/orgs/${this.orgId}/all-crawls/${this.itemId}/download?auth_bearer=${authToken}`}
download
>
<sl-icon name="cloud-download" slot="prefix"></sl-icon>
${msg("Download Item")}
${this.item?.fileSize
? html` <btrix-badge
slot="suffix"
class="font-monostyle text-xs text-neutral-500"
>${this.localize.bytes(this.item.fileSize)}</btrix-badge
>`
: nothing}
</btrix-menu-item-link>
<sl-divider></sl-divider>
`,
)}
${when( ${when(
this.itemType === "crawl", this.itemType === "crawl",
() => html` () => html`
@ -659,19 +679,15 @@ export class ArchivedItemDetail extends BtrixElement {
<sl-icon name="tags" slot="prefix"></sl-icon> <sl-icon name="tags" slot="prefix"></sl-icon>
${msg("Copy Tags")} ${msg("Copy Tags")}
</sl-menu-item> </sl-menu-item>
${when( <sl-menu-item
isSuccessfullyFinished(this.item), @click=${() =>
() => html` ClipboardController.copyToClipboard(
<sl-divider></sl-divider> this.item?.id ?? this.itemId ?? "",
<btrix-menu-item-link )}
href=${`/api/orgs/${this.orgId}/all-crawls/${this.itemId}/download?auth_bearer=${authToken}`} >
download <sl-icon name="copy" slot="prefix"></sl-icon>
> ${msg("Copy Item ID")}
<sl-icon name="cloud-download" slot="prefix"></sl-icon> </sl-menu-item>
${msg("Download Item")}
</btrix-menu-item-link>
`,
)}
${when( ${when(
this.isCrawler, this.isCrawler,
() => html` () => html`

View File

@ -16,6 +16,7 @@ import queryString from "query-string";
import { BtrixElement } from "@/classes/BtrixElement"; import { BtrixElement } from "@/classes/BtrixElement";
import { type Dialog } from "@/components/ui/dialog"; import { type Dialog } from "@/components/ui/dialog";
import type { PageChangeEvent } from "@/components/ui/pagination"; import type { PageChangeEvent } from "@/components/ui/pagination";
import { ClipboardController } from "@/controllers/clipboard";
import { iconFor as iconForPageReview } from "@/features/qa/page-list/helpers"; import { iconFor as iconForPageReview } from "@/features/qa/page-list/helpers";
import * as pageApproval from "@/features/qa/page-list/helpers/approval"; import * as pageApproval from "@/features/qa/page-list/helpers/approval";
import type { SelectDetail } from "@/features/qa/qa-run-dropdown"; import type { SelectDetail } from "@/features/qa/qa-run-dropdown";
@ -392,6 +393,13 @@ export class ArchivedItemDetailQA extends BtrixElement {
</btrix-menu-item-link> </btrix-menu-item-link>
<sl-divider></sl-divider> <sl-divider></sl-divider>
`} `}
<sl-menu-item
@click=${() => ClipboardController.copyToClipboard(run.id)}
>
<sl-icon name="copy" slot="prefix"></sl-icon>
${msg("Copy Run ID")}
</sl-menu-item>
<sl-divider></sl-divider>
<sl-menu-item <sl-menu-item
@click=${() => { @click=${() => {
this.deleting = run.id; this.deleting = run.id;
@ -750,12 +758,16 @@ export class ArchivedItemDetailQA extends BtrixElement {
"[clickable-start] minmax(12rem, auto)", "[clickable-start] minmax(12rem, auto)",
"minmax(min-content, 12rem)", "minmax(min-content, 12rem)",
"minmax(min-content, 12rem) [clickable-end]", "minmax(min-content, 12rem) [clickable-end]",
"min-content",
].join(" ")}" ].join(" ")}"
> >
<btrix-table-head> <btrix-table-head>
<btrix-table-header-cell>${msg("Page")}</btrix-table-header-cell> <btrix-table-header-cell>${msg("Page")}</btrix-table-header-cell>
<btrix-table-header-cell>${msg("Approval")}</btrix-table-header-cell> <btrix-table-header-cell>${msg("Approval")}</btrix-table-header-cell>
<btrix-table-header-cell>${msg("Comments")}</btrix-table-header-cell> <btrix-table-header-cell>${msg("Comments")}</btrix-table-header-cell>
<btrix-table-header-cell class="px-0">
<span class="sr-only">${msg("Row actions")}</span>
</btrix-table-header-cell>
</btrix-table-head> </btrix-table-head>
<btrix-table-body class="rounded border"> <btrix-table-body class="rounded border">
${this.pages?.items.map( ${this.pages?.items.map(
@ -809,6 +821,21 @@ export class ArchivedItemDetailQA extends BtrixElement {
${msg("None")} ${msg("None")}
</span>`} </span>`}
</btrix-table-cell> </btrix-table-cell>
<btrix-table-cell class="p-0">
<div class="col action">
<btrix-overflow-dropdown>
<sl-menu>
<sl-menu-item
@click=${() =>
ClipboardController.copyToClipboard(page.id)}
>
<sl-icon name="copy" slot="prefix"></sl-icon>
${msg("Copy Page ID")}
</sl-menu-item>
</sl-menu>
</btrix-overflow-dropdown>
</div>
</btrix-table-cell>
</btrix-table-row> </btrix-table-row>
`, `,
)} )}

View File

@ -598,6 +598,26 @@ export class CrawlsList extends BtrixElement {
<sl-divider></sl-divider> <sl-divider></sl-divider>
`, `,
)} )}
${when(
isSuccessfullyFinished(item),
() => html`
<btrix-menu-item-link
href=${`/api/orgs/${this.orgId}/all-crawls/${item.id}/download?auth_bearer=${authToken}`}
download
>
<sl-icon name="cloud-download" slot="prefix"></sl-icon>
${msg("Download Item")}
${item.fileSize
? html` <btrix-badge
slot="suffix"
class="font-monostyle text-xs text-neutral-500"
>${this.localize.bytes(item.fileSize)}</btrix-badge
>`
: nothing}
</btrix-menu-item-link>
<sl-divider></sl-divider>
`,
)}
${item.type === "crawl" ${item.type === "crawl"
? html` ? html`
<sl-menu-item <sl-menu-item
@ -615,14 +635,9 @@ export class CrawlsList extends BtrixElement {
<sl-icon name="copy" slot="prefix"></sl-icon> <sl-icon name="copy" slot="prefix"></sl-icon>
${msg("Copy Workflow ID")} ${msg("Copy Workflow ID")}
</sl-menu-item> </sl-menu-item>
<sl-menu-item
@click=${() => ClipboardController.copyToClipboard(item.id)}
>
<sl-icon name="copy" slot="prefix"></sl-icon>
${msg("Copy Archived Item ID")}
</sl-menu-item>
` `
: nothing} : nothing}
<sl-menu-item <sl-menu-item
@click=${() => @click=${() =>
ClipboardController.copyToClipboard(item.tags.join(", "))} ClipboardController.copyToClipboard(item.tags.join(", "))}
@ -631,19 +646,12 @@ export class CrawlsList extends BtrixElement {
<sl-icon name="tags" slot="prefix"></sl-icon> <sl-icon name="tags" slot="prefix"></sl-icon>
${msg("Copy Tags")} ${msg("Copy Tags")}
</sl-menu-item> </sl-menu-item>
${when( <sl-menu-item
isSuccessfullyFinished(item), @click=${() => ClipboardController.copyToClipboard(item.id)}
() => html` >
<sl-divider></sl-divider> <sl-icon name="copy" slot="prefix"></sl-icon>
<btrix-menu-item-link ${msg("Copy Item ID")}
href=${`/api/orgs/${this.orgId}/all-crawls/${item.id}/download?auth_bearer=${authToken}`} </sl-menu-item>
download
>
<sl-icon name="cloud-download" slot="prefix"></sl-icon>
${msg("Download Item")}
</btrix-menu-item-link>
`,
)}
${when( ${when(
this.isCrawler && (item.type !== "crawl" || !isActive(item)), this.isCrawler && (item.type !== "crawl" || !isActive(item)),
() => html` () => html`

View File

@ -10,6 +10,7 @@ import type { Profile, ProfileWorkflow } from "./types";
import { BtrixElement } from "@/classes/BtrixElement"; import { BtrixElement } from "@/classes/BtrixElement";
import type { Dialog } from "@/components/ui/dialog"; import type { Dialog } from "@/components/ui/dialog";
import { ClipboardController } from "@/controllers/clipboard";
import type { BrowserConnectionChange } from "@/features/browser-profiles/profile-browser"; import type { BrowserConnectionChange } from "@/features/browser-profiles/profile-browser";
import { pageNav } from "@/layouts/pageHeader"; import { pageNav } from "@/layouts/pageHeader";
import { isApiError } from "@/utils/api"; import { isApiError } from "@/utils/api";
@ -432,12 +433,19 @@ export class BrowserProfilesDetail extends BtrixElement {
${msg("Duplicate Profile")} ${msg("Duplicate Profile")}
</sl-menu-item> </sl-menu-item>
<sl-divider></sl-divider> <sl-divider></sl-divider>
<sl-menu-item
@click=${() => ClipboardController.copyToClipboard(this.profileId)}
>
<sl-icon name="copy" slot="prefix"></sl-icon>
${msg("Copy Profile ID")}
</sl-menu-item>
<sl-divider></sl-divider>
<sl-menu-item <sl-menu-item
style="--sl-color-neutral-700: var(--danger)" style="--sl-color-neutral-700: var(--danger)"
@click=${() => void this.deleteProfile()} @click=${() => void this.deleteProfile()}
> >
<sl-icon slot="prefix" name="trash3"></sl-icon> <sl-icon slot="prefix" name="trash3"></sl-icon>
${msg("Delete")} ${msg("Delete Profile")}
</sl-menu-item> </sl-menu-item>
</sl-menu> </sl-menu>
</sl-dropdown> </sl-dropdown>

View File

@ -15,6 +15,7 @@ import {
SortDirection, SortDirection,
type SortValues, type SortValues,
} from "@/components/ui/table/table-header-cell"; } from "@/components/ui/table/table-header-cell";
import { ClipboardController } from "@/controllers/clipboard";
import { pageHeader } from "@/layouts/pageHeader"; import { pageHeader } from "@/layouts/pageHeader";
import type { import type {
APIPaginatedList, APIPaginatedList,
@ -325,6 +326,14 @@ export class BrowserProfilesList extends BtrixElement {
<sl-icon slot="prefix" name="files"></sl-icon> <sl-icon slot="prefix" name="files"></sl-icon>
${msg("Duplicate Profile")} ${msg("Duplicate Profile")}
</sl-menu-item> </sl-menu-item>
<sl-divider></sl-divider>
<sl-menu-item
@click=${() => ClipboardController.copyToClipboard(data.id)}
>
<sl-icon name="copy" slot="prefix"></sl-icon>
${msg("Copy Profile ID")}
</sl-menu-item>
<sl-divider></sl-divider>
<sl-menu-item <sl-menu-item
style="--sl-color-neutral-700: var(--danger)" style="--sl-color-neutral-700: var(--danger)"
@click=${() => { @click=${() => {
@ -332,7 +341,7 @@ export class BrowserProfilesList extends BtrixElement {
}} }}
> >
<sl-icon slot="prefix" name="trash3"></sl-icon> <sl-icon slot="prefix" name="trash3"></sl-icon>
${msg("Delete")} ${msg("Delete Profile")}
</sl-menu-item> </sl-menu-item>
</sl-menu> </sl-menu>
</btrix-overflow-dropdown> </btrix-overflow-dropdown>

View File

@ -14,6 +14,7 @@ import { BtrixElement } from "@/classes/BtrixElement";
import type { MarkdownEditor } from "@/components/ui/markdown-editor"; import type { MarkdownEditor } from "@/components/ui/markdown-editor";
import type { PageChangeEvent } from "@/components/ui/pagination"; import type { PageChangeEvent } from "@/components/ui/pagination";
import { viewStateContext, type ViewStateContext } from "@/context/view-state"; import { viewStateContext, type ViewStateContext } from "@/context/view-state";
import { ClipboardController } from "@/controllers/clipboard";
import type { EditDialogTab } from "@/features/collections/collection-edit-dialog"; import type { EditDialogTab } from "@/features/collections/collection-edit-dialog";
import { collectionShareLink } from "@/features/collections/helpers/share-link"; import { collectionShareLink } from "@/features/collections/helpers/share-link";
import { SelectCollectionAccess } from "@/features/collections/select-collection-access"; import { SelectCollectionAccess } from "@/features/collections/select-collection-access";
@ -563,6 +564,16 @@ export class CollectionDetail extends BtrixElement {
)} )}
</btrix-menu-item-link> </btrix-menu-item-link>
<sl-divider></sl-divider> <sl-divider></sl-divider>
<sl-menu-item
@click=${() =>
ClipboardController.copyToClipboard(
this.collection?.id ?? this.collectionId,
)}
>
<sl-icon name="copy" slot="prefix"></sl-icon>
${msg("Copy Collection ID")}
</sl-menu-item>
<sl-divider></sl-divider>
<sl-menu-item <sl-menu-item
style="--sl-color-neutral-700: var(--danger)" style="--sl-color-neutral-700: var(--danger)"
@click=${this.confirmDelete} @click=${this.confirmDelete}
@ -868,6 +879,13 @@ export class CollectionDetail extends BtrixElement {
<sl-icon name="folder-minus" slot="prefix"></sl-icon> <sl-icon name="folder-minus" slot="prefix"></sl-icon>
${msg("Remove from Collection")} ${msg("Remove from Collection")}
</sl-menu-item> </sl-menu-item>
<sl-divider></sl-divider>
<sl-menu-item
@click=${() => ClipboardController.copyToClipboard(item.id)}
>
<sl-icon name="copy" slot="prefix"></sl-icon>
${msg("Copy Item ID")}
</sl-menu-item>
</sl-menu> </sl-menu>
</btrix-overflow-dropdown> </btrix-overflow-dropdown>
</btrix-table-cell> </btrix-table-cell>

View File

@ -585,12 +585,10 @@ export class CollectionsList extends BtrixElement {
<sl-icon name="gear" slot="prefix"></sl-icon> <sl-icon name="gear" slot="prefix"></sl-icon>
${msg("Edit Collection Settings")} ${msg("Edit Collection Settings")}
</sl-menu-item> </sl-menu-item>
<sl-divider></sl-divider>
${col.access === CollectionAccess.Public || ${col.access === CollectionAccess.Public ||
col.access === CollectionAccess.Unlisted col.access === CollectionAccess.Unlisted
? html` ? html`
<sl-menu-item <sl-menu-item
style="--sl-color-neutral-700: var(--success)"
@click=${() => { @click=${() => {
ClipboardController.copyToClipboard(this.getShareLink(col)); ClipboardController.copyToClipboard(this.getShareLink(col));
this.notify.toast({ this.notify.toast({
@ -605,14 +603,14 @@ export class CollectionsList extends BtrixElement {
</sl-menu-item> </sl-menu-item>
` `
: nothing} : nothing}
<sl-divider></sl-divider>
<btrix-menu-item-link <btrix-menu-item-link
href=${`/api/orgs/${this.orgId}/collections/${col.id}/download?auth_bearer=${authToken}`} href=${`/api/orgs/${this.orgId}/collections/${col.id}/download?auth_bearer=${authToken}`}
download download
?disabled=${!col.totalSize} ?disabled=${!col.totalSize}
> >
<sl-icon name="cloud-download" slot="prefix"></sl-icon> <sl-icon name="cloud-download" slot="prefix"></sl-icon>
${msg("Download")} ${msg("Download Collection")}
<btrix-badge <btrix-badge
slot="suffix" slot="suffix"
class="font-monostyle text-xs text-neutral-500" class="font-monostyle text-xs text-neutral-500"
@ -620,6 +618,13 @@ export class CollectionsList extends BtrixElement {
> >
</btrix-menu-item-link> </btrix-menu-item-link>
<sl-divider></sl-divider> <sl-divider></sl-divider>
<sl-menu-item
@click=${() => ClipboardController.copyToClipboard(col.id)}
>
<sl-icon name="copy" slot="prefix"></sl-icon>
${msg("Copy Collection ID")}
</sl-menu-item>
<sl-divider></sl-divider>
<sl-menu-item <sl-menu-item
style="--sl-color-neutral-700: var(--danger)" style="--sl-color-neutral-700: var(--danger)"
@click=${() => void this.manageCollection(col, "delete")} @click=${() => void this.manageCollection(col, "delete")}

View File

@ -744,6 +744,14 @@ export class WorkflowDetail extends BtrixElement {
<sl-icon name="gear" slot="prefix"></sl-icon> <sl-icon name="gear" slot="prefix"></sl-icon>
${msg("Edit Workflow Settings")} ${msg("Edit Workflow Settings")}
</sl-menu-item> </sl-menu-item>
<sl-menu-item
?disabled=${archivingDisabled}
@click=${() => void this.duplicateConfig()}
>
<sl-icon name="files" slot="prefix"></sl-icon>
${msg("Duplicate Workflow")}
</sl-menu-item>
<sl-divider></sl-divider>
<sl-menu-item <sl-menu-item
@click=${() => @click=${() =>
ClipboardController.copyToClipboard(workflow.tags.join(", "))} ClipboardController.copyToClipboard(workflow.tags.join(", "))}
@ -753,11 +761,10 @@ export class WorkflowDetail extends BtrixElement {
${msg("Copy Tags")} ${msg("Copy Tags")}
</sl-menu-item> </sl-menu-item>
<sl-menu-item <sl-menu-item
?disabled=${archivingDisabled} @click=${() => ClipboardController.copyToClipboard(workflow.id)}
@click=${() => void this.duplicateConfig()}
> >
<sl-icon name="files" slot="prefix"></sl-icon> <sl-icon name="copy" slot="prefix"></sl-icon>
${msg("Duplicate Workflow")} ${msg("Copy Workflow ID")}
</sl-menu-item> </sl-menu-item>
${when( ${when(
!workflow.crawlCount, !workflow.crawlCount,
@ -925,10 +932,18 @@ export class WorkflowDetail extends BtrixElement {
)} )}
.crawl=${crawl} .crawl=${crawl}
> >
${when( <sl-menu slot="menu">
this.isCrawler, <sl-menu-item
() => @click=${() =>
html` <sl-menu slot="menu"> ClipboardController.copyToClipboard(crawl.id)}
>
<sl-icon name="copy" slot="prefix"></sl-icon>
${msg("Copy Crawl ID")}
</sl-menu-item>
${when(
this.isCrawler,
() => html`
<sl-divider></sl-divider>
<sl-menu-item <sl-menu-item
style="--sl-color-neutral-700: var(--danger)" style="--sl-color-neutral-700: var(--danger)"
@click=${() => this.confirmDeleteCrawl(crawl)} @click=${() => this.confirmDeleteCrawl(crawl)}
@ -936,9 +951,10 @@ export class WorkflowDetail extends BtrixElement {
<sl-icon name="trash3" slot="prefix"></sl-icon> <sl-icon name="trash3" slot="prefix"></sl-icon>
${msg("Delete Crawl")} ${msg("Delete Crawl")}
</sl-menu-item> </sl-menu-item>
</sl-menu>`, `,
)}</btrix-crawl-list-item )}
>`, </sl-menu>
</btrix-crawl-list-item>`,
), ),
)} )}
</btrix-crawl-list> </btrix-crawl-list>

View File

@ -613,16 +613,15 @@ export class WorkflowsList extends BtrixElement {
${when( ${when(
this.appState.isCrawler, this.appState.isCrawler,
() => () =>
html` <sl-divider></sl-divider> html`<sl-menu-item
<sl-menu-item @click=${() =>
@click=${() => this.navigate.to(
this.navigate.to( `${this.navigate.orgBasePath}/workflows/${workflow.id}?edit`,
`${this.navigate.orgBasePath}/workflows/${workflow.id}?edit`, )}
)} >
> <sl-icon name="gear" slot="prefix"></sl-icon>
<sl-icon name="gear" slot="prefix"></sl-icon> ${msg("Edit Workflow Settings")}
${msg("Edit Workflow Settings")} </sl-menu-item>`,
</sl-menu-item>`,
)} )}
<sl-menu-item <sl-menu-item
@click=${() => @click=${() =>
@ -642,6 +641,13 @@ export class WorkflowsList extends BtrixElement {
<sl-icon name="files" slot="prefix"></sl-icon> <sl-icon name="files" slot="prefix"></sl-icon>
${msg("Duplicate Workflow")} ${msg("Duplicate Workflow")}
</sl-menu-item> </sl-menu-item>
<sl-divider></sl-divider>
<sl-menu-item
@click=${() => ClipboardController.copyToClipboard(workflow.id)}
>
<sl-icon name="copy" slot="prefix"></sl-icon>
${msg("Copy Workflow ID")}
</sl-menu-item>
${when( ${when(
!workflow.crawlCount, !workflow.crawlCount,
() => html` () => html`