xref: /openbmc/webui-vue/src/views/Operations/SerialOverLan/SerialOverLanConsole.vue (revision 24b377db47a05f742b1f3db77606f6bae845f637)
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';
53import { useI18n } from 'vue-i18n';
54
55export default {
56  name: 'SerialOverLanConsole',
57  components: {
58    Alert,
59    IconLaunch,
60    StatusIcon,
61  },
62  props: {
63    isFullWindow: {
64      type: Boolean,
65      default: true,
66    },
67  },
68  data() {
69    return {
70      $t: useI18n().t,
71      resizeConsoleWindow: null,
72    };
73  },
74  computed: {
75    serverStatus() {
76      return this.$store.getters['global/serverStatus'];
77    },
78    connection() {
79      return this.serverStatus === 'off' ? false : true;
80    },
81    serverStatusIcon() {
82      return this.connection ? 'success' : 'danger';
83    },
84  },
85  created() {
86    this.$store.dispatch('global/getSystemInfo');
87  },
88  mounted() {
89    this.openTerminal();
90  },
91  beforeUnmount() {
92    window.removeEventListener('resize', this.resizeConsoleWindow);
93    this.closeTerminal();
94  },
95  methods: {
96    openTerminal() {
97      const token = this.$store.getters['authentication/token'];
98      this.ws = new WebSocket(`wss://${window.location.host}/console/default`, [
99        token,
100      ]);
101
102      // Refer https://github.com/xtermjs/xterm.js/ for xterm implementation and addons.
103
104      this.term = new Terminal({
105        fontSize: 15,
106        fontFamily:
107          'SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace',
108      });
109
110      const attachAddon = new AttachAddon(this.ws);
111      this.term.loadAddon(attachAddon);
112
113      const fitAddon = new FitAddon();
114      this.term.loadAddon(fitAddon);
115
116      const SOL_THEME = {
117        background: '#19273c',
118        cursor: 'rgba(83, 146, 255, .5)',
119        scrollbar: 'rgba(83, 146, 255, .5)',
120      };
121      this.term.setOption('theme', SOL_THEME);
122
123      this.term.open(this.$refs.panel);
124      fitAddon.fit();
125
126      this.resizeConsoleWindow = throttle(() => {
127        fitAddon.fit();
128      }, 1000);
129      window.addEventListener('resize', this.resizeConsoleWindow);
130
131      try {
132        this.ws.onopen = function () {
133          console.log('websocket console/default opened');
134        };
135        this.ws.onclose = function (event) {
136          console.log(
137            'websocket console/default closed. code: ' +
138              event.code +
139              ' reason: ' +
140              event.reason,
141          );
142        };
143      } catch (error) {
144        console.log(error);
145      }
146    },
147    closeTerminal() {
148      console.log('closeTerminal');
149      this.term.dispose();
150      this.term = null;
151      this.ws.close();
152      this.ws = null;
153    },
154    openConsoleWindow() {
155      window.open(
156        '#/console/serial-over-lan-console',
157        '_blank',
158        'directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,scrollbars=no,resizable=yes,width=600,height=550',
159      );
160    },
161  },
162};
163</script>
164
165<style lang="scss" scoped>
166@import '~xterm/css/xterm.css';
167
168#terminal {
169  overflow: auto;
170}
171
172.full-window-container {
173  width: 97%;
174  margin: 1.5%;
175}
176</style>
177