dashboard-shell-shell 3.0.5-test.25 → 3.0.5-test.27

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.
@@ -1,3 +1,21 @@
1
+ /* Chrome, Edge, Safari */
2
+ input[type="password"]::-webkit-textfield-decoration-container,
3
+ input[type="password"]::-webkit-inner-spin-button,
4
+ input[type="password"]::-webkit-clear-button {
5
+ display: none !important;
6
+ }
7
+
8
+ /* Edge / IE */
9
+ input[type="password"]::-ms-reveal {
10
+ display: none !important;
11
+ }
12
+
13
+ /* Firefox */
14
+ input[type="password"]::-moz-reveal {
15
+ display: none !important;
16
+ }
17
+
18
+
1
19
  .info-tab-title{
2
20
  font-size: 14px;
3
21
  line-height: 19px;
@@ -38,8 +38,9 @@ $icon-inverse: #fff !default;
38
38
 
39
39
  // Sizes
40
40
  .icon-fw {
41
- width: math.div(18em, 14);
42
- text-align: center;
41
+ width: 32px;
42
+ // width: math.div(18em, 14);
43
+ // text-align: center;
43
44
  }
44
45
 
45
46
  .icon-sm {
@@ -596,6 +596,7 @@ assignTo:
596
596
 
597
597
  stateLabel:
598
598
  Pending migration: 待迁移
599
+ Imagepullbackoff: 镜像拉取失败
599
600
  VM error: 错误
600
601
  Locked: 锁定
601
602
  Bound: 已绑定
@@ -5532,7 +5533,12 @@ tableHeaders:
5532
5533
  missingPL: 缺少 PL
5533
5534
  memory: 内存
5534
5535
  monitored: 已监控
5536
+ request: 资源请求量
5537
+ limit: 资源限制
5535
5538
  name: 名称
5539
+ maxunavailable: 最大不可用数
5540
+ minAvailable: 最小可用数
5541
+ alloweddisruptions: 允许中断数
5536
5542
  nameDisplay: 显示名称
5537
5543
  nameUnlinked: 名称
5538
5544
  namespace: 资源组
@@ -6520,10 +6526,6 @@ typeDescription:
6520
6526
  projectsnamespaces: 项目/资源组是用于在集群内实现资源隔离和多租户管理的基本单元。通过项目可以对一组命名空间及相关资源进行统一的权限、配额和策略管理。
6521
6527
  members: 集群和项目成员管理页面用于配置用户和用户组对资源的访问权限。通过角色绑定(RBAC)来控制成员在集群或项目范围内的操作权限,实现安全的协同管理。
6522
6528
  event: 事件记录了 Kubernetes 资源(如 Pod、节点等)的状态变化、错误信息和生命周期事件。通过查看事件可以快速诊断应用部署和运行中的问题。
6523
- apps.deployment: Deployment 提供了对 Pod 和 ReplicaSet 的声明式更新管理。您可以定义应用的期望状态(如副本数、镜像版本),Deployment 控制器将以受控的方式逐步完成部署和滚动更新。
6524
- batch.job: Job 用于创建一个或多个 Pod 并确保指定数量的 Pod 成功终止。适用于运行一次性任务或批处理作业,任务完成后 Pod 不会自动重启。
6525
- apps.statefulset: StatefulSet 用于管理有状态应用的工作负载 API 对象。它为每个 Pod 提供稳定的网络标识符和持久化存储,确保 Pod 的部署、扩展、更新和删除都有序进行。
6526
- pod: Pod 是 Kubernetes 中最小的可部署计算单元,包含一个或多个共享存储和网络资源的容器。Pod 代表了集群中运行的单个应用实例,是工作负载执行的实际载体。
6527
6529
  autoscaling.horizontalpodautoscaler: HorizontalPodAutoscaler (HPA) 用于根据观察到的 CPU 利用率或其他自定义指标自动调整工作负载的 Pod 副本数量,实现应用的水平自动扩缩容。
6528
6530
  networking.k8s.io.ingress: Ingress 用于管理对集群内服务的外部访问,提供 HTTP 和 HTTPS 路由规则。通过 Ingress 可以配置负载均衡、SSL 终止和基于名称的虚拟主机等能力。
6529
6531
  service: Service 用于将一组 Pod 暴露为网络服务,提供稳定的 IP 地址和 DNS 名称,并实现负载均衡。Service 确保您的应用程序在网络中可被发现和可靠访问。
@@ -6537,6 +6539,12 @@ typeDescription:
6537
6539
  limitrange: 限制范围用于在命名空间内限制资源的使用量,包括 Pod 的计算资源(CPU、内存)请求和限制、存储卷大小以及可创建的资源对象数量,防止资源过度消耗。
6538
6540
  resourcequota: 资源配额用于限制命名空间可以使用的总体资源总量,包括计算资源、存储资源以及可创建的对象数量。它确保命名空间内的资源使用不会超过分配的配额限制。
6539
6541
  policy.poddisruptionbudget: Pod 中断预算用于限制自愿中断期间同时终止的 Pod 副本数量,确保应用的高可用性。它可以防止在节点维护或集群缩容时导致的应用服务中断。
6542
+ apps.daemonset: DaemonSet 在每个符合条件的节点上仅运行一个 Pod。当新节点添加到集群时,DaemonSet 会自动部署新节点。推荐用于全系统或可垂直扩展,且每个节点永远不需要超过一个 pod 的工作负载。
6543
+ apps.deployment: Deployment 运行分布在符合条件的节点中的可扩展数量的 Pod 副本。变更会逐步推出,并可回滚到之前的版本。推荐用于无状态和水平可扩展的工作负载。
6544
+ apps.statefulset: StatefulSet 管理有状态的应用,并保证创建的 Pod 的顺序和唯一性。推荐用于具有持久化存储或严格身份、法定人数或升级顺序要求的工作负载。
6545
+ batch.cronjob: CronJob 创建 Job,然后按照重复调度来运行 Pod。该调度以标准的 Unix cron 格式表示,并使用 Kubernetes Control Plane 的时区(通常是 UTC)。
6546
+ batch.job: Job 创建一个或多个 Pod。 Job 通过运行 Pod 直到其成功退出,以可靠执行一次性任务。失败的 Pod 会自动被替换,直到达到指定的完成运行次数。Job 还可以并行运行多个 Pod,或作为批处理工作队列。
6547
+ pod: Pod 是你可以在 Kubernetes 中创建和管理的最小可部署计算单元。Pod 是一个或多个容器,具有共享的存储和网络资源以及运行容器的规范。
6540
6548
  typeLabel:
6541
6549
  management.cattle.io.project: |-
6542
6550
  {count, plural,
@@ -6786,8 +6794,8 @@ typeLabel:
6786
6794
  }
6787
6795
  autoscaling.horizontalpodautoscaler: |-
6788
6796
  {count, plural,
6789
- one { HorizontalPodAutoscaler }
6790
- other { HorizontalPodAutoscaler }
6797
+ one { HPA }
6798
+ other { HPA }
6791
6799
  }
6792
6800
  networking.k8s.io.ingress: |-
6793
6801
  {count, plural,
@@ -216,7 +216,7 @@ export default defineComponent({
216
216
  <div
217
217
  v-for="(psaControl, level, i) in psaControls"
218
218
  :key="i"
219
- class="row row--y-center mb-20"
219
+ class="row row--y-center"
220
220
  >
221
221
  <span class="col span-1">
222
222
  <Checkbox
@@ -418,7 +418,7 @@ 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
 
@@ -441,7 +441,8 @@ 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
 
446
447
  return this.$store.getters['type-map/groupsForVirTypes'](product, resources) || 'default menuIcon';
447
448
  },
@@ -157,9 +157,12 @@ export default {
157
157
 
158
158
  const product = this.$store.getters['productId'];
159
159
  const productId = this.$store.getters['type-map/groupForBasicType'](this.$store.getters['productId'], this._createLocation?.params?.resource);
160
- console.log(this._createLocation, 'this._createLocation?.params?.resource')
160
+ console.log(product, 'product')
161
+ console.log(productId, 'productId')
161
162
  console.log(this._createLocation?.params?.resource, 'this._createLocation?.params?.resource')
163
+
162
164
  let parts = productId?.split('::');
165
+ console.log(parts, 'parts11111')
163
166
  const newString = 'root';
164
167
 
165
168
  if (!parts) {
@@ -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'];
@@ -208,9 +208,29 @@ 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
+
219
+ };
220
+
211
221
  const exists = this.$store.getters['i18n/exists'];
212
222
 
213
- return exists(col.tooltip) ? this.t(col.tooltip) : col.tooltip;
223
+ // 如果 tooltip 是语言包键名
224
+ if (exists(col.tooltip)) {
225
+ return this.t(col.tooltip);
226
+ }
227
+
228
+ // 如果 tooltip 是英文文本,使用映射
229
+ if (tooltipMap[col.tooltip]) {
230
+ return tooltipMap[col.tooltip];
231
+ }
232
+
233
+ return col.tooltip; // 回退到原始文本
214
234
  },
215
235
  }
216
236
 
@@ -1074,12 +1074,22 @@ export default {
1074
1074
  if ( col.labelKey ) {
1075
1075
  return this.t(col.labelKey, undefined, true);
1076
1076
  } else if ( col.label ) {
1077
- return col.label;
1077
+ // 判断 label 是否为中文
1078
+ if (this.isChinese(col.label)) {
1079
+ return col.label;
1080
+ } else {
1081
+ return this.t(`tableHeaders.${col.label.replace(/\s+/g, '').toLowerCase()}`, undefined, true);
1082
+ }
1078
1083
  }
1079
1084
 
1080
1085
  return ucFirst(col.name);
1081
1086
  },
1082
1087
 
1088
+ // 判断字符串是否包含中文
1089
+ isChinese(str) {
1090
+ return /[\u4e00-\u9fa5]/.test(str);
1091
+ },
1092
+
1083
1093
  valueFor(row, col, isLabel) {
1084
1094
  if (typeof col.value === 'function') {
1085
1095
  return col.value(row);
@@ -2669,7 +2679,7 @@ export default {
2669
2679
  .sort-table-div{
2670
2680
  width:100%;
2671
2681
  white-space:nowrap;
2672
- overflow-x: auto;
2682
+ // overflow-x: auto;
2673
2683
  }
2674
2684
 
2675
2685
  /* 滚动阴影左边 */
@@ -44,13 +44,8 @@ export default {
44
44
  demoDisplay() {
45
45
 
46
46
  const resources = this.$route.params?.resource || ''
47
- console.log(resources, 'resources')
48
-
49
- const productId = this.$store.getters['type-map/groupForBasicType'](this.$store.getters['productId'], resources);
50
-
51
- if (productId === undefined) {
52
- return '';
53
- }
47
+
48
+ let productId = this.$store.getters['type-map/groupForBasicType'](this.$store.getters['productId'], resources);
54
49
  const parts = productId.split('::');
55
50
  const newString = 'root';
56
51
 
@@ -68,6 +68,20 @@ export default {
68
68
  };
69
69
  });
70
70
  },
71
+ },
72
+ methods: {
73
+ hans(row) {
74
+ const conditionMap = {
75
+ 'DiskPressure': '磁盘压力',
76
+ 'MemoryPressure': '内存压力',
77
+ 'PIDPressure': '进程数压力',
78
+ 'Ready': '就绪状态',
79
+ 'EtcdIsVoter': 'Etcd投票成员',
80
+ 'NetworkUnavailable': '网络不可用',
81
+ };
82
+
83
+ return conditionMap[row.condition] || row.condition;
84
+ }
71
85
  }
72
86
  };
73
87
  </script>
@@ -83,7 +97,7 @@ export default {
83
97
  :search="false"
84
98
  >
85
99
  <template #cell:condition="{row}">
86
- <span :class="{'text-error': row.error}">{{ row.condition }}</span>
100
+ <span :class="{'text-error': row.error}">{{ hans(row) }}</span>
87
101
  </template>
88
102
 
89
103
  <template #cell:status="{row}">
@@ -393,7 +393,7 @@ export default {
393
393
  position: relative;
394
394
 
395
395
  :deep() .vs__actions:after {
396
- padding-top: 2px;
396
+ // padding-top: 2px;
397
397
  }
398
398
 
399
399
  :deep() .v-select.select-input-view {
@@ -204,6 +204,7 @@ export default {
204
204
  <div
205
205
  :id="id"
206
206
  class="hs-popover__content"
207
+ style="width: auto;padding-right: 10px;"
207
208
  :class="{expanded, [id]:true}"
208
209
  >
209
210
  <div>
@@ -212,14 +213,14 @@ export default {
212
213
  :key="i"
213
214
  class="counts"
214
215
  >
215
- <span class="counts-label">{{ obj.label }}</span>
216
- <span>{{ obj.value }}</span>
216
+ <span class="counts-label" style="white-space: normal;">{{ obj.label }}</span>
217
+ <span style="white-space: normal;">{{ obj.value }}</span>
217
218
  </div>
218
219
  <div
219
220
  v-if="canScale"
220
221
  class="text-center scale"
221
222
  >
222
- <span>{{ t('tableHeaders.scale') }} </span>
223
+ <span style="white-space: nowrap;margin-right: 5px;">{{ t('tableHeaders.scale') }} </span>
223
224
  <PlusMinus
224
225
  :value="row.spec.replicas"
225
226
  :disabled="disabled"
@@ -1,5 +1,7 @@
1
1
  <script>
2
2
  import Type from '@shell/components/nav/Type';
3
+ import { menuRouteMap } from '@shell/config/menuRouteMap';
4
+
3
5
  export default {
4
6
  name: 'Group',
5
7
 
@@ -178,6 +180,7 @@ export default {
178
180
 
179
181
  let parentPath = '';
180
182
  const cluster = this.$route.params?.cluster;
183
+ const resource = this.$route?.params?.resource || ''
181
184
 
182
185
  // Where we use nested route configuration, consider the parent route when trying to identify the nav location
183
186
  if (this.$route.matched.length > 1) {
@@ -201,6 +204,9 @@ export default {
201
204
  return true;
202
205
  } else if (parentPath && itemFullPath === parentPath) {
203
206
  return true;
207
+ // === 新增映射逻辑 ===
208
+ } else if (menuRouteMap[item.name] && menuRouteMap[item.name].includes(resource)) {
209
+ return true;
204
210
  }
205
211
  }
206
212
  }
@@ -670,7 +670,8 @@ export default {
670
670
  </template>
671
671
 
672
672
  <!-- 资源搜索按钮 -->
673
- <button
673
+ <!-- 2025/9/30 隐藏 -->
674
+ <!-- <button
674
675
  v-if="showSearch"
675
676
  id="header-btn-search"
676
677
  v-clean-tooltip="t('nav.resourceSearch.toolTip', {key: searchShortcut})"
@@ -685,7 +686,7 @@ export default {
685
686
  @click="openSearch()"
686
687
  >
687
688
  <i class="icon icon-search icon-lg" />
688
- </button>
689
+ </button> -->
689
690
 
690
691
  <!-- 搜索弹窗 -->
691
692
  <app-modal
@@ -706,9 +707,10 @@ export default {
706
707
  v-if="extensionHeaderActions.length"
707
708
  class="header-buttons"
708
709
  >
710
+ <template v-for="action, i in extensionHeaderActions" :key="`${action.label}${i}`">
711
+ <!-- kubectl-explain.action | 2025/9/30隐藏 -->
709
712
  <button
710
- v-for="action, i in extensionHeaderActions"
711
- :key="`${action.label}${i}`"
713
+ v-if="action.labelKey !== 'kubectl-explain.action'"
712
714
  v-clean-tooltip="handleExtensionTooltip(action)"
713
715
  v-shortkey="action.shortcutKey"
714
716
  :disabled="action.enabled ? !action.enabled(ctx) : false"
@@ -728,6 +730,7 @@ export default {
728
730
  color="header"
729
731
  />
730
732
  </button>
733
+ </template>
731
734
  </div>
732
735
 
733
736
  <!-- ===== 用户菜单(右上角头像 + 下拉) ===== -->
@@ -3,6 +3,7 @@ import Favorite from '@shell/components/nav/Favorite';
3
3
  import { TYPE_MODES } from '@shell/store/type-map';
4
4
 
5
5
  import TabTitle from '@shell/components/TabTitle';
6
+ import { menuRouteMap } from '@shell/config/menuRouteMap';
6
7
 
7
8
  const showFavoritesFor = [TYPE_MODES.FAVORITE, TYPE_MODES.USED];
8
9
 
@@ -61,6 +62,17 @@ export default {
61
62
  const pageFullPath = this.$route.fullPath?.toLowerCase().split('#')[0]; // Ignore the shebang when comparing routes
62
63
  const routeMetaNav = this.$route.meta?.nav;
63
64
 
65
+ const resource = this.$route?.params?.resource || ''
66
+
67
+ console.log(this.type, ' this.type----------------------------');
68
+ console.log(this.$route.params, ' this.$route?.params----------------------------');
69
+
70
+
71
+ // 菜单选中动态映射逻辑
72
+ if (menuRouteMap[this.type.name] && menuRouteMap[this.type.name].includes(resource)) {
73
+ return true;
74
+ }
75
+
64
76
  // If the route explicitly declares the nav path that should be highlighted, then use that
65
77
  if (routeMetaNav) {
66
78
  const cluster = this.$route.params?.cluster;
@@ -0,0 +1,10 @@
1
+ // menuRouteMap.js
2
+ export const menuRouteMap = {
3
+ 'projects-namespaces': [
4
+ 'management.cattle.io.project', // 创建项目
5
+ 'namespace',
6
+ ],
7
+ 'cluster-members': [
8
+ 'management.cattle.io.clusterroletemplatebinding'
9
+ ]
10
+ };
@@ -72,6 +72,7 @@ export function init(store) {
72
72
  'cluster-dashboard',
73
73
  'projects-namespaces',
74
74
  'namespaces',
75
+ 'namespace',
75
76
  NODE,
76
77
  VIRTUAL_TYPES.CLUSTER_MEMBERS,
77
78
  EVENT,
@@ -51,22 +51,31 @@ export function installNavigationGuards(router, context) {
51
51
 
52
52
  // 🔹 最后执行:只改地址栏,不改内部
53
53
  router.afterEach((to) => {
54
- const base = router.options.history?.base || ''; // 获取 router base,防止丢失
55
- let cloudPath = to.fullPath.replace(/harvester/g, 'cloud');
54
+ const base = router.options.history?.base || '';
55
+ const pathParts = to.path.split('/');
56
56
 
57
- // fullPath 可能已经不带 base,需要拼回去
57
+ const newPathParts = pathParts.map((part) => {
58
+ // 只替换 cluster/product/resource 对应的 segment
59
+ for (const key of ['cluster', 'product', 'resource']) {
60
+ if (to.params[key] && to.params[key] === part) {
61
+ return part.replace(/harvester/g, 'cloud');
62
+ }
63
+ }
64
+ return part;
65
+ });
66
+
67
+ let cloudPath = newPathParts.join('/');
58
68
  if (!cloudPath.startsWith(base)) {
59
69
  cloudPath = base + cloudPath;
60
70
  }
61
71
 
62
- // 获取当前地址栏完整 URL(path + search + hash)
63
72
  const currentLocation = window.location.pathname + window.location.search + window.location.hash;
64
73
 
65
- // 只有在地址栏实际不同的时候才替换,避免死循环
66
74
  if (cloudPath !== currentLocation) {
67
75
  console.info('[URL Replace] Updating address bar:', currentLocation, '→', cloudPath);
68
76
  window.history.replaceState({}, '', cloudPath);
69
77
  }
70
78
  });
79
+
71
80
  }
72
81
 
@@ -166,4 +166,8 @@ export default {
166
166
  .no-binary-data {
167
167
  opacity: 0.8;
168
168
  }
169
+
170
+ ::v-deep .CodeMirror-scroll {
171
+ min-height: auto;
172
+ }
169
173
  </style>
@@ -660,11 +660,11 @@ export default {
660
660
  .deployment-tabs {
661
661
  > .tabs.horizontal {
662
662
  border-bottom: 1px solid var(--border);
663
- margin-bottom: 20px;
664
663
  }
665
664
 
666
665
  > .tab-container{
667
- border: none !important;
666
+ padding: 20px 20px 0;
667
+ // border: none !important;
668
668
  }
669
669
  }
670
670
  .padded {
@@ -115,25 +115,26 @@ export default class ProvCluster extends SteveModel {
115
115
  const actions = [
116
116
  // Note: Actions are not supported in the Steve API, so we check
117
117
  // available actions for RKE1 clusters, but not RKE2 clusters.
118
+ // {
119
+ // action: 'openShell',
120
+ // label: this.$rootGetters['i18n/t']('nav.shell'),
121
+ // icon: 'icon icon-terminal',
122
+ // enabled: !!this.mgmt?.links.shell && ready,
123
+ // }, {
124
+ // action: 'downloadKubeConfig',
125
+ // bulkAction: 'downloadKubeConfigBulk',
126
+ // label: this.$rootGetters['i18n/t']('nav.kubeconfig.download'),
127
+ // icon: 'icon icon-download',
128
+ // bulkable: true,
129
+ // enabled: this.mgmt?.hasAction('generateKubeconfig'),
130
+ // }, {
131
+ // action: 'copyKubeConfig',
132
+ // label: this.t('cluster.copyConfig'),
133
+ // bulkable: false,
134
+ // enabled: this.mgmt?.hasAction('generateKubeconfig'),
135
+ // icon: 'icon icon-copy',
136
+ // },
118
137
  {
119
- action: 'openShell',
120
- label: this.$rootGetters['i18n/t']('nav.shell'),
121
- icon: 'icon icon-terminal',
122
- enabled: !!this.mgmt?.links.shell && ready,
123
- }, {
124
- action: 'downloadKubeConfig',
125
- bulkAction: 'downloadKubeConfigBulk',
126
- label: this.$rootGetters['i18n/t']('nav.kubeconfig.download'),
127
- icon: 'icon icon-download',
128
- bulkable: true,
129
- enabled: this.mgmt?.hasAction('generateKubeconfig'),
130
- }, {
131
- action: 'copyKubeConfig',
132
- label: this.t('cluster.copyConfig'),
133
- bulkable: false,
134
- enabled: this.mgmt?.hasAction('generateKubeconfig'),
135
- icon: 'icon icon-copy',
136
- }, {
137
138
  action: 'snapshotAction',
138
139
  label: this.$rootGetters['i18n/t']('nav.takeSnapshot'),
139
140
  icon: 'icon icon-snapshot',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dashboard-shell-shell",
3
- "version": "3.0.5-test.25",
3
+ "version": "3.0.5-test.27",
4
4
  "description": "Rancher Dashboard Shell",
5
5
  "repository": "https://github.com/rancherlabs/dashboard",
6
6
  "license": "Apache-2.0",
@@ -1,5 +1,10 @@
1
1
  {
2
2
  "translations": [
3
+ {
4
+ "pattern": "(\\S+) \"(\\S+)\" is forbidden: user \"(\\S+)\" cannot update resource \"(\\S+)\" in api group \"(\\S+)\" at the cluster scope",
5
+ "replacement": "$1 \"$2\" 被禁止:用户 \"$3\" 无权在集群范围内更新 API 组 \"$5\" 中的资源 \"$4\"",
6
+ "flags": "gi"
7
+ },
3
8
  {
4
9
  "pattern": "virtualmachine\\.kubevirt\\.io \"([^\"]+)\" is invalid:\\[metadata\\.labels: invalid value: \"([^\"]+)\": name part must consist of alphanumeric characters, '-', '_' or '\\.', and must start and end with an alphanumeric character\\]",
5
10
  "replacement": "虚拟机 \"$1\" 标签值 \"$2\" 无效:只能包含字母、数字、'-','_'或'.',且以字母/数字开头和结尾",
@@ -83,6 +88,11 @@
83
88
  {
84
89
  "pattern": "failed to list objects with param:[\\s\\S]*?authorizationheadermalformed[\\s\\S]*?the region is wrong; expecting '([^']+)'[\\s\\S]*",
85
90
  "replacement": "参数错误,无法连接到服务器",
91
+ "flags": "gi"
92
+ },
93
+ {
94
+ "pattern": "has timed out progressing.",
95
+ "replacement": "状态更新超时。",
86
96
  "flags": "gi"
87
97
  },
88
98
  {
@@ -1658,6 +1668,10 @@
1658
1668
  "pattern": "namespaces",
1659
1669
  "replacement": "资源组"
1660
1670
  },
1671
+ {
1672
+ "pattern": "replicaset",
1673
+ "replacement": "副本集"
1674
+ },
1661
1675
  {
1662
1676
  "pattern": "%",
1663
1677
  "replacement": ""