1<template>
2  <div>
3    <div class="nav-container" :class="{ open: isNavigationOpen }">
4      <nav ref="nav" :aria-label="$t('appNavigation.primaryNavigation')">
5        <b-nav vertical class="mb-4">
6          <b-nav-item to="/" data-test-id="nav-container-overview">
7            <icon-overview />
8            {{ $t('appNavigation.overview') }}
9          </b-nav-item>
10
11          <li class="nav-item">
12            <b-button
13              v-b-toggle.health-menu
14              variant="link"
15              data-test-id="nav-button-health"
16            >
17              <icon-health />
18              {{ $t('appNavigation.health') }}
19              <icon-expand class="icon-expand" />
20            </b-button>
21            <b-collapse id="health-menu" tag="ul" class="nav-item__nav">
22              <b-nav-item
23                to="/health/event-logs"
24                data-test-id="nav-container-event-logs"
25              >
26                {{ $t('appNavigation.eventLogs') }}
27              </b-nav-item>
28              <b-nav-item
29                to="/health/hardware-status"
30                data-test-id="nav-container-hardware-status"
31              >
32                {{ $t('appNavigation.hardwareStatus') }}
33              </b-nav-item>
34              <b-nav-item
35                to="/health/sensors"
36                data-test-id="nav-container-sensors"
37              >
38                {{ $t('appNavigation.sensors') }}
39              </b-nav-item>
40            </b-collapse>
41          </li>
42
43          <li class="nav-item">
44            <b-button
45              v-b-toggle.control-menu
46              variant="link"
47              data-test-id="nav-button-control"
48            >
49              <icon-control />
50              {{ $t('appNavigation.control') }}
51              <icon-expand class="icon-expand" />
52            </b-button>
53            <b-collapse id="control-menu" tag="ul" class="nav-item__nav">
54              <b-nav-item to="/control/kvm" data-test-id="nav-container-kvm">
55                {{ $t('appNavigation.kvm') }}
56              </b-nav-item>
57              <b-nav-item
58                to="/control/manage-power-usage"
59                data-test-id="nav-container-managePowerUsage"
60              >
61                {{ $t('appNavigation.managePowerUsage') }}
62              </b-nav-item>
63              <b-nav-item
64                to="/control/reboot-bmc"
65                data-test-id="nav-container-rebootBmc"
66              >
67                {{ $t('appNavigation.rebootBmc') }}
68              </b-nav-item>
69              <b-nav-item
70                to="/control/serial-over-lan"
71                data-test-id="nav-container-sol"
72              >
73                {{ $t('appNavigation.serialOverLan') }}
74              </b-nav-item>
75              <b-nav-item
76                to="/control/server-led"
77                data-test-id="nav-container-serverLed"
78              >
79                {{ $t('appNavigation.serverLed') }}
80              </b-nav-item>
81              <b-nav-item
82                to="/control/server-power-operations"
83                data-test-id="nav-container-serverPowerOperations"
84              >
85                {{ $t('appNavigation.serverPowerOperations') }}
86              </b-nav-item>
87              <b-nav-item to="/control/virtual-media">
88                {{ $t('appNavigation.virtualMedia') }}
89              </b-nav-item>
90            </b-collapse>
91          </li>
92
93          <li class="nav-item">
94            <b-button
95              v-b-toggle.configuration-menu
96              variant="link"
97              data-test-id="nav-button-configuration"
98            >
99              <icon-configuration />
100              {{ $t('appNavigation.configuration') }}
101              <icon-expand class="icon-expand" />
102            </b-button>
103            <b-collapse id="configuration-menu" tag="ul" class="nav-item__nav">
104              <b-nav-item
105                to="/configuration/date-time-settings"
106                data-test-id="nav-container-dateTimeSettings"
107              >
108                {{ $t('appNavigation.dateTimeSettings') }}
109              </b-nav-item>
110              <b-nav-item
111                to="/configuration/firmware"
112                data-test-id="nav-container-firmware"
113              >
114                {{ $t('appNavigation.firmware') }}
115              </b-nav-item>
116              <b-nav-item
117                to="/configuration/network-settings"
118                data-test-id="nav-container-networkSettings"
119              >
120                {{ $t('appNavigation.networkSettings') }}
121              </b-nav-item>
122              <b-nav-item
123                href="javascript:void(0)"
124                data-test-id="nav-container-snmp"
125              >
126                {{ $t('appNavigation.snmpSettings') }}
127              </b-nav-item>
128            </b-collapse>
129          </li>
130
131          <li class="nav-item">
132            <b-button
133              v-b-toggle.access-control-menu
134              variant="link"
135              data-test-id="nav-button-accessControl"
136            >
137              <icon-access-control />
138              {{ $t('appNavigation.accessControl') }}
139              <icon-expand class="icon-expand" />
140            </b-button>
141            <b-collapse id="access-control-menu" tag="ul" class="nav-item__nav">
142              <b-nav-item
143                to="/access-control/ldap"
144                data-test-id="nav-container-ldap"
145              >
146                {{ $t('appNavigation.ldap') }}
147              </b-nav-item>
148              <b-nav-item
149                to="/access-control/local-user-management"
150                data-test-id="nav-container-localUserManagement"
151              >
152                {{ $t('appNavigation.localUserManagement') }}
153              </b-nav-item>
154              <b-nav-item
155                to="/access-control/ssl-certificates"
156                data-test-id="nav-container-sslCertificates"
157              >
158                {{ $t('appNavigation.sslCertificates') }}
159              </b-nav-item>
160            </b-collapse>
161          </li>
162        </b-nav>
163      </nav>
164    </div>
165    <transition name="fade">
166      <div
167        v-if="isNavigationOpen"
168        id="nav-overlay"
169        class="nav-overlay"
170        @click="toggleIsOpen"
171      ></div>
172    </transition>
173  </div>
174</template>
175
176<script>
177import IconAnalytics from '@carbon/icons-vue/es/analytics/16';
178import IconDataCheck from '@carbon/icons-vue/es/data--check/16';
179import IconSettingsAdjust from '@carbon/icons-vue/es/settings--adjust/16';
180import IconSettings from '@carbon/icons-vue/es/settings/16';
181import IconPassword from '@carbon/icons-vue/es/password/16';
182import IconChevronUp from '@carbon/icons-vue/es/chevron--up/16';
183
184export default {
185  name: 'AppNavigation',
186  components: {
187    iconOverview: IconAnalytics,
188    iconHealth: IconDataCheck,
189    iconControl: IconSettingsAdjust,
190    iconConfiguration: IconSettings,
191    iconAccessControl: IconPassword,
192    iconExpand: IconChevronUp
193  },
194  data() {
195    return {
196      isNavigationOpen: false
197    };
198  },
199  watch: {
200    $route: function() {
201      this.isNavigationOpen = false;
202    },
203    isNavigationOpen: function(isNavigationOpen) {
204      this.$root.$emit('change:isNavigationOpen', isNavigationOpen);
205    }
206  },
207  mounted() {
208    this.$root.$on('toggle:navigation', () => this.toggleIsOpen());
209  },
210  methods: {
211    toggleIsOpen() {
212      this.isNavigationOpen = !this.isNavigationOpen;
213    }
214  }
215};
216</script>
217
218<style scoped lang="scss">
219svg {
220  fill: currentColor;
221  height: 1.2rem;
222  width: 1.2rem;
223  margin-left: 0 !important; //!important overriding button specificity
224  vertical-align: text-bottom;
225  &:not(.icon-expand) {
226    margin-right: $spacer;
227  }
228}
229
230.nav {
231  padding-top: $spacer / 4;
232  @include media-breakpoint-up($responsive-layout-bp) {
233    padding-top: $spacer;
234  }
235}
236
237.nav-item__nav {
238  list-style: none;
239  padding-left: 0;
240  margin-left: 0;
241
242  .nav-item {
243    outline: none;
244  }
245
246  .nav-link {
247    padding-left: $spacer * 4;
248    outline: none;
249
250    &:not(.nav-link--current) {
251      font-weight: normal;
252    }
253  }
254}
255
256.btn-link {
257  width: 100%;
258  text-align: left;
259  text-decoration: none !important;
260  border-radius: 0;
261
262  &.collapsed {
263    .icon-expand {
264      transform: rotate(180deg);
265    }
266  }
267}
268
269.icon-expand {
270  float: right;
271  margin-top: $spacer / 4;
272}
273
274.btn-link,
275.nav-link {
276  position: relative;
277  font-weight: $headings-font-weight;
278  padding-left: $spacer; // defining consistent padding for links and buttons
279  padding-right: $spacer;
280  color: theme-color('secondary');
281
282  &:hover {
283    background-color: gray('300');
284    color: theme-color('dark');
285  }
286
287  &:focus {
288    box-shadow: $btn-focus-box-shadow;
289    color: theme-color('dark');
290  }
291}
292
293.nav-link--current,
294.nav-link--current:hover,
295.nav-link--current:focus {
296  font-weight: $headings-font-weight;
297  background-color: theme-color('secondary');
298  color: theme-color('light');
299  cursor: default;
300
301  &::before {
302    content: '';
303    position: absolute;
304    top: 0;
305    bottom: 0;
306    left: 0;
307    width: 4px;
308    background-color: theme-color('primary');
309  }
310}
311
312.nav-container {
313  position: fixed;
314  width: $navigation-width;
315  top: $header-height;
316  bottom: 0;
317  left: 0;
318  z-index: $zindex-fixed;
319  overflow-y: auto;
320  background-color: gray('100');
321  transform: translateX(-$navigation-width);
322  transition: transform $exit-easing--productive $duration--moderate-02;
323  @include media-breakpoint-down(md) {
324    z-index: $zindex-fixed + 2;
325  }
326
327  &.open,
328  &:focus-within {
329    transform: translateX(0);
330    transition-timing-function: $entrance-easing--productive;
331  }
332
333  @include media-breakpoint-up($responsive-layout-bp) {
334    transition-duration: $duration--fast-01;
335    transform: translateX(0);
336  }
337}
338
339.nav-overlay {
340  position: fixed;
341  top: $header-height;
342  bottom: 0;
343  left: 0;
344  right: 0;
345  z-index: $zindex-fixed + 1;
346  background-color: $black;
347  opacity: 0.5;
348
349  &.fade-enter-active {
350    transition: opacity $duration--moderate-02 $entrance-easing--productive;
351  }
352
353  &.fade-leave-active {
354    transition: opacity $duration--fast-02 $exit-easing--productive;
355  }
356
357  &.fade-enter,
358  &.fade-leave-to {
359    opacity: 0;
360  }
361
362  @include media-breakpoint-up($responsive-layout-bp) {
363    display: none;
364  }
365}
366</style>
367