blob: 1ea6771276042806c335b2423f2bcf757b2ddbcc [file] [log] [blame]
Mateusz Gapski632de222020-07-09 09:21:33 +02001<template>
Mateusz Gapski96b37af2020-09-04 14:11:55 +02002 <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">
jason westoverd36ac8a2025-11-03 20:58:59 -06007 <dt class="d-inline fw-bold me-1">{{ $t('pageKvm.status') }}:</dt>
Mateusz Gapski96b37af2020-09-04 14:11:55 +02008 <dd class="d-inline">
Derick Montague71114fe2021-05-06 18:17:34 -05009 <status-icon :status="serverStatusIcon" />
10 <span class="d-none d-md-inline"> {{ serverStatus }}</span>
Mateusz Gapski96b37af2020-09-04 14:11:55 +020011 </dd>
12 </dl>
13 </b-col>
14
jason westoverd36ac8a2025-11-03 20:58:59 -060015 <b-col class="d-flex justify-content-end pe-1">
Mateusz Gapski96b37af2020-09-04 14:11:55 +020016 <b-button
17 v-if="isConnected"
18 variant="link"
19 type="button"
Mateusz Gapski96b37af2020-09-04 14:11:55 +020020 @click="sendCtrlAltDel"
21 >
Dixsie Wolmers30f11f82020-11-10 16:07:56 -060022 <icon-arrow-down />
Mateusz Gapski96b37af2020-09-04 14:11:55 +020023 {{ $t('pageKvm.buttonCtrlAltDelete') }}
24 </b-button>
25 <b-button
26 v-if="!isFullWindow"
27 variant="link"
28 type="button"
Mateusz Gapski96b37af2020-09-04 14:11:55 +020029 @click="openConsoleWindow()"
30 >
Dixsie Wolmers30f11f82020-11-10 16:07:56 -060031 <icon-launch />
32 {{ $t('pageKvm.openNewTab') }}
Mateusz Gapski96b37af2020-09-04 14:11:55 +020033 </b-button>
34 </b-col>
35 </b-row>
36 </div>
37 <div id="terminal-kvm" ref="panel" :class="terminalClass"></div>
Mateusz Gapski632de222020-07-09 09:21:33 +020038 </div>
39</template>
40
41<script>
42import RFB from '@novnc/novnc/core/rfb';
Mateusz Gapski96b37af2020-09-04 14:11:55 +020043import StatusIcon from '@/components/Global/StatusIcon';
44import IconLaunch from '@carbon/icons-vue/es/launch/20';
45import IconArrowDown from '@carbon/icons-vue/es/arrow--down/16';
Konstantin Aladyshev69e8ec52021-02-22 14:07:57 +030046import { throttle } from 'lodash';
Surya Vde23ea22024-07-11 15:19:46 +053047import { useI18n } from 'vue-i18n';
48import i18n from '@/i18n';
Mateusz Gapski96b37af2020-09-04 14:11:55 +020049
50const Connecting = 0;
51const Connected = 1;
52const Disconnected = 2;
Mateusz Gapski632de222020-07-09 09:21:33 +020053
54export default {
55 name: 'KvmConsole',
Mateusz Gapski96b37af2020-09-04 14:11:55 +020056 components: { StatusIcon, IconLaunch, IconArrowDown },
57 props: {
58 isFullWindow: {
59 type: Boolean,
Derick Montague602e98a2020-10-21 16:20:00 -050060 default: true,
61 },
Mateusz Gapski96b37af2020-09-04 14:11:55 +020062 },
Mateusz Gapski632de222020-07-09 09:21:33 +020063 data() {
64 return {
Surya Vde23ea22024-07-11 15:19:46 +053065 $t: useI18n().t,
Mateusz Gapski632de222020-07-09 09:21:33 +020066 rfb: null,
67 isConnected: false,
Mateusz Gapski96b37af2020-09-04 14:11:55 +020068 terminalClass: this.isFullWindow ? 'full-window' : '',
69 marginClass: this.isFullWindow ? 'margin-left-full-window' : '',
70 status: Connecting,
Derick Montague602e98a2020-10-21 16:20:00 -050071 convasRef: null,
Konstantin Aladyshev69e8ec52021-02-22 14:07:57 +030072 resizeKvmWindow: null,
Mateusz Gapski632de222020-07-09 09:21:33 +020073 };
74 },
Mateusz Gapski96b37af2020-09-04 14:11:55 +020075 computed: {
Derick Montague71114fe2021-05-06 18:17:34 -050076 serverStatusIcon() {
Mateusz Gapski96b37af2020-09-04 14:11:55 +020077 if (this.status === Connected) {
78 return 'success';
79 } else if (this.status === Disconnected) {
80 return 'danger';
81 }
82 return 'secondary';
83 },
Derick Montague71114fe2021-05-06 18:17:34 -050084 serverStatus() {
Mateusz Gapski96b37af2020-09-04 14:11:55 +020085 if (this.status === Connected) {
Surya Vde23ea22024-07-11 15:19:46 +053086 return i18n.global.t('pageKvm.connected');
Mateusz Gapski96b37af2020-09-04 14:11:55 +020087 } else if (this.status === Disconnected) {
Surya Vde23ea22024-07-11 15:19:46 +053088 return i18n.global.t('pageKvm.disconnected');
Mateusz Gapski96b37af2020-09-04 14:11:55 +020089 }
Surya Vde23ea22024-07-11 15:19:46 +053090 return i18n.global.t('pageKvm.connecting');
Derick Montague602e98a2020-10-21 16:20:00 -050091 },
Mateusz Gapski96b37af2020-09-04 14:11:55 +020092 },
kirankumarb07e78d10b2023-03-03 12:10:29 +053093 created() {
94 this.$store.dispatch('global/getSystemInfo');
95 },
Mateusz Gapski632de222020-07-09 09:21:33 +020096 mounted() {
97 this.openTerminal();
98 },
Ed Tanous7d6b44c2024-03-23 14:56:34 -070099 beforeUnmount() {
Konstantin Aladyshev69e8ec52021-02-22 14:07:57 +0300100 window.removeEventListener('resize', this.resizeKvmWindow);
Lei YU6641cc42021-06-18 19:22:57 +0800101 this.closeTerminal();
Konstantin Aladyshev69e8ec52021-02-22 14:07:57 +0300102 },
Mateusz Gapski632de222020-07-09 09:21:33 +0200103 methods: {
104 sendCtrlAltDel() {
105 this.rfb.sendCtrlAltDel();
106 },
Lei YU6641cc42021-06-18 19:22:57 +0800107 closeTerminal() {
108 this.rfb.disconnect();
109 this.rfb = null;
110 },
Mateusz Gapski632de222020-07-09 09:21:33 +0200111 openTerminal() {
112 const token = this.$store.getters['authentication/token'];
113 this.rfb = new RFB(
114 this.$refs.panel,
115 `wss://${window.location.host}/kvm/0`,
Ed Tanous81323992024-02-27 11:26:24 -0800116 { wsProtocols: [token] },
Mateusz Gapski632de222020-07-09 09:21:33 +0200117 );
118
119 this.rfb.scaleViewport = true;
Mateusz Gapski96b37af2020-09-04 14:11:55 +0200120 this.rfb.clipViewport = true;
Mateusz Gapski632de222020-07-09 09:21:33 +0200121 const that = this;
Mateusz Gapski96b37af2020-09-04 14:11:55 +0200122
Konstantin Aladyshev69e8ec52021-02-22 14:07:57 +0300123 this.resizeKvmWindow = throttle(() => {
Mateusz Gapski96b37af2020-09-04 14:11:55 +0200124 setTimeout(that.setWidthToolbar, 0);
Konstantin Aladyshev69e8ec52021-02-22 14:07:57 +0300125 }, 1000);
jason westoverd36ac8a2025-11-03 20:58:59 -0600126 window.addEventListener('resize', this.resizeKvmWindow, {
127 passive: true,
128 });
Mateusz Gapski96b37af2020-09-04 14:11:55 +0200129
Mateusz Gapski632de222020-07-09 09:21:33 +0200130 this.rfb.addEventListener('connect', () => {
131 that.isConnected = true;
Mateusz Gapski96b37af2020-09-04 14:11:55 +0200132 that.status = Connected;
133 that.setWidthToolbar();
Mateusz Gapski632de222020-07-09 09:21:33 +0200134 });
135
136 this.rfb.addEventListener('disconnect', () => {
Mateusz Gapski96b37af2020-09-04 14:11:55 +0200137 this.isConnected = false;
138 that.status = Disconnected;
Mateusz Gapski632de222020-07-09 09:21:33 +0200139 });
Mateusz Gapski96b37af2020-09-04 14:11:55 +0200140 },
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() {
Konstantinfb6c6de2023-06-14 17:23:14 +0300152 // If consoleWindow is not null
kirankumarb07b89eed22023-01-12 15:50:30 +0530153 // Check the newly opened window is closed or not
Konstantinfb6c6de2023-06-14 17:23:14 +0300154 if (this.$eventBus.$consoleWindow) {
kirankumarb07b89eed22023-01-12 15:50:30 +0530155 // If window is not closed set focus to new window
156 // If window is closed, do open new window
Konstantinfb6c6de2023-06-14 17:23:14 +0300157 if (!this.$eventBus.$consoleWindow.closed) {
158 this.$eventBus.$consoleWindow.focus();
kirankumarb07b89eed22023-01-12 15:50:30 +0530159 return;
160 } else {
161 this.openNewWindow();
162 }
163 } else {
Konstantinfb6c6de2023-06-14 17:23:14 +0300164 // If consoleWindow is null, open new window
kirankumarb07b89eed22023-01-12 15:50:30 +0530165 this.openNewWindow();
166 }
167 },
168 openNewWindow() {
Konstantinfb6c6de2023-06-14 17:23:14 +0300169 this.$eventBus.$consoleWindow = window.open(
Mateusz Gapski96b37af2020-09-04 14:11:55 +0200170 '#/console/kvm',
kirankumarb07b89eed22023-01-12 15:50:30 +0530171 'kvmConsoleWindow',
Ed Tanous81323992024-02-27 11:26:24 -0800172 'directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,scrollbars=no,resizable=yes,width=700,height=550',
Mateusz Gapski96b37af2020-09-04 14:11:55 +0200173 );
Derick Montague602e98a2020-10-21 16:20:00 -0500174 },
175 },
Mateusz Gapski632de222020-07-09 09:21:33 +0200176};
177</script>
178
suryav972424b377d2025-01-24 15:06:35 +0530179<style scoped lang="scss">
Mateusz Gapski632de222020-07-09 09:21:33 +0200180.button-ctrl-alt-delete {
jason westoverd36ac8a2025-11-03 20:58:59 -0600181 float: inline-end;
Mateusz Gapski632de222020-07-09 09:21:33 +0200182}
183
184.kvm-status {
jason westoverd36ac8a2025-11-03 20:58:59 -0600185 padding-top: calc(#{$spacer} / 2);
186 padding-inline-start: calc(#{$spacer} / 4);
Mateusz Gapski632de222020-07-09 09:21:33 +0200187 display: inline-block;
188}
Mateusz Gapski96b37af2020-09-04 14:11:55 +0200189
190.margin-left-full-window {
jason westoverd36ac8a2025-11-03 20:58:59 -0600191 margin-inline-start: 5px;
Mateusz Gapski96b37af2020-09-04 14:11:55 +0200192}
Mateusz Gapski632de222020-07-09 09:21:33 +0200193</style>