refactor(web): extract ShellPage side panel and computer JSX into components

The side panel header, the computer preview and the full-window computer
overlay were large inline blocks in ShellPage's render.

Move-only: they are now SidePanelHeader, ComputerPanelPreview and
FullscreenComputerOverlay in pages/shell, each with explicit props. The
booting screen, the routine list and the create-bot modal stay where they
are. DOM, classNames, test ids, aria attributes, handlers and messages are
unchanged; the catalogs only update their file references.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u
This commit is contained in:
Claude 2026-10-04 10:06:02 +00:00
parent 3c678519a6
commit 0ab148ba03
No known key found for this signature in database
13 changed files with 542 additions and 385 deletions

View File

@ -141,7 +141,7 @@ msgid "{0}, main conversation"
msgstr "{0}, Hauptunterhaltung"
#. placeholder {0}: active.name
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "{0}'s screen"
msgstr "{0}s Bildschirm"
@ -813,11 +813,11 @@ msgstr "Bot"
msgid "Bot"
msgstr "Bot"
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "Bot screen"
msgstr "Bot-Bildschirm"
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "Bot screen preview"
msgstr "Bot-Bildschirmvorschau"
@ -1089,7 +1089,7 @@ msgstr "Schließen"
msgid "Close chart"
msgstr "Diagramm schließen"
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "Close computer"
msgstr "Computer schließen"
@ -1129,7 +1129,7 @@ msgstr "Navigation schließen"
#: src/components/ArtifactPane.tsx
#: src/components/browser/InAppBrowser.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Close panel"
msgstr "Panel schließen"
@ -1202,7 +1202,7 @@ msgstr "Computer"
msgid "Computer failed to boot"
msgstr "Computer konnte nicht gestartet werden"
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "Computer is asleep"
msgstr "Computer ist im Ruhezustand"
@ -2401,6 +2401,7 @@ msgstr "Ziele für dieses Projekt, unabhängig von Chat-Nachrichten. Unterhaltun
#: src/components/stage/OoStage.tsx
#: src/pages/MessagingSettingsOverlay.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Group"
msgstr "Gruppe"
@ -3098,7 +3099,7 @@ msgstr "Braucht dich"
#: src/components/MainInbox.tsx
#: src/pages/ActivityList.tsx
#: src/pages/HeuteBrief.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
#: src/pages/shell/transcript.tsx
msgid "Needs you"
msgstr "Braucht dich"
@ -3392,7 +3393,7 @@ msgid "Only file and folder names are read."
msgstr "Gelesen werden nur Datei- und Ordnernamen."
#: src/pages/ScratchpadSection.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "Open"
msgstr "Öffnen"
@ -3413,7 +3414,7 @@ msgstr "Unterhaltung öffnen"
msgid "Open in browser"
msgstr "Im Browser öffnen"
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "Open in full window"
msgstr "In vollständigem Fenster öffnen"
@ -4202,7 +4203,7 @@ msgstr "Stimme einrichten"
#: src/pages/MessagingSettingsOverlay.tsx
#: src/pages/SettingsOverlay.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
#: src/pages/shell/user-menu.tsx
msgid "Settings"
msgstr "Einstellungen"
@ -4259,7 +4260,7 @@ msgstr "Alle {0} anzeigen"
msgid "Show bots"
msgstr "Bots anzeigen"
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Show computer"
msgstr "Computer anzeigen"
@ -4275,7 +4276,7 @@ msgstr "Mehr anzeigen"
msgid "Show password"
msgstr "Passwort anzeigen"
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Show settings"
msgstr "Einstellungen anzeigen"
@ -4463,8 +4464,8 @@ msgid "Steps"
msgstr "Schritte"
#: src/components/browser/InAppBrowser.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/composer.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
#: src/pages/shell/transcript.tsx
msgid "Stop"
msgstr "Stoppen"
@ -5091,7 +5092,7 @@ msgstr "Du kannst diesen Tab schließen, wenn du nicht automatisch weitergeleite
msgid "You can close this window."
msgstr "Du kannst dieses Fenster schließen."
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "You have control"
msgstr "Du hast die Kontrolle"

View File

@ -141,7 +141,7 @@ msgid "{0}, main conversation"
msgstr "{0}, main conversation"
#. placeholder {0}: active.name
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "{0}'s screen"
msgstr "{0}'s screen"
@ -813,11 +813,11 @@ msgstr "Bot"
msgid "Bot"
msgstr "Bot"
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "Bot screen"
msgstr "Bot screen"
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "Bot screen preview"
msgstr "Bot screen preview"
@ -1089,7 +1089,7 @@ msgstr "Close"
msgid "Close chart"
msgstr "Close chart"
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "Close computer"
msgstr "Close computer"
@ -1129,7 +1129,7 @@ msgstr "Close navigation"
#: src/components/ArtifactPane.tsx
#: src/components/browser/InAppBrowser.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Close panel"
msgstr "Close panel"
@ -1202,7 +1202,7 @@ msgstr "Computer"
msgid "Computer failed to boot"
msgstr "Computer failed to boot"
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "Computer is asleep"
msgstr "Computer is asleep"
@ -2401,6 +2401,7 @@ msgstr "Goals for this project, separate from chat messages. Conversations are b
#: src/components/stage/OoStage.tsx
#: src/pages/MessagingSettingsOverlay.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Group"
msgstr "Group"
@ -3098,7 +3099,7 @@ msgstr "Needs you"
#: src/components/MainInbox.tsx
#: src/pages/ActivityList.tsx
#: src/pages/HeuteBrief.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
#: src/pages/shell/transcript.tsx
msgid "Needs you"
msgstr "Needs you"
@ -3392,7 +3393,7 @@ msgid "Only file and folder names are read."
msgstr "Only file and folder names are read."
#: src/pages/ScratchpadSection.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "Open"
msgstr "Open"
@ -3413,7 +3414,7 @@ msgstr "Open conversation"
msgid "Open in browser"
msgstr "Open in browser"
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "Open in full window"
msgstr "Open in full window"
@ -4202,7 +4203,7 @@ msgstr "Set up voice"
#: src/pages/MessagingSettingsOverlay.tsx
#: src/pages/SettingsOverlay.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
#: src/pages/shell/user-menu.tsx
msgid "Settings"
msgstr "Settings"
@ -4259,7 +4260,7 @@ msgstr "Show all {0}"
msgid "Show bots"
msgstr "Show bots"
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Show computer"
msgstr "Show computer"
@ -4275,7 +4276,7 @@ msgstr "Show more"
msgid "Show password"
msgstr "Show password"
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Show settings"
msgstr "Show settings"
@ -4463,8 +4464,8 @@ msgid "Steps"
msgstr "Steps"
#: src/components/browser/InAppBrowser.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/composer.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
#: src/pages/shell/transcript.tsx
msgid "Stop"
msgstr "Stop"
@ -5091,7 +5092,7 @@ msgstr "You can close this tab if it does not redirect automatically."
msgid "You can close this window."
msgstr "You can close this window."
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "You have control"
msgstr "You have control"

