@rancher/shell 0.3.22 → 0.3.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/assets/styles/base/_variables.scss +1 -0
  2. package/assets/styles/themes/_dark.scss +1 -0
  3. package/assets/styles/themes/_light.scss +6 -5
  4. package/assets/translations/en-us.yaml +15 -10
  5. package/assets/translations/zh-hans.yaml +1 -1
  6. package/babel.config.js +3 -0
  7. package/components/ClusterProviderIconMenu.vue +161 -0
  8. package/components/Loading.vue +1 -1
  9. package/components/SideNav.vue +1 -1
  10. package/components/SortableTable/paging.js +10 -0
  11. package/components/form/GitPicker.vue +16 -0
  12. package/components/form/SelectOrCreateAuthSecret.vue +16 -3
  13. package/components/nav/Group.vue +54 -24
  14. package/components/nav/Header.vue +1 -1
  15. package/components/nav/TopLevelMenu.vue +469 -294
  16. package/components/nav/Type.vue +31 -5
  17. package/creators/pkg/init +2 -2
  18. package/edit/fleet.cattle.io.gitrepo.vue +43 -15
  19. package/edit/logging.banzaicloud.io.output/index.vue +7 -0
  20. package/edit/provisioning.cattle.io.cluster/CustomCommand.vue +3 -8
  21. package/edit/provisioning.cattle.io.cluster/rke2.vue +108 -33
  22. package/edit/resources.cattle.io.backup.vue +3 -1
  23. package/edit/resources.cattle.io.restore.vue +3 -1
  24. package/edit/workload/storage/ContainerMountPaths.vue +7 -5
  25. package/initialize/App.js +2 -0
  26. package/initialize/client.js +63 -51
  27. package/initialize/index.js +2 -0
  28. package/layouts/default.vue +8 -0
  29. package/machine-config/amazonec2.vue +1 -0
  30. package/mixins/fetch.client.js +3 -3
  31. package/package.json +1 -1
  32. package/pages/__tests__/prefs.test.ts +1 -1
  33. package/pages/c/_cluster/explorer/ConfigBadge.vue +1 -0
  34. package/pages/prefs.vue +3 -13
  35. package/plugins/dashboard-store/resource-class.js +1 -1
  36. package/public/index.html +4 -2
  37. package/rancher-components/Form/LabeledInput/LabeledInput.vue +8 -0
  38. package/rancher-components/Form/Radio/RadioButton.test.ts +7 -3
  39. package/scripts/extension/parse-tag-name +0 -0
  40. package/store/prefs.js +3 -4
  41. package/store/type-map.js +2 -16
  42. package/types/shell/index.d.ts +10 -1
  43. package/utils/__tests__/formatter.test.ts +77 -0
  44. package/utils/__tests__/sort.test.ts +61 -0
  45. package/utils/formatter.js +11 -0
  46. package/utils/string.js +12 -0
  47. package/vue.config.js +7 -6
  48. package/yarn-error.log +16 -16
@@ -1,10 +1,11 @@
1
1
  <script>
2
2
  import BrandImage from '@shell/components/BrandImage';
3
- import ClusterProviderIcon from '@shell/components/ClusterProviderIcon';
3
+ import ClusterProviderIconMenu from '@shell/components/ClusterProviderIconMenu';
4
4
  import IconOrSvg from '../IconOrSvg';
5
+ import { BLANK_CLUSTER } from '@shell/store/store-types.js';
5
6
  import { mapGetters } from 'vuex';
6
7
  import { CAPI, MANAGEMENT } from '@shell/config/types';
7
- import { mapPref, MENU_MAX_CLUSTERS } from '@shell/store/prefs';
8
+ import { MENU_MAX_CLUSTERS } from '@shell/store/prefs';
8
9
  import { sortBy } from '@shell/utils/sort';
9
10
  import { ucFirst } from '@shell/utils/string';
10
11
  import { KEY } from '@shell/utils/platform';
