dashboard-shell-shell 3.0.5-test.4 → 3.0.5-test.40

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 (163) hide show
  1. package/assets/brand/csp/favicon.png +0 -0
  2. package/assets/icons/iconfont.css +4 -1
  3. package/assets/images/pl/dark/logo.png +0 -0
  4. package/assets/styles/all.scss +23 -3
  5. package/assets/styles/base/_variables.scss +5 -5
  6. package/assets/styles/fonts/_icons.scss +3 -2
  7. package/assets/styles/global/_button.scss +8 -8
  8. package/assets/styles/global/_form.scss +1 -0
  9. package/assets/styles/global/_select.scss +1 -1
  10. package/assets/styles/global/_tooltip.scss +9 -5
  11. package/assets/styles/themes/_light.scss +6 -4
  12. package/assets/styles/vendor/vue-select.scss +2 -1
  13. package/assets/translations/en-us.yaml +59 -0
  14. package/assets/translations/zh-hans.yaml +168 -15
  15. package/components/ActionDropdown.vue +1 -1
  16. package/components/ButtonDropdown.vue +3 -1
  17. package/components/CodeMirror.vue +6 -4
  18. package/components/ContainerResourceLimit.vue +2 -2
  19. package/components/CopyToClipboard.vue +15 -0
  20. package/components/Drawer/Chrome.vue +2 -2
  21. package/components/Drawer/ResourceDetailDrawer/ConfigTab.vue +30 -27
  22. package/components/Drawer/ResourceDetailDrawer/YamlTab.vue +1 -1
  23. package/components/Drawer/ResourceDetailDrawer/index.vue +5 -4
  24. package/components/ExplorerMembers.vue +28 -4
  25. package/components/GlobalRoleBindings.vue +51 -112
  26. package/components/PodSecurityAdmission.vue +2 -2
  27. package/components/RelatedResources.vue +3 -0
  28. package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +1 -3
  29. package/components/Resource/Detail/Metadata/KeyValue.vue +8 -4
  30. package/components/Resource/Detail/Metadata/index.vue +3 -1
  31. package/components/Resource/Detail/TitleBar/Title.vue +4 -3
  32. package/components/Resource/Detail/TitleBar/Top.vue +2 -0
  33. package/components/Resource/Detail/TitleBar/composables.ts +16 -1
  34. package/components/Resource/Detail/TitleBar/index.vue +123 -25
  35. package/components/ResourceDetail/Masthead/index.vue +1 -1
  36. package/components/ResourceDetail/Masthead/latest.vue +1 -1
  37. package/components/ResourceDetail/Masthead/legacy.vue +8 -7
  38. package/components/ResourceDetail/legacy.vue +18 -16
  39. package/components/ResourceList/Masthead.vue +13 -17
  40. package/components/ResourceTable.vue +10 -0
  41. package/components/SideNav.vue +21 -21
  42. package/components/SortableTable/THead.vue +46 -1
  43. package/components/SortableTable/index.vue +40 -20
  44. package/components/Tabbed/index.vue +6 -1
  45. package/components/auth/Principal.vue +10 -5
  46. package/components/auth/RoleDetailEdit.vue +11 -7
  47. package/components/breadcrumb/index.vue +119 -0
  48. package/components/form/ArrayList.vue +164 -147
  49. package/components/form/ArrayListGrouped.vue +5 -3
  50. package/components/form/ChangePassword.vue +1 -1
  51. package/components/form/Command.vue +4 -5
  52. package/components/form/Conditions.vue +15 -1
  53. package/components/form/Footer.vue +1 -0
  54. package/components/form/HealthCheck.vue +0 -2
  55. package/components/form/HookOption.vue +87 -58
  56. package/components/form/InputWithSelect.vue +8 -7
  57. package/components/form/KeyValue.vue +20 -2
  58. package/components/form/LabeledSelect.vue +6 -3
  59. package/components/form/Labels.vue +2 -2
  60. package/components/form/MatchExpressions.vue +4 -4
  61. package/components/form/Members/ClusterMembershipEditor.vue +1 -1
  62. package/components/form/Members/ClusterPermissionsEditor.vue +31 -28
  63. package/components/form/Members/MembershipEditor.vue +2 -2
  64. package/components/form/NameNsDescription.vue +1 -1
  65. package/components/form/Networking.vue +6 -9
  66. package/components/form/NodeAffinity.vue +29 -28
  67. package/components/form/PodAffinity.vue +23 -23
  68. package/components/form/Probe.vue +15 -11
  69. package/components/form/ProjectMemberEditor.vue +28 -25
  70. package/components/form/ResourceQuota/Namespace.vue +4 -4
  71. package/components/form/ResourceQuota/NamespaceRow.vue +11 -9
  72. package/components/form/ResourceQuota/Project.vue +4 -4
  73. package/components/form/ResourceQuota/ProjectRow.vue +36 -30
  74. package/components/form/ResourceSelector.vue +1 -1
  75. package/components/form/Security.vue +1 -3
  76. package/components/form/Select.vue +7 -1
  77. package/components/form/ServiceNameSelect.vue +2 -5
  78. package/components/form/ServicePorts.vue +149 -75
  79. package/components/form/Taints.vue +2 -1
  80. package/components/form/Tolerations.vue +13 -9
  81. package/components/form/ValueFromResource.vue +110 -96
  82. package/components/form/WorkloadPorts.vue +143 -123
  83. package/components/formatter/WorkloadHealthScale.vue +4 -3
  84. package/components/nav/Group.vue +6 -0
  85. package/components/nav/Header.vue +7 -4
  86. package/components/nav/NamespaceFilter.vue +15 -21
  87. package/components/nav/TopLevelMenu.vue +99 -125
  88. package/components/nav/Type.vue +11 -3
  89. package/config/menuRouteMap.js +10 -0
  90. package/config/product/explorer.js +31 -9
  91. package/config/router/navigation-guards/index.js +61 -3
  92. package/detail/node.vue +28 -23
  93. package/dialog/AddCustomBadgeDialog.vue +17 -9
  94. package/edit/autoscaling.horizontalpodautoscaler/external-metric.vue +1 -1
  95. package/edit/autoscaling.horizontalpodautoscaler/hpa-scaling-rule.vue +9 -6
  96. package/edit/autoscaling.horizontalpodautoscaler/index.vue +3 -1
  97. package/edit/autoscaling.horizontalpodautoscaler/metric-identifier.vue +2 -2
  98. package/edit/autoscaling.horizontalpodautoscaler/metric-object-reference.vue +7 -5
  99. package/edit/autoscaling.horizontalpodautoscaler/metric-target.vue +5 -3
  100. package/edit/autoscaling.horizontalpodautoscaler/metrics-row.vue +2 -2
  101. package/edit/autoscaling.horizontalpodautoscaler/object-metric.vue +2 -2
  102. package/edit/autoscaling.horizontalpodautoscaler/pod-metric.vue +1 -1
  103. package/edit/autoscaling.horizontalpodautoscaler/resource-metric.vue +2 -2
  104. package/edit/configmap.vue +4 -0
  105. package/edit/networking.k8s.io.ingress/Certificate.vue +14 -5
  106. package/edit/networking.k8s.io.ingress/DefaultBackend.vue +2 -2
  107. package/edit/networking.k8s.io.ingress/Rule.vue +5 -11
  108. package/edit/networking.k8s.io.ingress/RulePath.vue +105 -96
  109. package/edit/networking.k8s.io.networkpolicy/PolicyRule.vue +3 -3
  110. package/edit/networking.k8s.io.networkpolicy/PolicyRulePort.vue +4 -2
  111. package/edit/networking.k8s.io.networkpolicy/PolicyRuleTarget.vue +12 -11
  112. package/edit/networking.k8s.io.networkpolicy/index.vue +1 -1
  113. package/edit/persistentvolume/index.vue +3 -1
  114. package/edit/persistentvolumeclaim.vue +2 -0
  115. package/edit/secret/index.vue +2 -2
  116. package/edit/service.vue +4 -1
  117. package/edit/storage.k8s.io.storageclass/index.vue +10 -8
  118. package/edit/storage.k8s.io.storageclass/provisioners/kubernetes.io/aws-ebs.vue +34 -27
  119. package/edit/storage.k8s.io.storageclass/provisioners/kubernetes.io/gce-pd.vue +15 -13
  120. package/edit/storage.k8s.io.storageclass/provisioners/kubernetes.io/vsphere-volume.vue +41 -39
  121. package/edit/workload/Job.vue +31 -34
  122. package/edit/workload/Upgrading.vue +5 -5
  123. package/edit/workload/index.vue +22 -18
  124. package/edit/workload/storage/Mount.vue +1 -0
  125. package/edit/workload/storage/awsElasticBlockStore.vue +9 -7
  126. package/edit/workload/storage/azureDisk.vue +14 -10
  127. package/edit/workload/storage/azureFile.vue +9 -7
  128. package/edit/workload/storage/csi/index.vue +6 -9
  129. package/edit/workload/storage/emptyDir.vue +7 -5
  130. package/edit/workload/storage/gcePersistentDisk.vue +9 -7
  131. package/edit/workload/storage/hostPath.vue +7 -5
  132. package/edit/workload/storage/nfs.vue +8 -6
  133. package/edit/workload/storage/persistentVolumeClaim/index.vue +12 -10
  134. package/edit/workload/storage/persistentVolumeClaim/persistentvolumeclaim.vue +20 -15
  135. package/edit/workload/storage/secret.vue +9 -6
  136. package/edit/workload/storage/vsphereVolume.vue +11 -7
  137. package/initialize/app-extended.js +7 -1
  138. package/models/provisioning.cattle.io.cluster.js +19 -18
  139. package/package.json +1 -1
  140. package/pages/account/index.vue +90 -118
  141. package/pages/account/pri.vue +229 -0
  142. package/pages/auth/login.vue +6 -1
  143. package/pages/auth/setup.vue +36 -17
  144. package/pages/c/_cluster/_product/namespaces.vue +1 -1
  145. package/pages/c/_cluster/auth/roles/index.vue +38 -5
  146. package/pages/c/_cluster/explorer/ConfigBadge.vue +1 -1
  147. package/pages/c/_cluster/explorer/tools/index.vue +6 -6
  148. package/pages/home.vue +3 -4
  149. package/pkg/tsconfig.json +9 -9
  150. package/pkg/vue.config.js +1 -1
  151. package/plugins/dashboard-store/resource-class.js +28 -27
  152. package/rancher-components/BadgeState/BadgeState.vue +33 -52
  153. package/rancher-components/Banner/Banner.vue +4 -1
  154. package/rancher-components/Form/Radio/RadioGroup.vue +9 -1
  155. package/rancher-components/LabeledTooltip/LabeledTooltip.vue +31 -2
  156. package/rancher-components/RcDropdown/RcDropdownMenu.vue +8 -7
  157. package/scripts/publish-shell.sh +1 -1
  158. package/store/i18n.js +4 -0
  159. package/store/type-map.js +1 -3
  160. package/types/shell/index.d.ts +4 -30
  161. package/utils/error.js +3 -1
  162. package/utils/errorTranslate.json +366 -2
  163. package/vue.config.js +1 -1
