@rancher/shell 0.5.1 → 0.5.3

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 (70) hide show
  1. package/assets/translations/en-us.yaml +8 -4
  2. package/components/ClusterIconMenu.vue +24 -9
  3. package/components/CodeMirror.vue +79 -18
  4. package/components/FixedBanner.vue +1 -0
  5. package/components/ResourceDetail/index.vue +1 -4
  6. package/components/ResourceYaml.vue +29 -5
  7. package/components/SideNav.vue +42 -64
  8. package/components/SortableTable/index.vue +1 -1
  9. package/components/YamlEditor.vue +1 -0
  10. package/components/__tests__/CodeMirror.spec.ts +99 -0
  11. package/components/form/BannerSettings.vue +3 -0
  12. package/components/form/FileSelector.vue +1 -0
  13. package/components/form/KeyValue.vue +1 -0
  14. package/components/formatter/WorkloadDetailEndpoints.vue +12 -22
  15. package/components/formatter/__tests__/WorkloadDetailEndpoints.test.ts +81 -0
  16. package/components/nav/Header.vue +1 -0
  17. package/components/nav/Jump.vue +19 -9
  18. package/components/nav/TopLevelMenu.vue +37 -15
  19. package/components/nav/Type.vue +15 -4
  20. package/components/nav/__tests__/TopLevelMenu.test.ts +1 -1
  21. package/components/nav/__tests__/Type.test.ts +30 -0
  22. package/core/types-provisioning.ts +7 -0
  23. package/detail/__tests__/provisioning.cattle.io.cluster.test.ts +77 -0
  24. package/detail/fleet.cattle.io.bundle.vue +1 -1
  25. package/detail/provisioning.cattle.io.cluster.vue +19 -4
  26. package/edit/management.cattle.io.setting.vue +1 -0
  27. package/edit/monitoring.coreos.com.alertmanagerconfig/types/opsgenie.vue +1 -1
  28. package/edit/monitoring.coreos.com.alertmanagerconfig/types/pagerduty.vue +1 -2
  29. package/edit/monitoring.coreos.com.alertmanagerconfig/types/slack.vue +1 -1
  30. package/edit/provisioning.cattle.io.cluster/index.vue +23 -10
  31. package/edit/provisioning.cattle.io.cluster/rke2.vue +22 -50
  32. package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +9 -11
  33. package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs.vue +3 -1
  34. package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +3 -0
  35. package/edit/token.vue +1 -0
  36. package/list/catalog.cattle.io.app.vue +1 -0
  37. package/list/management.cattle.io.setting.vue +1 -0
  38. package/machine-config/amazonec2.vue +1 -0
  39. package/models/__tests__/provisioning.cattle.io.cluster.test.ts +151 -0
  40. package/models/__tests__/secret.test.ts +37 -0
  41. package/models/__tests__/storage.k8s.io.storageclass.test.ts +22 -0
  42. package/models/management.cattle.io.kontainerdriver.js +2 -1
  43. package/models/provisioning.cattle.io.cluster.js +36 -1
  44. package/models/secret.js +9 -0
  45. package/models/storage.k8s.io.storageclass.js +1 -1
  46. package/package.json +1 -1
  47. package/pages/c/_cluster/settings/DefaultLinksEditor.vue +1 -0
  48. package/pages/c/_cluster/settings/brand.vue +3 -0
  49. package/pages/c/_cluster/uiplugins/AddExtensionRepos.vue +4 -4
  50. package/pages/c/_cluster/uiplugins/SetupUIPlugins.vue +5 -2
  51. package/pages/c/_cluster/uiplugins/__tests__/AddExtensionRepos.test.ts +96 -0
  52. package/pages/c/_cluster/uiplugins/__tests__/SetupUIPlugins.test.ts +128 -0
  53. package/plugins/dashboard-store/__tests__/actions.test.ts +196 -111
  54. package/plugins/dashboard-store/actions.js +4 -6
  55. package/plugins/dashboard-store/getters.js +60 -2
  56. package/plugins/dashboard-store/resource-class.js +6 -2
  57. package/plugins/steve/__tests__/getters.spec.ts +10 -0
  58. package/plugins/steve/__tests__/resource-utils.test.ts +159 -0
  59. package/plugins/steve/actions.js +3 -37
  60. package/plugins/steve/getters.js +6 -0
  61. package/plugins/steve/resource-utils.ts +38 -0
  62. package/scripts/extension/parse-tag-name +3 -3
  63. package/store/__tests__/type-map.test.ts +1122 -0
  64. package/store/index.js +3 -2
  65. package/store/plugins.js +7 -6
  66. package/store/type-map.js +145 -75
  67. package/types/shell/index.d.ts +2 -0
  68. package/utils/__tests__/create-yaml.test.ts +10 -0
  69. package/utils/create-yaml.js +5 -1
  70. package/utils/object.js +10 -0
