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