@rancher/shell 3.0.10 → 3.0.12-rc.1

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 (154) hide show
  1. package/assets/styles/base/_mixins.scss +31 -0
  2. package/assets/styles/base/_variables.scss +2 -0
  3. package/assets/styles/themes/_modern.scss +6 -5
  4. package/assets/translations/en-us.yaml +12 -9
  5. package/assets/translations/zh-hans.yaml +0 -3
  6. package/chart/__tests__/rancher-backup-index.test.ts +248 -0
  7. package/chart/rancher-backup/index.vue +41 -2
  8. package/components/BrandImage.vue +6 -5
  9. package/components/ConsumptionGauge.vue +12 -4
  10. package/components/DynamicContent/DynamicContentIcon.vue +3 -2
  11. package/components/EmptyProductPage.vue +76 -0
  12. package/components/ExplorerProjectsNamespaces.vue +1 -4
  13. package/components/LazyImage.vue +2 -1
  14. package/components/Resource/Detail/Card/Scaler.vue +4 -4
  15. package/components/Resource/Detail/CopyToClipboard.vue +1 -2
  16. package/components/Resource/Detail/Metadata/KeyValueRow.vue +9 -3
  17. package/components/Resource/Detail/TitleBar/__tests__/__snapshots__/index.test.ts.snap +31 -0
  18. package/components/Resource/Detail/TitleBar/__tests__/index.test.ts +45 -1
  19. package/components/Resource/Detail/TitleBar/index.vue +1 -1
  20. package/components/Resource/Detail/ViewOptions/__tests__/__snapshots__/index.test.ts.snap +9 -0
  21. package/components/Resource/Detail/ViewOptions/__tests__/index.test.ts +62 -0
  22. package/components/Resource/Detail/ViewOptions/index.vue +2 -1
  23. package/components/ResourceList/Masthead.vue +25 -2
  24. package/components/SideNav.vue +13 -0
  25. package/components/Tabbed/index.vue +6 -0
  26. package/components/__tests__/ConsumptionGauge.test.ts +31 -0
  27. package/components/__tests__/PromptModal.test.ts +2 -0
  28. package/components/fleet/FleetClusters.vue +1 -0
  29. package/components/fleet/__tests__/FleetClusters.test.ts +71 -0
  30. package/components/form/NodeScheduling.vue +17 -3
  31. package/components/form/PrivateRegistry.vue +69 -0
  32. package/components/form/ProjectMemberEditor.vue +0 -10
  33. package/components/form/__tests__/PrivateRegistry.test.ts +133 -0
  34. package/components/formatter/WorkloadHealthScale.vue +3 -1
  35. package/components/nav/Group.vue +26 -3
  36. package/components/nav/Header.vue +32 -7
  37. package/components/nav/TopLevelMenu.helper.ts +7 -79
  38. package/components/nav/TopLevelMenu.vue +15 -1
  39. package/components/nav/__tests__/TopLevelMenu.helper.test.ts +2 -53
  40. package/config/pagination-table-headers.js +8 -1
  41. package/config/private-label.js +2 -1
  42. package/config/product/apps.js +3 -1
  43. package/config/product/auth.js +1 -0
  44. package/config/product/backup.js +1 -0
  45. package/config/product/compliance.js +1 -1
  46. package/config/product/explorer.js +25 -6
  47. package/config/product/fleet.js +1 -0
  48. package/config/product/gatekeeper.js +1 -0
  49. package/config/product/istio.js +1 -0
  50. package/config/product/logging.js +1 -0
  51. package/config/product/longhorn.js +2 -1
  52. package/config/product/manager.js +1 -0
  53. package/config/product/monitoring.js +1 -0
  54. package/config/product/navlinks.js +1 -0
  55. package/config/product/neuvector.js +2 -1
  56. package/config/product/settings.js +1 -0
  57. package/config/product/uiplugins.js +1 -0
  58. package/core/__tests__/extension-manager-impl.test.js +187 -2
  59. package/core/__tests__/plugin-products-helpers.test.ts +454 -0
  60. package/core/__tests__/plugin-products.test.ts +3219 -0
  61. package/core/extension-manager-impl.js +34 -3
  62. package/core/plugin-helpers.ts +31 -0
  63. package/core/plugin-products-base.ts +375 -0
  64. package/core/plugin-products-extending.ts +44 -0
  65. package/core/plugin-products-helpers.ts +262 -0
  66. package/core/plugin-products-top-level.ts +66 -0
  67. package/core/plugin-products-type-guards.ts +33 -0
  68. package/core/plugin-products.ts +50 -0
  69. package/core/plugin-types.ts +222 -0
  70. package/core/plugin.ts +45 -10
  71. package/core/productDebugger.js +48 -0
  72. package/core/types.ts +95 -11
  73. package/detail/__tests__/__snapshots__/fleet.cattle.io.bundle.test.ts.snap +52 -0
  74. package/detail/__tests__/fleet.cattle.io.bundle.test.ts +171 -0
  75. package/detail/__tests__/node.test.ts +83 -0
  76. package/detail/fleet.cattle.io.bundle.vue +21 -34
  77. package/detail/management.cattle.io.oidcclient.vue +2 -1
  78. package/detail/node.vue +1 -0
  79. package/dialog/ExtensionCatalogInstallDialog.vue +1 -1
  80. package/dialog/InstallExtensionDialog.vue +6 -27
  81. package/dialog/UninstallExistingExtensionDialog.vue +141 -0
  82. package/dialog/UninstallExtensionDialog.vue +4 -26
  83. package/dialog/__tests__/UninstallExistingExtensionDialog.test.ts +114 -0
  84. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +1 -0
  85. package/edit/catalog.cattle.io.clusterrepo.vue +17 -3
  86. package/edit/cloudcredential.vue +2 -1
  87. package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +11 -6
  88. package/edit/provisioning.cattle.io.cluster/__tests__/Ingress.test.ts +176 -0
  89. package/edit/provisioning.cattle.io.cluster/index.vue +5 -4
  90. package/edit/provisioning.cattle.io.cluster/rke2.vue +4 -1
  91. package/edit/provisioning.cattle.io.cluster/shared.ts +4 -2
  92. package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +6 -0
  93. package/edit/provisioning.cattle.io.cluster/tabs/Ingress.vue +7 -2
  94. package/edit/secret/generic.vue +1 -0
  95. package/edit/secret/index.vue +2 -1
  96. package/edit/service.vue +2 -14
  97. package/list/management.cattle.io.feature.vue +7 -1
  98. package/list/provisioning.cattle.io.cluster.vue +0 -50
  99. package/list/workload.vue +11 -4
  100. package/mixins/brand.js +2 -1
  101. package/mixins/resource-fetch.js +12 -3
  102. package/models/catalog.cattle.io.clusterrepo.js +9 -0
  103. package/models/cluster.x-k8s.io.machinedeployment.js +8 -3
  104. package/models/management.cattle.io.authconfig.js +2 -1
  105. package/models/management.cattle.io.cluster.js +4 -3
  106. package/models/monitoring.coreos.com.receiver.js +11 -6
  107. package/models/pod.js +18 -0
  108. package/models/provisioning.cattle.io.cluster.js +2 -2
  109. package/models/workload.js +20 -2
  110. package/package.json +5 -6
  111. package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +0 -1
  112. package/pages/c/_cluster/apps/charts/index.vue +3 -8
  113. package/pages/c/_cluster/apps/charts/install.vue +8 -9
  114. package/pages/c/_cluster/istio/index.vue +4 -2
  115. package/pages/c/_cluster/longhorn/index.vue +2 -1
  116. package/pages/c/_cluster/monitoring/index.vue +2 -2
  117. package/pages/c/_cluster/neuvector/index.vue +2 -1
  118. package/pages/c/_cluster/settings/brand.vue +4 -4
  119. package/pages/c/_cluster/settings/performance.vue +0 -5
  120. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +2 -1
  121. package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +231 -13
  122. package/pages/c/_cluster/uiplugins/index.vue +145 -38
  123. package/plugins/dashboard-store/__tests__/resource-class.test.ts +1 -0
  124. package/plugins/dashboard-store/actions.js +3 -2
  125. package/plugins/dashboard-store/resource-class.js +62 -6
  126. package/plugins/plugin.js +16 -0
  127. package/plugins/steve/steve-pagination-utils.ts +8 -2
  128. package/plugins/steve/subscribe.js +29 -4
  129. package/rancher-components/RcButton/RcButton.vue +3 -3
  130. package/rancher-components/RcButtonSplit/RcButtonSplit.test.ts +253 -0
  131. package/rancher-components/RcButtonSplit/RcButtonSplit.vue +158 -0
  132. package/rancher-components/RcButtonSplit/index.ts +1 -0
  133. package/scripts/test-plugins-build.sh +4 -4
  134. package/scripts/typegen.sh +13 -1
  135. package/store/__tests__/type-map.test.ts +84 -24
  136. package/store/type-map.js +42 -3
  137. package/tsconfig.paths.json +1 -0
  138. package/types/resources/pod.ts +18 -0
  139. package/types/shell/index.d.ts +8506 -2908
  140. package/types/store/dashboard-store.types.ts +5 -0
  141. package/types/store/pagination.types.ts +6 -0
  142. package/utils/__tests__/require-asset.test.ts +98 -0
  143. package/utils/async.ts +1 -5
  144. package/utils/axios.js +1 -4
  145. package/utils/brand.ts +3 -1
  146. package/utils/dynamic-importer.js +3 -2
  147. package/utils/favicon.js +4 -3
  148. package/utils/pagination-utils.ts +1 -1
  149. package/utils/require-asset.ts +95 -0
  150. package/utils/uiplugins.ts +12 -16
  151. package/utils/validators/__tests__/private-registry.test.ts +76 -0
  152. package/utils/validators/private-registry.ts +28 -0
  153. package/vue.config.js +4 -3
  154. package/components/HarvesterServiceAddOnConfig.vue +0 -207
