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'; 49 50const Connecting = 0; 51const Connected = 1; 52const Disconnected = 2; 53 54export default { 55 name: 'KvmConsole', 56 components: { StatusIcon, IconLaunch, IconArrowDown }, 57 props: { 58 isFullWindow: { 59 type: Boolean, 60 default: true, 61 }, 62 }, 63 data() { 64 return { 65 rfb: null, 66 isConnected: false, 67 terminalClass: this.isFullWindow ? 'full-window' : '', 68 marginClass: this.isFullWindow ? 'margin-left-full-window' : '', 69 status: Connecting, 70 convasRef: null, 71 resizeKvmWindow: null, 72 }; 73 }, 74 computed: { 75 serverStatusIcon() { 76 if (this.status === Connected) { 77 return 'success'; 78 } else if (this.status === Disconnected) { 79 return 'danger'; 80 } 81 return 'secondary'; 82 }, 83 serverStatus() { 84 if (this.status === Connected) { 85 return this.$t('pageKvm.connected'); 86 } else if (this.status === Disconnected) { 87 return this.$t('pageKvm.disconnected'); 88 } 89 return this.$t('pageKvm.connecting'); 90 }, 91 }, 92 mounted() { 93 this.openTerminal(); 94 }, 95 beforeDestroy() { 96 window.removeEventListener('resize', this.resizeKvmWindow); 97 this.closeTerminal(); 98 }, 99 methods: { 100 sendCtrlAltDel() { 101 this.rfb.sendCtrlAltDel(); 102 }, 103 closeTerminal() { 104 this.rfb.disconnect(); 105 this.rfb = null; 106 }, 107 openTerminal() { 108 const token = this.$store.getters['authentication/token']; 109 this.rfb = new RFB( 110 this.$refs.panel, 111 `wss://${window.location.host}/kvm/0`, 112 { wsProtocols: [token] } 113 ); 114 115 this.rfb.scaleViewport = true; 116 this.rfb.clipViewport = true; 117 const that = this; 118 119 this.resizeKvmWindow = throttle(() => { 120 setTimeout(that.setWidthToolbar, 0); 121 }, 1000); 122 window.addEventListener('resize', this.resizeKvmWindow); 123 124 this.rfb.addEventListener('connect', () => { 125 that.isConnected = true; 126 that.status = Connected; 127 that.setWidthToolbar(); 128 }); 129 130 this.rfb.addEventListener('disconnect', () => { 131 this.isConnected = false; 132 that.status = Disconnected; 133 }); 134 }, 135 setWidthToolbar() { 136 if ( 137 this.$refs.panel.children && 138 this.$refs.panel.children.length > 0 && 139 this.$refs.panel.children[0].children.length > 0 140 ) { 141 this.$refs.toolbar.style.width = 142 this.$refs.panel.children[0].children[0].clientWidth - 10 + 'px'; 143 } 144 }, 145 openConsoleWindow() { 146 window.open( 147 '#/console/kvm', 148 '_blank', 149 'directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,scrollbars=no,resizable=yes,width=700,height=550' 150 ); 151 }, 152 }, 153}; 154</script> 155 156<style scoped lang="scss"> 157.button-ctrl-alt-delete { 158 float: right; 159} 160 161.kvm-status { 162 padding-top: $spacer / 2; 163 padding-left: $spacer / 4; 164 display: inline-block; 165} 166 167.margin-left-full-window { 168 margin-left: 5px; 169} 170</style> 171