QA review tooltip + comment improvements (#1779)
Resolves https://github.com/webrecorder/browsertrix/issues/1761 <!-- Fixes #issue_number --> ### Changes - Switches QA review page chip tooltip colors to dark text on light background - Shows newest comment when hovering over comment cell in QA tab page list to match tooltip in QA review page list - Validates textarea max entry for description and comments
This commit is contained in:
		
							parent
							
								
									26abbddd62
								
							
						
					
					
						commit
						e7dbf914a3
					
				| @ -98,6 +98,6 @@ export const pageDetails = (page: ArchivedItemQAPage) => | ||||
|               name="chat-square-text-fill" | ||||
|               class="mr-2 h-4 w-4 flex-none text-blue-600" | ||||
|             ></sl-icon> | ||||
|             ${page.notes[page.notes.length - 1]?.text} | ||||
|             ${page.notes[page.notes.length - 1].text} | ||||
|           </div>` | ||||
|       : nothing}`;
 | ||||
|  | ||||
| @ -138,8 +138,10 @@ export class QaPage extends TailwindElement { | ||||
|           tabindex="0" | ||||
|           aria-selected=${this.selected} | ||||
|         > | ||||
|           <sl-tooltip placement="left" hoist> | ||||
|             <div slot="content" class="text-xs">${pageDetails(page)}</div> | ||||
|           <sl-tooltip class="invert-tooltip" placement="left" hoist> | ||||
|             <div slot="content" class="max-w-60 text-xs"> | ||||
|               ${pageDetails(page)} | ||||
|             </div> | ||||
|             <div | ||||
|               class="absolute -left-4 top-[50%] flex w-8 translate-y-[-50%] flex-col place-items-center gap-1 rounded-full border border-gray-300 bg-neutral-0 p-2 leading-[14px] shadow transition-transform hover:scale-110" | ||||
|             > | ||||
|  | ||||
| @ -762,19 +762,31 @@ export class ArchivedItemDetailQA extends TailwindElement { | ||||
|                 <btrix-table-cell | ||||
|                   >${this.renderApprovalStatus(page)}</btrix-table-cell | ||||
|                 > | ||||
|                 <btrix-table-cell | ||||
|                   >${page.notes?.length | ||||
|                     ? statusWithIcon( | ||||
|                         html`<sl-icon
 | ||||
|                           name="chat-square-text-fill" | ||||
|                           class="text-blue-600" | ||||
|                         ></sl-icon>`, | ||||
|                         `${page.notes.length.toLocaleString()} ${pluralOf("comments", page.notes.length)}`, | ||||
|                       ) | ||||
|                     : html`<span class="text-neutral-400"
 | ||||
|                         >${msg("None")}</span | ||||
|                       >`}</btrix-table-cell
 | ||||
|                 > | ||||
|                 <btrix-table-cell> | ||||
|                   ${page.notes?.length | ||||
|                     ? html` | ||||
|                         <sl-tooltip class="invert-tooltip"> | ||||
|                           <div slot="content"> | ||||
|                             <div class="text-xs text-neutral-400"> | ||||
|                               ${msg("Newest comment:")} | ||||
|                             </div> | ||||
|                             <div class="leading04 max-w-60 text-xs"> | ||||
|                               ${page.notes[page.notes.length - 1].text} | ||||
|                             </div> | ||||
|                           </div> | ||||
|                           ${statusWithIcon( | ||||
|                             html`<sl-icon
 | ||||
|                               name="chat-square-text-fill" | ||||
|                               class="text-blue-600" | ||||
|                             ></sl-icon>`, | ||||
|                             `${page.notes.length.toLocaleString()} ${pluralOf("comments", page.notes.length)}`, | ||||
|                           )} | ||||
|                         </sl-tooltip> | ||||
|                       ` | ||||
|                     : html`<span class="text-neutral-400">
 | ||||
|                         ${msg("None")} | ||||
|                       </span>`}
 | ||||
|                 </btrix-table-cell> | ||||
|               </btrix-table-row> | ||||
|             `,
 | ||||
|           )} | ||||
|  | ||||
| @ -43,6 +43,7 @@ import type { ArchivedItem, ArchivedItemPageComment } from "@/types/crawler"; | ||||
| import type { ArchivedItemQAPage, QARun } from "@/types/qa"; | ||||
| import { type AuthState } from "@/utils/AuthService"; | ||||
| import { finishedCrawlStates, isActive, renderName } from "@/utils/crawler"; | ||||
| import { maxLengthValidator } from "@/utils/form"; | ||||
| import { formatISODateString, getLocale } from "@/utils/localization"; | ||||
| 
 | ||||
| const DEFAULT_PAGE_SIZE = 100; | ||||
| @ -158,6 +159,8 @@ export class ArchivedItemQA extends TailwindElement { | ||||
|   private readonly notify = new NotifyController(this); | ||||
|   private readonly replaySwReg = | ||||
|     navigator.serviceWorker.getRegistration("/replay/"); | ||||
|   private readonly validateItemDescriptionMax = maxLengthValidator(500); | ||||
|   private readonly validatePageCommentMax = maxLengthValidator(500); | ||||
| 
 | ||||
|   @query("#replayframe") | ||||
|   private readonly replayFrame?: HTMLIFrameElement | null; | ||||
| @ -581,11 +584,18 @@ export class ArchivedItemQA extends TailwindElement { | ||||
|         </sl-button> | ||||
|       </btrix-dialog> | ||||
| 
 | ||||
|       ${this.renderReviewDialog()} | ||||
|     `;
 | ||||
|   } | ||||
| 
 | ||||
|   private renderReviewDialog() { | ||||
|     const { helpText, validate } = this.validateItemDescriptionMax; | ||||
|     return html` | ||||
|       <btrix-dialog | ||||
|         class="reviewDialog [--width:60rem]" | ||||
|         label=${msg("QA Review")} | ||||
|       > | ||||
|         <form class="qaReviewForm" @submit=${this.onReviewSubmit}> | ||||
|         <form class="qaReviewForm" @submit=${this.onSubmitReview}> | ||||
|           <div class="flex flex-col gap-6 md:flex-row"> | ||||
|             <div> | ||||
|               <sl-radio-group | ||||
| @ -642,7 +652,11 @@ export class ArchivedItemQA extends TailwindElement { | ||||
|                 label=${msg("Update archived item description?")} | ||||
|                 name="description" | ||||
|                 value=${this.item?.description ?? ""} | ||||
|                 placeholder=${msg("No description")} | ||||
|                 placeholder=${msg("No description, yet")} | ||||
|                 rows="10" | ||||
|                 autocomplete="off" | ||||
|                 help-text=${helpText} | ||||
|                 @sl-input=${validate} | ||||
|               ></sl-textarea> | ||||
|             </div> | ||||
|           </div> | ||||
| @ -720,6 +734,7 @@ export class ArchivedItemQA extends TailwindElement { | ||||
|   } | ||||
| 
 | ||||
|   private renderComments() { | ||||
|     const { helpText, validate } = this.validatePageCommentMax; | ||||
|     return html` | ||||
|       ${when( | ||||
|         this.page?.notes?.length, | ||||
| @ -770,8 +785,10 @@ export class ArchivedItemQA extends TailwindElement { | ||||
|           name="pageComment" | ||||
|           label=${msg("Add a comment")} | ||||
|           placeholder=${msg("Enter page feedback")} | ||||
|           minlength="1" | ||||
|           maxlength="500" | ||||
|           rows="4" | ||||
|           autocomplete="off" | ||||
|           help-text=${helpText} | ||||
|           @sl-input=${validate} | ||||
|         ></sl-textarea> | ||||
|       </form> | ||||
|     `;
 | ||||
| @ -941,6 +958,9 @@ export class ArchivedItemQA extends TailwindElement { | ||||
| 
 | ||||
|     if (!value) return; | ||||
| 
 | ||||
|     const formEl = e.target as HTMLFormElement; | ||||
|     if (!(await this.checkFormValidity(formEl))) return; | ||||
| 
 | ||||
|     void this.commentDialog?.hide(); | ||||
| 
 | ||||
|     try { | ||||
| @ -975,6 +995,11 @@ export class ArchivedItemQA extends TailwindElement { | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   async checkFormValidity(formEl: HTMLFormElement) { | ||||
|     await this.updateComplete; | ||||
|     return !formEl.querySelector("[data-invalid]"); | ||||
|   } | ||||
| 
 | ||||
|   private async deletePageComment(commentId: string): Promise<void> { | ||||
|     try { | ||||
|       await this.api.fetch( | ||||
| @ -1293,14 +1318,15 @@ export class ArchivedItemQA extends TailwindElement { | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   private async onReviewSubmit(e: SubmitEvent) { | ||||
|   private async onSubmitReview(e: SubmitEvent) { | ||||
|     e.preventDefault(); | ||||
|     const form = e.currentTarget as HTMLFormElement; | ||||
|     const params = serialize(form); | ||||
| 
 | ||||
|     if (!params.reviewStatus) { | ||||
|       return; | ||||
|     } | ||||
|     if (!params.reviewStatus) return; | ||||
| 
 | ||||
|     const formEl = e.target as HTMLFormElement; | ||||
|     if (!(await this.checkFormValidity(formEl))) return; | ||||
| 
 | ||||
|     try { | ||||
|       const data = await this.api.fetch<{ updated: boolean }>( | ||||
|  | ||||
| @ -196,6 +196,18 @@ | ||||
|     min-width: min-content; | ||||
|   } | ||||
| 
 | ||||
|   /* Style tooltip with white background */ | ||||
|   sl-tooltip.invert-tooltip { | ||||
|     --sl-tooltip-arrow-size: 0; | ||||
|     --sl-tooltip-background-color: var(--sl-color-neutral-0); | ||||
|     --sl-tooltip-color: var(--sl-color-neutral-700); | ||||
|   } | ||||
| 
 | ||||
|   sl-tooltip.invert-tooltip::part(body) { | ||||
|     outline: 1px solid var(--sl-panel-border-color); | ||||
|     box-shadow: var(--sl-shadow-large); | ||||
|   } | ||||
| 
 | ||||
|   /* For single-input forms with submit button inline */ | ||||
|   /* Requires form control and button to be direct children */ | ||||
|   .inline-control-input, | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user