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 IconAvatar from '@carbon/icons-vue/es/user--avatar/20'; 98import IconClose from '@carbon/icons-vue/es/close/20'; 99import IconMenu from '@carbon/icons-vue/es/menu/20'; 100import IconRenew from '@carbon/icons-vue/es/renew/20'; 101import StatusIcon from '@/components/Global/StatusIcon'; 102import LoadingBar from '@/components/Global/LoadingBar'; 103 104export default { 105 name: 'AppHeader', 106 components: { 107 IconAvatar, 108 IconClose, 109 IconMenu, 110 IconRenew, 111 StatusIcon, 112 LoadingBar 113 }, 114 data() { 115 return { 116 isNavigationOpen: false, 117 altLogo: `${process.env.VUE_APP_COMPANY_NAME} logo` 118 }; 119 }, 120 computed: { 121 hostStatus() { 122 return this.$store.getters['global/hostStatus']; 123 }, 124 healthStatus() { 125 return this.$store.getters['eventLog/healthStatus']; 126 }, 127 hostStatusIcon() { 128 switch (this.hostStatus) { 129 case 'on': 130 return 'success'; 131 case 'error': 132 return 'danger'; 133 case 'diagnosticMode': 134 return 'warning'; 135 case 'off': 136 default: 137 return 'secondary'; 138 } 139 }, 140 healthStatusIcon() { 141 switch (this.healthStatus) { 142 case 'OK': 143 return 'success'; 144 case 'Warning': 145 return 'warning'; 146 case 'Critical': 147 return 'danger'; 148 default: 149 return 'secondary'; 150 } 151 }, 152 username() { 153 return this.$store.getters['global/username']; 154 } 155 }, 156 created() { 157 this.getHostInfo(); 158 this.getEvents(); 159 }, 160 mounted() { 161 this.$root.$on( 162 'change:isNavigationOpen', 163 isNavigationOpen => (this.isNavigationOpen = isNavigationOpen) 164 ); 165 }, 166 methods: { 167 getHostInfo() { 168 this.$store.dispatch('global/getHostStatus'); 169 }, 170 getEvents() { 171 this.$store.dispatch('eventLog/getEventLogData'); 172 }, 173 refresh() { 174 this.$emit('refresh'); 175 }, 176 logout() { 177 this.$store.dispatch('authentication/logout'); 178 }, 179 toggleNavigation() { 180 this.$root.$emit('toggle:navigation'); 181 } 182 } 183}; 184</script> 185 186<style lang="scss"> 187.app-header { 188 .link-skip-nav { 189 position: absolute; 190 top: -60px; 191 left: 0.5rem; 192 z-index: $zindex-popover; 193 transition: $duration--moderate-01 $exit-easing--expressive; 194 &:focus { 195 top: 0.5rem; 196 transition-timing-function: $entrance-easing--expressive; 197 } 198 } 199 .navbar-dark { 200 .navbar-text, 201 .nav-link, 202 .btn-link { 203 color: theme-color('light') !important; 204 fill: currentColor; 205 } 206 } 207 208 .nav-item { 209 fill: theme-color('light'); 210 } 211 212 .navbar { 213 padding: 0; 214 background-color: $navbar-color; 215 @include media-breakpoint-up($responsive-layout-bp) { 216 height: $header-height; 217 } 218 219 .btn-link { 220 padding: $spacer / 2; 221 } 222 223 .header-logo { 224 width: auto; 225 height: $header-height; 226 padding: $spacer/2 0; 227 } 228 229 .helper-menu { 230 @include media-breakpoint-down(sm) { 231 background-color: gray('800'); 232 width: 100%; 233 justify-content: flex-end; 234 235 .nav-link, 236 .btn { 237 padding: $spacer / 1.125 $spacer / 2; 238 } 239 } 240 241 .responsive-text { 242 @include media-breakpoint-down(xs) { 243 display: none; 244 } 245 } 246 } 247 } 248 249 .navbar-nav { 250 padding: 0 $spacer; 251 } 252 253 .nav-trigger { 254 fill: theme-color('light'); 255 width: $header-height; 256 height: $header-height; 257 transition: none; 258 259 svg { 260 margin: 0; 261 } 262 263 &:hover { 264 fill: theme-color('light'); 265 background-color: theme-color('dark'); 266 } 267 268 &.open { 269 background-color: gray('800'); 270 } 271 272 @include media-breakpoint-up($responsive-layout-bp) { 273 display: none; 274 } 275 } 276 277 .dropdown { 278 .dropdown-menu { 279 margin-top: 0; 280 @include media-breakpoint-up(md) { 281 margin-top: 7px; 282 } 283 } 284 } 285 286 .navbar-expand { 287 @include media-breakpoint-down(sm) { 288 flex-flow: wrap; 289 } 290 } 291} 292</style> 293