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