View File

@ -141,7 +141,7 @@ msgid "{0}, main conversation"
msgstr ""
#. placeholder {0}: active.name
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "{0}'s screen"
msgstr "Pantalla de {0}"
@ -813,11 +813,11 @@ msgstr "Bot"
msgid "Bot"
msgstr "Bot"
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "Bot screen"
msgstr "Pantalla del bot"
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "Bot screen preview"
msgstr "Vista previa de la pantalla del bot"
@ -1089,7 +1089,7 @@ msgstr "Cerrar"
msgid "Close chart"
msgstr "Cerrar gráfico"
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "Close computer"
msgstr "Cerrar computadora"
@ -1129,7 +1129,7 @@ msgstr "Cerrar navegación"
#: src/components/ArtifactPane.tsx
#: src/components/browser/InAppBrowser.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Close panel"
msgstr "Cerrar panel"
@ -1202,7 +1202,7 @@ msgstr "Computadora"
msgid "Computer failed to boot"
msgstr "La computadora no pudo iniciarse"
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "Computer is asleep"
msgstr "La computadora está en reposo"
@ -2401,6 +2401,7 @@ msgstr ""
#: src/components/stage/OoStage.tsx
#: src/pages/MessagingSettingsOverlay.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Group"
msgstr "Grupo"
@ -3098,7 +3099,7 @@ msgstr ""
#: src/components/MainInbox.tsx
#: src/pages/ActivityList.tsx
#: src/pages/HeuteBrief.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
#: src/pages/shell/transcript.tsx
msgid "Needs you"
msgstr ""
@ -3392,7 +3393,7 @@ msgid "Only file and folder names are read."
msgstr ""
#: src/pages/ScratchpadSection.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "Open"
msgstr "Abrir"
@ -3413,7 +3414,7 @@ msgstr ""
msgid "Open in browser"
msgstr ""
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "Open in full window"
msgstr "Abrir en ventana completa"
@ -4202,7 +4203,7 @@ msgstr ""
#: src/pages/MessagingSettingsOverlay.tsx
#: src/pages/SettingsOverlay.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
#: src/pages/shell/user-menu.tsx
msgid "Settings"
msgstr "Configuración"
@ -4259,7 +4260,7 @@ msgstr ""
msgid "Show bots"
msgstr ""
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Show computer"
msgstr ""
@ -4275,7 +4276,7 @@ msgstr "Mostrar más"
msgid "Show password"
msgstr "Mostrar contraseña"
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Show settings"
msgstr "Mostrar configuración"
@ -4463,8 +4464,8 @@ msgid "Steps"
msgstr "Pasos"
#: src/components/browser/InAppBrowser.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/composer.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
#: src/pages/shell/transcript.tsx
msgid "Stop"
msgstr "Detener"
@ -5091,7 +5092,7 @@ msgstr "Puedes cerrar esta pestaña si no redirige automáticamente."
msgid "You can close this window."
msgstr "Puedes cerrar esta ventana."
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "You have control"
msgstr "Tienes el control"

View File

@ -141,7 +141,7 @@ msgid "{0}, main conversation"
msgstr ""
#. placeholder {0}: active.name
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "{0}'s screen"
msgstr ""
@ -813,11 +813,11 @@ msgstr "बॉट"
msgid "Bot"
msgstr "बॉट"
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "Bot screen"
msgstr "बॉट स्क्रीन"
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "Bot screen preview"
msgstr "बॉट स्क्रीन प्रीव्यू"
@ -1089,7 +1089,7 @@ msgstr "बंद करें"
msgid "Close chart"
msgstr "चार्ट बंद करें"
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "Close computer"
msgstr "कंप्यूटर बंद करें"
@ -1129,7 +1129,7 @@ msgstr "नेविगेशन बंद करें"
#: src/components/ArtifactPane.tsx
#: src/components/browser/InAppBrowser.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Close panel"
msgstr "पैनल बंद करें"
@ -1202,7 +1202,7 @@ msgstr "कंप्यूटर"
msgid "Computer failed to boot"
msgstr "कंप्यूटर शुरू नहीं हो सका"
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "Computer is asleep"
msgstr "कंप्यूटर निष्क्रिय है"
@ -2401,6 +2401,7 @@ msgstr ""
#: src/components/stage/OoStage.tsx
#: src/pages/MessagingSettingsOverlay.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Group"
msgstr "समूह"
@ -3098,7 +3099,7 @@ msgstr ""
#: src/components/MainInbox.tsx
#: src/pages/ActivityList.tsx
#: src/pages/HeuteBrief.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
#: src/pages/shell/transcript.tsx
msgid "Needs you"
msgstr ""
@ -3392,7 +3393,7 @@ msgid "Only file and folder names are read."
msgstr ""
#: src/pages/ScratchpadSection.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "Open"
msgstr "खोलें"
@ -3413,7 +3414,7 @@ msgstr ""
msgid "Open in browser"
msgstr ""
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "Open in full window"
msgstr "पूरी विंडो में खोलें"
@ -4202,7 +4203,7 @@ msgstr ""
#: src/pages/MessagingSettingsOverlay.tsx
#: src/pages/SettingsOverlay.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
#: src/pages/shell/user-menu.tsx
msgid "Settings"
msgstr "सेटिंग्स"
@ -4259,7 +4260,7 @@ msgstr ""
msgid "Show bots"
msgstr ""
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Show computer"
msgstr ""
@ -4275,7 +4276,7 @@ msgstr "और दिखाएँ"
msgid "Show password"
msgstr ""
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Show settings"
msgstr "सेटिंग्स दिखाएं"
@ -4463,8 +4464,8 @@ msgid "Steps"
msgstr "चरण"
#: src/components/browser/InAppBrowser.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/composer.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
#: src/pages/shell/transcript.tsx
msgid "Stop"
msgstr "रोकें"
@ -5091,7 +5092,7 @@ msgstr "अगर यह अपने आप रीडायरेक्ट न
msgid "You can close this window."
msgstr "आप यह विंडो बंद कर सकते हैं।"
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "You have control"
msgstr "नियंत्रण आपके पास है"

