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