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