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