@rancher/shell 2.0.0 → 2.0.2-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/translations/en-us.yaml +69 -29
  2. package/assets/translations/zh-hans.yaml +1 -0
  3. package/components/AlertTable.vue +17 -7
  4. package/components/AssignTo.vue +2 -0
  5. package/components/GrafanaDashboard.vue +6 -4
  6. package/components/PromptRemove.vue +1 -0
  7. package/components/Questions/index.vue +2 -2
  8. package/components/auth/RoleDetailEdit.vue +5 -4
  9. package/components/form/KeyValue.vue +1 -0
  10. package/components/form/Members/ClusterPermissionsEditor.vue +1 -1
  11. package/components/form/ProjectMemberEditor.vue +1 -1
  12. package/components/form/ResourceLabeledSelect.vue +11 -3
  13. package/components/form/Taints.vue +13 -7
  14. package/components/form/__tests__/Taints.test.ts +70 -0
  15. package/components/form/labeled-select-utils/labeled-select.utils.ts +1 -1
  16. package/components/nav/Header.vue +1 -1
  17. package/components/nav/TopLevelMenu.vue +1 -4
  18. package/config/pagination-table-headers.js +5 -4
  19. package/config/product/auth.js +1 -1
  20. package/config/roles.ts +34 -19
  21. package/config/router/navigation-guards/attempt-first-login.js +1 -1
  22. package/config/router/navigation-guards/authentication.js +1 -1
  23. package/config/router/navigation-guards/i18n.js +13 -0
  24. package/config/router/navigation-guards/index.js +3 -1
  25. package/config/router/navigation-guards/load-initial-settings.js +1 -1
  26. package/config/router/navigation-guards/runtime-extension-route.js +31 -0
  27. package/config/router/routes.js +10 -1
  28. package/config/uiplugins.js +130 -61
  29. package/core/plugin.ts +5 -0
  30. package/core/plugins.js +7 -1
  31. package/detail/__tests__/provisioning.cattle.io.cluster.test.ts +42 -0
  32. package/detail/provisioning.cattle.io.cluster.vue +4 -4
  33. package/dialog/DeactivateDriverDialog.vue +30 -11
  34. package/edit/auth/__tests__/oidc.test.ts +2 -2
  35. package/edit/provisioning.cattle.io.cluster/__tests__/Basics.test.ts +86 -13
  36. package/edit/provisioning.cattle.io.cluster/__tests__/DirectoryConfig.test.ts +3 -134
  37. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +209 -0
  38. package/edit/provisioning.cattle.io.cluster/index.vue +8 -4
  39. package/edit/provisioning.cattle.io.cluster/rke2.vue +115 -17
  40. package/edit/provisioning.cattle.io.cluster/tabs/AddOnAdditionalManifest.vue +50 -0
  41. package/edit/provisioning.cattle.io.cluster/tabs/AddOnConfig.vue +29 -64
  42. package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +42 -3
  43. package/edit/provisioning.cattle.io.cluster/tabs/DirectoryConfig.vue +22 -86
  44. package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs.vue +8 -2
  45. package/edit/provisioning.cattle.io.cluster/tabs/registries/__tests__/RegistryConfigs.test.ts +61 -0
  46. package/edit/token.vue +2 -1
  47. package/initialize/entry-helpers.js +4 -24
  48. package/list/management.cattle.io.feature.vue +4 -2
  49. package/middleware/authenticated.js +0 -19
  50. package/mixins/__tests__/chart.test.ts +4 -1
  51. package/mixins/auth-config.js +1 -1
  52. package/mixins/chart.js +30 -14
  53. package/models/__tests__/apps.deployment.test.ts +93 -0
  54. package/models/apps.deployment.js +18 -4
  55. package/models/driver.js +3 -2
  56. package/models/kontainerdriver.js +30 -13
  57. package/models/management.cattle.io.authconfig.js +2 -2
  58. package/models/management.cattle.io.cluster.js +2 -2
  59. package/models/management.cattle.io.user.js +3 -3
  60. package/models/nodedriver.js +35 -13
  61. package/models/provisioning.cattle.io.cluster.js +4 -0
  62. package/package.json +3 -2
  63. package/pages/404.vue +15 -0
  64. package/pages/auth/login.vue +4 -1
  65. package/pages/auth/setup.vue +4 -1
  66. package/pages/c/_cluster/apps/charts/install.vue +3 -2
  67. package/pages/c/_cluster/explorer/index.vue +5 -0
  68. package/pages/c/_cluster/manager/drivers/kontainerDriver/index.vue +0 -3
  69. package/pages/c/_cluster/manager/drivers/nodeDriver/index.vue +1 -4
  70. package/pages/c/_cluster/manager/jwt.authentication/index.vue +10 -4
  71. package/pages/c/_cluster/settings/performance.vue +2 -2
  72. package/pages/c/_cluster/uiplugins/InstallDialog.vue +2 -1
  73. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +7 -10
  74. package/pages/c/_cluster/uiplugins/index.vue +24 -16
  75. package/pages/home.vue +1 -13
  76. package/plugins/dashboard-store/actions.js +1 -1
  77. package/plugins/dashboard-store/getters.js +1 -1
  78. package/plugins/steve/__tests__/getters.test.ts +5 -5
  79. package/plugins/steve/getters.js +6 -4
  80. package/plugins/steve/hybrid-class.js +1 -5
  81. package/promptRemove/pod.vue +15 -7
  82. package/scripts/extension/helm/charts/ui-plugin-server/Chart.yaml +1 -1
  83. package/scripts/publish-shell.sh +54 -55
  84. package/scripts/test-plugins-build.sh +45 -39
  85. package/shell/types/shell/index.d.ts +2 -0
  86. package/store/auth.js +1 -1
  87. package/store/index.js +1 -1
  88. package/store/type-map.js +4 -2
  89. package/types/store/pagination.types.ts +1 -1
  90. package/utils/__tests__/kontainer.test.ts +89 -1
  91. package/utils/auth.js +1 -1
  92. package/utils/cluster.js +9 -0
  93. package/utils/kontainer.ts +5 -1
  94. package/utils/settings.ts +3 -1
  95. package/utils/version.js +2 -1
  96. package/creators/app/app.package.json +0 -13
  97. package/creators/app/files/.eslintignore +0 -16
  98. package/creators/app/files/.eslintrc.js +0 -173
  99. package/creators/app/files/.gitignore +0 -70
  100. package/creators/app/files/.gitlab-ci.yml +0 -14
  101. package/creators/app/files/.vscode/settings.json +0 -21
  102. package/creators/app/files/babel.config.js +0 -1
  103. package/creators/app/files/tsconfig.json +0 -42
  104. package/creators/app/files/vue.config.js +0 -6
  105. package/creators/app/init +0 -120
  106. package/creators/app/package.json +0 -25
  107. package/creators/pkg/files/.github/workflows/build-extension-catalog.yml +0 -24
  108. package/creators/pkg/files/.github/workflows/build-extension-charts.yml +0 -22
  109. package/creators/pkg/files/babel.config.js +0 -1
  110. package/creators/pkg/files/index.ts +0 -14
  111. package/creators/pkg/files/tsconfig.json +0 -53
  112. package/creators/pkg/files/vue.config.js +0 -1
  113. package/creators/pkg/init +0 -286
  114. package/creators/pkg/package.json +0 -19
  115. package/creators/pkg/pkg.package.json +0 -21
  116. package/creators/pkg/vue-shim.ts +0 -4
  117. package/creators/update/init +0 -56
  118. package/creators/update/package.json +0 -20
  119. package/creators/update/upgrade +0 -56
  120. package/rancher-components/components/Accordion/Accordion.test.ts +0 -45
  121. package/rancher-components/components/Accordion/Accordion.vue +0 -86
  122. package/rancher-components/components/Accordion/index.ts +0 -1
  123. package/rancher-components/components/BadgeState/BadgeState.test.ts +0 -12
  124. package/rancher-components/components/BadgeState/BadgeState.vue +0 -111
  125. package/rancher-components/components/BadgeState/index.ts +0 -1
  126. package/rancher-components/components/Banner/Banner.test.ts +0 -59
  127. package/rancher-components/components/Banner/Banner.vue +0 -244
  128. package/rancher-components/components/Banner/index.ts +0 -1
  129. package/rancher-components/components/Card/Card.test.ts +0 -37
  130. package/rancher-components/components/Card/Card.vue +0 -167
  131. package/rancher-components/components/Card/index.ts +0 -1
  132. package/rancher-components/components/Form/Checkbox/Checkbox.test.ts +0 -68
  133. package/rancher-components/components/Form/Checkbox/Checkbox.vue +0 -421
  134. package/rancher-components/components/Form/Checkbox/index.ts +0 -1
  135. package/rancher-components/components/Form/LabeledInput/LabeledInput.test.ts +0 -40
  136. package/rancher-components/components/Form/LabeledInput/LabeledInput.vue +0 -402
  137. package/rancher-components/components/Form/LabeledInput/index.ts +0 -1
  138. package/rancher-components/components/Form/Radio/RadioButton.test.ts +0 -33
  139. package/rancher-components/components/Form/Radio/RadioButton.vue +0 -293
  140. package/rancher-components/components/Form/Radio/RadioGroup.test.ts +0 -30
  141. package/rancher-components/components/Form/Radio/RadioGroup.vue +0 -259
  142. package/rancher-components/components/Form/Radio/index.ts +0 -2
  143. package/rancher-components/components/Form/TextArea/TextAreaAutoGrow.vue +0 -172
  144. package/rancher-components/components/Form/TextArea/index.ts +0 -1
  145. package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.test.ts +0 -94
  146. package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.vue +0 -152
  147. package/rancher-components/components/Form/ToggleSwitch/index.ts +0 -1
  148. package/rancher-components/components/Form/index.ts +0 -5
  149. package/rancher-components/components/LabeledTooltip/LabeledTooltip.vue +0 -156
  150. package/rancher-components/components/LabeledTooltip/index.ts +0 -1
  151. package/rancher-components/components/StringList/StringList.test.ts +0 -754
  152. package/rancher-components/components/StringList/StringList.vue +0 -650
  153. package/rancher-components/components/StringList/index.ts +0 -1
  154. package/types/shell/index.d.ts +0 -4585
