Prevent duplicate planning-history rows and keep deletions visible only after the backend confirms persistence. - dedupe Planning Mode history by session id across initial loads, live updates, archive toggles, and draft creation - make deleteAiSession surface backend/content-type errors instead of silently succeeding on failed deletes - keep failed history deletions visible, refresh the list, and show an error toast when persistence fails - add dashboard tests covering session deduplication, delete API failures, and persistence-aware Planning Mode deletion behavior - document the history dedupe/delete semantics and add a patch changeset for @runfusion/fusion Files changed: .changeset/fn-5892-planning-history-fix.md | 5 + docs/dashboard-guide.md | 2 +- packages/dashboard/app/api/__tests__/deleteAiSession.test.ts | 54 +++++ packages/dashboard/app/api/legacy.ts | 41 +++- packages/dashboard/app/components/PlanningModeModal.tsx | 70 ++++--- packages/dashboard/app/components/__tests__/PlanningModeModal.autosize.test.tsx | 11 + packages/dashboard/app/components/__tests__/PlanningModeModal.dedupeSessionsById.test.ts | 44 ++++ packages/dashboard/app/components/__tests__/PlanningModeModal.initial.test.tsx | 11 + packages/dashboard/app/components/__tests__/PlanningModeModal.planning-flow.test.tsx | 226 ++++++++++++++++++++- packages/dashboard/app/components/__tests__/PlanningModeModal.test-helpers.ts | 1 + 10 files changed, 439 insertions(+), 26 deletions(-) Fusion-Task-Id: FN-5892 Fusion-Task-Lineage: 7453bc34-6d57-4d67-ac92-8fb50084fbee
45 lines
1.5 KiB
TypeScript
45 lines
1.5 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import type { AiSessionSummary } from "../../api";
|
|
import { dedupeSessionsById } from "../PlanningModeModal";
|
|
|
|
function makeSession(id: string, updatedAt: string, title = id): AiSessionSummary {
|
|
return {
|
|
id,
|
|
type: "planning",
|
|
status: "complete",
|
|
title,
|
|
projectId: null,
|
|
lockedByTab: null,
|
|
updatedAt,
|
|
archived: false,
|
|
};
|
|
}
|
|
|
|
describe("dedupeSessionsById", () => {
|
|
it("keeps the most recently updated session for duplicate ids", () => {
|
|
const sessions = [
|
|
makeSession("session-1", "2026-01-01T00:00:00.000Z", "older"),
|
|
makeSession("session-2", "2026-01-03T00:00:00.000Z", "second"),
|
|
makeSession("session-1", "2026-01-04T00:00:00.000Z", "newer"),
|
|
];
|
|
|
|
expect(dedupeSessionsById(sessions)).toEqual([
|
|
makeSession("session-1", "2026-01-04T00:00:00.000Z", "newer"),
|
|
makeSession("session-2", "2026-01-03T00:00:00.000Z", "second"),
|
|
]);
|
|
});
|
|
|
|
it("preserves stable newest-first ordering when timestamps tie", () => {
|
|
const sessions = [
|
|
makeSession("session-a", "2026-01-02T00:00:00.000Z", "first"),
|
|
makeSession("session-b", "2026-01-02T00:00:00.000Z", "second"),
|
|
makeSession("session-a", "2026-01-02T00:00:00.000Z", "ignored duplicate"),
|
|
];
|
|
|
|
expect(dedupeSessionsById(sessions)).toEqual([
|
|
makeSession("session-a", "2026-01-02T00:00:00.000Z", "first"),
|
|
makeSession("session-b", "2026-01-02T00:00:00.000Z", "second"),
|
|
]);
|
|
});
|
|
});
|