@rancher/shell 3.0.12-rc.4 → 3.0.12-rc.6

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 (159) hide show
  1. package/apis/intf/resources-api/resource-base.ts +42 -2
  2. package/apis/intf/resources-api/resource-instance.ts +101 -0
  3. package/apis/intf/resources-api/resources-api.ts +177 -23
  4. package/apis/intf/resources.ts +8 -6
  5. package/apis/resources/__tests__/resources-api-class.test.ts +309 -28
  6. package/apis/resources/resources-api-class.ts +232 -43
  7. package/assets/images/providers/traefik.png +0 -0
  8. package/assets/styles/global/_button.scss +1 -1
  9. package/assets/translations/en-us.yaml +49 -14
  10. package/chart/__tests__/rancher-monitoring-dashboards-index.test.ts +269 -0
  11. package/chart/rancher-monitoring-dashboards/index.vue +155 -0
  12. package/cloud-credential/__tests__/generic.test.ts +132 -0
  13. package/cloud-credential/generic.vue +33 -3
  14. package/components/ActionDropdownShell.vue +5 -3
  15. package/components/ButtonGroup.vue +26 -1
  16. package/components/CruResource.vue +51 -2
  17. package/components/EtcdInfoBanner.vue +2 -12
  18. package/components/GrafanaDashboard.vue +2 -8
  19. package/components/PromptRestore.vue +93 -32
  20. package/components/Questions/index.vue +1 -0
  21. package/components/Resource/Detail/Masthead/__tests__/index.test.ts +68 -14
  22. package/components/Resource/Detail/Masthead/index.vue +8 -3
  23. package/components/ResourceTable.vue +1 -0
  24. package/components/SortableTable/index.vue +4 -3
  25. package/components/Wizard.vue +14 -1
  26. package/components/__tests__/ButtonGroup.test.ts +56 -0
  27. package/components/__tests__/PromptRestore.test.ts +169 -19
  28. package/components/fleet/GitRepoAdvancedTab.vue +1 -0
  29. package/components/fleet/GitRepoMetadataTab.vue +5 -0
  30. package/components/fleet/HelmOpAppCoConfigTab.vue +4 -0
  31. package/components/fleet/HelmOpMetadataTab.vue +5 -0
  32. package/components/form/FileSelector.vue +39 -1
  33. package/components/form/PrivateRegistry.constants.ts +7 -0
  34. package/components/form/PrivateRegistry.vue +253 -18
  35. package/components/form/Security.vue +1 -1
  36. package/components/form/SelectOrCreateAuthSecret.vue +140 -17
  37. package/components/form/__tests__/FileSelector.test.ts +23 -0
  38. package/components/form/__tests__/PrivateRegistry.test.ts +463 -73
  39. package/components/form/__tests__/SelectOrCreateAuthSecret.test.ts +122 -0
  40. package/components/formatter/EtcdSnapshotName.vue +73 -0
  41. package/components/formatter/Translate.vue +22 -1
  42. package/components/nav/Group.vue +5 -10
  43. package/components/nav/Header.vue +8 -1
  44. package/components/nav/TopLevelMenu.vue +1 -30
  45. package/components/nav/__tests__/Group.test.ts +61 -0
  46. package/components/templates/default.vue +7 -0
  47. package/config/features.js +1 -0
  48. package/config/labels-annotations.js +3 -0
  49. package/config/product/manager.js +6 -0
  50. package/config/secret.ts +10 -0
  51. package/config/settings.ts +6 -2
  52. package/config/table-headers.js +5 -2
  53. package/config/types.js +7 -0
  54. package/core/__tests__/plugin-products-apply.test.ts +787 -0
  55. package/core/__tests__/plugin-products-extend.test.ts +189 -0
  56. package/core/__tests__/plugin-products-helpers.test.ts +81 -78
  57. package/core/__tests__/plugin-products-new.test.ts +389 -0
  58. package/core/__tests__/plugin-products-scenarios.test.ts +980 -0
  59. package/core/__tests__/plugin-products-side-menu.test.ts +1935 -0
  60. package/core/plugin-products-base.ts +201 -93
  61. package/core/plugin-products-extending.ts +1 -1
  62. package/core/plugin-products-external.ts +380 -0
  63. package/core/plugin-products-helpers.ts +28 -24
  64. package/core/plugin-products-internal.ts +207 -0
  65. package/core/plugin-products-top-level.ts +10 -5
  66. package/core/plugin-products-type-guards.ts +17 -6
  67. package/core/plugin-products.ts +5 -7
  68. package/core/plugin-types.ts +1 -389
  69. package/core/plugin.ts +10 -11
  70. package/core/types.ts +6 -202
  71. package/detail/__tests__/provisioning.cattle.io.cluster.test.ts +52 -0
  72. package/detail/pod.vue +1 -1
  73. package/detail/provisioning.cattle.io.cluster.vue +79 -5
  74. package/dialog/RotateEncryptionKeyDialog.vue +33 -9
  75. package/dialog/__tests__/RotateEncryptionKeyDialog.test.ts +78 -0
  76. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +92 -0
  77. package/edit/__tests__/fleet.cattle.io.helmop.test.ts +101 -0
  78. package/edit/__tests__/management.cattle.io.setting.test.ts +2 -1
  79. package/edit/auth/AuthProviderWarningBanners.vue +12 -0
  80. package/edit/auth/__tests__/AuthProviderWarningBanners.test.ts +10 -1
  81. package/edit/auth/__tests__/azuread.test.ts +1 -0
  82. package/edit/auth/__tests__/github.test.ts +1 -0
  83. package/edit/auth/__tests__/oidc.test.ts +1 -0
  84. package/edit/auth/__tests__/saml.test.ts +1 -0
  85. package/edit/auth/ldap/__tests__/index.test.ts +1 -0
  86. package/edit/compliance.cattle.io.clusterscanprofile.vue +39 -41
  87. package/edit/fleet.cattle.io.gitrepo.vue +70 -16
  88. package/edit/fleet.cattle.io.helmop.vue +51 -5
  89. package/edit/helm.cattle.io.projecthelmchart.vue +1 -0
  90. package/edit/{management.cattle.io.setting.vue → management.cattle.io.setting/index.vue} +32 -9
  91. package/edit/management.cattle.io.setting/system-default-registry-pull-secrets.vue +81 -0
  92. package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +3 -12
  93. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +18 -0
  94. package/edit/provisioning.cattle.io.cluster/index.vue +1 -1
  95. package/edit/provisioning.cattle.io.cluster/rke2.vue +6 -2
  96. package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +0 -1
  97. package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +2 -2
  98. package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +14 -55
  99. package/list/management.cattle.io.user.vue +24 -5
  100. package/list/utils/management.cattle.io.cluster.utils.ts +1 -1
  101. package/machine-config/__tests__/generic.test.ts +163 -0
  102. package/machine-config/components/EC2Networking.vue +31 -7
  103. package/machine-config/components/__tests__/EC2Networking.test.ts +38 -15
  104. package/machine-config/generic.vue +32 -5
  105. package/mixins/resource-fetch.js +1 -1
  106. package/models/__tests__/provisioning.cattle.io.cluster.test.ts +156 -0
  107. package/models/__tests__/rke-machine.cattle.io.vmwarevspheremachinetemplate.test.ts +22 -0
  108. package/models/__tests__/secret.test.ts +68 -1
  109. package/models/management.cattle.io.cluster.js +21 -3
  110. package/models/pod.js +25 -12
  111. package/models/provisioning.cattle.io.cluster.js +59 -9
  112. package/models/rke-machine.cattle.io.vmwarevspheremachinetemplate.js +9 -0
  113. package/models/rke.cattle.io.etcdsnapshot.js +17 -9
  114. package/models/secret.js +19 -0
  115. package/models/workload.js +12 -7
  116. package/package.json +1 -1
  117. package/pages/auth/login.vue +1 -1
  118. package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +569 -81
  119. package/pages/c/_cluster/apps/charts/install.vue +143 -28
  120. package/pages/c/_cluster/auth/config/index.vue +11 -4
  121. package/pages/c/_cluster/monitoring/index.vue +6 -1
  122. package/pkg/require-asset.lib.js +25 -0
  123. package/pkg/vue.config.js +7 -0
  124. package/plugins/dashboard-store/__tests__/resource-class.test.ts +84 -0
  125. package/plugins/dashboard-store/getters.js +0 -1
  126. package/plugins/dashboard-store/resource-class.js +62 -15
  127. package/plugins/steve/__tests__/steve-class-resource-api.test.ts +147 -0
  128. package/plugins/steve/steve-class.js +43 -0
  129. package/plugins/steve/subscribe.js +11 -0
  130. package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +115 -0
  131. package/rancher-components/Form/LabeledInput/LabeledInput.vue +83 -3
  132. package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +30 -0
  133. package/rancher-components/Form/TextArea/__tests__/TextAreaAutoGrow.test.ts +95 -0
  134. package/rancher-components/RcButton/index.ts +1 -1
  135. package/rancher-components/RcDropdown/RcDropdownTrigger.vue +6 -1
  136. package/store/__tests__/auth.test.ts +18 -0
  137. package/store/__tests__/features.test.ts +131 -0
  138. package/store/__tests__/growl.test.ts +374 -0
  139. package/store/__tests__/modal.test.ts +131 -0
  140. package/store/__tests__/notifications.test.ts +466 -1
  141. package/store/__tests__/slideInPanel.test.ts +88 -0
  142. package/store/__tests__/type-map.utils.test.ts +433 -0
  143. package/store/__tests__/ui-context.test.ts +255 -0
  144. package/store/auth.js +11 -1
  145. package/store/features.js +5 -0
  146. package/store/plugins.js +6 -0
  147. package/types/rancher/steve.api.ts +2 -2
  148. package/types/shell/index.d.ts +120 -0
  149. package/types/store/dashboard-store.types.ts +2 -2
  150. package/types/store/type-map.ts +262 -1
  151. package/utils/__tests__/operation-cr.test.ts +34 -0
  152. package/utils/async.ts +2 -0
  153. package/utils/grafana.js +2 -17
  154. package/utils/monitoring.js +38 -1
  155. package/utils/operation-cr.js +19 -0
  156. package/utils/require-asset.ts +7 -0
  157. package/utils/validators/__tests__/private-registry.test.ts +27 -15
  158. package/utils/validators/private-registry.ts +15 -4
  159. package/core/__tests__/plugin-products.test.ts +0 -4694
