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,17 +1,19 @@ | ||||
| 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 { customElement } from "lit/decorators.js"; | ||||
| 
 | ||||
| /** | ||||
|  * Customized <sl-dialog> | ||||
|  * <sl-dialog> with custom CSS | ||||
|  * | ||||
|  * Usage: see https://shoelace.style/components/dialog
 | ||||
|  */ | ||||
| @customElement("btrix-dialog") | ||||
| export class Dialog extends SLDialog { | ||||
|   static styles = css` | ||||
|     ${dialogStyles} .dialog__panel { | ||||
| export class Dialog extends SlDialog { | ||||
|   static styles = [ | ||||
|     dialogStyles, | ||||
|     css` | ||||
|       .dialog__panel { | ||||
|         overflow: hidden; | ||||
|       } | ||||
| 
 | ||||
| @ -21,14 +23,19 @@ export class Dialog extends SLDialog { | ||||
|       } | ||||
| 
 | ||||
|       .dialog__title { | ||||
|       padding-top: var(--sl-spacing-small); | ||||
|         padding-top: calc(var(--sl-spacing-small) + 0.2rem); | ||||
|         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); | ||||
|         line-height: 1; | ||||
|       } | ||||
| 
 | ||||
|       .dialog__close { | ||||
|       --header-spacing: var(--sl-spacing-2x-small); | ||||
|         --header-spacing: var(--sl-spacing-x-small); | ||||
|       } | ||||
| 
 | ||||
|       .dialog__body { | ||||
|         line-height: var(--sl-line-height-normal); | ||||
|       } | ||||
| 
 | ||||
