dashboard-shell-shell 0.0.3 → 0.0.1000000000001124

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 (86) hide show
  1. package/assets/images/action.svg +6 -0
  2. package/assets/styles/base/_mixins.scss +1 -1
  3. package/assets/styles/global/_button.scss +17 -10
  4. package/assets/styles/global/_form.scss +2 -2
  5. package/assets/styles/global/_labeled-input.scss +6 -3
  6. package/assets/styles/global/_select.scss +5 -6
  7. package/assets/styles/global/_tooltip.scss +8 -1
  8. package/assets/styles/themes/_dark.scss +2 -0
  9. package/assets/styles/themes/_light.scss +5 -2
  10. package/assets/styles/vendor/vue-select.scss +2 -1
  11. package/components/ActionDropdown.vue +1 -0
  12. package/components/ActionMenuShell.vue +6 -1
  13. package/components/BrandImage.vue +21 -0
  14. package/components/ClusterIconMenu.vue +1 -1
  15. package/components/CodeMirror.vue +1 -0
  16. package/components/CruResource.vue +1 -0
  17. package/components/CruResourceFooter.vue +1 -1
  18. package/components/IndentedPanel.vue +4 -10
  19. package/components/PromptRemove.vue +2 -2
  20. package/components/ResourceDetail/Masthead.vue +161 -232
  21. package/components/ResourceDetail/index.vue +20 -1
  22. package/components/ResourceList/Masthead-btn.vue +225 -0
  23. package/components/ResourceList/Masthead.vue +96 -68
  24. package/components/ResourceList/ResourceLoadingIndicator.vue +5 -2
  25. package/components/ResourceTable.vue +64 -1
  26. package/components/SideNav.vue +24 -17
  27. package/components/SortableTable/THead.vue +6 -0
  28. package/components/SortableTable/index.vue +474 -366
  29. package/components/Tabbed/index.vue +4 -5
  30. package/components/auth/Principal.vue +3 -2
  31. package/components/auth/RoleDetailEdit.vue +56 -3
  32. package/components/auth/SelectPrincipal.vue +1 -0
  33. package/components/form/BannerSettings.vue +18 -16
  34. package/components/form/ChangePassword.vue +4 -4
  35. package/components/form/ColorInput.vue +32 -8
  36. package/components/form/Footer.vue +1 -1
  37. package/components/form/InputWithSelect.vue +2 -0
  38. package/components/form/KeyValue.vue +31 -7
  39. package/components/form/LabeledSelect.vue +178 -178
  40. package/components/form/Members/ClusterPermissionsEditor.vue +1 -2
  41. package/components/form/Members/MembershipEditor.vue +1 -1
  42. package/components/form/NameNsDescription.vue +24 -11
  43. package/components/form/Password.vue +6 -2
  44. package/components/form/Select.vue +2 -2
  45. package/components/nav/Favorite.vue +5 -1
  46. package/components/nav/Group.vue +45 -24
  47. package/components/nav/Header.vue +103 -14
  48. package/components/nav/HeaderPageActionMenu.vue +1 -0
  49. package/components/nav/TopLevelMenu.vue +63 -23
  50. package/components/nav/Type.vue +24 -5
  51. package/composables/useClickOutside.ts +1 -1
  52. package/config/product/auth.js +1 -1
  53. package/config/product/explorer.js +1 -1
  54. package/config/product/settings.js +10 -10
  55. package/detail/management.cattle.io.user.vue +1 -0
  56. package/edit/management.cattle.io.user.vue +17 -4
  57. package/list/management.cattle.io.user.vue +23 -12
  58. package/list/provisioning.cattle.io.cluster.vue +6 -7
  59. package/mixins/brand.js +17 -0
  60. package/package.json +1 -1
  61. package/pages/auth/login.vue +8 -22
  62. package/pages/c/_cluster/auth/roles/index.vue +48 -14
  63. package/pages/c/_cluster/settings/banners.vue +164 -101
  64. package/pages/c/_cluster/settings/brand.vue +338 -301
  65. package/pages/c/_cluster/settings/performance.vue +53 -38
  66. package/pages/home.vue +64 -8
  67. package/pages/prefs.vue +23 -21
  68. package/rancher-components/Banner/Banner.vue +4 -0
  69. package/rancher-components/Card/Card.vue +3 -6
  70. package/rancher-components/Form/Checkbox/Checkbox.vue +3 -0
  71. package/rancher-components/Form/LabeledInput/LabeledInput.vue +4 -2
  72. package/rancher-components/Form/Radio/RadioButton.vue +3 -3
  73. package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +0 -4
  74. package/rancher-components/LabeledTooltip/LabeledTooltip.vue +9 -4
  75. package/rancher-components/RcDropdown/RcDropdownItem.vue +1 -2
  76. package/rancher-components/RcDropdown/RcDropdownMenu.vue +3 -2
  77. package/rancher-components/RcDropdown/types.ts +1 -0
  78. package/scripts/typegen.sh +0 -1
  79. package/store/i18n.js +5 -5
  80. package/store/prefs.js +1 -1
  81. package/store/type-map.js +2 -1
  82. package/utils/router.js +1 -1
  83. package/types/resources/fleet.d.ts +0 -57
  84. package/types/resources/pod-security-admission.ts +0 -36
  85. package/types/resources/settings.d.ts +0 -93
  86. package/types/resources/userPreferences.d.ts +0 -13
