diff --git a/frontend/src/components/history/HistoryDisplay.tsx b/frontend/src/components/history/HistoryDisplay.tsx
index db0b74b..615aed8 100644
--- a/frontend/src/components/history/HistoryDisplay.tsx
+++ b/frontend/src/components/history/HistoryDisplay.tsx
@@ -1,4 +1,4 @@
-import { History, HistoryItemType } from "./history_types";
+import { History } from "./history_types";
import toast from "react-hot-toast";
import classNames from "classnames";
import {
@@ -7,6 +7,7 @@ import {
HoverCardContent,
} from "../ui/hover-card";
import { Badge } from "../ui/badge";
+import { renderHistory } from "./utils";
interface Props {
history: History;
@@ -15,32 +16,19 @@ interface Props {
shouldDisableReverts: boolean;
}
-function displayHistoryItemType(itemType: HistoryItemType) {
- switch (itemType) {
- case "ai_create":
- return "Create";
- case "ai_edit":
- return "Edit";
- case "code_create":
- return "Imported from code";
- default: {
- const exhaustiveCheck: never = itemType;
- throw new Error(`Unhandled case: ${exhaustiveCheck}`);
- }
- }
-}
-
export default function HistoryDisplay({
history,
currentVersion,
revertToVersion,
shouldDisableReverts,
}: Props) {
- return history.length === 0 ? null : (
+ const renderedHistory = renderHistory(history, currentVersion);
+
+ return renderedHistory.length === 0 ? null : (
Versions
- {history.map((item, index) => (
+ {renderedHistory.map((item, index) => (
-
@@ -63,32 +50,16 @@ export default function HistoryDisplay({
>
{" "}
-
- {item.type === "ai_edit"
- ? item.inputs.prompt
- : item.type === "ai_create"
- ? "Create"
- : "Imported from code"}
-
- {/* {displayHistoryItemType(item.type)}
*/}
- {item.parentIndex !== null &&
- item.parentIndex !== index - 1 ? (
-
- (parent: v{(item.parentIndex || 0) + 1})
-
- ) : null}
+ {item.summary}
+ {item.parentVersion !== null && (
+ (parent: {item.parentVersion})
+ )}
v{index + 1}
-
- {item.type === "ai_edit"
- ? item.inputs.prompt
- : item.type === "ai_create"
- ? "Create"
- : "Imported from code"}
-
- {displayHistoryItemType(item.type)}
+ {item.summary}
+ {item.type}
diff --git a/frontend/src/components/history/history_types.ts b/frontend/src/components/history/history_types.ts
index 832e379..8dcd219 100644
--- a/frontend/src/components/history/history_types.ts
+++ b/frontend/src/components/history/history_types.ts
@@ -32,3 +32,10 @@ export type CodeCreateInputs = {
};
export type History = HistoryItem[];
+
+export type RenderedHistoryItem = {
+ type: string;
+ summary: string;
+ parentVersion: string | null;
+ isActive: boolean;
+};
diff --git a/frontend/src/components/history/utils.test.ts b/frontend/src/components/history/utils.test.ts
index 2abaf90..330b8e5 100644
--- a/frontend/src/components/history/utils.test.ts
+++ b/frontend/src/components/history/utils.test.ts
@@ -1,5 +1,5 @@
import { expect, test } from "vitest";
-import { extractHistoryTree } from "./utils";
+import { extractHistoryTree, renderHistory } from "./utils";
import type { History } from "./history_types";
const basicLinearHistory: History = [
@@ -29,6 +29,18 @@ const basicLinearHistory: History = [
},
];
+const basicLinearHistoryWithCode: History = [
+ {
+ type: "code_create",
+ parentIndex: null,
+ code: "1. create",
+ inputs: {
+ code: "1. create",
+ },
+ },
+ ...basicLinearHistory.slice(1),
+];
+
const basicBranchingHistory: History = [
...basicLinearHistory,
{
@@ -121,3 +133,98 @@ test("should correctly extract the history tree", () => {
// Bad tree
expect(() => extractHistoryTree(basicBadHistory, 1)).toThrow();
});
+
+test("should correctly render the history tree", () => {
+ expect(renderHistory(basicLinearHistory, 2)).toEqual([
+ {
+ isActive: false,
+ parentVersion: null,
+ summary: "Create",
+ type: "Create",
+ },
+ {
+ isActive: false,
+ parentVersion: null,
+ summary: "use better icons",
+ type: "Edit",
+ },
+ {
+ isActive: true,
+ parentVersion: null,
+ summary: "make text red",
+ type: "Edit",
+ },
+ ]);
+
+ // Current version is the first version
+ expect(renderHistory(basicLinearHistory, 0)).toEqual([
+ {
+ isActive: true,
+ parentVersion: null,
+ summary: "Create",
+ type: "Create",
+ },
+ {
+ isActive: false,
+ parentVersion: null,
+ summary: "use better icons",
+ type: "Edit",
+ },
+ {
+ isActive: false,
+ parentVersion: null,
+ summary: "make text red",
+ type: "Edit",
+ },
+ ]);
+
+ // Render a history with code
+ expect(renderHistory(basicLinearHistoryWithCode, 0)).toEqual([
+ {
+ isActive: true,
+ parentVersion: null,
+ summary: "Imported from code",
+ type: "Imported from code",
+ },
+ {
+ isActive: false,
+ parentVersion: null,
+ summary: "use better icons",
+ type: "Edit",
+ },
+ {
+ isActive: false,
+ parentVersion: null,
+ summary: "make text red",
+ type: "Edit",
+ },
+ ]);
+
+ // Render a non-linear history
+ expect(renderHistory(basicBranchingHistory, 3)).toEqual([
+ {
+ isActive: false,
+ parentVersion: null,
+ summary: "Create",
+ type: "Create",
+ },
+ {
+ isActive: false,
+ parentVersion: null,
+ summary: "use better icons",
+ type: "Edit",
+ },
+ {
+ isActive: false,
+ parentVersion: null,
+ summary: "make text red",
+ type: "Edit",
+ },
+ {
+ isActive: true,
+ parentVersion: "v2",
+ summary: "make text green",
+ type: "Edit",
+ },
+ ]);
+});
diff --git a/frontend/src/components/history/utils.ts b/frontend/src/components/history/utils.ts
index 5e476af..785c20b 100644
--- a/frontend/src/components/history/utils.ts
+++ b/frontend/src/components/history/utils.ts
@@ -1,4 +1,9 @@
-import { History, HistoryItem } from "./history_types";
+import {
+ History,
+ HistoryItem,
+ HistoryItemType,
+ RenderedHistoryItem,
+} from "./history_types";
export function extractHistoryTree(
history: History,
@@ -30,3 +35,62 @@ export function extractHistoryTree(
return flatHistory;
}
+
+function displayHistoryItemType(itemType: HistoryItemType) {
+ switch (itemType) {
+ case "ai_create":
+ return "Create";
+ case "ai_edit":
+ return "Edit";
+ case "code_create":
+ return "Imported from code";
+ default: {
+ const exhaustiveCheck: never = itemType;
+ throw new Error(`Unhandled case: ${exhaustiveCheck}`);
+ }
+ }
+}
+
+function summarizeHistoryItem(item: HistoryItem) {
+ const itemType = item.type;
+ switch (itemType) {
+ case "ai_create":
+ return "Create";
+ case "ai_edit":
+ return item.inputs.prompt;
+ case "code_create":
+ return "Imported from code";
+ default: {
+ const exhaustiveCheck: never = itemType;
+ throw new Error(`Unhandled case: ${exhaustiveCheck}`);
+ }
+ }
+}
+
+export const renderHistory = (
+ history: History,
+ currentVersion: number | null
+) => {
+ const renderedHistory: RenderedHistoryItem[] = [];
+
+ for (let i = 0; i < history.length; i++) {
+ const item = history[i];
+ // Only show the parent version if it's not the previous version
+ // (i.e. it's the branching point) and if it's not the first version
+ const parentVersion =
+ item.parentIndex !== null && item.parentIndex !== i - 1
+ ? `v${(item.parentIndex || 0) + 1}`
+ : null;
+ const type = displayHistoryItemType(item.type);
+ const isActive = i === currentVersion;
+ const summary = summarizeHistoryItem(item);
+ renderedHistory.push({
+ isActive,
+ summary: summary,
+ parentVersion,
+ type,
+ });
+ }
+
+ return renderedHistory;
+};