@rancher/shell 3.0.11 → 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 (98) 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 +5 -4
  5. package/assets/translations/zh-hans.yaml +0 -3
  6. package/components/EmptyProductPage.vue +76 -0
  7. package/components/Resource/Detail/CopyToClipboard.vue +1 -2
  8. package/components/Resource/Detail/Metadata/KeyValueRow.vue +9 -3
  9. package/components/Resource/Detail/TitleBar/__tests__/__snapshots__/index.test.ts.snap +31 -0
  10. package/components/Resource/Detail/TitleBar/__tests__/index.test.ts +45 -1
  11. package/components/Resource/Detail/TitleBar/index.vue +1 -1
  12. package/components/Resource/Detail/ViewOptions/__tests__/__snapshots__/index.test.ts.snap +9 -0
  13. package/components/Resource/Detail/ViewOptions/__tests__/index.test.ts +62 -0
  14. package/components/Resource/Detail/ViewOptions/index.vue +2 -1
  15. package/components/ResourceList/Masthead.vue +25 -2
  16. package/components/SideNav.vue +13 -0
  17. package/components/__tests__/PromptModal.test.ts +2 -0
  18. package/components/fleet/FleetClusters.vue +1 -0
  19. package/components/fleet/__tests__/FleetClusters.test.ts +71 -0
  20. package/components/form/NodeScheduling.vue +17 -3
  21. package/components/form/PrivateRegistry.vue +69 -0
  22. package/components/form/__tests__/PrivateRegistry.test.ts +133 -0
  23. package/components/formatter/WorkloadHealthScale.vue +3 -1
  24. package/components/nav/Group.vue +26 -3
  25. package/components/nav/Header.vue +32 -7
  26. package/components/nav/TopLevelMenu.vue +15 -1
  27. package/config/pagination-table-headers.js +8 -1
  28. package/config/product/apps.js +2 -1
  29. package/config/product/auth.js +1 -0
  30. package/config/product/backup.js +1 -0
  31. package/config/product/compliance.js +1 -1
  32. package/config/product/explorer.js +25 -6
  33. package/config/product/fleet.js +1 -0
  34. package/config/product/gatekeeper.js +1 -0
  35. package/config/product/istio.js +1 -0
  36. package/config/product/logging.js +1 -0
  37. package/config/product/longhorn.js +2 -1
  38. package/config/product/manager.js +1 -0
  39. package/config/product/monitoring.js +1 -0
  40. package/config/product/navlinks.js +1 -0
  41. package/config/product/neuvector.js +2 -1
  42. package/config/product/settings.js +1 -0
  43. package/config/product/uiplugins.js +1 -0
  44. package/core/__tests__/plugin-products-helpers.test.ts +454 -0
  45. package/core/__tests__/plugin-products.test.ts +3219 -0
  46. package/core/extension-manager-impl.js +30 -1
  47. package/core/plugin-products-base.ts +375 -0
  48. package/core/plugin-products-extending.ts +44 -0
  49. package/core/plugin-products-helpers.ts +262 -0
  50. package/core/plugin-products-top-level.ts +66 -0
  51. package/core/plugin-products-type-guards.ts +33 -0
  52. package/core/plugin-products.ts +50 -0
  53. package/core/plugin-types.ts +222 -0
  54. package/core/plugin.ts +45 -10
  55. package/core/productDebugger.js +48 -0
  56. package/core/types.ts +95 -11
  57. package/detail/__tests__/__snapshots__/fleet.cattle.io.bundle.test.ts.snap +52 -0
  58. package/detail/__tests__/fleet.cattle.io.bundle.test.ts +171 -0
  59. package/detail/fleet.cattle.io.bundle.vue +21 -34
  60. package/dialog/ExtensionCatalogInstallDialog.vue +1 -1
  61. package/dialog/InstallExtensionDialog.vue +6 -27
  62. package/dialog/UninstallExistingExtensionDialog.vue +141 -0
  63. package/dialog/UninstallExtensionDialog.vue +4 -26
  64. package/dialog/__tests__/UninstallExistingExtensionDialog.test.ts +114 -0
  65. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +1 -0
  66. package/edit/provisioning.cattle.io.cluster/__tests__/Ingress.test.ts +176 -0
  67. package/edit/provisioning.cattle.io.cluster/rke2.vue +4 -1
  68. package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +6 -0
  69. package/edit/provisioning.cattle.io.cluster/tabs/Ingress.vue +7 -2
  70. package/list/provisioning.cattle.io.cluster.vue +0 -1
  71. package/list/workload.vue +11 -4
  72. package/mixins/resource-fetch.js +12 -3
  73. package/models/pod.js +18 -0
  74. package/models/workload.js +20 -2
  75. package/package.json +1 -2
  76. package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +0 -1
  77. package/pages/c/_cluster/settings/brand.vue +4 -4
  78. package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +231 -13
  79. package/pages/c/_cluster/uiplugins/index.vue +143 -37
  80. package/plugins/dashboard-store/__tests__/resource-class.test.ts +1 -0
  81. package/plugins/dashboard-store/actions.js +3 -2
  82. package/plugins/dashboard-store/resource-class.js +62 -6
  83. package/plugins/plugin.js +16 -0
  84. package/plugins/steve/steve-pagination-utils.ts +7 -0
  85. package/scripts/typegen.sh +13 -1
  86. package/store/__tests__/type-map.test.ts +84 -24
  87. package/store/type-map.js +42 -3
  88. package/tsconfig.paths.json +1 -0
  89. package/types/resources/pod.ts +18 -0
  90. package/types/shell/index.d.ts +8506 -2909
  91. package/types/store/dashboard-store.types.ts +5 -0
  92. package/types/store/pagination.types.ts +6 -0
  93. package/utils/axios.js +1 -4
  94. package/utils/dynamic-importer.js +3 -2
  95. package/utils/pagination-utils.ts +1 -1
  96. package/utils/uiplugins.ts +12 -16
  97. package/utils/validators/__tests__/private-registry.test.ts +76 -0
  98. package/utils/validators/private-registry.ts +28 -0
@@ -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]';