@@ -107,7 +107,7 @@ createTestComponent() {
107
107
 
108
108
  # Publish shell pkg (tag is needed as publish-shell is optimized to work with release-shell-pkg workflow)
109
109
  echo "Publishing Shell package to local registry"
110
- yarn install
110
+ yarn install --frozen-lockfile
111
111
  export TAG="shell-pkg-v${SHELL_VERSION}"
112
112
  ${SHELL_DIR}/scripts/publish-shell.sh
113
113
 
@@ -139,7 +139,7 @@ if [ "${SKIP_STANDALONE}" == "false" ]; then
139
139
 
140
140
  pushd test-app > /dev/null
141
141
 
142
- yarn install
142
+ yarn install --frozen-lockfile
143
143
  # this is the "same" as doing a yarn dev (in a build sense)
144
144
  # it's to make sure the dev environment is running properly
145
145
  FORCE_COLOR=true yarn build | cat
@@ -165,7 +165,7 @@ pushd $BASE_DIR
165
165
  # Now try a plugin within the dashboard codebase
166
166
  echo "Validating in-tree package"
167
167
 
168
- yarn install
168
+ yarn install --frozen-lockfile
169
169
 
170
170
  if [ "${TEST_PERSIST_BUILD}" != "true" ]; then
171
171
  echo "Removing folder ./pkg/test-pkg"
@@ -202,7 +202,7 @@ function clone_repo_test_extension_build() {
202
202
  pushd ${BASE_DIR}/$REPO_NAME
203
203
 
204
204
  echo -e "\nInstalling dependencies for $REPO_NAME\n"
205
- yarn install
205
+ yarn install --frozen-lockfile
206
206
 
207
207
  # set registry to local verdaccio (to install new shell)
208
208
  yarn config set registry ${VERDACCIO_NPM_REGISTRY}
@@ -22,11 +22,13 @@ ${BASE_DIR}/node_modules/.bin/tsc ${SHELL_DIR}/config/table-headers.js --declara
22
22
  ${BASE_DIR}/node_modules/.bin/tsc ${SHELL_DIR}/config/types.js --declaration --allowJs --emitDeclarationOnly --outDir ${SHELL_DIR}/tmp/config > /dev/null
23
23
  ${BASE_DIR}/node_modules/.bin/tsc ${SHELL_DIR}/config/labels-annotations.js --declaration --allowJs --emitDeclarationOnly --outDir ${SHELL_DIR}/tmp/config > /dev/null
24
24
  ${BASE_DIR}/node_modules/.bin/tsc ${SHELL_DIR}/config/version.js --declaration --allowJs --emitDeclarationOnly --outDir ${SHELL_DIR}/tmp/config > /dev/null
25
+ ${BASE_DIR}/node_modules/.bin/tsc ${SHELL_DIR}/config/product/*.js --declaration --allowJs --emitDeclarationOnly --outDir ${SHELL_DIR}/tmp/config/product > /dev/null
25
26
 
26
27
  # # store
27
28
  ${BASE_DIR}/node_modules/.bin/tsc ${SHELL_DIR}/store/features.js --declaration --allowJs --emitDeclarationOnly --outDir ${SHELL_DIR}/tmp/store > /dev/null
28
- ${BASE_DIR}/node_modules/.bin/tsc ${SHELL_DIR}/store/prefs.js --declaration --allowJs --emitDeclarationOnly --outDir ${SHELL_DIR}/tmp/store > /dev/null
29
29
  ${BASE_DIR}/node_modules/.bin/tsc ${SHELL_DIR}/store/plugins.js --declaration --allowJs --emitDeclarationOnly --outDir ${SHELL_DIR}/tmp/store > /dev/null
30
+ ${BASE_DIR}/node_modules/.bin/tsc ${SHELL_DIR}/store/prefs.js --declaration --allowJs --emitDeclarationOnly --outDir ${SHELL_DIR}/tmp/store > /dev/null
31
+ ${BASE_DIR}/node_modules/.bin/tsc ${SHELL_DIR}/store/store-types.js --declaration --allowJs --emitDeclarationOnly --outDir ${SHELL_DIR}/tmp/store > /dev/null
30
32
 
31
33
  # # plugins
32
34
  ${BASE_DIR}/node_modules/.bin/tsc ${SHELL_DIR}/plugins/i18n.js --declaration --allowJs --emitDeclarationOnly --outDir ${SHELL_DIR}/tmp/ > /dev/null
@@ -93,6 +95,16 @@ function processDir() {
93
95
  echo "declare module '${module}' {" >> ${INDEX}
94
96
  cat $entry >> ${INDEX}
95
97
  echo -e "}" >> ${INDEX}
98
+
99
+ # Also generate a module declaration with .js extension for JS source files
100
+ # TypeScript imports use .js extensions for JS files
101
+ if [ "${name}" != "index" ]; then
102
+ local moduleWithJs=${basePkg}/${name}.js
103
+ echo -e "\n// ${moduleWithJs}\n" >> ${INDEX}
104
+ echo "declare module '${moduleWithJs}' {" >> ${INDEX}
105
+ cat $entry >> ${INDEX}
106
+ echo -e "}" >> ${INDEX}
107
+ fi
96
108
  fi
97
109
  fi
98
110
  done
@@ -7,6 +7,17 @@ import {
7
7
  SCHEMA,
8
8
  } from '@shell/config/types';
9
9
 
10
+ // Type definitions for test data
11
+ interface TestSchema {
12
+ id: string;
13
+ type: string;
14
+ attributes?: { kind: string };
15
+ _group?: string;
16
+ _id?: string;
17
+ }
18
+
19
+ type SchemaOrType = TestSchema | string;
20
+
10
21
  /**
11
22
  * types in the store
12
23
  */
@@ -115,9 +126,9 @@ describe('type-map', () => {
115
126
  /**
116
127
  * Stick in the required mode param to the expected menu items
117
128
  */
118
- const setTypeMode = (modes, resourcesById) => {
119
- return modes.reduce((res, mode) => {
120
- const newResource = { };
129
+ const setTypeMode = (modes: string[], resourcesById: Record<string, any>) => {
130
+ return modes.reduce((res: Record<string, any>, mode: string) => {
131
+ const newResource: Record<string, any> = { };
121
132
 
122
133
  Object.entries(resourcesById).forEach(([id, resource]: [string, any]) => {
123
134
  newResource[id] = {
@@ -146,17 +157,17 @@ describe('type-map', () => {
146
157
  spoofedTypes: { [productName]: [] }
147
158
  },
148
159
  typeMapGetters: {
149
- labelFor: (schema, count) => '',
150
- optionsFor: (schema) => {},
160
+ labelFor: (schema: SchemaOrType, count: number) => '',
161
+ optionsFor: (schema: SchemaOrType) => ({}),
151
162
  groupForBasicType: () => {},
152
- typeWeightFor: (label, isBasic) => 1
163
+ typeWeightFor: (label: string, isBasic: boolean) => 1
153
164
  },
154
165
  rootState: {},
155
166
  rootGetters: {
156
167
  [`${ productStore }/all`]: (schema: string) => {
157
168
  return [];
158
169
  },
159
- 'prefs/get': (pref) => {},
170
+ 'prefs/get': (pref: string) => {},
160
171
 
161
172
  },
162
173
 
@@ -201,9 +212,9 @@ describe('type-map', () => {
201
212
 
202
213
  const testTypeMapGetters = {
203
214
  ...typeMapGetters,
204
- labelFor: (schema, count) => 'Pod',
215
+ labelFor: (schema: SchemaOrType, count: number) => 'Pod',
205
216
  groupForBasicType: () => true,
206
- optionsFor: (schema) => ({
217
+ optionsFor: (schema: SchemaOrType) => ({
207
218
  namespaced: true,
208
219
  customRoute: 'cde'
209
220
  }),
@@ -320,7 +331,7 @@ describe('type-map', () => {
320
331
 
321
332
  const testTypeMapGetters = {
322
333
  ...typeMapGetters,
323
- groupForBasicType: (product, id) => false
334
+ groupForBasicType: (product: string, id: string) => false
324
335
  };
325
336
 
326
337
  const groups = getters.allTypes(state, testTypeMapGetters, rootState, rootGetters)(productName, modes);
@@ -473,7 +484,7 @@ describe('type-map', () => {
473
484
 
474
485
  const testTypeMapGetters = {
475
486
  ...typeMapGetters,
476
- optionsFor: (schema) => ({
487
+ optionsFor: (schema: SchemaOrType) => ({
477
488
  namespaced: true,
478
489
  customRoute: 'cde',
479
490
  ifRancherCluster: true
@@ -497,7 +508,7 @@ describe('type-map', () => {
497
508
 
498
509
  const testTypeMapGetters = {
499
510
  ...typeMapGetters,
500
- optionsFor: (schema) => ({
511
+ optionsFor: (schema: SchemaOrType) => ({
501
512
  namespaced: true,
502
513
  customRoute: 'cde',
503
514
  ifRancherCluster: false
@@ -521,7 +532,7 @@ describe('type-map', () => {
521
532
 
522
533
  const testTypeMapGetters = {
523
534
  ...typeMapGetters,
524
- optionsFor: (schema) => ({
535
+ optionsFor: (schema: SchemaOrType) => ({
525
536
  namespaced: true,
526
537
  customRoute: 'cde',
527
538
  ifRancherCluster: true
@@ -545,7 +556,7 @@ describe('type-map', () => {
545
556
 
546
557
  const testTypeMapGetters = {
547
558
  ...typeMapGetters,
548
- optionsFor: (schema) => ({
559
+ optionsFor: (schema: SchemaOrType) => ({
549
560
  namespaced: true,
550
561
  customRoute: 'cde',
551
562
  localOnly: true
@@ -569,7 +580,7 @@ describe('type-map', () => {
569
580
 
570
581
  const testTypeMapGetters = {
571
582
  ...typeMapGetters,
572
- optionsFor: (schema) => ({
583
+ optionsFor: (schema: SchemaOrType) => ({
573
584
  namespaced: true,
574
585
  customRoute: 'cde',
575
586
  localOnly: true
@@ -630,9 +641,9 @@ describe('type-map', () => {
630
641
 
631
642
  const testTypeMapGetters = {
632
643
  ...typeMapGetters,
633
- labelFor: (schema, count) => 'Secret',
644
+ labelFor: (schema: SchemaOrType, count: number) => 'Secret',
634
645
  groupForBasicType: () => true,
635
- optionsFor: (schema) => ({
646
+ optionsFor: (schema: SchemaOrType) => ({
636
647
  namespaced: true,
637
648
  customRoute: 'cde'
638
649
  }),
@@ -882,8 +893,10 @@ describe('type-map', () => {
882
893
 
883
894
  const testTypeMapGetters = {
884
895
  ...typeMapGetters,
885
- labelFor: (schema, count) => {
886
- switch (schema.id) {
896
+ labelFor: (schema: SchemaOrType, count: number) => {
897
+ const schemaId = typeof schema === 'object' ? schema.id : schema;
898
+
899
+ switch (schemaId) {
887
900
  case 'secret':
888
901
  return 'Secret';
889
902
  default:
@@ -891,11 +904,11 @@ describe('type-map', () => {
891
904
  }
892
905
  },
893
906
  groupForBasicType: () => true,
894
- optionsFor: (schema) => ({
907
+ optionsFor: (schema: SchemaOrType) => ({
895
908
  namespaced: true,
896
909
  customRoute: 'cde'
897
910
  }),
898
- isFavorite: (id) => id === 'secret',
911
+ isFavorite: (id: string) => id === 'secret',
899
912
  };
900
913
 
901
914
  return {
@@ -1134,14 +1147,14 @@ describe('type-map', () => {
1134
1147
  },
1135
1148
  };
1136
1149
 
1137
- const createProductState = (products) => ({
1150
+ const createProductState = (products: any) => ({
1138
1151
  products,
1139
1152
  schemaGeneration: 1,
1140
1153
  });
1141
1154
 
1142
- const createProductRootGetters = (moduleSchemas = [], moduleName = 'cluster') => ({
1155
+ const createProductRootGetters = (moduleSchemas: any[] = [], moduleName = 'cluster') => ({
1143
1156
  'prefs/get': () => false,
1144
- [`${ moduleName }/all`]: (resource) => {
1157
+ [`${ moduleName }/all`]: (resource: any) => {
1145
1158
  if (resource === SCHEMA) {
1146
1159
  return moduleSchemas;
1147
1160
  }
@@ -1281,4 +1294,51 @@ describe('type-map', () => {
1281
1294
  });
1282
1295
  });
1283
1296
  });
1297
+
1298
+ describe('groupLabel', () => {
1299
+ it('should return groupLabel when it exists in state', () => {
1300
+ const state = { groupLabels: { mygroup: { label: 'My Group Label', labelKey: undefined } } };
1301
+
1302
+ const result = getters.groupLabel(state)('mygroup');
1303
+
1304
+ expect(result).toStrictEqual({ label: 'My Group Label', labelKey: undefined });
1305
+ });
1306
+
1307
+ it('should return groupLabel with labelKey when set', () => {
1308
+ const state = { groupLabels: { anothergroup: { label: undefined, labelKey: 'typeLabel.myKey' } } };
1309
+
1310
+ const result = getters.groupLabel(state)('anothergroup');
1311
+
1312
+ expect(result).toStrictEqual({ label: undefined, labelKey: 'typeLabel.myKey' });
1313
+ });
1314
+
1315
+ it('should handle case-insensitive group names', () => {
1316
+ const state = { groupLabels: { mygroup: { label: 'My Group', labelKey: undefined } } };
1317
+
1318
+ const result = getters.groupLabel(state)('MyGroup');
1319
+
1320
+ expect(result).toStrictEqual({ label: 'My Group', labelKey: undefined });
1321
+ });
1322
+
1323
+ it('should return undefined when group label does not exist', () => {
1324
+ const state = { groupLabels: {} };
1325
+
1326
+ const result = getters.groupLabel(state)('nonexistent');
1327
+
1328
+ expect(result).toBeUndefined();
1329
+ });
1330
+
1331
+ it('should return undefined for empty, null, undefined, or non-existent group name', () => {
1332
+ const state = { groupLabels: { mygroup: { label: 'My Group', labelKey: undefined } } };
1333
+
1334
+ // Empty string fails the groupName check and returns undefined
1335
+ expect(getters.groupLabel(state)('')).toBeUndefined();
1336
+ // null returns undefined
1337
+ expect(getters.groupLabel(state)(null)).toBeUndefined();
1338
+ // undefined returns undefined
1339
+ expect(getters.groupLabel(state)(undefined)).toBeUndefined();
1340
+ // Non-existent group returns undefined
1341
+ expect(getters.groupLabel(state)('nonexistent')).toBeUndefined();
1342
+ });
1343
+ });
1284
1344
  });
package/store/type-map.js CHANGED
@@ -317,6 +317,12 @@ export function DSL(store, product, module = 'type-map') {
317
317
  }
318
318
  },
319
319
 
320
+ labelGroup(group, label, labelKey) {
321
+ store.commit(`${ module }/labelGroup`, {
322
+ group, label, labelKey
323
+ });
324
+ },
325
+
320
326
  setGroupDefaultType(input, defaultType) {
321
327
  if ( isArray(input) ) {
322
328
  store.commit(`${ module }/setGroupDefaultType`, { groups: input, defaultType });
@@ -397,6 +403,7 @@ export const state = function() {
397
403
  groupIgnore: [],
398
404
  groupWeights: {},
399
405
  groupDefaultTypes: {},
406
+ groupLabels: {},
400
407
  basicGroupWeights: { [ROOT]: 1000 },
401
408
  groupMappings: [],
402
409
  typeIgnore: [],
@@ -499,6 +506,23 @@ export const getters = {
499
506
  };
500
507
  },
501
508
 
509
+ groupLabel(state) {
510
+ return (group) => {
511
+ // Handle null/undefined
512
+ if (!group) {
513
+ return;
514
+ }
515
+
516
+ // commit is done with lowercase group names, so lowercase here to match
517
+ const groupName = group.toLowerCase();
518
+
519
+ // If this has been explicitly set, use that
520
+ if (groupName) {
521
+ return state.groupLabels[groupName];
522
+ }
523
+ };
524
+ },
525
+
502
526
  groupForBasicType(state) {
503
527
  return (product, schemaId) => {
504
528
  return state.basicTypes?.[product]?.[schemaId];
@@ -740,10 +764,21 @@ export const getters = {
740
764
 
741
765
  // Translate if an entry exists
742
766
  let label = name;
743
- // i18n-uses nav.group.*
744
- const key = `nav.group."${ name }"`;
767
+ let key;
768
+
769
+ // See if we have a configured label for this group
770
+ const groupLabel = getters['groupLabel'](name);
771
+
772
+ if (groupLabel?.label) {
773
+ label = groupLabel.label;
774
+ } else if (groupLabel?.labelKey) {
775
+ key = groupLabel.labelKey;
776
+ } else {
777
+ // i18n-uses nav.group.*
778
+ key = `nav.group."${ name }"`;
779
+ }
745
780
 
746
- if ( rootGetters['i18n/exists'](key) ) {
781
+ if (key && rootGetters['i18n/exists'](key) ) {
747
782
  label = rootGetters['i18n/t'](key);
748
783
  }
749
784
 
@@ -1680,6 +1715,10 @@ export const mutations = {
1680
1715
  }
1681
1716
  },
1682
1717
 
1718
+ labelGroup(state, { group, label, labelKey }) {
1719
+ state.groupLabels[group.toLowerCase()] = { label, labelKey };
1720
+ },
1721
+
1683
1722
  // setGroupDefaultType({group: 'core', defaultType: 'name'});
1684
1723
  // By default when a group is clicked, the first item is selected - this allows
1685
1724
  // this behaviour to be changed and a named child type can be chosen
@@ -14,6 +14,7 @@
14
14
  "../shell/pkg/*"
15
15
  ],
16
16
  "@components/*": [
17
+ "./rancher-components/*",
17
18
  "../pkg/rancher-components/src/components/*"
18
19
  ]
19
20
  },
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Takes the contents of the POD restarts value `1 (2m47s ago)` and splits it into `1` and `2m47s ago`
3
+ */
4
+ export const POD_RESTARTS_REG_EX = /^(\d+)\s*\(([^)]+)\)/;
5
+
6
+ /**
7
+ * POD restarts value can be split into two (restart count and last restarted).
8
+ *
9
+ * This is a special path that Vai uses to sort/filter on the first part (restart count)
10
+ */
11
+ export const POD_RESTART_FIELD = 'metadata.fields[3][0]';
12
+
13
+ /**
14
+ * POD restarts value can be split into two (restart count and last restarted).
15
+ *
16
+ * This is a special path that Vai uses to sort/filter on the first part (last restarted)
17
+ */
18
+ export const POD_LAST_RESTART_FIELD = 'metadata.fields[3][1]';