EE-1976 fix(docker): support copy and paste in container console

pull/7697/head
RexWangPT 2022-09-19 16:28:33 +08:00 committed by testa113
parent 93866644c6
commit ac99b9561e
6 changed files with 49 additions and 28 deletions

View File

@ -1,6 +1,6 @@
import 'bootstrap/dist/css/bootstrap.css';
import 'toastr/build/toastr.css';
import 'xterm/dist/xterm.css';
import 'xterm/css/xterm.css';
import 'angularjs-slider/dist/rzslider.css';
import 'angular-json-tree/dist/angular-json-tree.css';
import 'angular-loading-bar/build/loading-bar.css';

View File

@ -1,5 +1,3 @@
import { Terminal } from 'xterm';
import * as fit from 'xterm/lib/addons/fit/fit';
import { agentInterceptor } from './portainer/services/axios';
/* @ngInject */
@ -27,8 +25,6 @@ export function configApp($urlRouterProvider, $httpProvider, localStorageService
request: agentInterceptor,
}));
Terminal.applyAddon(fit);
$uibTooltipProvider.setTriggers({
mouseenter: 'mouseleave',
click: 'click',

View File

@ -1,4 +1,5 @@
import { Terminal } from 'xterm';
import { FitAddon } from 'xterm-addon-fit';
import { baseHref } from '@/portainer/helpers/pathHelper';
angular.module('portainer.docker').controller('ContainerConsoleController', [
@ -28,7 +29,7 @@ angular.module('portainer.docker').controller('ContainerConsoleController', [
CONSOLE_COMMANDS_LABEL_PREFIX,
SidebarService
) {
var socket, term;
var socket, term, fitAddon;
let states = Object.freeze({
disconnected: 0,
@ -138,6 +139,9 @@ angular.module('portainer.docker').controller('ContainerConsoleController', [
term.write('\n\r(connection closed)');
term.dispose();
}
if (fitAddon) {
fitAddon.dispose();
}
}
};
@ -152,7 +156,7 @@ angular.module('portainer.docker').controller('ContainerConsoleController', [
function resize(restcall, add) {
add = add || 0;
term.fit();
fitAddon.fit();
var termWidth = term.cols;
var termHeight = 30;
term.resize(termWidth, termHeight);
@ -161,7 +165,7 @@ angular.module('portainer.docker').controller('ContainerConsoleController', [
}
function initTerm(url, resizeRestCall) {
let resizefun = resize.bind(this, resizeRestCall);
let resizeFunc = resize.bind(this, resizeRestCall);
if ($transition$.params().nodeName) {
url += '&nodeName=' + $transition$.params().nodeName;
@ -176,23 +180,24 @@ angular.module('portainer.docker').controller('ContainerConsoleController', [
socket.onopen = function () {
$scope.state = states.connected;
term = new Terminal();
term = new Terminal({ cursorBlink: true });
fitAddon = new FitAddon();
term.loadAddon(fitAddon);
term.on('data', function (data) {
term.onData(function (data) {
socket.send(data);
});
var terminal_container = document.getElementById('terminal-container');
term.open(terminal_container);
term.focus();
term.setOption('cursorBlink', true);
window.onresize = function () {
resizefun();
resizeFunc();
$scope.$apply();
};
$scope.$watch(SidebarService.isSidebarOpen, function () {
setTimeout(resizefun, 400);
setTimeout(resizeFunc, 400);
});
socket.onmessage = function (e) {
@ -208,7 +213,7 @@ angular.module('portainer.docker').controller('ContainerConsoleController', [
$scope.$apply();
};
resizefun(1);
resizeFunc(1);
$scope.$apply();
};
}

View File

@ -1,5 +1,5 @@
import { Terminal } from 'xterm';
import { fit } from 'xterm/lib/addons/fit/fit';
import { FitAddon } from 'xterm-addon-fit';
import { useCallback, useEffect, useRef, useState } from 'react';
import clsx from 'clsx';
import { RotateCw, X, Terminal as TerminalIcon } from 'lucide-react';
@ -29,7 +29,8 @@ interface Props {
}
export function KubeCtlShell({ environmentId, onClose }: Props) {
const [terminal] = useState(new Terminal());
const [terminal] = useState(new Terminal({ cursorBlink: true }));
const [fitAddon] = useState(new FitAddon());
const [shell, setShell] = useState<ShellState>({
socket: null,
@ -46,22 +47,23 @@ export function KubeCtlShell({ environmentId, onClose }: Props) {
terminalClose(); // only css trick
socket?.close();
terminal.dispose();
fitAddon.dispose();
onClose();
}, [onClose, terminal, socket]);
}, [onClose, socket, terminal, fitAddon]);
const openTerminal = useCallback(() => {
if (!terminalElem.current) {
return;
}
terminal.loadAddon(fitAddon);
terminal.open(terminalElem.current);
terminal.setOption('cursorBlink', true);
terminal.focus();
fit(terminal);
fitAddon.fit();
terminal.writeln('#Run kubectl commands inside here');
terminal.writeln('#e.g. kubectl get all');
terminal.writeln('');
}, [terminal]);
}, [terminal, fitAddon]);
// refresh socket listeners on socket updates
useEffect(() => {
@ -106,7 +108,17 @@ export function KubeCtlShell({ environmentId, onClose }: Props) {
const socket = new WebSocket(buildUrl(jwt, environmentId));
setShell((shell) => ({ ...shell, socket }));
terminal.onData((data) => socket.send(data));
terminal.onData((data) => {
if (
terminal.modes.bracketedPasteMode &&
data.slice(0, 6) === '\x1b[200~' &&
data.slice(-6) === '\x1b[201~'
) {
socket.send(data.slice(6, -6));
} else {
socket.send(data);
}
});
terminal.onKey(({ domEvent }) => {
if (domEvent.ctrlKey && domEvent.code === 'KeyD') {
close();
@ -118,11 +130,12 @@ export function KubeCtlShell({ environmentId, onClose }: Props) {
function close() {
socket.close();
terminal.dispose();
fitAddon.dispose();
window.removeEventListener('resize', terminalResize);
}
return close;
}, [environmentId, jwt, terminal]);
}, [environmentId, jwt, terminal, fitAddon]);
return (
<div className={clsx(styles.root, { [styles.minimized]: shell.minimized })}>

View File

@ -118,7 +118,9 @@
"tippy.js": "^6.3.7",
"toastr": "^2.1.4",
"uuid": "^3.3.2",
"xterm": "^3.8.0",
"x256": "^0.0.2",
"xterm": "^4.1.3",
"xterm-addon-fit": "^0.5.0",
"yaml": "^1.10.2",
"yup": "^0.32.11",
"zustand": "^4.1.1"
@ -234,4 +236,4 @@
}
},
"browserslist": "last 2 versions"
}
}

View File

@ -18932,10 +18932,15 @@ xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2, xtend@~4.0.1:
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
xterm@^3.8.0:
version "3.14.5"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.14.5.tgz#c9d14e48be6873aa46fb429f22f2165557fd2dea"
integrity sha512-DVmQ8jlEtL+WbBKUZuMxHMBgK/yeIZwkXB81bH+MGaKKnJGYwA+770hzhXPfwEIokK9On9YIFPRleVp/5G7z9g==
xterm-addon-fit@^0.5.0:
version "0.5.0"
resolved "https://registry.npmmirror.com/xterm-addon-fit/-/xterm-addon-fit-0.5.0.tgz#2d51b983b786a97dcd6cde805e700c7f913bc596"
integrity sha512-DsS9fqhXHacEmsPxBJZvfj2la30Iz9xk+UKjhQgnYNkrUIN5CYLbw7WEfz117c7+S86S/tpHPfvNxJsF5/G8wQ==
xterm@^4.1.3:
version "4.19.0"
resolved "https://registry.npmmirror.com/xterm/-/xterm-4.19.0.tgz#c0f9d09cd61de1d658f43ca75f992197add9ef6d"
integrity sha512-c3Cp4eOVsYY5Q839dR5IejghRPpxciGmLWWaP9g+ppfMeBChMeLa1DCA+pmX/jyDZ+zxFOmlJL/82qVdayVoGQ==
xterm@^4.13.0:
version "4.17.0"