@@ -460,12 +460,14 @@ export default {
460
460
 
461
461
  <template>
462
462
  <div>
463
- <!-- Overlay -->
463
+ <!-- ====================== 遮罩层(点击可关闭菜单) ====================== -->
464
464
  <div
465
465
  v-if="shown"
466
466
  class="side-menu-glass"
467
467
  @click="hide()"
468
468
  />
469
+
470
+ <!-- ====================== 菜单主容器(带淡入淡出过渡) ====================== -->
469
471
  <transition name="fade">
470
472
  <!-- Side menu -->
471
473
  <div
@@ -476,8 +478,11 @@ export default {
476
478
  role="navigation"
477
479
  :aria-label="t('nav.ariaLabel.topLevelMenu')"
478
480
  >
479
- <!-- Logo and name -->
481
+
482
+ <!-- ====================== 菜单头部(Logo + 菜单按钮) ====================== -->
480
483
  <div class="title">
484
+
485
+ <!-- 菜单按钮(汉堡图标) -->
481
486
  <div
482
487
  data-testid="top-level-menu"
483
488
  :aria-label="t('nav.expandCollapseAppBar')"
@@ -488,6 +493,8 @@ export default {
488
493
  @keyup.space="toggle()"
489
494
  @click="toggle()"
490
495
  >
496
+
497
+ <!-- 汉堡菜单SVG图标 -->
491
498
  <svg
492
499
  class="menu-icon"
493
500
  xmlns="http://www.w3.org/2000/svg"
@@ -500,6 +507,8 @@ export default {
500
507
  fill="none"
501
508
  /><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z" /></svg>
502
509
  </div>
510
+
511
+ <!-- 品牌Logo -->
503
512
  <div class="side-menu-logo">
504
513
  <BrandImage
505
514
  data-testid="side-menu__brand-img"
@@ -509,10 +518,11 @@ export default {
509
518
  </div>
510
519
  </div>
511
520
 
512
- <!-- Menu body -->
521
+ <!-- ====================== 菜单内容区 ====================== -->
513
522
  <div class="body">
514
523
  <div>
515
- <!-- Home button -->
524
+
525
+ <!-- 首页按钮 -->
516
526
  <div @click="hide()">
517
527
  <router-link
518
528
  class="option cluster selector home"
@@ -520,6 +530,8 @@ export default {
520
530
  role="link"
521
531
  :aria-label="t('nav.ariaLabel.homePage')"
522
532
  >
533
+
534
+ <!-- 首页图标 -->
523
535
  <svg
524
536
  v-clean-tooltip="getTooltipConfig(t('nav.home'))"
525
537
  class="top-menu-icon"
@@ -536,12 +548,14 @@ export default {
536
548
  </div>
537
549
  </router-link>
538
550
  </div>
539
- <!-- Search bar -->
551
+
552
+ <!-- 集群搜索框 -->
540
553
  <div
541
554
  v-if="showClusterSearch"
542
555
  class="clusters-search"
543
556
  >
544
557
  <div class="clusters-search-count">
558
+ <!-- 当前搜索到的集群数量 -->
545
559
  <span>{{ clusterFilterCount }}</span>
546
560
  {{ t('nav.search.clusters') }}
547
561
  <i
@@ -560,10 +574,14 @@ export default {
560
574
  :tabindex="!shown ? -1 : 0"
561
575
  :aria-label="t('nav.search.ariaLabel')"
562
576
  >
577
+
578
+ <!-- 搜索图标 -->
563
579
  <i
564
580
  class="magnifier icon icon-search"
565
581
  :class="{ active: clusterFilter }"
566
582
  />
583
+
584
+ <!-- 清空按钮 -->
567
585
  <i
568
586
  v-if="clusterFilter"
569
587
  class="icon icon-close"
@@ -573,9 +591,11 @@ export default {
573
591
  </div>
574
592
  </div>
575
593
 
576
- <!-- Harvester extras -->
594
+ <!-- ====================== Harvester 相关功能区 ====================== -->
577
595
  <template v-if="hciApps.length">
578
596
  <div class="category" />
597
+
598
+ <!-- 跳转 Harvester Dashboard -->
579
599
  <div>
580
600
  <a
581
601
  v-if="isRancherInHarvester"
@@ -591,6 +611,8 @@ export default {
591
611
  </div>
592
612
  </a>
593
613
  </div>
614
+
615
+ <!-- Harvester 应用列表 -->
594
616
  <div
595
617
  v-for="(a, i) in appBar.hciApps"
596
618
  :key="i"
@@ -613,14 +635,14 @@ export default {
613
635
  </div>
614
636
  </template>
615
637
 
616
- <!-- Cluster menu -->
638
+ <!-- ====================== 集群列表 ====================== -->
617
639
  <template v-if="!!allClustersCount">
618
640
  <div
619
641
  ref="clusterList"
620
642
  class="clusters"
621
643
  :style="pinnedClustersHeight"
622
644
  >
623
- <!-- Pinned Clusters -->
645
+ <!-- 已固定集群 -->
624
646
  <div
625
647
  v-if="showPinClusters && pinFiltered.length"
626
648
  class="clustersPinned"
@@ -631,11 +653,13 @@ export default {
631
653
  :data-testid="`pinned-ready-cluster-${index}`"
632
654
  @click="hide()"
633
655
  >
634
- <button
656
+
657
+ <!-- 可用集群按钮 -->
658
+ <span
635
659
  v-if="c.ready"
636
660
  v-shortkey.push="{windows: ['alt'], mac: ['option']}"
637
661
  :data-testid="`pinned-menu-cluster-${ c.id }`"
638
- class="cluster selector option"
662
+ class="clusterBtn cluster selector option"
639
663
  :class="{'active-menu-link': c.isMenuActive }"
640
664
  :to="c.clusterRoute"
641
665
  role="button"
@@ -665,7 +689,9 @@ export default {
665
689
  :cluster="c"
666
690
  :tab-order="shown ? 0 : -1"
667
691
  />
668
- </button>
692
+ </span>
693
+
694
+ <!-- 不可用集群 -->
669
695
  <span
670
696
  v-else
671
697
  class="option cluster selector disabled"
@@ -694,6 +720,8 @@ export default {
694
720
  />
695
721
  </span>
696
722
  </div>
723
+
724
+ <!-- 分割线 -->
697
725
  <div
698
726
  v-if="clustersFiltered.length > 0"
699
727
  class="category-title"
@@ -702,7 +730,7 @@ export default {
702
730
  </div>
703
731
  </div>
704
732
 
705
- <!-- Clusters Search result -->
733
+ <!-- 搜索结果集群列表 -->
706
734
  <div class="clustersList">
707
735
  <div
708
736
  v-for="(c, index) in appBar.clustersFiltered"
@@ -710,11 +738,13 @@ export default {
710
738
  :data-testid="`top-level-menu-cluster-${index}`"
711
739
  @click="hide()"
712
740
  >
713
- <button
741
+
742
+ <!-- 可用集群 -->
743
+ <span
714
744
  v-if="c.ready"
715
745
  v-shortkey.push="{windows: ['alt'], mac: ['option']}"
716
746
  :data-testid="`menu-cluster-${ c.id }`"
717
- class="cluster selector option"
747
+ class="cluster selector option clusterBtn"
718
748
  :class="{'active-menu-link': c.isMenuActive }"
719
749
  :to="c.clusterRoute"
720
750
  role="button"
@@ -745,7 +775,9 @@ export default {
745
775
  :tab-order="shown ? 0 : -1"
746
776
  :cluster="c"
747
777
  />
748
- </button>
778
+ </span>
779
+
780
+ <!-- 不可用集群 -->
749
781
  <span
750
782
  v-else
751
783
  class="option cluster selector disabled"
@@ -777,7 +809,7 @@ export default {
777
809
  </div>
778
810
  </div>
779
811
 
780
- <!-- No clusters message -->
812
+ <!-- 无匹配集群提示 -->
781
813
  <div
782
814
  v-if="clustersFiltered.length === 0 && searchActive"
783
815
  data-testid="top-level-menu-no-results"
@@ -787,7 +819,7 @@ export default {
787
819
  </div>
788
820
  </div>
789
821
 
790
- <!-- See all clusters -->
822
+ <!-- 查看所有集群按钮 -->
791
823
  <router-link
792
824
  v-if="allClustersCount > maxClustersToShow"
793
825
  class="clusters-all"
@@ -806,8 +838,9 @@ export default {
806
838
  </router-link>
807
839
  </template>
808
840
 
809
- <!-- MULTI CLUSTER APPS -->
841
+ <!-- ====================== 多集群应用区 ====================== -->
810
842
  <div class="category">
843
+ <!-- 多集群应用 -->
811
844
  <template v-if="multiClusterApps.length">
812
845
  <div
813
846
  class="category-title"
@@ -840,7 +873,7 @@ export default {
840
873
  </div>
841
874
  </template>
842
875
 
843
- <!-- Configuration apps menu -->
876
+ <!-- 配置类应用 -->
844
877
  <template v-if="configurationApps.length">
845
878
  <div
846
879
  class="category-title"
@@ -875,10 +908,11 @@ export default {
875
908
  </div>
876
909
  </div>
877
910
 
878
- <!-- Footer -->
911
+ <!-- ====================== 底部区域 ====================== -->
879
912
  <div
880
913
  class="footer"
881
914
  >
915
+ <!-- 支持页面链接 -->
882
916
  <div
883
917
  v-if="canEditSettings"
884
918
  class="support"
@@ -892,6 +926,8 @@ export default {
892
926
  {{ t('nav.support', {hasSupport}) }}
893
927
  </router-link>
894
928
  </div>
929
+
930
+ <!-- 关于页面链接 -->
895
931
  <div
896
932
  class="version"
897
933
  :class="{'version-small': largeAboutText}"
@@ -962,6 +998,10 @@ export default {
962
998
  $option-padding-left: 14px;
963
999
  $option-height: $icon-size + $option-padding + $option-padding;
964
1000
 
1001
+ .clusterBtn {
1002
+ background-color: var(--nav-icon-badge-bg);
1003
+ }
1004
+
965
1005
  .side-menu {
966
1006
  .menu {
967
1007
  position: absolute;
@@ -1066,7 +1106,7 @@ export default {
1066
1106
  align-items: center;
1067
1107
  cursor: pointer;
1068
1108
  display: flex;
1069
- color: var(--link);
1109
+ color: var(--primary);
1070
1110
  font-size: 14px;
1071
1111
  height: $option-height;
1072
1112
  white-space: nowrap;
@@ -1076,7 +1116,7 @@ export default {
1076
1116
  border: none;
1077
1117
 
1078
1118
  .cluster-badge-logo-text {
1079
- color: var(--default-active-text);
1119
+ color: var(--primary);
1080
1120
  font-weight: 500;
1081
1121
  }
1082
1122
 
@@ -1148,7 +1188,7 @@ export default {
1148
1188
  .rancher-provider-icon,
1149
1189
  svg {
1150
1190
  margin-right: 16px;
1151
- fill: var(--link);
1191
+ fill: var(--primary);
1152
1192
  }
1153
1193
 
1154
1194
  .top-menu-icon {
@@ -109,6 +109,7 @@ export default {
109
109
  </script>
110
110
 
111
111
  <template>
112
+ <!-- 当 type 有 route 时,渲染一个 Vue Router 自定义链接 -->
112
113
  <router-link
113
114
  v-if="type.route"
114
115
  :key="type.name"
@@ -116,18 +117,24 @@ export default {
116
117
  custom
117
118
  :to="type.route"
118
119
  >
120
+
121
+ <!-- 导航项容器 -->
119
122
  <li
120
123
  class="child nav-type"
121
124
  :class="{'root': isRoot, [`depth-${depth}`]: true, 'router-link-active': isActive, 'router-link-exact-active': isExactActive}"
122
125
  @click="navigate"
123
126
  @keypress.enter="navigate"
124
127
  >
128
+
129
+ <!-- 如果是精确匹配激活状态,则显示 TabTitle 组件 -->
125
130
  <TabTitle
126
131
  v-if="isExactActive"
127
132
  :show-child="false"
128
133
  >
129
134
  {{ type.labelKey ? t(type.labelKey) : (type.labelDisplay || type.label) }}
130
135
  </TabTitle>
136
+
137
+ <!-- 链接主体 -->
131
138
  <a
132
139
  role="link"
133
140
  :aria-label="type.labelKey ? t(type.labelKey) : (type.labelDisplay || type.label)"
@@ -138,30 +145,38 @@ export default {
138
145
  @mouseenter="setNear(true)"
139
146
  @mouseleave="setNear(false)"
140
147
  >
148
+ <!-- 文本标签:优先使用多语言 key -->
141
149
  <span
142
150
  v-if="type.labelKey"
143
151
  class="label"
144
152
  ><t :k="type.labelKey" /></span>
153
+
154
+ <!-- 没有 labelKey 时,直接使用 HTML 文本 -->
145
155
  <span
146
156
  v-else
147
157
  v-clean-html="type.labelDisplay || type.label"
148
158
  class="label"
149
159
  :class="{'no-icon': !type.icon}"
150
160
  />
161
+
162
+ <!-- 右侧附加信息(收藏按钮 / 命名空间图标 / 计数) -->
151
163
  <!-- <span
152
164
  v-if="showFavorite || namespaceIcon || showCount"
153
165
  class="count"
154
166
  >
167
+
155
168
  <Favorite
156
169
  v-if="showFavorite"
157
170
  :resource="type.name"
158
171
  />
172
+
159
173
  <i
160
174
  v-if="namespaceIcon"
161
175
  class="icon icon-namespace"
162
176
  :class="{'ns-and-icon': showCount}"
163
177
  data-testid="type-namespaced"
164
178
  />
179
+
165
180
  <span
166
181
  v-if="showCount"
167
182
  data-testid="type-count"
@@ -170,6 +185,8 @@ export default {
170
185
  </a>
171
186
  </li>
172
187
  </router-link>
188
+
189
+ <!-- 当 type 没有 route 但有外部 link 时 -->
173
190
  <li
174
191
  v-else-if="type.link"
175
192
  class="child nav-type nav-link"
@@ -185,6 +202,8 @@ export default {
185
202
  <span class="label">{{ type.label }}&nbsp;<i class="icon icon-external-link" /></span>
186
203
  </a>
187
204
  </li>
205
+
206
+ <!-- 兜底情况:既没有 route,也没有 link -->
188
207
  <li v-else>
189
208
  {{ type }}?
190
209
  </li>
@@ -234,12 +253,12 @@ export default {
234
253
  A {
235
254
  display: grid;
236
255
  grid-template-areas: "label count";
237
- grid-template-columns: auto auto;
256
+ grid-template-columns: auto 20px;
238
257
  grid-column-gap: 5px;
239
258
  font-size: 14px;
240
259
  line-height: 24px;
241
260
  /* padding: 7.5px 7px 7.5px 10px; */
242
- padding: 0px 16px 0px 40px;
261
+ padding: 0px 16px 0px 30px;
243
262
  height: 50px;
244
263
  margin: 0 0 0 -3px;
245
264
  overflow: hidden;
@@ -248,7 +267,7 @@ export default {
248
267
  color: var(--body-text);
249
268
 
250
269
  &:hover {
251
- background: var(--nav-active);
270
+ background: var(--nav-active) !important;
252
271
  color: var(--nav-hover-color);
253
272
  /* background: var(--nav-hover); */
254
273
  text-decoration: none;
@@ -271,13 +290,13 @@ export default {
271
290
  font-size: 12px;
272
291
  text-align: right;
273
292
  justify-items: center;
274
- padding-right: 4px;
293
+ line-height: 50px;
275
294
  }
276
295
 
277
296
  &.nav-type:not(.depth-0) {
278
297
  A {
279
298
  font-size: 13px;
280
- padding: 5.5px 7px 5.5px 10px;
299
+ padding: 5.5px 7px 5.5px 40px;
281
300
  }
282
301
 
283
302
  ::v-deep .label I {
@@ -76,6 +76,6 @@ export const useClickOutside = <T extends OnClickOutsideOptions>(
76
76
 
77
77
  onBeforeUnmount(() => {
78
78
  window.removeEventListener('click', listener as any);
79
- window.removeEventListener('pointerDown', setShouldListen);
79
+ window.removeEventListener('pointerdown', setShouldListen);
80
80
  });
81
81
  };
@@ -28,7 +28,7 @@ export function init(store) {
28
28
  product({
29
29
  ifHaveType: new RegExp(`${ MANAGEMENT.USER }|${ MANAGEMENT.AUTH_CONFIG }`, 'i'),
30
30
  ifHaveVerb: 'GET',
31
- ifFeature: MULTI_CLUSTER,
31
+ // ifFeature: MULTI_CLUSTER,
32
32
  inStore: 'management',
33
33
  icon: 'user',
34
34
  removable: false,
@@ -64,7 +64,7 @@ export function init(store) {
64
64
  [NORMAN.CLUSTER_ROLE_TEMPLATE_BINDING]: 'rancher',
65
65
  [NORMAN.PROJECT_ROLE_TEMPLATE_BINDING]: 'rancher',
66
66
  [CAPI.RANCHER_CLUSTER]: 'management',
67
- }
67
+ },
68
68
  });
69
69
 
70
70
  basicType(['cluster-dashboard', 'cluster-tools']);
@@ -92,15 +92,15 @@ export function init(store) {
92
92
  route: { name: 'c-cluster-settings-performance' }
93
93
  });
94
94
 
95
- virtualType({
96
- ifHaveType: MANAGEMENT.SETTING,
97
- labelKey: 'customLinks.label',
98
- name: 'links',
99
- namespaced: false,
100
- weight: 96,
101
- icon: 'folder',
102
- route: { name: 'c-cluster-settings-links' }
103
- });
95
+ // virtualType({
96
+ // ifHaveType: MANAGEMENT.SETTING,
97
+ // labelKey: 'customLinks.label',
98
+ // name: 'links',
99
+ // namespaced: false,
100
+ // weight: 96,
101
+ // icon: 'folder',
102
+ // route: { name: 'c-cluster-settings-links' }
103
+ // });
104
104
 
105
105
  basicType([
106
106
  'settings',
@@ -108,7 +108,7 @@ export function init(store) {
108
108
  'brand',
109
109
  'banners',
110
110
  'performance',
111
- 'links'
111
+ // 'links'
112
112
  ]);
113
113
 
114
114
  configureType(MANAGEMENT.SETTING, {
@@ -228,6 +228,7 @@ export default {
228
228
  </script>
229
229
 
230
230
  <template>
231
+ 编辑页面1-----------------------------------------------------------
231
232
  <Loading v-if="$fetchState.pending" />
232
233
  <div v-else>
233
234
  <ResourceTabs
@@ -214,7 +214,11 @@ export default {
214
214
  </script>
215
215
 
216
216
  <template>
217
+
218
+ <!-- 如果没有获取到 value 数据,则显示加载组件 -->
217
219
  <Loading v-if="!value" />
220
+
221
+ <!-- 如果有数据,则进入资源编辑/创建的表单界面 -->
218
222
  <CruResource
219
223
  v-else
220
224
  :done-route="doneRoute"
@@ -226,10 +230,14 @@ export default {
226
230
  class="create-edit"
227
231
  @finish="save"
228
232
  >
233
+
234
+ <!-- 账户凭据区域 -->
229
235
  <div class="credentials">
230
236
  <h2> {{ t("user.edit.credentials.label") }}</h2>
237
+
238
+ <!-- 用户名 & 显示名 -->
231
239
  <div class="row">
232
- <div class="col span-4">
240
+ <div class="col span-6">
233
241
  <LabeledInput
234
242
  ref="name"
235
243
  v-model:value="form.username"
@@ -241,7 +249,7 @@ export default {
241
249
  :ignore-password-managers="!isCreate"
242
250
  />
243
251
  </div>
244
- <div class="col span-4">
252
+ <div class="col span-6">
245
253
  <LabeledInput
246
254
  v-model:value="form.displayName"
247
255
  label-key="user.edit.credentials.displayName.label"
@@ -250,8 +258,10 @@ export default {
250
258
  />
251
259
  </div>
252
260
  </div>
253
- <div class="row mt-20 mb-10">
254
- <div class="col span-8">
261
+
262
+ <!-- 用户描述 -->
263
+ <div class="row">
264
+ <div class="col span-6">
255
265
  <LabeledInput
256
266
  v-model:value="form.description"
257
267
  label-key="user.edit.credentials.userDescription.label"
@@ -261,6 +271,7 @@ export default {
261
271
  </div>
262
272
  </div>
263
273
 
274
+ <!-- 修改密码(仅非查看模式显示) -->
264
275
  <ChangePassword
265
276
  v-if="!isView"
266
277
  ref="changePassword"
@@ -270,6 +281,8 @@ export default {
270
281
  @valid="validation.password = $event"
271
282
  />
272
283
  </div>
284
+
285
+ <!-- 全局角色绑定区域(仅当 showGlobalRoles 为 true 时显示) -->
273
286
  <div
274
287
  v-if="showGlobalRoles"
275
288
  class="global-permissions"
@@ -122,18 +122,9 @@ export default {
122
122
  :show-incremental-loading-indicator="incrementalLoadingIndicator"
123
123
  :load-resources="loadResources"
124
124
  :load-indeterminate="loadIndeterminate"
125
+ :main-button-visible="false"
125
126
  >
126
- <template #extraActions>
127
- <AsyncButton
128
- v-if="canRefreshAccess"
129
- mode="refresh"
130
- :action-label="t('authGroups.actions.refresh')"
131
- :waiting-label="t('authGroups.actions.refresh')"
132
- :success-label="t('authGroups.actions.refresh')"
133
- :error-label="t('authGroups.actions.refresh')"
134
- @click="refreshGroupMemberships"
135
- />
136
- </template>
127
+
137
128
  <template
138
129
  v-if="isAdmin"
139
130
  #subHeader
@@ -142,6 +133,7 @@ export default {
142
133
  :to="{ name: 'c-cluster-auth-user.retention'}"
143
134
  class="btn role-link btn-sm btn-user-retention"
144
135
  data-testid="router-link-user-retention"
136
+ style="text-align: left;"
145
137
  >
146
138
  <i class="icon icon-gear" />
147
139
  {{ t('user.retention.button.label') }}
@@ -156,7 +148,23 @@ export default {
156
148
  :loading="loading"
157
149
  :use-query-params-for-simple-filtering="useQueryParamsForSimpleFiltering"
158
150
  :force-update-live-and-delayed="forceUpdateLiveAndDelayed"
151
+
152
+ :resource="resource"
153
+ :main-button-visible="true"
159
154
  >
155
+ <template #extraActions>
156
+ <AsyncButton
157
+ v-if="canRefreshAccess"
158
+ style="margin-right: 6px;"
159
+ mode="refresh"
160
+ :action-label="t('authGroups.actions.refresh')"
161
+ :waiting-label="t('authGroups.actions.refresh')"
162
+ :success-label="t('authGroups.actions.refresh')"
163
+ :error-label="t('authGroups.actions.refresh')"
164
+ @click="refreshGroupMemberships"
165
+ />
166
+ </template>
167
+
160
168
  <template #col:user-state="{row}">
161
169
  <td>
162
170
  <TableDataUserIcon
@@ -171,8 +179,11 @@ export default {
171
179
 
172
180
  <style lang="scss">
173
181
  .btn-user-retention {
174
- display: flex;
182
+ display: block;
175
183
  gap: 0.25rem;
176
184
  padding: 0;
177
185
  }
186
+ .btn-user-retention:hover {
187
+ color: #333 !important;
188
+ }
178
189
  </style>
@@ -307,19 +307,18 @@ export default {
307
307
  <router-link
308
308
  v-if="row.mgmt && row.mgmt.isReady && !row.hasError"
309
309
  data-testid="cluster-manager-list-explore-management"
310
- class="btn btn-sm role-secondary"
311
310
  :to="{name: 'c-cluster', params: {cluster: row.mgmt.id}}"
312
311
  >
313
- {{ t('cluster.explore') }}
312
+ <a href="javascript:;">
313
+ {{ t('cluster.explore') }}
314
+ </a>
314
315
  </router-link>
315
- <button
316
- v-else
316
+ <span
317
317
  data-testid="cluster-manager-list-explore"
318
- :disabled="true"
319
- class="btn btn-sm role-secondary"
318
+ v-else
320
319
  >
321
320
  {{ t('cluster.explore') }}
322
- </button>
321
+ </span>
323
322
  </template>
324
323
  </ResourceTable>
325
324
  </div>
package/mixins/brand.js CHANGED
@@ -176,7 +176,24 @@ export default {
176
176
  const vars = createCssVars(color, this.theme, name);
177
177
 
178
178
  for (const prop in vars) {
179
+
179
180
  document.body.style.setProperty(prop, vars[prop]);
181
+
182
+ // 主色调hover值动态
183
+ if (prop === '--primary-hover-bg') {
184
+ // 如果是你要设置透明度的变量,比如 hover
185
+ let value = '#E8F4FF';
186
+ if (vars[prop]) {
187
+ const match = vars[prop].match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
188
+ if (match) {
189
+ const [_, r, g, b] = match;
190
+ value = `rgba(${r}, ${g}, ${b}, 0.15)`;
191
+ }
192
+ }
193
+
194
+ document.body.style.setProperty('--nav-hover-color', vars[prop]);
195
+ document.body.style.setProperty('--nav-active', value);
196
+ }
180
197
  }
181
198
  },
182
199