@rancher/shell 3.0.2-rc.5 → 3.0.2

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 (219) hide show
  1. package/assets/images/providers/nutanix.svg +12 -1
  2. package/assets/styles/base/_basic.scss +2 -1
  3. package/assets/styles/base/_helpers.scss +4 -0
  4. package/assets/styles/base/_variables.scss +2 -0
  5. package/assets/styles/global/_labeled-input.scss +5 -13
  6. package/assets/styles/global/_layout.scss +4 -1
  7. package/assets/styles/global/_select.scss +5 -0
  8. package/assets/styles/themes/_dark.scss +1 -3
  9. package/assets/styles/themes/_light.scss +5 -1
  10. package/assets/translations/en-us.yaml +130 -23
  11. package/assets/translations/zh-hans.yaml +0 -3
  12. package/cloud-credential/azure.vue +1 -1
  13. package/components/ActionMenuShell.vue +105 -0
  14. package/components/AppModal.vue +2 -2
  15. package/components/AsyncButton.vue +2 -0
  16. package/components/ButtonGroup.vue +9 -2
  17. package/components/ClusterBadge.vue +1 -0
  18. package/components/ClusterIconMenu.vue +3 -0
  19. package/components/ClusterProviderIcon.vue +14 -1
  20. package/components/CodeMirror.vue +96 -5
  21. package/components/Collapse.vue +16 -3
  22. package/components/CruResource.vue +9 -0
  23. package/components/CruResourceFooter.vue +1 -1
  24. package/components/ExplorerMembers.vue +2 -1
  25. package/components/FixedBanner.vue +19 -12
  26. package/components/Import.vue +14 -1
  27. package/components/LandingPagePreference.vue +4 -2
  28. package/components/PodSecurityAdmission.vue +8 -6
  29. package/components/PromptChangePassword.vue +1 -0
  30. package/components/PromptRemove.vue +23 -21
  31. package/components/ResourceDetail/Masthead.vue +30 -11
  32. package/components/ResourceDetail/__tests__/Masthead.test.ts +61 -0
  33. package/components/ResourceDetail/index.vue +6 -0
  34. package/components/ResourceTable.vue +6 -1
  35. package/components/ResourceYaml.vue +1 -0
  36. package/components/Setting.vue +115 -0
  37. package/components/SortableTable/THead.vue +2 -0
  38. package/components/SortableTable/index.vue +7 -12
  39. package/components/StatusBadge.vue +71 -0
  40. package/components/Tabbed/index.vue +16 -15
  41. package/components/Wizard.vue +108 -104
  42. package/components/YamlEditor.vue +12 -2
  43. package/components/__tests__/Collapse.test.ts +2 -2
  44. package/components/__tests__/FixedBanner.test.ts +3 -3
  45. package/components/auth/Principal.vue +29 -17
  46. package/components/auth/__tests__/Principal.test.ts +40 -0
  47. package/components/auth/login/ldap.vue +7 -0
  48. package/components/fleet/FleetBundles.vue +1 -1
  49. package/components/fleet/FleetRepos.vue +1 -1
  50. package/components/fleet/FleetResources.vue +0 -2
  51. package/components/fleet/FleetSummary.vue +60 -65
  52. package/components/fleet/ForceDirectedTreeChart/index.vue +5 -1
  53. package/components/fleet/__tests__/FleetSummary.test.ts +49 -9
  54. package/components/form/ArrayList.vue +6 -2
  55. package/components/form/ColorInput.vue +1 -0
  56. package/components/form/KeyValue.vue +11 -12
  57. package/components/form/LabeledSelect.vue +15 -3
  58. package/components/form/Labels.vue +8 -1
  59. package/components/form/Members/MembershipEditor.vue +230 -222
  60. package/components/form/Members/__tests__/MembershipEditor.test.ts +62 -0
  61. package/components/form/Password.vue +3 -0
  62. package/components/form/ProjectMemberEditor.vue +6 -3
  63. package/components/form/ResourceTabs/index.vue +15 -13
  64. package/components/form/SSHKnownHosts/KnownHostsEditDialog.vue +5 -4
  65. package/components/form/SchedulingCustomization.vue +85 -0
  66. package/components/form/Select.vue +3 -2
  67. package/components/form/SelectOrCreateAuthSecret.vue +2 -1
  68. package/components/form/UnitInput.vue +3 -4
  69. package/components/form/__tests__/ArrayList.test.ts +9 -6
  70. package/components/form/__tests__/LabeledSelect.test.ts +37 -0
  71. package/components/form/__tests__/SelectOrCreateAuthSecret.test.ts +34 -0
  72. package/components/form/__tests__/UnitInput.test.ts +4 -5
  73. package/components/formatter/LiveDate.vue +3 -1
  74. package/components/formatter/ServiceType.vue +12 -4
  75. package/components/formatter/WorkloadHealthScale.vue +2 -1
  76. package/components/nav/Header.vue +35 -2
  77. package/components/nav/HeaderPageActionMenu.vue +11 -40
  78. package/components/nav/Jump.vue +8 -2
  79. package/components/nav/NamespaceFilter.vue +5 -4
  80. package/components/nav/Pinned.vue +1 -1
  81. package/components/nav/TopLevelMenu.helper.ts +5 -5
  82. package/components/nav/TopLevelMenu.vue +1 -12
  83. package/components/nav/WindowManager/ContainerLogs.vue +96 -58
  84. package/components/nav/WindowManager/ContainerShell.vue +99 -18
  85. package/components/nav/WindowManager/index.vue +74 -6
  86. package/components/nav/__tests__/TopLevelMenu.test.ts +0 -40
  87. package/components/templates/default.vue +2 -47
  88. package/config/features.js +1 -0
  89. package/config/labels-annotations.js +11 -1
  90. package/config/router/navigation-guards/index.js +2 -1
  91. package/config/router/navigation-guards/record-last-route.js +24 -0
  92. package/config/settings.ts +66 -98
  93. package/config/version.js +1 -1
  94. package/core/types-provisioning.ts +7 -0
  95. package/detail/fleet.cattle.io.bundle.vue +7 -0
  96. package/detail/fleet.cattle.io.cluster.vue +0 -3
  97. package/detail/fleet.cattle.io.gitrepo.vue +8 -15
  98. package/detail/provisioning.cattle.io.cluster.vue +8 -2
  99. package/dialog/DeactivateDriverDialog.vue +5 -5
  100. package/dialog/GitRepoForceUpdateDialog.vue +132 -0
  101. package/directives/strip-html-aria-label.js +19 -0
  102. package/edit/__tests__/cis.cattle.io.clusterscan.test.ts +87 -0
  103. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +217 -37
  104. package/edit/auth/__tests__/oidc.test.ts +60 -12
  105. package/edit/auth/ldap/__tests__/config.test.ts +40 -0
  106. package/edit/auth/ldap/config.vue +67 -89
  107. package/edit/auth/oidc.vue +16 -2
  108. package/edit/catalog.cattle.io.clusterrepo.vue +12 -8
  109. package/edit/cis.cattle.io.clusterscan.vue +13 -1
  110. package/edit/fleet.cattle.io.gitrepo.vue +198 -72
  111. package/edit/logging-flow/Match.vue +0 -21
  112. package/edit/management.cattle.io.project.vue +1 -1
  113. package/edit/monitoring.coreos.com.prometheusrule/AlertingRule.vue +10 -3
  114. package/edit/monitoring.coreos.com.prometheusrule/RecordingRule.vue +5 -1
  115. package/edit/monitoring.coreos.com.prometheusrule/index.vue +5 -2
  116. package/edit/provisioning.cattle.io.cluster/CustomCommand.vue +8 -1
  117. package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +2 -0
  118. package/edit/provisioning.cattle.io.cluster/__tests__/Advanced.test.ts +0 -2
  119. package/edit/provisioning.cattle.io.cluster/__tests__/CustomCommand.test.ts +55 -15
  120. package/edit/provisioning.cattle.io.cluster/index.vue +28 -30
  121. package/edit/provisioning.cattle.io.cluster/rke2.vue +64 -13
  122. package/edit/provisioning.cattle.io.cluster/tabs/AgentConfiguration.vue +37 -2
  123. package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +3 -2
  124. package/edit/resources.cattle.io.backup.vue +150 -15
  125. package/edit/secret/__tests__/ssh.test.ts +79 -0
  126. package/edit/secret/ssh.vue +7 -1
  127. package/edit/service.vue +0 -3
  128. package/edit/workload/Job.vue +8 -8
  129. package/edit/workload/__tests__/Job.test.ts +0 -1
  130. package/edit/workload/index.vue +3 -1
  131. package/initialize/install-directives.js +2 -0
  132. package/initialize/install-plugins.js +6 -1
  133. package/list/catalog.cattle.io.app.vue +21 -4
  134. package/list/fleet.cattle.io.bundle.vue +1 -1
  135. package/list/management.cattle.io.setting.vue +34 -132
  136. package/list/provisioning.cattle.io.cluster.vue +11 -3
  137. package/machine-config/vmwarevsphere.vue +15 -8
  138. package/mixins/__tests__/auth-config.test.ts +74 -0
  139. package/mixins/__tests__/chart.test.ts +5 -4
  140. package/mixins/__tests__/create-edit-view.test.ts +38 -0
  141. package/mixins/auth-config.js +8 -0
  142. package/mixins/chart.js +2 -2
  143. package/mixins/create-edit-view/impl.js +4 -1
  144. package/mixins/vue-select-overrides.js +10 -0
  145. package/models/__tests__/catalog.cattle.io.app.test.ts +148 -0
  146. package/models/__tests__/fleet.cattle.io.gitrepo.test.ts +157 -0
  147. package/models/__tests__/secret.test.ts +56 -13
  148. package/models/catalog.cattle.io.app.js +112 -37
  149. package/models/cluster.js +11 -0
  150. package/models/fleet.cattle.io.bundle.js +40 -2
  151. package/models/fleet.cattle.io.gitrepo.js +169 -109
  152. package/models/management.cattle.io.fleetworkspace.js +4 -0
  153. package/models/management.cattle.io.kontainerdriver.js +7 -0
  154. package/models/nodedriver.js +4 -1
  155. package/models/provisioning.cattle.io.cluster.js +24 -0
  156. package/models/secret.js +1 -1
  157. package/package.json +5 -5
  158. package/pages/auth/login.vue +5 -11
  159. package/pages/auth/verify.vue +11 -1
  160. package/pages/c/_cluster/apps/charts/index.vue +6 -4
  161. package/pages/c/_cluster/apps/charts/install.vue +1 -1
  162. package/pages/c/_cluster/explorer/ConfigBadge.vue +3 -5
  163. package/pages/c/_cluster/explorer/EventsTable.vue +3 -2
  164. package/pages/c/_cluster/explorer/__tests__/index.test.ts +9 -9
  165. package/pages/c/_cluster/explorer/index.vue +33 -35
  166. package/pages/c/_cluster/explorer/tools/index.vue +3 -3
  167. package/pages/c/_cluster/fleet/index.vue +0 -5
  168. package/pages/c/_cluster/legacy/project/index.vue +1 -1
  169. package/pages/c/_cluster/settings/performance.vue +52 -53
  170. package/pages/c/_cluster/uiplugins/index.vue +19 -22
  171. package/pages/home.vue +17 -12
  172. package/pages/prefs.vue +5 -1
  173. package/plugins/shortkey.js +10 -1
  174. package/plugins/steve/steve-pagination-utils.ts +58 -8
  175. package/promptRemove/management.cattle.io.fleetworkspace.vue +98 -0
  176. package/promptRemove/management.cattle.io.globalrole.vue +1 -1
  177. package/promptRemove/management.cattle.io.project.vue +2 -8
  178. package/promptRemove/management.cattle.io.roletemplate.vue +1 -1
  179. package/promptRemove/mixin/roleDeletionCheck.js +1 -7
  180. package/promptRemove/pod.vue +7 -28
  181. package/rancher-components/Card/Card.vue +9 -1
  182. package/rancher-components/Form/Checkbox/Checkbox.vue +42 -6
  183. package/rancher-components/Form/LabeledInput/LabeledInput.vue +30 -3
  184. package/rancher-components/Form/Radio/RadioButton.vue +18 -3
  185. package/rancher-components/Form/Radio/RadioGroup.vue +39 -5
  186. package/rancher-components/LabeledTooltip/LabeledTooltip.vue +13 -1
  187. package/rancher-components/RcButton/RcButton.test.ts +97 -0
  188. package/rancher-components/RcButton/RcButton.vue +14 -9
  189. package/rancher-components/RcDropdown/RcDropdown.vue +3 -1
  190. package/rancher-components/RcDropdown/RcDropdownItem.vue +8 -2
  191. package/rancher-components/RcDropdown/RcDropdownMenu.vue +66 -0
  192. package/rancher-components/RcDropdown/index.ts +1 -0
  193. package/rancher-components/RcDropdown/types.ts +27 -0
  194. package/rancher-components/RcDropdown/useDropdownContext.ts +5 -2
  195. package/scripts/extension/helm/charts/ui-plugin-server/templates/_helpers.tpl +2 -2
  196. package/scripts/typegen.sh +1 -0
  197. package/store/__tests__/auth.test.ts +120 -0
  198. package/store/action-menu.js +13 -3
  199. package/store/auth.js +14 -9
  200. package/store/aws.js +9 -2
  201. package/store/catalog.js +14 -7
  202. package/store/features.js +1 -0
  203. package/store/prefs.js +9 -28
  204. package/store/type-map.utils.ts +4 -0
  205. package/types/resources/settings.d.ts +27 -20
  206. package/types/shell/index.d.ts +18 -12
  207. package/utils/__tests__/array.test.ts +13 -1
  208. package/utils/__tests__/string.test.ts +80 -1
  209. package/utils/array.ts +13 -0
  210. package/utils/auth.js +4 -0
  211. package/utils/banners.js +0 -45
  212. package/utils/cluster.js +1 -1
  213. package/{edit/monitoring.coreos.com.prometheusrule → utils}/duration.js +5 -3
  214. package/utils/object.js +0 -3
  215. package/utils/pagination-utils.ts +15 -2
  216. package/utils/string.js +31 -7
  217. package/utils/validators/formRules/__tests__/index.test.ts +27 -0
  218. package/utils/validators/formRules/index.ts +16 -0
  219. package/edit/provisioning.cattle.io.cluster/import.vue +0 -198