@@ -249,6 +249,21 @@ export default class ProvCluster extends SteveModel {
249
249
  return providers.includes(this.provisioner);
250
250
  }
251
251
 
252
+ get isPrivateHostedProvider() {
253
+ if (this.isHostedKubernetesProvider && this.mgmt && this.provisioner) {
254
+ switch (this.provisioner.toLowerCase()) {
255
+ case 'gke':
256
+ return this.mgmt.spec?.gkeConfig?.privateClusterConfig?.enablePrivateEndpoint;
257
+ case 'eks':
258
+ return this.mgmt.spec?.eksConfig?.privateAccess;
259
+ case 'aks':
260
+ return this.mgmt.spec?.aksConfig?.privateCluster;
261
+ }
262
+ }
263
+
264
+ return false;
265
+ }
266
+
252
267
  get isLocal() {
253
268
  return this.mgmt?.isLocal;
254
269
  }
@@ -891,7 +906,27 @@ export default class ProvCluster extends SteveModel {
891
906
  }
892
907
 
893
908
  get hasError() {
894
- return this.status?.conditions?.some((condition) => condition.error === true);
909
+ // Before we were just checking for this.status?.conditions?.some((condition) => condition.error === true)
910
+ // but this is wrong as an error might exist but it might not be meaningful in the context of readiness of a cluster
911
+ // which is what this 'hasError' is used for.
912
+ // We now check if there's a ready condition after an error, which helps dictate the readiness of a cluster
913
+ // Based on the findings in https://github.com/rancher/dashboard/issues/10043
914
+ if (this.status?.conditions && this.status?.conditions.length) {
915
+ // if there are errors, we compare with how recent the "Ready" condition is compared to that error, otherwise we just move on
916
+ if (this.status?.conditions.some((c) => c.error === true)) {
917
+ // there's no ready condition and has an error, mark it
918
+ if (!this.status?.conditions.some((c) => c.type === 'Ready')) {
919
+ return true;
920
+ }
921
+
922
+ const filteredConditions = this.status?.conditions.filter((c) => c.error === true || c.type === 'Ready');
923
+ const mostRecentCondition = filteredConditions.reduce((a, b) => ((a.lastUpdateTime > b.lastUpdateTime) ? a : b));
924
+
925
+ return mostRecentCondition.error;
926
+ }
927
+ }
928
+
929
+ return false;
895
930
  }
896
931
 
