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