xref: /openbmc/webui-vue/src/components/AppHeader/AppHeader.vue (revision 51abe87feea7261ec6f7589d8214af3d8019e71e)
1a2988f40SDerick Montague<template>
2a2988f40SDerick Montague  <div>
36859203cSDerick Montague    <header id="page-header">
480267970SDerick Montague      <a
580267970SDerick Montague        class="link-skip-nav btn btn-light"
680267970SDerick Montague        href="#main-content"
780267970SDerick Montague        @click="setFocus"
880267970SDerick Montague      >
9e0b76c33SYoshie Muranaka        {{ $t('appHeader.skipToContent') }}
10dc04feb5SYoshie Muranaka      </a>
116859203cSDerick Montague
1221d6de00SMateusz Gapski      <b-navbar type="dark" :aria-label="$t('appHeader.applicationHeader')">
13dc04feb5SYoshie Muranaka        <!-- Left aligned nav items -->
1474f8687dSYoshie Muranaka        <b-button
156859203cSDerick Montague          id="app-header-trigger"
1674f8687dSYoshie Muranaka          class="nav-trigger"
1774f8687dSYoshie Muranaka          aria-hidden="true"
1874f8687dSYoshie Muranaka          type="button"
1974f8687dSYoshie Muranaka          variant="link"
20057232b8SSurenNeware          :class="{ open: isNavigationOpen }"
2174f8687dSYoshie Muranaka          @click="toggleNavigation"
2274f8687dSYoshie Muranaka        >
23a5cbc449SSurenNeware          <icon-close
24a5cbc449SSurenNeware            v-if="isNavigationOpen"
25a5cbc449SSurenNeware            :title="$t('appHeader.titleHideNavigation')"
26a5cbc449SSurenNeware          />
27a5cbc449SSurenNeware          <icon-menu
28a5cbc449SSurenNeware            v-if="!isNavigationOpen"
29a5cbc449SSurenNeware            :title="$t('appHeader.titleShowNavigation')"
30a5cbc449SSurenNeware          />
3174f8687dSYoshie Muranaka        </b-button>
32dc04feb5SYoshie Muranaka        <b-navbar-nav>
33c5c2ae99SSukanya Pandey          <b-navbar-brand
34c5c2ae99SSukanya Pandey            class="mr-0"
35c5c2ae99SSukanya Pandey            to="/"
36c5c2ae99SSukanya Pandey            data-test-id="appHeader-container-overview"
37c5c2ae99SSukanya Pandey          >
3803505916SMateusz Gapski            <img
39*51abe87fSEd Tanous              svg-inline
4003505916SMateusz Gapski              class="header-logo"
4103505916SMateusz Gapski              src="@/assets/images/logo-header.svg"
4203505916SMateusz Gapski              :alt="altLogo"
4303505916SMateusz Gapski            />
441f8117f8SSurenNeware          </b-navbar-brand>
4514172d74Skennyneedsmilky          <div v-if="isNavTagPresent" :key="routerKey" class="pl-2 nav-tags">
464dd7eabfSSukanya Pandey            <span>|</span>
474dd7eabfSSukanya Pandey            <span class="pl-3 asset-tag">{{ assetTag }}</span>
484dd7eabfSSukanya Pandey            <span class="pl-3">{{ modelType }}</span>
494dd7eabfSSukanya Pandey            <span class="pl-3">{{ serialNumber }}</span>
50c5c2ae99SSukanya Pandey          </div>
51b8b6f791SYoshie Muranaka        </b-navbar-nav>
52dc04feb5SYoshie Muranaka        <!-- Right aligned nav items -->
53057232b8SSurenNeware        <b-navbar-nav class="ml-auto helper-menu">
54965cf673SDerick Montague          <b-nav-item
55828dda9bSDerick Montague            to="/logs/event-logs"
56965cf673SDerick Montague            data-test-id="appHeader-container-health"
57965cf673SDerick Montague          >
581ace1d91SYoshie Muranaka            <status-icon :status="healthStatusIcon" />
59057232b8SSurenNeware            {{ $t('appHeader.health') }}
60b8b6f791SYoshie Muranaka          </b-nav-item>
61965cf673SDerick Montague          <b-nav-item
6268cbbe90SSandeepa Singh            to="/operations/server-power-operations"
63965cf673SDerick Montague            data-test-id="appHeader-container-power"
64965cf673SDerick Montague          >
6571114febSDerick Montague            <status-icon :status="serverStatusIcon" />
66057232b8SSurenNeware            {{ $t('appHeader.power') }}
67b8b6f791SYoshie Muranaka          </b-nav-item>
686859203cSDerick Montague          <!-- Using LI elements instead of b-nav-item to support semantic button elements -->
696859203cSDerick Montague          <li class="nav-item">
70965cf673SDerick Montague            <b-button
71965cf673SDerick Montague              id="app-header-refresh"
72965cf673SDerick Montague              variant="link"
73965cf673SDerick Montague              data-test-id="appHeader-button-refresh"
74965cf673SDerick Montague              @click="refresh"
75965cf673SDerick Montague            >
76a5cbc449SSurenNeware              <icon-renew :title="$t('appHeader.titleRefresh')" />
77057232b8SSurenNeware              <span class="responsive-text">{{ $t('appHeader.refresh') }}</span>
786859203cSDerick Montague            </b-button>
796859203cSDerick Montague          </li>
80b1f559f0SSukanya Pandey          <li class="nav-item">
81965cf673SDerick Montague            <b-dropdown
82965cf673SDerick Montague              id="app-header-user"
83965cf673SDerick Montague              variant="link"
84965cf673SDerick Montague              right
85965cf673SDerick Montague              data-test-id="appHeader-container-user"
86965cf673SDerick Montague            >
87602e98aaSDerick Montague              <template #button-content>
88a5cbc449SSurenNeware                <icon-avatar :title="$t('appHeader.titleProfile')" />
89057232b8SSurenNeware                <span class="responsive-text">{{ username }}</span>
90b1f559f0SSukanya Pandey              </template>
91965cf673SDerick Montague              <b-dropdown-item
92965cf673SDerick Montague                to="/profile-settings"
93965cf673SDerick Montague                data-test-id="appHeader-link-profile"
94b1f559f0SSukanya Pandey                >{{ $t('appHeader.profileSettings') }}
95b1f559f0SSukanya Pandey              </b-dropdown-item>
96965cf673SDerick Montague              <b-dropdown-item
97965cf673SDerick Montague                data-test-id="appHeader-link-logout"
98965cf673SDerick Montague                @click="logout"
99965cf673SDerick Montague              >
100965cf673SDerick Montague                {{ $t('appHeader.logOut') }}
101965cf673SDerick Montague              </b-dropdown-item>
102b1f559f0SSukanya Pandey            </b-dropdown>
1036859203cSDerick Montague          </li>
104b8b6f791SYoshie Muranaka        </b-navbar-nav>
105a2988f40SDerick Montague      </b-navbar>
106a2988f40SDerick Montague    </header>
1073be801aaSYoshie Muranaka    <loading-bar />
108a2988f40SDerick Montague  </div>
109a2988f40SDerick Montague</template>
110a2988f40SDerick Montague
111a2988f40SDerick Montague<script>
112dd6aa0aaSSukanya Pandeyimport BVToastMixin from '@/components/Mixins/BVToastMixin';
113e2fd1567SDerick Montagueimport IconAvatar from '@carbon/icons-vue/es/user--avatar/20';
11474f8687dSYoshie Muranakaimport IconClose from '@carbon/icons-vue/es/close/20';
11574f8687dSYoshie Muranakaimport IconMenu from '@carbon/icons-vue/es/menu/20';
116e2fd1567SDerick Montagueimport IconRenew from '@carbon/icons-vue/es/renew/20';
11761859097SSurenNewareimport StatusIcon from '@/components/Global/StatusIcon';
11861859097SSurenNewareimport LoadingBar from '@/components/Global/LoadingBar';
119fb6c6de9SKonstantinimport { mapState } from 'vuex';
12074f8687dSYoshie Muranaka
121a2988f40SDerick Montagueexport default {
122e2fd1567SDerick Montague  name: 'AppHeader',
1233be801aaSYoshie Muranaka  components: {
1243be801aaSYoshie Muranaka    IconAvatar,
1253be801aaSYoshie Muranaka    IconClose,
1263be801aaSYoshie Muranaka    IconMenu,
1273be801aaSYoshie Muranaka    IconRenew,
1283be801aaSYoshie Muranaka    StatusIcon,
129602e98aaSDerick Montague    LoadingBar,
1303be801aaSYoshie Muranaka  },
131dd6aa0aaSSukanya Pandey  mixins: [BVToastMixin],
13214172d74Skennyneedsmilky  props: {
13300cb42b6SKenneth Fullbright    routerKey: {
13400cb42b6SKenneth Fullbright      type: Number,
13500cb42b6SKenneth Fullbright      default: 0,
13600cb42b6SKenneth Fullbright    },
13714172d74Skennyneedsmilky  },
13874f8687dSYoshie Muranaka  data() {
13974f8687dSYoshie Muranaka    return {
14003505916SMateusz Gapski      isNavigationOpen: false,
141932aff93SDerick Montague      altLogo: process.env.VUE_APP_COMPANY_NAME || 'Built on OpenBMC',
14274f8687dSYoshie Muranaka    };
14374f8687dSYoshie Muranaka  },
144b8b6f791SYoshie Muranaka  computed: {
145fb6c6de9SKonstantin    ...mapState('authentication', ['consoleWindow']),
1464dd7eabfSSukanya Pandey    isNavTagPresent() {
1474dd7eabfSSukanya Pandey      return this.assetTag || this.modelType || this.serialNumber;
1484dd7eabfSSukanya Pandey    },
149c5c2ae99SSukanya Pandey    assetTag() {
150c5c2ae99SSukanya Pandey      return this.$store.getters['global/assetTag'];
151c5c2ae99SSukanya Pandey    },
1524dd7eabfSSukanya Pandey    modelType() {
1534dd7eabfSSukanya Pandey      return this.$store.getters['global/modelType'];
1544dd7eabfSSukanya Pandey    },
1554dd7eabfSSukanya Pandey    serialNumber() {
1564dd7eabfSSukanya Pandey      return this.$store.getters['global/serialNumber'];
1574dd7eabfSSukanya Pandey    },
158dd6aa0aaSSukanya Pandey    isAuthorized() {
159dd6aa0aaSSukanya Pandey      return this.$store.getters['global/isAuthorized'];
160dd6aa0aaSSukanya Pandey    },
161aeb19816SDamian Celico    userPrivilege() {
162aeb19816SDamian Celico      return this.$store.getters['global/userPrivilege'];
163aeb19816SDamian Celico    },
16471114febSDerick Montague    serverStatus() {
16571114febSDerick Montague      return this.$store.getters['global/serverStatus'];
166dc04feb5SYoshie Muranaka    },
1671ace1d91SYoshie Muranaka    healthStatus() {
1681ace1d91SYoshie Muranaka      return this.$store.getters['eventLog/healthStatus'];
1691ace1d91SYoshie Muranaka    },
17071114febSDerick Montague    serverStatusIcon() {
17171114febSDerick Montague      switch (this.serverStatus) {
172e2fd1567SDerick Montague        case 'on':
173e2fd1567SDerick Montague          return 'success';
174e2fd1567SDerick Montague        case 'error':
175e2fd1567SDerick Montague          return 'danger';
176a3cbc659SYoshie Muranaka        case 'diagnosticMode':
177a3cbc659SYoshie Muranaka          return 'warning';
178e2fd1567SDerick Montague        case 'off':
179dc04feb5SYoshie Muranaka        default:
180e2fd1567SDerick Montague          return 'secondary';
181dc04feb5SYoshie Muranaka      }
1821ace1d91SYoshie Muranaka    },
1831ace1d91SYoshie Muranaka    healthStatusIcon() {
1841ace1d91SYoshie Muranaka      switch (this.healthStatus) {
185ce9a3ef3SYoshie Muranaka        case 'OK':
1861ace1d91SYoshie Muranaka          return 'success';
187ce9a3ef3SYoshie Muranaka        case 'Warning':
1881ace1d91SYoshie Muranaka          return 'warning';
189ce9a3ef3SYoshie Muranaka        case 'Critical':
1901ace1d91SYoshie Muranaka          return 'danger';
1911ace1d91SYoshie Muranaka        default:
1921ace1d91SYoshie Muranaka          return 'secondary';
1931ace1d91SYoshie Muranaka      }
194b1f559f0SSukanya Pandey    },
195b1f559f0SSukanya Pandey    username() {
196b1f559f0SSukanya Pandey      return this.$store.getters['global/username'];
197602e98aaSDerick Montague    },
198b8b6f791SYoshie Muranaka  },
199dd6aa0aaSSukanya Pandey  watch: {
200fb6c6de9SKonstantin    consoleWindow() {
201fb6c6de9SKonstantin      if (this.consoleWindow === false) this.$eventBus.$consoleWindow.close();
202fb6c6de9SKonstantin    },
203dd6aa0aaSSukanya Pandey    isAuthorized(value) {
204dd6aa0aaSSukanya Pandey      if (value === false) {
205f92e2969SYoshie Muranaka        this.errorToast(this.$t('global.toast.unAuthDescription'), {
206f92e2969SYoshie Muranaka          title: this.$t('global.toast.unAuthTitle'),
207f92e2969SYoshie Muranaka        });
208dd6aa0aaSSukanya Pandey      }
209602e98aaSDerick Montague    },
210dd6aa0aaSSukanya Pandey  },
21109e45cd4SDerick Montague  created() {
212d624dae9SYoshie Muranaka    // Reset auth state to check if user is authenticated based
213d624dae9SYoshie Muranaka    // on available browser cookies
214d624dae9SYoshie Muranaka    this.$store.dispatch('authentication/resetStoreState');
2154dd7eabfSSukanya Pandey    this.getSystemInfo();
2161ace1d91SYoshie Muranaka    this.getEvents();
21709e45cd4SDerick Montague  },
21874f8687dSYoshie Muranaka  mounted() {
21974f8687dSYoshie Muranaka    this.$root.$on(
220edb8a774SSukanya Pandey      'change-is-navigation-open',
2218132399cSEd Tanous      (isNavigationOpen) => (this.isNavigationOpen = isNavigationOpen),
22274f8687dSYoshie Muranaka    );
22374f8687dSYoshie Muranaka  },
224b8b6f791SYoshie Muranaka  methods: {
2254dd7eabfSSukanya Pandey    getSystemInfo() {
2264dd7eabfSSukanya Pandey      this.$store.dispatch('global/getSystemInfo');
227e080a1a7SDerick Montague    },
2281ace1d91SYoshie Muranaka    getEvents() {
2291ace1d91SYoshie Muranaka      this.$store.dispatch('eventLog/getEventLogData');
2301ace1d91SYoshie Muranaka    },
231eb154bbcSYoshie Muranaka    refresh() {
232eb154bbcSYoshie Muranaka      this.$emit('refresh');
233eb154bbcSYoshie Muranaka    },
234e080a1a7SDerick Montague    logout() {
235c031b698SDerick Montague      this.$store.dispatch('authentication/logout');
23674f8687dSYoshie Muranaka    },
23774f8687dSYoshie Muranaka    toggleNavigation() {
238edb8a774SSukanya Pandey      this.$root.$emit('toggle-navigation');
239602e98aaSDerick Montague    },
24080267970SDerick Montague    setFocus(event) {
24180267970SDerick Montague      event.preventDefault();
24280267970SDerick Montague      this.$root.$emit('skip-navigation');
24380267970SDerick Montague    },
244602e98aaSDerick Montague  },
245a2988f40SDerick Montague};
246a2988f40SDerick Montague</script>
247a2988f40SDerick Montague
248b1f559f0SSukanya Pandey<style lang="scss">
2497d4b53bcSDerick Montague@mixin focus-box-shadow($padding-color: $navbar-color, $outline-color: $white) {
2508132399cSEd Tanous  box-shadow:
2518132399cSEd Tanous    inset 0 0 0 3px $padding-color,
2528132399cSEd Tanous    inset 0 0 0 5px $outline-color;
2537d4b53bcSDerick Montague}
254b1f559f0SSukanya Pandey.app-header {
25575b48321SDerick Montague  .link-skip-nav {
25675b48321SDerick Montague    position: absolute;
25775b48321SDerick Montague    top: -60px;
25875b48321SDerick Montague    left: 0.5rem;
25974f8687dSYoshie Muranaka    z-index: $zindex-popover;
26074f8687dSYoshie Muranaka    transition: $duration--moderate-01 $exit-easing--expressive;
26175b48321SDerick Montague    &:focus {
26275b48321SDerick Montague      top: 0.5rem;
26374f8687dSYoshie Muranaka      transition-timing-function: $entrance-easing--expressive;
26475b48321SDerick Montague    }
26575b48321SDerick Montague  }
2661ace1d91SYoshie Muranaka  .navbar-text,
2676859203cSDerick Montague  .nav-link,
2686859203cSDerick Montague  .btn-link {
2691f8117f8SSurenNeware    color: color('white') !important;
2706859203cSDerick Montague    fill: currentColor;
2711f8117f8SSurenNeware    padding: 0.68rem 1rem !important;
2721f8117f8SSurenNeware
2731f8117f8SSurenNeware    &:hover {
2741f8117f8SSurenNeware      background-color: theme-color-level(light, 10);
2751f8117f8SSurenNeware    }
2761f8117f8SSurenNeware    &:active {
2771f8117f8SSurenNeware      background-color: theme-color-level(light, 9);
2781f8117f8SSurenNeware    }
2791f8117f8SSurenNeware    &:focus {
2807d4b53bcSDerick Montague      @include focus-box-shadow;
2817d4b53bcSDerick Montague      outline: 0;
2821ace1d91SYoshie Muranaka    }
2831ace1d91SYoshie Muranaka  }
2846859203cSDerick Montague
285dc04feb5SYoshie Muranaka  .nav-item {
28601da8187SYoshie Muranaka    fill: theme-color('light');
287dc04feb5SYoshie Muranaka  }
28874f8687dSYoshie Muranaka
28974f8687dSYoshie Muranaka  .navbar {
29074f8687dSYoshie Muranaka    padding: 0;
29121d6de00SMateusz Gapski    background-color: $navbar-color;
292057232b8SSurenNeware    @include media-breakpoint-up($responsive-layout-bp) {
29374f8687dSYoshie Muranaka      height: $header-height;
294057232b8SSurenNeware    }
2956859203cSDerick Montague
296057232b8SSurenNeware    .helper-menu {
297057232b8SSurenNeware      @include media-breakpoint-down(sm) {
29801da8187SYoshie Muranaka        background-color: gray('800');
299057232b8SSurenNeware        width: 100%;
300057232b8SSurenNeware        justify-content: flex-end;
301057232b8SSurenNeware
302057232b8SSurenNeware        .nav-link,
303057232b8SSurenNeware        .btn {
304057232b8SSurenNeware          padding: $spacer / 1.125 $spacer / 2;
305057232b8SSurenNeware        }
3067d4b53bcSDerick Montague
3077d4b53bcSDerick Montague        .nav-link:focus,
3087d4b53bcSDerick Montague        .btn:focus {
3097d4b53bcSDerick Montague          @include focus-box-shadow($gray-800);
3107d4b53bcSDerick Montague        }
311057232b8SSurenNeware      }
312057232b8SSurenNeware
313057232b8SSurenNeware      .responsive-text {
314057232b8SSurenNeware        @include media-breakpoint-down(xs) {
3154dd7eabfSSukanya Pandey          @include sr-only;
316057232b8SSurenNeware        }
317057232b8SSurenNeware      }
318057232b8SSurenNeware    }
31974f8687dSYoshie Muranaka  }
32074f8687dSYoshie Muranaka
32174f8687dSYoshie Muranaka  .navbar-nav {
3224dd7eabfSSukanya Pandey    @include media-breakpoint-up($responsive-layout-bp) {
32374f8687dSYoshie Muranaka      padding: 0 $spacer;
3244dd7eabfSSukanya Pandey    }
3251f8117f8SSurenNeware    align-items: center;
3261f8117f8SSurenNeware
3271f8117f8SSurenNeware    .navbar-brand,
3281f8117f8SSurenNeware    .nav-link {
3291f8117f8SSurenNeware      transition: $focus-transition;
3301f8117f8SSurenNeware    }
3314dd7eabfSSukanya Pandey    .nav-tags {
332c5c2ae99SSukanya Pandey      color: theme-color-level(light, 3);
3334dd7eabfSSukanya Pandey      @include media-breakpoint-down(xs) {
3344dd7eabfSSukanya Pandey        @include sr-only;
3354dd7eabfSSukanya Pandey      }
3364dd7eabfSSukanya Pandey      .asset-tag {
3374dd7eabfSSukanya Pandey        @include media-breakpoint-down($responsive-layout-bp) {
3384dd7eabfSSukanya Pandey          @include sr-only;
3394dd7eabfSSukanya Pandey        }
3404dd7eabfSSukanya Pandey      }
341c5c2ae99SSukanya Pandey    }
34274f8687dSYoshie Muranaka  }
34374f8687dSYoshie Muranaka
34474f8687dSYoshie Muranaka  .nav-trigger {
34501da8187SYoshie Muranaka    fill: theme-color('light');
34674f8687dSYoshie Muranaka    width: $header-height;
34774f8687dSYoshie Muranaka    height: $header-height;
34874f8687dSYoshie Muranaka    transition: none;
3491f8117f8SSurenNeware    display: inline-flex;
3501f8117f8SSurenNeware    flex: 0 0 20px;
3511f8117f8SSurenNeware    align-items: center;
35274f8687dSYoshie Muranaka
35374f8687dSYoshie Muranaka    svg {
35474f8687dSYoshie Muranaka      margin: 0;
35574f8687dSYoshie Muranaka    }
35674f8687dSYoshie Muranaka
35774f8687dSYoshie Muranaka    &:hover {
35801da8187SYoshie Muranaka      fill: theme-color('light');
3591f8117f8SSurenNeware      background-color: theme-color-level(light, 10);
36074f8687dSYoshie Muranaka    }
36174f8687dSYoshie Muranaka
362057232b8SSurenNeware    &.open {
36301da8187SYoshie Muranaka      background-color: gray('800');
364057232b8SSurenNeware    }
365057232b8SSurenNeware
36674f8687dSYoshie Muranaka    @include media-breakpoint-up($responsive-layout-bp) {
36774f8687dSYoshie Muranaka      display: none;
36874f8687dSYoshie Muranaka    }
369dc04feb5SYoshie Muranaka  }
370b1f559f0SSukanya Pandey
371b1f559f0SSukanya Pandey  .dropdown-menu {
372057232b8SSurenNeware    margin-top: 0;
3731f8117f8SSurenNeware
3741f8117f8SSurenNeware    @include media-breakpoint-only(md) {
3751f8117f8SSurenNeware      margin-top: 4px;
376b1f559f0SSukanya Pandey    }
377b1f559f0SSukanya Pandey  }
378057232b8SSurenNeware
379057232b8SSurenNeware  .navbar-expand {
380057232b8SSurenNeware    @include media-breakpoint-down(sm) {
381057232b8SSurenNeware      flex-flow: wrap;
382057232b8SSurenNeware    }
383057232b8SSurenNeware  }
384057232b8SSurenNeware}
3851f8117f8SSurenNeware
3861f8117f8SSurenNeware.navbar-brand {
3871f8117f8SSurenNeware  padding: $spacer/2;
3881f8117f8SSurenNeware  height: $header-height;
3891f8117f8SSurenNeware  line-height: 1;
3901f8117f8SSurenNeware  &:focus {
3918132399cSEd Tanous    box-shadow:
3928132399cSEd Tanous      inset 0 0 0 3px $navbar-color,
3938132399cSEd Tanous      inset 0 0 0 5px color('white');
3941f8117f8SSurenNeware    outline: 0;
3951f8117f8SSurenNeware  }
3961f8117f8SSurenNeware}
397b8b6f791SYoshie Muranaka</style>
398