@@ -18,7 +19,7 @@ export default {
18
19
 
19
20
  components: {
20
21
  BrandImage,
21
- ClusterProviderIcon,
22
+ ClusterProviderIconMenu,
22
23
  IconOrSvg
23
24
  },
24
25
 
@@ -27,11 +28,13 @@ export default {
27
28
  const hasProvCluster = this.$store.getters[`management/schemaFor`](CAPI.RANCHER_CLUSTER);
28
29
 
29
30
  return {
30
- shown: false,
31
+ shown: false,
31
32
  displayVersion,
32
33
  fullVersion,
33
- clusterFilter: '',
34
+ clusterFilter: '',
34
35
  hasProvCluster,
36
+ maxClustersToShow: MENU_MAX_CLUSTERS,
37
+ emptyCluster: BLANK_CLUSTER
35
38
  };
36
39
  },
37
40
 
@@ -74,9 +77,9 @@ export default {
74
77
  return p;
75
78
  }, {});
76
79
 
77
- // Filter to only show mgmt clusters that exist for the available provisionning clusters
80
+ // Filter to only show mgmt clusters that exist for the available provisioning clusters
78
81
  // Addresses issue where a mgmt cluster can take some time to get cleaned up after the corresponding
79
- // provisionning cluster has been deleted
82
+ // provisioning cluster has been deleted
80
83
  kubeClusters = kubeClusters.filter((c) => !!available[c]);
81
84
  }
82
85
 
@@ -91,7 +94,8 @@ export default {
91
94
  providerNavLogo: x.providerMenuLogo,
92
95
  badge: x.badge,
93
96
  isLocal: x.isLocal,
94
- isHarvester: x.isHarvester
97
+ isHarvester: x.isHarvester,
98
+ pinned: true,
95
99
  };
96
100
  });
97
101
  },
@@ -101,12 +105,18 @@ export default {
101
105
 
102
106
  const out = search ? this.clusters.filter((item) => item.label.toLowerCase().includes(search)) : this.clusters;
103
107
 
104
- const sorted = sortBy(out, ['name:desc', 'label']);
108
+ const sorted = sortBy(out, ['ready:desc', 'label']);
105
109
 
106
- return sorted;
110
+ if (sorted.length >= this.maxClustersToShow) {
111
+ return sorted.slice(0, this.maxClustersToShow);
112
+ } else {
113
+ return sorted;
114
+ }
107
115
  },
108
116
 
109
- maxClustersToShow: mapPref(MENU_MAX_CLUSTERS),
117
+ clusterFilterCount() {
118
+ return this.clusterFilter ? this.clustersFiltered.length : this.clusters.length;
119
+ },
110
120
 
