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 { useI18n } from 'vue-i18n'; 50import i18n from '@/i18n'; 51 52const Connecting = 0; 53const Connected = 1; 54const Disconnected = 2; 55 56export default { 57 name: 'KvmConsole', 58 components: { StatusIcon, IconLaunch, IconArrowDown }, 59 props: { 60 isFullWindow: { 61 type: Boolean, 62 default: true, 63 }, 64 }, 65 data() { 66 return { 67 $t: useI18n().t, 68 rfb: null, 69 isConnected: false, 70 terminalClass: this.isFullWindow ? 'full-window' : '', 71 marginClass: this.isFullWindow ? 'margin-left-full-window' : '', 72 status: Connecting, 73 convasRef: null, 74 resizeKvmWindow: null, 75 }; 76 }, 77 computed: { 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 i18n.global.t('pageKvm.connected'); 89 } else if (this.status === Disconnected) { 90 return i18n.global.t('pageKvm.disconnected'); 91 } 92 return i18n.global.t('pageKvm.connecting'); 93 }, 94 }, 95 created() { 96 this.$store.dispatch('global/getSystemInfo'); 97 }, 98 mounted() { 99 this.openTerminal(); 100 }, 101 beforeUnmount() { 102 window.removeEventListener('resize', this.resizeKvmWindow); 103 this.closeTerminal(); 104 }, 105 methods: { 106 sendCtrlAltDel() { 107 this.rfb.sendCtrlAltDel(); 108 }, 109 closeTerminal() { 110 this.rfb.disconnect(); 111 this.rfb = null; 112 }, 113 openTerminal() { 114 const token = this.$store.getters['authentication/token']; 115 this.rfb = new RFB( 116 this.$refs.panel, 117 `wss://${window.location.host}/kvm/0`, 118 { wsProtocols: [token] }, 119 ); 120 121 this.rfb.scaleViewport = true; 122 this.rfb.clipViewport = true; 123 const that = this; 124 125 this.resizeKvmWindow = throttle(() => { 126 setTimeout(that.setWidthToolbar, 0); 127 }, 1000); 128 window.addEventListener('resize', this.resizeKvmWindow); 129 130 this.rfb.addEventListener('connect', () => { 131 that.isConnected = true; 132 that.status = Connected; 133 that.setWidthToolbar(); 134 }); 135 136 this.rfb.addEventListener('disconnect', () => { 137 this.isConnected = false; 138 that.status = Disconnected; 139 }); 140 }, 141 setWidthToolbar() { 142 if ( 143 this.$refs.panel.children && 144 this.$refs.panel.children.length > 0 && 145 this.$refs.panel.children[0].children.length > 0 146 ) { 147 this.$refs.toolbar.style.width = 148 this.$refs.panel.children[0].children[0].clientWidth - 10 + 'px'; 149 } 150 }, 151 openConsoleWindow() { 152 // If consoleWindow is not null 153 // Check the newly opened window is closed or not 154 if (this.$eventBus.$consoleWindow) { 155 // If window is not closed set focus to new window 156 // If window is closed, do open new window 157 if (!this.$eventBus.$consoleWindow.closed) { 158 this.$eventBus.$consoleWindow.focus(); 159 return; 160 } else { 161 this.openNewWindow(); 162 } 163 } else { 164 // If consoleWindow is null, open new window 165 this.openNewWindow(); 166 } 167 }, 168 openNewWindow() { 169 this.$eventBus.$consoleWindow = window.open( 170 '#/console/kvm', 171 'kvmConsoleWindow', 172 'directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,scrollbars=no,resizable=yes,width=700,height=550', 173 ); 174 }, 175 }, 176}; 177</script> 178 179<style lang="scss" scoped> 180@import '@/assets/styles/bmc/helpers/_index.scss'; 181@import '@/assets/styles/bootstrap/_helpers.scss'; 182 183.button-ctrl-alt-delete { 184 float: right; 185} 186 187.kvm-status { 188 padding-top: $spacer / 2; 189 padding-left: $spacer / 4; 190 display: inline-block; 191} 192 193.margin-left-full-window { 194 margin-left: 5px; 195} 196</style> 197