diff --git a/frontend/src/features/qa/page-list/ui/page-details.ts b/frontend/src/features/qa/page-list/ui/page-details.ts index d080f398..aa1927c0 100644 --- a/frontend/src/features/qa/page-list/ui/page-details.ts +++ b/frontend/src/features/qa/page-list/ui/page-details.ts @@ -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" > - ${page.notes[page.notes.length - 1]?.text} + ${page.notes[page.notes.length - 1].text} ` : nothing}`; diff --git a/frontend/src/features/qa/page-list/ui/page.ts b/frontend/src/features/qa/page-list/ui/page.ts index c5b48768..0efea3f9 100644 --- a/frontend/src/features/qa/page-list/ui/page.ts +++ b/frontend/src/features/qa/page-list/ui/page.ts @@ -138,8 +138,10 @@ export class QaPage extends TailwindElement { tabindex="0" aria-selected=${this.selected} > - -
${pageDetails(page)}
+ +
+ ${pageDetails(page)} +
diff --git a/frontend/src/pages/org/archived-item-detail/ui/qa.ts b/frontend/src/pages/org/archived-item-detail/ui/qa.ts index 815a928c..e0b000d6 100644 --- a/frontend/src/pages/org/archived-item-detail/ui/qa.ts +++ b/frontend/src/pages/org/archived-item-detail/ui/qa.ts @@ -762,19 +762,31 @@ export class ArchivedItemDetailQA extends TailwindElement { ${this.renderApprovalStatus(page)} - ${page.notes?.length - ? statusWithIcon( - html``, - `${page.notes.length.toLocaleString()} ${pluralOf("comments", page.notes.length)}`, - ) - : html`${msg("None")}`} + + ${page.notes?.length + ? html` + +
+
+ ${msg("Newest comment:")} +
+
+ ${page.notes[page.notes.length - 1].text} +
+
+ ${statusWithIcon( + html``, + `${page.notes.length.toLocaleString()} ${pluralOf("comments", page.notes.length)}`, + )} +
+ ` + : html` + ${msg("None")} + `} +
`, )} diff --git a/frontend/src/pages/org/archived-item-qa/archived-item-qa.ts b/frontend/src/pages/org/archived-item-qa/archived-item-qa.ts index 3d7fd178..8694853a 100644 --- a/frontend/src/pages/org/archived-item-qa/archived-item-qa.ts +++ b/frontend/src/pages/org/archived-item-qa/archived-item-qa.ts @@ -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 { + ${this.renderReviewDialog()} + `; + } + + private renderReviewDialog() { + const { helpText, validate } = this.validateItemDescriptionMax; + return html` -
+
@@ -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} >
`; @@ -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 { 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 }>( diff --git a/frontend/src/theme.stylesheet.css b/frontend/src/theme.stylesheet.css index 42d242a2..1efd27ce 100644 --- a/frontend/src/theme.stylesheet.css +++ b/frontend/src/theme.stylesheet.css @@ -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,