xref: /openbmc/webui-vue/src/components/AppHeader/AppHeader.vue (revision 1f8117f810a87e563aa2e33c67a7779dc0542a0d)
1a2988f40SDerick Montague<template>
2a2988f40SDerick Montague  <div>
36859203cSDerick Montague    <header id="page-header">
46859203cSDerick Montague      <a role="link" class="link-skip-nav btn btn-light" href="#main-content">
5e0b76c33SYoshie Muranaka        {{ $t('appHeader.skipToContent') }}
6dc04feb5SYoshie Muranaka      </a>
76859203cSDerick Montague
821d6de00SMateusz Gapski      <b-navbar type="dark" :aria-label="$t('appHeader.applicationHeader')">
9dc04feb5SYoshie Muranaka        <!-- Left aligned nav items -->
1074f8687dSYoshie Muranaka        <b-button
116859203cSDerick Montague          id="app-header-trigger"
1274f8687dSYoshie Muranaka          class="nav-trigger"
1374f8687dSYoshie Muranaka          aria-hidden="true"
1474f8687dSYoshie Muranaka          type="button"
1574f8687dSYoshie Muranaka          variant="link"
16057232b8SSurenNeware          :class="{ open: isNavigationOpen }"
1774f8687dSYoshie Muranaka          @click="toggleNavigation"
1874f8687dSYoshie Muranaka        >
19a5cbc449SSurenNeware          <icon-close
20a5cbc449SSurenNeware            v-if="isNavigationOpen"
21a5cbc449SSurenNeware            :title="$t('appHeader.titleHideNavigation')"
22a5cbc449SSurenNeware          />
23a5cbc449SSurenNeware          <icon-menu
24a5cbc449SSurenNeware            v-if="!isNavigationOpen"
25a5cbc449SSurenNeware            :title="$t('appHeader.titleShowNavigation')"
26a5cbc449SSurenNeware          />
2774f8687dSYoshie Muranaka        </b-button>
28dc04feb5SYoshie Muranaka        <b-navbar-nav>
29*1f8117f8SSurenNeware          <b-navbar-brand to="/" data-test-id="appHeader-container-overview">
3003505916SMateusz Gapski            <img
3103505916SMateusz Gapski              class="header-logo"
3203505916SMateusz Gapski              src="@/assets/images/logo-header.svg"
3303505916SMateusz Gapski              :alt="altLogo"
3403505916SMateusz Gapski            />
35*1f8117f8SSurenNeware          </b-navbar-brand>
36b8b6f791SYoshie Muranaka        </b-navbar-nav>
37dc04feb5SYoshie Muranaka        <!-- Right aligned nav items -->
38057232b8SSurenNeware        <b-navbar-nav class="ml-auto helper-menu">
39965cf673SDerick Montague          <b-nav-item
40965cf673SDerick Montague            to="/health/event-logs"
41965cf673SDerick Montague            data-test-id="appHeader-container-health"
42965cf673SDerick Montague          >
431ace1d91SYoshie Muranaka            <status-icon :status="healthStatusIcon" />
44057232b8SSurenNeware            {{ $t('appHeader.health') }}
45b8b6f791SYoshie Muranaka          </b-nav-item>
46965cf673SDerick Montague          <b-nav-item
47965cf673SDerick Montague            to="/control/server-power-operations"
48965cf673SDerick Montague            data-test-id="appHeader-container-power"
49965cf673SDerick Montague          >
50dc04feb5SYoshie Muranaka            <status-icon :status="hostStatusIcon" />
51057232b8SSurenNeware            {{ $t('appHeader.power') }}
52b8b6f791SYoshie Muranaka          </b-nav-item>
536859203cSDerick Montague          <!-- Using LI elements instead of b-nav-item to support semantic button elements -->
546859203cSDerick Montague          <li class="nav-item">
55965cf673SDerick Montague            <b-button
56965cf673SDerick Montague              id="app-header-refresh"
57965cf673SDerick Montague              variant="link"
58965cf673SDerick Montague              data-test-id="appHeader-button-refresh"
59965cf673SDerick Montague              @click="refresh"
60965cf673SDerick Montague            >
61a5cbc449SSurenNeware              <icon-renew :title="$t('appHeader.titleRefresh')" />
62057232b8SSurenNeware              <span class="responsive-text">{{ $t('appHeader.refresh') }}</span>
636859203cSDerick Montague            </b-button>
646859203cSDerick Montague          </li>
65b1f559f0SSukanya Pandey          <li class="nav-item">
66965cf673SDerick Montague            <b-dropdown
67965cf673SDerick Montague              id="app-header-user"
68965cf673SDerick Montague              variant="link"
69965cf673SDerick Montague              right
70965cf673SDerick Montague              data-test-id="appHeader-container-user"
71965cf673SDerick Montague            >
72b1f559f0SSukanya Pandey              <template v-slot:button-content>
73a5cbc449SSurenNeware                <icon-avatar :title="$t('appHeader.titleProfile')" />
74057232b8SSurenNeware                <span class="responsive-text">{{ username }}</span>
75b1f559f0SSukanya Pandey              </template>
76965cf673SDerick Montague              <b-dropdown-item
77965cf673SDerick Montague                to="/profile-settings"
78965cf673SDerick Montague                data-test-id="appHeader-link-profile"
79b1f559f0SSukanya Pandey                >{{ $t('appHeader.profileSettings') }}
80b1f559f0SSukanya Pandey              </b-dropdown-item>
81965cf673SDerick Montague              <b-dropdown-item
82965cf673SDerick Montague                data-test-id="appHeader-link-logout"
83965cf673SDerick Montague                @click="logout"
84965cf673SDerick Montague              >
85965cf673SDerick Montague                {{ $t('appHeader.logOut') }}
86965cf673SDerick Montague              </b-dropdown-item>
87b1f559f0SSukanya Pandey            </b-dropdown>
886859203cSDerick Montague          </li>
89b8b6f791SYoshie Muranaka        </b-navbar-nav>
90a2988f40SDerick Montague      </b-navbar>
91a2988f40SDerick Montague    </header>
923be801aaSYoshie Muranaka    <loading-bar />
93a2988f40SDerick Montague  </div>
94a2988f40SDerick Montague</template>
95a2988f40SDerick Montague
96a2988f40SDerick Montague<script>
97dd6aa0aaSSukanya Pandeyimport BVToastMixin from '@/components/Mixins/BVToastMixin';
98e2fd1567SDerick Montagueimport IconAvatar from '@carbon/icons-vue/es/user--avatar/20';
9974f8687dSYoshie Muranakaimport IconClose from '@carbon/icons-vue/es/close/20';
10074f8687dSYoshie Muranakaimport IconMenu from '@carbon/icons-vue/es/menu/20';
101e2fd1567SDerick Montagueimport IconRenew from '@carbon/icons-vue/es/renew/20';
10261859097SSurenNewareimport StatusIcon from '@/components/Global/StatusIcon';
10361859097SSurenNewareimport LoadingBar from '@/components/Global/LoadingBar';
10474f8687dSYoshie Muranaka
105a2988f40SDerick Montagueexport default {
106e2fd1567SDerick Montague  name: 'AppHeader',
1073be801aaSYoshie Muranaka  components: {
1083be801aaSYoshie Muranaka    IconAvatar,
1093be801aaSYoshie Muranaka    IconClose,
1103be801aaSYoshie Muranaka    IconMenu,
1113be801aaSYoshie Muranaka    IconRenew,
1123be801aaSYoshie Muranaka    StatusIcon,
1133be801aaSYoshie Muranaka    LoadingBar
1143be801aaSYoshie Muranaka  },
115dd6aa0aaSSukanya Pandey  mixins: [BVToastMixin],
11674f8687dSYoshie Muranaka  data() {
11774f8687dSYoshie Muranaka    return {
11803505916SMateusz Gapski      isNavigationOpen: false,
11903505916SMateusz Gapski      altLogo: `${process.env.VUE_APP_COMPANY_NAME} logo`
12074f8687dSYoshie Muranaka    };
12174f8687dSYoshie Muranaka  },
122b8b6f791SYoshie Muranaka  computed: {
123dd6aa0aaSSukanya Pandey    isAuthorized() {
124dd6aa0aaSSukanya Pandey      return this.$store.getters['global/isAuthorized'];
125dd6aa0aaSSukanya Pandey    },
126b8b6f791SYoshie Muranaka    hostStatus() {
127e2fd1567SDerick Montague      return this.$store.getters['global/hostStatus'];
128dc04feb5SYoshie Muranaka    },
1291ace1d91SYoshie Muranaka    healthStatus() {
1301ace1d91SYoshie Muranaka      return this.$store.getters['eventLog/healthStatus'];
1311ace1d91SYoshie Muranaka    },
132dc04feb5SYoshie Muranaka    hostStatusIcon() {
133dc04feb5SYoshie Muranaka      switch (this.hostStatus) {
134e2fd1567SDerick Montague        case 'on':
135e2fd1567SDerick Montague          return 'success';
136e2fd1567SDerick Montague        case 'error':
137e2fd1567SDerick Montague          return 'danger';
138a3cbc659SYoshie Muranaka        case 'diagnosticMode':
139a3cbc659SYoshie Muranaka          return 'warning';
140e2fd1567SDerick Montague        case 'off':
141dc04feb5SYoshie Muranaka        default:
142e2fd1567SDerick Montague          return 'secondary';
143dc04feb5SYoshie Muranaka      }
1441ace1d91SYoshie Muranaka    },
1451ace1d91SYoshie Muranaka    healthStatusIcon() {
1461ace1d91SYoshie Muranaka      switch (this.healthStatus) {
147ce9a3ef3SYoshie Muranaka        case 'OK':
1481ace1d91SYoshie Muranaka          return 'success';
149ce9a3ef3SYoshie Muranaka        case 'Warning':
1501ace1d91SYoshie Muranaka          return 'warning';
151ce9a3ef3SYoshie Muranaka        case 'Critical':
1521ace1d91SYoshie Muranaka          return 'danger';
1531ace1d91SYoshie Muranaka        default:
1541ace1d91SYoshie Muranaka          return 'secondary';
1551ace1d91SYoshie Muranaka      }
156b1f559f0SSukanya Pandey    },
157b1f559f0SSukanya Pandey    username() {
158b1f559f0SSukanya Pandey      return this.$store.getters['global/username'];
159b8b6f791SYoshie Muranaka    }
160b8b6f791SYoshie Muranaka  },
161dd6aa0aaSSukanya Pandey  watch: {
162dd6aa0aaSSukanya Pandey    isAuthorized(value) {
163dd6aa0aaSSukanya Pandey      if (value === false) {
164dd6aa0aaSSukanya Pandey        this.errorToast(
165dd6aa0aaSSukanya Pandey          this.$t('global.toast.unAuthDescription'),
166dd6aa0aaSSukanya Pandey          this.$t('global.toast.unAuthTitle')
167dd6aa0aaSSukanya Pandey        );
168dd6aa0aaSSukanya Pandey      }
169dd6aa0aaSSukanya Pandey    }
170dd6aa0aaSSukanya Pandey  },
17109e45cd4SDerick Montague  created() {
172d624dae9SYoshie Muranaka    // Reset auth state to check if user is authenticated based
173d624dae9SYoshie Muranaka    // on available browser cookies
174d624dae9SYoshie Muranaka    this.$store.dispatch('authentication/resetStoreState');
17509e45cd4SDerick Montague    this.getHostInfo();
1761ace1d91SYoshie Muranaka    this.getEvents();
17709e45cd4SDerick Montague  },
17874f8687dSYoshie Muranaka  mounted() {
17974f8687dSYoshie Muranaka    this.$root.$on(
18074f8687dSYoshie Muranaka      'change:isNavigationOpen',
18174f8687dSYoshie Muranaka      isNavigationOpen => (this.isNavigationOpen = isNavigationOpen)
18274f8687dSYoshie Muranaka    );
18374f8687dSYoshie Muranaka  },
184b8b6f791SYoshie Muranaka  methods: {
185b8b6f791SYoshie Muranaka    getHostInfo() {
186e2fd1567SDerick Montague      this.$store.dispatch('global/getHostStatus');
187e080a1a7SDerick Montague    },
1881ace1d91SYoshie Muranaka    getEvents() {
1891ace1d91SYoshie Muranaka      this.$store.dispatch('eventLog/getEventLogData');
1901ace1d91SYoshie Muranaka    },
191eb154bbcSYoshie Muranaka    refresh() {
192eb154bbcSYoshie Muranaka      this.$emit('refresh');
193eb154bbcSYoshie Muranaka    },
194e080a1a7SDerick Montague    logout() {
195c031b698SDerick Montague      this.$store.dispatch('authentication/logout');
19674f8687dSYoshie Muranaka    },
19774f8687dSYoshie Muranaka    toggleNavigation() {
19874f8687dSYoshie Muranaka      this.$root.$emit('toggle:navigation');
199b8b6f791SYoshie Muranaka    }
200a2988f40SDerick Montague  }
201a2988f40SDerick Montague};
202a2988f40SDerick Montague</script>
203a2988f40SDerick Montague
204b1f559f0SSukanya Pandey<style lang="scss">
205b1f559f0SSukanya Pandey.app-header {
20675b48321SDerick Montague  .link-skip-nav {
20775b48321SDerick Montague    position: absolute;
20875b48321SDerick Montague    top: -60px;
20975b48321SDerick Montague    left: 0.5rem;
21074f8687dSYoshie Muranaka    z-index: $zindex-popover;
21174f8687dSYoshie Muranaka    transition: $duration--moderate-01 $exit-easing--expressive;
21275b48321SDerick Montague    &:focus {
21375b48321SDerick Montague      top: 0.5rem;
21474f8687dSYoshie Muranaka      transition-timing-function: $entrance-easing--expressive;
21575b48321SDerick Montague    }
21675b48321SDerick Montague  }
2171ace1d91SYoshie Muranaka  .navbar-text,
2186859203cSDerick Montague  .nav-link,
2196859203cSDerick Montague  .btn-link {
220*1f8117f8SSurenNeware    color: color('white') !important;
2216859203cSDerick Montague    fill: currentColor;
222*1f8117f8SSurenNeware    padding: 0.68rem 1rem !important;
223*1f8117f8SSurenNeware
224*1f8117f8SSurenNeware    &:hover {
225*1f8117f8SSurenNeware      background-color: theme-color-level(light, 10);
226*1f8117f8SSurenNeware    }
227*1f8117f8SSurenNeware    &:active {
228*1f8117f8SSurenNeware      background-color: theme-color-level(light, 9);
229*1f8117f8SSurenNeware    }
230*1f8117f8SSurenNeware    &:focus {
231*1f8117f8SSurenNeware      box-shadow: inset 0 0 0 3px $navbar-color, inset 0 0 0 5px color('white');
2321ace1d91SYoshie Muranaka    }
2331ace1d91SYoshie Muranaka  }
2346859203cSDerick Montague
235dc04feb5SYoshie Muranaka  .nav-item {
23601da8187SYoshie Muranaka    fill: theme-color('light');
237dc04feb5SYoshie Muranaka  }
23874f8687dSYoshie Muranaka
23974f8687dSYoshie Muranaka  .navbar {
24074f8687dSYoshie Muranaka    padding: 0;
24121d6de00SMateusz Gapski    background-color: $navbar-color;
242057232b8SSurenNeware    @include media-breakpoint-up($responsive-layout-bp) {
24374f8687dSYoshie Muranaka      height: $header-height;
244057232b8SSurenNeware    }
2456859203cSDerick Montague
246*1f8117f8SSurenNeware    &:focus {
247*1f8117f8SSurenNeware      outline: 0;
24803505916SMateusz Gapski    }
24903505916SMateusz Gapski
250057232b8SSurenNeware    .helper-menu {
251057232b8SSurenNeware      @include media-breakpoint-down(sm) {
25201da8187SYoshie Muranaka        background-color: gray('800');
253057232b8SSurenNeware        width: 100%;
254057232b8SSurenNeware        justify-content: flex-end;
255057232b8SSurenNeware
256057232b8SSurenNeware        .nav-link,
257057232b8SSurenNeware        .btn {
258057232b8SSurenNeware          padding: $spacer / 1.125 $spacer / 2;
259057232b8SSurenNeware        }
260057232b8SSurenNeware      }
261057232b8SSurenNeware
262057232b8SSurenNeware      .responsive-text {
263057232b8SSurenNeware        @include media-breakpoint-down(xs) {
264057232b8SSurenNeware          display: none;
265057232b8SSurenNeware        }
266057232b8SSurenNeware      }
267057232b8SSurenNeware    }
26874f8687dSYoshie Muranaka  }
26974f8687dSYoshie Muranaka
27074f8687dSYoshie Muranaka  .navbar-nav {
27174f8687dSYoshie Muranaka    padding: 0 $spacer;
272*1f8117f8SSurenNeware    align-items: center;
273*1f8117f8SSurenNeware
274*1f8117f8SSurenNeware    .navbar-brand,
275*1f8117f8SSurenNeware    .nav-link {
276*1f8117f8SSurenNeware      transition: $focus-transition;
277*1f8117f8SSurenNeware    }
278*1f8117f8SSurenNeware    &:focus {
279*1f8117f8SSurenNeware      outline: 0;
280*1f8117f8SSurenNeware    }
28174f8687dSYoshie Muranaka  }
28274f8687dSYoshie Muranaka
28374f8687dSYoshie Muranaka  .nav-trigger {
28401da8187SYoshie Muranaka    fill: theme-color('light');
28574f8687dSYoshie Muranaka    width: $header-height;
28674f8687dSYoshie Muranaka    height: $header-height;
28774f8687dSYoshie Muranaka    transition: none;
288*1f8117f8SSurenNeware    display: inline-flex;
289*1f8117f8SSurenNeware    flex: 0 0 20px;
290*1f8117f8SSurenNeware    align-items: center;
29174f8687dSYoshie Muranaka
29274f8687dSYoshie Muranaka    svg {
29374f8687dSYoshie Muranaka      margin: 0;
29474f8687dSYoshie Muranaka    }
29574f8687dSYoshie Muranaka
29674f8687dSYoshie Muranaka    &:hover {
29701da8187SYoshie Muranaka      fill: theme-color('light');
298*1f8117f8SSurenNeware      background-color: theme-color-level(light, 10);
29974f8687dSYoshie Muranaka    }
30074f8687dSYoshie Muranaka
301057232b8SSurenNeware    &.open {
30201da8187SYoshie Muranaka      background-color: gray('800');
303057232b8SSurenNeware    }
304057232b8SSurenNeware
30574f8687dSYoshie Muranaka    @include media-breakpoint-up($responsive-layout-bp) {
30674f8687dSYoshie Muranaka      display: none;
30774f8687dSYoshie Muranaka    }
308dc04feb5SYoshie Muranaka  }
309b1f559f0SSukanya Pandey
310b1f559f0SSukanya Pandey  .dropdown-menu {
311057232b8SSurenNeware    margin-top: 0;
312*1f8117f8SSurenNeware
313*1f8117f8SSurenNeware    @include media-breakpoint-only(md) {
314*1f8117f8SSurenNeware      margin-top: 4px;
315b1f559f0SSukanya Pandey    }
316b1f559f0SSukanya Pandey  }
317057232b8SSurenNeware
318057232b8SSurenNeware  .navbar-expand {
319057232b8SSurenNeware    @include media-breakpoint-down(sm) {
320057232b8SSurenNeware      flex-flow: wrap;
321057232b8SSurenNeware    }
322057232b8SSurenNeware  }
323057232b8SSurenNeware}
324*1f8117f8SSurenNeware
325*1f8117f8SSurenNeware.navbar-brand {
326*1f8117f8SSurenNeware  padding: $spacer/2;
327*1f8117f8SSurenNeware  height: $header-height;
328*1f8117f8SSurenNeware  line-height: 1;
329*1f8117f8SSurenNeware  &:focus {
330*1f8117f8SSurenNeware    box-shadow: inset 0 0 0 3px $navbar-color, inset 0 0 0 5px color('white');
331*1f8117f8SSurenNeware    outline: 0;
332*1f8117f8SSurenNeware  }
333*1f8117f8SSurenNeware}
334b8b6f791SYoshie Muranaka</style>
335