Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 29 additions & 6 deletions apps/desktop/src/ui/Rows.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,28 @@ function messageMarkdown(text: string): string {
return slash ? `\`${COMMAND_MARK}${slash.command}\` ${slash.rest}` : text;
}

/**
* A message's Edit and Retry: shown on hover with Copy, and dimmed rather than removed while a
* turn runs (`aria-disabled` keeps the tooltip that says why).
*/
const MESSAGE_ACTION =
"inline-flex size-[22px] items-center justify-center rounded-md text-fg-muted opacity-0 transition-opacity hover:bg-fill hover:text-fg focus-visible:opacity-100 group-hover:opacity-100 aria-disabled:cursor-default aria-disabled:text-fg-faint aria-disabled:hover:bg-transparent aria-disabled:hover:text-fg-faint";

export const UserRow = memo(function UserRow({
item,
threadId,
busy,
rewind,
before,
after,
}: {
item: Item<"user">;
threadId?: string;
/**
* A turn runs: Edit and Retry keep their place but are off until it ends, so the message's
* actions are the same three whether the thread runs or not.
*/
busy?: boolean;
/** Edit and Retry take the thread back to this message (`_rustcode/rewind`). */
rewind?: boolean;
/** The message after this one is the sender's too. */
Expand Down Expand Up @@ -258,24 +271,34 @@ export const UserRow = memo(function UserRow({
<>
<Tooltip
label={
rewind ? "Edit and resend: the thread goes back to this message" : "Edit in the composer"
busy
? "Stop the turn to edit"
: rewind
? "Edit and resend: the thread goes back to this message"
: "Edit in the composer"
}
>
<button
type="button"
aria-label="Edit message"
onClick={() => editMessage(threadId, item.id)}
className="inline-flex size-[22px] items-center justify-center rounded-md text-fg-muted opacity-0 transition-opacity hover:bg-fill hover:text-fg focus-visible:opacity-100 group-hover:opacity-100"
aria-disabled={busy || undefined}
onClick={() => !busy && editMessage(threadId, item.id)}
className={MESSAGE_ACTION}
>
<Pencil size={12} />
</button>
</Tooltip>
<Tooltip label={rewind ? "Retry: send it again from here" : "Send it again"}>
<Tooltip
label={
busy ? "Stop the turn to retry" : rewind ? "Retry: send it again from here" : "Send it again"
}
>
<button
type="button"
aria-label="Retry message"
onClick={() => retryMessage(threadId, item.id)}
className="inline-flex size-[22px] items-center justify-center rounded-md text-fg-muted opacity-0 transition-opacity hover:bg-fill hover:text-fg focus-visible:opacity-100 group-hover:opacity-100"
aria-disabled={busy || undefined}
onClick={() => !busy && retryMessage(threadId, item.id)}
className={MESSAGE_ACTION}
>
<RotateCcw size={12} />
</button>
Expand Down
3 changes: 2 additions & 1 deletion apps/desktop/src/ui/Transcript.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1414,7 +1414,8 @@ export function Transcript({
<SelectableMessage threadId={thread.id}>
<UserRow
item={item}
threadId={thread.running || peek ? undefined : thread.id}
threadId={peek ? undefined : thread.id}
busy={thread.running}
rewind={rewind}
// Consecutive messages from the same side soften the corners they share.
after={rows[v.index - 1]?.item?.kind === "user"}
Expand Down
Loading