@@ -13,6 +13,8 @@ import { _CONFIG, _GRAPH, AS } from '@shell/config/query-params';
13
13
  import ButtonGroup from '@shell/components/ButtonGroup';
14
14
  import { ExtensionPoint, PanelLocation } from '@shell/core/types';
15
15
  import ExtensionPanel from '@shell/components/ExtensionPanel.vue';
16
+ import breadcrumb from '@shell/components/breadcrumb/index.vue'
17
+ import { useDefaultConfigTabProps } from '@shell/components/Drawer/ResourceDetailDrawer/composables';
16
18
 
17
19
  export interface Badge {
18
20
  color: 'bg-success' | 'bg-error' | 'bg-warning' | 'bg-info';
@@ -36,6 +38,7 @@ export interface TitleBarProps {
36
38
  showViewOptions?: boolean;
37
39
 
38
40
  onShowConfiguration?: (returnFocusSelector: string) => void;
41
+ parentRouteOverride?: string;
39
42
  }
40
43
 
41
44
  const showConfigurationIcon = require(`@shell/assets/images/icons/document.svg`);
@@ -43,9 +46,10 @@ const showConfigurationIcon = require(`@shell/assets/images/icons/document.svg`)
43
46
 
44
47
  <script setup lang="ts">
45
48
  const {
46
- resource, resourceTypeLabel, resourceTo, resourceName, description, badge, showViewOptions, onShowConfiguration,
49
+ parentRouteOverride, resource, resourceTypeLabel, resourceTo, resourceName, description, badge, showViewOptions, onShowConfiguration,
47
50
  } = defineProps<TitleBarProps>();
48
51
 
52
+
49
53
  const store = useStore();
50
54
  const i18n = useI18n(store);
51
55
  const router = useRouter();
@@ -54,6 +58,10 @@ const emit = defineEmits(['show-configuration']);
54
58
  const showConfigurationDataTestId = 'show-configuration-cta';
55
59
  const showConfigurationReturnFocusSelector = computed(() => `[data-testid="${ showConfigurationDataTestId }"]`);
56
60
 
61
+
62
+ const configTabProps = useDefaultConfigTabProps(resource);
63
+
64
+
57
65
  const currentView = ref(router?.currentRoute?.value?.query?.as || _CONFIG);
58
66
  const viewOptions = computed(() => {
59
67
  if (!showViewOptions) {
@@ -72,6 +80,45 @@ const viewOptions = computed(() => {
72
80
  ];
73
81
  });
74
82
 
83
+ const Svg = require('~shell/assets/images/API.svg')
84
+
85
+ const parent = computed(() => {
86
+
87
+ const product = store.getters['currentProduct'].name;
88
+
89
+ const defaultLocation = {
90
+ name: 'c-cluster-product-resource',
91
+ params: {
92
+ resource,
93
+ product,
94
+ }
95
+ };
96
+
97
+ const location = resource?.parentLocationOverride || defaultLocation;
98
+
99
+ if (parentRouteOverride) {
100
+ location.name = parentRouteOverride;
101
+ }
102
+
103
+ return { location };
104
+ });
105
+
106
+ const menuIcon = computed(() => {
107
+ const product = store.getters['productId'];
108
+ const resources = parent.value.location?.params?.resource || '';
109
+ return store.getters['type-map/groupsForVirTypes'](product, resources) || 'default menuIcon';
110
+ });
111
+
112
+ const hiddenTypes = [
113
+ 'harvesterhci.io.virtualmachinebackup',
114
+ ];
115
+
116
+ const shouldShowConfiguration = computed(() =>
117
+ onShowConfiguration &&
118
+ configTabProps &&
119
+ !hiddenTypes.includes(resource?.type)
120
+ );
121
+
75
122
  watch(
76
123
  () => currentView.value,
77
124
  () => {
@@ -82,33 +129,58 @@ watch(
82
129
 
83
130
  <template>
84
131
  <div class="title-bar">
132
+ <breadcrumb :resourceTypeLabel="resourceTypeLabel" :resource="resource"/>
85
133
  <Top>
86
134
  <Title class="title">
135
+ <span class="detailIcon-span">
136
+ <img
137
+ v-if="parentRouteOverride === 'account' && resource=== 'token'"
138
+ :src="Svg"
139
+ style="margin-top: 4px; margin-left: 5px;"
140
+ >
141
+ <i
142
+ v-else
143
+ :class="'icon-'+ menuIcon + ' detailIcon'"
144
+ />
145
+ </span>
146
+ <div class="resourceTypeLabelCls">
147
+ {{ resourceTypeLabel }}名称:
148
+ </div>
149
+ <span class="resource-name masthead-resource-title">
150
+ {{ resourceName }}
151
+ </span>
152
+ <BadgeState
153
+ v-if="badge"
154
+ class="badge-state"
155
+ :color="badge.color"
156
+ :label="badge.label"
157
+ />
158
+ <span
159
+ class="valid"
160
+ >|</span>
87
161
  <TabTitle :show-child="false">
88
- {{ resourceTypeLabel }}
162
+ 返回
89
163
  </TabTitle>
90
164
  <router-link
91
165
  v-if="resourceTo"
92
166
  :to="resourceTo"
93
167
  class="resource-link"
94
168
  >
95
- {{ resourceTypeLabel }}:
169
+ 返回
96
170
  </router-link>
97
171
  <span
98
172
  v-else
99
173
  class="resource-text"
100
174
  >
101
- {{ resourceTypeLabel }}:
175
+ 返回
102
176
  </span>
103
- <span class="resource-name masthead-resource-title">
104
- {{ resourceName }}
105
- </span>
106
- <BadgeState
107
- v-if="badge"
108
- class="badge-state"
109
- :color="badge.color"
110
- :label="badge.label"
111
- />
177
+ <div
178
+ v-if="description"
179
+ style="font-size: 12px;margin-left: 16px;"
180
+ class="bottom description text-deemphasized"
181
+ >
182
+ ( {{ description }} )
183
+ </div>
112
184
  </Title>
113
185
  <div class="actions">
114
186
  <!-- Please don't expand this pattern, this was a quick fix to resolve a conflict between the new masthead and fleet. -->
@@ -118,7 +190,7 @@ watch(
118
190
  :options="viewOptions"
119
191
  />
120
192
  <RcButton
121
- v-if="onShowConfiguration"
193
+ v-if="shouldShowConfiguration"
122
194
  :data-testid="showConfigurationDataTestId"
123
195
  class="show-configuration"
124
196
  :primary="true"
@@ -134,6 +206,7 @@ watch(
134
206
  </RcButton>
135
207
  <ActionMenu
136
208
  v-if="actionMenuResource"
209
+ :showIcon="true"
137
210
  button-role="multiAction"
138
211
  :resource="actionMenuResource"
139
212
  data-testid="masthead-action-menu"
@@ -141,12 +214,6 @@ watch(
141
214
  />
142
215
  </div>
143
216
  </Top>
144
- <div
145
- v-if="description"
146
- class="bottom description text-deemphasized"
147
- >
148
- {{ description }}
149
- </div>
150
217
  <ExtensionPanel
151
218
  :resource="resource"
152
219
  :type="ExtensionPoint.PANEL"
@@ -156,12 +223,39 @@ watch(
156
223
  </template>
157
224
 
158
225
  <style lang="scss" scoped>
226
+
227
+ .detailIcon-span{
228
+ width: 24px;
229
+ height: 24px;
230
+ display: inline-block;
231
+ position: relative;
232
+ background: var(--primary);
233
+ margin-right: 10px;
234
+ }
235
+ .detailIcon{
236
+ position: absolute;
237
+ color: #fff;
238
+ font-size: 38px;
239
+ left: 4px;
240
+ top: -2px;
241
+ }
242
+
243
+ .detailIcon-span-title{
244
+ font-weight: bold;
245
+ }
246
+ .resourceTypeLabelCls {
247
+ font-weight: 700;
248
+ }
249
+ .valid{
250
+ color: #d7d7d7;
251
+ margin: 0px 10px;
252
+ }
159
253
  .title-bar {
160
254
  min-width: 740px;
161
255
 
162
256
  .badge-state {
163
257
  font-size: 16px;
164
- margin-left: 12px;
258
+ margin-left: 5px;
165
259
  position: relative;
166
260
  }
167
261
 
@@ -170,15 +264,19 @@ watch(
170
264
  }
171
265
 
172
266
  &:deep() button[data-testid="masthead-action-menu"] {
173
- border-radius: 4px;
174
- width: 35px;
175
- height: 40px;
176
- margin-left: 16px;
267
+ border-radius: 2px;
268
+ width: 32px;
269
+ height: 32px;
270
+ margin-left: 10px;
177
271
 
178
272
  display: inline-flex;
179
273
  flex-direction: row;
180
274
  justify-content: center;
181
275
  align-items: center;
276
+
277
+ a{
278
+ color: #fff;
279
+ }
182
280
  }
183
281
 
184
282
  .description {
@@ -60,6 +60,6 @@ const showLatestMasthead = computed(() => isNewDetailPageEnabled.value && isView
60
60
  <style lang="scss" scoped>
61
61
  .new.state-banner {
62
62
  margin: 0;
63
- margin-top: 16px;
63
+ margin-bottom: 20px;
64
64
  }
65
65
  </style>
@@ -39,6 +39,6 @@ const bannerProps = useResourceDetailBannerProps(props.value);
39
39
  <style lang="scss" scoped>
40
40
  .new.state-banner {
41
41
  margin: 0;
42
- margin-top: 16px;
42
+ margin-bottom: 20px;
43
43
  }
44
44
  </style>
@@ -254,7 +254,7 @@ export default {
254
254
  },
255
255
 
256
256
  parent() {
257
- const displayName = this.value?.parentNameOverride || this.$store.getters['type-map/labelFor'](this.schema);
257
+ let displayName = this.value?.parentNameOverride || this.$store.getters['type-map/labelFor'](this.schema);
258
258
  const product = this.$store.getters['currentProduct'].name;
259
259
 
260
260
  const defaultLocation = {
@@ -418,14 +418,14 @@ export default {
418
418
  demoDisplay() {
419
419
  const product = this.$store.getters['productId'];
420
420
 
421
- const resources = this.location?.params?.resource || ''
421
+ const resources = this.location?.params?.resource || this.$route.params?.resource || ''
422
422
 
423
423
  const productId = this.$store.getters['type-map/groupForBasicType'](this.$store.getters['productId'], resources);
424
424
 
425
425
  if (productId === undefined) {
426
426
  return '';
427
427
  }
428
- const parts = productId.split('::');
428
+ const parts = productId?.split('::') || [];
429
429
  const newString = 'root';
430
430
 
431
431
  if (!parts?.includes(newString)) {
@@ -441,9 +441,10 @@ export default {
441
441
  menuIcon() {
442
442
  const product = this.$store.getters['productId'];
443
443
 
444
- const resources = this.location?.params?.resource || ''
444
+ const resources = this.location?.params?.resource || this.$route.params?.resource || ''
445
445
 
446
- return this.$store.getters['type-map/groupsForVirTypes'](product, resources);
446
+
447
+ return this.$store.getters['type-map/groupsForVirTypes'](product, resources) || 'default menuIcon';
447
448
  },
448
449
 
449
450
  location() {
@@ -506,7 +507,7 @@ export default {
506
507
  <span>/</span>
507
508
  </span>
508
509
  <span class="excram-last-name">
509
- {{ (realMode === 'view'? '查看': realMode === 'edit' ? '编辑':'创建') + parent.displayName }}
510
+ {{ (realMode === 'view'? '查看': realMode === 'edit' ? '编辑':'创建') + parent?.displayName }}
510
511
  </span>
511
512
  </div>
512
513
  <header>
@@ -530,7 +531,7 @@ export default {
530
531
  :class="'icon-'+ menuIcon + ' detailIcon'"
531
532
  />
532
533
  </span>
533
- <span class="detailIcon-span-title">{{ realMode=== 'create'? '创建': '' }}{{ parent.displayName }}{{ realMode=== 'create'? '': '名称:' }}</span>
534
+ <span class="detailIcon-span-title">{{ realMode=== 'create'? '创建': '' }}{{ parent?.displayName }}{{ realMode=== 'create'? '': '名称:' }}</span>
534
535
  <span v-if="realMode !== 'create'">
535
536
  <span v-if="value.detailPageHeaderActionOverride && value.detailPageHeaderActionOverride(realMode)">{{ value.detailPageHeaderActionOverride(realMode) }}</span>
536
537
  <t
@@ -464,7 +464,7 @@ export default {
464
464
 
465
465
  <template>
466
466
  <Loading v-if="$fetchState.pending || notFound" />
467
- <div v-else>
467
+ <div style="padding: 20px;height: 100%;" v-else>
468
468
  <Masthead
469
469
  v-if="showMasthead"
470
470
  :resource="resourceType"
@@ -478,6 +478,8 @@ export default {
478
478
  :resource-subtype="resourceSubtype"
479
479
  :parent-route-override="parentRouteOverride"
480
480
  :store-override="storeOverride"
481
+
482
+ :isManuallyHide="false"
481
483
  >
482
484
  <!-- <DetailTop
483
485
  v-if="isView && isDetail"
@@ -521,21 +523,21 @@ export default {
521
523
  />
522
524
 
523
525
  <component
524
- :is="showComponent"
525
- v-else
526
- ref="comp"
527
- v-model:value="value"
528
- v-bind="$data"
529
- :done-params="doneParams"
530
- :done-route="doneRoute"
531
- :mode="mode"
532
- :initial-value="initialModel"
533
- :live-value="liveModel"
534
- :real-mode="realMode"
535
- :class="{'flex-content': flexContent}"
536
- @update:value="$emit('input', $event)"
537
- @update:mode="setMode"
538
- @set-subtype="setSubtype"
526
+ :is="showComponent"
527
+ v-else
528
+ ref="comp"
529
+ v-model:value="value"
530
+ v-bind="$data"
531
+ :done-params="doneParams"
532
+ :done-route="doneRoute"
533
+ :mode="mode"
534
+ :initial-value="initialModel"
535
+ :live-value="liveModel"
536
+ :real-mode="realMode"
537
+ :class="{'flex-content': flexContent}"
538
+ @update:value="$emit('input', $event)"
539
+ @update:mode="setMode"
540
+ @set-subtype="setSubtype"
539
541
  />
540
542
 
541
543
  <button
@@ -156,37 +156,36 @@ export default {
156
156
  demoDisplay() {
157
157
 
158
158
  const product = this.$store.getters['productId'];
159
- const productId = this.$store.getters['type-map/groupForBasicType'](this.$store.getters['productId'], this._createLocation.params.resource);
160
- const parts = productId?.split('::');
161
- const newString = 'root';
162
-
163
- // const product = this.$store.getters['productId'];
164
- // const productId = this.$store.getters['type-map/groupForBasicType'](this.$store.getters['productId'], this._createLocation.params.resource);
159
+ const productId = this.$store.getters['type-map/groupForBasicType'](this.$store.getters['productId'], this._createLocation?.params?.resource);
160
+ console.log(product, 'product')
161
+ console.log(productId, 'productId')
162
+ console.log(this._createLocation?.params?.resource, 'this._createLocation?.params?.resource')
165
163
 
166
- // const parts = productId?.split('::') || [];
167
- // const newString = 'root';
164
+ const parts = productId?.split('::') || [];
165
+ const newString = 'root';
168
166
 
167
+ if (!parts) {
168
+ if (this.$route.path.includes('/c/local/explorer/secret')) {
169
+ parts = ['storage']
170
+ }
171
+ }
169
172
 
170
173
  const breadcrumbList = {
171
174
  'harvesterhci.io.management.cluster': {
172
175
  origin: 'Harvester 集群',
173
176
  bread: ['虚拟化管理'],
174
- description: '提供虚拟化集群的实时健康状态监控、版本号管理及资源负载管理,支持批量导入/删除集群、配置调优与权限分级功能,实现高效运维管控。'
175
177
  },
176
178
  'management.cattle.io.user': {
177
179
  origin: '用户',
178
180
  bread: ['用户 & 认证'],
179
- description: '用于管理用户账号,支持创建、维护用户信息,可设置用户权限、管理密码等,保障系统资源仅由授权用户访问,提升系统安全性。'
180
181
  },
181
182
  'management.cattle.io.setting':{
182
183
  origin: '基础设置',
183
184
  bread: ['全局设置'],
184
- description: '统一配置平台基础选项与全局设置,支持CA证书、密码规则、域名、Token时效等核心配置。'
185
185
  },
186
186
  'management.cattle.io.feature':{
187
187
  origin: '功能开关',
188
188
  bread: ['全局设置'],
189
- description: '还没有添加描述。。。。'
190
189
  },
191
190
  }
192
191
  const resourcePath = this.$route.params.resource || ''
@@ -194,7 +193,6 @@ export default {
194
193
  const breadcrumb = []
195
194
  if (breadcrumbList[resourcePath] && Object.keys(breadcrumbList[resourcePath]).length > 0) {
196
195
  breadcrumb.push(...breadcrumbList[resourcePath].bread)
197
- this.description = breadcrumbList[resourcePath].description
198
196
  return breadcrumb
199
197
  } else {
200
198
  if (!parts?.includes(newString)) {
@@ -261,8 +259,6 @@ export default {
261
259
  for (const entry of entries) {
262
260
  const width = entry?.contentRect?.width && entry.contentRect.width > 0 ? entry.contentRect.width + 10 : 0
263
261
 
264
- console.log(width, ' width----------------------------')
265
-
266
262
  this.$store.commit('type-map/setActionsWidth', width)
267
263
  }
268
264
  })
@@ -325,7 +321,7 @@ export default {
325
321
  <!-- 操作按钮区域 -->
326
322
  <div
327
323
  ref="actionsContainer"
328
- v-if="!(tabList.includes(_typeDisplay)) && mainButtonVisible"
324
+ v-if="!(tabList.includes(_typeDisplay))"
329
325
  class="actions-container actions-positioning"
330
326
  style="min-height: 32px;align-self: flex-end;"
331
327
  >
@@ -419,6 +415,6 @@ export default {
419
415
  .actions-positioning {
420
416
  position: absolute;
421
417
  bottom: -48px;
422
- z-index: 20;
418
+ z-index: 15;
423
419
  }
424
420
  </style>
@@ -689,6 +689,16 @@ export default {
689
689
  />
690
690
  </template>
691
691
 
692
+ <template
693
+ v-if="showGrouping"
694
+ #header-button-left
695
+ >
696
+ <slot
697
+ name="header-button-left"
698
+ />
699
+ </template>
700
+
701
+
692
702
  <template
693
703
  v-if="externalPaginationEnabled"
694
704
  #watch-controls
@@ -244,31 +244,31 @@ export default {
244
244
 
245
245
  replaceWith(this.groups, ...sortBy(out, ['weight:desc', 'label']));
246
246
 
247
- // if (this.principal.loginName !== 'admin') {
248
- // // 递归过滤函数(根据 label)
249
- // this.groups = this.filterMenus(this.groups);
250
- // }
247
+
248
+ if (sessionStorage.getItem('TOPLEVELPERMISSIONS') !== 'superadmin') {
249
+ // 递归过滤函数(根据 label)
250
+ this.groups = this.filterMenus(this.groups);
251
+ }
251
252
 
252
253
 
253
254
  this.gettingGroups = false;
254
255
  },
255
256
 
256
- // filterMenus(menus) {
257
- // return menus
258
- // .filter(item => item.label !== 'RBAC') // 过滤掉顶层 RBAC
259
- // .map(item => {
260
- // let newItem = { ...item };
261
- // if (newItem.children) {
262
- // // 过滤掉 children 里的 "资源大盘"
263
- // newItem.children = newItem.children.filter(
264
- // child => child.label !== '资源大盘'
265
- // );
266
- // // 递归处理剩下的 children
267
- // newItem.children = filterMenus(newItem.children);
268
- // }
269
- // return newItem;
270
- // });
271
- // },
257
+ filterMenus(menus) {
258
+ return menus.filter(item => item.name !== 'inUse' && item.name !== 'apps') // 过滤掉顶层 inUse 和 apps
259
+ // .map(item => {
260
+ // let newItem = { ...item };
261
+ // if (newItem.children) {
262
+ // // 过滤掉 children 里的 "资源大盘"
263
+ // newItem.children = newItem.children.filter(
264
+ // child => child.label !== '资源大盘'
265
+ // );
266
+ // // 递归处理剩下的 children
267
+ // newItem.children = filterMenus(newItem.children);
268
+ // }
269
+ // return newItem;
270
+ // });
271
+ },
272
272
 
273
273
  getProductsGroups(out, loadProducts, namespaceMode, productMap) {
274
274
  const clusterId = this.$store.getters['clusterId'];
@@ -436,7 +436,7 @@ export default {
436
436
  :aria-label="t('nav.ariaLabel.sideNav')"
437
437
  >
438
438
  <div class="side-all-title">
439
- {{ prod == 'Cloud' && currentCluster ? '控制台' : prod }}
439
+ {{ (prod == 'Cloud' || prod == 'Harvester') && currentCluster ? '控制台' : prod }}
440
440
  </div>
441
441
 
442
442
  <!-- Actual nav -->
@@ -208,9 +208,54 @@ export default {
208
208
  return null;
209
209
  }
210
210
 
211
+ // 创建英文到中文的映射
212
+ const tooltipMap = {
213
+ 'The minimum number of pods that must be available': '必须可用的 Pod 最小数量',
214
+ 'The maximum number of pods that may be unavailable': '允许不可用的 Pod 最大数量',
215
+ 'Calculated number of pods that may be disrupted at this time': '当前允许中断的 Pod 数量',
216
+ 'Request represents a minimum amount of cpu/memory that a container may consume': 'Request 表示容器必须保证的最小 CPU/内存资源量',
217
+ 'Limits control the maximum amount of cpu/memory that a container may use independent of contention on the node': 'Limits 控制容器可使用的 CPU/内存最大资源量,该限制与节点上的资源竞争情况无关',
218
+ 'If referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. For example, if the object reference is to a container within a pod, this would take on a value like: "spec.containers{name}" (where "name" refers to the name of the container that triggered the event) or if no container name is specified "spec.containers[2]" (container with index 2 in this pod). This syntax is chosen only to have some well-defined way of referencing a part of an object': '如果引用对象的一部分而不是整个对象,则此字符串应包含有效的JSON/Go字段访问语句,例如desiredState.manifest.containers[2]。例如,如果对象引用指向pod中的一个容器,则其值为:“spec.containers{name}”(其中“name”表示触发事件的容器的名称),或者如果没有指定容器名称,则为“spec.containers[2]”(此pod中索引为2的容器)。选择此语法只是为了有一些定义良好的方式来引用对象的一部分',
219
+ 'The number of times this event has occurred': '此事件发生的次数',
220
+ 'The component reporting this event. Should be a short machine understandable string': '用于报告此事件的组件名称,应为简短且可被程序识别的字符串',
221
+ 'The time at which the event was first recorded. (Time of server receipt is in TypeMeta.)': '事件首次被记录的时间。(服务器接收时间为TypeMeta。)',
222
+ 'Information when was the last time the job was successfully scheduled': '上次成功调度的任务信息',
223
+ 'The schedule in Cron format, see https://en.wikipedia.org/wiki/Cron': '以 Cron 格式表示的调度,详见 https://en.wikipedia.org/wiki/Cron',
224
+ 'The number of nodes that should be running the daemon pod and have one or more of the daemon pod running and ready': '运行该守护 Pod 且至少有一个 Pod 就绪的节点数量',
225
+ 'The number of nodes that are running at least 1 daemon pod and are supposed to run the daemon pod. More info: https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/': '运行至少一个守护 Pod 且应运行该 Pod 的节点数量。详情:https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/',
226
+ 'The total number of nodes that should be running the daemon pod (including nodes correctly running the daemon pod). More info: https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/': '应运行该守护 Pod 的节点总数(含已正确运行的节点)。详情:https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/',
227
+ 'Number of the pod with ready state': '就绪 Pod 数量',
228
+ 'Total number of non-terminated pods targeted by this deployment that have the desired template spec': '该 Deployment 管理的符合模板规范的未终止 Pod 总数',
229
+ 'Total number of available pods (ready for at least minReadySeconds) targeted by this deployment': '该 Deployment 管理的可用 Pod 数(至少就绪 minReadySeconds 秒)',
230
+ 'The number of pods which reached phase Succeeded. The value increases monotonically for a given spec. However, it may decrease in reaction to scale down of elastic indexed jobs': '已完成(Succeeded)的 Pod 数量,通常单调增加,但弹性索引 Job 缩减时可能减少。',
231
+ 'The aggregate readiness state of this pod for accepting traffic': 'Pod 接收流量的就绪状态',
232
+ 'The number of times the containers in this pod have been restarted and when the last container in this pod has restarted': 'Pod 容器重启次数及最后重启时间',
233
+ 'podIP address allocated to the pod. Routable at least within the cluster. Empty if not yet allocated': 'Pod 分配的 IP 地址(集群内可路由),未分配时为空。',
234
+ 'phase represents the current phase of PersistentVolumeClaim': 'phase 表示 PersistentVolumeClaim 的当前阶段',
235
+ 'volumeName is the binding reference to the PersistentVolume backing this claim': 'volumeName是支持此声明的持久卷的绑定引用',
236
+ 'capacity represents the actual resources of the underlying volume': 'capacity 表示底层卷的实际资源',
237
+ 'accessModes contains the actual access modes the volume backing the PVC has. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1': '卷的实际访问模式(支撑该 PVC)。详情:https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1',
238
+ 'StorageClass of the pvc': 'PVC 的存储类',
239
+ 'VolumeAttributesClass of the pvc': 'PVC 的卷属性类',
240
+ 'volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec': 'PVC 卷模式,未指定时默认为 Filesystem',
241
+ 'Selects the pods to which this NetworkPolicy object applies. The array of ingress rules is applied to any pods selected by this field. Multiple network policies can select the same set of pods. In this case, the ingress rules for each are combined additively. This field is NOT optional and follows standard label selector semantics. An empty podSelector matches all pods in this namespace': '选择此 NetworkPolicy 作用的 Pod。所选 Pod 会应用所有 ingress 规则。多个 NetworkPolicy 可选择同一 Pod 集合,其 ingress 规则会叠加。该字段必填,空 podSelector 匹配命名空间内所有 Pod。',
242
+ 'CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC.Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata ': '对象创建时间的时间戳(UTC,RFC3339 格式),表示对象创建时的服务器时间。 系统自动填充,仅可读,客户端不可设置,不保证跨操作的先后顺序。列表对象该字段为 null。 更多信息:https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata',
243
+ 'The time at which the most recent occurrence of this event was recorded': '事件最近记录时间',
244
+ };
245
+
211
246
  const exists = this.$store.getters['i18n/exists'];
212
247
 
213
- return exists(col.tooltip) ? this.t(col.tooltip) : col.tooltip;
248
+ // 如果 tooltip 是语言包键名
249
+ if (exists(col.tooltip)) {
250
+ return this.t(col.tooltip);
251
+ }
252
+
253
+ // 如果 tooltip 是英文文本,使用映射
254
+ if (tooltipMap[col.tooltip]) {
255
+ return tooltipMap[col.tooltip];
256
+ }
257
+
258
+ return col.tooltip; // 回退到原始文本
214
259
  },
215
260
  }
216
261