fix(webapp): stabilize time-sensitive UI renders

This commit is contained in:
Chris Arderne
2026-08-19 17:36:31 +01:00
parent d1fc356fef
commit 310d459128
3 changed files with 27 additions and 18 deletions
@@ -49,6 +49,7 @@ export function DashboardAgentHeader({
onClose: () => void;
}) {
const [isHistoryOpen, setHistoryOpen] = useState(false);
const [historyOpenedAt, setHistoryOpenedAt] = useState<number | null>(null);
const [pendingDelete, setPendingDelete] = useState<DashboardAgentChat | null>(null);
return (
@@ -57,7 +58,10 @@ export function DashboardAgentHeader({
open={isHistoryOpen}
onOpenChange={(open) => {
setHistoryOpen(open);
if (open) onOpenHistory();
if (open) {
setHistoryOpenedAt(Date.now());
onOpenHistory();
}
}}
>
<PopoverArrowTrigger
@@ -74,19 +78,22 @@ export function DashboardAgentHeader({
className="w-72 max-w-(--radix-popover-content-available-width) p-0"
align="start"
>
<DashboardAgentHistoryMenu
chats={chats}
currentChatId={currentChatId}
thinkingChatId={thinkingChatId}
onSelect={(chatId) => {
setHistoryOpen(false);
onSelectChat(chatId);
}}
onRequestDelete={(chat) => {
setHistoryOpen(false);
setPendingDelete(chat);
}}
/>
{historyOpenedAt === null ? null : (
<DashboardAgentHistoryMenu
chats={chats}
currentChatId={currentChatId}
thinkingChatId={thinkingChatId}
now={historyOpenedAt}
onSelect={(chatId) => {
setHistoryOpen(false);
onSelectChat(chatId);
}}
onRequestDelete={(chat) => {
setHistoryOpen(false);
setPendingDelete(chat);
}}
/>
)}
</PopoverContent>
</Popover>
@@ -80,17 +80,17 @@ export function DashboardAgentHistoryMenu({
chats,
currentChatId,
thinkingChatId,
now,
onSelect,
onRequestDelete,
}: {
chats: DashboardAgentChat[];
currentChatId: string;
thinkingChatId?: string | null;
now: number;
onSelect: (chatId: string) => void;
onRequestDelete: (chat: DashboardAgentChat) => void;
}) {
const now = Date.now();
return (
<div className="max-h-80 overflow-y-auto p-1.5 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-surface-control">
{chats.length === 0 ? (
@@ -252,7 +252,9 @@ function CompleteDateTimeWaitpointForm({
const project = useProject();
const environment = useEnvironment();
const timeToComplete = waitpoint.completedAfter.getTime() - Date.now();
// oxlint-disable-next-line react/react-compiler -- This form intentionally snapshots wall-clock time for its deadline UI.
const now = Date.now();
const timeToComplete = waitpoint.completedAfter.getTime() - now;
if (timeToComplete < 0) {
return (
<div className="flex items-center justify-center">
@@ -286,7 +288,7 @@ function CompleteDateTimeWaitpointForm({
<div className="flex items-center gap-1">
<AnimatedHourglassIcon
className="text-dimmed-dimmed size-4"
delay={(waitpoint.completedAfter.getMilliseconds() - Date.now()) / 1000}
delay={(waitpoint.completedAfter.getMilliseconds() - now) / 1000}
/>
<span className="mt-0.5 ">
<LiveCountdown endTime={waitpoint.completedAfter} />