1<template> 2 <div :class="marginClass"> 3 <div ref="toolbar" class="kvm-toolbar"> 4 <b-row class="d-flex"> 5 <b-col class="d-flex flex-column justify-content-end" cols="4"> 6 <dl class="mb-2" sm="2" md="2"> 7 <dt class="d-inline font-weight-bold mr-1"> 8 {{ $t('pageKvm.status') }}: 9 </dt> 10 <dd class="d-inline"> 11 <status-icon :status="serverStatusIcon" /> 12 <span class="d-none d-md-inline"> {{ serverStatus }}</span> 13 </dd> 14 </dl> 15 </b-col> 16 17 <b-col class="d-flex justify-content-end pr-1"> 18 <b-button 19 v-if="isConnected" 20 variant="link" 21 type="button" 22 @click="sendCtrlAltDel" 23 > 24 <icon-arrow-down /> 25 {{ $t('pageKvm.buttonCtrlAltDelete') }} 26 </b-button> 27 <b-button 28 v-if="!isFullWindow" 29 variant="link" 30 type="button" 31 @click="openConsoleWindow()" 32 > 33 <icon-launch /> 34 {{ $t('pageKvm.openNewTab') }} 35 </b-button> 36 </b-col> 37 </b-row> 38 </div> 39 <div id="terminal-kvm" ref="panel" :class="terminalClass"></div> 40 </div> 41</template> 42 43<script> 44import RFB from '@novnc/novnc/core/rfb'; 45import StatusIcon from '@/components/Global/StatusIcon'; 46import IconLaunch from '@carbon/icons-vue/es/launch/20'; 47import IconArrowDown from '@carbon/icons-vue/es/arrow--down/16'; 48import { throttle } from 'lodash'; 49import { mapState } from 'vuex'; 50 51const Connecting = 0; 52const Connected = 1; 53const Disconnected = 2; 54 55export default { 56 name: 'KvmConsole', 57 components: { StatusIcon, IconLaunch, IconArrowDown }, 58 props: { 59 isFullWindow: { 60 type: Boolean, 61 default: true, 62 }, 63 }, 64 data() { 65 return { 66 isConsoleWindow: null, 67 rfb: null, 68 isConnected: false, 69 terminalClass: this.isFullWindow ? 'full-window' : '', 70 marginClass: this.isFullWindow ? 'margin-left-full-window' : '', 71 status: Connecting, 72 convasRef: null, 73 resizeKvmWindow: null, 74 }; 75 }, 76 computed: { 77 ...mapState('authentication', ['consoleWindow']), 78 serverStatusIcon() { 79 if (this.status === Connected) { 80 return 'success'; 81 } else if (this.status === Disconnected) { 82 return 'danger'; 83 } 84 return 'secondary'; 85 }, 86 serverStatus() { 87 if (this.status === Connected) { 88 return this.$t('pageKvm.connected'); 89 } else if (this.status === Disconnected) { 90 return this.$t('pageKvm.disconnected'); 91 } 92 return this.$t('pageKvm.connecting'); 93 }, 94 }, 95 watch: { 96 consoleWindow() { 97 if (this.consoleWindow == false) this.isConsoleWindow.close(); 98 }, 99 }, 100 created() { 101 this.$store.dispatch('global/getSystemInfo'); 102 }, 103 mounted() { 104 this.openTerminal(); 105 }, 106 beforeDestroy() { 107 window.removeEventListener('resize', this.resizeKvmWindow); 108 this.closeTerminal(); 109 }, 110 methods: { 111 sendCtrlAltDel() { 112 this.rfb.sendCtrlAltDel(); 113 }, 114 closeTerminal() { 115 this.rfb.disconnect(); 116 this.rfb = null; 117 }, 118 openTerminal() { 119 const token = this.$store.getters['authentication/token']; 120 this.rfb = new RFB( 121 this.$refs.panel, 122 `wss://${window.location.host}/kvm/0`, 123 { wsProtocols: [token] } 124 ); 125 126 this.rfb.scaleViewport = true; 127 this.rfb.clipViewport = true; 128 const that = this; 129 130 this.resizeKvmWindow = throttle(() => { 131 setTimeout(that.setWidthToolbar, 0); 132 }, 1000); 133 window.addEventListener('resize', this.resizeKvmWindow); 134 135 this.rfb.addEventListener('connect', () => { 136 that.isConnected = true; 137 that.status = Connected; 138 that.setWidthToolbar(); 139 }); 140 141 this.rfb.addEventListener('disconnect', () => { 142 this.isConnected = false; 143 that.status = Disconnected; 144 }); 145 }, 146 setWidthToolbar() { 147 if ( 148 this.$refs.panel.children && 149 this.$refs.panel.children.length > 0 && 150 this.$refs.panel.children[0].children.length > 0 151 ) { 152 this.$refs.toolbar.style.width = 153 this.$refs.panel.children[0].children[0].clientWidth - 10 + 'px'; 154 } 155 }, 156 openConsoleWindow() { 157 // If isConsoleWindow is not null 158 // Check the newly opened window is closed or not 159 if (this.isConsoleWindow) { 160 // If window is not closed set focus to new window 161 // If window is closed, do open new window 162 if (!this.isConsoleWindow.closed) { 163 this.isConsoleWindow.focus(); 164 return; 165 } else { 166 this.openNewWindow(); 167 } 168 } else { 169 // If isConsoleWindow is null, open new window 170 this.openNewWindow(); 171 } 172 }, 173 openNewWindow() { 174 this.isConsoleWindow = window.open( 175 '#/console/kvm', 176 'kvmConsoleWindow', 177 'directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,scrollbars=no,resizable=yes,width=700,height=550' 178 ); 179 }, 180 }, 181}; 182</script> 183 184<style scoped lang="scss"> 185.button-ctrl-alt-delete { 186 float: right; 187} 188 189.kvm-status { 190 padding-top: $spacer / 2; 191 padding-left: $spacer / 4; 192 display: inline-block; 193} 194 195.margin-left-full-window { 196 margin-left: 5px; 197} 198</style> 199