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.app-header {
164  .link-skip-nav {
165    position: absolute;
166    top: -60px;
167    left: 0.5rem;
168    z-index: $zindex-popover;
169    transition: $duration--moderate-01 $exit-easing--expressive;
170    &:focus {
171      top: 0.5rem;
172      transition-timing-function: $entrance-easing--expressive;
173    }
174  }
175  .navbar-dark {
176    .navbar-text,
177    .nav-link,
178    .btn-link {
179      color: $white !important;
180      fill: currentColor;
181    }
182  }
183
184  .nav-item {
185    fill: theme-color('light');
186  }
187
188  .navbar {
189    padding: 0;
190    @include media-breakpoint-up($responsive-layout-bp) {
191      height: $header-height;
192    }
193
194    .btn-link {
195      padding: $spacer / 2;
196    }
197
198    .header-logo {
199      width: auto;
200      height: $header-height;
201      padding: $spacer/2 0;
202    }
203
204    .helper-menu {
205      @include media-breakpoint-down(sm) {
206        background-color: gray('800');
207        width: 100%;
208        justify-content: flex-end;
209
210        .nav-link,
211        .btn {
212          padding: $spacer / 1.125 $spacer / 2;
213        }
214      }
215
216      .responsive-text {
217        @include media-breakpoint-down(xs) {
218          display: none;
219        }
220      }
221    }
222  }
223
224  .navbar-nav {
225    padding: 0 $spacer;
226  }
227
228  .nav-trigger {
229    fill: theme-color('light');
230    width: $header-height;
231    height: $header-height;
232    transition: none;
233
234    svg {
235      margin: 0;
236    }
237
238    &:hover {
239      fill: theme-color('light');
240      background-color: theme-color('dark');
241    }
242
243    &.open {
244      background-color: gray('800');
245    }
246
247    @include media-breakpoint-up($responsive-layout-bp) {
248      display: none;
249    }
250  }
251
252  .dropdown {
253    .dropdown-menu {
254      margin-top: 0;
255      @include media-breakpoint-up(md) {
256        margin-top: 7px;
257      }
258    }
259  }
260
261  .navbar-expand {
262    @include media-breakpoint-down(sm) {
263      flex-flow: wrap;
264    }
265  }
266}
267</style>
268