package/utils/grafana.js CHANGED
@@ -1,6 +1,5 @@
1
- import { haveV2Monitoring } from '@shell/utils/monitoring';
1
+ import { haveV2Monitoring, fetchMonitoringVersion } from '@shell/utils/monitoring';
2
2
  import { parse as parseUrl, addParam } from '@shell/utils/url';
3
- import { CATALOG } from '@shell/config/types';
4
3
 
5
4
  // these two versions of monitoring included a bug fix attempt that required the local cluster to use a different url
6
5
  // the solution going forward doesn't require this, see https://github.com/rancher/dashboard/issues/8885
@@ -60,21 +59,7 @@ export async function dashboardExists(monitoringVersion, store, clusterId, embed
60
59
  }
61
60
 
62
61
  export async function allDashboardsExist(store, clusterId, embeddedUrls, storeName = 'cluster', projectId = null) {
63
- let res;
64
-
65
- let monitoringVersion = '';
66
-
67
- if (!projectId && store.getters[`${ storeName }/canList`](CATALOG.APP)) {
68
- try {
69
- res = await store.dispatch(`${ storeName }/find`, {
70
- type: CATALOG.APP,
71
- id: 'cattle-monitoring-system/rancher-monitoring'
72
- });
73
- } catch (err) {
74
- }
75
-
76
- monitoringVersion = res?.currentVersion;
77
- }
62
+ const monitoringVersion = projectId ? '' : await fetchMonitoringVersion(store, storeName);
78
63
 
79
64
  const existPromises = embeddedUrls.map((url) => dashboardExists(monitoringVersion, store, clusterId, url, storeName, projectId));
80
65
 
@@ -1,6 +1,6 @@
1
1
  // Helpers for determining if V2 or v1 Monitoring are installed
2
2
 
3
- import { SCHEMA, MONITORING, ENDPOINTS } from '@shell/config/types';
3
+ import { SCHEMA, MONITORING, ENDPOINTS, CATALOG } from '@shell/config/types';
4
4
  import { normalizeType } from '@shell/plugins/dashboard-store/normalize';
5
5
  import { findBy } from '@shell/utils/array';
6
6
  import { isEmpty } from '@shell/utils/object';
@@ -30,6 +30,43 @@ export function haveV2Monitoring(getters) {
30
30
 
31
31
  export const CATTLE_MONITORING_NAMESPACE = 'cattle-monitoring-system';
32
32
 
33
+ /**
34
+ * Look up the installed Rancher monitoring app, preferring the new
35
+ * `rancher-monitoring-dashboards` chart and falling back to the legacy
36
+ * `rancher-monitoring`. Returns null if the user lacks permission, neither
37
+ * chart is installed, or any lookup fails.
38
+ */
39
+ export async function fetchMonitoringApp(store, storeName) {
40
+ if (!store.getters[`${ storeName }/canList`](CATALOG.APP)) {
41
+ return null;
42
+ }
43
+
44
+ const ids = [
45
+ `${ CATTLE_MONITORING_NAMESPACE }/rancher-monitoring-dashboards`,
46
+ `${ CATTLE_MONITORING_NAMESPACE }/rancher-monitoring`,
47
+ ];
48
+
49
+ for (const id of ids) {
50
+ try {
51
+ const res = await store.dispatch(`${ storeName }/find`, { type: CATALOG.APP, id });
52
+
53
+ if (res) {
54
+ return res;
55
+ }
56
+ } catch (err) {
57
+ // Try the next id; both failing means nothing is installed.
58
+ }
59
+ }
60
+
61
+ return null;
62
+ }
63
+
64
+ export async function fetchMonitoringVersion(store, storeName) {
65
+ const app = await fetchMonitoringApp(store, storeName);
66
+
67
+ return app?.currentVersion || '';
68
+ }
69
+
33
70
  async function hasEndpointSubsets(store, id) {
34
71
  if (store.getters['cluster/schemaFor'](ENDPOINTS)) {
35
72
  const endpoints = await store.dispatch('cluster/findAll', { type: ENDPOINTS }) || [];
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Create a day 2 operation CR for imported clusters.
3
+ *
4
+ * @param {Function} dispatch - The Vuex dispatch function
5
+ * @param {string} type - The operation CRD type
6
+ * @param {object} spec - The operation spec
7
+ * @param {string} namespace - The namespace for the operation CR
8
+ * @param {string} namePrefix - The name prefix for the generated name
9
+ * @returns {Promise} The saved resource
10
+ */
11
+ export async function createOperationCR(dispatch, type, spec, namespace, namePrefix) {
12
+ const resource = await dispatch('management/create', {
13
+ type,
14
+ metadata: { namespace, generateName: `${ namePrefix }-` },
15
+ spec,
16
+ }, { root: true });
17
+
18
+ return resource.save();
19
+ }
@@ -88,6 +88,13 @@ export function requireJson(path: string): object {
88
88
  return mod.default || mod;
89
89
  }
90
90
 
91
+ // Expose asset resolvers on window so extension builds (which use a stub
92
+ // instead of require.context) can delegate to the host dashboard at runtime.
93
+ if (typeof window !== 'undefined') {
94
+ (window as any).__shell_requireAsset = requireAsset;
95
+ (window as any).__shell_requireJson = requireJson;
96
+ }
97
+
91
98
  // Exported for testing — allows injecting mock contexts
92
99
  export function _setContexts(img: WebpackRequireContext | null, json: WebpackRequireContext | null): void {
93
100
  imgCtx = img;
@@ -3,28 +3,22 @@ import { privateRegistryRequired } from '@shell/utils/validators/private-registr
3
3
  const makeCtx = (overrides: any = {}) => ({
4
4
  t: jest.fn((key: string, params?: any) => (params ? `${ key }:${ JSON.stringify(params) }` : key)),
5
5
  privateRegistryEnabled: false,
6
- normanCluster: { importedConfig: { privateRegistryURL: null } },
7
- isImportedCluster: true,
6
+ normanCluster: { importedConfig: {} },
7
+ $store: { getters: { 'management/byId': () => null } },
8
8
  ...overrides,
9
9
  });
10
10
 
11
- describe('privateRegistryRequired', () => {
12
- it('should return undefined when the cluster is not imported', () => {
13
- const ctx = makeCtx({ isImportedCluster: false, privateRegistryEnabled: true });
14
- const rule = privateRegistryRequired(ctx);
15
-
16
- expect(rule()).toBeUndefined();
17
- });
11
+ const storeWithGlobalRegistry = { getters: { 'management/byId': () => ({ value: 'registry.global.io' }) } };
18
12
 
19
- it('should default isImportedCluster to true when the property is absent from the context', () => {
20
- const ctx: any = {
21
- t: jest.fn((key: string, params?: any) => (params ? `${ key }:${ JSON.stringify(params) }` : key)),
13
+ describe('privateRegistryRequired', () => {
14
+ it('should return undefined when a global default registry is configured', () => {
15
+ const ctx = makeCtx({
22
16
  privateRegistryEnabled: true,
23
- normanCluster: { importedConfig: { privateRegistryURL: null } },
24
- };
17
+ $store: storeWithGlobalRegistry,
18
+ });
25
19
  const rule = privateRegistryRequired(ctx);
26
20
 
27
- expect(rule()).toStrictEqual('validation.required:{"key":"cluster.privateRegistry.label"}');
21
+ expect(rule()).toBeUndefined();
28
22
  });
29
23
 
30
24
  it('should return undefined when the registry toggle is off', () => {
@@ -73,4 +67,22 @@ describe('privateRegistryRequired', () => {
73
67
 
74
68
  expect(rule()).toBeUndefined();
75
69
  });
70
+
71
+ it('should handle $store getter throwing gracefully', () => {
72
+ const ctx = makeCtx({
73
+ privateRegistryEnabled: true,
74
+ normanCluster: { importedConfig: {} },
75
+ $store: {
76
+ getters: {
77
+ get 'management/byId'() {
78
+ throw new Error('no store');
79
+ }
80
+ }
81
+ },
82
+ });
83
+ const rule = privateRegistryRequired(ctx);
84
+
85
+ // Falls through to validation since no global default detected
86
+ expect(rule()).toStrictEqual('validation.required:{"key":"cluster.privateRegistry.label"}');
87
+ });
76
88
  });
@@ -1,19 +1,30 @@
1
+ import { VuexStore } from 'types/store/vuex';
1
2
  import { Translation } from '@shell/types/t';
2
3
  import formRulesGenerator from '@shell/utils/validators/formRules';
4
+ import { SETTING } from '@shell/config/settings';
5
+ import { MANAGEMENT } from '@shell/config/types';
3
6
 
4
7
  interface PrivateRegistryRuleContext {
5
8
  t: Translation;
6
9
  privateRegistryEnabled: boolean;
7
10
  normanCluster: { importedConfig?: { privateRegistryURL?: string | null } } | null;
8
- isImportedCluster?: boolean;
11
+ $store: VuexStore
9
12
  }
10
13
 
11
14
  export function privateRegistryRequired(ctx: PrivateRegistryRuleContext) {
12
15
  return () => {
13
- // Check existence using `in` rather than direct access to avoid Vue's render-time warning
14
- const isImported = 'isImportedCluster' in ctx ? !!ctx.isImportedCluster : true;
16
+ let hasGlobalDefault = false;
15
17
 
16
- if (!isImported || !ctx.privateRegistryEnabled) {
18
+ try {
19
+ // settings are loaded when the dashboard loads so using a synchronous getter is reliable here
20
+ const globalRegistrySetting = ctx.$store.getters['management/byId'](MANAGEMENT.SETTING, SETTING.SYSTEM_DEFAULT_REGISTRY);
21
+
22
+ hasGlobalDefault = !!globalRegistrySetting?.value;
23
+ } catch {
24
+ // if no setting proceed like there's no global default
25
+ }
26
+
27
+ if (!ctx.privateRegistryEnabled || hasGlobalDefault) {
17
28
  return undefined;
18
29
  }
19
30
  const url = ctx.normanCluster?.importedConfig?.privateRegistryURL;