View File

@ -141,7 +141,7 @@ msgid "{0}, main conversation"
msgstr ""
#. placeholder {0}: active.name
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "{0}'s screen"
msgstr "{0}의 화면"
@ -813,11 +813,11 @@ msgstr "Bot"
msgid "Bot"
msgstr "봇"
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "Bot screen"
msgstr "Bot 화면"
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "Bot screen preview"
msgstr "Bot 화면 미리보기"
@ -1089,7 +1089,7 @@ msgstr "닫기"
msgid "Close chart"
msgstr "차트 닫기"
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "Close computer"
msgstr "컴퓨터 닫기"
@ -1129,7 +1129,7 @@ msgstr "메뉴 닫기"
#: src/components/ArtifactPane.tsx
#: src/components/browser/InAppBrowser.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Close panel"
msgstr "패널 닫기"
@ -1202,7 +1202,7 @@ msgstr "컴퓨터"
msgid "Computer failed to boot"
msgstr "컴퓨터를 시작하지 못했습니다"
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "Computer is asleep"
msgstr "컴퓨터가 절전 상태입니다"
@ -2401,6 +2401,7 @@ msgstr ""
#: src/components/stage/OoStage.tsx
#: src/pages/MessagingSettingsOverlay.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Group"
msgstr "그룹"
@ -3098,7 +3099,7 @@ msgstr ""
#: src/components/MainInbox.tsx
#: src/pages/ActivityList.tsx
#: src/pages/HeuteBrief.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
#: src/pages/shell/transcript.tsx
msgid "Needs you"
msgstr ""
@ -3392,7 +3393,7 @@ msgid "Only file and folder names are read."
msgstr ""
#: src/pages/ScratchpadSection.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "Open"
msgstr "열기"
@ -3413,7 +3414,7 @@ msgstr ""
msgid "Open in browser"
msgstr ""
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "Open in full window"
msgstr "전체 창으로 열기"
@ -4202,7 +4203,7 @@ msgstr ""
#: src/pages/MessagingSettingsOverlay.tsx
#: src/pages/SettingsOverlay.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
#: src/pages/shell/user-menu.tsx
msgid "Settings"
msgstr "설정"
@ -4259,7 +4260,7 @@ msgstr ""
msgid "Show bots"
msgstr ""
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Show computer"
msgstr ""
@ -4275,7 +4276,7 @@ msgstr "더 보기"
msgid "Show password"
msgstr "비밀번호 표시"
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Show settings"
msgstr "설정 보기"
@ -4463,8 +4464,8 @@ msgid "Steps"
msgstr "실행 단계"
#: src/components/browser/InAppBrowser.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/composer.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
#: src/pages/shell/transcript.tsx
msgid "Stop"
msgstr "중지"
@ -5091,7 +5092,7 @@ msgstr "자동으로 이동하지 않으면 이 탭을 닫아도 됩니다."
msgid "You can close this window."
msgstr "이 창을 닫아도 됩니다."
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "You have control"
msgstr "직접 조작 중"

View File

@ -141,7 +141,7 @@ msgid "{0}, main conversation"
msgstr ""
#. placeholder {0}: active.name
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "{0}'s screen"
msgstr ""
@ -813,11 +813,11 @@ msgstr "Bot"
msgid "Bot"
msgstr "Bot"
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "Bot screen"
msgstr "Tela do bot"
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "Bot screen preview"
msgstr "Pré-visualização da tela"
@ -1089,7 +1089,7 @@ msgstr "Fechar"
msgid "Close chart"
msgstr "Fechar gráfico"
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "Close computer"
msgstr "Fechar computador"
@ -1129,7 +1129,7 @@ msgstr "Fechar navegação"
#: src/components/ArtifactPane.tsx
#: src/components/browser/InAppBrowser.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Close panel"
msgstr "Fechar painel"
@ -1202,7 +1202,7 @@ msgstr "Computador"
msgid "Computer failed to boot"
msgstr "Falha ao inicializar o computador"
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "Computer is asleep"
msgstr "O computador está dormindo"
@ -2401,6 +2401,7 @@ msgstr ""
#: src/components/stage/OoStage.tsx
#: src/pages/MessagingSettingsOverlay.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Group"
msgstr "Grupo"
@ -3098,7 +3099,7 @@ msgstr ""
#: src/components/MainInbox.tsx
#: src/pages/ActivityList.tsx
#: src/pages/HeuteBrief.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
#: src/pages/shell/transcript.tsx
msgid "Needs you"
msgstr ""
@ -3392,7 +3393,7 @@ msgid "Only file and folder names are read."
msgstr ""
#: src/pages/ScratchpadSection.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "Open"
msgstr "Abrir"
@ -3413,7 +3414,7 @@ msgstr ""
msgid "Open in browser"
msgstr ""
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "Open in full window"
msgstr "Abrir em janela cheia"
@ -4202,7 +4203,7 @@ msgstr ""
#: src/pages/MessagingSettingsOverlay.tsx
#: src/pages/SettingsOverlay.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
#: src/pages/shell/user-menu.tsx
msgid "Settings"
msgstr "Configurações"
@ -4259,7 +4260,7 @@ msgstr ""
msgid "Show bots"
msgstr ""
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Show computer"
msgstr ""
@ -4275,7 +4276,7 @@ msgstr "Mostrar mais"
msgid "Show password"
msgstr ""
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Show settings"
msgstr "Mostrar configurações"
@ -4463,8 +4464,8 @@ msgid "Steps"
msgstr "Passos"
#: src/components/browser/InAppBrowser.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/composer.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
#: src/pages/shell/transcript.tsx
msgid "Stop"
msgstr "Parar"
@ -5091,7 +5092,7 @@ msgstr "Você pode fechar esta guia se ela não for redirecionada automaticament
msgid "You can close this window."
msgstr "Você pode fechar esta janela."
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "You have control"
msgstr "Você tem o controle"

View File

