1<template>
2  <div>
3    <header id="page-header">
4      <a role="link" class="link-skip-nav btn btn-light" href="#main-content">
5        {{ $t('appHeader.skipToContent') }}
6      </a>
7
8      <b-navbar
9        variant="dark"
10        type="dark"
11        :aria-label="$t('appHeader.applicationHeader')"
12      >
13        <!-- Left aligned nav items -->
14        <b-button
15          id="app-header-trigger"
16          class="nav-trigger"
17          aria-hidden="true"
18          title="Open navigation"
19          type="button"
20          variant="link"
21          :class="{ open: isNavigationOpen }"
22          @click="toggleNavigation"
23        >
24          <icon-close v-if="isNavigationOpen" />
25          <icon-menu v-if="!isNavigationOpen" />
26        </b-button>
27        <b-navbar-nav>
28          <img
29            class="header-logo"
30            src="@/assets/images/logo-header.svg"
31            :alt="altLogo"
32          />
33        </b-navbar-nav>
34        <!-- Right aligned nav items -->
35        <b-navbar-nav class="ml-auto helper-menu">
36          <b-nav-item to="/health/event-logs">
37            <status-icon :status="healthStatusIcon" />
38            {{ $t('appHeader.health') }}
39          </b-nav-item>
40          <b-nav-item to="/control/server-power-operations">
41            <status-icon :status="hostStatusIcon" />
42            {{ $t('appHeader.power') }}
43          </b-nav-item>
44          <!-- Using LI elements instead of b-nav-item to support semantic button elements -->
45          <li class="nav-item">
46            <b-button id="app-header-refresh" variant="link" @click="refresh">
47              <icon-renew />
48              <span class="responsive-text">{{ $t('appHeader.refresh') }}</span>
49            </b-button>
50          </li>
51          <li class="nav-item">
52            <b-dropdown id="app-header-user" variant="link" right>
53              <template v-slot:button-content>
54                <icon-avatar />
55                <span class="responsive-text">{{ username }}</span>
56              </template>
57              <b-dropdown-item to="/profile-settings"
58                >{{ $t('appHeader.profileSettings') }}
59              </b-dropdown-item>
60              <b-dropdown-item @click="logout">{{
61                $t('appHeader.logOut')
62              }}</b-dropdown-item>
63            </b-dropdown>
64          </li>
65        </b-navbar-nav>
66      </b-navbar>
67    </header>
68    <loading-bar />
69  </div>
70</template>
71
72<script>
73import IconAvatar from '@carbon/icons-vue/es/user--avatar/20';
74import IconClose from '@carbon/icons-vue/es/close/20';
75import IconMenu from '@carbon/icons-vue/es/menu/20';
76import IconRenew from '@carbon/icons-vue/es/renew/20';
77import StatusIcon from '../Global/StatusIcon';
78import LoadingBar from '../Global/LoadingBar';
79
80export default {
81  name: 'AppHeader',
82  components: {
83    IconAvatar,
84    IconClose,
85    IconMenu,
86    IconRenew,
87    StatusIcon,
88    LoadingBar
89  },
90  data() {
91    return {
92      isNavigationOpen: false,
93      altLogo: `${process.env.VUE_APP_COMPANY_NAME} logo`
94    };
95  },
96  computed: {
97    hostStatus() {
98      return this.$store.getters['global/hostStatus'];
99    },
100    healthStatus() {
101      return this.$store.getters['eventLog/healthStatus'];
102    },
103    hostStatusIcon() {
104      switch (this.hostStatus) {
105        case 'on':
106          return 'success';
107        case 'error':
108          return 'danger';
109        case 'diagnosticMode':
110          return 'warning';
111        case 'off':
112        default:
113          return 'secondary';
114      }
115    },
116    healthStatusIcon() {
117      switch (this.healthStatus) {
118        case 'OK':
119          return 'success';
120        case 'Warning':
121          return 'warning';
122        case 'Critical':
123          return 'danger';
124        default:
125          return 'secondary';
126      }
127    },
128    username() {
129      return this.$store.getters['global/username'];
130    }
131  },
132  created() {
133    this.getHostInfo();
134    this.getEvents();
135  },
136  mounted() {
137    this.$root.$on(
138      'change:isNavigationOpen',
139      isNavigationOpen => (this.isNavigationOpen = isNavigationOpen)
140    );
141  },
142  methods: {
143    getHostInfo() {
144      this.$store.dispatch('global/getHostStatus');
145    },
146    getEvents() {
147      this.$store.dispatch('eventLog/getEventLogData');
148    },
149    refresh() {
150      this.$emit('refresh');
151    },
152    logout() {
153      this.$store.dispatch('authentication/logout');
154    },
155    toggleNavigation() {
156      this.$root.$emit('toggle:navigation');
157    }
158  }
159};
160</script>
161
162<style lang="scss">
163@import 'src/assets/styles/helpers';
164
165.app-header {
166  .link-skip-nav {
167    position: absolute;
168    top: -60px;
169    left: 0.5rem;
170    z-index: $zindex-popover;
171    transition: $duration--moderate-01 $exit-easing--expressive;
172    &:focus {
173      top: 0.5rem;
174      transition-timing-function: $entrance-easing--expressive;
175    }
176  }
177  .navbar-dark {
178    .navbar-text,
179    .nav-link,
180    .btn-link {
181      color: $white !important;
182      fill: currentColor;
183    }
184  }
185
186  .nav-item {
187    fill: theme-color('light');
188  }
189
190  .navbar {
191    padding: 0;
192    @include media-breakpoint-up($responsive-layout-bp) {
193      height: $header-height;
194    }
195
196    .btn-link {
197      padding: $spacer / 2;
198    }
199
200    .header-logo {
201      width: auto;
202      height: $header-height;
203      padding: $spacer/2 0;
204    }
205
206    .helper-menu {
207      @include media-breakpoint-down(sm) {
208        background-color: gray('800');
209        width: 100%;
210        justify-content: flex-end;
211
212        .nav-link,
213        .btn {
214          padding: $spacer / 1.125 $spacer / 2;
215        }
216      }
217
218      .responsive-text {
219        @include media-breakpoint-down(xs) {
220          display: none;
221        }
222      }
223    }
224  }
225
226  .navbar-nav {
227    padding: 0 $spacer;
228  }
229
230  .nav-trigger {
231    fill: theme-color('light');
232    width: $header-height;
233    height: $header-height;
234    transition: none;
235
236    svg {
237      margin: 0;
238    }
239
240    &:hover {
241      fill: theme-color('light');
242      background-color: theme-color('dark');
243    }
244
245    &.open {
246      background-color: gray('800');
247    }
248
249    @include media-breakpoint-up($responsive-layout-bp) {
250      display: none;
251    }
252  }
253
254  .dropdown {
255    .dropdown-menu {
256      margin-top: 0;
257      @include media-breakpoint-up(md) {
258        margin-top: 7px;
259      }
260    }
261  }
262
263  .navbar-expand {
264    @include media-breakpoint-down(sm) {
265      flex-flow: wrap;
266    }
267  }
268}
269</style>
270