1<template>
2  <div :class="isFullWindow ? 'full-window-container' : 'terminal-container'">
3    <b-row class="d-flex">
4      <b-col class="d-flex flex-column justify-content-end">
5        <dl class="mb-2" sm="6" md="6">
6          <dt class="d-inline font-weight-bold mr-1">
7            {{ $t('pageSerialOverLan.status') }}:
8          </dt>
9          <dd class="d-inline">
10            <status-icon :status="serverStatusIcon" /> {{ connectionStatus }}
11          </dd>
12        </dl>
13      </b-col>
14
15      <b-col v-if="!isFullWindow" class="d-flex justify-content-end">
16        <b-button variant="link" type="button" @click="openConsoleWindow()">
17          <icon-launch />
18          {{ $t('pageSerialOverLan.openNewTab') }}
19        </b-button>
20      </b-col>
21    </b-row>
22    <div id="terminal" ref="panel"></div>
23  </div>
24</template>
25
26<script>
27import { AttachAddon } from 'xterm-addon-attach';
28import { FitAddon } from 'xterm-addon-fit';
29import { Terminal } from 'xterm';
30import { throttle } from 'lodash';
31import IconLaunch from '@carbon/icons-vue/es/launch/20';
32import StatusIcon from '@/components/Global/StatusIcon';
33
34export default {
35  name: 'SerialOverLanConsole',
36  components: {
37    IconLaunch,
38    StatusIcon,
39  },
40  props: {
41    isFullWindow: {
42      type: Boolean,
43      default: true,
44    },
45  },
46  data() {
47    return {
48      resizeConsoleWindow: null,
49    };
50  },
51  computed: {
52    serverStatus() {
53      return this.$store.getters['global/serverStatus'];
54    },
55    serverStatusIcon() {
56      return this.serverStatus === 'on' ? 'success' : 'danger';
57    },
58    connectionStatus() {
59      return this.serverStatus === 'on'
60        ? this.$t('pageSerialOverLan.connected')
61        : this.$t('pageSerialOverLan.disconnected');
62    },
63  },
64  created() {
65    this.$store.dispatch('global/getServerStatus');
66  },
67  mounted() {
68    this.openTerminal();
69  },
70  beforeDestroy() {
71    window.removeEventListener('resize', this.resizeConsoleWindow);
72  },
73  methods: {
74    openTerminal() {
75      const token = this.$store.getters['authentication/token'];
76
77      const ws = new WebSocket(`wss://${window.location.host}/console0`, [
78        token,
79      ]);
80
81      // Refer https://github.com/xtermjs/xterm.js/ for xterm implementation and addons.
82
83      const term = new Terminal({
84        fontSize: 15,
85        fontFamily:
86          'SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace',
87      });
88
89      const attachAddon = new AttachAddon(ws);
90      term.loadAddon(attachAddon);
91
92      const fitAddon = new FitAddon();
93      term.loadAddon(fitAddon);
94
95      const SOL_THEME = {
96        background: '#19273c',
97        cursor: 'rgba(83, 146, 255, .5)',
98        scrollbar: 'rgba(83, 146, 255, .5)',
99      };
100      term.setOption('theme', SOL_THEME);
101
102      term.open(this.$refs.panel);
103      fitAddon.fit();
104
105      this.resizeConsoleWindow = throttle(() => {
106        fitAddon.fit();
107      }, 1000);
108      window.addEventListener('resize', this.resizeConsoleWindow);
109
110      try {
111        ws.onopen = function () {
112          console.log('websocket console0/ opened');
113        };
114        ws.onclose = function (event) {
115          console.log(
116            'websocket console0/ closed. code: ' +
117              event.code +
118              ' reason: ' +
119              event.reason
120          );
121        };
122      } catch (error) {
123        console.log(error);
124      }
125    },
126    openConsoleWindow() {
127      window.open(
128        '#/console/serial-over-lan-console',
129        '_blank',
130        'directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,scrollbars=no,resizable=yes,width=600,height=550'
131      );
132    },
133  },
134};
135</script>
136
137<style lang="scss" scoped>
138@import '~xterm/css/xterm.css';
139
140#terminal {
141  overflow: auto;
142}
143
144.full-window-container {
145  width: 97%;
146  margin: 1.5%;
147}
148</style>
149