897
932
  get namespaceLocation() {
package/models/secret.js CHANGED
@@ -9,6 +9,7 @@ import SteveModel from '@shell/plugins/steve/steve-class';
9
9
  import { colorForState, stateDisplay, STATES_ENUM } from '@shell/plugins/dashboard-store/resource-class';
10
10
  import { diffFrom } from '@shell/utils/time';
11
11
  import day from 'dayjs';
12
+ import { steveCleanForDownload } from '@shell/plugins/steve/resource-utils';
12
13
 
13
14
  export const TYPES = {
14
15
  OPAQUE: 'Opaque',
@@ -456,4 +457,12 @@ export default class Secret extends SteveModel {
456
457
 
457
458
  return val;
458
459
  }
460
+
461
+ async cleanForDownload(yaml) {
462
+ // secret resource contains the type attribute
463
+ // ref: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/secret-v1/
464
+ // ref: https://kubernetes.io/docs/concepts/configuration/secret/#secret-types
465
+
466
+ return steveCleanForDownload(yaml, { rootKeys: ['id', 'links', 'actions'] });
467
+ }
459
468
  }
@@ -84,7 +84,7 @@ export const PROVISIONER_OPTIONS = [
84
84
  export default class extends SteveModel {
85
85
  get provisionerDisplay() {
86
86
  const option = PROVISIONER_OPTIONS.find((o) => o.value === this.provisioner);
87
- const fallback = `${ this.provisioner } ${ this.t('persistentVolume.csi.drivers.suffix') }`;
87
+ const fallback = `${ this.provisioner } ${ this.t('persistentVolume.csi.suffix') }`;
88
88
 
89
89
  return option ? this.t(option.labelKey) : this.$rootGetters['i18n/withFallback'](`persistentVolume.csi.drivers.${ this.provisioner.replaceAll('.', '-') }`, null, fallback);
90
90
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rancher/shell",
3
- "version": "0.5.1",
3
+ "version": "0.5.3",
4
4
  "description": "Rancher Dashboard Shell",
5
5
  "repository": "https://github.com/rancherlabs/dashboard",
6
6
  "license": "Apache-2.0",
@@ -81,6 +81,7 @@ export default {
81
81
  v-if="!isView"
82
82
  v-model="row.enabled"
83
83
  label-key="customLinks.settings.showLabel"
84
+ :data-testid="`custom-links__checkbox-${i}`"
84
85
  @input="showhide(row, i, $event)"
85
86
  />
86
87
  </div>
@@ -238,6 +238,7 @@ export default {
238
238
  <label class="text-muted">{{ t('branding.logos.lightPreview') }}</label>
239
239
  <img
240
240
  class="logo-preview"
241
+ data-testid="branding-logo-light-preview"
241
242
  :src="uiLogoLight ? uiLogoLight : uiLogoDark"
242
243
  >
243
244
  </SimpleBox>
@@ -262,6 +263,7 @@ export default {
262
263
  <label class="text-muted">{{ t('branding.logos.darkPreview') }}</label>
263
264
  <img
264
265
  class="logo-preview"
266
+ data-testid="branding-logo-dark-preview"
265
267
  :src="uiLogoDark ? uiLogoDark : uiLogoLight"
266
268
  >
267
269
  </SimpleBox>
@@ -304,6 +306,7 @@ export default {
304
306
  <label class="text-muted">{{ t('branding.favicon.preview') }}</label>
305
307
  <img
306
308
  class="logo-preview"
309
+ data-testid="branding-favicon-preview"
307
310
  :src="uiFavicon"
308
311
  >
309
312
  </SimpleBox>
@@ -10,6 +10,7 @@ import {
10
10
  UI_PLUGINS_PARTNERS_REPO_URL,
11
11
  UI_PLUGINS_PARTNERS_REPO_BRANCH,
12
12
  } from '@shell/config/uiplugins';
13
+ import { isRancherPrime } from '@shell/config/version';
13
14
 
14
15
  export default {
15
16
  components: {
@@ -27,6 +28,7 @@ export default {
27
28
  return {
28
29
  errors: [],
29
30
  repos: [],
31
+ prime: isRancherPrime(),
30
32
  addRepos: {
31
33
  official: true,
32
34
  partners: true
@@ -54,16 +56,13 @@ export default {
54
56
  },
55
57
  hasRancherUIPartnersPluginsRepo() {
56
58
  return !!this.repos.find((r) => r.urlDisplay === UI_PLUGINS_PARTNERS_REPO_URL);
57
- },
58
- isAnyRepoAvailableForInstall() {
59
- return !this.hasRancherUIPluginsRepo || !this.hasRancherUIPartnersPluginsRepo;
60
59
  }
61
60
  },
62
61
 
63
62
  methods: {
64
63
  showDialog() {
65
64
  this.addRepos = {
66
- official: !this.hasRancherUIPluginsRepo,
65
+ official: isRancherPrime() && !this.hasRancherUIPluginsRepo,
67
66
  partners: !this.hasRancherUIPartnersPluginsRepo,
68
67
  };
69
68
  this.$modal.show('add-extensions-repos');
@@ -121,6 +120,7 @@ export default {
121
120
  </p>
122
121
  <!-- Official repo -->
123
122
  <div
123
+ v-if="prime"
124
124
  class="mb-15"
125
125
  >
126
126
  <Checkbox
@@ -7,6 +7,7 @@ import { CATALOG as CATALOG_ANNOTATIONS } from '@shell/config/labels-annotations
7
7
  import Dialog from '@shell/components/Dialog.vue';
8
8
  import Checkbox from '@components/Form/Checkbox/Checkbox.vue';
9
9
  import Banner from '@components/Banner/Banner.vue';
10
+ import { isRancherPrime } from '@shell/config/version';
10
11
 
11
12
  import {
12
13
  UI_PLUGIN_NAMESPACE,
@@ -68,6 +69,7 @@ export default {
68
69
  haveCharts: false,
69
70
  installCharts: [],
70
71
  errors: [],
72
+ prime: isRancherPrime(),
71
73
  addRepos: {
72
74
  official: true,
73
75
  partners: true,
@@ -98,7 +100,7 @@ export default {
98
100
  return !!this.repos.find((r) => r.urlDisplay === UI_PLUGINS_PARTNERS_REPO_URL);
99
101
  },
100
102
  isAnyRepoAvailableForInstall() {
101
- return !this.hasRancherUIPluginsRepo || !this.hasRancherUIPartnersPluginsRepo;
103
+ return (isRancherPrime() && !this.hasRancherUIPluginsRepo) || !this.hasRancherUIPartnersPluginsRepo;
102
104
  }
103
105
  },
104
106
 
@@ -155,7 +157,7 @@ export default {
155
157
 
156
158
  // Reset checkbox based on if the repo is already installed
157
159
  this.addRepos = {
158
- official: !this.hasRancherUIPluginsRepo,
160
+ official: isRancherPrime() && !this.hasRancherUIPluginsRepo,
159
161
  partners: !this.hasRancherUIPartnersPluginsRepo,
160
162
  };
161
163
 
@@ -286,6 +288,7 @@ export default {
286
288
  </Banner>
287
289
  <!-- Official rancher repo -->
288
290
  <div
291
+ v-if="prime"
289
292
  class="mb-15"
290
293
  >
291
294
  <Checkbox
@@ -0,0 +1,96 @@
1
+ import { mount } from '@vue/test-utils';
2
+ import {
3
+ UI_PLUGINS_REPO_URL,
4
+ UI_PLUGINS_PARTNERS_REPO_URL,
5
+ } from '@shell/config/uiplugins';
6
+ import AddExtensionRepos from '@shell/pages/c/_cluster/uiplugins/AddExtensionRepos.vue';
7
+ const mockedStore = () => {
8
+ return {
9
+ getters: {
10
+ 'i18n/t': (text: string) => text,
11
+ 'i18n/exists': (text: string) => text,
12
+ t: (text: string) => text,
13
+ 'management/schemaFor': () => true,
14
+ 'management/findAll': () => [
15
+ { urlDisplay: UI_PLUGINS_REPO_URL },
16
+ { urlDisplay: UI_PLUGINS_PARTNERS_REPO_URL },
17
+ ]
18
+ }
19
+ };
20
+ };
21
+
22
+ const requiredSetup = () => {
23
+ return {
24
+ mocks: {
25
+ $store: mockedStore(),
26
+ $fetchState: {},
27
+ }
28
+ };
29
+ };
30
+
31
+ describe('component: AddExtensionRepos', () => {
32
+ it('should NOT SHOW a checkbox to install official Rancher repo if NOT prime', async() => {
33
+ jest.useFakeTimers();
34
+
35
+ const wrapper = mount(AddExtensionRepos, {
36
+ ...requiredSetup(),
37
+ // since vue-js-modal uses transitions, we need disable
38
+ // the default behaviour of transition-stubbing that vue-test-utils has...
39
+ stubs: { transition: false }
40
+ });
41
+
42
+ wrapper.vm.showDialog();
43
+
44
+ // these couple of nextTick + advanceTimersByTime are needed for
45
+ // the dialog content to be rendered!
46
+ await wrapper.vm.$nextTick();
47
+
48
+ jest.advanceTimersByTime(1);
49
+
50
+ await wrapper.vm.$nextTick();
51
+
52
+ jest.advanceTimersByTime(1);
53
+
54
+ const rancherCheckbox = wrapper.find('[data-testid="add-extensions-repos-modal-add-official-repo"]');
55
+ const partnersCheckbox = wrapper.find('[data-testid="add-extensions-repos-modal-add-partners-repo"]');
56
+
57
+ expect(rancherCheckbox.exists()).toBe(false);
58
+ expect(partnersCheckbox.exists()).toBe(true);
59
+
60
+ jest.clearAllTimers();
61
+ wrapper.destroy();
62
+ });
63
+
64
+ it('should SHOW a checkbox to install official Rancher repo if IS prime', async() => {
65
+ jest.useFakeTimers();
66
+
67
+ const wrapper = mount(AddExtensionRepos, {
68
+ ...requiredSetup(),
69
+ // since vue-js-modal uses transitions, we need disable
70
+ // the default behaviour of transition-stubbing that vue-test-utils has...
71
+ stubs: { transition: false }
72
+ });
73
+
74
+ wrapper.vm.prime = true;
75
+ wrapper.vm.showDialog();
76
+
77
+ // these couple of nextTick + advanceTimersByTime are needed for
78
+ // the dialog content to be rendered!
79
+ await wrapper.vm.$nextTick();
80
+
81
+ jest.advanceTimersByTime(1);
82
+
83
+ await wrapper.vm.$nextTick();
84
+
85
+ jest.advanceTimersByTime(1);
86
+
87
+ const rancherCheckbox = wrapper.find('[data-testid="add-extensions-repos-modal-add-official-repo"]');
88
+ const partnersCheckbox = wrapper.find('[data-testid="add-extensions-repos-modal-add-partners-repo"]');
89
+
90
+ expect(rancherCheckbox.exists()).toBe(true);
91
+ expect(partnersCheckbox.exists()).toBe(true);
92
+
93
+ jest.clearAllTimers();
94
+ wrapper.destroy();
95
+ });
96
+ });
@@ -0,0 +1,128 @@
1
+ import { mount, createLocalVue } from '@vue/test-utils';
2
+ import Vuex from 'vuex';
3
+ import {
4
+ UI_PLUGINS_REPO_URL,
5
+ UI_PLUGINS_PARTNERS_REPO_URL,
6
+ } from '@shell/config/uiplugins';
7
+ import SetupUIPlugins from '@shell/pages/c/_cluster/uiplugins/SetupUIPlugins.vue';
8
+
9
+ describe('component: SetupUIPlugins', () => {
10
+ const localVue = createLocalVue();
11
+
12
+ localVue.use(Vuex);
13
+
14
+ it('should NOT SHOW a checkbox to install official Rancher repo if NOT prime', async() => {
15
+ const store = new Vuex.Store({
16
+ modules: {
17
+ catalog: {
18
+ namespaced: true,
19
+ getters: {
20
+ repos: () => [
21
+ { urlDisplay: UI_PLUGINS_REPO_URL },
22
+ { urlDisplay: UI_PLUGINS_PARTNERS_REPO_URL },
23
+ ],
24
+ repo: () => {},
25
+ rawCharts: () => [],
26
+ }
27
+ }
28
+ },
29
+ getters: {
30
+ 'i18n/t': () => jest.fn(),
31
+ 'i18n/exists': () => jest.fn(),
32
+ t: () => jest.fn(),
33
+ 'management/schemaFor': () => true,
34
+ 'management/findAll': () => [],
35
+ 'management/find': () => {}
36
+ }
37
+ });
38
+
39
+ jest.useFakeTimers();
40
+
41
+ const wrapper = mount(SetupUIPlugins, {
42
+ store,
43
+ localVue,
44
+ // since vue-js-modal uses transitions, we need disable
45
+ // the default behaviour of transition-stubbing that vue-test-utils has...
46
+ stubs: { transition: false }
47
+ });
48
+
49
+ wrapper.vm.enable();
50
+
51
+ // these couple of nextTick + advanceTimersByTime are needed for
52
+ // the dialog content to be rendered!
53
+ await wrapper.vm.$nextTick();
54
+
55
+ jest.advanceTimersByTime(1);
56
+
57
+ await wrapper.vm.$nextTick();
58
+
59
+ jest.advanceTimersByTime(1);
60
+
61
+ const rancherCheckbox = wrapper.find('[data-testid="extension-enable-operator-official-repo"]');
62
+ const partnersCheckbox = wrapper.find('[data-testid="extension-enable-operator-partners-repo"]');
63
+
64
+ expect(rancherCheckbox.exists()).toBe(false);
65
+ expect(partnersCheckbox.exists()).toBe(true);
66
+
67
+ jest.clearAllTimers();
68
+ wrapper.destroy();
69
+ });
70
+
71
+ it('should SHOW a checkbox to install official Rancher repo if IS prime', async() => {
72
+ const store = new Vuex.Store({
73
+ modules: {
74
+ catalog: {
75
+ namespaced: true,
76
+ getters: {
77
+ repos: () => [
78
+ { urlDisplay: UI_PLUGINS_REPO_URL },
79
+ { urlDisplay: UI_PLUGINS_PARTNERS_REPO_URL },
80
+ ],
81
+ repo: () => {},
82
+ rawCharts: () => [],
83
+ }
84
+ }
85
+ },
86
+ getters: {
87
+ 'i18n/t': () => jest.fn(),
88
+ 'i18n/exists': () => jest.fn(),
89
+ t: () => jest.fn(),
90
+ 'management/schemaFor': () => true,
91
+ 'management/findAll': () => [],
92
+ 'management/find': () => {}
93
+ }
94
+ });
95
+
96
+ jest.useFakeTimers();
97
+
98
+ const wrapper = mount(SetupUIPlugins, {
99
+ store,
100
+ localVue,
101
+ // since vue-js-modal uses transitions, we need disable
102
+ // the default behaviour of transition-stubbing that vue-test-utils has...
103
+ stubs: { transition: false }
104
+ });
105
+
106
+ wrapper.vm.prime = true;
107
+ wrapper.vm.enable();
108
+
109
+ // these couple of nextTick + advanceTimersByTime are needed for
110
+ // the dialog content to be rendered!
111
+ await wrapper.vm.$nextTick();
112
+
113
+ jest.advanceTimersByTime(1);
114
+
115
+ await wrapper.vm.$nextTick();
116
+
117
+ jest.advanceTimersByTime(1);
118
+
119
+ const rancherCheckbox = wrapper.find('[data-testid="extension-enable-operator-official-repo"]');
120
+ const partnersCheckbox = wrapper.find('[data-testid="extension-enable-operator-partners-repo"]');
121
+
122
+ expect(rancherCheckbox.exists()).toBe(true);
123
+ expect(partnersCheckbox.exists()).toBe(true);
124
+
125
+ jest.clearAllTimers();
126
+ wrapper.destroy();
127
+ });
128
+ });