Skip to content

Commit 357cbf4

Browse files
authored
feat: Show all crawl runs + crawl deletion UX improvements (#2917)
Overall, a more consistent experience for navigating all workflow crawls and managing crawl-related items. - Adds new "Crawl Runs" page under "Crawling" to display all crawl runs, including canceled and failed - Enables sorting crawls for by execution time and page count - Updates icon for "Canceled" state to not appear as error - Update archived item type labels - Refactors archived item and crawl deletion confirmation to use same dialog (partially addresses #619) - Show collections in deletion confirmation - Refactors `/archived-items/crawl-list.ts` component to -> `/crawls/crawl-list/` components
1 parent 7626e16 commit 357cbf4

File tree

31 files changed

+1915
-452
lines changed

31 files changed

+1915
-452
lines changed

backend/btrixcloud/crawls.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,8 @@ async def list_crawls(
297297
"qaRunCount",
298298
"lastQAState",
299299
"lastQAStarted",
300+
"crawlExecSeconds",
301+
"pageCount",
300302
):
301303
raise HTTPException(status_code=400, detail="invalid_sort_by")
302304
if sort_direction not in (1, -1):

frontend/docs/docs/user-guide/archived-items.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ The status of an archived item depends on its type. Uploads will always have the
1515
| <span class="status-success">:bootstrap-check-circle-fill: Complete</span> | The crawl completed according to the workflow's settings. Workflows with [crawl limits](workflow-setup.md#crawl-limits) set may stop running before they capture every queued page, but the resulting archived item will still be marked as "Complete". |
1616
| <span class="status-neutral">:bootstrap-dash-square-fill: Stopped</span> | The crawl workflow was _stopped_ gracefully by a user and data is saved. |
1717
| <span class="status-neutral">:bootstrap-exclamation-square-fill: Stopped: Reason</span> | A workflow limit (listed as the reason) was reached and data is saved. |
18-
| <span class="status-warning">:bootstrap-x-octagon-fill: Canceled</span> | The crawl workflow was _canceled_ by a user, no data is saved. |
18+
| <span class="status-neutral">:bootstrap-exclamation-octagon: Canceled</span> | The crawl workflow was _canceled_ by a user, no data is saved. |
1919
| <span class="status-danger">:bootstrap-diamond-triangle-fill: Failed</span> | A serious error occurred while crawling, no data is saved.|
2020

21-
Because <span class="status-warning">:bootstrap-x-octagon-fill: Canceled</span> and <span class="status-danger">:bootstrap-exclamation-diamond-fill: Failed</span> crawls do not contain data, they are omitted from the archived items list page and cannot be added to a collection.
21+
Because <span class="status-neutral">:bootstrap-exclamation-octagon: Canceled</span> and <span class="status-danger">:bootstrap-exclamation-diamond-fill: Failed</span> crawls do not contain data, they are omitted from the archived items list page and cannot be added to a collection.
2222

2323
## Archived Item Details
2424

frontend/src/components/ui/badge.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ export class Badge extends TailwindElement {
2828
@property({ type: String })
2929
variant: BadgeVariant = "neutral";
3030

31+
@property({ type: String })
32+
size?: "medium" | "large" = "medium";
33+
3134
@property({ type: Boolean })
3235
outline = false;
3336

@@ -47,15 +50,16 @@ export class Badge extends TailwindElement {
4750
return html`
4851
<span
4952
class=${clsx(
50-
tw`inline-flex min-h-4 items-center justify-center align-[1px] text-xs leading-none`,
53+
tw`inline-flex min-h-4 items-center justify-center align-[1px] leading-none`,
54+
this.size === "medium" && tw`text-xs`,
5155
this.outline
5256
? [
53-
tw`ring-1`,
57+
tw`mx-px ring-1`,
5458
{
55-
success: tw`bg-success-500 text-success-500 ring-success-500`,
59+
success: tw`bg-success-50 text-success-700 ring-success-400`,
5660
warning: tw`bg-warning-600 text-warning-600 ring-warning-600`,
5761
danger: tw`bg-danger-500 text-danger-500 ring-danger-500`,
58-
neutral: tw`bg-neutral-100 text-neutral-600 ring-neutral-600`,
62+
neutral: tw`bg-neutral-100 text-neutral-600 ring-neutral-300`,
5963
"high-contrast": tw`bg-neutral-600 text-neutral-0 ring-neutral-0`,
6064
primary: tw`bg-white text-primary ring-primary`,
6165
cyan: tw`bg-cyan-50 text-cyan-600 ring-cyan-600`,
@@ -72,7 +76,12 @@ export class Badge extends TailwindElement {
7276
cyan: tw`bg-cyan-50 text-cyan-600`,
7377
blue: tw`bg-blue-50 text-blue-600`,
7478
}[this.variant],
75-
this.pill ? tw`min-w-[1.125rem] rounded-full px-1` : tw`rounded px-2`,
79+
this.pill
80+
? [
81+
tw`min-w-[1.125rem] rounded-full`,
82+
this.size === "large" ? tw`px-1.5 py-0.5` : tw`px-1`,
83+
]
84+
: [tw`rounded`, this.size === "large" ? tw`px-2.5 py-1` : tw`px-2`],
7685
)}
7786
part="base"
7887
>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export type BtrixCancelEvent = CustomEvent<never>;
2+
3+
declare global {
4+
interface GlobalEventHandlersEventMap {
5+
"btrix-cancel": BtrixCancelEvent;
6+
}
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export type BtrixConfirmEvent = CustomEvent<never>;
2+
3+
declare global {
4+
interface GlobalEventHandlersEventMap {
5+
"btrix-confirm": BtrixConfirmEvent;
6+
}
7+
}

frontend/src/features/archived-items/crawl-status.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,9 +308,9 @@ export class CrawlStatus extends TailwindElement {
308308
break;
309309

310310
case "canceled":
311-
color = "var(--sl-color-orange-600)";
311+
color = "var(--sl-color-neutral-600)";
312312
icon = html`<sl-icon
313-
name="x-octagon-fill"
313+
name="x-octagon"
314314
slot="prefix"
315315
style="color: ${color}"
316316
></sl-icon>`;
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import { localized, msg, str } from "@lit/localize";
2+
import { Task } from "@lit/task";
3+
import { html } from "lit";
4+
import { customElement, property, query } from "lit/decorators.js";
5+
import { when } from "lit/directives/when.js";
6+
7+
import { BtrixElement } from "@/classes/BtrixElement";
8+
import type { Dialog } from "@/components/ui/dialog";
9+
import type { ArchivedItem } from "@/types/crawler";
10+
import { isCrawl, renderName } from "@/utils/crawler";
11+
import { pluralOf } from "@/utils/pluralize";
12+
13+
/**
14+
* Confirm deletion of an archived item, crawl associated
15+
* with an archived item, or crawl run.
16+
*
17+
* @slot name
18+
*/
19+
@customElement("btrix-delete-item-dialog")
20+
@localized()
21+
export class DeleteItemDialog extends BtrixElement {
22+
@property({ type: Object })
23+
item?: ArchivedItem;
24+
25+
@property({ type: Boolean })
26+
open = false;
27+
28+
@query("btrix-dialog")
29+
readonly dialog?: Dialog | null;
30+
31+
private readonly collectionsTask = new Task(this, {
32+
task: async ([open, crawl], { signal }) => {
33+
if (!crawl?.collectionIds) return;
34+
35+
if (!open) {
36+
return crawl.collectionIds.map((id) => ({ id }));
37+
}
38+
39+
return (await this.getCrawl(crawl.id, signal)).collections;
40+
},
41+
args: () => [this.open, this.item] as const,
42+
});
43+
44+
render() {
45+
return html`<btrix-dialog
46+
.label=${this.item
47+
? isCrawl(this.item)
48+
? msg("Delete Crawl?")
49+
: msg("Delete Archived Item?")
50+
: msg("Delete")}
51+
.open=${this.open}
52+
>
53+
${this.renderContent()}
54+
</btrix-dialog>`;
55+
}
56+
57+
private renderContent() {
58+
const item = this.item;
59+
60+
if (!item) return;
61+
62+
const crawl = isCrawl(item);
63+
const item_name = html`<slot name="name"
64+
><strong class="font-semibold">${renderName(item)}</strong></slot
65+
>`;
66+
67+
return html`
68+
<p>
69+
${msg(html`Are you sure you want to delete ${item_name}?`)}
70+
${msg("All associated files and logs will be deleted.")}
71+
</p>
72+
73+
${this.renderCollections()}
74+
<div slot="footer" class="flex justify-between">
75+
<sl-button
76+
size="small"
77+
.autofocus=${true}
78+
@click=${() => {
79+
void this.dialog?.hide();
80+
this.dispatchEvent(new CustomEvent("btrix-cancel"));
81+
}}
82+
>${msg("Cancel")}</sl-button
83+
>
84+
<sl-button
85+
size="small"
86+
variant="danger"
87+
@click=${() => {
88+
this.dispatchEvent(new CustomEvent("btrix-confirm"));
89+
}}
90+
>${crawl
91+
? msg("Delete Crawl")
92+
: msg("Delete Archived Item")}</sl-button
93+
>
94+
</div>
95+
`;
96+
}
97+
98+
private renderCollections() {
99+
if (!this.item?.collectionIds.length) return;
100+
101+
const { collectionIds } = this.item;
102+
const count = collectionIds.length;
103+
104+
const number_of_collections = this.localize.number(count);
105+
const plural_of_collections = pluralOf("collections", count);
106+
107+
return html`
108+
<p class="my-2">
109+
${msg(
110+
str`The archived item will be removed from ${number_of_collections} ${plural_of_collections}:`,
111+
)}
112+
</p>
113+
${this.collectionsTask.render({
114+
pending: () =>
115+
html`<btrix-linked-collections-list
116+
.collections=${collectionIds.map((id) => ({ id }))}
117+
baseUrl="${this.navigate.orgBasePath}/collections/view"
118+
>
119+
</btrix-linked-collections-list>`,
120+
complete: (res) =>
121+
when(
122+
res,
123+
(collections) =>
124+
html`<btrix-linked-collections-list
125+
.collections=${collections}
126+
baseUrl="${this.navigate.orgBasePath}/collections/view"
127+
>
128+
</btrix-linked-collections-list>`,
129+
),
130+
})}
131+
`;
132+
}
133+
134+
private async getCrawl(id: string, signal: AbortSignal) {
135+
const data: ArchivedItem = await this.api.fetch<ArchivedItem>(
136+
`/orgs/${this.orgId}/crawls/${id}/replay.json`,
137+
{
138+
signal,
139+
},
140+
);
141+
142+
return data;
143+
}
144+
}

frontend/src/features/archived-items/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import("./archived-item-list");
22
import("./archived-item-state-filter");
33
import("./archived-item-tag-filter");
4-
import("./crawl-list");
54
import("./crawl-log-table");
65
import("./crawl-logs");
6+
import("./delete-item-dialog");
77
import("./item-metadata-editor");
88
import("./crawl-pending-exclusions");
99
import("./crawl-queue");

frontend/src/features/crawl-workflows/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import("./workflow-action-menu/workflow-action-menu");
99
import("./workflow-editor");
1010
import("./workflow-list");
1111
import("./workflow-schedule-filter");
12+
import("./workflow-search");
1213
import("./workflow-tag-filter");
1314
import("./workflow-profile-filter");
1415
import("./workflow-last-crawl-state-filter");

frontend/src/features/crawl-workflows/workflow-list.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,12 @@ export class WorkflowListItem extends BtrixElement {
452452
<sl-tooltip hoist placement="bottom">
453453
<div>
454454
<div class="detail truncate">
455-
<span class="userName">${workflow.modifiedByName}</span>
455+
${workflow.modifiedByName
456+
? html`<btrix-user-chip
457+
userId=${workflow.modifiedBy}
458+
userName=${workflow.modifiedByName}
459+
></btrix-user-chip>`
460+
: notSpecified}
456461
</div>
457462
<div class="desc">${shortDate(workflow.modified)}</div>
458463
</div>

0 commit comments

Comments
 (0)