From 084fdd6ee477f640b25902fe9befb9966cbe8aa2 Mon Sep 17 00:00:00 2001 From: nil-err Date: Tue, 28 Jul 2026 23:31:09 +0800 Subject: [PATCH] feat(dashboard): add writable terminal action --- src/dashboard/web/i18n.ts | 4 ++ src/dashboard/web/sessions-kanban.tsx | 12 +++++- src/dashboard/web/sessions-page.tsx | 57 ++++++++++++--------------- src/dashboard/web/style.css | 4 +- test/dashboard-sessions-ui.test.ts | 21 ++++++++++ 5 files changed, 63 insertions(+), 35 deletions(-) diff --git a/src/dashboard/web/i18n.ts b/src/dashboard/web/i18n.ts index b2d848b63..41f170889 100644 --- a/src/dashboard/web/i18n.ts +++ b/src/dashboard/web/i18n.ts @@ -317,6 +317,8 @@ const zh: DashboardMessages = { 'sessions.locating': '发送中...', 'sessions.cooldown': '冷却 {seconds}s', 'sessions.openTerminal': '终端', + 'sessions.openReadonlyTerminal': '打开只读终端', + 'sessions.openWritableTerminal': '打开可操作 Web 终端', 'sessions.writeLink': '操作链接', 'sessions.writeLinkHint': '获取可操作终端链接(带写权限 token,新标签打开)', 'sessions.writeLinkFail': '获取操作链接失败', @@ -2315,6 +2317,8 @@ const en: DashboardMessages = { 'sessions.locating': 'Sending...', 'sessions.cooldown': 'Cooldown {seconds}s', 'sessions.openTerminal': 'Terminal', + 'sessions.openReadonlyTerminal': 'Open read-only terminal', + 'sessions.openWritableTerminal': 'Open interactive web terminal', 'sessions.writeLink': 'Write Link', 'sessions.writeLinkHint': 'Get a writable terminal link (carries a write-access token; opens in a new tab)', 'sessions.writeLinkFail': 'Failed to get write link', diff --git a/src/dashboard/web/sessions-kanban.tsx b/src/dashboard/web/sessions-kanban.tsx index e417a6992..1d0ada3da 100644 --- a/src/dashboard/web/sessions-kanban.tsx +++ b/src/dashboard/web/sessions-kanban.tsx @@ -45,6 +45,7 @@ export interface SessionsKanbanIcons { details: string; feishu: string; history: string; + key: string; lock: string; restart: string; terminal: string; @@ -79,6 +80,7 @@ export interface SessionsKanbanCallbacks { onNeedTeamBoard: (team: SessionsKanbanTeam) => void; onNeedTeams: () => void; onOpenTerminal?: (row: any) => void; + onOpenWritableTerminal?: (row: any, button: HTMLButtonElement) => void; onRename: (row: any, title: string) => void; onRestart: (row: any, button: HTMLButtonElement) => void; onTeamScope: (scope: { chats: number; sessions: number } | null) => void; @@ -431,10 +433,18 @@ function KanbanCard(props: { callbacks.onOpenTerminal?.(row)} /> ) : null} + {row.webPort && callbacks.onOpenWritableTerminal ? ( + callbacks.onOpenWritableTerminal?.(row, button)} + /> + ) : null} {row.feishuChatLink ? ( - {readOnly ? ( - event.stopPropagation()} - dangerouslySetInnerHTML={rawHtml(ICON.terminal)} - /> - ) : ( + + event.stopPropagation()} + dangerouslySetInnerHTML={rawHtml(ICON.terminal)} + /> + {canOpenWritable ? (