@rancher/shell 0.3.16 → 0.3.18

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 (174) hide show
  1. package/assets/images/wechat-qr-code.jpg +0 -0
  2. package/assets/translations/en-us.yaml +75 -16
  3. package/assets/translations/zh-hans.yaml +151 -15
  4. package/chart/__tests__/S3.test.ts +50 -0
  5. package/chart/rancher-backup/S3.vue +21 -0
  6. package/chart/rancher-backup/index.vue +4 -0
  7. package/components/AsyncButton.vue +1 -1
  8. package/components/CommunityLinks.vue +1 -0
  9. package/components/FileDiff.vue +92 -85
  10. package/components/Inactivity.vue +10 -0
  11. package/components/LazyImage.vue +2 -2
  12. package/components/PromptRestore.vue +7 -5
  13. package/components/ResourceDetail/Masthead.vue +1 -1
  14. package/components/ResourceDetail/index.vue +8 -14
  15. package/components/ResourceList/index.vue +1 -1
  16. package/components/ResourceTable.vue +50 -2
  17. package/components/YamlEditor.vue +1 -0
  18. package/components/__tests__/PromptRestore.test.ts +72 -0
  19. package/components/auth/AzureWarning.vue +1 -1
  20. package/components/auth/RoleDetailEdit.vue +1 -0
  21. package/components/fleet/FleetResources.vue +3 -64
  22. package/components/form/FileImageSelector.vue +9 -0
  23. package/components/form/FileSelector.vue +2 -1
  24. package/components/form/MatchExpressions.vue +1 -3
  25. package/components/form/NameNsDescription.vue +28 -12
  26. package/components/form/NodeAffinity.vue +2 -2
  27. package/components/form/PodAffinity.vue +2 -2
  28. package/components/form/ResourceTabs/index.vue +8 -2
  29. package/components/form/Select.vue +16 -0
  30. package/components/form/__tests__/FileImageSelector.test.ts +42 -0
  31. package/components/form/__tests__/FileSelector.test.ts +76 -0
  32. package/components/form/__tests__/NodeAffinity.test.ts +38 -0
  33. package/components/form/__tests__/PodAffinity.test.ts +46 -0
  34. package/components/formatter/ClusterLink.vue +8 -4
  35. package/components/formatter/ClusterProvider.vue +3 -1
  36. package/components/formatter/ImageName.vue +23 -0
  37. package/components/formatter/PodImages.vue +7 -1
  38. package/components/formatter/__tests__/ClusterLink.test.ts +101 -0
  39. package/components/formatter/__tests__/ClusterProvider.test.ts +24 -0
  40. package/components/nav/Header.vue +2 -2
  41. package/components/nav/WindowManager/ContainerShell.vue +60 -36
  42. package/components/nav/WindowManager/__tests__/ContainerShell.test.ts +561 -0
  43. package/config/__test__/home-links.test.ts +62 -0
  44. package/config/home-links.js +15 -3
  45. package/config/labels-annotations.js +7 -2
  46. package/config/persistentVolume.ts +108 -0
  47. package/config/product/manager.js +5 -1
  48. package/config/router.js +0 -4
  49. package/config/settings.ts +4 -0
  50. package/config/table-headers.js +6 -5
  51. package/config/types.js +2 -0
  52. package/config/uiplugins.js +50 -5
  53. package/core/plugin-helpers.js +39 -15
  54. package/core/plugin.ts +9 -0
  55. package/core/plugins.js +1 -1
  56. package/core/types-provisioning.ts +253 -0
  57. package/core/types.ts +21 -3
  58. package/detail/autoscaling.horizontalpodautoscaler/index.vue +50 -1
  59. package/detail/fleet.cattle.io.gitrepo.vue +10 -2
  60. package/detail/node.vue +6 -6
  61. package/detail/pod.vue +38 -9
  62. package/detail/provisioning.cattle.io.cluster.vue +46 -7
  63. package/detail/workload/index.vue +49 -18
  64. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +62 -0
  65. package/edit/__tests__/ui.cattle.io.navlink.test.ts +110 -0
  66. package/edit/auth/github.vue +1 -0
  67. package/edit/autoscaling.horizontalpodautoscaler/hpa-scaling-rule.vue +130 -0
  68. package/edit/autoscaling.horizontalpodautoscaler/index.vue +79 -0
  69. package/edit/fleet.cattle.io.clustergroup.vue +14 -3
  70. package/edit/fleet.cattle.io.gitrepo.vue +18 -1
  71. package/edit/namespace.vue +9 -1
  72. package/edit/networking.k8s.io.ingress/RulePath.vue +0 -2
  73. package/edit/persistentvolume/__tests__/persistentvolume.test.ts +82 -0
  74. package/edit/persistentvolume/index.vue +2 -1
  75. package/edit/persistentvolume/plugins/csi.vue +3 -1
  76. package/edit/persistentvolume/plugins/longhorn.vue +12 -12
  77. package/edit/provisioning.cattle.io.cluster/AgentConfiguration.vue +1 -30
  78. package/edit/provisioning.cattle.io.cluster/RegistryConfigs.vue +15 -11
  79. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +79 -1
  80. package/edit/provisioning.cattle.io.cluster/index.vue +53 -1
  81. package/edit/provisioning.cattle.io.cluster/rke2.vue +335 -151
  82. package/edit/storage.k8s.io.storageclass/index.vue +1 -2
  83. package/edit/ui.cattle.io.navlink.vue +213 -186
  84. package/initialize/App.js +3 -13
  85. package/initialize/layouts.ts +26 -0
  86. package/layouts/default.vue +1 -1
  87. package/list/group.principal.vue +1 -1
  88. package/list/provisioning.cattle.io.cluster.vue +8 -1
  89. package/middleware/authenticated.js +101 -5
  90. package/mixins/brand.js +39 -3
  91. package/mixins/child-hook.js +2 -2
  92. package/mixins/create-edit-view/impl.js +4 -4
  93. package/models/chart.js +1 -1
  94. package/models/fleet.cattle.io.cluster.js +33 -4
  95. package/models/fleet.cattle.io.gitrepo.js +113 -38
  96. package/models/management.cattle.io.kontainerdriver.js +14 -0
  97. package/models/persistentvolume.js +2 -111
  98. package/models/pod.js +30 -0
  99. package/models/provisioning.cattle.io.cluster.js +9 -1
  100. package/models/rke.cattle.io.etcdsnapshot.js +10 -7
  101. package/package.json +2 -2
  102. package/pages/about.vue +8 -2
  103. package/pages/auth/login.vue +1 -1
  104. package/pages/auth/logout.vue +11 -3
  105. package/pages/c/_cluster/apps/charts/index.vue +5 -2
  106. package/pages/c/_cluster/apps/charts/install.vue +5 -0
  107. package/pages/c/_cluster/auth/group.principal/assign-edit.vue +1 -1
  108. package/pages/c/_cluster/auth/roles/index.vue +1 -1
  109. package/pages/c/_cluster/explorer/index.vue +2 -11
  110. package/pages/c/_cluster/manager/cloudCredential/_id.vue +0 -1
  111. package/pages/c/_cluster/manager/cloudCredential/create.vue +0 -1
  112. package/pages/c/_cluster/settings/brand.vue +11 -8
  113. package/pages/c/_cluster/uiplugins/AddExtensionRepos.vue +177 -0
  114. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +19 -3
  115. package/pages/c/_cluster/uiplugins/RemoveUIPlugins.vue +90 -21
  116. package/pages/c/_cluster/uiplugins/SetupUIPlugins.vue +107 -37
  117. package/pages/c/_cluster/uiplugins/index.vue +160 -44
  118. package/pages/docs/_doc.vue +9 -3
  119. package/pages/home.vue +6 -6
  120. package/pages/support/index.vue +10 -4
  121. package/pkg/auto-import.js +1 -1
  122. package/plugins/clean-tooltip-directive.js +1 -1
  123. package/plugins/dashboard-store/__tests__/actions.spec.ts +165 -0
  124. package/plugins/dashboard-store/__tests__/getters.spec.ts +100 -0
  125. package/plugins/dashboard-store/__tests__/{mutations.spec.js → mutations.spec.ts} +2 -2
  126. package/plugins/dashboard-store/actions.js +1 -1
  127. package/plugins/dashboard-store/resource-class.js +39 -2
  128. package/plugins/plugin.js +9 -1
  129. package/plugins/steve/__tests__/getters.spec.ts +93 -0
  130. package/plugins/steve/getters.js +21 -1
  131. package/plugins/steve/subscribe.js +1 -3
  132. package/rancher-components/BadgeState/BadgeState.vue +5 -1
  133. package/rancher-components/Banner/Banner.test.ts +51 -1
  134. package/rancher-components/Banner/Banner.vue +134 -53
  135. package/rancher-components/Card/Card.test.ts +37 -0
  136. package/rancher-components/Card/Card.vue +24 -7
  137. package/rancher-components/Form/Checkbox/Checkbox.test.ts +20 -29
  138. package/rancher-components/Form/Checkbox/Checkbox.vue +45 -20
  139. package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +2 -8
  140. package/rancher-components/Form/LabeledInput/LabeledInput.vue +22 -10
  141. package/rancher-components/Form/Radio/RadioButton.test.ts +31 -0
  142. package/rancher-components/Form/Radio/RadioButton.vue +30 -13
  143. package/rancher-components/Form/Radio/RadioGroup.vue +26 -7
  144. package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +7 -6
  145. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.test.ts +25 -38
  146. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +23 -11
  147. package/rancher-components/LabeledTooltip/LabeledTooltip.vue +19 -5
  148. package/rancher-components/StringList/StringList.test.ts +453 -49
  149. package/rancher-components/StringList/StringList.vue +44 -26
  150. package/scripts/extension/publish +2 -2
  151. package/scripts/typegen.sh +11 -2
  152. package/server/server-middleware.js +4 -12
  153. package/store/index.js +14 -3
  154. package/store/prefs.js +0 -3
  155. package/store/store-types.js +2 -0
  156. package/store/type-map.js +17 -29
  157. package/types/api.d.ts +1 -0
  158. package/types/fleet.d.ts +1 -0
  159. package/types/shell/index.d.ts +931 -85
  160. package/types/userPreferences.d.ts +1 -1
  161. package/utils/__mocks__/socket.js +21 -0
  162. package/utils/grafana.js +23 -11
  163. package/utils/kube.js +9 -0
  164. package/utils/object.js +27 -0
  165. package/utils/selector.js +2 -1
  166. package/utils/settings.ts +2 -2
  167. package/utils/validators/formRules/index.ts +3 -3
  168. package/vue.config.js +3 -2
  169. package/components/.DS_Store +0 -0
  170. package/components/__tests__/.DS_Store +0 -0
  171. package/creators/pkg/package-lock.json +0 -37
  172. package/pages/safeMode.vue +0 -17
  173. package/plugins/steve/urloptions.js +0 -47
  174. package/yarn-error.log +0 -196
