xref: /openbmc/webui-vue/src/layouts/AppLayout.vue (revision d36ac8a8be8636ddd0e64ce005d507b21bcdeb00)
1<template>
2  <div class="app-container">
3    <app-header
4      ref="focusTarget"
5      class="app-header"
6      :router-key="routerKey"
7      @refresh="refresh"
8    />
9    <app-navigation class="app-navigation" />
10    <page-container class="app-content">
11      <router-view ref="routerView" :key="routerKey" />
12      <!-- Scroll to top button -->
13      <button-back-to-top />
14    </page-container>
15  </div>
16</template>
17
18<script>
19import AppHeader from '@/components/AppHeader';
20import AppNavigation from '@/components/AppNavigation';
21import PageContainer from '@/components/Global/PageContainer';
22import ButtonBackToTop from '@/components/Global/ButtonBackToTop';
23import JumpLinkMixin from '@/components/Mixins/JumpLinkMixin';
24
25export default {
26  name: 'App',
27  components: {
28    AppHeader,
29    AppNavigation,
30    PageContainer,
31    ButtonBackToTop,
32  },
33  mixins: [JumpLinkMixin],
34  data() {
35    return {
36      routerKey: 0,
37    };
38  },
39  watch: {
40    $route: function () {
41      this.$nextTick(function () {
42        this.setFocus(this.$refs.focusTarget.$el);
43      });
44    },
45  },
46  mounted() {
47    require('@/eventBus').default.$on('refresh-application', () =>
48      this.refresh(),
49    );
50    setInterval(() => {
51      if (!localStorage.getItem('storedUsername')) {
52        this.$eventBus.$consoleWindow?.close();
53        this.refresh();
54      }
55    }, 10000);
56  },
57  beforeUnmount() {
58    require('@/eventBus').default.$off(
59      'refresh-application',
60      this.handleRefreshApplication,
61    );
62  },
63  methods: {
64    handleRefreshApplication() {
65      this.refresh();
66    },
67    refresh() {
68      // Clear all toast messages
69      document.querySelectorAll('.toast').forEach((toast) => {
70        const toastId = toast.id;
71        if (toastId) {
72          this.$bvToast.hide(toastId);
73        }
74      });
75      // Changing the component :key value will trigger
76      // a component re-rendering and 'refresh' the view
77      this.routerKey += 1;
78    },
79  },
80};
81</script>
82
83<style lang="scss" scoped>
84.app-container {
85  display: grid;
86  grid-template-columns: 100%;
87  grid-template-rows: auto;
88  grid-template-areas:
89    'header'
90    'content';
91
92  @include media-breakpoint-up($responsive-layout-bp) {
93    grid-template-columns: $navigation-width 1fr;
94    grid-template-areas:
95      'header header'
96      'navigation content';
97  }
98}
99
100.app-header {
101  grid-area: header;
102  position: sticky;
103  top: 0;
104  z-index: $zindex-fixed + 1;
105}
106
107.app-navigation {
108  grid-area: navigation;
109}
110
111.app-content {
112  grid-area: content;
113  background-color: $white;
114}
115</style>
116