@@ -15,10 +15,10 @@ export const configType = {
15
15
  local: '',
16
16
  github: 'oauth',
17
17
  keycloakoidc: 'oidc',
18
- oidc: 'oidc',
18
+ genericoidc: 'oidc',
19
19
  };
20
20
 
21
- const imageOverrides = { keycloakoidc: 'keycloak', oidc: 'openid' };
21
+ const imageOverrides = { keycloakoidc: 'keycloak', genericoidc: 'openid' };
22
22
 
23
23
  export default class AuthConfig extends SteveModel {
24
24
  get _availableActions() {
@@ -10,7 +10,7 @@ import { addParams } from '@shell/utils/url';
10
10
  import { isEmpty } from '@shell/utils/object';
11
11
  import { HARVESTER_NAME as HARVESTER } from '@shell/config/features';
12
12
  import { isHarvesterCluster } from '@shell/utils/cluster';
13
- import HybridModel from '@shell/plugins/steve/hybrid-class';
13
+ import SteveModel from '@shell/plugins/steve/steve-class';
14
14
  import { LINUX, WINDOWS } from '@shell/store/catalog';
15
15
  import { KONTAINER_TO_DRIVER } from './management.cattle.io.kontainerdriver';
16
16
  import { PINNED_CLUSTERS } from '@shell/store/prefs';
@@ -27,7 +27,7 @@ function findRelationship(verb, type, relationships = []) {
27
27
  return relationships.find((r) => r[from] === type)?.[id];
28
28
  }
29
29
 
30
- export default class MgmtCluster extends HybridModel {
30
+ export default class MgmtCluster extends SteveModel {
31
31
  get details() {
32
32
  const out = [
33
33
  {
@@ -105,7 +105,7 @@ export default class User extends HybridModel {
105
105
  * @returns {number}
106
106
  */
107
107
  get userLastLogin() {
108
- return this.metadata?.labels?.['cattle.io/last-login'] * 1000;
108
+ return this.metadata?.labels?.['cattle.io/last-login'] * 1000 || 0;
109
109
  }
110
110
 
111
111
  /**
@@ -113,7 +113,7 @@ export default class User extends HybridModel {
113
113
  * @returns {number}
114
114
  */
115
115
  get userDisabledIn() {
116
- return this.metadata?.labels?.['cattle.io/disable-after'] * 1000;
116
+ return this.metadata?.labels?.['cattle.io/disable-after'] * 1000 || 0;
117
117
  }
118
118
 
119
119
  /**
@@ -129,7 +129,7 @@ export default class User extends HybridModel {
129
129
  * @returns {number}
130
130
  */
131
131
  get userDeletedIn() {
132
- return this.metadata?.labels?.['cattle.io/delete-after'] * 1000;
132
+ return this.metadata?.labels?.['cattle.io/delete-after'] * 1000 || 0;
133
133
  }
134
134
 
135
135
  get state() {
@@ -1,5 +1,10 @@
1
1
  import Driver from '@shell/models/driver';
2
2
 
3
+ /**
4
+ * Overrides for spec.addCloudCredential
5
+ */
6
+ export const CLOUD_CREDENTIAL_OVERRIDE = { nutanix: true };
7
+
3
8
  export default class NodeDriver extends Driver {
4
9
  get doneRoute() {
5
10
  return 'c-cluster-manager-driver-nodedriver';
@@ -8,19 +13,21 @@ export default class NodeDriver extends Driver {
8
13
  get _availableActions() {
9
14
  const out = [
10
15
  {
11
- action: 'activate',
12
- label: 'Activate',
13
- icon: 'icon icon-play',
14
- bulkable: true,
15
- enabled: !!this.actions.activate && this.state === 'inactive',
16
+ action: 'activate',
17
+ label: this.t('action.activate'),
18
+ icon: 'icon icon-play',
19
+ bulkable: true,
20
+ bulkAction: 'activateBulk',
21
+ enabled: !!this.actions.activate && this.state === 'inactive',
16
22
  },
17
23
  {
18
- action: 'deactivate',
19
- label: 'Deactivate',
20
- icon: 'icon icon-pause',
21
- bulkable: true,
22
- enabled: !!this.actions.deactivate && this.state === 'active',
23
- weight: -1,
24
+ action: 'deactivate',
25
+ label: this.t('action.deactivate'),
26
+ icon: 'icon icon-pause',
27
+ bulkable: true,
28
+ bulkAction: 'deactivateBulk',
29
+ enabled: !!this.actions.deactivate && this.state === 'active',
30
+ weight: -1,
24
31
  },
25
32
  { divider: true },
26
33
  {
@@ -52,9 +59,16 @@ export default class NodeDriver extends Driver {
52
59
  return out;
53
60
  }
54
61
 
55
- deactivate() {
62
+ deactivate(resources = [this]) {
56
63
  this.$dispatch('promptModal', {
57
- componentProps: { url: `v3/nodeDrivers/${ escape(this.id) }?action=deactivate`, name: this.nameDisplay },
64
+ componentProps: { drivers: resources, driverType: 'nodeDrivers' },
65
+ component: 'DeactivateDriverDialog'
66
+ });
67
+ }
68
+
69
+ deactivateBulk(resources) {
70
+ this.$dispatch('promptModal', {
71
+ componentProps: { drivers: resources, driverType: 'nodeDrivers' },
58
72
  component: 'DeactivateDriverDialog'
59
73
  });
60
74
  }
@@ -65,4 +79,12 @@ export default class NodeDriver extends Driver {
65
79
  method: 'post',
66
80
  }, { root: true });
67
81
  }
82
+
83
+ async activateBulk(resources) {
84
+ await Promise.all(resources.map((resource) => this.$dispatch('rancher/request', {
85
+ url: `v3/nodeDrivers/${ escape(resource.id) }?action=activate`,
86
+ method: 'post',
87
+ }, { root: true }
88
+ )));
89
+ }
68
90
  }
@@ -986,4 +986,8 @@ export default class ProvCluster extends SteveModel {
986
986
  'spec.rkeConfig.machinePools.dynamicSchemaSpec',
987
987
  ];
988
988
  }
989
+
990
+ get description() {
991
+ return super.description || this.mgmt?.description;
992
+ }
989
993
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rancher/shell",
3
- "version": "2.0.0",
3
+ "version": "2.0.2-rc.1",
4
4
  "description": "Rancher Dashboard Shell",
5
5
  "repository": "https://github.com/rancherlabs/dashboard",
6
6
  "license": "Apache-2.0",
@@ -153,7 +153,8 @@
153
153
  "nth-check": ">=2.0.1",
154
154
  "follow-redirects": ">=1.14.7",
155
155
  "merge": ">=2.1.1",
156
- "semver": ">=7.5.2"
156
+ "semver": ">=7.5.2",
157
+ "glob": "7.2.3"
157
158
  },
158
159
  "nyc": {
159
160
  "extension": [
package/pages/404.vue ADDED
@@ -0,0 +1,15 @@
1
+ <script>
2
+ import Brand from '@shell/mixins/brand';
3
+
4
+ export default {
5
+ mixins: [Brand],
6
+ beforeMount() {
7
+ this.$store.commit('setError', { error: new Error('404: This page could not be found') });
8
+ this.$router.replace('/fail-whale');
9
+ }
10
+ };
11
+ </script>
12
+
13
+ <template>
14
+ <div class="dashboard-root" />
15
+ </template>
@@ -288,7 +288,10 @@ export default {
288
288
  </script>
289
289
 
290
290
  <template>
291
- <Loading v-if="$fetchState.pending" />
291
+ <Loading
292
+ v-if="$fetchState.pending"
293
+ mode="relative"
294
+ />
292
295
  <main
293
296
  v-else
294
297
  class="main-layout login"
@@ -276,7 +276,10 @@ export default {
276
276
  </script>
277
277
 
278
278
  <template>
279
- <Loading v-if="$fetchState.pending" />
279
+ <Loading
280
+ v-if="$fetchState.pending"
281
+ mode="relative"
282
+ />
280
283
  <form
281
284
  v-else
282
285
  class="setup"
@@ -37,6 +37,7 @@ import { findBy, insertAt } from '@shell/utils/array';
37
37
  import Vue from 'vue';
38
38
  import { saferDump } from '@shell/utils/create-yaml';
39
39
  import { LINUX, WINDOWS } from '@shell/store/catalog';
40
+ import { SETTING } from '@shell/config/settings';
40
41
 
41
42
  const VALUES_STATE = {
42
43
  FORM: 'FORM',
@@ -126,7 +127,7 @@ export default {
126
127
  try {
127
128
  this.serverUrlSetting = await this.$store.dispatch('management/find', {
128
129
  type: MANAGEMENT.SETTING,
129
- id: 'server-url'
130
+ id: SETTING.SERVER_URL,
130
131
  });
131
132
  } catch (e) {
132
133
  console.error('Unable to fetch `server-url` setting: ', e); // eslint-disable-line no-console
@@ -888,7 +889,7 @@ export default {
888
889
  // runtime will pull images from docker.io.
889
890
  const globalRegistry = await this.$store.dispatch('management/find', {
890
891
  type: MANAGEMENT.SETTING,
891
- id: 'system-default-registry'
892
+ id: SETTING.SYSTEM_DEFAULT_REGISTRY,
892
893
  });
893
894
 
894
895
  return globalRegistry.value;
@@ -48,6 +48,7 @@ import { NAME as EXPLORER } from '@shell/config/product/explorer';
48
48
  import TabTitle from '@shell/components/TabTitle';
49
49
  import { STATES_ENUM } from '@shell/plugins/dashboard-store/resource-class';
50
50
  import capitalize from 'lodash/capitalize';
51
+ import paginationUtils from '@shell/utils/pagination-utils';
51
52
 
52
53
  export const RESOURCES = [NAMESPACE, INGRESS, PV, WORKLOAD_TYPES.DEPLOYMENT, WORKLOAD_TYPES.STATEFUL_SET, WORKLOAD_TYPES.JOB, WORKLOAD_TYPES.DAEMON_SET, SERVICE];
53
54
 
@@ -122,6 +123,8 @@ export default {
122
123
  this.loadAgents();
123
124
  }
124
125
  }
126
+
127
+ this.showCertificates = !paginationUtils.isSteveCacheEnabled({ rootGetters: this.$store.getters });
125
128
  },
126
129
 
127
130
  data() {
@@ -156,6 +159,7 @@ export default {
156
159
  clusterCounts,
157
160
  selectedTab: 'cluster-events',
158
161
  extensionCards: getApplicableExtensionEnhancements(this, ExtensionPoint.CARD, CardLocation.CLUSTER_DASHBOARD_CARD, this.$route),
162
+ showCertificates: false,
159
163
  };
160
164
  },
161
165
 
@@ -739,6 +743,7 @@ export default {
739
743
  <AlertTable v-if="selectedTab === 'cluster-alerts'" />
740
744
  </Tab>
741
745
  <Tab
746
+ v-if="showCertificates"
742
747
  name="cluster-certs"
743
748
  :label="t('clusterIndexPage.sections.certs.label')"
744
749
  :weight="1"
@@ -44,9 +44,6 @@ export default {
44
44
  buttonDone(false);
45
45
  }
46
46
  }
47
- },
48
- mounted() {
49
- window.c = this;
50
47
  }
51
48
  };
52
49
  </script>
@@ -26,10 +26,7 @@ export default {
26
26
  rows() {
27
27
  return this.allDrivers || [];
28
28
  },
29
- },
30
- mounted() {
31
- window.c = this;
32
- },
29
+ }
33
30
  };
34
31
  </script>
35
32
 
@@ -22,7 +22,7 @@ export default {
22
22
  async fetch() {
23
23
  const hash = {
24
24
  mgmtClusters: this.$fetchType(MANAGEMENT.CLUSTER),
25
- proxyConfig: this.$fetchType(MANAGEMENT.CLUSTER_PROXY_CONFIG)
25
+ proxyConfig: this.$store.dispatch('management/findAll', { type: MANAGEMENT.CLUSTER_PROXY_CONFIG, opt: { omitExcludeFields: ['metadata.managedFields'] } })
26
26
  };
27
27
 
28
28
  const res = await allHash(hash);
@@ -150,7 +150,11 @@ export default {
150
150
 
151
151
  const value = config?.enabled || '';
152
152
  const configName = config?.metadata?.name || '';
153
- const updatedOn = value ? config?.metadata?.creationTimestamp : '';
153
+ let updatedOn = '';
154
+
155
+ if (value) {
156
+ updatedOn = config?.metadata?.managedFields?.find((field) => field.operation === 'Update')?.time || '';
157
+ }
154
158
  const stateBackground = value ? colorForState(STATES_ENUM.ACTIVE).replace('text', 'bg') : colorForState(STATES_ENUM.INFO).replace('text', 'bg');
155
159
  const stateLabel = value ? this.t('jwt.state.enabled') : this.t('jwt.state.disabled');
156
160
  const creationTimestamp = cluster.metadata.creationTimestamp;
@@ -159,7 +163,7 @@ export default {
159
163
  if (!configName) {
160
164
  const clusterProxyConfig = await this.$store.dispatch('management/create', {
161
165
  enabled: true,
162
- metadata: { namespace: id, generateName: 'cluster-proxy-config-' },
166
+ metadata: { namespace: id, name: 'clusterproxyconfig' },
163
167
  });
164
168
 
165
169
  return clusterProxyConfig.save({ url: 'v1/management.cattle.io.clusterproxyconfigs', method: 'POST' });
@@ -170,7 +174,9 @@ export default {
170
174
  }
171
175
  };
172
176
  const disable = async() => {
173
- return config.remove();
177
+ config.enabled = false;
178
+
179
+ return config.save();
174
180
  };
175
181
 
176
182
  rows.push({
@@ -61,7 +61,7 @@ export default {
61
61
 
62
62
  data() {
63
63
  return {
64
- uiPerfSetting: DEFAULT_PERF_SETTING,
64
+ uiPerfSetting: null,
65
65
  authUserTTL: null,
66
66
  bannerVal: {},
67
67
  value: {},
@@ -161,7 +161,7 @@ export default {
161
161
  return;
162
162
  }
163
163
 
164
- // We're enabling a preference. Are there any incomaptible preferences?
164
+ // We're enabling a preference. Are there any incompatible preferences?
165
165
  if ((incompatible[property] || []).every((p) => !this.value[p].enabled)) {
166
166
  // No, just set and exit
167
167
  this.value[property].enabled = true;
@@ -6,6 +6,7 @@ import { CATALOG, MANAGEMENT } from '@shell/config/types';
6
6
  import { CATALOG as CATALOG_ANNOTATIONS } from '@shell/config/labels-annotations';
7
7
  import { UI_PLUGIN_NAMESPACE } from '@shell/config/uiplugins';
8
8
  import Banner from '@components/Banner/Banner.vue';
9
+ import { SETTING } from '@shell/config/settings';
9
10
 
10
11
  // Note: This dialog handles installation and update of a plugin
11
12
 
@@ -20,7 +21,7 @@ export default {
20
21
  async fetch() {
21
22
  this.defaultRegistrySetting = await this.$store.dispatch('management/find', {
22
23
  type: MANAGEMENT.SETTING,
23
- id: 'system-default-registry'
24
+ id: SETTING.SYSTEM_DEFAULT_REGISTRY,
24
25
  });
25
26
  },
26
27
 
@@ -5,6 +5,7 @@ import { Banner } from '@components/Banner';
5
5
  import LazyImage from '@shell/components/LazyImage';
6
6
  import { MANAGEMENT } from '@shell/config/types';
7
7
  import { SETTING } from '@shell/config/settings';
8
+ import { EXTENSIONS_INCOMPATIBILITY_TYPES, UI_PLUGIN_HOST_APP } from '@shell/config/uiplugins';
8
9
 
9
10
  export default {
10
11
  async fetch() {
@@ -65,10 +66,9 @@ export default {
65
66
  async loadPluginVersionInfo(version) {
66
67
  const versionName = version || this.info.displayVersion;
67
68
 
68
- const isVersionNotCompatibleWithUi = this.info.versions?.find((v) => v.version === versionName && !v.isCompatibleWithUi);
69
- const isVersionNotCompatibleWithKubeVersion = this.info.versions?.find((v) => v.version === versionName && !v.isCompatibleWithKubeVersion);
69
+ const isVersionNotCompatible = this.info.versions?.find((v) => v.version === versionName && !v.isVersionCompatible);
70
70
 
71
- if (!this.info.chart || isVersionNotCompatibleWithUi || isVersionNotCompatibleWithKubeVersion) {
71
+ if (!this.info.chart || isVersionNotCompatible) {
72
72
  return;
73
73
  }
74
74
 
@@ -107,18 +107,15 @@ export default {
107
107
  },
108
108
 
109
109
  handleVersionBtnTooltip(version) {
110
- if (version.requiredUiVersion) {
111
- return this.t('plugins.info.requiresRancherVersion', { version: version.requiredUiVersion });
112
- }
113
- if (version.requiredKubeVersion) {
114
- return this.t('plugins.info.requiresKubeVersion', { version: version.requiredKubeVersion });
110
+ if (!version.isVersionCompatible && Object.keys(version.versionIncompatibilityData).length) {
111
+ return this.t(version.versionIncompatibilityData?.tooltipKey, { required: version.versionIncompatibilityData?.type === EXTENSIONS_INCOMPATIBILITY_TYPES.HOST ? UI_PLUGIN_HOST_APP : version.versionIncompatibilityData?.required });
115
112
  }
116
113
 
117
114
  return '';
118
115
  },
119
116
 
120
117
  handleVersionBtnClass(version) {
121
- return { 'version-active': version.version === this.infoVersion, disabled: !version.isCompatibleWithUi || !version.isCompatibleWithKubeVersion };
118
+ return { 'version-active': version.version === this.infoVersion, disabled: !version.isVersionCompatible };
122
119
  }
123
120
  }
124
121
  };
@@ -219,7 +216,7 @@ export default {
219
216
  <div class="plugin-versions mb-10">
220
217
  <div
221
218
  v-for="v in info.versions"
222
- :key="v.version"
219
+ :key="`${v.name}-${v.version}`"
223
220
  >
224
221
  <a
225
222
  v-clean-tooltip="handleVersionBtnTooltip(v)"
@@ -31,12 +31,13 @@ import {
31
31
  uiPluginAnnotation,
32
32
  uiPluginHasAnnotation,
33
33
  isSupportedChartVersion,
34
- isChartVersionAvailableForInstall,
35
34
  isChartVersionHigher,
36
35
  UI_PLUGIN_NAMESPACE,
37
36
  UI_PLUGIN_CHART_ANNOTATIONS,
38
37
  UI_PLUGINS_REPO_URL,
39
- UI_PLUGINS_PARTNERS_REPO_URL
38
+ UI_PLUGINS_PARTNERS_REPO_URL,
39
+ UI_PLUGIN_HOST_APP,
40
+ EXTENSIONS_INCOMPATIBILITY_TYPES
40
41
  } from '@shell/config/uiplugins';
41
42
  import TabTitle from '@shell/components/TabTitle';
42
43
 
@@ -258,19 +259,20 @@ export default {
258
259
 
259
260
  item.versions = [...chart.versions];
260
261
  item.chart = chart;
262
+ item.incompatibilityMessage = '';
261
263
 
262
264
  // Filter the versions available to install (plugins-api version and current dashboard version)
263
- item.installableVersions = item.versions.filter((version) => isSupportedChartVersion({ version, kubeVersion: this.kubeVersion }) && isChartVersionAvailableForInstall({
265
+ item.installableVersions = item.versions.filter((version) => isSupportedChartVersion({
264
266
  version, rancherVersion: this.rancherVersion, kubeVersion: this.kubeVersion
265
267
  }));
266
268
 
267
269
  // add prop to version object if version is compatible with the current dashboard version
268
- item.versions = item.versions.map((version) => isChartVersionAvailableForInstall({
270
+ item.versions = item.versions.map((version) => isSupportedChartVersion({
269
271
  version, rancherVersion: this.rancherVersion, kubeVersion: this.kubeVersion
270
272
  }, true));
271
273
 
272
274
  const latestCompatible = item.installableVersions?.[0];
273
- const latestNotCompatible = item.versions.find((version) => !version.isCompatibleWithUi || !version.isCompatibleWithKubeVersion);
275
+ const latestNotCompatible = item.versions.find((version) => !version.isVersionCompatible);
274
276
 
275
277
  if (latestCompatible) {
276
278
  item.displayVersion = latestCompatible.version;
@@ -280,11 +282,20 @@ export default {
280
282
  item.icon = chart.icon || latestCompatible?.annotations?.['catalog.cattle.io/ui-icon'];
281
283
  }
282
284
 
285
+ // add message of extension card if there's a newer version of the extension, but it's not available to be installed
283
286
  if (latestNotCompatible && item.installableVersions.length && isChartVersionHigher(latestNotCompatible.version, item.installableVersions?.[0].version)) {
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);
287
+ switch (latestNotCompatible.versionIncompatibilityData?.type) {
288
+ case EXTENSIONS_INCOMPATIBILITY_TYPES.HOST:
289
+ item.incompatibilityMessage = this.t(latestNotCompatible.versionIncompatibilityData?.cardMessageKey, {
290
+ version: latestNotCompatible.version, required: latestNotCompatible.versionIncompatibilityData?.required, mainHost: UI_PLUGIN_HOST_APP
291
+ }, true);
292
+ break;
293
+ default:
294
+ item.incompatibilityMessage = this.t(latestNotCompatible.versionIncompatibilityData?.cardMessageKey, {
295
+ version: latestNotCompatible.version,
296
+ required: latestNotCompatible.versionIncompatibilityData?.required
297
+ }, true);
298
+ break;
288
299
  }
289
300
  }
290
301
 
@@ -398,8 +409,9 @@ export default {
398
409
 
399
410
  if (versionInstalledData) {
400
411
  const kubeVersionToCheck = versionInstalledData.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.KUBE_VERSION];
412
+ const versionSupportedData = isSupportedChartVersion({ version: versionInstalledData, kubeVersion: this.kubeVersion });
401
413
 
402
- if (this.kubeVersion && !isSupportedChartVersion({ version: versionInstalledData, kubeVersion: this.kubeVersion })) {
414
+ if (this.kubeVersion && !versionSupportedData.isVersionCompatible && versionSupportedData.versionIncompatibilityData?.type === EXTENSIONS_INCOMPATIBILITY_TYPES.KUBE) {
403
415
  plugin.installedError = this.t('plugins.currentInstalledVersionBlockedByKubeVersion', { kubeVersion: this.kubeVersion, kubeVersionToCheck }, true);
404
416
  }
405
417
  }
@@ -848,13 +860,9 @@ export default {
848
860
  <span>{{ plugin.installedError }}</span>
849
861
  </p>
850
862
  <p
851
- v-else-if="plugin.incompatibleRancherVersion"
863
+ v-else-if="plugin.incompatibilityMessage"
852
864
  class="incompatible"
853
- >{{ plugin.incompatibleRancherVersion }}</p>
854
- <p
855
- v-else-if="plugin.incompatibleKubeVersion"
856
- class="incompatible"
857
- >{{ plugin.incompatibleKubeVersion }}</p>
865
+ >{{ plugin.incompatibilityMessage }}</p>
858
866
  </span>
859
867
  </div>
860
868
  <!-- plugin badges -->
package/pages/home.vue CHANGED
@@ -91,10 +91,6 @@ export default {
91
91
  ...mapGetters(['currentCluster', 'defaultClusterId', 'releaseNotesUrl']),
92
92
  mcm: mapFeature(MULTI_CLUSTER),
93
93
 
94
- mgmtClusters() {
95
- return this.$store.getters['management/all'](MANAGEMENT.CLUSTER);
96
- },
97
-
98
94
  provClusters() {
99
95
  return this.$store.getters['management/all'](CAPI.RANCHER_CLUSTER);
100
96
  },
@@ -211,15 +207,7 @@ export default {
211
207
  },
212
208
 
213
209
  kubeClusters() {
214
- const filteredClusters = filterHiddenLocalCluster(filterOnlyKubernetesClusters(this.provClusters || [], this.$store), this.$store);
215
-
216
- return filteredClusters.map((provCluster) => {
217
- const mgmtCluster = this.mgmtClusters?.find((c) => provCluster.mgmt?.id === c.id);
218
-
219
- provCluster.description = provCluster.description || mgmtCluster?.description;
220
-
221
- return provCluster;
222
- });
210
+ return filterHiddenLocalCluster(filterOnlyKubernetesClusters(this.provClusters || [], this.$store), this.$store);
223
211
  }
224
212
  },
225
213
 
@@ -419,7 +419,7 @@ export default {
419
419
  },
420
420
  result: {
421
421
  count: out.count,
422
- pages: out.pages,
422
+ pages: out.pages || Math.ceil(out.count / (opt.pagination.pageSize || Number.MAX_SAFE_INTEGER)),
423
423
  timestamp: new Date().getTime()
424
424
  }
425
425
  } : undefined,
@@ -429,7 +429,7 @@ export default {
429
429
  };
430
430
  }
431
431
 
432
- const namespaces = _typeObj?.namespaced ? Object.keys(rootGetters.activeNamespaceCache || {}) : [];
432
+ const namespaces = _typeObj?.namespaced && !rootGetters.isAllNamespaces ? Object.keys(rootGetters.activeNamespaceCache || {}) : [];
433
433
 
434
434
  return matchingCounts(_typeObj, namespaces.length ? namespaces : null);
435
435
  },
@@ -109,13 +109,13 @@ describe('steve: getters:', () => {
109
109
  it('returns a string with a labelSelector and filter, and formatted for steve if the url starts with "/v1"', () => {
110
110
  expect(urlOptionsGetter('/v1/foo', { labelSelector: 'a=b', filter: { bar: 'baz', far: 'faz' } })).toBe('/v1/foo?labelSelector=a=b&filter=bar=baz&far=faz&exclude=metadata.managedFields');
111
111
  });
112
- it('returns a string with an exclude statement for "bar" and "metadata.managedFields" if excludeFields is a single element array with the string "bar" and the url starts with "/v1/"', () => {
113
- expect(urlOptionsGetter('/v1/foo', { excludeFields: ['bar'] })).toBe('/v1/foo?exclude=bar&exclude=metadata.managedFields');
112
+ it('returns a string with an exclude statement for "bar" if excludeFields is a single element array with the string "bar" and the url starts with "/v1/"', () => {
113
+ expect(urlOptionsGetter('/v1/foo', { excludeFields: ['bar'] })).toBe('/v1/foo?exclude=bar');
114
114
  });
115
- it('returns a string without an exclude statement if excludeFields is but the url does not start with "/v1/"', () => {
116
- expect(urlOptionsGetter('foo', { excludeFields: ['bar'] })).toBe('foo');
115
+ it('returns a string without an exclude statement for "managedFields" if omitExcludeFields includes it and the url starts with "/v1/"', () => {
116
+ expect(urlOptionsGetter('/v1/foo', { omitExcludeFields: ['metadata.managedFields'] })).toBe('/v1/foo?');
117
117
  });
118
- it('returns a string without an exclude statement if excludeFields is an array but the URL doesn\'t include the "/v1/ string"', () => {
118
+ it('returns a string without an exclude statement if excludeFields is set but the url does not start with "/v1/"', () => {
119
119
  expect(urlOptionsGetter('foo', { excludeFields: ['bar'] })).toBe('foo');
120
120
  });
121
121
  it('returns a string with a limit applied if a limit is provided', () => {
@@ -119,11 +119,13 @@ export default {
119
119
  // excludeFields should be an array of strings representing the paths of the fields to exclude
120
120
  // only works on Steve but is ignored without error by Norman
121
121
  if (isSteve) {
122
- if (Array.isArray(opt?.excludeFields)) {
123
- opt.excludeFields = [...opt.excludeFields, 'metadata.managedFields'];
124
- } else {
125
- opt.excludeFields = ['metadata.managedFields'];
122
+ if (!Array.isArray(opt?.excludeFields)) {
123
+ const excludeFields = ['metadata.managedFields'];
124
+
125
+ // for some resources, we might want to include fields, excluded by default.
126
+ opt.excludeFields = Array.isArray(opt?.omitExcludeFields) ? excludeFields.filter((f) => !f.includes(opt.omitExcludeFields)) : excludeFields;
126
127
  }
128
+
127
129
  const excludeParamsString = opt.excludeFields.map((field) => `exclude=${ field }`).join('&');
128
130
 
129
131
  url += `${ url.includes('?') ? '&' : '?' }${ excludeParamsString }`;
@@ -1,4 +1,4 @@
1
- import { ANNOTATIONS_TO_IGNORE_REGEX, LABELS_TO_IGNORE_REGEX, DESCRIPTION } from '@shell/config/labels-annotations';
1
+ import { ANNOTATIONS_TO_IGNORE_REGEX, LABELS_TO_IGNORE_REGEX } from '@shell/config/labels-annotations';
2
2
  import omitBy from 'lodash/omitBy';
3
3
  import pickBy from 'lodash/pickBy';
4
4
  import Vue from 'vue';
@@ -100,8 +100,4 @@ export default class HybridModel extends Resource {
100
100
  get state() {
101
101
  return this.stateObj?.name || 'unknown';
102
102
  }
103
-
104
- get description() {
105
- return this.metadata?.annotations?.[DESCRIPTION] || this.spec?.description || this._description;
106
- }
107
103
  }