fix: Allow deleting workflows without any crawls (#2285)
- Uses crawl count to determine whether workflow can be deleted instead of last crawl ID - Display delete confirmation dialog when trying to delete a workflow
This commit is contained in:
parent
1260aec976
commit
6a5e070ffc
@ -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`
|
||||
<div class="grid grid-cols-1 gap-7">
|
||||
<div class="grid grid-cols-1 gap-7 pb-7">
|
||||
${when(this.workflow, this.renderEditor)}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
return html`
|
||||
<div class="grid grid-cols-1 gap-7">
|
||||
<div class="grid grid-cols-1 gap-7 pb-7">
|
||||
<div class="col-span-1">${this.renderBreadcrumbs()}</div>
|
||||
|
||||
<div>
|
||||
@ -355,7 +362,7 @@ export class WorkflowDetail extends BtrixElement {
|
||||
</btrix-dialog>
|
||||
<btrix-dialog
|
||||
.label=${msg("Delete Crawl?")}
|
||||
.open=${this.openDialogName === "delete"}
|
||||
.open=${this.openDialogName === "deleteCrawl"}
|
||||
@sl-request-close=${() => (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() : ""}
|
||||
</btrix-dialog>
|
||||
<btrix-dialog
|
||||
.label=${msg("Delete Workflow?")}
|
||||
.open=${this.openDialogName === "delete"}
|
||||
@sl-request-close=${() => (this.openDialogName = undefined)}
|
||||
@sl-show=${this.showDialog}
|
||||
@sl-after-hide=${() => (this.isDialogVisible = false)}
|
||||
>
|
||||
${deleteConfirmation(this.renderName())}
|
||||
<div slot="footer" class="flex justify-between">
|
||||
<sl-button
|
||||
size="small"
|
||||
.autofocus=${true}
|
||||
@click=${() => (this.openDialogName = undefined)}
|
||||
>${msg("Cancel")}</sl-button
|
||||
>
|
||||
<sl-button
|
||||
size="small"
|
||||
variant="danger"
|
||||
@click=${async () => {
|
||||
void this.delete();
|
||||
this.openDialogName = undefined;
|
||||
}}
|
||||
>${msg("Delete Workflow")}</sl-button
|
||||
>
|
||||
</div>
|
||||
</btrix-dialog>
|
||||
`;
|
||||
}
|
||||
|
||||
@ -736,12 +769,12 @@ export class WorkflowDetail extends BtrixElement {
|
||||
${msg("Duplicate Workflow")}
|
||||
</sl-menu-item>
|
||||
${when(
|
||||
!this.lastCrawlId,
|
||||
!workflow.crawlCount,
|
||||
() => html`
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-item
|
||||
style="--sl-color-neutral-700: var(--danger)"
|
||||
@click=${() => void this.delete()}
|
||||
@click=${() => (this.openDialogName = "delete")}
|
||||
>
|
||||
<sl-icon name="trash3" slot="prefix"></sl-icon>
|
||||
${msg("Delete Workflow")}
|
||||
@ -842,7 +875,7 @@ export class WorkflowDetail extends BtrixElement {
|
||||
|
||||
private renderCrawls() {
|
||||
return html`
|
||||
<section>
|
||||
<section class="h-56 min-h-max">
|
||||
<div
|
||||
class="mb-3 flex items-center justify-end rounded-lg border bg-neutral-50 p-4"
|
||||
>
|
||||
@ -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);
|
||||
|
@ -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 {
|
||||
</btrix-alert>
|
||||
</div>
|
||||
`,
|
||||
() =>
|
||||
this.workflows
|
||||
? this.workflows.total
|
||||
? this.renderWorkflowList()
|
||||
: this.renderEmptyState()
|
||||
: this.renderLoading(),
|
||||
() => html`
|
||||
<div class="pb-10">
|
||||
${this.workflows
|
||||
? this.workflows.total
|
||||
? this.renderWorkflowList()
|
||||
: this.renderEmptyState()
|
||||
: this.renderLoading()}
|
||||
</div>
|
||||
`,
|
||||
)}
|
||||
${this.renderDialogs()}
|
||||
`;
|
||||
}
|
||||
|
||||
private renderDialogs() {
|
||||
return html`
|
||||
${when(
|
||||
this.workflowToDelete,
|
||||
(workflow) => html`
|
||||
<btrix-dialog id="deleteDialog" .label=${msg("Delete Workflow?")}>
|
||||
${deleteConfirmation(this.renderName(workflow))}
|
||||
<div slot="footer" class="flex justify-between">
|
||||
<sl-button
|
||||
size="small"
|
||||
.autofocus=${true}
|
||||
@click=${() => void this.deleteDialog?.hide()}
|
||||
>${msg("Cancel")}</sl-button
|
||||
>
|
||||
<sl-button
|
||||
size="small"
|
||||
variant="danger"
|
||||
@click=${async () => {
|
||||
void this.deleteDialog?.hide();
|
||||
|
||||
try {
|
||||
await this.delete(workflow);
|
||||
this.workflowToDelete = undefined;
|
||||
} catch {
|
||||
void this.deleteDialog?.show();
|
||||
}
|
||||
}}
|
||||
>${msg("Delete Workflow")}</sl-button
|
||||
>
|
||||
</div>
|
||||
</btrix-dialog>
|
||||
`,
|
||||
)}
|
||||
`;
|
||||
}
|
||||
@ -593,12 +644,16 @@ export class WorkflowsList extends BtrixElement {
|
||||
${msg("Duplicate Workflow")}
|
||||
</sl-menu-item>
|
||||
${when(
|
||||
!workflow.lastCrawlId,
|
||||
!workflow.crawlCount,
|
||||
() => html`
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-item
|
||||
style="--sl-color-neutral-700: var(--danger)"
|
||||
@click=${() => void this.delete(workflow)}
|
||||
@click=${async () => {
|
||||
this.workflowToDelete = workflow;
|
||||
await this.updateComplete;
|
||||
void this.deleteDialog?.show();
|
||||
}}
|
||||
>
|
||||
<sl-icon name="trash3" slot="prefix"></sl-icon>
|
||||
${msg("Delete Workflow")}
|
||||
|
9
frontend/src/strings/ui.ts
Normal file
9
frontend/src/strings/ui.ts
Normal file
@ -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
|
||||
<strong class="font-semibold">${name}</strong>?
|
||||
`);
|
Loading…
Reference in New Issue
Block a user