From bca428194db514995d52f02d70bc94ecf4792770 Mon Sep 17 00:00:00 2001 From: NeilJo-GY <43027886+NeilJo-GY@users.noreply.github.com> Date: Wed, 14 Oct 2026 21:33:33 +0800 Subject: [PATCH] Print the screen hourly price on the header button when it would start a bill. --- .../agent-chat/src/ChatComputerControl.tsx | 43 +++++++++++++------ tests/computer-send-boot.test.cjs | 3 ++ 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/packages/agent-chat/src/ChatComputerControl.tsx b/packages/agent-chat/src/ChatComputerControl.tsx index 182f1e5..c9f4e2f 100644 --- a/packages/agent-chat/src/ChatComputerControl.tsx +++ b/packages/agent-chat/src/ChatComputerControl.tsx @@ -13,12 +13,15 @@ function IconMonitor() { ); } -function headerIconStyle(on: boolean): CSSProperties { +function headerIconStyle(on: boolean, wide = false): CSSProperties { return { ...btnGhost, - width: 28, + width: wide ? "auto" : 28, height: 28, - padding: 0, + padding: wide ? "0 8px" : 0, + gap: wide ? 6 : 0, + fontSize: 12, + whiteSpace: "nowrap", display: "inline-flex", alignItems: "center", justifyContent: "center", @@ -27,7 +30,12 @@ function headerIconStyle(on: boolean): CSSProperties { }; } import { chatComputerLabel, extraIndex, type ComputerNameRow } from "./computerLabel"; -import type { ScreenChargeHint } from "./computerSendBoot"; +import { screenAsksBeforeCharge, type ScreenChargeHint } from "./computerSendBoot"; + +const copy = { + en: { screenAt: "Open computer screen · {rate}/hr" }, + zh: { screenAt: "打开电脑屏幕 · {rate} 星币/小时" }, +} as const; type ChatPlace = { place: "agent" | "cloud"; @@ -106,27 +114,34 @@ export function ChatComputerControl({ const label = chatComputerLabel(place.place, place.is_default, nth, locale); const openable = place.place === "cloud" && !!place.computer_id; const on = openable && !!place.computer_id && openScreenIds.includes(place.computer_id); + const row = place.computer_id + ? computers.find((item) => item.computer_id === place.computer_id) + : undefined; + const screen = row?.screen_credits_per_hour ?? place.screen_credits_per_hour ?? undefined; + const hint: ScreenChargeHint = { + status: row?.status ?? place.status, + resumeCreditsPerHour: row?.resume_credits_per_hour ?? place.resume_credits_per_hour, + screenCreditsPerHour: screen, + }; + const t = copy[locale] ?? copy.en; + const asks = openable && !on && screenAsksBeforeCharge(hint) && screen != null; + const caption = asks ? t.screenAt.replace("{rate}", String(screen)) : label; return ( ); } diff --git a/tests/computer-send-boot.test.cjs b/tests/computer-send-boot.test.cjs index 56be8ac..d891ffa 100644 --- a/tests/computer-send-boot.test.cjs +++ b/tests/computer-send-boot.test.cjs @@ -162,6 +162,9 @@ test("the header screen button uses the chat place rates when the list has not l assert.match(panel, /row\?\.screen_credits_per_hour \?\? place\.screen_credits_per_hour/); assert.match(panel, /row\?\.status \?\? place\.status/); assert.match(panel, /row\?\.resume_credits_per_hour \?\? place\.resume_credits_per_hour/); + assert.match(panel, /screenAsksBeforeCharge/); + assert.match(panel, /screenAt: "打开电脑屏幕 · \{rate\} 星币\/小时"/); + assert.match(panel, /asks \? caption : null/); }); test("opening a screen asks when it would raise the hourly rate", () => {