@@ -2,7 +2,7 @@ import { convert, matching, convertSelectorObj } from '@shell/utils/selector';
2
2
  import jsyaml from 'js-yaml';
3
3
  import isEmpty from 'lodash/isEmpty';
4
4
  import { escapeHtml } from '@shell/utils/string';
5
- import { FLEET } from '@shell/config/types';
5
+ import { FLEET, MANAGEMENT } from '@shell/config/types';
6
6
  import { FLEET as FLEET_ANNOTATIONS } from '@shell/config/labels-annotations';
7
7
  import { addObject, addObjects, findBy, insertAt } from '@shell/utils/array';
8
8
  import { set } from '@shell/utils/object';
@@ -42,6 +42,10 @@ function normalizeStateCounts(data) {
42
42
  }
43
43
 
44
44
  export default class GitRepo extends SteveModel {
45
+ get currentUser() {
46
+ return this.$rootGetters['auth/v3User'] || {};
47
+ }
48
+
45
49
  applyDefaults() {
46
50
  const spec = this.spec || {};
47
51
  const meta = this.metadata || {};
@@ -68,7 +72,7 @@ export default class GitRepo extends SteveModel {
68
72
 
69
73
  insertAt(out, 0, {
70
74
  action: 'pause',
71
- label: 'Pause',
75
+ label: this.t('fleet.gitRepo.actions.pause.label'),
72
76
  icon: 'icon icon-pause',
73
77
  bulkable: true,
74
78
  enabled: !!this.links.update && !this.spec?.paused
@@ -76,21 +80,38 @@ export default class GitRepo extends SteveModel {
76
80
 
77
81
  insertAt(out, 1, {
78
82
  action: 'unpause',
79
- label: 'Unpause',
83
+ label: this.t('fleet.gitRepo.actions.unpause.label'),
80
84
  icon: 'icon icon-play',
81
85
  bulkable: true,
82
86
  enabled: !!this.links.update && this.spec?.paused === true
83
87
  });
84
88
 
85
89
  insertAt(out, 2, {
86
- action: 'forceUpdate',
87
- label: 'Force Update',
88
- icon: 'icon icon-refresh',
90
+ action: 'enablePolling',
91
+ label: this.t('fleet.gitRepo.actions.enablePolling.label'),
92
+ icon: 'icon icon-endpoints_connected',
89
93
  bulkable: true,
90
- enabled: !!this.links.update
94
+ enabled: !!this.links.update && !!this.spec?.disablePolling
91
95
  });
92
96
 
93
- insertAt(out, 3, { divider: true });
97
+ insertAt(out, 3, {
98
+ action: 'disablePolling',
99
+ label: this.t('fleet.gitRepo.actions.disablePolling.label'),
100
+ icon: 'icon icon-endpoints_disconnected',
101
+ bulkable: true,
102
+ enabled: !!this.links.update && !this.spec?.disablePolling
103
+ });
104
+
105
+ insertAt(out, 4, {
106
+ action: 'forceUpdate',
107
+ label: this.t('fleet.gitRepo.actions.forceUpdate.label'),
108
+ icon: 'icon icon-refresh',
109
+ bulkable: true,
110
+ bulkAction: 'forceUpdateBulk',
111
+ enabled: !!this.links.update
112
+ });
113
+
114
+ insertAt(out, 5, { divider: true });
94
115
 
95
116
  return out;
96
117
  }
@@ -105,13 +126,42 @@ export default class GitRepo extends SteveModel {
105
126
  this.save();
106
127
  }
107
128
 
108
- forceUpdate() {
109
- const now = this.spec.forceSyncGeneration || 1;
129
+ enablePolling() {
130
+ this.spec.disablePolling = false;
131
+ this.save();
132
+ }
110
133
 
111
- this.spec.forceSyncGeneration = now + 1;
134
+ disablePolling() {
135
+ this.spec.disablePolling = true;
112
136
  this.save();
113
137
  }
114
138
 
139
+ goToClone() {
140
+ if (this.metadata?.labels?.[FLEET_ANNOTATIONS.CREATED_BY_USER_ID]) {
141
+ delete this.metadata.labels[FLEET_ANNOTATIONS.CREATED_BY_USER_ID];
142
+ }
143
+
144
+ if (this.metadata?.labels?.[FLEET_ANNOTATIONS.CREATED_BY_USER_NAME]) {
145
+ delete this.metadata.labels[FLEET_ANNOTATIONS.CREATED_BY_USER_NAME];
146
+ }
147
+
148
+ super.goToClone();
149
+ }
150
+
151
+ forceUpdate(resources = [this]) {
152
+ this.$dispatch('promptModal', {
153
+ componentProps: { repositories: resources },
154
+ component: 'GitRepoForceUpdateDialog'
155
+ });
156
+ }
157
+
158
+ forceUpdateBulk(resources) {
159
+ this.$dispatch('promptModal', {
160
+ componentProps: { repositories: resources },
161
+ component: 'GitRepoForceUpdateDialog'
162
+ });
163
+ }
164
+
115
165
  get state() {
116
166
  if (this.spec?.paused === true) {
117
167
  return 'paused';
@@ -326,47 +376,32 @@ export default class GitRepo extends SteveModel {
326
376
  }
327
377
 
328
378
  get bundles() {
329
- return this.$getters['matching'](FLEET.BUNDLE, { 'fleet.cattle.io/repo-name': this.name }, this.namespace);
379
+ return this.$getters['matching'](FLEET.BUNDLE, { [FLEET_ANNOTATIONS.REPO_NAME]: this.name }, this.namespace);
330
380
  }
331
381
 
332
382
  get bundleDeployments() {
333
- const bds = this.$getters['all'](FLEET.BUNDLE_DEPLOYMENT);
334
-
335
- return bds.filter((bd) => bd.metadata?.labels?.['fleet.cattle.io/repo-name'] === this.name);
383
+ return this.$getters['matching'](FLEET.BUNDLE_DEPLOYMENT, { [FLEET_ANNOTATIONS.REPO_NAME]: this.name });
336
384
  }
337
385
 
338
386
  get allBundlesStatuses() {
339
- const bundleDeploymentCountsPerBundle = this.bundleDeployments.reduce((acc, bd) => {
340
- const bundleId = FleetUtils.bundleIdFromBundleDeploymentLabels(bd.metadata?.labels);
341
- const state = mapStateToEnum(FleetUtils.bundleDeploymentState(bd));
342
-
343
- if (!acc[bundleId]) {
344
- acc[bundleId] = {
345
- total: 0,
346
- states: { [STATES_ENUM.READY]: 0 },
347
- };
348
- }
349
- acc[bundleId].total++;
350
-
351
- if (!acc[bundleId].states[state]) {
352
- acc[bundleId].states[state] = 0;
387
+ return this.bundles.reduce((acc, bundle) => {
388
+ if (isEmpty(bundle.status?.summary)) {
389
+ return acc;
353
390
  }
354
- acc[bundleId].states[state]++;
355
391
 
356
- return acc;
357
- }, {});
358
- const bundleIds = Object.keys(bundleDeploymentCountsPerBundle);
392
+ const { nonReadyResources, ...summary } = bundle.status?.summary;
359
393
 
360
- return bundleIds.reduce((acc, bundleId) => {
361
- const state = primaryDisplayStatusFromCount(bundleDeploymentCountsPerBundle[bundleId].states);
394
+ const bdCounts = normalizeStateCounts(summary);
395
+ const state = primaryDisplayStatusFromCount(bdCounts.states);
362
396
 
363
397
  if (!acc.states[state]) {
364
398
  acc.states[state] = 0;
365
399
  }
366
400
  acc.states[state]++;
401
+ acc.total++;
367
402
 
368
403
  return acc;
369
- }, { total: bundleIds.length, states: { [STATES_ENUM.READY]: 0 } } );
404
+ }, { total: 0, states: { [STATES_ENUM.READY]: 0 } } );
370
405
  }
371
406
 
372
407
  get allResourceStatuses() {
@@ -378,91 +413,79 @@ export default class GitRepo extends SteveModel {
378
413
  return {};
379
414
  }
380
415
 
381
- return this.bundleDeployments
382
- .filter((bd) => FleetUtils.clusterIdFromBundleDeploymentLabels(bd.metadata?.labels) === clusterId)
383
- .map((bd) => FleetUtils.resourcesFromBundleDeploymentStatus(bd.status))
384
- .flat()
385
- .map((r) => r.state)
386
- .reduce((prev, state) => {
387
- if (!prev[state]) {
388
- prev[state] = 0;
389
- }
390
- prev[state]++;
391
- prev.desiredReady++;
392
-
393
- return prev;
394
- }, { desiredReady: 0 });
416
+ return this.status?.perClusterResourceCounts[clusterId] || { desiredReady: 0 };
395
417
  }
396
418
 
397
419
  get resourcesStatuses() {
398
- const bundleDeployments = this.bundleDeployments || [];
420
+ if (isEmpty(this.status?.resources)) {
421
+ return [];
422
+ }
423
+
399
424
  const clusters = (this.targetClusters || []).reduce((res, c) => {
400
425
  res[c.id] = c;
401
426
 
402
427
  return res;
403
428
  }, {});
429
+ const resources = this.status?.resources?.reduce((acc, resourceInfo) => {
430
+ const { perClusterState, ...resource } = resourceInfo;
404
431
 
405
- const out = [];
406
-
407
- for (const bd of bundleDeployments) {
408
- const clusterId = FleetUtils.clusterIdFromBundleDeploymentLabels(bd.metadata?.labels);
409
- const c = clusters[clusterId];
410
-
411
- if (!c) {
412
- continue;
413
- }
414
-
415
- const resources = FleetUtils.resourcesFromBundleDeploymentStatus(bd.status);
416
-
417
- resources.forEach((r) => {
418
- const id = FleetUtils.resourceId(r);
419
- const type = FleetUtils.resourceType(r);
420
- const state = r.state;
421
-
422
- const color = colorForState(state).replace('text-', 'bg-');
423
- const display = stateDisplay(state);
424
-
425
- const detailLocation = {
426
- name: `c-cluster-product-resource${ r.namespace ? '-namespace' : '' }-id`,
427
- params: {
428
- product: NAME,
429
- cluster: c.metadata.labels[FLEET_ANNOTATIONS.CLUSTER_NAME], // explorer uses the "management" Cluster name, which differs from the Fleet Cluster name
430
- resource: type,
431
- namespace: r.namespace,
432
- id: r.name,
433
- }
434
- };
435
-
436
- const key = `${ c.id }-${ type }-${ r.namespace }-${ r.name }`;
437
-
438
- out.push({
439
- key,
440
- tableKey: key,
441
-
442
- // Needed?
443
- id,
444
- type,
445
- clusterId: c.id,
446
-
447
- // columns, see FleetResources.vue
448
- state: mapStateToEnum(state),
449
- clusterName: c.nameDisplay,
450
- apiVersion: r.apiVersion,
451
- kind: r.kind,
452
- name: r.name,
453
- namespace: r.namespace,
454
- creationTimestamp: r.createdAt,
455
-
456
- // other properties
457
- stateBackground: color,
458
- stateDisplay: display,
459
- stateSort: stateSort(color, display),
460
- detailLocation,
432
+ Object.entries(perClusterState).forEach(([state, clusterIds]) => {
433
+ clusterIds.filter((id) => !!clusters[id]).forEach((clusterId) => {
434
+ acc.push(Object.assign({}, resource, { clusterId, state }));
461
435
  });
462
436
  });
463
- }
464
437
 
465
- return out;
438
+ return acc;
439
+ }, []);
440
+
441
+ return resources.map((r) => {
442
+ const {
443
+ namespace, name, clusterId, state
444
+ } = r;
445
+ const id = FleetUtils.resourceId(r);
446
+ const type = FleetUtils.resourceType(r);
447
+ const c = clusters[clusterId];
448
+
449
+ const color = colorForState(state).replace('text-', 'bg-');
450
+ const display = stateDisplay(state);
451
+
452
+ const detailLocation = state !== STATES_ENUM.MISSING ? {
453
+ name: `c-cluster-product-resource${ r.namespace ? '-namespace' : '' }-id`,
454
+ params: {
455
+ product: NAME,
456
+ cluster: c.metadata.labels[FLEET_ANNOTATIONS.CLUSTER_NAME], // explorer uses the "management" Cluster name, which differs from the Fleet Cluster name
457
+ resource: type,
458
+ namespace,
459
+ id: name,
460
+ }
461
+ } : undefined;
462
+
463
+ const key = `${ clusterId }-${ type }-${ namespace }-${ name }`;
464
+
465
+ return {
466
+ key,
467
+ tableKey: key,
468
+
469
+ // Needed?
470
+ id,
471
+ type,
472
+ clusterId,
473
+
474
+ // columns, see FleetResources.vue
475
+ state: mapStateToEnum(state),
476
+ clusterName: c.nameDisplay,
477
+ apiVersion: r.apiVersion,
478
+ kind: r.kind,
479
+ name: r.name,
480
+ namespace: r.namespace,
481
+
482
+ // other properties
483
+ stateBackground: color,
484
+ stateDisplay: display,
485
+ stateSort: stateSort(color, display),
486
+ detailLocation,
487
+ };
488
+ });
466
489
  }
467
490
 
468
491
  get clusterInfo() {
@@ -485,4 +508,41 @@ export default class GitRepo extends SteveModel {
485
508
  get clustersList() {
486
509
  return this.$getters['all'](FLEET.CLUSTER);
487
510
  }
511
+
512
+ get authorId() {
513
+ return this.metadata?.labels?.[FLEET_ANNOTATIONS.CREATED_BY_USER_ID];
514
+ }
515
+
516
+ get author() {
517
+ if (this.authorId) {
518
+ return this.$rootGetters['management/byId'](MANAGEMENT.USER, this.authorId);
519
+ }
520
+
521
+ return null;
522
+ }
523
+
524
+ get createdBy() {
525
+ const displayName = this.metadata?.labels?.[FLEET_ANNOTATIONS.CREATED_BY_USER_NAME];
526
+
527
+ if (!displayName) {
528
+ return null;
529
+ }
530
+
531
+ return {
532
+ displayName,
533
+ location: !this.author ? null : {
534
+ name: 'c-cluster-product-resource-id',
535
+ params: {
536
+ cluster: '_',
537
+ product: 'auth',
538
+ resource: MANAGEMENT.USER,
539
+ id: this.author.id,
540
+ }
541
+ }
542
+ };
543
+ }
544
+
545
+ get showCreatedBy() {
546
+ return !!this.createdBy;
547
+ }
488
548
  }
@@ -83,4 +83,8 @@ export default class Workspace extends HybridModel {
83
83
 
84
84
  await norman.remove();
85
85
  }
86
+
87
+ get confirmRemove() {
88
+ return true;
89
+ }
86
90
  }
@@ -29,6 +29,13 @@ export const KONTAINER_TO_DRIVER = {
29
29
  opentelekomcloudcontainerengine: 'otccce',
30
30
  };
31
31
 
32
+ // Legacy KEV1 Hosted cluster drivers
33
+ export const KEV1 = [
34
+ 'amazonelasticcontainerservice',
35
+ 'azurekubernetesservice',
36
+ 'googlekubernetesengine',
37
+ ];
38
+
32
39
  // And the Import page has even shorter ones that don't match kontainer or create...
33
40
  export const DRIVER_TO_IMPORT = {
34
41
  googlegke: 'gke',
@@ -3,7 +3,10 @@ import Driver from '@shell/models/driver';
3
3
  /**
4
4
  * Overrides for spec.addCloudCredential
5
5
  */
6
- export const CLOUD_CREDENTIAL_OVERRIDE = { nutanix: true };
6
+ export const CLOUD_CREDENTIAL_OVERRIDE = {
7
+ nutanix: true,
8
+ oci: true
9
+ };
7
10
 
8
11
  export default class NodeDriver extends Driver {
9
12
  get doneRoute() {
@@ -10,6 +10,7 @@ import { compare } from '@shell/utils/version';
10
10
  import { AS, MODE, _VIEW, _YAML } from '@shell/config/query-params';
11
11
  import { HARVESTER_NAME as HARVESTER } from '@shell/config/features';
12
12
  import { CAPI as CAPI_ANNOTATIONS, NODE_ARCHITECTURE } from '@shell/config/labels-annotations';
13
+ import { KEV1 } from '@shell/models/management.cattle.io.kontainerdriver';
13
14
 
14
15
  /**
15
16
  * Class representing Cluster resource.
@@ -180,6 +181,15 @@ export default class ProvCluster extends SteveModel {
180
181
 
181
182
  const all = actions.concat(out);
182
183
 
184
+ // If the cluster is a KEV1 cluster then prevent edit
185
+ if (this.isKev1) {
186
+ const edit = all.find((action) => action.action === 'goToEdit');
187
+
188
+ if (edit) {
189
+ edit.enabled = false;
190
+ }
191
+ }
192
+
183
193
  // If we have a helper that wants to modify the available actions, let it do it
184
194
  if (this.customProvisionerHelper?.availableActions) {
185
195
  // Provider can either modify the provided list or return one of its own
@@ -189,6 +199,15 @@ export default class ProvCluster extends SteveModel {
189
199
  return all;
190
200
  }
191
201
 
202
+ get detailLocation() {
203
+ // Prevent going to detail page for a KEV1 cluster
204
+ if (this.isKev1) {
205
+ return undefined;
206
+ }
207
+
208
+ return super.detailLocation;
209
+ }
210
+
192
211
  get normanCluster() {
193
212
  const name = this.status?.clusterName;
194
213
 
@@ -289,6 +308,11 @@ export default class ProvCluster extends SteveModel {
289
308
  return this.mgmt?.isLocal;
290
309
  }
291
310
 
311
+ // Is the cluster a legacy (unsupported) KEV1 cluster?
312
+ get isKev1() {
313
+ return KEV1.includes(this.mgmt?.spec?.genericEngineConfig?.driverName);
314
+ }
315
+
292
316
  get isImported() {
293
317
  if (this.isLocal) {
294
318
  return false;
package/models/secret.js CHANGED
@@ -51,7 +51,7 @@ export default class Secret extends SteveModel {
51
51
 
52
52
  // For Fleet SSH secrets - does the secret have the 'known_hosts' data key?
53
53
  get supportsSshKnownHosts() {
54
- return this._type === TYPES.SSH && 'known_hosts' in this.data;
54
+ return this._type === TYPES.SSH && !!this.data && 'known_hosts' in this.data;
55
55
  }
56
56
 
57
57
  get issuer() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rancher/shell",
3
- "version": "3.0.2-rc.5",
3
+ "version": "3.0.2",
4
4
  "description": "Rancher Dashboard Shell",
5
5
  "repository": "https://github.com/rancherlabs/dashboard",
6
6
  "license": "Apache-2.0",
@@ -79,13 +79,13 @@
79
79
  "element-matches": "^0.1.2",
80
80
  "entities": "4.5.0",
81
81
  "eslint-config-standard": "16.0.3",
82
- "eslint-import-resolver-node": "0.3.4",
82
+ "eslint-import-resolver-node": "0.3.9",
83
83
  "eslint-module-utils": "2.6.1",
84
84
  "eslint-plugin-cypress": "2.12.1",
85
85
  "eslint-plugin-import": "2.31.0",
86
86
  "eslint-plugin-jest": "24.4.0",
87
87
  "eslint-plugin-n": "15.2.0",
88
- "eslint-plugin-vue": "9.10.0",
88
+ "eslint-plugin-vue": "9.32.0",
89
89
  "eslint": "7.32.0",
90
90
  "event-target-shim": "5.0.1",
91
91
  "express": "4.17.1",
@@ -101,7 +101,7 @@
101
101
  "jexl": "2.3.0",
102
102
  "jest": "27.5.1",
103
103
  "jquery": "3.5.1",
104
- "js-cookie": "2.2.1",
104
+ "js-cookie": "3.0.5",
105
105
  "js-yaml-loader": "1.2.2",
106
106
  "js-yaml": "4.1.0",
107
107
  "jsdiff": "1.1.1",
@@ -170,4 +170,4 @@
170
170
  ".vue"
171
171
  ]
172
172
  }
173
- }
173
+ }
@@ -30,7 +30,6 @@ import {
30
30
  } from '@shell/config/private-label';
31
31
  import loadPlugins from '@shell/plugins/plugin';
32
32
  import Loading from '@shell/components/Loading';
33
- import { getGlobalBannerFontSizes } from '@shell/utils/banners';
34
33
  import { HARVESTER_NAME as HARVESTER } from '@shell/config/features';
35
34
 
36
35
  export default {
@@ -105,6 +104,10 @@ export default {
105
104
  return this.t('login.clientError');
106
105
  } else if (this.err === LOGIN_ERRORS.CLIENT || this.err === LOGIN_ERRORS.SERVER) {
107
106
  return this.t('login.error');
107
+ } else if (this.err === LOGIN_ERRORS.NONCE) {
108
+ return this.t('login.invalidResponseError');
109
+ } else if (this.err === LOGIN_ERRORS.USER_UNAUTHORIZED) {
110
+ return this.t('login.userUnauthorized');
108
111
  }
109
112
 
110
113
  return this.err?.length ? this.t('login.specificError', { msg: this.err }) : '';
@@ -129,13 +132,6 @@ export default {
129
132
  hasLoginMessage() {
130
133
  return this.errorToDisplay || this.loggedOut || this.timedOut;
131
134
  },
132
-
133
- // Apply bottom margin so that the locale secletor control lifts up to avoid the footer fixed banner, if it is shown
134
- localeSelectorStyle() {
135
- const globalBannerSettings = getGlobalBannerFontSizes(this.$store);
136
-
137
- return { marginBottom: globalBannerSettings?.footerFont };
138
- }
139
135
  },
140
136
 
141
137
  async fetch() {
@@ -433,7 +429,6 @@ export default {
433
429
  <div class="mb-20">
434
430
  <LabeledInput
435
431
  v-if="!firstLogin"
436
- id="username"
437
432
  ref="username"
438
433
  v-model:value.trim="username"
439
434
  data-testid="local-login-username"
@@ -443,7 +438,6 @@ export default {
443
438
  </div>
444
439
  <div class="">
445
440
  <Password
446
- id="password"
447
441
  ref="password"
448
442
  v-model:value="password"
449
443
  data-testid="local-login-password"
@@ -507,7 +501,6 @@ export default {
507
501
  class="locale-selector"
508
502
  >
509
503
  <LocaleSelector
510
- :style="localeSelectorStyle"
511
504
  mode="login"
512
505
  />
513
506
  </div>
@@ -524,6 +517,7 @@ export default {
524
517
  <style lang="scss" scoped>
525
518
  .login {
526
519
  overflow: hidden;
520
+ position: relative; // Used to keep the locale selector positioned correctly
527
521
 
528
522
  .row {
529
523
  align-items: center;
@@ -5,9 +5,12 @@ import {
5
5
  import { get } from '@shell/utils/object';
6
6
  import { base64Decode } from '@shell/utils/crypto';
7
7
  import loadPlugins from '@shell/plugins/plugin';
8
+ import { LOGIN_ERRORS } from '@shell/store/auth';
8
9
 
9
10
  const samlProviders = ['ping', 'adfs', 'keycloak', 'okta', 'shibboleth'];
10
11
 
12
+ const oauthProviders = ['github', 'googleoauth', 'azuread'];
13
+
11
14
  function reply(err, code) {
12
15
  try {
13
16
  window.opener.window.onAuthTest(err, code);
@@ -114,7 +117,14 @@ export default {
114
117
  this.$router.replace(`/auth/login?err=${ escape(res) }`);
115
118
  }
116
119
  } catch (err) {
117
- this.$router.replace(`/auth/login?err=${ escape(err) }`);
120
+ let errCode = err;
121
+
122
+ // If the provider is OAUTH, then the client error is not that the credentials are wrong, but that the user is not authorized
123
+ if (oauthProviders.includes(provider) && err === LOGIN_ERRORS.CLIENT_UNAUTHORIZED) {
124
+ errCode = LOGIN_ERRORS.USER_UNAUTHORIZED;
125
+ }
126
+
127
+ this.$router.replace(`/auth/login?err=${ escape(errCode) }`);
118
128
  }
119
129
  },
120
130
 
@@ -58,12 +58,14 @@ export default {
58
58
  showHidden: null,
59
59
  chartOptions: [
60
60
  {
61
- label: 'Browse',
62
- value: 'browse',
61
+ label: this.t('catalog.charts.browseBtn'),
62
+ value: 'browse',
63
+ ariaLabel: this.t('catalog.charts.browseAriaLabel')
63
64
  },
64
65
  {
65
- label: 'Featured',
66
- value: 'featured'
66
+ label: this.t('catalog.charts.featuredBtn'),
67
+ value: 'featured',
68
+ ariaLabel: this.t('catalog.charts.featuredAriaLabel')
67
69
  }
68
70
  ]
69
71
  };
@@ -502,7 +502,7 @@ export default {
502
502
  },
503
503
 
504
504
  charts() {
505
- const current = this.existing?.matchingChart(true);
505
+ const current = this.existing?.matchingCharts(true)[0];
506
506
 
507
507
  const out = this.$store.getters['catalog/charts'].filter((x) => {
508
508
  if ( x.key === current?.key || x.chartName === current?.chartName ) {
@@ -27,16 +27,14 @@ export default {
27
27
  <div class="config-badge">
28
28
  <div>
29
29
  <button
30
+ v-clean-tooltip="{content: tooltip, triggers: ['hover', 'touch', 'focus'] }"
31
+ v-stripped-aria-label="tooltip"
30
32
  class="badge-install btn btn-sm role-secondary"
31
33
  data-testid="add-custom-cluster-badge"
32
34
  role="button"
33
- tabindex="0"
34
35
  @click="customBadgeDialog"
35
36
  >
36
- <i
37
- v-clean-tooltip="tooltip"
38
- class="icon icon-brush-icon"
39
- />
37
+ <i class="icon icon-brush-icon" />
40
38
  </button>
41
39
  </div>
42
40
  </div>
@@ -35,7 +35,7 @@ export default {
35
35
 
36
36
  const schema = this.$store.getters['cluster/schemaFor'](EVENT);
37
37
 
38
- const paginationHeaders = [
38
+ const paginationHeaders = schema ? [
39
39
  reason,
40
40
  STEVE_EVENT_OBJECT,
41
41
  MESSAGE,
@@ -49,7 +49,7 @@ export default {
49
49
  defaultSort: true,
50
50
  },
51
51
  headerFromSchemaColString('Count', schema, this.$store.getters, true),
52
- ];
52
+ ] : [];
53
53
 
54
54
  return {
55
55
  schema,
@@ -88,6 +88,7 @@ export default {
88
88
 
89
89
  <template>
90
90
  <PaginatedResourceTable
91
+ v-if="!!schema"
91
92
  :schema="schema"
92
93
  :headers="eventHeaders"
93
94
  :pagination-headers="paginationHeaders"