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