1<template> 2 <div :class="isFullWindow ? 'full-window-container' : 'terminal-container'"> 3 <b-row class="d-flex"> 4 <b-col class="d-flex flex-column justify-content-end"> 5 <dl class="mb-2" sm="6" md="6"> 6 <dt class="d-inline font-weight-bold mr-1"> 7 {{ $t('pageSerialOverLan.status') }}: 8 </dt> 9 <dd class="d-inline"> 10 <status-icon :status="serverStatusIcon" /> {{ connectionStatus }} 11 </dd> 12 </dl> 13 </b-col> 14 15 <b-col v-if="!isFullWindow" class="d-flex justify-content-end"> 16 <b-button variant="link" type="button" @click="openConsoleWindow()"> 17 <icon-launch /> 18 {{ $t('pageSerialOverLan.openNewTab') }} 19 </b-button> 20 </b-col> 21 </b-row> 22 <div id="terminal" ref="panel"></div> 23 </div> 24</template> 25 26<script> 27import { AttachAddon } from 'xterm-addon-attach'; 28import { FitAddon } from 'xterm-addon-fit'; 29import { Terminal } from 'xterm'; 30import { throttle } from 'lodash'; 31import IconLaunch from '@carbon/icons-vue/es/launch/20'; 32import StatusIcon from '@/components/Global/StatusIcon'; 33 34export default { 35 name: 'SerialOverLanConsole', 36 components: { 37 IconLaunch, 38 StatusIcon, 39 }, 40 props: { 41 isFullWindow: { 42 type: Boolean, 43 default: true, 44 }, 45 }, 46 data() { 47 return { 48 resizeConsoleWindow: null, 49 }; 50 }, 51 computed: { 52 serverStatus() { 53 return this.$store.getters['global/serverStatus']; 54 }, 55 serverStatusIcon() { 56 return this.serverStatus === 'on' ? 'success' : 'danger'; 57 }, 58 connectionStatus() { 59 return this.serverStatus === 'on' 60 ? this.$t('pageSerialOverLan.connected') 61 : this.$t('pageSerialOverLan.disconnected'); 62 }, 63 }, 64 created() { 65 this.$store.dispatch('global/getServerStatus'); 66 }, 67 mounted() { 68 this.openTerminal(); 69 }, 70 beforeDestroy() { 71 window.removeEventListener('resize', this.resizeConsoleWindow); 72 }, 73 methods: { 74 openTerminal() { 75 const token = this.$store.getters['authentication/token']; 76 77 const ws = new WebSocket(`wss://${window.location.host}/console0`, [ 78 token, 79 ]); 80 81 // Refer https://github.com/xtermjs/xterm.js/ for xterm implementation and addons. 82 83 const term = new Terminal({ 84 fontSize: 15, 85 fontFamily: 86 'SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace', 87 }); 88 89 const attachAddon = new AttachAddon(ws); 90 term.loadAddon(attachAddon); 91 92 const fitAddon = new FitAddon(); 93 term.loadAddon(fitAddon); 94 95 const SOL_THEME = { 96 background: '#19273c', 97 cursor: 'rgba(83, 146, 255, .5)', 98 scrollbar: 'rgba(83, 146, 255, .5)', 99 }; 100 term.setOption('theme', SOL_THEME); 101 102 term.open(this.$refs.panel); 103 fitAddon.fit(); 104 105 this.resizeConsoleWindow = throttle(() => { 106 fitAddon.fit(); 107 }, 1000); 108 window.addEventListener('resize', this.resizeConsoleWindow); 109 110 try { 111 ws.onopen = function () { 112 console.log('websocket console0/ opened'); 113 }; 114 ws.onclose = function (event) { 115 console.log( 116 'websocket console0/ closed. code: ' + 117 event.code + 118 ' reason: ' + 119 event.reason 120 ); 121 }; 122 } catch (error) { 123 console.log(error); 124 } 125 }, 126 openConsoleWindow() { 127 window.open( 128 '#/console/serial-over-lan-console', 129 '_blank', 130 'directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,scrollbars=no,resizable=yes,width=600,height=550' 131 ); 132 }, 133 }, 134}; 135</script> 136 137<style lang="scss" scoped> 138@import '~xterm/css/xterm.css'; 139 140#terminal { 141 overflow: auto; 142} 143 144.full-window-container { 145 width: 97%; 146 margin: 1.5%; 147} 148</style> 149