mirror of
https://github.com/davidkaya/aryx.git
synced 2026-07-30 08:28:48 +02:00
feat: add session branching frontend UI
- Add "Branch from here" hover button on user messages in ChatPane - Wire onBranchFromMessage to api.branchSession IPC call - Show branch origin banner at top of branched session transcripts - Display GitBranch indicator on branched sessions in sidebar - Resolve source session title from workspace for origin display Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -571,6 +571,14 @@ export default function App() {
|
||||
autoApprovedToolNames: settings.autoApprovedToolNames,
|
||||
});
|
||||
}}
|
||||
onBranchFromMessage={(messageId) => {
|
||||
void api.branchSession({ sessionId: selectedSession.id, messageId });
|
||||
}}
|
||||
branchOriginLabel={
|
||||
selectedSession.branchOrigin
|
||||
? workspace.sessions.find((s) => s.id === selectedSession.branchOrigin!.sourceSessionId)?.title
|
||||
: undefined
|
||||
}
|
||||
availableModels={availableModels}
|
||||
mcpProbingServerIds={workspace.mcpProbingServerIds}
|
||||
onTerminalToggle={handleTerminalToggle}
|
||||
|
||||
@@ -64,6 +64,8 @@ interface ChatPaneProps {
|
||||
}) => Promise<unknown>;
|
||||
onUpdateSessionTooling?: (selection: SessionToolingSelection) => void;
|
||||
onUpdateSessionApprovalSettings?: (settings: { autoApprovedToolNames?: string[] }) => void;
|
||||
onBranchFromMessage?: (messageId: string) => void;
|
||||
branchOriginLabel?: string;
|
||||
}
|
||||
|
||||
export function ChatPane({
|
||||
@@ -90,6 +92,8 @@ export function ChatPane({
|
||||
onUpdateSessionModelConfig,
|
||||
onUpdateSessionTooling,
|
||||
onUpdateSessionApprovalSettings,
|
||||
onBranchFromMessage,
|
||||
branchOriginLabel,
|
||||
}: ChatPaneProps) {
|
||||
const [hasComposerContent, setHasComposerContent] = useState(false);
|
||||
const [configError, setConfigError] = useState<string>();
|
||||
@@ -327,6 +331,18 @@ export function ChatPane({
|
||||
</div>
|
||||
) : (
|
||||
<div className="mx-auto max-w-3xl px-6 py-4">
|
||||
{/* Branch origin banner */}
|
||||
{session.branchOrigin && (
|
||||
<div className="mb-4 flex items-center gap-2.5 rounded-lg border border-[var(--color-border-subtle)] bg-[var(--color-surface-1)]/60 px-3.5 py-2.5 text-[12px] text-[var(--color-text-secondary)]">
|
||||
<GitBranch className="size-3.5 shrink-0 text-[var(--color-accent)]" />
|
||||
<span>
|
||||
Branched from{' '}
|
||||
<span className="font-medium text-[var(--color-text-primary)]">
|
||||
{branchOriginLabel ?? 'a previous session'}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="space-y-1">
|
||||
{session.messages.map((message, index) => {
|
||||
const isUser = message.role === 'user';
|
||||
@@ -364,6 +380,17 @@ export function ChatPane({
|
||||
{phaseLabel}
|
||||
</span>
|
||||
)}
|
||||
{isUser && onBranchFromMessage && (
|
||||
<button
|
||||
className="ml-auto flex items-center gap-1 rounded-md px-1.5 py-0.5 text-[11px] text-[var(--color-text-muted)] opacity-0 transition-all duration-150 hover:bg-[var(--color-surface-2)] hover:text-[var(--color-accent)] group-hover:opacity-100"
|
||||
onClick={() => onBranchFromMessage(message.id)}
|
||||
title="Branch from here — create a new session starting from this message"
|
||||
type="button"
|
||||
>
|
||||
<GitBranch className="size-3" />
|
||||
Branch
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className={
|
||||
|
||||
@@ -296,6 +296,11 @@ function SessionItem({
|
||||
Archived
|
||||
</span>
|
||||
)}
|
||||
{session.branchOrigin && (
|
||||
<span className="inline-flex items-center gap-0.5 text-[10px] text-[var(--color-text-muted)]" title="Branched session">
|
||||
<GitBranch className="size-2.5" />
|
||||
</span>
|
||||
)}
|
||||
<span className="ml-auto text-[10px] text-[var(--color-text-muted)] group-hover:text-[var(--color-text-secondary)]">
|
||||
{relativeTime(session.updatedAt)}
|
||||
</span>
|
||||
|
||||
Reference in New Issue
Block a user