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