@ -141,7 +141,7 @@ msgid "{0}, main conversation"
msgstr ""
#. placeholder {0}: active.name
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "{0}'s screen"
msgstr "Экран {0}"
@ -813,11 +813,11 @@ msgstr "Бот"
msgid "Bot"
msgstr "Бот"
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "Bot screen"
msgstr "Экран бота"
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "Bot screen preview"
msgstr "Предварительный просмотр экрана бота"
@ -1089,7 +1089,7 @@ msgstr "Закрыть"
msgid "Close chart"
msgstr "Закрыть график"
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "Close computer"
msgstr "Закрыть компьютер"
@ -1129,7 +1129,7 @@ msgstr "Закрыть навигацию"
#: src/components/ArtifactPane.tsx
#: src/components/browser/InAppBrowser.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Close panel"
msgstr "Закрыть панель"
@ -1202,7 +1202,7 @@ msgstr "Компьютер"
msgid "Computer failed to boot"
msgstr "Компьютер не смог загрузиться"
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "Computer is asleep"
msgstr "Компьютер спит"
@ -2401,6 +2401,7 @@ msgstr ""
#: src/components/stage/OoStage.tsx
#: src/pages/MessagingSettingsOverlay.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Group"
msgstr "Группа"
@ -3098,7 +3099,7 @@ msgstr "Требуется ваше участие"
#: src/components/MainInbox.tsx
#: src/pages/ActivityList.tsx
#: src/pages/HeuteBrief.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
#: src/pages/shell/transcript.tsx
msgid "Needs you"
msgstr "Требуется ваше участие"
@ -3392,7 +3393,7 @@ msgid "Only file and folder names are read."
msgstr ""
#: src/pages/ScratchpadSection.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "Open"
msgstr "Открыть"
@ -3413,7 +3414,7 @@ msgstr ""
msgid "Open in browser"
msgstr ""
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "Open in full window"
msgstr "Открыть в полном окне"
@ -4202,7 +4203,7 @@ msgstr ""
#: src/pages/MessagingSettingsOverlay.tsx
#: src/pages/SettingsOverlay.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
#: src/pages/shell/user-menu.tsx
msgid "Settings"
msgstr "Настройки"
@ -4259,7 +4260,7 @@ msgstr ""
msgid "Show bots"
msgstr "Показать ботов"
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Show computer"
msgstr ""
@ -4275,7 +4276,7 @@ msgstr "Показать ещё"
msgid "Show password"
msgstr "Показать пароль"
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Show settings"
msgstr "Показать настройки"
@ -4463,8 +4464,8 @@ msgid "Steps"
msgstr "Шаги"
#: src/components/browser/InAppBrowser.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/composer.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
#: src/pages/shell/transcript.tsx
msgid "Stop"
msgstr "Остановить"
@ -5091,7 +5092,7 @@ msgstr "Вы можете закрыть эту вкладку, если она
msgid "You can close this window."
msgstr "Вы можете закрыть это окно."
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "You have control"
msgstr "Вы управляете"

View File

@ -141,7 +141,7 @@ msgid "{0}, main conversation"
msgstr ""
#. placeholder {0}: active.name
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "{0}'s screen"
msgstr ""
@ -813,11 +813,11 @@ msgstr "Bot"
msgid "Bot"
msgstr "Bot"
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "Bot screen"
msgstr "Bot ekranı"
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "Bot screen preview"
msgstr "Bot ekranı önizlemesi"
@ -1089,7 +1089,7 @@ msgstr "Kapat"
msgid "Close chart"
msgstr "Grafiği kapat"
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "Close computer"
msgstr "Bilgisayarı kapat"
@ -1129,7 +1129,7 @@ msgstr "Gezinmeyi kapat"
#: src/components/ArtifactPane.tsx
#: src/components/browser/InAppBrowser.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Close panel"
msgstr "Paneli kapat"
@ -1202,7 +1202,7 @@ msgstr "Bilgisayar"
msgid "Computer failed to boot"
msgstr "Bilgisayar başlatılamadı"
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "Computer is asleep"
msgstr "Bilgisayar uykuda"
@ -2401,6 +2401,7 @@ msgstr ""
#: src/components/stage/OoStage.tsx
#: src/pages/MessagingSettingsOverlay.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Group"
msgstr "Grup"
@ -3098,7 +3099,7 @@ msgstr ""
#: src/components/MainInbox.tsx
#: src/pages/ActivityList.tsx
#: src/pages/HeuteBrief.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
#: src/pages/shell/transcript.tsx
msgid "Needs you"
msgstr ""
@ -3392,7 +3393,7 @@ msgid "Only file and folder names are read."
msgstr ""
#: src/pages/ScratchpadSection.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "Open"
msgstr "Aç"
@ -3413,7 +3414,7 @@ msgstr ""
msgid "Open in browser"
msgstr ""
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "Open in full window"
msgstr "Tam pencerede aç"
@ -4202,7 +4203,7 @@ msgstr ""
#: src/pages/MessagingSettingsOverlay.tsx
#: src/pages/SettingsOverlay.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
#: src/pages/shell/user-menu.tsx
msgid "Settings"
msgstr "Ayarlar"
@ -4259,7 +4260,7 @@ msgstr ""
msgid "Show bots"
msgstr ""
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Show computer"
msgstr ""
@ -4275,7 +4276,7 @@ msgstr "Daha fazla göster"
msgid "Show password"
msgstr ""
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Show settings"
msgstr "Ayarları göster"
@ -4463,8 +4464,8 @@ msgid "Steps"
msgstr "Adımlar"
#: src/components/browser/InAppBrowser.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/composer.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
#: src/pages/shell/transcript.tsx
msgid "Stop"
msgstr "Durdur"
@ -5091,7 +5092,7 @@ msgstr "Otomatik yönlendirilmezsen bu sekmeyi kapatabilirsin."
msgid "You can close this window."
msgstr "Bu pencereyi kapatabilirsin."
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "You have control"
msgstr "Kontrol sende"

View File

