Prompt user to confirm workflow crawl deletion (#1401)
- Adds confirmation dialog for workflow crawls - Changes archived item confirmation from default browser dialog to shoelace dialog - Increase dialog title size - Out of scope: Localizes other workflow detail confirmation buttons - Out of scope: Reword missed "Archive" reference in file uploader
This commit is contained in:
		
							parent
							
								
									d64def00c2
								
							
						
					
					
						commit
						006ce5a013
					
				| @ -1,40 +1,48 @@ | |||||||
| import { css } from "lit"; | import { css } from "lit"; | ||||||
| import SLDialog from "@shoelace-style/shoelace/dist/components/dialog/dialog.js"; | import SlDialog from "@shoelace-style/shoelace/dist/components/dialog/dialog.js"; | ||||||
| import dialogStyles from "@shoelace-style/shoelace/dist/components/dialog/dialog.styles.js"; | import dialogStyles from "@shoelace-style/shoelace/dist/components/dialog/dialog.styles.js"; | ||||||
| import { customElement } from "lit/decorators.js"; | import { customElement } from "lit/decorators.js"; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Customized <sl-dialog> |  * <sl-dialog> with custom CSS | ||||||
|  * |  * | ||||||
|  * Usage: see https://shoelace.style/components/dialog
 |  * Usage: see https://shoelace.style/components/dialog
 | ||||||
|  */ |  */ | ||||||
| @customElement("btrix-dialog") | @customElement("btrix-dialog") | ||||||
| export class Dialog extends SLDialog { | export class Dialog extends SlDialog { | ||||||
|   static styles = css` |   static styles = [ | ||||||
|     ${dialogStyles} .dialog__panel { |     dialogStyles, | ||||||
|       overflow: hidden; |     css` | ||||||
|     } |       .dialog__panel { | ||||||
|  |         overflow: hidden; | ||||||
|  |       } | ||||||
| 
 | 
 | ||||||
|     .dialog__header { |       .dialog__header { | ||||||
|       background-color: var(--sl-color-neutral-50); |         background-color: var(--sl-color-neutral-50); | ||||||
|       border-bottom: 1px solid var(--sl-color-neutral-100); |         border-bottom: 1px solid var(--sl-color-neutral-100); | ||||||
|     } |       } | ||||||
| 
 | 
 | ||||||
|     .dialog__title { |       .dialog__title { | ||||||
|       padding-top: var(--sl-spacing-small); |         padding-top: calc(var(--sl-spacing-small) + 0.2rem); | ||||||
|       padding-bottom: var(--sl-spacing-small); |         padding-bottom: var(--sl-spacing-small); | ||||||
|       font-size: var(--sl-font-size-medium); |         font-size: var(--font-size-base); | ||||||
|       font-weight: var(--sl-font-weight-medium); |         font-weight: var(--sl-font-weight-medium); | ||||||
|     } |         line-height: 1; | ||||||
|  |       } | ||||||
| 
 | 
 | ||||||
|     .dialog__close { |       .dialog__close { | ||||||
|       --header-spacing: var(--sl-spacing-2x-small); |         --header-spacing: var(--sl-spacing-x-small); | ||||||
|     } |       } | ||||||
| 
 | 
 | ||||||
|     .dialog__footer { |       .dialog__body { | ||||||
|       padding-top: var(--sl-spacing-small); |         line-height: var(--sl-line-height-normal); | ||||||
|       padding-bottom: var(--sl-spacing-small); |       } | ||||||
|       border-top: 1px solid var(--sl-color-neutral-100); | 
 | ||||||
|     } |       .dialog__footer { | ||||||
|   `;
 |         padding-top: var(--sl-spacing-small); | ||||||
|  |         padding-bottom: var(--sl-spacing-small); | ||||||
|  |         border-top: 1px solid var(--sl-color-neutral-100); | ||||||
|  |       } | ||||||
|  |     `,
 | ||||||
|  |   ]; | ||||||
| } | } | ||||||
|  | |||||||
| @ -454,7 +454,7 @@ export class FileUploader extends LiteElement { | |||||||
|               class="underline hover:no-underline" |               class="underline hover:no-underline" | ||||||
|               href="${this.orgBasePath}/items/upload/${data.id}" |               href="${this.orgBasePath}/items/upload/${data.id}" | ||||||
|               @click="${this.navLink.bind(this)}" |               @click="${this.navLink.bind(this)}" | ||||||
|               >View Archive</a |               >View Item</a | ||||||
|             > `),
 |             > `),
 | ||||||
