diff --git a/frontend/package.json b/frontend/package.json
index 4652dc7..0d454b0 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -36,6 +36,7 @@
"codemirror": "^6.0.1",
"copy-to-clipboard": "^3.3.3",
"html2canvas": "^1.4.1",
+ "nanoid": "^5.0.7",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-dropzone": "^14.2.3",
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 048426c..4ec5c6f 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -8,8 +8,7 @@ import { OnboardingNote } from "./components/messages/OnboardingNote";
import { usePersistedState } from "./hooks/usePersistedState";
import TermsOfServiceDialog from "./components/TermsOfServiceDialog";
import { USER_CLOSE_WEB_SOCKET_CODE } from "./constants";
-import { History } from "./components/history/history_types";
-import { extractHistoryTree } from "./components/history/utils";
+import { extractHistory } from "./components/history/utils";
import toast from "react-hot-toast";
import { Stack } from "./lib/stacks";
import { CodeGenerationModel } from "./lib/models";
@@ -23,6 +22,7 @@ import DeprecationMessage from "./components/messages/DeprecationMessage";
import { GenerationSettings } from "./components/settings/GenerationSettings";
import StartPane from "./components/start-pane/StartPane";
import { takeScreenshot } from "./lib/takeScreenshot";
+import { Commit, createCommit } from "./components/history/history_types";
function App() {
const {
@@ -34,18 +34,18 @@ function App() {
referenceImages,
setReferenceImages,
+ head,
+ commits,
+ addCommit,
+ removeCommit,
+ setHead,
+ appendCommitCode,
+ setCommitCode,
+ resetCommits,
+
// Outputs
- setGeneratedCode,
- currentVariantIndex,
- setVariant,
- appendToVariant,
- resetVariants,
appendExecutionConsole,
resetExecutionConsoles,
- currentVersion,
- setCurrentVersion,
- appHistory,
- setAppHistory,
} = useProjectStore();
const {
@@ -113,34 +113,30 @@ function App() {
setShouldIncludeResultImage(false);
setUpdateInstruction("");
disableInSelectAndEditMode();
- setGeneratedCode("");
- resetVariants();
resetExecutionConsoles();
+ resetCommits();
+
// Inputs
setInputMode("image");
setReferenceImages([]);
setIsImportedFromCode(false);
-
- setAppHistory([]);
- setCurrentVersion(null);
};
const regenerate = () => {
- if (currentVersion === null) {
+ // TODO: post to Sentry
+ if (head === null) {
toast.error(
"No current version set. Please open a Github issue as this shouldn't happen."
);
return;
}
-
// Retrieve the previous command
- const previousCommand = appHistory[currentVersion];
- if (previousCommand.type !== "ai_create") {
+ const currentCommit = commits[head];
+ if (currentCommit.type !== "ai_create") {
toast.error("Only the first version can be regenerated.");
return;
}
-
// Re-run the create
doCreate(referenceImages, inputMode);
};
@@ -149,25 +145,32 @@ function App() {
const cancelCodeGeneration = () => {
wsRef.current?.close?.(USER_CLOSE_WEB_SOCKET_CODE);
// make sure stop can correct the state even if the websocket is already closed
- cancelCodeGenerationAndReset();
+ // TODO: Look into this
+ // cancelCodeGenerationAndReset();
};
// Used for code generation failure as well
- const cancelCodeGenerationAndReset = () => {
- // When this is the first version, reset the entire app state
- if (currentVersion === null) {
+ const cancelCodeGenerationAndReset = (commit: Commit) => {
+ // When the current commit is the first version, reset the entire app state
+ if (commit.type === "ai_create") {
reset();
} else {
- // Otherwise, revert to the last version
- setGeneratedCode(appHistory[currentVersion].code);
+ // Otherwise, remove current commit from commits
+ removeCommit(commit.hash);
+
+ // Revert to parent commit
+ const parentCommitHash = commit.parentHash;
+ if (parentCommitHash) {
+ setHead(parentCommitHash);
+ } else {
+ // TODO: Hit Sentry
+ }
+
setAppState(AppState.CODE_READY);
}
};
- function doGenerateCode(
- params: CodeGenerationParams,
- parentVersion: number | null
- ) {
+ function doGenerateCode(params: CodeGenerationParams) {
// Reset the execution console
resetExecutionConsoles();
@@ -177,69 +180,51 @@ function App() {
// Merge settings with params
const updatedParams = { ...params, ...settings };
+ const baseCommitObject = {
+ date_created: new Date(),
+ variants: [{ code: "" }, { code: "" }],
+ selectedVariantIndex: 0,
+ };
+
+ const commitInputObject =
+ params.generationType === "create"
+ ? {
+ ...baseCommitObject,
+ type: "ai_create" as const,
+ parentHash: null,
+ inputs: { image_url: referenceImages[0] },
+ }
+ : {
+ ...baseCommitObject,
+ type: "ai_edit" as const,
+ parentHash: head,
+ inputs: {
+ prompt: params.history
+ ? params.history[params.history.length - 1]
+ : "",
+ },
+ };
+
+ const commit = createCommit(commitInputObject);
+ addCommit(commit);
+ setHead(commit.hash);
+
generateCode(
wsRef,
updatedParams,
// On change
(token, variant) => {
- if (variant === currentVariantIndex) {
- setGeneratedCode((prev) => prev + token);
- }
-
- appendToVariant(token, variant);
+ appendCommitCode(commit.hash, variant, token);
},
// On set code
(code, variant) => {
- if (variant === currentVariantIndex) {
- setGeneratedCode(code);
- }
-
- setVariant(code, variant);
-
- // TODO: How to deal with variants?
- if (params.generationType === "create") {
- setAppHistory([
- {
- type: "ai_create",
- parentIndex: null,
- code,
- inputs: { image_url: referenceImages[0] },
- },
- ]);
- setCurrentVersion(0);
- } else {
- setAppHistory((prev) => {
- // Validate parent version
- if (parentVersion === null) {
- toast.error(
- "No parent version set. Contact support or open a Github issue."
- );
- return prev;
- }
-
- const newHistory: History = [
- ...prev,
- {
- type: "ai_edit",
- parentIndex: parentVersion,
- code,
- inputs: {
- prompt: params.history
- ? params.history[params.history.length - 1]
- : "", // History should never be empty when performing an edit
- },
- },
- ];
- setCurrentVersion(newHistory.length - 1);
- return newHistory;
- });
- }
+ setCommitCode(commit.hash, variant, code);
},
// On status update
(line, variant) => appendExecutionConsole(variant, line),
// On cancel
() => {
- cancelCodeGenerationAndReset();
+ cancelCodeGenerationAndReset(commit);
},
// On complete
() => {
@@ -259,14 +244,11 @@ function App() {
// Kick off the code generation
if (referenceImages.length > 0) {
- doGenerateCode(
- {
- generationType: "create",
- image: referenceImages[0],
- inputMode,
- },
- currentVersion
- );
+ doGenerateCode({
+ generationType: "create",
+ image: referenceImages[0],
+ inputMode,
+ });
}
}
@@ -280,16 +262,17 @@ function App() {
return;
}
- if (currentVersion === null) {
- toast.error(
- "No current version set. Contact support or open a Github issue."
- );
- return;
- }
+ // if (currentVersion === null) {
+ // toast.error(
+ // "No current version set. Contact support or open a Github issue."
+ // );
+ // return;
+ // }
let historyTree;
try {
- historyTree = extractHistoryTree(appHistory, currentVersion);
+ // TODO: Fix head being null
+ historyTree = extractHistory(head || "", commits);
} catch {
toast.error(
"Version history is invalid. This shouldn't happen. Please contact support or open a Github issue."
@@ -309,34 +292,28 @@ function App() {
const updatedHistory = [...historyTree, modifiedUpdateInstruction];
+ console.log(updatedHistory);
+
if (shouldIncludeResultImage) {
const resultImage = await takeScreenshot();
- doGenerateCode(
- {
- generationType: "update",
- inputMode,
- image: referenceImages[0],
- resultImage: resultImage,
- history: updatedHistory,
- isImportedFromCode,
- },
- currentVersion
- );
+ doGenerateCode({
+ generationType: "update",
+ inputMode,
+ image: referenceImages[0],
+ resultImage: resultImage,
+ history: updatedHistory,
+ isImportedFromCode,
+ });
} else {
- doGenerateCode(
- {
- generationType: "update",
- inputMode,
- image: referenceImages[0],
- history: updatedHistory,
- isImportedFromCode,
- },
- currentVersion
- );
+ doGenerateCode({
+ generationType: "update",
+ inputMode,
+ image: referenceImages[0],
+ history: updatedHistory,
+ isImportedFromCode,
+ });
}
- setGeneratedCode("");
- resetVariants();
setUpdateInstruction("");
}
@@ -358,18 +335,27 @@ function App() {
// Set input state
setIsImportedFromCode(true);
+ console.log(code);
+
// Set up this project
- setGeneratedCode(code);
+ // TODO*
+ // setGeneratedCode(code);
setStack(stack);
- setAppHistory([
- {
- type: "code_create",
- parentIndex: null,
- code,
- inputs: { code },
- },
- ]);
- setCurrentVersion(0);
+ // setAppHistory([
+ // {
+ // type: "code_create",
+ // parentIndex: null,
+ // code,
+ // inputs: { code },
+ // },
+ // ]);
+ // setVariant(0, {
+ // type: "code_create",
+ // parentIndex: null,
+ // code,
+ // });
+ // setCurrentVariantIndex(0);
+ // setCurrentVersion(0);
// Set the app state
setAppState(AppState.CODE_READY);
diff --git a/frontend/src/components/history/HistoryDisplay.tsx b/frontend/src/components/history/HistoryDisplay.tsx
index a3dcdb1..5b81f22 100644
--- a/frontend/src/components/history/HistoryDisplay.tsx
+++ b/frontend/src/components/history/HistoryDisplay.tsx
@@ -2,7 +2,7 @@ import toast from "react-hot-toast";
import classNames from "classnames";
import { Badge } from "../ui/badge";
-import { renderHistory } from "./utils";
+import { summarizeHistoryItem } from "./utils";
import {
Collapsible,
CollapsibleContent,
@@ -17,25 +17,58 @@ interface Props {
}
export default function HistoryDisplay({ shouldDisableReverts }: Props) {
- const {
- appHistory: history,
- currentVersion,
- setCurrentVersion,
- setGeneratedCode,
- } = useProjectStore();
- const renderedHistory = renderHistory(history, currentVersion);
+ const { commits, head, setHead } = useProjectStore();
- const revertToVersion = (index: number) => {
- if (index < 0 || index >= history.length || !history[index]) return;
- setCurrentVersion(index);
- setGeneratedCode(history[index].code);
+ // TODO: Clean this up
+
+ const newHistory = Object.values(commits).flatMap((commit) => {
+ if (commit.type === "ai_create" || commit.type === "ai_edit") {
+ return {
+ type: commit.type,
+ hash: commit.hash,
+ summary: summarizeHistoryItem(commit),
+ parentHash: commit.parentHash,
+ code: commit.variants[commit.selectedVariantIndex].code,
+ inputs: commit.inputs,
+ date_created: commit.date_created,
+ };
+ }
+ return [];
+ });
+
+ // Sort by date created
+ newHistory.sort(
+ (a, b) =>
+ new Date(a.date_created).getTime() - new Date(b.date_created).getTime()
+ );
+
+ const setParentVersion = (
+ parentHash: string | null,
+ currentHash: string | null
+ ) => {
+ if (!parentHash) return null;
+ const parentIndex = newHistory.findIndex(
+ (item) => item.hash === parentHash
+ );
+ const currentIndex = newHistory.findIndex(
+ (item) => item.hash === currentHash
+ );
+ return parentIndex !== -1 && parentIndex != currentIndex - 1
+ ? parentIndex + 1
+ : null;
};
- return renderedHistory.length === 0 ? null : (
+ // Update newHistory to include the parent version
+ const updatedHistory = newHistory.map((item) => ({
+ ...item,
+ parentVersion: setParentVersion(item.parentHash, item.hash),
+ }));
+
+ return updatedHistory.length === 0 ? null : (
Versions
- {renderedHistory.map((item, index) => (
+ {updatedHistory.map((item, index) => (
-
@@ -55,14 +88,14 @@ export default function HistoryDisplay({ shouldDisableReverts }: Props) {
? toast.error(
"Please wait for code generation to complete before viewing an older version."
)
- : revertToVersion(index)
+ : setHead(item.hash)
}
>
{item.summary}
{item.parentVersion !== null && (
- (parent: {item.parentVersion})
+ (parent: v{item.parentVersion})
)}
diff --git a/frontend/src/components/history/history_types.ts b/frontend/src/components/history/history_types.ts
index 8dcd219..183b1b6 100644
--- a/frontend/src/components/history/history_types.ts
+++ b/frontend/src/components/history/history_types.ts
@@ -1,37 +1,44 @@
-export type HistoryItemType = "ai_create" | "ai_edit" | "code_create";
+export type CommitType = "ai_create" | "ai_edit" | "code_create";
-type CommonHistoryItem = {
- parentIndex: null | number;
+export type CommitHash = string;
+
+export type Variant = {
code: string;
};
-export type HistoryItem =
- | ({
- type: "ai_create";
- inputs: AiCreateInputs;
- } & CommonHistoryItem)
- | ({
- type: "ai_edit";
- inputs: AiEditInputs;
- } & CommonHistoryItem)
- | ({
- type: "code_create";
- inputs: CodeCreateInputs;
- } & CommonHistoryItem);
-
-export type AiCreateInputs = {
- image_url: string;
+export type BaseCommit = {
+ hash: CommitHash;
+ parentHash: CommitHash | null;
+ date_created: Date;
+ variants: Variant[];
+ selectedVariantIndex: number;
};
-export type AiEditInputs = {
- prompt: string;
+import { nanoid } from "nanoid";
+
+// TODO: Move to a different file
+export function createCommit(
+ commit: Omit
| Omit
+): Commit {
+ const hash = nanoid();
+ return { ...commit, hash };
+}
+
+export type AiCreateCommit = BaseCommit & {
+ type: "ai_create";
+ inputs: {
+ image_url: string;
+ };
};
-export type CodeCreateInputs = {
- code: string;
+export type AiEditCommit = BaseCommit & {
+ type: "ai_edit";
+ inputs: {
+ prompt: string;
+ };
};
-export type History = HistoryItem[];
+export type Commit = AiCreateCommit | AiEditCommit;
export type RenderedHistoryItem = {
type: string;
diff --git a/frontend/src/components/history/utils.test.ts b/frontend/src/components/history/utils.test.ts
index e321bdc..f70d2bc 100644
--- a/frontend/src/components/history/utils.test.ts
+++ b/frontend/src/components/history/utils.test.ts
@@ -1,231 +1,231 @@
-import { extractHistoryTree, renderHistory } from "./utils";
-import type { History } from "./history_types";
+// import { extractHistoryTree, renderHistory } from "./utils";
+// import type { History } from "./history_types";
-const basicLinearHistory: History = [
- {
- type: "ai_create",
- parentIndex: null,
- code: "1. create",
- inputs: {
- image_url: "",
- },
- },
- {
- type: "ai_edit",
- parentIndex: 0,
- code: "2. edit with better icons",
- inputs: {
- prompt: "use better icons",
- },
- },
- {
- type: "ai_edit",
- parentIndex: 1,
- code: "3. edit with better icons and red text",
- inputs: {
- prompt: "make text red",
- },
- },
-];
+// const basicLinearHistory: History = [
+// {
+// type: "ai_create",
+// parentIndex: null,
+// code: "1. create",
+// inputs: {
+// image_url: "",
+// },
+// },
+// {
+// type: "ai_edit",
+// parentIndex: 0,
+// code: "2. edit with better icons",
+// inputs: {
+// prompt: "use better icons",
+// },
+// },
+// {
+// type: "ai_edit",
+// parentIndex: 1,
+// code: "3. edit with better icons and red text",
+// inputs: {
+// prompt: "make text red",
+// },
+// },
+// ];
-const basicLinearHistoryWithCode: History = [
- {
- type: "code_create",
- parentIndex: null,
- code: "1. create",
- inputs: {
- code: "1. create",
- },
- },
- ...basicLinearHistory.slice(1),
-];
+// const basicLinearHistoryWithCode: History = [
+// {
+// type: "code_create",
+// parentIndex: null,
+// code: "1. create",
+// inputs: {
+// code: "1. create",
+// },
+// },
+// ...basicLinearHistory.slice(1),
+// ];
-const basicBranchingHistory: History = [
- ...basicLinearHistory,
- {
- type: "ai_edit",
- parentIndex: 1,
- code: "4. edit with better icons and green text",
- inputs: {
- prompt: "make text green",
- },
- },
-];
+// const basicBranchingHistory: History = [
+// ...basicLinearHistory,
+// {
+// type: "ai_edit",
+// parentIndex: 1,
+// code: "4. edit with better icons and green text",
+// inputs: {
+// prompt: "make text green",
+// },
+// },
+// ];
-const longerBranchingHistory: History = [
- ...basicBranchingHistory,
- {
- type: "ai_edit",
- parentIndex: 3,
- code: "5. edit with better icons and green, bold text",
- inputs: {
- prompt: "make text bold",
- },
- },
-];
+// const longerBranchingHistory: History = [
+// ...basicBranchingHistory,
+// {
+// type: "ai_edit",
+// parentIndex: 3,
+// code: "5. edit with better icons and green, bold text",
+// inputs: {
+// prompt: "make text bold",
+// },
+// },
+// ];
-const basicBadHistory: History = [
- {
- type: "ai_create",
- parentIndex: null,
- code: "1. create",
- inputs: {
- image_url: "",
- },
- },
- {
- type: "ai_edit",
- parentIndex: 2, // <- Bad parent index
- code: "2. edit with better icons",
- inputs: {
- prompt: "use better icons",
- },
- },
-];
+// const basicBadHistory: History = [
+// {
+// type: "ai_create",
+// parentIndex: null,
+// code: "1. create",
+// inputs: {
+// image_url: "",
+// },
+// },
+// {
+// type: "ai_edit",
+// parentIndex: 2, // <- Bad parent index
+// code: "2. edit with better icons",
+// inputs: {
+// prompt: "use better icons",
+// },
+// },
+// ];
-describe("History Utils", () => {
- test("should correctly extract the history tree", () => {
- expect(extractHistoryTree(basicLinearHistory, 2)).toEqual([
- "1. create",
- "use better icons",
- "2. edit with better icons",
- "make text red",
- "3. edit with better icons and red text",
- ]);
+// describe("History Utils", () => {
+// test("should correctly extract the history tree", () => {
+// expect(extractHistoryTree(basicLinearHistory, 2)).toEqual([
+// "1. create",
+// "use better icons",
+// "2. edit with better icons",
+// "make text red",
+// "3. edit with better icons and red text",
+// ]);
- expect(extractHistoryTree(basicLinearHistory, 0)).toEqual([
- "1. create",
- ]);
+// expect(extractHistoryTree(basicLinearHistory, 0)).toEqual([
+// "1. create",
+// ]);
- // Test branching
- expect(extractHistoryTree(basicBranchingHistory, 3)).toEqual([
- "1. create",
- "use better icons",
- "2. edit with better icons",
- "make text green",
- "4. edit with better icons and green text",
- ]);
+// // Test branching
+// expect(extractHistoryTree(basicBranchingHistory, 3)).toEqual([
+// "1. create",
+// "use better icons",
+// "2. edit with better icons",
+// "make text green",
+// "4. edit with better icons and green text",
+// ]);
- expect(extractHistoryTree(longerBranchingHistory, 4)).toEqual([
- "1. create",
- "use better icons",
- "2. edit with better icons",
- "make text green",
- "4. edit with better icons and green text",
- "make text bold",
- "5. edit with better icons and green, bold text",
- ]);
+// expect(extractHistoryTree(longerBranchingHistory, 4)).toEqual([
+// "1. create",
+// "use better icons",
+// "2. edit with better icons",
+// "make text green",
+// "4. edit with better icons and green text",
+// "make text bold",
+// "5. edit with better icons and green, bold text",
+// ]);
- expect(extractHistoryTree(longerBranchingHistory, 2)).toEqual([
- "1. create",
- "use better icons",
- "2. edit with better icons",
- "make text red",
- "3. edit with better icons and red text",
- ]);
+// expect(extractHistoryTree(longerBranchingHistory, 2)).toEqual([
+// "1. create",
+// "use better icons",
+// "2. edit with better icons",
+// "make text red",
+// "3. edit with better icons and red text",
+// ]);
- // Errors
+// // Errors
- // Bad index
- expect(() => extractHistoryTree(basicLinearHistory, 100)).toThrow();
- expect(() => extractHistoryTree(basicLinearHistory, -2)).toThrow();
+// // Bad index
+// expect(() => extractHistoryTree(basicLinearHistory, 100)).toThrow();
+// expect(() => extractHistoryTree(basicLinearHistory, -2)).toThrow();
- // Bad tree
- expect(() => extractHistoryTree(basicBadHistory, 1)).toThrow();
- });
+// // 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",
- },
- ]);
+// 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",
- },
- ]);
+// // 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 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",
- },
- ]);
- });
-});
+// // 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 785c20b..e442925 100644
--- a/frontend/src/components/history/utils.ts
+++ b/frontend/src/components/history/utils.ts
@@ -1,33 +1,29 @@
-import {
- History,
- HistoryItem,
- HistoryItemType,
- RenderedHistoryItem,
-} from "./history_types";
+import { Commit, CommitHash } from "./history_types";
-export function extractHistoryTree(
- history: History,
- version: number
+export function extractHistory(
+ hash: CommitHash,
+ commits: Record
): string[] {
const flatHistory: string[] = [];
- let currentIndex: number | null = version;
- while (currentIndex !== null) {
- const item: HistoryItem = history[currentIndex];
+ let currentCommitHash: CommitHash | null = hash;
+ while (currentCommitHash !== null) {
+ const commit: Commit = commits[currentCommitHash];
- if (item) {
- if (item.type === "ai_create") {
+ if (commit) {
+ if (commit.type === "ai_create") {
// Don't include the image for ai_create
- flatHistory.unshift(item.code);
- } else if (item.type === "ai_edit") {
- flatHistory.unshift(item.code);
- flatHistory.unshift(item.inputs.prompt);
- } else if (item.type === "code_create") {
- flatHistory.unshift(item.code);
+ flatHistory.unshift(commit.variants[commit.selectedVariantIndex].code);
+ } else if (commit.type === "ai_edit") {
+ flatHistory.unshift(commit.variants[commit.selectedVariantIndex].code);
+ flatHistory.unshift(commit.inputs.prompt);
}
+ // } else if (item.type === "code_create") {
+ // flatHistory.unshift(item.code);
+ // }
// Move to the parent of the current item
- currentIndex = item.parentIndex;
+ currentCommitHash = commit.parentHash;
} else {
throw new Error("Malformed history: missing parent index");
}
@@ -36,61 +32,16 @@ export function extractHistoryTree(
return flatHistory;
}
-function displayHistoryItemType(itemType: HistoryItemType) {
- switch (itemType) {
+export function summarizeHistoryItem(commit: Commit) {
+ const commitType = commit.type;
+ switch (commitType) {
case "ai_create":
return "Create";
case "ai_edit":
- return "Edit";
- case "code_create":
- return "Imported from code";
+ return commit.inputs.prompt;
default: {
- const exhaustiveCheck: never = itemType;
+ const exhaustiveCheck: never = commitType;
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;
-};
diff --git a/frontend/src/components/preview/PreviewPane.tsx b/frontend/src/components/preview/PreviewPane.tsx
index bc4c1cf..83ee182 100644
--- a/frontend/src/components/preview/PreviewPane.tsx
+++ b/frontend/src/components/preview/PreviewPane.tsx
@@ -23,12 +23,17 @@ interface Props {
function PreviewPane({ doUpdate, reset, settings }: Props) {
const { appState } = useAppStore();
- const { inputMode, generatedCode, setGeneratedCode } = useProjectStore();
+ const { inputMode, head, commits } = useProjectStore();
+
+ const currentCommit = head && commits[head] ? commits[head] : "";
+ const currentCode = currentCommit
+ ? currentCommit.variants[currentCommit.selectedVariantIndex].code
+ : "";
const previewCode =
inputMode === "video" && appState === AppState.CODING
- ? extractHtml(generatedCode)
- : generatedCode;
+ ? extractHtml(currentCode)
+ : currentCode;
return (
@@ -45,7 +50,7 @@ function PreviewPane({ doUpdate, reset, settings }: Props) {
Reset
-
+