@ -141,7 +141,7 @@ msgid "{0}, main conversation"
msgstr ""
#. placeholder {0}: active.name
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "{0}'s screen"
msgstr ""
@ -813,11 +813,11 @@ msgstr "Bot"
msgid "Bot"
msgstr "Bot"
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "Bot screen"
msgstr "Bot 屏幕"
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "Bot screen preview"
msgstr "Bot 屏幕预览"
@ -1089,7 +1089,7 @@ msgstr "关闭"
msgid "Close chart"
msgstr "关闭图表"
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "Close computer"
msgstr "关闭电脑"
@ -1129,7 +1129,7 @@ msgstr "关闭导航"
#: src/components/ArtifactPane.tsx
#: src/components/browser/InAppBrowser.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Close panel"
msgstr "关闭面板"
@ -1202,7 +1202,7 @@ msgstr "电脑"
msgid "Computer failed to boot"
msgstr "电脑启动失败"
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "Computer is asleep"
msgstr "电脑已休眠"
@ -2401,6 +2401,7 @@ msgstr ""
#: src/components/stage/OoStage.tsx
#: src/pages/MessagingSettingsOverlay.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Group"
msgstr "群组"
@ -3098,7 +3099,7 @@ msgstr ""
#: src/components/MainInbox.tsx
#: src/pages/ActivityList.tsx
#: src/pages/HeuteBrief.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
#: src/pages/shell/transcript.tsx
msgid "Needs you"
msgstr ""
@ -3392,7 +3393,7 @@ msgid "Only file and folder names are read."
msgstr ""
#: src/pages/ScratchpadSection.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "Open"
msgstr "打开"
@ -3413,7 +3414,7 @@ msgstr ""
msgid "Open in browser"
msgstr ""
#: src/pages/Shell.tsx
#: src/pages/shell/computer-panel-preview.tsx
msgid "Open in full window"
msgstr "在完整窗口中打开"
@ -4202,7 +4203,7 @@ msgstr ""
#: src/pages/MessagingSettingsOverlay.tsx
#: src/pages/SettingsOverlay.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
#: src/pages/shell/user-menu.tsx
msgid "Settings"
msgstr "设置"
@ -4259,7 +4260,7 @@ msgstr ""
msgid "Show bots"
msgstr ""
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Show computer"
msgstr ""
@ -4275,7 +4276,7 @@ msgstr "显示更多"
msgid "Show password"
msgstr "显示密码"
#: src/pages/Shell.tsx
#: src/pages/shell/side-panel-header.tsx
msgid "Show settings"
msgstr "显示设置"
@ -4463,8 +4464,8 @@ msgid "Steps"
msgstr "步骤"
#: src/components/browser/InAppBrowser.tsx
#: src/pages/Shell.tsx
#: src/pages/shell/composer.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
#: src/pages/shell/transcript.tsx
msgid "Stop"
msgstr "停止"
@ -5091,7 +5092,7 @@ msgstr "如果没有自动跳转,可以关闭此标签页。"
msgid "You can close this window."
msgstr "可以关闭此窗口。"
#: src/pages/Shell.tsx
#: src/pages/shell/fullscreen-computer-overlay.tsx
msgid "You have control"
msgstr "你已接管"

View File