|           variant: "success", |           variant: "success", | ||||||
|           icon: "check2-circle", |           icon: "check2-circle", | ||||||
|  | |||||||
| @ -10,7 +10,7 @@ import { CrawlStatus } from "../../components/crawl-status"; | |||||||
| import type { PageChangeEvent } from "../../components/pagination"; | import type { PageChangeEvent } from "../../components/pagination"; | ||||||
| import type { AuthState } from "../../utils/AuthService"; | import type { AuthState } from "../../utils/AuthService"; | ||||||
| import LiteElement, { html } from "../../utils/LiteElement"; | import LiteElement, { html } from "../../utils/LiteElement"; | ||||||
| import type { Crawl, CrawlState, Workflow, WorkflowParams } from "./types"; | import type { Crawl, CrawlState, Workflow, Upload } from "./types"; | ||||||
| import type { APIPaginatedList, APIPaginationQuery } from "../../types/api"; | import type { APIPaginatedList, APIPaginationQuery } from "../../types/api"; | ||||||
| import { | import { | ||||||
|   isActive, |   isActive, | ||||||
| @ -97,11 +97,17 @@ export class CrawlsList extends LiteElement { | |||||||
|   private filterBy: Partial<Record<keyof Crawl, any>> = {}; |   private filterBy: Partial<Record<keyof Crawl, any>> = {}; | ||||||
| 
 | 
 | ||||||
|   @state() |   @state() | ||||||
|   private itemToEdit: Crawl | null = null; |   private itemToEdit: Crawl | Upload | null = null; | ||||||
| 
 | 
 | ||||||
|   @state() |   @state() | ||||||
|   private isEditingItem = false; |   private isEditingItem = false; | ||||||
| 
 | 
 | ||||||
|  |   @state() | ||||||
|  |   private itemToDelete: Crawl | Upload | null = null; | ||||||
|  | 
 | ||||||
|  |   @state() | ||||||
|  |   private isDeletingItem = false; | ||||||
|  | 
 | ||||||
|   @state() |   @state() | ||||||
|   private isUploadingArchive = false; |   private isUploadingArchive = false; | ||||||
| 
 | 
 | ||||||
| @ -439,6 +445,38 @@ export class CrawlsList extends LiteElement { | |||||||
|           /* TODO fetch current page or single crawl */ this.fetchArchivedItems |           /* TODO fetch current page or single crawl */ this.fetchArchivedItems | ||||||
|         } |         } | ||||||
|       ></btrix-crawl-metadata-editor> |       ></btrix-crawl-metadata-editor> | ||||||
|  |       <btrix-dialog | ||||||
|  |         label=${msg("Delete Archived Item?")} | ||||||
|  |         ?open=${this.isDeletingItem} | ||||||
|  |         @sl-after-hide=${() => (this.isDeletingItem = false)} | ||||||
|  |       > | ||||||
|  |         ${msg("This item will be removed from any Collection it is a part of.")} | ||||||
|  |         ${when(this.itemToDelete?.type === "crawl", () => | ||||||
|  |           msg( | ||||||
|  |             "All files and logs associated with this item will also be deleted, and the crawl will no longer be visible in its associated Workflow." | ||||||
|  |           ) | ||||||
|  |         )} | ||||||
|  |         <div slot="footer" class="flex justify-between"> | ||||||
|  |           <sl-button size="small" autofocus>${msg("Cancel")}</sl-button> | ||||||
|  |           <sl-button | ||||||
|  |             size="small" | ||||||
|  |             variant="danger" | ||||||
|  |             @click=${async () => { | ||||||
|  |               this.isDeletingItem = false; | ||||||
|  |               if (this.itemToDelete) { | ||||||
|  |                 await this.deleteItem(this.itemToDelete); | ||||||
|  |               } | ||||||
|  |             }} | ||||||
|  |             >${msg( | ||||||
|  |               str`Delete ${ | ||||||
|  |                 this.itemToDelete?.type === "upload" | ||||||
|  |                   ? msg("Upload") | ||||||
|  |                   : msg("Crawl") | ||||||
|  |               }` | ||||||
|  |             )}</sl-button | ||||||
|  |           > | ||||||
|  |         </div> | ||||||
|  |       </btrix-dialog> | ||||||
|     `;
 |     `;
 | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -504,7 +542,7 @@ export class CrawlsList extends LiteElement { | |||||||
|           <sl-divider></sl-divider> |           <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.deleteItem(item)} |             @click=${() => this.confirmDeleteItem(item)} | ||||||
|           > |           > | ||||||
|             <sl-icon name="trash3" slot="prefix"></sl-icon> |             <sl-icon name="trash3" slot="prefix"></sl-icon> | ||||||
|             ${msg("Delete Item")} |             ${msg("Delete Item")} | ||||||
| @ -658,13 +696,12 @@ export class CrawlsList extends LiteElement { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private async deleteItem(item: Crawl) { |   private confirmDeleteItem = (item: Crawl | Upload) => { | ||||||
|     if ( |     this.itemToDelete = item; | ||||||
|       !window.confirm(msg(str`Are you sure you want to delete ${item.name}?`)) |     this.isDeletingItem = true; | ||||||
|     ) { |   }; | ||||||
|       return; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|  |   private async deleteItem(item: Crawl | Upload) { | ||||||
|     let apiPath; |     let apiPath; | ||||||
| 
 | 
 | ||||||
|     switch (this.itemType) { |     switch (this.itemType) { | ||||||
| @ -691,6 +728,7 @@ export class CrawlsList extends LiteElement { | |||||||
|         } |         } | ||||||
|       ); |       ); | ||||||
|       const { items, ...crawlsData } = this.archivedItems!; |       const { items, ...crawlsData } = this.archivedItems!; | ||||||
|  |       this.itemToDelete = null; | ||||||
|       this.archivedItems = { |       this.archivedItems = { | ||||||
|         ...crawlsData, |         ...crawlsData, | ||||||
|         items: items.filter((c) => c.id !== item.id), |         items: items.filter((c) => c.id !== item.id), | ||||||
| @ -702,6 +740,9 @@ export class CrawlsList extends LiteElement { | |||||||
|       }); |       }); | ||||||
|       this.fetchArchivedItems(); |       this.fetchArchivedItems(); | ||||||
|     } catch (e: any) { |     } catch (e: any) { | ||||||
|  |       if (this.itemToDelete) { | ||||||
|  |         this.confirmDeleteItem(this.itemToDelete); | ||||||
|  |       } | ||||||
|       let message = msg( |       let message = msg( | ||||||
|         str`Sorry, couldn't delete archived item at this time.` |         str`Sorry, couldn't delete archived item at this time.` | ||||||
|       ); |       ); | ||||||
|  | |||||||
| @ -64,7 +64,7 @@ export class WorkflowDetail extends LiteElement { | |||||||
|   isCrawler!: boolean; |   isCrawler!: boolean; | ||||||
| 
 | 
 | ||||||
|   @property({ type: String }) |   @property({ type: String }) | ||||||
|   openDialogName?: "scale" | "exclusions" | "cancel" | "stop"; |   openDialogName?: "scale" | "exclusions" | "cancel" | "stop" | "delete"; | ||||||
| 
 | 
 | ||||||
|   @property({ type: String }) |   @property({ type: String }) | ||||||
|   initialActivePanel?: Tab; |   initialActivePanel?: Tab; | ||||||
| @ -107,6 +107,9 @@ export class WorkflowDetail extends LiteElement { | |||||||
|   @state() |   @state() | ||||||
|   private isCancelingOrStoppingCrawl: boolean = false; |   private isCancelingOrStoppingCrawl: boolean = false; | ||||||
| 
 | 
 | ||||||
|  |   @state() | ||||||
|  |   private crawlToDelete: Crawl | null = null; | ||||||
|  | 
 | ||||||
|   @state() |   @state() | ||||||
|   private filterBy: Partial<Record<keyof Crawl, any>> = {}; |   private filterBy: Partial<Record<keyof Crawl, any>> = {}; | ||||||
| 
 | 
 | ||||||
| @ -321,8 +324,9 @@ export class WorkflowDetail extends LiteElement { | |||||||
|         <div slot="footer" class="flex justify-between"> |         <div slot="footer" class="flex justify-between"> | ||||||
|           <sl-button |           <sl-button | ||||||
|             size="small" |             size="small" | ||||||
|  |             autofocus | ||||||
|             @click=${() => (this.openDialogName = undefined)} |             @click=${() => (this.openDialogName = undefined)} | ||||||
|             >Keep Crawling</sl-button |             >${msg("Keep Crawling")}</sl-button | ||||||
|           > |           > | ||||||
|           <sl-button |           <sl-button | ||||||
|             size="small" |             size="small" | ||||||
| @ -332,7 +336,7 @@ export class WorkflowDetail extends LiteElement { | |||||||
|               await this.stop(); |               await this.stop(); | ||||||
|               this.openDialogName = undefined; |               this.openDialogName = undefined; | ||||||
|             }} |             }} | ||||||
|             >Stop Crawling</sl-button |             >${msg("Stop Crawling")}</sl-button | ||||||
|           > |           > | ||||||
|         </div> |         </div> | ||||||
|       </btrix-dialog> |       </btrix-dialog> | ||||||
| @ -349,8 +353,9 @@ export class WorkflowDetail extends LiteElement { | |||||||
|         <div slot="footer" class="flex justify-between"> |         <div slot="footer" class="flex justify-between"> | ||||||
|           <sl-button |           <sl-button | ||||||
|             size="small" |             size="small" | ||||||
|  |             autofocus | ||||||
|             @click=${() => (this.openDialogName = undefined)} |             @click=${() => (this.openDialogName = undefined)} | ||||||
|             >Keep Crawling</sl-button |             >${msg("Keep Crawling")}</sl-button | ||||||
|           > |           > | ||||||
|           <sl-button |           <sl-button | ||||||
|             size="small" |             size="small" | ||||||
| @ -360,7 +365,37 @@ export class WorkflowDetail extends LiteElement { | |||||||
|               await this.cancel(); |               await this.cancel(); | ||||||
|               this.openDialogName = undefined; |               this.openDialogName = undefined; | ||||||
|             }} |             }} | ||||||
|             >Cancel & Discard Crawl</sl-button |             >${msg("Cancel & Discard Crawl")}</sl-button | ||||||
|  |           > | ||||||
|  |         </div> | ||||||
|  |       </btrix-dialog> | ||||||
|  |       <btrix-dialog | ||||||
|  |         label=${msg("Delete Crawl?")} | ||||||
|  |         ?open=${this.openDialogName === "delete"} | ||||||
|  |         @sl-request-close=${() => (this.openDialogName = undefined)} | ||||||
|  |         @sl-show=${this.showDialog} | ||||||
|  |         @sl-after-hide=${() => (this.isDialogVisible = false)} | ||||||
|  |       > | ||||||
|  |         ${msg( | ||||||
|  |           "All files and logs associated with this crawl will also be deleted, and the crawl will be removed from any Collection it is a part of." | ||||||
|  |         )} | ||||||
|  |         <div slot="footer" class="flex justify-between"> | ||||||
|  |           <sl-button | ||||||
|  |             size="small" | ||||||
|  |             autofocus | ||||||
|  |             @click=${() => (this.openDialogName = undefined)} | ||||||
|  |             >${msg("Cancel")}</sl-button | ||||||
|  |           > | ||||||
|  |           <sl-button | ||||||
|  |             size="small" | ||||||
|  |             variant="danger" | ||||||
|  |             @click=${async () => { | ||||||
|  |               this.openDialogName = undefined; | ||||||
|  |               if (this.crawlToDelete) { | ||||||
|  |                 await this.deleteCrawl(this.crawlToDelete); | ||||||
|  |               } | ||||||
|  |             }} | ||||||
|  |             >${msg("Delete Crawl")}</sl-button | ||||||
|           > |           > | ||||||
|         </div> |         </div> | ||||||
|       </btrix-dialog> |       </btrix-dialog> | ||||||
| @ -855,7 +890,7 @@ export class WorkflowDetail extends LiteElement { | |||||||
|                     () => html` <sl-menu slot="menu">
 |                     () => html` <sl-menu slot="menu">
 | ||||||
|                       <sl-menu-item |                       <sl-menu-item | ||||||
|                         style="--sl-color-neutral-700: var(--danger)" |                         style="--sl-color-neutral-700: var(--danger)" | ||||||
|                         @click=${() => this.deleteCrawl(crawl)} |                         @click=${() => this.confirmDeleteCrawl(crawl)} | ||||||
|                       > |                       > | ||||||
|                         <sl-icon name="trash3" slot="prefix"></sl-icon> |                         <sl-icon name="trash3" slot="prefix"></sl-icon> | ||||||
|                         ${msg("Delete Crawl")} |                         ${msg("Delete Crawl")} | ||||||
| @ -1644,6 +1679,11 @@ export class WorkflowDetail extends LiteElement { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   private confirmDeleteCrawl = (crawl: Crawl) => { | ||||||
|  |     this.crawlToDelete = crawl; | ||||||
|  |     this.openDialogName = "delete"; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|   private async deleteCrawl(crawl: Crawl) { |   private async deleteCrawl(crawl: Crawl) { | ||||||
|     try { |     try { | ||||||
|       const data = await this.apiFetch( |       const data = await this.apiFetch( | ||||||
| @ -1656,6 +1696,7 @@ export class WorkflowDetail extends LiteElement { | |||||||
|           }), |           }), | ||||||
|         } |         } | ||||||
|       ); |       ); | ||||||
|  |       this.crawlToDelete = null; | ||||||
|       this.crawls = { |       this.crawls = { | ||||||
|         ...this.crawls!, |         ...this.crawls!, | ||||||
|         items: this.crawls!.items.filter((c) => c.id !== crawl.id), |         items: this.crawls!.items.filter((c) => c.id !== crawl.id), | ||||||
| @ -1667,6 +1708,10 @@ export class WorkflowDetail extends LiteElement { | |||||||
|       }); |       }); | ||||||
|       this.fetchCrawls(); |       this.fetchCrawls(); | ||||||
|     } catch (e: any) { |     } catch (e: any) { | ||||||
|  |       if (this.crawlToDelete) { | ||||||
|  |         this.confirmDeleteCrawl(this.crawlToDelete); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|       let message = msg( |       let message = msg( | ||||||
|         str`Sorry, couldn't delete archived item at this time.` |         str`Sorry, couldn't delete archived item at this time.` | ||||||
|       ); |       ); | ||||||
|  | |||||||
| @ -23,6 +23,7 @@ const theme = css` | |||||||
|     /* Custom font variables */ |     /* Custom font variables */ | ||||||
|     --font-monostyle-family: var(--sl-font-mono); |     --font-monostyle-family: var(--sl-font-mono); | ||||||
|     --font-monostyle-variation: "MONO" 0.51, "CASL" 0, "slnt" 0, "CRSV" 0; |     --font-monostyle-variation: "MONO" 0.51, "CASL" 0, "slnt" 0, "CRSV" 0; | ||||||
|  |     --font-size-base: 1rem; | ||||||
| 
 | 
 | ||||||
|     /* |     /* | ||||||
|      * Shoelace Theme Tokens |      * Shoelace Theme Tokens | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user