diff --git a/ui/src/components/IssueDocumentsSection.test.tsx b/ui/src/components/IssueDocumentsSection.test.tsx
index 6c3ec8ab66f..9f04df9f433 100644
--- a/ui/src/components/IssueDocumentsSection.test.tsx
+++ b/ui/src/components/IssueDocumentsSection.test.tsx
@@ -414,6 +414,85 @@ describe("IssueDocumentsSection", () => {
queryClient.clear();
});
+ it("returns from a historical preview when fetched history is newer than the document summary", async () => {
+ const staleDocument = createIssueDocument({
+ body: "Original plan body",
+ latestRevisionId: "revision-2",
+ latestRevisionNumber: 2,
+ updatedAt: new Date("2026-03-31T12:00:00.000Z"),
+ });
+ const issue = createIssue();
+ const root = createRoot(container);
+ const queryClient = new QueryClient({
+ defaultOptions: {
+ queries: {
+ retry: false,
+ },
+ mutations: {
+ retry: false,
+ },
+ },
+ });
+
+ mockIssuesApi.listDocuments.mockResolvedValue([staleDocument]);
+ queryClient.setQueryData(
+ queryKeys.issues.documentRevisions(issue.id, "plan"),
+ [
+ createRevision({
+ id: "revision-3",
+ revisionNumber: 3,
+ body: "Current plan body",
+ createdAt: new Date("2026-03-31T12:05:00.000Z"),
+ }),
+ createRevision({
+ id: "revision-2",
+ revisionNumber: 2,
+ body: "Original plan body",
+ createdAt: new Date("2026-03-31T12:00:00.000Z"),
+ }),
+ ],
+ );
+
+ await act(async () => {
+ root.render(
+
+
+ ,
+ );
+ });
+ await flush();
+ await flush();
+
+ expect(container.textContent).toContain("Current plan body");
+
+ const revisionButtons = Array.from(container.querySelectorAll("button"));
+ const historicalRevisionButton = revisionButtons.find((button) => button.textContent?.includes("rev 2"));
+ expect(historicalRevisionButton).toBeTruthy();
+
+ await act(async () => {
+ historicalRevisionButton?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
+ });
+
+ expect(container.textContent).toContain("Viewing revision 2");
+ expect(container.textContent).toContain("Original plan body");
+
+ const currentRevisionButton = Array.from(container.querySelectorAll("button"))
+ .find((button) => button.textContent?.includes("rev 3"));
+ expect(currentRevisionButton).toBeTruthy();
+
+ await act(async () => {
+ currentRevisionButton?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
+ });
+
+ expect(container.textContent).not.toContain("Viewing revision 2");
+ expect(container.textContent).toContain("Current plan body");
+
+ await act(async () => {
+ root.unmount();
+ });
+ queryClient.clear();
+ });
+
it("ignores mount-time editor change noise before a document is actively being edited", async () => {
markdownEditorMockState.emitMountEmptyChange = true;
diff --git a/ui/src/components/IssueDocumentsSection.tsx b/ui/src/components/IssueDocumentsSection.tsx
index fe8b65a11ad..6923befab07 100644
--- a/ui/src/components/IssueDocumentsSection.tsx
+++ b/ui/src/components/IssueDocumentsSection.tsx
@@ -537,13 +537,13 @@ export function IssueDocumentsSection({
}, []);
const previewRevision = useCallback((doc: IssueDocument, revisionId: string) => {
- if (revisionId === doc.latestRevisionId) {
+ const revisionState = deriveDocumentRevisionState(doc, getDocumentRevisions(doc.key));
+ const selectedRevision = revisionState.revisions.find((revision) => revision.id === revisionId);
+ if (!selectedRevision) return;
+ if (selectedRevision.id === revisionState.currentRevision.id) {
returnToLatestRevision(doc.key);
return;
}
- const revisions = getDocumentRevisions(doc.key);
- const selectedRevision = revisions.find((revision) => revision.id === revisionId);
- if (!selectedRevision) return;
if (documentConflict?.key === doc.key || documentHasUnsavedChanges(doc, draft)) {
setError("Save or cancel your local changes before viewing an older revision.");
return;
@@ -788,7 +788,8 @@ export function IssueDocumentsSection({
const activeDraft = draft?.key === doc.key && !draft.isNew ? draft : null;
const activeConflict = documentConflict?.key === doc.key ? documentConflict : null;
const isFolded = foldedDocumentKeys.includes(doc.key);
- const revisionState = deriveDocumentRevisionState(doc, getDocumentRevisions(doc.key));
+ const rawRevisionHistory = getDocumentRevisions(doc.key);
+ const revisionState = deriveDocumentRevisionState(doc, rawRevisionHistory);
const revisionHistory = revisionState.revisions;
const currentRevision = revisionState.currentRevision;
const selectedRevisionId = selectedRevisionIds[doc.key] ?? null;
@@ -848,7 +849,7 @@ export function IssueDocumentsSection({
Revision history
- {revisionMenuOpenKey === doc.key && isFetchingDocumentRevisions && revisionHistory.length === 0 ? (
+ {revisionMenuOpenKey === doc.key && isFetchingDocumentRevisions && rawRevisionHistory.length === 0 ? (
Loading revisions...
) : revisionHistory.length > 0 ? (