@@ -4,7 +4,9 @@ import { mapGetters } from 'vuex';
4
4
  import { mapPref, PLUGIN_DEVELOPER } from '@shell/store/prefs';
5
5
  import { sortBy } from '@shell/utils/sort';
6
6
  import { allHash } from '@shell/utils/promise';
7
- import { CATALOG, UI_PLUGIN, SERVICE } from '@shell/config/types';
7
+ import { CATALOG, UI_PLUGIN, SERVICE, MANAGEMENT } from '@shell/config/types';
8
+ import { SETTING } from '@shell/config/settings';
9
+ import { fetchOrCreateSetting } from '@shell/utils/settings';
8
10
  import { getVersionData } from '@shell/config/version';
9
11
  import { CATALOG as CATALOG_ANNOTATIONS } from '@shell/config/labels-annotations';
10
12
  import { NAME as APP_PRODUCT } from '@shell/config/product/apps';
@@ -21,7 +23,9 @@ import DeveloperInstallDialog from './DeveloperInstallDialog.vue';
21
23
  import PluginInfoPanel from './PluginInfoPanel.vue';
22
24
  import SetupUIPlugins from './SetupUIPlugins';
23
25
  import RemoveUIPlugins from './RemoveUIPlugins';
26
+ import AddExtensionRepos from './AddExtensionRepos';
24
27
  import CatalogList from './CatalogList/index.vue';
