diff --git a/ui/src/components/documents/DocumentReviewRail.test.tsx b/ui/src/components/documents/DocumentReviewRail.test.tsx index 96b4ce0e356..fb27531612b 100644 --- a/ui/src/components/documents/DocumentReviewRail.test.tsx +++ b/ui/src/components/documents/DocumentReviewRail.test.tsx @@ -246,7 +246,8 @@ describe("DocumentReviewRail", () => { expect(container.textContent).toContain("Orphaned feedback (1)"); }); - it("disables Done reviewing for read-only viewers", async () => { + it("keeps Done reviewing keyboard-focusable but inert for read-only viewers", async () => { + const onDoneReviewing = vi.fn(); await act(() => root.render( { canReview={false} canFinishReview={false} latestRevisionId="rev-1" + doneReviewingDisabledReason="You don't have edit access" + onDoneReviewing={onDoneReviewing} {...baseHandlers} />, ), ); const done = container.querySelector('[data-testid="rail-done-reviewing"]'); - expect(done?.disabled).toBe(true); + // aria-disabled (not the `disabled` attribute) so it stays in the tab order and can + // surface the tooltip explaining *why* it's disabled to keyboard / screen-reader users. + expect(done?.getAttribute("aria-disabled")).toBe("true"); + expect(done?.hasAttribute("disabled")).toBe(false); + // ...but clicking it must not fire the handoff. + await act(() => done!.click()); + expect(onDoneReviewing).not.toHaveBeenCalled(); + }); + + it("fires the Done reviewing handler when the viewer can finish review", async () => { + const onDoneReviewing = vi.fn(); + await act(() => + root.render( + , + ), + ); + const done = container.querySelector('[data-testid="rail-done-reviewing"]'); + expect(done?.getAttribute("aria-disabled")).toBeNull(); + await act(() => done!.click()); + expect(onDoneReviewing).toHaveBeenCalledTimes(1); }); }); diff --git a/ui/src/components/documents/DocumentReviewRail.tsx b/ui/src/components/documents/DocumentReviewRail.tsx index e1a0449485c..ecf118e2869 100644 --- a/ui/src/components/documents/DocumentReviewRail.tsx +++ b/ui/src/components/documents/DocumentReviewRail.tsx @@ -388,19 +388,29 @@ function ReviewRailBody({
- - - + {/* + Use aria-disabled (not the `disabled` attribute) so the button stays + in the tab order and remains the tooltip trigger: keyboard and screen-reader + users can focus it to learn *why* it's disabled, instead of hitting a dead + control. onClick is guarded so the action can't fire while disabled. + */} + {!canFinishReview ? ( diff --git a/ui/src/components/documents/DoneReviewingDialog.tsx b/ui/src/components/documents/DoneReviewingDialog.tsx index 5dff1da0953..90f66df50c1 100644 --- a/ui/src/components/documents/DoneReviewingDialog.tsx +++ b/ui/src/components/documents/DoneReviewingDialog.tsx @@ -93,7 +93,7 @@ export function DoneReviewingDialog({ Done reviewing - Hand the document back to its owner with an optional note and a real wake. + Hand the document back to its owner with an optional note. We'll notify them so they pick the review back up. @@ -171,6 +171,7 @@ export function DoneReviewingDialog({ variant="ghost" onClick={() => onOpenChange(false)} disabled={submitting} + title="Close this dialog without notifying the owner" data-testid="done-reviewing-just-close" > Just close