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 }, 89 methods: { 90 openTerminal() { 91 const token = this.$store.getters['authentication/token']; 92 93 const ws = new WebSocket(`wss://${window.location.host}/console0`, [ 94 token, 95 ]); 96 97 // Refer https://github.com/xtermjs/xterm.js/ for xterm implementation and addons. 98 99 const term = new Terminal({ 100 fontSize: 15, 101 fontFamily: 102 'SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace', 103 }); 104 105 const attachAddon = new AttachAddon(ws); 106 term.loadAddon(attachAddon); 107 108 const fitAddon = new FitAddon(); 109 term.loadAddon(fitAddon); 110 111 const SOL_THEME = { 112 background: '#19273c', 113 cursor: 'rgba(83, 146, 255, .5)', 114 scrollbar: 'rgba(83, 146, 255, .5)', 115 }; 116 term.setOption('theme', SOL_THEME); 117 118 term.open(this.$refs.panel); 119 fitAddon.fit(); 120 121 this.resizeConsoleWindow = throttle(() => { 122 fitAddon.fit(); 123 }, 1000); 124 window.addEventListener('resize', this.resizeConsoleWindow); 125 126 try { 127 ws.onopen = function () { 128 console.log('websocket console0/ opened'); 129 }; 130 ws.onclose = function (event) { 131 console.log( 132 'websocket console0/ closed. code: ' + 133 event.code + 134 ' reason: ' + 135 event.reason 136 ); 137 }; 138 } catch (error) { 139 console.log(error); 140 } 141 }, 142 openConsoleWindow() { 143 window.open( 144 '#/console/serial-over-lan-console', 145 '_blank', 146 'directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,scrollbars=no,resizable=yes,width=600,height=550' 147 ); 148 }, 149 }, 150}; 151</script> 152 153<style lang="scss" scoped> 154@import '~xterm/css/xterm.css'; 155 156#terminal { 157 overflow: auto; 158} 159 160.full-window-container { 161 width: 97%; 162 margin: 1.5%; 163} 164</style> 165