|       .dialog__footer { | ||||
| @ -36,5 +43,6 @@ export class Dialog extends SLDialog { | ||||
|         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" | ||||
|               href="${this.orgBasePath}/items/upload/${data.id}" | ||||
|               @click="${this.navLink.bind(this)}" | ||||
|               >View Archive</a | ||||
|               >View Item</a | ||||
|             > `),
 | ||||
|           variant: "success", | ||||
|           icon: "check2-circle", | ||||
|  | ||||
| @ -10,7 +10,7 @@ import { CrawlStatus } from "../../components/crawl-status"; | ||||
| import type { PageChangeEvent } from "../../components/pagination"; | ||||
| import type { AuthState } from "../../utils/AuthService"; | ||||
| 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 { | ||||
|   isActive, | ||||
| @ -97,11 +97,17 @@ export class CrawlsList extends LiteElement { | ||||
|   private filterBy: Partial<Record<keyof Crawl, any>> = {}; | ||||
| 
 | ||||
|   @state() | ||||
|   private itemToEdit: Crawl | null = null; | ||||
|   private itemToEdit: Crawl | Upload | null = null; | ||||
| 
 | ||||
|   @state() | ||||
|   private isEditingItem = false; | ||||
| 
 | ||||
|   @state() | ||||
|   private itemToDelete: Crawl | Upload | null = null; | ||||
| 
 | ||||
|   @state() | ||||
|   private isDeletingItem = false; | ||||
| 
 | ||||
|   @state() | ||||
|   private isUploadingArchive = false; | ||||
| 
 | ||||
| @ -439,6 +445,38 @@ export class CrawlsList extends LiteElement { | ||||
|           /* TODO fetch current page or single crawl */ this.fetchArchivedItems | ||||
|         } | ||||
|       ></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-menu-item | ||||
|             style="--sl-color-neutral-700: var(--danger)" | ||||
|             @click=${() => this.deleteItem(item)} | ||||
|             @click=${() => this.confirmDeleteItem(item)} | ||||
|           > | ||||
|             <sl-icon name="trash3" slot="prefix"></sl-icon> | ||||
|             ${msg("Delete Item")} | ||||
| @ -658,13 +696,12 @@ export class CrawlsList extends LiteElement { | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private async deleteItem(item: Crawl) { | ||||
|     if ( | ||||
|       !window.confirm(msg(str`Are you sure you want to delete ${item.name}?`)) | ||||
|     ) { | ||||
|       return; | ||||
|     } | ||||
|   private confirmDeleteItem = (item: Crawl | Upload) => { | ||||
|     this.itemToDelete = item; | ||||
|     this.isDeletingItem = true; | ||||
|   }; | ||||
| 
 | ||||
|   private async deleteItem(item: Crawl | Upload) { | ||||
|     let apiPath; | ||||
| 
 | ||||
|     switch (this.itemType) { | ||||
| @ -691,6 +728,7 @@ export class CrawlsList extends LiteElement { | ||||
|         } | ||||
|       ); | ||||
|       const { items, ...crawlsData } = this.archivedItems!; | ||||
|       this.itemToDelete = null; | ||||
|       this.archivedItems = { | ||||
|         ...crawlsData, | ||||
|         items: items.filter((c) => c.id !== item.id), | ||||
| @ -702,6 +740,9 @@ export class CrawlsList extends LiteElement { | ||||
|       }); | ||||
|       this.fetchArchivedItems(); | ||||
|     } catch (e: any) { | ||||
|       if (this.itemToDelete) { | ||||
|         this.confirmDeleteItem(this.itemToDelete); | ||||
|       } | ||||
|       let message = msg( | ||||
|         str`Sorry, couldn't delete archived item at this time.` | ||||
|       ); | ||||
|  | ||||
| @ -64,7 +64,7 @@ export class WorkflowDetail extends LiteElement { | ||||
|   isCrawler!: boolean; | ||||
| 
 | ||||
|   @property({ type: String }) | ||||
|   openDialogName?: "scale" | "exclusions" | "cancel" | "stop"; | ||||
|   openDialogName?: "scale" | "exclusions" | "cancel" | "stop" | "delete"; | ||||
| 
 | ||||
|   @property({ type: String }) | ||||
|   initialActivePanel?: Tab; | ||||
| @ -107,6 +107,9 @@ export class WorkflowDetail extends LiteElement { | ||||
|   @state() | ||||
|   private isCancelingOrStoppingCrawl: boolean = false; | ||||
| 
 | ||||
|   @state() | ||||
|   private crawlToDelete: Crawl | null = null; | ||||
| 
 | ||||
|   @state() | ||||
|   private filterBy: Partial<Record<keyof Crawl, any>> = {}; | ||||
| 
 | ||||
| @ -321,8 +324,9 @@ export class WorkflowDetail extends LiteElement { | ||||
|         <div slot="footer" class="flex justify-between"> | ||||
|           <sl-button | ||||
|             size="small" | ||||
|             autofocus | ||||
|             @click=${() => (this.openDialogName = undefined)} | ||||
|             >Keep Crawling</sl-button | ||||
|             >${msg("Keep Crawling")}</sl-button | ||||
|           > | ||||
|           <sl-button | ||||
|             size="small" | ||||
| @ -332,7 +336,7 @@ export class WorkflowDetail extends LiteElement { | ||||
|               await this.stop(); | ||||
|               this.openDialogName = undefined; | ||||
|             }} | ||||
|             >Stop Crawling</sl-button | ||||
|             >${msg("Stop Crawling")}</sl-button | ||||
|           > | ||||
|         </div> | ||||
|       </btrix-dialog> | ||||
| @ -349,8 +353,9 @@ export class WorkflowDetail extends LiteElement { | ||||
|         <div slot="footer" class="flex justify-between"> | ||||
|           <sl-button | ||||
|             size="small" | ||||
|             autofocus | ||||
|             @click=${() => (this.openDialogName = undefined)} | ||||
|             >Keep Crawling</sl-button | ||||
|             >${msg("Keep Crawling")}</sl-button | ||||
|           > | ||||
|           <sl-button | ||||
|             size="small" | ||||
| @ -360,7 +365,37 @@ export class WorkflowDetail extends LiteElement { | ||||
|               await this.cancel(); | ||||
|               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> | ||||
|       </btrix-dialog> | ||||
| @ -855,7 +890,7 @@ export class WorkflowDetail extends LiteElement { | ||||
|                     () => html` <sl-menu slot="menu">
 | ||||
|                       <sl-menu-item | ||||
|                         style="--sl-color-neutral-700: var(--danger)" | ||||
|                         @click=${() => this.deleteCrawl(crawl)} | ||||
|                         @click=${() => this.confirmDeleteCrawl(crawl)} | ||||
|                       > | ||||
|                         <sl-icon name="trash3" slot="prefix"></sl-icon> | ||||
|                         ${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) { | ||||
|     try { | ||||
|       const data = await this.apiFetch( | ||||
| @ -1656,6 +1696,7 @@ export class WorkflowDetail extends LiteElement { | ||||
|           }), | ||||
|         } | ||||
|       ); | ||||
|       this.crawlToDelete = null; | ||||
|       this.crawls = { | ||||
|         ...this.crawls!, | ||||
|         items: this.crawls!.items.filter((c) => c.id !== crawl.id), | ||||
| @ -1667,6 +1708,10 @@ export class WorkflowDetail extends LiteElement { | ||||
|       }); | ||||
|       this.fetchCrawls(); | ||||
|     } catch (e: any) { | ||||
|       if (this.crawlToDelete) { | ||||
|         this.confirmDeleteCrawl(this.crawlToDelete); | ||||
|       } | ||||
| 
 | ||||
|       let message = msg( | ||||
|         str`Sorry, couldn't delete archived item at this time.` | ||||
|       ); | ||||
|  | ||||
| @ -23,6 +23,7 @@ const theme = css` | ||||
|     /* Custom font variables */ | ||||
|     --font-monostyle-family: var(--sl-font-mono); | ||||
|     --font-monostyle-variation: "MONO" 0.51, "CASL" 0, "slnt" 0, "CRSV" 0; | ||||
|     --font-size-base: 1rem; | ||||
| 
 | ||||
|     /* | ||||
|      * Shoelace Theme Tokens | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user