28
+ import Banner from '@components/Banner/Banner.vue';
25
29
  import {
26
30
  isUIPlugin,
27
31
  uiPluginAnnotation,
@@ -31,11 +35,20 @@ import {
31
35
  isChartVersionHigher,
32
36
  UI_PLUGIN_NAMESPACE,
33
37
  UI_PLUGIN_CHART_ANNOTATIONS,
34
- UI_PLUGIN_LABELS
38
+ UI_PLUGIN_LABELS,
39
+ UI_PLUGINS_REPO_URL,
40
+ UI_PLUGINS_PARTNERS_REPO_URL
35
41
  } from '@shell/config/uiplugins';
36
42
 
37
43
  const MAX_DESCRIPTION_LENGTH = 200;
38
44
 
45
+ const TABS_VALUES = {
46
+ INSTALLED: 'installed',
47
+ UPDATES: 'updates',
48
+ AVAILABLE: 'available',
49
+ ALL: 'all'
50
+ };
51
+
39
52
  export default {
40
53
  components: {
41
54
  ActionMenu,
@@ -43,6 +56,7 @@ export default {
43
56
  DeveloperInstallDialog,
44
57
  IconMessage,
45
58
  CatalogList,
59
+ Banner,
46
60
  CatalogLoadDialog,
47
61
  InstallDialog,
48
62
  LazyImage,
@@ -52,25 +66,29 @@ export default {
52
66
  UninstallDialog,
53
67
  SetupUIPlugins,
54
68
  RemoveUIPlugins,
69
+ AddExtensionRepos,
55
70
  },
56
71
 
57
72
  data() {
58
73
  return {
59
- view: '',
60
- charts: [],
61
- installing: {},
62
- errors: {},
63
- plugins: [], // The installed plugins
64
- helmOps: [], // Helm operations
65
- loading: true,
66
- menuTargetElement: null,
67
- menuTargetEvent: null,
68
- menuOpen: false,
69
- hasService: false,
70
- defaultIcon: require('~shell/assets/images/generic-plugin.svg'),
71
- reloadRequired: false,
72
- rancherVersion: getVersionData()?.Version,
73
- showCatalogList: false
74
+ TABS_VALUES,
75
+ kubeVersion: null,
76
+ view: '',
77
+ charts: [],
78
+ installing: {},
79
+ errors: {},
80
+ plugins: [], // The installed plugins
81
+ helmOps: [], // Helm operations
82
+ addExtensionReposBannerSetting: undefined,
83
+ loading: true,
84
+ menuTargetElement: null,
85
+ menuTargetEvent: null,
86
+ menuOpen: false,
87
+ hasService: false,
88
+ defaultIcon: require('~shell/assets/images/generic-plugin.svg'),
89
+ reloadRequired: false,
90
+ rancherVersion: getVersionData()?.Version,
91
+ showCatalogList: false
74
92
  };
75
93
  },
76
94
 
@@ -79,7 +97,7 @@ export default {
79
97
  async fetch() {
80
98
  const hash = {};
81
99
 
82
- const isSetup = await this.updateInstallStatus();
100
+ const isSetup = await this.updateInstallStatus(true);
83
101
 
84
102
  if (isSetup) {
85
103
  if (this.$store.getters['management/schemaFor'](UI_PLUGIN)) {
@@ -89,6 +107,10 @@ export default {
89
107
 
90
108
  hash.load = await this.$store.dispatch('catalog/load', { reset: true });
91
109
 
110
+ if (this.$store.getters['management/schemaFor'](MANAGEMENT.CLUSTER)) {
111
+ hash.localCluster = await this.$store.dispatch('management/find', { type: MANAGEMENT.CLUSTER, id: 'local' });
112
+ }
113
+
92
114
  if (this.$store.getters['management/schemaFor'](CATALOG.OPERATION)) {
93
115
  hash.helmOps = await this.$store.dispatch('management/findAll', { type: CATALOG.OPERATION });
94
116
  }
@@ -100,7 +122,11 @@ export default {
100
122
  const res = await allHash(hash);
101
123
 
102
124
  this.plugins = res.plugins || [];
125
+ this.repos = res.repos || [];
103
126
  this.helmOps = res.helmOps || [];
127
+ this.kubeVersion = res.localCluster?.kubernetesVersionBase || [];
128
+
129
+ this.addExtensionReposBannerSetting = await fetchOrCreateSetting(this.$store, SETTING.ADD_EXTENSION_REPOS_BANNER_DISPLAY, 'true', true) || {};
104
130
 
105
131
  const c = this.$store.getters['catalog/rawCharts'];
106
132
 
@@ -108,7 +134,7 @@ export default {
108
134
 
109
135
  // If there are no plugins installed, default to the catalog view
110
136
  if (this.plugins.length === 0) {
111
- this.$refs.tabs?.select('available');
137
+ this.$refs.tabs?.select(TABS_VALUES.AVAILABLE);
112
138
  }
113
139
 
114
140
  this.loading = false;
@@ -121,6 +147,10 @@ export default {
121
147
  ...mapGetters({ uiErrors: 'uiplugins/errors' }),
122
148
  ...mapGetters({ theme: 'prefs/theme' }),
123
149
 
150
+ showAddReposBanner() {
151
+ return this.addExtensionReposBannerSetting?.value === 'true' && (!this.repos.find((r) => r.urlDisplay === UI_PLUGINS_REPO_URL) || !this.repos.find((r) => r.urlDisplay === UI_PLUGINS_PARTNERS_REPO_URL));
152
+ },
153
+
124
154
  applyDarkModeBg() {
125
155
  if (this.theme === 'dark') {
126
156
  return { 'dark-mode': true };
@@ -139,6 +169,13 @@ export default {
139
169
  enabled: true
140
170
  });
141
171
 
172
+ // Add link to add extensions repositories (Official, Partners, etc)
173
+ menuActions.push({
174
+ action: 'addRancherRepos',
175
+ label: this.t('plugins.addRancherRepos'),
176
+ enabled: true
177
+ });
178
+
142
179
  // Only show Manage Extension Catalogs when on main charts view
143
180
  if (!this.showCatalogList) {
144
181
  menuActions.push({
@@ -174,11 +211,11 @@ export default {
174
211
  const all = this.available;
175
212
 
176
213
  switch (this.view) {
177
- case 'installed':
214
+ case TABS_VALUES.INSTALLED:
178
215
  return all.filter((p) => !!p.installed || !!p.installing);
179
- case 'updates':
216
+ case TABS_VALUES.UPDATES:
180
217
  return this.updates;
181
- case 'available':
218
+ case TABS_VALUES.AVAILABLE:
182
219
  return all.filter((p) => !p.installed);
183
220
  default:
184
221
  return all;
@@ -223,24 +260,32 @@ export default {
223
260
  item.chart = chart;
224
261
 
225
262
  // Filter the versions available to install (plugins-api version and current dashboard version)
226
- item.installableVersions = item.versions.filter((version) => isSupportedChartVersion(version) && isChartVersionAvailableForInstall(version, this.rancherVersion));
263
+ item.installableVersions = item.versions.filter((version) => isSupportedChartVersion({ version, kubeVersion: this.kubeVersion }) && isChartVersionAvailableForInstall({
264
+ version, rancherVersion: this.rancherVersion, kubeVersion: this.kubeVersion
265
+ }));
227
266
 
228
267
  // add prop to version object if version is compatible with the current dashboard version
229
- item.versions = item.versions.map((version) => isChartVersionAvailableForInstall(version, this.rancherVersion, true));
268
+ item.versions = item.versions.map((version) => isChartVersionAvailableForInstall({
269
+ version, rancherVersion: this.rancherVersion, kubeVersion: this.kubeVersion
270
+ }, true));
230
271
 
231
272
  const latestCompatible = item.installableVersions?.[0];
232
- const latestNotCompatible = item.versions.find((version) => !version.isCompatibleWithUi);
273
+ const latestNotCompatible = item.versions.find((version) => !version.isCompatibleWithUi || !version.isCompatibleWithKubeVersion);
233
274
 
234
275
  if (latestCompatible) {
235
276
  item.displayVersion = latestCompatible.version;
236
277
  item.icon = latestCompatible.icon;
237
278
  } else {
238
279
  item.displayVersion = item.versions?.[0]?.version;
239
- item.icon = chart.icon || latestCompatible.annotations['catalog.cattle.io/ui-icon'];
280
+ item.icon = chart.icon || latestCompatible?.annotations?.['catalog.cattle.io/ui-icon'];
240
281
  }
241
282
 
242
283
  if (latestNotCompatible && item.installableVersions.length && isChartVersionHigher(latestNotCompatible.version, item.installableVersions?.[0].version)) {
243
- item.incompatibleDisclaimer = this.t('plugins.incompatibleDisclaimer', { version: latestNotCompatible.version, rancherVersion: latestNotCompatible.requiredUiVersion }, true);
284
+ if (!item.isCompatibleWithUi) {
285
+ item.incompatibleRancherVersion = this.t('plugins.incompatibleRancherVersion', { version: latestNotCompatible.version, rancherVersion: latestNotCompatible.requiredUiVersion }, true);
286
+ } else if (!item.isCompatibleWithKubeVersion) {
287
+ item.incompatibleKubeVersion = this.t('plugins.incompatibleKubeVersion', { version: latestNotCompatible.version, kubeVersion: latestNotCompatible.requiredKubeVersion }, true);
288
+ }
244
289
  }
245
290
 
246
291
  if (this.installing[item.name]) {
@@ -341,11 +386,25 @@ export default {
341
386
  }
342
387
  });
343
388
 
344
- // Clamp the lengths of the descriptions
345
389
  all.forEach((plugin) => {
390
+ // Clamp the lengths of the descriptions
346
391
  if (plugin.description && plugin.description.length > MAX_DESCRIPTION_LENGTH) {
347
392
  plugin.description = `${ plugin.description.substr(0, MAX_DESCRIPTION_LENGTH) } ...`;
348
393
  }
394
+
395
+ // check if kube version compatibility is met for installed extension
396
+ if (plugin.uiplugin) {
397
+ const versionInstalled = plugin.uiplugin.spec?.plugin?.version;
398
+ const versionInstalledData = plugin.versions.find((v) => v.version === versionInstalled);
399
+
400
+ if (versionInstalledData) {
401
+ const kubeVersionToCheck = versionInstalledData.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.KUBE_VERSION];
402
+
403
+ if (this.kubeVersion && !isSupportedChartVersion({ version: versionInstalledData, kubeVersion: this.kubeVersion })) {
404
+ plugin.installedError = this.t('plugins.currentInstalledVersionBlockedByKubeVersion', { kubeVersion: this.kubeVersion, kubeVersionToCheck }, true);
405
+ }
406
+ }
407
+ }
349
408
  });
350
409
 
351
410
  // Sort by name
@@ -412,7 +471,7 @@ export default {
412
471
  changes++;
413
472
  }
414
473
  if (isCustomImage) {
415
- this.refreshCharts();
474
+ this.refreshCharts(true);
416
475
  }
417
476
 
418
477
  this.updatePluginInstallStatus(plugin.name, false);
@@ -434,14 +493,16 @@ export default {
434
493
  },
435
494
 
436
495
  methods: {
437
- async refreshCharts() {
438
- await this.$store.dispatch('catalog/load', { reset: true });
496
+ async refreshCharts(forceChartsUpdate = false) {
497
+ // we might need to force the request, so that we know at all times if what's the status of the offical and partners repos (installed or not)
498
+ // tied to the SetupUIPlugins, AddExtensionRepos and RemoveUIPlugins checkboxes
499
+ await this.$store.dispatch('catalog/load', { reset: true, force: forceChartsUpdate });
439
500
  const c = this.$store.getters['catalog/rawCharts'];
440
501
 
441
502
  this.charts = Object.values(c);
442
503
  },
443
504
 
444
- async updateInstallStatus() {
505
+ async updateInstallStatus(forceChartsUpdate = false) {
445
506
  let hasService;
446
507
 
447
508
  try {
@@ -456,8 +517,8 @@ export default {
456
517
  hasService = false;
457
518
  }
458
519
 
459
- if (hasService) {
460
- this.refreshCharts();
520
+ if (hasService || forceChartsUpdate) {
521
+ this.refreshCharts(forceChartsUpdate);
461
522
  }
462
523
 
463
524
  Vue.set(this, 'hasService', hasService);
@@ -470,6 +531,7 @@ export default {
470
531
  },
471
532
 
472
533
  removePluginSupport() {
534
+ this.refreshCharts(true);
473
535
  this.$refs.removeUIPlugins.showDialog();
474
536
  },
475
537
 
@@ -478,6 +540,12 @@ export default {
478
540
  this.$refs.developerInstallDialog.showDialog();
479
541
  },
480
542
 
543
+ showAddExtensionReposDialog() {
544
+ this.updateAddReposSetting();
545
+ this.refreshCharts(true);
546
+ this.$refs.addExtensionReposDialog.showDialog();
547
+ },
548
+
481
549
  showCatalogLoadDialog() {
482
550
  this.$refs.catalogLoadDialog.showDialog();
483
551
  },
@@ -514,7 +582,7 @@ export default {
514
582
  didInstall(plugin) {
515
583
  if (plugin) {
516
584
  // Change the view to installed if we started installing a plugin
517
- this.$refs.tabs?.select('installed');
585
+ this.$refs.tabs?.select(TABS_VALUES.INSTALLED);
518
586
 
519
587
  // Clear the load error, if there was one previously
520
588
  this.$store.dispatch('uiplugins/setError', { name: plugin.name, error: false });
@@ -526,7 +594,6 @@ export default {
526
594
  },
527
595
 
528
596
  updatePluginInstallStatus(name, status) {
529
- // console.log(`UPDATING PLUGIN STATUS: ${ name } ${ status }`);
530
597
  Vue.set(this.installing, name, status);
531
598
  },
532
599
 
@@ -559,6 +626,13 @@ export default {
559
626
 
560
627
  manageExtensionView() {
561
628
  this.showCatalogList = !this.showCatalogList;
629
+ },
630
+
631
+ updateAddReposSetting() {
632
+ if (this.addExtensionReposBannerSetting?.value === 'true') {
633
+ this.addExtensionReposBannerSetting.value = 'false';
634
+ this.addExtensionReposBannerSetting.save();
635
+ }
562
636
  }
563
637
  }
564
638
  };
@@ -634,6 +708,7 @@ export default {
634
708
  @devLoad="showDeveloperLoadDialog"
635
709
  @removePluginSupport="removePluginSupport"
636
710
  @manageRepos="manageRepos"
711
+ @addRancherRepos="showAddExtensionReposDialog"
637
712
  @manageExtensionView="manageExtensionView"
638
713
  />
639
714
  </div>
@@ -655,7 +730,8 @@ export default {
655
730
  <SetupUIPlugins
656
731
  v-else
657
732
  class="setup-message"
658
- @done="updateInstallStatus"
733
+ @done="updateInstallStatus(true)"
734
+ @refreshCharts="refreshCharts(true)"
659
735
  />
660
736
  </div>
661
737
  <div v-else>
@@ -667,6 +743,22 @@ export default {
667
743
  />
668
744
  </template>
669
745
  <template v-else>
746
+ <Banner
747
+ v-if="showAddReposBanner"
748
+ color="warning"
749
+ class="add-repos-banner mb-20"
750
+ data-testid="extensions-new-repos-banner"
751
+ >
752
+ <span>{{ t('plugins.addRepos.banner', {}, true) }}</span>
753
+ <button
754
+ class="ml-10 btn btn-sm role-primary"
755
+ data-testid="extensions-new-repos-banner-action-btn"
756
+ @click="showAddExtensionReposDialog()"
757
+ >
758
+ {{ t('plugins.addRepos.bannerBtn') }}
759
+ </button>
760
+ </Banner>
761
+
670
762
  <Tabbed
671
763
  ref="tabs"
672
764
  :tabs-only="true"
@@ -674,25 +766,25 @@ export default {
674
766
  @changed="filterChanged"
675
767
  >
676
768
  <Tab
677
- name="installed"
769
+ :name="TABS_VALUES.INSTALLED"
678
770
  data-testid="extension-tab-installed"
679
771
  label-key="plugins.tabs.installed"
680
772
  :weight="20"
681
773
  />
682
774
  <Tab
683
- name="available"
775
+ :name="TABS_VALUES.AVAILABLE"
684
776
  data-testid="extension-tab-available"
685
777
  label-key="plugins.tabs.available"
686
778
  :weight="19"
687
779
  />
688
780
  <Tab
689
- name="updates"
781
+ :name="TABS_VALUES.UPDATES"
690
782
  label-key="plugins.tabs.updates"
691
783
  :weight="18"
692
784
  :badge="updates.length"
693
785
  />
694
786
  <Tab
695
- name="all"
787
+ :name="TABS_VALUES.ALL"
696
788
  label-key="plugins.tabs.all"
697
789
  :weight="17"
698
790
  />
@@ -767,9 +859,20 @@ export default {
767
859
  v-clean-tooltip="t('plugins.upgradeAvailable')"
768
860
  > -> {{ plugin.upgrade }}</span>
769
861
  <p
770
- v-if="plugin.incompatibleDisclaimer"
862
+ v-if="plugin.installedError"
863
+ class="incompatible"
864
+ >
865
+ <i class="icon icon-warning icon-lg text-warning" />
866
+ <span>{{ plugin.installedError }}</span>
867
+ </p>
868
+ <p
869
+ v-else-if="plugin.incompatibleRancherVersion"
771
870
  class="incompatible"
772
- >{{ plugin.incompatibleDisclaimer }}</p>
871
+ >{{ plugin.incompatibleRancherVersion }}</p>
872
+ <p
873
+ v-else-if="plugin.incompatibleKubeVersion"
874
+ class="incompatible"
875
+ >{{ plugin.incompatibleKubeVersion }}</p>
773
876
  </span>
774
877
  </div>
775
878
  <!-- plugin badges -->
@@ -863,7 +966,7 @@ export default {
863
966
  </button>
864
967
  </div>
865
968
  <div
866
- v-else
969
+ v-else-if="plugin.installableVersions && plugin.installableVersions.length"
867
970
  class="plugin-buttons"
868
971
  >
869
972
  <button
@@ -905,6 +1008,10 @@ export default {
905
1008
  ref="removeUIPlugins"
906
1009
  @done="updateInstallStatus"
907
1010
  />
1011
+ <AddExtensionRepos
1012
+ ref="addExtensionReposDialog"
1013
+ @done="updateInstallStatus(true)"
1014
+ />
908
1015
  </div>
909
1016
  </template>
910
1017
 
@@ -1130,6 +1237,15 @@ export default {
1130
1237
  }
1131
1238
  }
1132
1239
  }
1240
+ ::v-deep .checkbox-label {
1241
+ font-weight: normal !important;
1242
+ }
1243
+
1244
+ ::v-deep .add-repos-banner .banner__content {
1245
+ display: flex;
1246
+ justify-content: space-between;
1247
+ align-items: center;
1248
+ }
1133
1249
 
1134
1250
  @media screen and (max-width: 1200px) {
1135
1251
  .plugin-list {
@@ -121,8 +121,14 @@ export default {
121
121
  const y = event.srcElement.scrollTop - top - 20;
122
122
  let found = false;
123
123
 
124
+ if (!this.doc?.toc || this.doc.toc.length === 0) {
125
+ this.selected = null;
126
+
127
+ return;
128
+ }
129
+
124
130
  // Debounce scroll events
125
- this.doc.toc.forEach((item) => {
131
+ this.doc.toc?.forEach((item) => {
126
132
  const elm = document.getElementById(item.id);
127
133
  const tocElm = document.getElementById(`toc-link-${ item.id }`);
128
134
 
@@ -146,8 +152,8 @@ export default {
146
152
  }
147
153
  });
148
154
 
149
- if (!found) {
150
- const last = this.doc.toc[this.doc.toc.length - 1].id;
155
+ if (!found & this.doc.toc) {
156
+ const last = this.doc.toc[this.doc.toc.length - 1]?.id;
151
157
  const tocElm = document.getElementById(`toc-link-${ last }`);
152
158
 
153
159
  if ( tocElm ) {
package/pages/home.vue CHANGED
@@ -17,7 +17,7 @@ import { getVersionInfo, readReleaseNotes, markReadReleaseNotes, markSeenRelease
17
17
  import PageHeaderActions from '@shell/mixins/page-actions';
18
18
  import { getVendor } from '@shell/config/private-label';
19
19
  import { mapFeature, MULTI_CLUSTER } from '@shell/store/features';
20
- import { BLANK_CLUSTER } from '@shell/store';
20
+ import { BLANK_CLUSTER } from '@shell/store/store-types.js';
21
21
  import { filterOnlyKubernetesClusters, filterHiddenLocalCluster } from '@shell/utils/cluster';
22
22
 
23
23
  import { RESET_CARDS_ACTION, SET_LOGIN_ACTION } from '@shell/config/page-actions';
@@ -86,7 +86,7 @@ export default {
86
86
 
87
87
  computed: {
88
88
  ...mapState(['managementReady']),
89
- ...mapGetters(['currentCluster']),
89
+ ...mapGetters(['currentCluster', 'defaultClusterId', 'releaseNotesUrl']),
90
90
  mcm: mapFeature(MULTI_CLUSTER),
91
91
 
92
92
  provClusters() {
@@ -203,8 +203,6 @@ export default {
203
203
  ];
204
204
  },
205
205
 
206
- ...mapGetters(['currentCluster', 'defaultClusterId']),
207
-
208
206
  kubeClusters() {
209
207
  return filterHiddenLocalCluster(filterOnlyKubernetesClusters(this.provClusters || [], this.$store), this.$store);
210
208
  }
@@ -266,7 +264,6 @@ export default {
266
264
  showWhatsNew() {
267
265
  // Update the value, so that the message goes away
268
266
  markReadReleaseNotes(this.$store);
269
- this.$router.push({ name: 'docs-doc', params: { doc: 'whats-new' } });
270
267
  },
271
268
 
272
269
  showUserPrefs() {
@@ -323,7 +320,10 @@ export default {
323
320
  </div>
324
321
  <a
325
322
  class="hand"
326
- @click.prevent.stop="showWhatsNew"
323
+ :href="releaseNotesUrl"
324
+ target="_blank"
325
+ rel="noopener noreferrer nofollow"
326
+ @click.stop="showWhatsNew"
327
327
  ><span v-clean-html="t('landing.whatsNewLink')" /></a>
328
328
  </Banner>
329
329
  </div>
@@ -5,9 +5,9 @@ import CommunityLinks from '@shell/components/CommunityLinks';
5
5
  import { CATALOG, MANAGEMENT } from '@shell/config/types';
6
6
  import { getVendor } from '@shell/config/private-label';
7
7
  import { SETTING } from '@shell/config/settings';
8
- import { findBy } from '@shell/utils/array';
9
8
  import { addParam } from '@shell/utils/url';
10
9
  import { isRancherPrime } from '@shell/config/version';
10
+ import { hasCspAdapter } from 'mixins/brand';
11
11
  import { generateSupportLink } from '@shell/utils/version';
12
12
 
13
13
  export default {
@@ -71,7 +71,7 @@ export default {
71
71
 
72
72
  computed: {
73
73
  cspAdapter() {
74
- return findBy(this.apps, 'metadata.name', 'rancher-csp-adapter' );
74
+ return hasCspAdapter(this.apps);
75
75
  },
76
76
 
77
77
  hasSupport() {
@@ -93,11 +93,17 @@ export default {
93
93
  },
94
94
 
95
95
  supportConfigLink() {
96
- if (!this.cspAdapter) {
96
+ const adapter = this.cspAdapter;
97
+
98
+ if (!adapter) {
97
99
  return false;
98
100
  }
99
101
 
100
- return `${ this.serverUrl }/v1/generateSUSERancherSupportConfig`;
102
+ if (adapter.metadata.name === 'rancher-csp-billing-adapter') {
103
+ return `${ this.serverUrl }/v1/generateSUSERancherSupportConfig?usePAYG=true`;
104
+ } else {
105
+ return `${ this.serverUrl }/v1/generateSUSERancherSupportConfig`;
106
+ }
101
107
  },
102
108
 
103
109
  title() {
@@ -1,6 +1,6 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
- const contextFolders = ['chart', 'cloud-credential', 'content', 'detail', 'edit', 'list', 'machine-config', 'models', 'promptRemove', 'l10n', 'windowComponents', 'dialog', 'formatters', 'login'];
3
+ const contextFolders = ['chart', 'cloud-credential', 'content', 'detail', 'edit', 'layouts', 'list', 'machine-config', 'models', 'promptRemove', 'l10n', 'windowComponents', 'dialog', 'formatters', 'login'];
4
4
  const contextMap = contextFolders.reduce((map, obj) => {
5
5
  map[obj] = true;
6
6
 
@@ -24,7 +24,7 @@ function bind(el, { value, oldValue, modifiers }) {
24
24
  });
25
25
  }
26
26
 
27
- const VCleanTooltip = {
27
+ export const VCleanTooltip = {
28
28
  ...VTooltip,
29
29
  bind,
30
30
  update: bind,