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