diff --git a/frontend/src/components/App/icons.ts b/frontend/src/components/App/icons.ts index b2fa0780dd5..dce03b1c21a 100644 --- a/frontend/src/components/App/icons.ts +++ b/frontend/src/components/App/icons.ts @@ -423,6 +423,9 @@ const mdiIcons = { 'content-copy': { body: '\u003Cpath fill="currentColor" d="M19 21H8V7h11m0-2H8a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h11a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2m-3-4H4a2 2 0 0 0-2 2v14h2V3h12z"/\u003E', }, + 'content-paste': { + body: '\u003Cpath fill="currentColor" d="M19 20H5V4h2v3h10V4h2m-7-2a1 1 0 0 1 1 1a1 1 0 0 1-1 1a1 1 0 0 1-1-1a1 1 0 0 1 1-1m7 0h-4.18C14.4.84 13.3 0 12 0S9.6.84 9.18 2H5a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2"/\u003E', + }, 'arrow-left': { body: '\u003Cpath fill="currentColor" d="M20 11v2H8l5.5 5.5l-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5L8 11z"/\u003E', }, diff --git a/frontend/src/components/common/Terminal.tsx b/frontend/src/components/common/Terminal.tsx index 4f1cf88216f..c6ccb9e5ee3 100644 --- a/frontend/src/components/common/Terminal.tsx +++ b/frontend/src/components/common/Terminal.tsx @@ -15,11 +15,15 @@ */ import '@xterm/xterm/css/xterm.css'; +import { Icon } from '@iconify/react'; import Box from '@mui/material/Box'; import { DialogProps } from '@mui/material/Dialog'; import DialogContent from '@mui/material/DialogContent'; import FormControl from '@mui/material/FormControl'; import InputLabel from '@mui/material/InputLabel'; +import ListItemIcon from '@mui/material/ListItemIcon'; +import ListItemText from '@mui/material/ListItemText'; +import Menu from '@mui/material/Menu'; import MenuItem from '@mui/material/MenuItem'; import Select from '@mui/material/Select'; import { FitAddon } from '@xterm/addon-fit'; @@ -68,6 +72,11 @@ export default function Terminal(props: TerminalProps) { available: getAvailableShells(), currentIdx: 0, }); + const [contextMenu, setContextMenu] = React.useState<{ + mouseX: number; + mouseY: number; + hasSelection: boolean; + } | null>(null); const { t } = useTranslation(['translation', 'glossary']); function getDefaultContainer() { @@ -369,6 +378,46 @@ export default function Terminal(props: TerminalProps) { setContainer(event.target.value); } + const handleContextMenu = (event: React.MouseEvent) => { + event.preventDefault(); + const hasSelection = !!xtermRef.current?.xterm.getSelection(); + setContextMenu({ + mouseX: event.clientX + 2, + mouseY: event.clientY - 6, + hasSelection, + }); + }; + + const handleContextMenuClose = () => { + setContextMenu(null); + }; + + const handleCopy = async () => { + if (xtermRef.current) { + const selection = xtermRef.current.xterm.getSelection(); + if (selection) { + try { + await navigator.clipboard.writeText(selection); + } catch (err) { + console.error('Failed to copy text: ', err); + } + } + } + handleContextMenuClose(); + }; + + const handlePaste = async () => { + if (xtermRef.current) { + try { + const text = await navigator.clipboard.readText(); + send(0, text); + } catch (err) { + console.error('Failed to paste text: ', err); + } + } + handleContextMenuClose(); + }; + function isSuccessfulExitError(channel: number, text: string): boolean { // Linux container Error if (channel === 3) { @@ -479,8 +528,34 @@ export default function Terminal(props: TerminalProps) {
setTerminalContainerRef(x)} - style={{ flex: 1, display: 'flex', flexDirection: 'column-reverse' }} + onContextMenu={handleContextMenu} + style={{ + flex: 1, + display: 'flex', + flexDirection: 'column-reverse', + }} /> + + + + + + {t('translation|Copy')} + + + + + + {t('translation|Paste')} + + ); diff --git a/frontend/src/i18n/locales/de/translation.json b/frontend/src/i18n/locales/de/translation.json index 813048be994..a7e3702fe11 100644 --- a/frontend/src/i18n/locales/de/translation.json +++ b/frontend/src/i18n/locales/de/translation.json @@ -400,6 +400,7 @@ "Failed to run \"{{ command }}\"": "Ausführung von \"{{ command }}\" fehlgeschlagen", "Trying to attach to the container {{ container }}…": "Versuche, an den Container {{ container }} anzuhängen…", "Trying to run \"{{command}}\"…": "Versuche, \"{{command}}\" auszuführen…", + "Paste": "Einfügen", "Attach: {{ itemName }}": "", "Terminal: {{ itemName }}": "", "Timezone": "Zeitzone", diff --git a/frontend/src/i18n/locales/en/translation.json b/frontend/src/i18n/locales/en/translation.json index b7e3c1713ea..a4c8be8ba82 100644 --- a/frontend/src/i18n/locales/en/translation.json +++ b/frontend/src/i18n/locales/en/translation.json @@ -400,6 +400,7 @@ "Failed to run \"{{ command }}\"": "Failed to run \"{{ command }}\"", "Trying to attach to the container {{ container }}…": "Trying to attach to the container {{ container }}…", "Trying to run \"{{command}}\"…": "Trying to run \"{{command}}\"…", + "Paste": "Paste", "Attach: {{ itemName }}": "Attach: {{ itemName }}", "Terminal: {{ itemName }}": "Terminal: {{ itemName }}", "Timezone": "Timezone", diff --git a/frontend/src/i18n/locales/es/translation.json b/frontend/src/i18n/locales/es/translation.json index e202c7f01e5..a7b28d1c249 100644 --- a/frontend/src/i18n/locales/es/translation.json +++ b/frontend/src/i18n/locales/es/translation.json @@ -403,6 +403,7 @@ "Failed to run \"{{ command }}\"": "Fallo al ejecutar \"{{ command }}\"", "Trying to attach to the container {{ container }}…": "Intentando adjuntarse al contenedor {{ container }}…", "Trying to run \"{{command}}\"…": "Intentando ejecutar \"{{command}}\"…", + "Paste": "Pegar", "Attach: {{ itemName }}": "", "Terminal: {{ itemName }}": "", "Timezone": "Huso horario", diff --git a/frontend/src/i18n/locales/fr/translation.json b/frontend/src/i18n/locales/fr/translation.json index 12429e6367e..a599cf07ba1 100644 --- a/frontend/src/i18n/locales/fr/translation.json +++ b/frontend/src/i18n/locales/fr/translation.json @@ -403,6 +403,7 @@ "Failed to run \"{{ command }}\"": "Échec de l'exécution de \"{commande }}\"", "Trying to attach to the container {{ container }}…": "Tentative de connexion au conteneur {{ container }}…", "Trying to run \"{{command}}\"…": "Essayer d'exécuter \"{{command}}\"…", + "Paste": "Coller", "Attach: {{ itemName }}": "", "Terminal: {{ itemName }}": "", "Timezone": "Fuseau horaire", diff --git a/frontend/src/i18n/locales/hi/translation.json b/frontend/src/i18n/locales/hi/translation.json index c211c4f70fc..33b3acb2317 100644 --- a/frontend/src/i18n/locales/hi/translation.json +++ b/frontend/src/i18n/locales/hi/translation.json @@ -400,6 +400,7 @@ "Failed to run \"{{ command }}\"": "\"{{ command }}\" चलाने में विफल", "Trying to attach to the container {{ container }}…": "कंटेनर {{ container }} से जुड़ने का प्रयास कर रहे हैं…", "Trying to run \"{{command}}\"…": "\"{{command}}\" चलाने का प्रयास कर रहे हैं…", + "Paste": "पेस्ट करें", "Attach: {{ itemName }}": "जोड़ें: {{ itemName }}", "Terminal: {{ itemName }}": "टर्मिनल: {{ itemName }}", "Timezone": "समय क्षेत्र", diff --git a/frontend/src/i18n/locales/it/translation.json b/frontend/src/i18n/locales/it/translation.json index 5345b0abbc7..16508329c03 100644 --- a/frontend/src/i18n/locales/it/translation.json +++ b/frontend/src/i18n/locales/it/translation.json @@ -403,6 +403,7 @@ "Failed to run \"{{ command }}\"": "Impossibile eseguire \"{{ command }}\"", "Trying to attach to the container {{ container }}…": "Tentativo di collegamento al container {{ container }}…", "Trying to run \"{{command}}\"…": "Sto tentando di eseguire \"{{command}}\"…", + "Paste": "Incolla", "Attach: {{ itemName }}": "Collega: {{ itemName }}", "Terminal: {{ itemName }}": "Terminale: {{ itemName }}", "Timezone": "Fuso orario", diff --git a/frontend/src/i18n/locales/ja/translation.json b/frontend/src/i18n/locales/ja/translation.json index 5aae17befc1..2faf9840db7 100644 --- a/frontend/src/i18n/locales/ja/translation.json +++ b/frontend/src/i18n/locales/ja/translation.json @@ -397,6 +397,7 @@ "Failed to run \"{{ command }}\"": "\"{{ command }}\" の実行に失敗しました", "Trying to attach to the container {{ container }}…": "コンテナー {{ container }} にアタッチしようとしています…", "Trying to run \"{{command}}\"…": "\"{{command}}\" を実行しようとしています…", + "Paste": "貼り付け", "Attach: {{ itemName }}": "アタッチ: {{ itemName }}", "Terminal: {{ itemName }}": "ターミナル: {{ itemName }}", "Timezone": "タイムゾーン", diff --git a/frontend/src/i18n/locales/ko/translation.json b/frontend/src/i18n/locales/ko/translation.json index 6f4758bf423..60e978d3f72 100644 --- a/frontend/src/i18n/locales/ko/translation.json +++ b/frontend/src/i18n/locales/ko/translation.json @@ -397,6 +397,7 @@ "Failed to run \"{{ command }}\"": "\"{{ command }}\" 실행에 실패했습니다.", "Trying to attach to the container {{ container }}…": "컨테이너 {{ container }}에 연결을 시도 중…", "Trying to run \"{{command}}\"…": "\"{{command}}\" 실행 중…", + "Paste": "붙여넣기", "Attach: {{ itemName }}": "연결: {{ itemName }}", "Terminal: {{ itemName }}": "터미널: {{ itemName }}", "Timezone": "시간대", diff --git a/frontend/src/i18n/locales/pt/translation.json b/frontend/src/i18n/locales/pt/translation.json index 1685951605f..acca5d8a3c4 100644 --- a/frontend/src/i18n/locales/pt/translation.json +++ b/frontend/src/i18n/locales/pt/translation.json @@ -403,6 +403,7 @@ "Failed to run \"{{ command }}\"": "Falha ao executar \"{{ command }}\"", "Trying to attach to the container {{ container }}…": "A tentar anexar ao container {{ container }}…", "Trying to run \"{{command}}\"…": "A tentar executar \"{{command}}\"…", + "Paste": "Colar", "Attach: {{ itemName }}": "", "Terminal: {{ itemName }}": "", "Timezone": "Fuso horário", diff --git a/frontend/src/i18n/locales/ta/translation.json b/frontend/src/i18n/locales/ta/translation.json index eb9b23e6f7e..263245a675f 100644 --- a/frontend/src/i18n/locales/ta/translation.json +++ b/frontend/src/i18n/locales/ta/translation.json @@ -400,6 +400,7 @@ "Failed to run \"{{ command }}\"": "\"{{ command }}\"-ஐ இயக்குவதில் தோல்வி", "Trying to attach to the container {{ container }}…": "{{ container }} கண்டெய்னருடன் இணைக்க முயற்சிக்கிறது...", "Trying to run \"{{command}}\"…": "\"{{command}}\"-ஐ இயக்க முயற்சிக்கிறது...", + "Paste": "ஒட்டு", "Attach: {{ itemName }}": "அட்டாச்: {{ itemName }}", "Terminal: {{ itemName }}": "டெர்மினல்: {{ itemName }}", "Timezone": "டைம்ஸோன்", diff --git a/frontend/src/i18n/locales/zh-tw/translation.json b/frontend/src/i18n/locales/zh-tw/translation.json index 2e9325cf72e..15db38f056e 100644 --- a/frontend/src/i18n/locales/zh-tw/translation.json +++ b/frontend/src/i18n/locales/zh-tw/translation.json @@ -397,6 +397,7 @@ "Failed to run \"{{ command }}\"": "執行 \"{{ command }}\" 失敗", "Trying to attach to the container {{ container }}…": "嘗試附加到容器 {{ container }}…", "Trying to run \"{{command}}\"…": "嘗試執行 \"{{command}}\"…", + "Paste": "貼上", "Attach: {{ itemName }}": "附加:{{ itemName }}", "Terminal: {{ itemName }}": "終端:{{ itemName }}", "Timezone": "時區", diff --git a/frontend/src/i18n/locales/zh/translation.json b/frontend/src/i18n/locales/zh/translation.json index e84b098a5af..66f5aa3ca41 100644 --- a/frontend/src/i18n/locales/zh/translation.json +++ b/frontend/src/i18n/locales/zh/translation.json @@ -397,6 +397,7 @@ "Failed to run \"{{ command }}\"": "执行 \"{{ command }}\" 失败", "Trying to attach to the container {{ container }}…": "尝试附加到容器 {{ container }}…", "Trying to run \"{{command}}\"…": "尝试执行 \"{{command}}\"…", + "Paste": "粘贴", "Attach: {{ itemName }}": "附加:{{ itemName }}", "Terminal: {{ itemName }}": "终端:{{ itemName }}", "Timezone": "时区",