diff options
| author | Adam <[email protected]> | 2026-03-11 16:34:48 -0500 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-03-11 21:34:48 +0000 |
| commit | fbd9b7cf4fb27433a066a10a197c7edb420336d1 (patch) | |
| tree | 39697e059b99369f370682a0f68da037adfe1016 /packages/ui/src/components/message-part.tsx | |
| parent | 58f45ae22b0faeba4a98910b0d3b42146846462b (diff) | |
| download | opencode-fbd9b7cf4fb27433a066a10a197c7edb420336d1.tar.gz opencode-fbd9b7cf4fb27433a066a10a197c7edb420336d1.zip | |
feat(app): restore to message and fork session (#17092)
Diffstat (limited to 'packages/ui/src/components/message-part.tsx')
| -rw-r--r-- | packages/ui/src/components/message-part.tsx | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/packages/ui/src/components/message-part.tsx b/packages/ui/src/components/message-part.tsx index 65b6229d6..1a50ed48c 100644 --- a/packages/ui/src/components/message-part.tsx +++ b/packages/ui/src/components/message-part.tsx @@ -129,12 +129,20 @@ function DiagnosticsDisplay(props: { diagnostics: Diagnostic[] }): JSX.Element { export interface MessageProps { message: MessageType parts: PartType[] + actions?: UserActions showAssistantCopyPartID?: string | null interrupted?: boolean queued?: boolean showReasoningSummaries?: boolean } +export type SessionAction = (input: { sessionID: string; messageID: string }) => Promise<void> | void + +export type UserActions = { + fork?: SessionAction + revert?: SessionAction +} + export interface MessagePartProps { part: PartType message: MessageType @@ -676,6 +684,7 @@ export function Message(props: MessageProps) { <UserMessageDisplay message={userMessage() as UserMessage} parts={props.parts} + actions={props.actions} interrupted={props.interrupted} queued={props.queued} /> @@ -872,6 +881,7 @@ function ContextToolGroup(props: { parts: ToolPart[]; busy?: boolean }) { export function UserMessageDisplay(props: { message: UserMessage parts: PartType[] + actions?: UserActions interrupted?: boolean queued?: boolean }) { @@ -879,6 +889,7 @@ export function UserMessageDisplay(props: { const dialog = useDialog() const i18n = useI18n() const [copied, setCopied] = createSignal(false) + const [busy, setBusy] = createSignal<"fork" | "revert" | undefined>() const textPart = createMemo( () => props.parts?.find((p) => p.type === "text" && !(p as TextPart).synthetic) as TextPart | undefined, @@ -945,6 +956,22 @@ export function UserMessageDisplay(props: { setTimeout(() => setCopied(false), 2000) } + const run = (kind: "fork" | "revert") => { + const act = kind === "fork" ? props.actions?.fork : props.actions?.revert + if (!act || busy()) return + setBusy(kind) + void Promise.resolve() + .then(() => + act({ + sessionID: props.message.sessionID, + messageID: props.message.id, + }), + ) + .finally(() => { + if (busy() === kind) setBusy(undefined) + }) + } + return ( <div data-component="user-message" data-interrupted={props.interrupted ? "" : undefined}> <Show when={attachments().length > 0}> @@ -1012,6 +1039,38 @@ export function UserMessageDisplay(props: { </Show> </span> </Show> + <Show when={props.actions?.fork}> + <Tooltip value={i18n.t("ui.message.forkMessage")} placement="top" gutter={4}> + <IconButton + icon="fork" + size="normal" + variant="ghost" + disabled={!!busy()} + onMouseDown={(e) => e.preventDefault()} + onClick={(event) => { + event.stopPropagation() + run("fork") + }} + aria-label={i18n.t("ui.message.forkMessage")} + /> + </Tooltip> + </Show> + <Show when={props.actions?.revert}> + <Tooltip value={i18n.t("ui.message.revertMessage")} placement="top" gutter={4}> + <IconButton + icon="reset" + size="normal" + variant="ghost" + disabled={!!busy()} + onMouseDown={(e) => e.preventDefault()} + onClick={(event) => { + event.stopPropagation() + run("revert") + }} + aria-label={i18n.t("ui.message.revertMessage")} + /> + </Tooltip> + </Show> <Tooltip value={copied() ? i18n.t("ui.message.copied") : i18n.t("ui.message.copyMessage")} placement="top" |
