diff --git a/releasenotes/notes/feat_adding_terminal_zun_detail-7a1e18e800b20a2d.yaml b/releasenotes/notes/feat_adding_terminal_zun_detail-7a1e18e800b20a2d.yaml new file mode 100644 index 00000000..4909f6a0 --- /dev/null +++ b/releasenotes/notes/feat_adding_terminal_zun_detail-7a1e18e800b20a2d.yaml @@ -0,0 +1,4 @@ +--- +features: + - | + Adding terminal feature to Zun detail page. \ No newline at end of file diff --git a/src/client/zun/index.js b/src/client/zun/index.js index be15f9e1..4911a7e2 100644 --- a/src/client/zun/index.js +++ b/src/client/zun/index.js @@ -66,6 +66,10 @@ export class ZunClient extends Base { key: 'execute', method: 'post', }, + { + key: 'attach', + method: 'get', + }, { key: 'network_attach', method: 'post', diff --git a/src/pages/container-service/containers/Containers/Detail/Console.jsx b/src/pages/container-service/containers/Containers/Detail/Console.jsx new file mode 100644 index 00000000..b04d5601 --- /dev/null +++ b/src/pages/container-service/containers/Containers/Detail/Console.jsx @@ -0,0 +1,78 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import React, { useEffect } from "react"; +import globalContainersStore from 'src/stores/zun/containers'; + +export default function Console(props) { + + useEffect(() => { + globalContainersStore.attach(props.detail.uuid).then((res) => { + const head = document.head; + + const xtermCssLink = document.createElement("link"); + xtermCssLink.rel = "stylesheet"; + xtermCssLink.href = "https://cdn.jsdelivr.net/npm/xterm@4.19.0/css/xterm.css"; + head.appendChild(xtermCssLink); + + + const xtermScript = document.createElement("script"); + xtermScript.src = "https://cdnjs.cloudflare.com/ajax/libs/xterm/3.14.5/xterm.min.js"; + + xtermScript.onload = () => { + const term = new window.Terminal({ + cursorBlink: true, + }); + term.write(" >$ "); + term.open(document.getElementById('terminal')); + let socket = new WebSocket(res, ['binary', 'base64']); + term.on('data', function (data) { + socket.send(str2ab(data)); + }); + socket.onmessage = function (e) { + if (e.data instanceof Blob) { + let f = new FileReader(); + f.onload = function () { + term.write(f.result); + }; + f.readAsText(e.data); + } else { + term.write(e.data); + } + }; + function str2ab(str) { + let buf = new ArrayBuffer(str.length); // 2 bytes for each char + let bufView = new Uint8Array(buf); + for (let i = 0, strLen = str.length; i < strLen; i++) { + bufView[i] = str.charCodeAt(i); + } + return buf; + } + }; + head.appendChild(xtermScript); + + return () => { + head.removeChild(xtermCssLink); + head.removeChild(xtermScript); + }; + }); + + }, []); + + return ( +
+
+
+
+ ); + +} diff --git a/src/pages/container-service/containers/Containers/Detail/index.jsx b/src/pages/container-service/containers/Containers/Detail/index.jsx index 2fe7b5ec..ed65e6b4 100644 --- a/src/pages/container-service/containers/Containers/Detail/index.jsx +++ b/src/pages/container-service/containers/Containers/Detail/index.jsx @@ -19,6 +19,7 @@ import actionConfigs from '../actions'; import BaseDetail from './BaseDetail'; import ActionLogs from './ActionLogs'; import Logs from './Logs'; +import Console from './Console'; export class ContainerDetail extends Base { init() { @@ -84,6 +85,13 @@ export class ContainerDetail extends Base { component: Logs, }); } + if (this.detailData.interactive === true) { + items.push({ + title: t('Console'), + key: 'console', + component: Console, + }); + } return items; } } diff --git a/src/stores/zun/containers.js b/src/stores/zun/containers.js index de9dc1b6..5463a6d9 100644 --- a/src/stores/zun/containers.js +++ b/src/stores/zun/containers.js @@ -98,6 +98,11 @@ export class ContainersStore extends Base { return this.client.execute(id, data); } + @action + async attach(id) { + return this.client.attach(id); + } + @action async attachNetwork(id, data) { return this.client.network_attach(id, null, data);