diff --git a/frontend/src/pages/org/workflow-detail.ts b/frontend/src/pages/org/workflow-detail.ts index 020e4602df..3fc789ed9c 100644 --- a/frontend/src/pages/org/workflow-detail.ts +++ b/frontend/src/pages/org/workflow-detail.ts @@ -18,6 +18,7 @@ import type { CrawlLog } from "@/features/archived-items/crawl-logs"; import { CrawlStatus } from "@/features/archived-items/crawl-status"; import { ExclusionEditor } from "@/features/crawl-workflows/exclusion-editor"; import { pageNav, type Breadcrumb } from "@/layouts/pageHeader"; +import { deleteConfirmation } from "@/strings/ui"; import type { APIPaginatedList } from "@/types/api"; import { type CrawlState } from "@/types/crawlState"; import { isApiError } from "@/utils/api"; @@ -54,7 +55,13 @@ export class WorkflowDetail extends BtrixElement { isCrawler!: boolean; @property({ type: String }) - openDialogName?: "scale" | "exclusions" | "cancel" | "stop" | "delete"; + openDialogName?: + | "scale" + | "exclusions" + | "cancel" + | "stop" + | "delete" + | "deleteCrawl"; @property({ type: String }) initialActivePanel?: Tab; @@ -255,14 +262,14 @@ export class WorkflowDetail extends BtrixElement { render() { if (this.isEditing && this.isCrawler) { return html` -
+
${when(this.workflow, this.renderEditor)}
`; } return html` -
+
${this.renderBreadcrumbs()}
@@ -355,7 +362,7 @@ export class WorkflowDetail extends BtrixElement { (this.openDialogName = undefined)} @sl-show=${this.showDialog} @sl-after-hide=${() => (this.isDialogVisible = false)} @@ -392,6 +399,32 @@ export class WorkflowDetail extends BtrixElement { > ${this.isDialogVisible ? this.renderEditScale() : ""} + (this.openDialogName = undefined)} + @sl-show=${this.showDialog} + @sl-after-hide=${() => (this.isDialogVisible = false)} + > + ${deleteConfirmation(this.renderName())} +
+ (this.openDialogName = undefined)} + >${msg("Cancel")} + { + void this.delete(); + this.openDialogName = undefined; + }} + >${msg("Delete Workflow")} +
+
`; } @@ -736,12 +769,12 @@ export class WorkflowDetail extends BtrixElement { ${msg("Duplicate Workflow")} ${when( - !this.lastCrawlId, + !workflow.crawlCount, () => html` void this.delete()} + @click=${() => (this.openDialogName = "delete")} > ${msg("Delete Workflow")} @@ -842,7 +875,7 @@ export class WorkflowDetail extends BtrixElement { private renderCrawls() { return html` -
+
@@ -1643,7 +1676,7 @@ export class WorkflowDetail extends BtrixElement { private readonly confirmDeleteCrawl = (crawl: Crawl) => { this.crawlToDelete = crawl; - this.openDialogName = "delete"; + this.openDialogName = "deleteCrawl"; }; private async deleteCrawl(crawl: Crawl) { @@ -1666,6 +1699,9 @@ export class WorkflowDetail extends BtrixElement { id: "archived-item-delete-status", }); void this.fetchCrawls(); + + // Update crawl count + void this.fetchWorkflow(); } catch (e) { if (this.crawlToDelete) { this.confirmDeleteCrawl(this.crawlToDelete); diff --git a/frontend/src/pages/org/workflows-list.ts b/frontend/src/pages/org/workflows-list.ts index bbf31135be..e7f39c81d4 100644 --- a/frontend/src/pages/org/workflows-list.ts +++ b/frontend/src/pages/org/workflows-list.ts @@ -1,7 +1,11 @@ import { localized, msg, str } from "@lit/localize"; -import type { SlCheckbox, SlSelectEvent } from "@shoelace-style/shoelace"; +import type { + SlCheckbox, + SlDialog, + SlSelectEvent, +} from "@shoelace-style/shoelace"; import { html, type PropertyValues } from "lit"; -import { customElement, state } from "lit/decorators.js"; +import { customElement, query, state } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; import { when } from "lit/directives/when.js"; import queryString from "query-string"; @@ -21,6 +25,7 @@ import { type SelectEvent } from "@/components/ui/search-combobox"; import type { SelectJobTypeEvent } from "@/features/crawl-workflows/new-workflow-dialog"; import { pageHeader } from "@/layouts/pageHeader"; import scopeTypeLabels from "@/strings/crawl-workflows/scopeType"; +import { deleteConfirmation } from "@/strings/ui"; import type { APIPaginatedList, APIPaginationQuery } from "@/types/api"; import { NewWorkflowOnlyScopeType } from "@/types/workflow"; import { isApiError } from "@/utils/api"; @@ -91,6 +96,9 @@ export class WorkflowsList extends BtrixElement { @state() private fetchErrorStatusCode?: number; + @state() + private workflowToDelete?: ListWorkflow; + @state() private orderBy: { field: SortField; @@ -106,6 +114,9 @@ export class WorkflowsList extends BtrixElement { @state() private filterByCurrentUser = false; + @query("#deleteDialog") + private readonly deleteDialog?: SlDialog | null; + // For fuzzy search: private readonly searchKeys = ["name", "firstSeed"]; @@ -311,12 +322,52 @@ export class WorkflowsList extends BtrixElement {
`, - () => - this.workflows - ? this.workflows.total - ? this.renderWorkflowList() - : this.renderEmptyState() - : this.renderLoading(), + () => html` +
+ ${this.workflows + ? this.workflows.total + ? this.renderWorkflowList() + : this.renderEmptyState() + : this.renderLoading()} +
+ `, + )} + ${this.renderDialogs()} + `; + } + + private renderDialogs() { + return html` + ${when( + this.workflowToDelete, + (workflow) => html` + + ${deleteConfirmation(this.renderName(workflow))} +
+ void this.deleteDialog?.hide()} + >${msg("Cancel")} + { + void this.deleteDialog?.hide(); + + try { + await this.delete(workflow); + this.workflowToDelete = undefined; + } catch { + void this.deleteDialog?.show(); + } + }} + >${msg("Delete Workflow")} +
+
+ `, )} `; } @@ -593,12 +644,16 @@ export class WorkflowsList extends BtrixElement { ${msg("Duplicate Workflow")} ${when( - !workflow.lastCrawlId, + !workflow.crawlCount, () => html` void this.delete(workflow)} + @click=${async () => { + this.workflowToDelete = workflow; + await this.updateComplete; + void this.deleteDialog?.show(); + }} > ${msg("Delete Workflow")} diff --git a/frontend/src/strings/ui.ts b/frontend/src/strings/ui.ts new file mode 100644 index 0000000000..95c560639a --- /dev/null +++ b/frontend/src/strings/ui.ts @@ -0,0 +1,9 @@ +import { msg } from "@lit/localize"; +import { html, type TemplateResult } from "lit"; + +// TODO Refactor all generic confirmation messages to use utility +export const deleteConfirmation = (name: string | TemplateResult) => + msg(html` + Are you sure you want to delete + ${name}? + `);