From 79128e3d82bafc290422cd21c75c952ddafa3f5f Mon Sep 17 00:00:00 2001 From: jacoblee93 Date: Wed, 20 Mar 2024 16:23:27 -0700 Subject: [PATCH] WIP: Time travel to previous states of a thread --- frontend/src/components/Timeline.tsx | 59 ++++++++++++++++++++++++++++ frontend/src/hooks/useHistories.ts | 41 +++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 frontend/src/components/Timeline.tsx create mode 100644 frontend/src/hooks/useHistories.ts diff --git a/frontend/src/components/Timeline.tsx b/frontend/src/components/Timeline.tsx new file mode 100644 index 00000000..1d4796e8 --- /dev/null +++ b/frontend/src/components/Timeline.tsx @@ -0,0 +1,59 @@ +import { useState } from "react"; +import { Slider } from "@mui/material"; +import { + ChevronLeftIcon, + ChevronRightIcon, + ClockIcon, +} from "@heroicons/react/24/outline"; +import { cn } from "../utils/cn"; +import { History } from "../hooks/useHistories"; + +export function Timeline(props: { + disabled: boolean; + histories: History[]; + activeHistoryIndex: number; + onChange?: (newValue: number) => void; +}) { + const [expanded, setExpanded] = useState(false); + return ( +
+ + props.onChange?.((e.target as any).value)} + valueLabelDisplay="auto" + step={1} + marks + min={0} + max={props.histories.length - 1} + /> + {expanded ? ( + setExpanded((expanded) => !expanded)} + /> + ) : ( + setExpanded((expanded) => !expanded)} + /> + )} +
+ ); +} diff --git a/frontend/src/hooks/useHistories.ts b/frontend/src/hooks/useHistories.ts new file mode 100644 index 00000000..d011e415 --- /dev/null +++ b/frontend/src/hooks/useHistories.ts @@ -0,0 +1,41 @@ +import { useEffect, useState } from "react"; +import { Message } from "../types"; +import { StreamState } from "./useStreamState"; + +async function getHistories(threadId: string) { + const response = await fetch(`/threads/${threadId}/history`, { + headers: { + Accept: "application/json", + }, + }).then((r) => r.json()); + return response; +} + +export interface History { + values: Message[]; + next: string[]; + config: Record; +} + +export function useHistories( + threadId: string | null, + stream: StreamState | null, +): { + histories: History[]; + setHistories: React.Dispatch>; +} { + const [histories, setHistories] = useState([]); + + useEffect(() => { + async function fetchHistories() { + if (threadId) { + const histories = await getHistories(threadId); + setHistories(histories); + } + } + fetchHistories(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [threadId, stream?.status]); + + return { histories, setHistories }; +}