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