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          @click="toggleNavigation"
22        >
23          <icon-close v-if="isNavigationOpen" />
24          <icon-menu v-if="!isNavigationOpen" />
25        </b-button>
26        <b-navbar-nav>
27          <b-nav-text>{{ $t('appHeader.bmcSystemManagement') }}</b-nav-text>
28        </b-navbar-nav>
29        <!-- Right aligned nav items -->
30        <b-navbar-nav class="ml-auto">
31          <b-nav-item to="/health/event-logs">
32            {{ $t('appHeader.health') }}
33            <status-icon :status="healthStatusIcon" />
34          </b-nav-item>
35          <b-nav-item to="/control/server-power-operations">
36            {{ $t('appHeader.power') }}
37            <status-icon :status="hostStatusIcon" />
38          </b-nav-item>
39          <!-- Using LI elements instead of b-nav-item to support semantic button elements -->
40          <li class="nav-item">
41            <b-button id="app-header-refresh" variant="link" @click="refresh">
42              {{ $t('appHeader.refresh') }}
43              <icon-renew />
44            </b-button>
45          </li>
46          <li>
47            <b-button id="app-header-logout" variant="link" @click="logout">
48              {{ $t('appHeader.logOut') }}
49              <icon-avatar />
50            </b-button>
51          </li>
52        </b-navbar-nav>
53      </b-navbar>
54    </header>
55    <loading-bar />
56  </div>
57</template>
58
59<script>
60import IconAvatar from '@carbon/icons-vue/es/user--avatar/20';
61import IconClose from '@carbon/icons-vue/es/close/20';
62import IconMenu from '@carbon/icons-vue/es/menu/20';
63import IconRenew from '@carbon/icons-vue/es/renew/20';
64import StatusIcon from '../Global/StatusIcon';
65import LoadingBar from '../Global/LoadingBar';
66
67export default {
68  name: 'AppHeader',
69  components: {
70    IconAvatar,
71    IconClose,
72    IconMenu,
73    IconRenew,
74    StatusIcon,
75    LoadingBar
76  },
77  data() {
78    return {
79      isNavigationOpen: false
80    };
81  },
82  computed: {
83    hostStatus() {
84      return this.$store.getters['global/hostStatus'];
85    },
86    healthStatus() {
87      return this.$store.getters['eventLog/healthStatus'];
88    },
89    hostStatusIcon() {
90      switch (this.hostStatus) {
91        case 'on':
92          return 'success';
93        case 'error':
94          return 'danger';
95        case 'diagnosticMode':
96          return 'warning';
97        case 'off':
98        default:
99          return 'secondary';
100      }
101    },
102    healthStatusIcon() {
103      switch (this.healthStatus) {
104        case 'OK':
105          return 'success';
106        case 'Warning':
107          return 'warning';
108        case 'Critical':
109          return 'danger';
110        default:
111          return 'secondary';
112      }
113    }
114  },
115  created() {
116    this.getHostInfo();
117    this.getEvents();
118  },
119  mounted() {
120    this.$root.$on(
121      'change:isNavigationOpen',
122      isNavigationOpen => (this.isNavigationOpen = isNavigationOpen)
123    );
124  },
125  methods: {
126    getHostInfo() {
127      this.$store.dispatch('global/getHostStatus');
128    },
129    getEvents() {
130      this.$store.dispatch('eventLog/getEventLogData');
131    },
132    refresh() {
133      this.$emit('refresh');
134    },
135    logout() {
136      this.$store.dispatch('authentication/logout');
137    },
138    toggleNavigation() {
139      this.$root.$emit('toggle:navigation');
140    }
141  }
142};
143</script>
144
145<style lang="scss" scoped>
146@import 'src/assets/styles/helpers';
147
148.link-skip-nav {
149  position: absolute;
150  top: -60px;
151  left: 0.5rem;
152  z-index: $zindex-popover;
153  transition: $duration--moderate-01 $exit-easing--expressive;
154  &:focus {
155    top: 0.5rem;
156    transition-timing-function: $entrance-easing--expressive;
157  }
158}
159.navbar-dark {
160  .navbar-text,
161  .nav-link,
162  .btn-link {
163    color: $white !important;
164    fill: currentColor;
165  }
166}
167
168.nav-item {
169  fill: $light;
170}
171
172.navbar {
173  padding: 0;
174  height: $header-height;
175  overflow: hidden;
176
177  .btn-link {
178    padding: $spacer / 2;
179  }
180}
181
182.navbar-nav {
183  padding: 0 $spacer;
184}
185
186.nav-trigger {
187  fill: $light;
188  width: $header-height;
189  height: $header-height;
190  transition: none;
191
192  svg {
193    margin: 0;
194  }
195
196  &:hover {
197    fill: $light;
198    background-color: $dark;
199  }
200
201  @include media-breakpoint-up($responsive-layout-bp) {
202    display: none;
203  }
204}
205</style>
206