@ -90,7 +90,6 @@ import {
Calendar,
Globe,
LayoutGrid,
Maximize2,
PanelRight,
Pencil,
Plus,
@ -113,18 +112,9 @@ import { createPortal } from "react-dom";
import { useNavigate, useParams, useSearchParams } from "react-router-dom";
import { ArtifactPane } from "../components/ArtifactPane";
import { InAppBrowser } from "../components/browser/InAppBrowser";
import { ComputerMaintenanceActions } from "../components/ComputerMaintenanceActions";
import {
ComputersUnavailableHint,
computersAreUnavailable,
} from "../components/ComputersUnavailableHint";
import { ComputerUpdateProgress } from "../components/ComputerUpdateProgress";
import { AgentCursor } from "../components/computer/AgentCursor";
import { MainInbox } from "../components/MainInbox";
import { OoGroupStage, OoStage } from "../components/stage/OoStage";
import { TeachCaptureOverlay } from "../components/teach/TeachCaptureOverlay";
import { TeachComputerOverlayControl } from "../components/teach/TeachComputerOverlay";
import { TeachRecordingChrome, TeachStopButton } from "../components/teach/TeachRecordingChrome";
import { useSidebarResize } from "../hooks/useSidebarResize";
import { useWideLayout } from "../hooks/useWideLayout";
import { readActivityMode, writeActivityMode } from "../lib/activity-mode";
@ -174,7 +164,6 @@ import {
clearActiveThreadRuns,
computerPanelAutoBoot,
computerPanelAutoUsesBoot,
computerPanelNeedsMaintenance,
computerTakeoverBlocked,
isComputerStatusEvent,
prependThreadMessagePage,
@ -212,14 +201,8 @@ import {
} from "./shell/collapsed-sidebar-sections";
import { CommandPalette, isCommandPaletteHotkey } from "./shell/command-palette";
import { Composer } from "./shell/composer";
import {
ComputerReleaseActions,
computerLabel,
computerPlaceholder,
DesktopKindEmptyState,
embeddableScreenUrl,
screenIframeSandbox,
} from "./shell/computer-screen";
import { ComputerPanelPreview } from "./shell/computer-panel-preview";
import { embeddableScreenUrl } from "./shell/computer-screen";
import {
ClearConversationDialog,
DeleteBotDialog,
@ -229,12 +212,14 @@ import {
PickerInfoDialog,
RenameBotSectionDialog,
} from "./shell/dialogs";
import { FullscreenComputerOverlay } from "./shell/fullscreen-computer-overlay";
import { MainConversationRow } from "./shell/main-conversation-row";
import { cleanRosterPreview, formatRosterTime, stripSpaceTitlePrefix } from "./shell/roster-format";
import { rosterRowClass } from "./shell/roster-row-style";
import { ProjectRosterRow, TeamRosterRow } from "./shell/roster-rows";
import type { PendingAttachment } from "./shell/shell-types";
import { FALLBACK_BOT_COLOR } from "./shell/shell-types";
import { SidePanelHeader } from "./shell/side-panel-header";
import { SidebarGroupHeader } from "./shell/sidebar-group-header";
import { SidebarHeader } from "./shell/sidebar-header";
import { SidebarToggleButtons } from "./shell/sidebar-toggle-buttons";
@ -4149,107 +4134,28 @@ export function ShellPage() {
panel !== "create" &&
panel !== "create-group" &&
panel !== "group-settings" ? (
<div className="mb-4 flex items-center justify-between">
<span className="text-ui-body text-muted-foreground">
{panel === "settings" ? (
<Trans>Settings</Trans>
) : active ? (
(computer?.state ?? active.status)
) : (
<Trans>Group</Trans>
)}
</span>
<div className="flex gap-1">
{active &&
panel === "computer" &&
!computerOpen &&
computerPanelNeedsMaintenance(computer?.state, booting) ? (
<ComputerMaintenanceActions
botId={active.id}
computer={computer}
onChanged={async () => {
await refreshThread(active.id);
}}
/>
) : null}
{active ? (
<Button
variant="ghost"
size="icon-sm"
aria-label={panel === "settings" ? t`Show computer` : t`Show settings`}
onClick={() => setPanel(panel === "settings" ? "computer" : "settings")}
className={panel === "settings" ? "text-foreground" : "text-muted-foreground"}
>
<Settings strokeWidth={1.7} className="size-icon-md" />
</Button>
) : null}
<Button
variant="ghost"
size="icon-sm"
aria-label={t`Close panel`}
onClick={() => setPanel(null)}
>
<X strokeWidth={1.8} className="size-icon-md" />
</Button>
</div>
</div>
<SidePanelHeader
panel={panel}
active={active}
computer={computer}
computerOpen={computerOpen}
booting={booting}
refreshThread={refreshThread}
onPanelChange={setPanel}
/>
) : null}
{panel === "computer" && active ? (
<div>
<div
data-testid="computer-preview"
className="group relative aspect-[16/10] overflow-hidden rounded-[14px] bg-background"
>
{computerOpen ? (
<div className="grid h-full place-items-center text-sm text-muted-foreground/80">
<Trans>Open in full window</Trans>
</div>
) : computer?.kind === "desktop" ? (
<DesktopKindEmptyState className="grid h-full place-items-center px-6 text-center text-sm text-muted-foreground/80" />
) : computer?.state === "running" && embeddedScreenUrl && !computerScreenError ? (
<>
<iframe
title={t`Bot screen preview`}
src={embeddedScreenUrl}
sandbox={screenIframeSandbox(embeddedScreenUrl)}
className="h-full w-full border-0 bg-black"
allow="clipboard-read; clipboard-write"
style={{ pointerEvents: "none" }}
/>
<AgentCursor botId={active.id} color={active.color} name={active.name} />
</>
) : (
<div className="grid h-full place-items-center px-6 text-center text-sm text-muted-foreground/80">
{computerScreenError ??
(computersAreUnavailable(bootstrapMe?.sandboxProvider) ? (
<ComputersUnavailableHint />
) : (
computerPlaceholder(
computer?.state,
booting,
computerLabel(computer?.mode, active.name),
)
))}
</div>
)}
{!computerScreenError ? (
<button
type="button"
data-testid="computer-preview-open"
className="absolute inset-0 flex cursor-pointer items-center justify-center bg-overlay/40 opacity-0 transition-opacity group-hover:opacity-100 focus-visible:opacity-100"
aria-label={t`Open`}
onClick={() => void openComputer()}
>
<span className="inline-flex items-center gap-2 rounded-full bg-overlay px-3.5 py-2 text-ui-body text-foreground shadow-md">
<Maximize2 strokeWidth={1.9} aria-hidden className="size-icon-md" />
<Trans>Open</Trans>
</span>
</button>
) : null}
</div>
<p className="mt-2 truncate text-ui-body text-muted-foreground" dir="auto">
{t`${active.name}'s screen`}
</p>
<ComputerPanelPreview
active={active}
computer={computer}
computerOpen={computerOpen}
booting={booting}
embeddedScreenUrl={embeddedScreenUrl}
computerScreenError={computerScreenError}
sandboxProvider={bootstrapMe?.sandboxProvider}
onOpen={() => void openComputer()}
/>
<RoutineListHeader
onCreate={() => {
setRoutineDraft(emptyRoutineDraft());
@ -4992,148 +4898,25 @@ export function ShellPage() {
</div>
</div>
) : computerOpen && active ? (
<div className="fixed inset-0 z-30 bg-background">
<div
data-testid="computer-viewport"
className="fixed inset-x-0 top-0 flex flex-col bg-background"
style={{
height: computerViewport ? `${computerViewport.height}px` : "100dvh",
top: computerViewport ? `${computerViewport.offsetTop}px` : undefined,
}}
>
<div
data-testid="computer-chrome"
className="flex items-center justify-between gap-4 border-b border-sidebar-border px-[18px] py-3.5"
>
<div className="flex min-w-0 flex-1 items-center gap-3">
<BotAvatar
color={active.color}
identity={active.id}
size={28}
status={active.status}
/>
{recordingSkill ? (
<TeachRecordingChrome
recording={recordingSkill}
busy={teachBusy}
onStop={stopTeaching}
variant="overlay"
/>
) : (
<span className="truncate text-ui-body font-medium text-foreground" dir="auto">
{computerLabel(computer?.mode, active.name)}
</span>
)}
{!recordingSkill && hasControl ? (
computer?.takeoverRequested ? (
<span className="rounded-full bg-warning/15 px-[11px] py-1 text-ui-body-sm text-warning">
<Trans>Needs you</Trans>
</span>
) : (
<span className="rounded-full bg-success/15 px-[11px] py-1 text-ui-body-sm text-success">
<Trans>You have control</Trans>
</span>
)
) : null}
</div>
<div className="flex items-center gap-3">
{composerRunning ? (
<Button
type="button"
variant="outline"
size="sm"
aria-label={t`Stop`}
data-testid="computer-overlay-stop"
onClick={() => void stopRun()}
disabled={sending}
>
<Trans>Stop</Trans>
</Button>
) : null}
{recordingSkill ? (
<TeachStopButton busy={teachBusy} onStop={stopTeaching} />
) : hasControl ? (
<ComputerReleaseActions
takeoverRequested={Boolean(computer?.takeoverRequested)}
onRelease={releaseComputer}
/>
) : null}
{active && !recordingSkill ? (
<TeachComputerOverlayControl
key={active.id}
botId={active.id}
computer={computer}
busy={teachBusy}
onRefresh={refreshActiveTeaching}
/>
) : null}
{active && !recordingSkill ? (
<ComputerMaintenanceActions
botId={active.id}
computer={computer}
onChanged={async () => {
await refreshThread(active.id);
}}
/>
) : null}
<Button
variant="ghost"
size="icon-sm"
className="text-muted-foreground"
aria-label={t`Close computer`}
onClick={() => setComputerOpen(false)}
>
<X strokeWidth={1.8} className="size-icon-md" />
</Button>
</div>
</div>
{sendError ? (
<div
role="alert"
className="border-b border-destructive/40 bg-destructive/10 px-[18px] py-2 text-ui-body-sm text-destructive"
>
{sendError}
</div>
) : null}
<div className="relative min-h-0 flex-1 bg-background">
{computer?.kind === "desktop" ? (
<DesktopKindEmptyState className="grid h-full place-items-center px-8 text-center text-sm text-muted-foreground/80" />
) : computer?.state === "running" && embeddedScreenUrl && !computerScreenError ? (
<>
<iframe
title={t`Bot screen`}
src={embeddedScreenUrl}
sandbox={screenIframeSandbox(embeddedScreenUrl)}
className="h-full w-full border-0 bg-black"
allow="clipboard-read; clipboard-write; fullscreen"
style={{
pointerEvents: recordingSkill || !hasControl ? "none" : "auto",
}}
/>
{active && !hasControl ? (
<AgentCursor botId={active.id} color={active.color} name={active.name} />
) : null}
{active ? (
<TeachCaptureOverlay
botId={active.id}
skill={recordingSkill}
enabled={Boolean(recordingSkill)}
screenWidth={computer?.screenWidth}
screenHeight={computer?.screenHeight}
/>
) : null}
</>
) : (
<div className="grid h-full place-items-center text-sm text-muted-foreground/80">
{computerScreenError ??
(computer?.state === "suspended"
? t`Computer is asleep`
: computerLabel(computer?.mode, active.name))}
</div>
)}
</div>
</div>
</div>
<FullscreenComputerOverlay
active={active}
computer={computer}
computerViewport={computerViewport}
embeddedScreenUrl={embeddedScreenUrl}
computerScreenError={computerScreenError}
hasControl={hasControl}
recordingSkill={recordingSkill}
teachBusy={teachBusy}
composerRunning={composerRunning}
sending={sending}
sendError={sendError}
onStopRun={stopRun}
onStopTeaching={stopTeaching}
onRelease={releaseComputer}
onRefreshTeaching={refreshActiveTeaching}
refreshThread={refreshThread}
onClose={() => setComputerOpen(false)}
/>
) : null}
</div>
);

View File

@ -0,0 +1,96 @@
import { Trans, useLingui } from "@lingui/react/macro";
import type { Bot, ComputerStatus } from "@rakazo/contracts";
import { Maximize2 } from "lucide-react";
import type { ReactNode } from "react";
import {
ComputersUnavailableHint,
computersAreUnavailable,
} from "../../components/ComputersUnavailableHint";
import { AgentCursor } from "../../components/computer/AgentCursor";
import {
computerLabel,
computerPlaceholder,
DesktopKindEmptyState,
screenIframeSandbox,
} from "./computer-screen";
/** The bot's screen in the side panel: a live, non-interactive preview that opens full window. */
export function ComputerPanelPreview({
active,
computer,
computerOpen,
booting,
embeddedScreenUrl,
computerScreenError,
sandboxProvider,
onOpen,
}: {
active: Bot;
computer: ComputerStatus | null;
computerOpen: boolean;
booting: boolean;
embeddedScreenUrl: string | null;
computerScreenError: ReactNode;
sandboxProvider: string | undefined;
onOpen: () => void;
}) {
const { t } = useLingui();
return (
<>
<div
data-testid="computer-preview"
className="group relative aspect-[16/10] overflow-hidden rounded-[14px] bg-background"
>
{computerOpen ? (
<div className="grid h-full place-items-center text-sm text-muted-foreground/80">
<Trans>Open in full window</Trans>
</div>
) : computer?.kind === "desktop" ? (
<DesktopKindEmptyState className="grid h-full place-items-center px-6 text-center text-sm text-muted-foreground/80" />
) : computer?.state === "running" && embeddedScreenUrl && !computerScreenError ? (
<>
<iframe
title={t`Bot screen preview`}
src={embeddedScreenUrl}
sandbox={screenIframeSandbox(embeddedScreenUrl)}
className="h-full w-full border-0 bg-black"
allow="clipboard-read; clipboard-write"
style={{ pointerEvents: "none" }}
/>
<AgentCursor botId={active.id} color={active.color} name={active.name} />
</>
) : (
<div className="grid h-full place-items-center px-6 text-center text-sm text-muted-foreground/80">
{computerScreenError ??
(computersAreUnavailable(sandboxProvider) ? (
<ComputersUnavailableHint />
) : (
computerPlaceholder(
computer?.state,
booting,
computerLabel(computer?.mode, active.name),
)
))}
</div>
)}
{!computerScreenError ? (
<button
type="button"
data-testid="computer-preview-open"
className="absolute inset-0 flex cursor-pointer items-center justify-center bg-overlay/40 opacity-0 transition-opacity group-hover:opacity-100 focus-visible:opacity-100"
aria-label={t`Open`}
onClick={onOpen}
>
<span className="inline-flex items-center gap-2 rounded-full bg-overlay px-3.5 py-2 text-ui-body text-foreground shadow-md">
<Maximize2 strokeWidth={1.9} aria-hidden className="size-icon-md" />
<Trans>Open</Trans>
</span>
</button>
) : null}
</div>
<p className="mt-2 truncate text-ui-body text-muted-foreground" dir="auto">
{t`${active.name}'s screen`}
</p>
</>
);
}

View File

@ -0,0 +1,196 @@
import { Trans, useLingui } from "@lingui/react/macro";
import type { Bot, ComputerReleaseReason, ComputerStatus, TaughtSkill } from "@rakazo/contracts";
import { BotAvatar, Button } from "@rakazo/ui-web";
import { X } from "lucide-react";
import type { ReactNode } from "react";
import { ComputerMaintenanceActions } from "../../components/ComputerMaintenanceActions";
import { AgentCursor } from "../../components/computer/AgentCursor";
import { TeachCaptureOverlay } from "../../components/teach/TeachCaptureOverlay";
import { TeachComputerOverlayControl } from "../../components/teach/TeachComputerOverlay";
import { TeachRecordingChrome, TeachStopButton } from "../../components/teach/TeachRecordingChrome";
import {
ComputerReleaseActions,
computerLabel,
DesktopKindEmptyState,
screenIframeSandbox,
} from "./computer-screen";
/** The bot's computer in full window, where the user takes control or teaches a skill. */
export function FullscreenComputerOverlay({
active,
computer,
computerViewport,
embeddedScreenUrl,
computerScreenError,
hasControl,
recordingSkill,
teachBusy,
composerRunning,
sending,
sendError,
onStopRun,
onStopTeaching,
onRelease,
onRefreshTeaching,
refreshThread,
onClose,
}: {
active: Bot;
computer: ComputerStatus | null;
computerViewport: { height: number; offsetTop: number } | null;
embeddedScreenUrl: string | null;
computerScreenError: ReactNode;
hasControl: boolean;
recordingSkill: TaughtSkill | null;
teachBusy: boolean;
composerRunning: boolean;
sending: boolean;
sendError: string | null;
onStopRun: () => Promise<void>;
onStopTeaching: () => Promise<void>;
onRelease: (reason?: ComputerReleaseReason) => Promise<void>;
onRefreshTeaching: () => Promise<void>;
refreshThread: (botId: string) => Promise<unknown>;
onClose: () => void;
}) {
const { t } = useLingui();
return (
<div className="fixed inset-0 z-30 bg-background">
<div
data-testid="computer-viewport"
className="fixed inset-x-0 top-0 flex flex-col bg-background"
style={{
height: computerViewport ? `${computerViewport.height}px` : "100dvh",
top: computerViewport ? `${computerViewport.offsetTop}px` : undefined,
}}
>
<div
data-testid="computer-chrome"
className="flex items-center justify-between gap-4 border-b border-sidebar-border px-[18px] py-3.5"
>
<div className="flex min-w-0 flex-1 items-center gap-3">
<BotAvatar color={active.color} identity={active.id} size={28} status={active.status} />
{recordingSkill ? (
<TeachRecordingChrome
recording={recordingSkill}
busy={teachBusy}
onStop={onStopTeaching}
variant="overlay"
/>
) : (
<span className="truncate text-ui-body font-medium text-foreground" dir="auto">
{computerLabel(computer?.mode, active.name)}
</span>
)}
{!recordingSkill && hasControl ? (
computer?.takeoverRequested ? (
<span className="rounded-full bg-warning/15 px-[11px] py-1 text-ui-body-sm text-warning">
<Trans>Needs you</Trans>
</span>
) : (
<span className="rounded-full bg-success/15 px-[11px] py-1 text-ui-body-sm text-success">
<Trans>You have control</Trans>
</span>
)
) : null}
</div>
<div className="flex items-center gap-3">
{composerRunning ? (
<Button
type="button"
variant="outline"
size="sm"
aria-label={t`Stop`}
data-testid="computer-overlay-stop"
onClick={() => void onStopRun()}
disabled={sending}
>
<Trans>Stop</Trans>
</Button>
) : null}
{recordingSkill ? (
<TeachStopButton busy={teachBusy} onStop={onStopTeaching} />
) : hasControl ? (
<ComputerReleaseActions
takeoverRequested={Boolean(computer?.takeoverRequested)}
onRelease={onRelease}
/>
) : null}
{active && !recordingSkill ? (
<TeachComputerOverlayControl
key={active.id}
botId={active.id}
computer={computer}
busy={teachBusy}
onRefresh={onRefreshTeaching}
/>
) : null}
{active && !recordingSkill ? (
<ComputerMaintenanceActions
botId={active.id}
computer={computer}
onChanged={async () => {
await refreshThread(active.id);
}}
/>
) : null}
<Button
variant="ghost"
size="icon-sm"
className="text-muted-foreground"
aria-label={t`Close computer`}
onClick={onClose}
>
<X strokeWidth={1.8} className="size-icon-md" />
</Button>
</div>
</div>
{sendError ? (
<div
role="alert"
className="border-b border-destructive/40 bg-destructive/10 px-[18px] py-2 text-ui-body-sm text-destructive"
>
{sendError}
</div>
) : null}
<div className="relative min-h-0 flex-1 bg-background">
{computer?.kind === "desktop" ? (
<DesktopKindEmptyState className="grid h-full place-items-center px-8 text-center text-sm text-muted-foreground/80" />
) : computer?.state === "running" && embeddedScreenUrl && !computerScreenError ? (
<>
<iframe
title={t`Bot screen`}
src={embeddedScreenUrl}
sandbox={screenIframeSandbox(embeddedScreenUrl)}
className="h-full w-full border-0 bg-black"
allow="clipboard-read; clipboard-write; fullscreen"
style={{
pointerEvents: recordingSkill || !hasControl ? "none" : "auto",
}}
/>
{active && !hasControl ? (
<AgentCursor botId={active.id} color={active.color} name={active.name} />
) : null}
{active ? (
<TeachCaptureOverlay
botId={active.id}
skill={recordingSkill}
enabled={Boolean(recordingSkill)}
screenWidth={computer?.screenWidth}
screenHeight={computer?.screenHeight}
/>
) : null}
</>
) : (
<div className="grid h-full place-items-center text-sm text-muted-foreground/80">
{computerScreenError ??
(computer?.state === "suspended"
? t`Computer is asleep`
: computerLabel(computer?.mode, active.name))}
</div>
)}
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,73 @@
import { Trans, useLingui } from "@lingui/react/macro";
import type { Bot, ComputerStatus } from "@rakazo/contracts";
import { Button } from "@rakazo/ui-web";
import { Settings, X } from "lucide-react";
import { ComputerMaintenanceActions } from "../../components/ComputerMaintenanceActions";
import { computerPanelNeedsMaintenance } from "../../lib/thread-events";
/** Title row of the computer and settings side panel, with its switch and close buttons. */
export function SidePanelHeader({
panel,
active,
computer,
computerOpen,
booting,
refreshThread,
onPanelChange,
}: {
panel: "computer" | "settings";
active: Bot | undefined;
computer: ComputerStatus | null;
computerOpen: boolean;
booting: boolean;
refreshThread: (botId: string) => Promise<unknown>;
onPanelChange: (panel: "computer" | "settings" | null) => void;
}) {
const { t } = useLingui();
return (
<div className="mb-4 flex items-center justify-between">
<span className="text-ui-body text-muted-foreground">
{panel === "settings" ? (
<Trans>Settings</Trans>
) : active ? (
(computer?.state ?? active.status)
) : (
<Trans>Group</Trans>
)}
</span>
<div className="flex gap-1">
{active &&
panel === "computer" &&
!computerOpen &&
computerPanelNeedsMaintenance(computer?.state, booting) ? (
<ComputerMaintenanceActions
botId={active.id}
computer={computer}
onChanged={async () => {
await refreshThread(active.id);
}}
/>
) : null}
{active ? (
<Button
variant="ghost"
size="icon-sm"
aria-label={panel === "settings" ? t`Show computer` : t`Show settings`}
onClick={() => onPanelChange(panel === "settings" ? "computer" : "settings")}
className={panel === "settings" ? "text-foreground" : "text-muted-foreground"}
>
<Settings strokeWidth={1.7} className="size-icon-md" />
</Button>
) : null}
<Button
variant="ghost"
size="icon-sm"
aria-label={t`Close panel`}
onClick={() => onPanelChange(null)}
>
<X strokeWidth={1.8} className="size-icon-md" />
</Button>
</div>
</div>
);
}