111
121
  multiClusterApps() {
112
122
  const options = this.options;
@@ -198,18 +208,6 @@ export default {
198
208
  },
199
209
 
200
210
  methods: {
201
- // Cluster list number of items shown is configurable via user preference
202
- setClusterListHeight(maxToShow) {
203
- const el = this.$refs.clusterList;
204
- const max = Math.min(maxToShow, this.clusters.length);
205
-
206
- if (el) {
207
- const h = 33 * max;
208
-
209
- el.style.minHeight = `${ h }px`;
210
- el.style.maxHeight = `${ h }px`;
211
- }
212
- },
213
211
  handler(e) {
214
212
  if (e.keyCode === KEY.ESCAPE ) {
215
213
  this.hide();
@@ -218,13 +216,13 @@ export default {
218
216
 
219
217
  hide() {
220
218
  this.shown = false;
219
+ if (this.clustersFiltered === 0) {
220
+ this.clusterFilter = '';
221
+ }
221
222
  },
222
223
 
223
224
  toggle() {
224
225
  this.shown = !this.shown;
225
- this.$nextTick(() => {
226
- this.setClusterListHeight(this.maxClustersToShow);
227
- });
228
226
  },
229
227
 
230
228
  async goToHarvesterCluster() {
@@ -234,29 +232,27 @@ export default {
234
232
  await localCluster.goToHarvesterCluster();
235
233
  } catch {
236
234
  }
237
- }
235
+ },
236
+ getTooltipConfig(item) {
237
+ if (!this.shown && !item) {
238
+ return;
239
+ }
240
+
241
+ if (!this.shown) {
242
+ return {
243
+ content: this.shown ? null : item,
244
+ placement: 'right',
245
+ popperOptions: { modifiers: { preventOverflow: { enabled: false } } }
246
+ };
247
+ } else {
248
+ return { content: undefined };
249
+ }
250
+ },
238
251
  }
239
252
  };
240
253
  </script>
241
254
  <template>
242
255
  <div>
243
- <div
244
- data-testid="top-level-menu"
245
- class="menu"
246
- :class="{'raised': shown, 'unraised':!shown}"
247
- @click="toggle()"
248
- >
249
- <svg
250
- class="menu-icon"
251
- xmlns="http://www.w3.org/2000/svg"
252
- height="24"
253
- viewBox="0 0 24 24"
254
- width="24"
255
- ><path
256
- d="M0 0h24v24H0z"
257
- fill="none"
258
- /><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z" /></svg>
259
- </div>
260
256
  <div
261
257
  v-if="shown"
262
258
  class="side-menu-glass"
@@ -264,24 +260,40 @@ export default {
264
260
  />
265
261
  <transition name="fade">
266
262
  <div
267
- v-if="shown"
268
263
  data-testid="side-menu"
269
264
  class="side-menu"
265
+ :class="{'menu-open': shown, 'menu-close':!shown}"
270
266
  tabindex="-1"
271
267
  >
272
268
  <div class="title">
273
- <div class="menu-spacer" />
269
+ <div
270
+ data-testid="top-level-menu"
271
+ class="menu"
272
+ @click="toggle()"
273
+ >
274
+ <svg
275
+ class="menu-icon"
276
+ xmlns="http://www.w3.org/2000/svg"
277
+ height="24"
278
+ viewBox="0 0 24 24"
279
+ width="24"
280
+ ><path
281
+ d="M0 0h24v24H0z"
282
+ fill="none"
283
+ /><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z" /></svg>
284
+ </div>
274
285
  <div class="side-menu-logo">
275
286
  <BrandImage file-name="rancher-logo.svg" />
276
287
  </div>
277
288
  </div>
278
289
  <div class="body">
279
- <div @click="hide()">
290
+ <div>
280
291
  <nuxt-link
281
292
  class="option cluster selector home"
282
293
  :to="{ name: 'home' }"
283
294
  >
284
295
  <svg
296
+ v-tooltip="getTooltipConfig(t('nav.home'))"
285
297
  xmlns="http://www.w3.org/2000/svg"
286
298
  height="24"
287
299
  viewBox="0 0 24 24"
@@ -290,16 +302,42 @@ export default {
290
302
  d="M0 0h24v24H0z"
291
303
  fill="none"
292
304
  /><path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z" /></svg>
293
- <div>
305
+ <div class="home-text">
294
306
  {{ t('nav.home') }}
295
307
  </div>
296
308
  </nuxt-link>
297
- </div>
298
309
 
299
- <template v-if="hciApps.length">
300
- <div class="category">
301
- {{ t('nav.categories.hci') }}
310
+ <div
311
+ v-if="showClusterSearch"
312
+ class="clusters-search"
313
+ >
314
+ <div class="clusters-search-count">
315
+ <span>{{ clusterFilterCount }}</span>
316
+ {{ t('nav.search.clusters') }}
317
+ <i
318
+ v-if="clusterFilter"
319
+ class="icon icon-filter_alt"
320
+ />
321
+ </div>
322
+
323
+ <div
324
+ class="search"
325
+ >
326
+ <input
327
+ ref="clusterFilter"
328
+ v-model="clusterFilter"
329
+ :placeholder="t('nav.search.placeholder')"
330
+ >
331
+ <i
332
+ v-if="clusterFilter"
333
+ class="icon icon-close"
334
+ @click="clusterFilter=''"
335
+ />
336
+ </div>
302
337
  </div>
338
+ </div>
339
+ <template v-if="hciApps.length">
340
+ <div class="category" />
303
341
  <div>
304
342
  <a
305
343
  v-if="isRancherInHarvester"
@@ -334,25 +372,6 @@ export default {
334
372
  </template>
335
373
 
336
374
  <template v-if="clusters && !!clusters.length">
337
- <div class="category">
338
- {{ t('nav.categories.explore') }}
339
- </div>
340
-
341
- <div
342
- v-if="showClusterSearch"
343
- class="search"
344
- >
345
- <input
346
- ref="clusterFilter"
347
- v-model="clusterFilter"
348
- :placeholder="t('nav.search.placeholder')"
349
- >
350
- <i
351
- v-if="clusterFilter"
352
- class="icon icon-close"
353
- @click="clusterFilter=''"
354
- />
355
- </div>
356
375
  <div
357
376
  ref="clusterList"
358
377
  class="clusters"
@@ -364,13 +383,14 @@ export default {
364
383
  >
365
384
  <nuxt-link
366
385
  v-if="c.ready"
386
+ :data-testid="`menu-cluster-${ c.id }`"
367
387
  class="cluster selector option"
368
388
  :to="{ name: 'c-cluster-explorer', params: { cluster: c.id } }"
369
389
  >
370
- <ClusterProviderIcon
371
- :small="true"
390
+ <ClusterProviderIconMenu
391
+ v-tooltip="getTooltipConfig(c.label)"
372
392
  :cluster="c"
373
- class="rancher-provider-icon mr-10"
393
+ class="rancher-provider-icon"
374
394
  />
375
395
  <div class="cluster-name">
376
396
  {{ c.label }}
@@ -378,103 +398,144 @@ export default {
378
398
  </nuxt-link>
379
399
  <span
380
400
  v-else
381
- class="option-disabled cluster selector disabled"
401
+ class="option cluster selector disabled"
382
402
  >
383
- <ClusterProviderIcon
384
- :small="true"
403
+ <ClusterProviderIconMenu
404
+ v-tooltip="getTooltipConfig(c.label)"
385
405
  :cluster="c"
386
- class="rancher-provider-icon mr-10"
406
+ class="rancher-provider-icon"
387
407
  />
388
408
  <div class="cluster-name">{{ c.label }}</div>
389
409
  </span>
390
410
  </div>
391
411
  <div
392
- v-if="clustersFiltered.length === 0"
412
+ v-if="clustersFiltered.length === 0 && shown"
393
413
  class="none-matching"
394
414
  >
395
415
  {{ t('nav.search.noResults') }}
396
416
  </div>
397
417
  </div>
398
- </template>
399
418
 
400
- <template v-if="multiClusterApps.length">
401
- <div class="category">
402
- {{ t('nav.categories.multiCluster') }}
403
- </div>
404
- <div
405
- v-for="a in multiClusterApps"
406
- :key="a.label"
407
- @click="hide()"
419
+ <nuxt-link
420
+ v-if="clusters.length > maxClustersToShow"
421
+ class="clusters-all"
422
+ :to="{name: 'c-cluster-product-resource', params: {
423
+ cluster: emptyCluster,
424
+ product: 'manager',
425
+ resource: 'provisioning.cattle.io.cluster'
426
+ } }"
408
427
  >
409
- <nuxt-link
410
- class="option"
411
- :to="a.to"
412
- >
413
- <IconOrSvg
414
- :icon="a.icon"
415
- :src="a.svg"
416
- />
417
- <div>{{ a.label }}</div>
418
- </nuxt-link>
419
- </div>
428
+ <span>
429
+ {{ shown ? t('nav.seeAllClusters') : t('nav.seeAllClustersCollapsed') }}
430
+ <i class="icon icon-chevron-right" />
431
+ </span>
432
+ </nuxt-link>
420
433
  </template>
421
- <template v-if="legacyEnabled">
422
- <div class="category">
423
- {{ t('nav.categories.legacy') }}
424
- </div>
425
- <div
426
- v-for="a in legacyApps"
427
- :key="a.label"
428
- @click="hide()"
429
- >
430
- <nuxt-link
431
- class="option"
432
- :to="a.to"
434
+
435
+ <div class="category">
436
+ <template v-if="multiClusterApps.length">
437
+ <div
438
+ class="category-title"
433
439
  >
434
- <IconOrSvg
435
- :icon="a.icon"
436
- :src="a.svg"
437
- />
438
- <div>{{ a.label }}</div>
439
- </nuxt-link>
440
- </div>
441
- </template>
442
- <template v-if="configurationApps.length">
443
- <div class="category">
444
- {{ t('nav.categories.configuration') }}
445
- </div>
446
- <div
447
- v-for="a in configurationApps"
448
- :key="a.label"
449
- @click="hide()"
450
- >
451
- <nuxt-link
452
- class="option"
453
- :to="a.to"
440
+ <hr>
441
+ <span>
442
+ {{ t('nav.categories.multiCluster') }}
443
+ </span>
444
+ </div>
445
+ <div
446
+ v-for="a in multiClusterApps"
447
+ :key="a.label"
448
+ @click="hide()"
454
449
  >
455
- <IconOrSvg
456
- :icon="a.icon"
457
- :src="a.svg"
458
- />
459
- <div>{{ a.label }}</div>
460
- </nuxt-link>
461
- </div>
462
- </template>
463
- <div class="pad" />
450
+ <nuxt-link
451
+ class="option"
452
+ :to="a.to"
453
+ >
454
+ <IconOrSvg
455
+ v-tooltip="getTooltipConfig(a.label)"
456
+ :icon="a.icon"
457
+ :src="a.svg"
458
+ />
459
+ <span class="option-link">{{ a.label }}</span>
460
+ </nuxt-link>
461
+ </div>
462
+ </template>
463
+ <template v-if="legacyEnabled">
464
+ <div
465
+ class="category-title"
466
+ >
467
+ <hr>
468
+ <span>
469
+ {{ t('nav.categories.legacy') }}
470
+ </span>
471
+ </div>
472
+ <div
473
+ v-for="a in legacyApps"
474
+ :key="a.label"
475
+ @click="hide()"
476
+ >
477
+ <nuxt-link
478
+ class="option"
479
+ :to="a.to"
480
+ >
481
+ <IconOrSvg
482
+ v-tooltip="getTooltipConfig(a.label)"
483
+ :icon="a.icon"
484
+ :src="a.svg"
485
+ />
486
+ <div>{{ a.label }}</div>
487
+ </nuxt-link>
488
+ </div>
489
+ </template>
490
+ <template v-if="configurationApps.length">
491
+ <div
492
+ class="category-title"
493
+ >
494
+ <hr>
495
+ <span>
496
+ {{ t('nav.categories.configuration') }}
497
+ </span>
498
+ </div>
499
+ <div
500
+ v-for="a in configurationApps"
501
+ :key="a.label"
502
+ @click="hide()"
503
+ >
504
+ <nuxt-link
505
+ class="option"
506
+ :to="a.to"
507
+ >
508
+ <IconOrSvg
509
+ v-tooltip="getTooltipConfig(a.label)"
510
+ :icon="a.icon"
511
+ :src="a.svg"
512
+ />
513
+ <div>{{ a.label }}</div>
514
+ </nuxt-link>
515
+ </div>
516
+ </template>
517
+ </div>
464
518
  </div>
465
- <div class="footer">
519
+ <div
520
+ class="footer"
521
+ >
466
522
  <div
467
523
  v-if="canEditSettings"
524
+ class="support"
468
525
  @click="hide()"
469
526
  >
470
- <nuxt-link :to="{name: 'support'}">
527
+ <nuxt-link
528
+ :to="{name: 'support'}"
529
+ >
471
530
  {{ t('nav.support', {hasSupport}) }}
472
531
  </nuxt-link>
473
532
  </div>
474
- <div @click="hide()">
533
+ <div
534
+ class="version"
535
+ @click="hide()"
536
+ >
475
537
  <nuxt-link
476
538
  :to="{ name: 'about' }"
477
- class="version"
478
539
  >
479
540
  {{ t('about.title') }}
480
541
  </nuxt-link>
@@ -485,41 +546,11 @@ export default {
485
546
  </div>
486
547
  </template>
487
548
 
488
- <style scoped>
489
- .cluster.disabled > * {
490
- cursor: not-allowed;
491
- filter: grayscale(1);
492
- color: var(--muted);
493
- }
494
- </style>
495
-
496
549
  <style lang="scss">
497
550
  .localeSelector, .footer-tooltip {
498
551
  z-index: 1000;
499
552
  }
500
553
 
501
- .cluster {
502
- &.selector:not(.disabled):hover {
503
- color: var(--primary-hover-text);
504
- background: var(--primary-hover-bg);
505
- border-radius: 5px;
506
- text-decoration: none;
507
-
508
- .rancher-provider-icon {
509
- .rancher-icon-fill {
510
- fill: var(--primary-hover-text);;
511
- }
512
- }
513
- }
514
-
515
- .rancher-provider-icon {
516
- .rancher-icon-fill {
517
- // Should match .option color
518
- fill: var(--link);
519
- }
520
- }
521
- }
522
-
523
554
  .localeSelector {
524
555
  .popover-inner {
525
556
  padding: 10px 0;
@@ -533,73 +564,18 @@ export default {
533
564
  outline: 0;
534
565
  }
535
566
  }
536
-
537
567
  </style>
538
568
 
539
569
  <style lang="scss" scoped>
540
570
  $clear-search-size: 20px;
541
571
  $icon-size: 25px;
542
- $option-padding: 4px;
572
+ $option-padding: 9px;
573
+ $option-padding-left: 14px;
543
574
  $option-height: $icon-size + $option-padding + $option-padding;
544
575
 
545
- .option {
546
- align-items: center;
547
- cursor: pointer;
548
- display: flex;
549
- color: var(--link);
550
-
551
- &:hover {
552
- text-decoration: none;
553
- }
554
-
555
- &:focus {
556
- outline: 0;
557
- > div {
558
- text-decoration: underline;
559
- }
560
- }
561
-
562
- > i {
563
- width: $icon-size;
564
- font-size: $icon-size;
565
- margin-right: 8px;
566
- }
567
- svg {
568
- margin-right: 8px;
569
- fill: var(--link);
570
- }
571
- img {
572
- margin-right: 8px;
573
- }
574
-
575
- > div {
576
- color: var(--link);
577
- }
578
-
579
- &:hover {
580
- color: var(--primary-hover-text);
581
- background: var(--primary-hover-bg);
582
- border-radius: 5px;
583
- > div {
584
- color: var(--primary-hover-text);
585
- }
586
- svg {
587
- fill: var(--primary-hover-text);
588
- }
589
- div {
590
- color: var(--primary-hover-text);
591
- }
592
- }
593
- }
594
-
595
- .option, .option-disabled {
596
- padding: $option-padding 0 $option-padding 10px;
597
- }
598
-
599
576
  .menu {
600
577
  position: absolute;
601
- left: 0;
602
- width: 55px;
578
+ width: $app-bar-collapsed-width;
603
579
  height: 54px;
604
580
  top: 0;
605
581
  grid-area: menu;
@@ -607,37 +583,37 @@ export default {
607
583
  display: flex;
608
584
  align-items: center;
609
585
  justify-content: center;
610
- &:hover {
611
- background-color: var(--topmost-light-hover);
612
- }
586
+
613
587
  .menu-icon {
614
- width: 24px;
615
- height: 24px;
588
+ width: 25px;
589
+ height: 25px;
616
590
  fill: var(--header-btn-text);
617
591
  }
618
- &.raised {
619
- z-index: 200;
620
- }
621
592
  }
622
593
 
623
594
  .side-menu {
624
- position: absolute;
595
+ position: fixed;
625
596
  top: 0;
626
597
  left: 0px;
627
598
  bottom: 0;
628
- width: 280px;
599
+ width: $app-bar-collapsed-width;
629
600
  background-color: var(--topmenu-bg);
630
601
  z-index: 100;
631
602
  border-right: 1px solid var(--topmost-border);
632
- box-shadow: 0 0 15px 4px var(--topmost-shadow);
633
603
  display: flex;
634
604
  flex-direction: column;
635
605
  padding: 0;
606
+ overflow: hidden;
607
+ transition: width 500ms;
636
608
 
637
609
  &:focus {
638
610
  outline: 0;
639
611
  }
640
612
 
613
+ &.menu-open {
614
+ width: 300px;
615
+ }
616
+
641
617
  .title {
642
618
  display: flex;
643
619
  height: 55px;
@@ -646,64 +622,126 @@ export default {
646
622
  border-bottom: 1px solid var(--nav-border);
647
623
  justify-content: flex-start;
648
624
  align-items: center;
625
+
649
626
  .menu {
650
627
  display: flex;
651
628
  justify-content: center;
652
- width: 55px;
653
- margin-right: 10px;
654
629
  }
655
630
  .menu-icon {
656
- width: 24px;
657
- height: 24px;
631
+ width: 25px;
632
+ height: 25px;
658
633
  }
659
- .menu-spacer {
660
- width: 55px;
634
+ }
635
+ .home {
636
+ svg {
637
+ width: 25px;
638
+ height: 25px;
639
+ margin-left: 10px;
661
640
  }
662
641
  }
642
+ .home-text {
643
+ margin-left: $option-padding-left - 7;
644
+ }
663
645
  .body {
664
646
  flex: 1;
665
647
  display: flex;
666
648
  flex-direction: column;
667
- margin: 10px 20px;
668
- overflow-y: auto;
669
-
670
- .category {
671
- padding: 10px 0;
672
- text-transform: uppercase;
673
- opacity: 0.8;
674
- margin-top: 10px;
675
- }
676
-
677
- .home {
678
- color: var(--link);
679
- }
680
-
681
- .home:focus {
682
- outline: 0;
683
- }
649
+ margin: 10px 0;
650
+ width: 300px;
651
+ overflow: auto;
684
652
 
685
- .cluster {
653
+ .option {
686
654
  align-items: center;
655
+ cursor: pointer;
687
656
  display: flex;
657
+ color: var(--link);
658
+ font-size: 14px;
688
659
  height: $option-height;
689
-
690
660
  white-space: nowrap;
661
+
662
+ .cluster-badge-logo-text {
663
+ color: var(--default-active-text);
664
+ font-weight: 500;
665
+ }
666
+
667
+ &:hover {
668
+ text-decoration: none;
669
+ }
670
+ &.disabled {
671
+ background: transparent;
672
+ cursor: not-allowed;
673
+
674
+ .rancher-provider-icon,
675
+ .cluster-name {
676
+ filter: grayscale(1);
677
+ color: var(--muted);
678
+ }
679
+ }
680
+
691
681
  &:focus {
692
682
  outline: 0;
683
+ > div {
684
+ text-decoration: underline;
685
+ }
686
+ }
687
+
688
+ > i {
689
+ display: block;
690
+ width: 42px;
691
+ font-size: $icon-size;
692
+ margin-right: 14px;
693
+ }
694
+
695
+ .rancher-provider-icon,
696
+ svg {
697
+ margin-right: 16px;
698
+ fill: var(--link);
699
+ }
700
+ img {
701
+ margin-right: 16px;
693
702
  }
703
+
704
+ &.nuxt-link-active {
705
+ background: var(--primary-hover-bg);
706
+ color: var(--primary-hover-text);
707
+
708
+ svg {
709
+ fill: var(--primary-hover-text);
710
+ }
711
+
712
+ i {
713
+ color: var(--primary-hover-text);
714
+ }
715
+ }
716
+
717
+ &:hover {
718
+ color: var(--primary-hover-text);
719
+ background: var(--primary-hover-bg);
720
+ > div {
721
+ color: var(--primary-hover-text);
722
+ }
723
+ svg {
724
+ fill: var(--primary-hover-text);
725
+ }
726
+ div {
727
+ color: var(--primary-hover-text);
728
+ }
729
+ &.disabled {
730
+ background: transparent;
731
+ color: var(--muted);
732
+ }
733
+ }
734
+
694
735
  .cluster-name {
695
- text-overflow: ellipsis;
736
+ max-width: 220px;
737
+ white-space: nowrap;
696
738
  overflow: hidden;
697
- }
698
- > img {
699
- max-height: $icon-size;
700
- max-width: $icon-size;
701
- margin-right: 8px;
739
+ text-overflow: ellipsis;
702
740
  }
703
741
  }
704
742
 
705
- .pad {
706
- flex: 1;
743
+ .option, .option-disabled {
744
+ padding: $option-padding 0 $option-padding $option-padding-left;
707
745
  }
708
746
 
709
747
  .search {
@@ -716,7 +754,7 @@ export default {
716
754
  > i {
717
755
  position: absolute;
718
756
  font-size: $clear-search-size;
719
- top: 9px;
757
+ top: 11px;
720
758
  right: 8px;
721
759
  opacity: 0.7;
722
760
  cursor: pointer;
@@ -726,18 +764,165 @@ export default {
726
764
  }
727
765
  }
728
766
 
767
+ .clusters-all {
768
+ display: flex;
769
+ flex-direction: row-reverse;
770
+ margin-right: 16px;
771
+ margin-top: 10px;
772
+
773
+ span {
774
+ display: flex;
775
+ align-items: center;
776
+ }
777
+ }
778
+
729
779
  .clusters {
730
780
  overflow-y: auto;
731
- overflow-x: hidden;
781
+
782
+ @media screen and (max-height: 720px) {
783
+ min-height: 80px;
784
+ }
785
+
786
+ a, span {
787
+ margin: 0;
788
+ }
789
+
790
+ &-search {
791
+ display: flex;
792
+ align-items: center;
793
+ gap: 14px;
794
+ margin: 16px 0;
795
+ height: 42px;
796
+
797
+ .search {
798
+ transition: all 0.5s ease-in-out;
799
+ transition-delay: 2s;
800
+ width: 72%;
801
+ height: 42px;
802
+
803
+ input {
804
+ height: 100%;
805
+ }
806
+ }
807
+
808
+ &-count {
809
+ position: relative;
810
+ display: flex;
811
+ flex-direction: column;
812
+ width: 42px;
813
+ height: 42px;
814
+ display: flex;
815
+ align-items: center;
816
+ justify-content: center;
817
+ color: var(--default-active-text);
818
+ margin-left: $option-padding-left;
819
+ border-radius: 5px;
820
+ font-size: 10px;
821
+ font-weight: bold;
822
+
823
+ span {
824
+ font-size: 14px;
825
+ }
826
+
827
+ .nuxt-link-active {
828
+ &:hover {
829
+ text-decoration: none;
830
+ }
831
+ }
832
+
833
+ i {
834
+ font-size: 12px;
835
+ position: absolute;
836
+ right: -3px;
837
+ top: 2px;
838
+ }
839
+ }
840
+ }
732
841
  }
733
842
 
734
843
  .none-matching {
844
+ width: 100%;
845
+ text-align: center;
735
846
  padding: 8px
736
847
  }
848
+
849
+ .category {
850
+ display: flex;
851
+ flex-direction: column;
852
+ place-content: flex-end;
853
+ flex: 1;
854
+
855
+ &-title {
856
+ display: flex;
857
+ flex-direction: row;
858
+ align-items: flex-start;
859
+ align-items: center;
860
+ margin: 15px 0;
861
+ margin-left: 16px;
862
+ font-size: 14px;
863
+ text-transform: uppercase;
864
+
865
+ span {
866
+ transition: all 0.5s ease-in-out;
867
+ display: flex;
868
+ max-height: 16px;
869
+ }
870
+
871
+ hr {
872
+ margin: 0;
873
+ max-width: 50px;
874
+ width: 0;
875
+ transition: all 0.5s ease-in-out;
876
+ }
877
+ }
878
+
879
+ i {
880
+ padding-left: $option-padding-left - 5;
881
+ }
882
+ }
737
883
  }
884
+
885
+ &.menu-close {
886
+ .side-menu-logo {
887
+ opacity: 0;
888
+ }
889
+ .category {
890
+ &-title {
891
+ span {
892
+ opacity: 0;
893
+ }
894
+
895
+ hr {
896
+ width: 40px;
897
+ }
898
+ }
899
+ }
900
+ .clusters-all {
901
+ flex-direction: row;
902
+ margin-left: $option-padding-left + 2;
903
+
904
+ span {
905
+ i {
906
+ display: none;
907
+ }
908
+ }
909
+ }
910
+ .footer {
911
+ margin: 20px 15px;
912
+
913
+ .support {
914
+ display: none;
915
+ }
916
+
917
+ .version{
918
+ text-align: left;
919
+ }
920
+ }
921
+ }
922
+
738
923
  .footer {
739
924
  margin: 20px;
740
-
925
+ width: 240px;
741
926
  display: flex;
742
927
  flex: 0;
743
928
  flex-direction: row;
@@ -761,7 +946,6 @@ export default {
761
946
  }
762
947
 
763
948
  .side-menu-glass {
764
- background-color: transparent;
765
949
  position: absolute;
766
950
  top: 0;
767
951
  left: 0px;
@@ -774,12 +958,13 @@ export default {
774
958
  .side-menu-logo {
775
959
  align-items: center;
776
960
  display: flex;
777
- margin-left: 10px;
961
+ transform: translateX($app-bar-collapsed-width);
778
962
  opacity: 1;
779
- transition: opacity 1.2s;
780
- transition-delay: 0s;
781
- height: 55px;
782
963
  max-width: 200px;
964
+ width: 100%;
965
+ justify-content: center;
966
+ transition: all 0.5s;
967
+ overflow: hidden;
783
968
  & IMG {
784
969
  object-fit: contain;
785
970
  height: 21px;
@@ -787,12 +972,6 @@ export default {
787
972
  }
788
973
  }
789
974
 
790
- .fade-enter-active {
791
- .side-menu-logo {
792
- opacity: 0;
793
- }
794
- }
795
-
796
975
  .fade-enter-active, .fade-leave-active {
797
976
  transition: all 0.2s;
798
977
  transition-timing-function: ease;
@@ -808,10 +987,6 @@ export default {
808
987
 
809
988
  .fade-enter {
810
989
  left: -300px;
811
-
812
- .side-menu-logo {
813
- opacity: 0;
814
- }
815
990
  }
816
991
 
817
992
  .locale-chooser {