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

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 (258) hide show
  1. package/assets/styles/global/_layout.scss +4 -0
  2. package/assets/translations/en-us.yaml +144 -41
  3. package/assets/translations/zh-hans.yaml +1 -7
  4. package/chart/monitoring/ClusterSelector.vue +0 -21
  5. package/chart/monitoring/prometheus/index.vue +6 -3
  6. package/components/CruResource.vue +161 -14
  7. package/components/ExplorerMembers.vue +8 -4
  8. package/components/ExplorerProjectsNamespaces.vue +10 -6
  9. package/components/GrowlManager.vue +4 -0
  10. package/components/MgmtNodeList.vue +184 -0
  11. package/components/Resource/Detail/Card/StateCard/__tests__/composables.test.ts +90 -1
  12. package/components/Resource/Detail/Card/StateCard/composables.ts +57 -87
  13. package/components/Resource/Detail/Card/StatusCard/__tests__/StatusCard.test.ts +61 -0
  14. package/components/Resource/Detail/Card/StatusCard/index.vue +61 -15
  15. package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +2 -0
  16. package/components/Resource/Detail/Metadata/KeyValue.vue +5 -2
  17. package/components/Resource/Detail/Metadata/KeyValueRow.vue +2 -6
  18. package/components/ResourceDetail/index.vue +1 -1
  19. package/components/ResourceList/Masthead.vue +7 -1
  20. package/components/ResourceList/index.vue +82 -1
  21. package/components/RichTranslation.vue +5 -2
  22. package/components/Setting.vue +1 -0
  23. package/components/SubtleLink.vue +31 -6
  24. package/components/Tabbed/Tab.vue +29 -3
  25. package/components/Tabbed/index.vue +25 -3
  26. package/components/TableOfContents/TableOfContents.vue +109 -0
  27. package/components/TableOfContents/composables.ts +258 -0
  28. package/components/Window/ContainerShell.vue +21 -11
  29. package/components/Window/__tests__/ContainerShell.test.ts +107 -37
  30. package/components/Wizard.vue +9 -4
  31. package/components/fleet/AppCoChartGrid.vue +401 -0
  32. package/components/fleet/AppCoEmptyState.vue +127 -0
  33. package/components/fleet/AppCoPageHeader.vue +119 -0
  34. package/components/fleet/AppCoVersionSelect.vue +70 -0
  35. package/components/fleet/FleetClusterTargets/ClusterSelectionFields.vue +217 -0
  36. package/components/fleet/FleetClusterTargets/TargetsList.vue +123 -35
  37. package/components/fleet/FleetClusterTargets/index.vue +189 -146
  38. package/components/fleet/FleetIntro.vue +7 -3
  39. package/components/fleet/FleetNoWorkspaces.vue +7 -3
  40. package/components/fleet/FleetSecretSelector.vue +5 -3
  41. package/components/fleet/FleetValuesFrom.vue +8 -2
  42. package/components/fleet/GitRepoTargetTab.vue +0 -2
  43. package/components/fleet/HelmOpAdvancedTab.vue +19 -53
  44. package/components/fleet/HelmOpAppCoConfigTab.vue +593 -0
  45. package/components/fleet/HelmOpAppCoResourcesSection.vue +162 -0
  46. package/components/fleet/HelmOpResourcesSection.vue +82 -0
  47. package/components/fleet/HelmOpTargetOptionsSection.vue +89 -0
  48. package/components/fleet/HelmOpTargetTab.vue +64 -60
  49. package/components/fleet/HelmOpValuesTab.vue +129 -105
  50. package/components/fleet/__tests__/AppCoEmptyState.test.ts +71 -0
  51. package/components/fleet/__tests__/AppCoVersionSelect.test.ts +36 -0
  52. package/components/fleet/__tests__/ClusterSelectionFields.test.ts +62 -0
  53. package/components/fleet/__tests__/FleetClusterTargets.test.ts +253 -0
  54. package/components/fleet/__tests__/FleetSecretSelector.test.ts +16 -0
  55. package/components/fleet/__tests__/FleetValuesFrom.test.ts +44 -0
  56. package/components/fleet/__tests__/HelmOpAppCoConfigTab.test.ts +59 -0
  57. package/components/fleet/__tests__/HelmOpAppCoResourcesSection.test.ts +62 -0
  58. package/components/fleet/__tests__/HelmOpResourcesSection.test.ts +43 -0
  59. package/components/fleet/__tests__/HelmOpTargetOptionsSection.test.ts +34 -0
  60. package/components/fleet/__tests__/HelmOpValuesTab.test.ts +39 -0
  61. package/components/fleet/__tests__/__snapshots__/AppCoEmptyState.test.ts.snap +97 -0
  62. package/components/fleet/__tests__/__snapshots__/AppCoVersionSelect.test.ts.snap +30 -0
  63. package/components/fleet/__tests__/__snapshots__/ClusterSelectionFields.test.ts.snap +209 -0
  64. package/components/fleet/__tests__/__snapshots__/HelmOpTargetOptionsSection.test.ts.snap +140 -0
  65. package/components/fleet/dashboard/Empty.vue +8 -4
  66. package/components/fleet/dashboard/ResourceCard.vue +28 -0
  67. package/components/fleet/dashboard/ResourceDetails.vue +28 -0
  68. package/components/fleet/dashboard/__tests__/ResourceCard.test.ts +87 -0
  69. package/components/form/ArrayList.vue +61 -4
  70. package/components/form/KeyValue.vue +23 -2
  71. package/components/form/LabeledSelect.vue +39 -1
  72. package/components/form/Labels.vue +22 -3
  73. package/components/form/NameNsDescription.vue +13 -5
  74. package/components/form/ResourceTabs/index.vue +1 -0
  75. package/components/form/__tests__/NameNsDescription.test.ts +75 -0
  76. package/components/formatter/InternalExternalIP.vue +10 -4
  77. package/components/formatter/ServiceTargets.vue +26 -7
  78. package/components/formatter/__tests__/InternalExternalIP.test.ts +132 -0
  79. package/components/formatter/__tests__/ServiceTargets.test.ts +412 -0
  80. package/components/nav/Header.vue +4 -0
  81. package/components/nav/TopLevelMenu.vue +7 -2
  82. package/components/nav/__tests__/Header.test.ts +15 -0
  83. package/components/nav/__tests__/TopLevelMenu.test.ts +120 -2
  84. package/components/templates/default.vue +9 -4
  85. package/components/templates/home.vue +9 -4
  86. package/components/templates/plain.vue +9 -4
  87. package/composables/useHelmOpResources.test.ts +56 -0
  88. package/composables/useHelmOpResources.ts +32 -0
  89. package/composables/useStateColor.test.ts +325 -0
  90. package/composables/useStateColor.ts +128 -0
  91. package/config/home-links.js +1 -1
  92. package/config/labels-annotations.js +1 -0
  93. package/config/product/explorer.js +17 -4
  94. package/config/product/manager.js +2 -0
  95. package/config/router/index.js +16 -0
  96. package/config/router/navigation-guards/__tests__/authentication.test.ts +130 -0
  97. package/config/router/navigation-guards/authentication.js +10 -4
  98. package/config/router/routes.js +20 -6
  99. package/config/settings.ts +0 -2
  100. package/config/table-headers.js +3 -4
  101. package/config/types.js +9 -0
  102. package/core/plugin-products-base.ts +3 -3
  103. package/core/plugin-types.ts +83 -30
  104. package/core/plugin.ts +3 -0
  105. package/core/types-provisioning.ts +34 -1
  106. package/core/types.ts +15 -2
  107. package/detail/__tests__/provisioning.cattle.io.cluster.test.ts +114 -0
  108. package/detail/__tests__/workload.test.ts +3 -152
  109. package/detail/catalog.cattle.io.clusterrepo.vue +1 -1
  110. package/detail/provisioning.cattle.io.cluster.vue +30 -4
  111. package/detail/workload/index.vue +12 -55
  112. package/edit/__tests__/catalog.cattle.io.clusterrepo.test.ts +248 -0
  113. package/edit/__tests__/fleet.cattle.io.helmop.test.ts +105 -0
  114. package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/General.test.ts.snap +6 -0
  115. package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/index.test.ts.snap +1 -0
  116. package/edit/auth/__tests__/azuread.test.ts +34 -9
  117. package/edit/auth/__tests__/github.test.ts +234 -0
  118. package/edit/auth/__tests__/oidc.test.ts +26 -6
  119. package/edit/auth/__tests__/saml.test.ts +196 -0
  120. package/edit/auth/azuread.vue +128 -95
  121. package/edit/auth/github.vue +72 -13
  122. package/edit/auth/ldap/__tests__/index.test.ts +206 -0
  123. package/edit/auth/ldap/config.vue +8 -0
  124. package/edit/auth/ldap/index.vue +75 -1
  125. package/edit/auth/oidc.vue +119 -73
  126. package/edit/auth/saml.vue +76 -12
  127. package/edit/catalog.cattle.io.clusterrepo.vue +140 -32
  128. package/edit/fleet.cattle.io.helmop.vue +491 -136
  129. package/edit/management.cattle.io.user.vue +5 -2
  130. package/edit/provisioning.cattle.io.cluster/rke2.vue +84 -10
  131. package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +11 -0
  132. package/list/group.principal.vue +5 -4
  133. package/list/harvesterhci.io.management.cluster.vue +8 -9
  134. package/list/management.cattle.io.user.vue +12 -9
  135. package/list/provisioning.cattle.io.cluster.vue +16 -10
  136. package/mixins/__tests__/auth-config.test.ts +90 -0
  137. package/mixins/__tests__/chart.test.ts +94 -0
  138. package/mixins/__tests__/resource-fetch-api-pagination.test.ts +48 -0
  139. package/mixins/auth-config.js +7 -0
  140. package/mixins/chart.js +11 -2
  141. package/mixins/child-hook.js +12 -6
  142. package/mixins/create-edit-view/impl.js +5 -3
  143. package/mixins/resource-fetch-api-pagination.js +21 -1
  144. package/models/__tests__/catalog.cattle.io.clusterrepo.test.ts +57 -0
  145. package/models/__tests__/compliance.cattle.io.clusterscan.test.ts +144 -0
  146. package/models/__tests__/fleet-application.test.ts +175 -0
  147. package/models/__tests__/fleet.cattle.io.bundle.test.ts +169 -0
  148. package/models/__tests__/fleet.cattle.io.helmop.test.ts +84 -0
  149. package/models/__tests__/management.cattle.io.node.ts +22 -0
  150. package/models/__tests__/namespace.test.ts +36 -0
  151. package/models/__tests__/provisioning.cattle.io.cluster.test.ts +49 -0
  152. package/models/__tests__/workload.test.ts +401 -26
  153. package/models/catalog.cattle.io.clusterrepo.js +28 -4
  154. package/models/compliance.cattle.io.clusterscan.js +39 -4
  155. package/models/fleet-application.js +4 -0
  156. package/models/fleet.cattle.io.helmop.js +20 -1
  157. package/models/management.cattle.io.cluster.js +18 -2
  158. package/models/management.cattle.io.node.js +44 -3
  159. package/models/namespace.js +1 -1
  160. package/models/pod.js +33 -1
  161. package/models/provisioning.cattle.io.cluster.js +5 -5
  162. package/models/workload.js +108 -13
  163. package/models/workload.service.js +5 -0
  164. package/package.json +14 -13
  165. package/pages/about.vue +5 -6
  166. package/pages/auth/login.vue +0 -35
  167. package/pages/auth/setup.vue +11 -0
  168. package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +2 -2
  169. package/pages/c/_cluster/apps/charts/AppChartCardSubHeader.vue +10 -1
  170. package/pages/c/_cluster/apps/charts/__tests__/index.test.ts +93 -0
  171. package/pages/c/_cluster/apps/charts/chart.vue +2 -1
  172. package/pages/c/_cluster/apps/charts/index.vue +48 -10
  173. package/pages/c/_cluster/apps/charts/install.vue +122 -116
  174. package/pages/c/_cluster/auth/roles/index.vue +5 -4
  175. package/pages/c/_cluster/explorer/workload-dashboard/ByNamespaceSection.vue +31 -0
  176. package/pages/c/_cluster/explorer/workload-dashboard/ByStateSection.vue +138 -0
  177. package/pages/c/_cluster/explorer/workload-dashboard/ByTypeSection.vue +30 -0
  178. package/pages/c/_cluster/explorer/workload-dashboard/WorkloadCard.vue +155 -0
  179. package/pages/c/_cluster/explorer/workload-dashboard/WorkloadNamespaceCard.vue +142 -0
  180. package/pages/c/_cluster/explorer/workload-dashboard/WorkloadTypeCard.vue +159 -0
  181. package/pages/c/_cluster/explorer/workload-dashboard/__tests__/composable.test.ts +561 -0
  182. package/pages/c/_cluster/explorer/workload-dashboard/composable.ts +440 -0
  183. package/pages/c/_cluster/explorer/workload-dashboard/index.vue +187 -0
  184. package/pages/c/_cluster/explorer/workload-dashboard/types.ts +80 -0
  185. package/pages/c/_cluster/fleet/application/create.vue +187 -136
  186. package/pages/c/_cluster/fleet/application/index.vue +5 -3
  187. package/pages/c/_cluster/fleet/application/suse-app-collection/ChartDetailBody.vue +338 -0
  188. package/pages/c/_cluster/fleet/application/suse-app-collection/ChartDetailHeader.vue +121 -0
  189. package/pages/c/_cluster/fleet/application/suse-app-collection/chart.vue +369 -0
  190. package/pages/c/_cluster/fleet/application/suse-app-collection/charts.vue +248 -0
  191. package/pages/c/_cluster/fleet/application/suse-app-collection/credentials.vue +310 -0
  192. package/pages/c/_cluster/fleet/index.vue +2 -2
  193. package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +96 -0
  194. package/pages/c/_cluster/uiplugins/index.vue +15 -0
  195. package/pages/fail-whale.vue +16 -11
  196. package/pages/home.vue +16 -46
  197. package/plugins/clean-html.d.ts +9 -0
  198. package/plugins/dashboard-store/__tests__/resource-class.test.ts +93 -0
  199. package/plugins/dashboard-store/resource-class.js +62 -7
  200. package/plugins/steve/__tests__/actions.test.ts +212 -0
  201. package/plugins/steve/actions.js +96 -0
  202. package/plugins/steve/steve-pagination-utils.ts +1 -1
  203. package/rancher-components/Accordion/Accordion.vue +53 -9
  204. package/rancher-components/Form/Checkbox/Checkbox.vue +14 -0
  205. package/rancher-components/Form/Radio/RadioButton.vue +17 -1
  206. package/rancher-components/Form/Radio/RadioGroup.vue +10 -0
  207. package/rancher-components/Pill/RcTag/RcTag.vue +3 -2
  208. package/rancher-components/RcButton/RcButton.test.ts +103 -0
  209. package/rancher-components/RcButton/RcButton.vue +94 -15
  210. package/rancher-components/RcButton/types.ts +3 -0
  211. package/rancher-components/RcItemCard/RcItemCard.test.ts +18 -0
  212. package/rancher-components/RcItemCard/RcItemCard.vue +2 -2
  213. package/rancher-components/RcSection/RcSection.vue +28 -3
  214. package/scripts/extension/helm/package/Dockerfile +1 -1
  215. package/scripts/test-plugins-build.sh +2 -1
  216. package/store/__tests__/notifications.test.ts +434 -0
  217. package/store/catalog.js +57 -0
  218. package/store/plugins.js +7 -4
  219. package/types/components/buttonGroup.ts +5 -0
  220. package/types/shell/index.d.ts +104 -70
  221. package/utils/__tests__/auth.test.ts +273 -0
  222. package/utils/__tests__/computed.test.ts +193 -0
  223. package/utils/__tests__/cspAdaptor.test.ts +163 -0
  224. package/utils/__tests__/dom.test.ts +81 -0
  225. package/utils/__tests__/duration.test.ts +37 -1
  226. package/utils/__tests__/dynamic-importer.test.ts +102 -0
  227. package/utils/__tests__/fleet-appco.test.ts +312 -0
  228. package/utils/__tests__/monitoring.test.ts +130 -0
  229. package/utils/__tests__/object.test.ts +22 -0
  230. package/utils/__tests__/platform.test.ts +91 -0
  231. package/utils/__tests__/position.test.ts +237 -0
  232. package/utils/__tests__/provider.test.ts +51 -1
  233. package/utils/__tests__/queue.test.ts +232 -0
  234. package/utils/__tests__/release-notes.test.ts +221 -0
  235. package/utils/__tests__/router.test.js +254 -1
  236. package/utils/__tests__/select.test.ts +208 -0
  237. package/utils/__tests__/time.test.ts +265 -1
  238. package/utils/__tests__/title.test.ts +47 -0
  239. package/utils/__tests__/width.test.ts +53 -0
  240. package/utils/__tests__/window.test.ts +158 -0
  241. package/utils/__tests__/xccdf.test.ts +126 -6
  242. package/utils/crypto/__tests__/browserHashUtils.test.ts +98 -0
  243. package/utils/crypto/__tests__/index.test.ts +144 -0
  244. package/utils/duration.ts +104 -0
  245. package/utils/dynamic-content/__tests__/notification-handler.test.ts +196 -0
  246. package/utils/dynamic-content/info.ts +2 -1
  247. package/utils/error.js +13 -0
  248. package/utils/fleet-appco.ts +323 -0
  249. package/utils/object.js +22 -2
  250. package/utils/provider.ts +12 -0
  251. package/utils/validators/__tests__/container-images.test.ts +104 -0
  252. package/utils/validators/__tests__/flow-output.test.ts +91 -0
  253. package/utils/validators/__tests__/logging-outputs.test.ts +58 -0
  254. package/utils/validators/__tests__/monitoring-route.test.ts +119 -0
  255. package/utils/xccdf.ts +39 -42
  256. package/vue.config.js +1 -1
  257. package/pages/support/index.vue +0 -264
  258. package/utils/duration.js +0 -43
@@ -17,7 +17,7 @@ import { KEV1 } from './management.cattle.io.kontainerdriver';
17
17
  import { requireAsset } from '@shell/utils/require-asset';
18
18
  import { PINNED_CLUSTERS } from '@shell/store/prefs';
19
19
  import { copyTextToClipboard } from '@shell/utils/clipboard';
20
- import { isHostedProvider } from '@shell/utils/provider';
20
+ import { isHostedProvider, isCAPIProvider } from '@shell/utils/provider';
21
21
  import { ucFirst } from '@shell/utils/string';
22
22
  import { sortBy } from '@shell/utils/sort';
23
23
 
@@ -180,7 +180,7 @@ export default class MgmtCluster extends SteveModel {
180
180
  }
181
181
 
182
182
  get machineProvider() {
183
- return this.status?.info.machineProvider;
183
+ return this.status?.info?.machineProvider;
184
184
  }
185
185
 
186
186
  get machineProviderDisplay() {
@@ -261,6 +261,22 @@ export default class MgmtCluster extends SteveModel {
261
261
  return !!capiMachines;
262
262
  }
263
263
 
264
+ get isCAPIProvider() {
265
+ if (!this.isCapiHybrid || !this.machineProvider) {
266
+ return false;
267
+ }
268
+
269
+ const context = {
270
+ dispatch: this.$dispatch,
271
+ getters: this.$getters,
272
+ axios: this.$axios,
273
+ $extension: this.$extension,
274
+ t: (...args) => this.t.apply(this, args),
275
+ };
276
+
277
+ return isCAPIProvider(context, this.machineProvider.toLowerCase());
278
+ }
279
+
264
280
  get isHostedKubernetesProvider() {
265
281
  const context = {
266
282
  dispatch: this.$dispatch,
@@ -10,7 +10,8 @@ import { notOnlyOfRole } from '@shell/models/cluster.x-k8s.io.machine';
10
10
  const RKE1_ALLOWED_ACTIONS = [
11
11
  'goToViewYaml',
12
12
  'download',
13
- 'viewInApi'
13
+ 'viewInApi',
14
+ 'showConfiguration'
14
15
  ];
15
16
 
16
17
  export default class MgmtNode extends HybridModel {
@@ -63,6 +64,10 @@ export default class MgmtNode extends HybridModel {
63
64
  }
64
65
 
65
66
  get pool() {
67
+ if (!this.spec?.nodePoolName) {
68
+ return undefined;
69
+ }
70
+
66
71
  const nodePoolID = this.spec.nodePoolName.replace(':', '/');
67
72
 
68
73
  return this.$rootGetters['management/byId'](MANAGEMENT.NODE_POOL, nodePoolID);
@@ -118,6 +123,42 @@ export default class MgmtNode extends HybridModel {
118
123
  return this.status?.addresses || this.status?.internalNodeStatus?.addresses || [];
119
124
  }
120
125
 
126
+ get internalIps() {
127
+ const internal = this.addresses.filter(({ type }) => {
128
+ return type === ADDRESSES.INTERNAL_IP;
129
+ });
130
+
131
+ if (!internal.length) {
132
+ // For RKE1 clusters in EC2, node addresses are
133
+ // under status.rkeNode.address and status.rkeNode.internalAddress
134
+ if (this.status?.rkeNode) {
135
+ return this.status.rkeNode.internalAddress ? [this.status.rkeNode.internalAddress] : [];
136
+ }
137
+
138
+ return [];
139
+ }
140
+
141
+ return internal.map(({ address }) => address);
142
+ }
143
+
144
+ get externalIps() {
145
+ const external = this.addresses.filter(({ type }) => {
146
+ return type === ADDRESSES.EXTERNAL_IP;
147
+ });
148
+
149
+ if (!external.length) {
150
+ // For RKE1 clusters in EC2, node addresses are
151
+ // under status.rkeNode.address and status.rkeNode.internalAddress
152
+ if (this.status?.rkeNode) {
153
+ return this.status.rkeNode.address ? [this.status.rkeNode.address] : [];
154
+ }
155
+
156
+ return [];
157
+ }
158
+
159
+ return external.map(({ address }) => address);
160
+ }
161
+
121
162
  get internalIp() {
122
163
  // This shows in the IP address column for RKE1 nodes in the
123
164
  // list of nodes in the cluster detail page of Cluster Management.
@@ -131,7 +172,7 @@ export default class MgmtNode extends HybridModel {
131
172
 
132
173
  // For RKE1 clusters in EC2, node addresses are
133
174
  // under status.rkeNode.address and status.rkeNode.internalAddress
134
- if (!internal && this.status.rkeNode) {
175
+ if (!internal && this.status?.rkeNode) {
135
176
  return this.status.rkeNode.internalAddress;
136
177
  }
137
178
 
@@ -147,7 +188,7 @@ export default class MgmtNode extends HybridModel {
147
188
 
148
189
  // For RKE1 clusters in EC2, node addresses are
149
190
  // under status.rkeNode.address and status.rkeNode.internalAddress
150
- if (!statusAddress && this.status.rkeNode) {
191
+ if (!statusAddress && this.status?.rkeNode) {
151
192
  return this.status.rkeNode.address;
152
193
  }
153
194
 
@@ -68,7 +68,7 @@ export default class Namespace extends SteveModel {
68
68
  label: this.t('namespace.move'),
69
69
  bulkable: true,
70
70
  bulkAction: 'move',
71
- enabled: true,
71
+ enabled: this.canUpdate,
72
72
  icon: 'icon icon-fork',
73
73
  weight: 3,
74
74
  });
package/models/pod.js CHANGED
@@ -1,10 +1,11 @@
1
1
  import { insertAt } from '@shell/utils/array';
2
- import { colorForState, stateDisplay } from '@shell/plugins/dashboard-store/resource-class';
2
+ import { colorForState, simpleColorForState, stateDisplay } from '@shell/plugins/dashboard-store/resource-class';
3
3
  import { NODE, WORKLOAD_TYPES } from '@shell/config/types';
4
4
  import { escapeHtml, shortenedImage } from '@shell/utils/string';
5
5
  import WorkloadService from '@shell/models/workload.service';
6
6
  import { deleteProperty } from '@shell/utils/object';
7
7
  import { POD_RESTARTS_REG_EX } from '@shell/types/resources/pod';
8
+ import { useResourceCardRow } from '@shell/components/Resource/Detail/Card/StateCard/composables';
8
9
 
9
10
  export const WORKLOAD_PRIORITY = {
10
11
  [WORKLOAD_TYPES.DEPLOYMENT]: 1,
@@ -156,6 +157,37 @@ export default class Pod extends WorkloadService {
156
157
  return initContainers.includes(container);
157
158
  }
158
159
 
160
+ get resourceContainers() {
161
+ const statuses = [...(this.status?.containerStatuses || []), ...(this.status?.initContainerStatuses || [])];
162
+
163
+ return statuses.map((s) => {
164
+ const state = Object.keys(s.state || {})[0] || 'unknown';
165
+
166
+ return {
167
+ stateDisplay: stateDisplay(state),
168
+ stateSimpleColor: simpleColorForState(state),
169
+ };
170
+ });
171
+ }
172
+
173
+ get resourcesCardRows() {
174
+ const rows = [...this._resourcesCardRows];
175
+
176
+ if (this.resourceContainers.length) {
177
+ rows.unshift(useResourceCardRow(this.t('workload.container.titles.containers'), this.resourceContainers, 'stateSimpleColor', 'stateDisplay', '#containers'));
178
+ }
179
+
180
+ return rows;
181
+ }
182
+
183
+ get cards() {
184
+ return [
185
+ this.resourcesCard,
186
+ this.insightCard,
187
+ ...this._cards
188
+ ].filter((c) => c);
189
+ }
190
+
159
191
  get imageNames() {
160
192
  return this.spec.containers.map((container) => shortenedImage(container.image));
161
193
  }
@@ -97,7 +97,7 @@ export default class ProvCluster extends SteveModel {
97
97
 
98
98
  get canEdit() {
99
99
  // If the cluster is a KEV1 cluster, Harvester cluster, or v2 provisioning cluster that uses upstream capi infrastructure providers, then prevent edit
100
- if (this.isKev1 || this.isHarvester || this.isCapiHybrid) {
100
+ if (this.isKev1 || this.isHarvester || this.isCapiWithoutExtension) {
101
101
  return false;
102
102
  }
103
103
 
@@ -105,7 +105,7 @@ export default class ProvCluster extends SteveModel {
105
105
  }
106
106
 
107
107
  get canCustomEdit() {
108
- return !this.isCapiHybrid && super.canCustomEdit;
108
+ return !this.isCapiWithoutExtension && super.canCustomEdit;
109
109
  }
110
110
 
111
111
  get _availableActions() {
@@ -319,8 +319,8 @@ export default class ProvCluster extends SteveModel {
319
319
  }
320
320
 
321
321
  // identify v2 provisioning clusters created using upstream capi infrastructure providers instead of rancher/machine
322
- get isCapiHybrid() {
323
- return this.mgmt?.isCapiHybrid;
322
+ get isCapiWithoutExtension() {
323
+ return this.mgmt?.isCapiHybrid && !this.mgmt?.isCAPIProvider;
324
324
  }
325
325
 
326
326
  get mgmtClusterId() {
@@ -789,7 +789,7 @@ export default class ProvCluster extends SteveModel {
789
789
  }
790
790
 
791
791
  get disableResourceDetailDrawerConfigTab() {
792
- return !!this.isHarvester || this.isCapiHybrid;
792
+ return !!this.isHarvester || this.isCapiWithoutExtension;
793
793
  }
794
794
 
795
795
  get fullDetailPageOverride() {
@@ -1,9 +1,9 @@
1
1
  import { findBy, insertAt } from '@shell/utils/array';
2
2
  import { CATTLE_PUBLIC_ENDPOINTS } from '@shell/config/labels-annotations';
3
- import { WORKLOAD_TYPES, SERVICE, POD } from '@shell/config/types';
3
+ import { WORKLOAD_TYPES, SERVICE, INGRESS, POD } from '@shell/config/types';
4
4
  import { set } from '@shell/utils/object';
5
5
  import day from 'dayjs';
6
- import { convertSelectorObj, parse, matches } from '@shell/utils/selector';
6
+ import { convertSelectorObj, parse, matches, convert } from '@shell/utils/selector';
7
7
  import { SEPARATOR } from '@shell/config/workload';
8
8
  import WorkloadService from '@shell/models/workload.service';
9
9
  import { matching } from '@shell/utils/selector-typed';
@@ -586,6 +586,29 @@ export default class Workload extends WorkloadService {
586
586
  return undefined;
587
587
  }
588
588
 
589
+ async fetchSummaries() {
590
+ const summaries = { pods: null };
591
+
592
+ try {
593
+ if (this.podMatchExpression) {
594
+ summaries.pods = await this.$dispatch('fetchResourceSummary', {
595
+ type: POD,
596
+ opt: {
597
+ summaryField: 'metadata.state.name',
598
+ namespace: this.metadata.namespace,
599
+ labelSelector: { matchExpressions: this.podMatchExpression },
600
+ }
601
+ });
602
+ }
603
+ } catch (e) {
604
+ console.warn('fetchSummaries: failed to fetch pod summary', e); // eslint-disable-line no-console
605
+ }
606
+
607
+ set(this, '_summaries', summaries);
608
+
609
+ return summaries;
610
+ }
611
+
589
612
  async unWatchPods() {
590
613
  return await this.$dispatch('unwatch', { type: POD, all: true });
591
614
  }
@@ -747,16 +770,70 @@ export default class Workload extends WorkloadService {
747
770
  }
748
771
 
749
772
  get relatedServices() {
750
- // Find Services that have selectors that match this workload's Pod(s).
773
+ if (this.type === WORKLOAD_TYPES.JOB || this.type === WORKLOAD_TYPES.CRON_JOB) {
774
+ return [];
775
+ }
776
+
777
+ const podTemplateLabels = this.spec?.template?.metadata?.labels;
778
+
779
+ if (!podTemplateLabels || Object.keys(podTemplateLabels).length === 0) {
780
+ return [];
781
+ }
782
+
783
+ const templateAsObj = { metadata: { labels: podTemplateLabels } };
784
+
751
785
  return this.servicesInNamespace.filter((service) => {
752
786
  const selector = service.spec.selector;
753
787
 
754
- for (let i = 0; i < this.pods.length; i++) {
755
- const pod = this.pods[i];
788
+ if (!selector || typeof selector !== 'object') {
789
+ return false;
790
+ }
791
+
792
+ return matches(templateAsObj, convert(selector));
793
+ });
794
+ }
795
+
796
+ get matchingIngresses() {
797
+ const allIngresses = this.$rootGetters['cluster/all'](INGRESS);
798
+ const services = this.relatedServices;
756
799
 
757
- if (service.metadata?.namespace === this.metadata?.namespace && matches(pod, selector)) {
758
- return true;
800
+ if (!services.length) {
801
+ return [];
802
+ }
803
+
804
+ return allIngresses.filter((ingress) => {
805
+ try {
806
+ const rules = ingress.spec?.rules;
807
+
808
+ if (!rules || !Array.isArray(rules)) {
809
+ return false;
759
810
  }
811
+
812
+ for (const rule of rules) {
813
+ const paths = rule?.http?.paths;
814
+
815
+ if (!paths || !Array.isArray(paths)) {
816
+ continue;
817
+ }
818
+
819
+ for (const pathData of paths) {
820
+ const targetServiceName = pathData?.backend?.service?.name;
821
+
822
+ if (!targetServiceName) {
823
+ continue;
824
+ }
825
+
826
+ for (const service of services) {
827
+ if (ingress.metadata?.namespace === this.metadata?.namespace && service?.metadata?.name === targetServiceName) {
828
+ return true;
829
+ }
830
+ }
831
+ }
832
+ }
833
+ } catch (err) {
834
+ console.warn(`matchingIngresses: failed to match ingress "${ ingress.id }"`, err); // eslint-disable-line no-console
835
+
836
+ return false;
760
837
  }
761
838
 
762
839
  return false;
@@ -764,10 +841,23 @@ export default class Workload extends WorkloadService {
764
841
  }
765
842
 
766
843
  get resourcesCardRows() {
767
- return [
768
- useResourceCardRow(this.t('component.resource.detail.card.resourcesCard.rows.services'), this.relatedServices, undefined, undefined, '#services'),
769
- ...this._resourcesCardRows,
770
- ];
844
+ const rows = [...this._resourcesCardRows];
845
+ const showsIngressesAndServices = this.type !== WORKLOAD_TYPES.JOB && this.type !== WORKLOAD_TYPES.CRON_JOB;
846
+
847
+ if (showsIngressesAndServices) {
848
+ const services = this.relatedServices || [];
849
+ const ingresses = this.matchingIngresses || [];
850
+
851
+ if (ingresses.length) {
852
+ rows.unshift(useResourceCardRow(this.t('component.resource.detail.card.resourcesCard.rows.ingresses'), ingresses, undefined, undefined, '#ingresses'));
853
+ }
854
+
855
+ if (services.length) {
856
+ rows.unshift(useResourceCardRow(this.t('component.resource.detail.card.resourcesCard.rows.services'), services, undefined, undefined, '#services'));
857
+ }
858
+ }
859
+
860
+ return rows;
771
861
  }
772
862
 
773
863
  get podsCard() {
@@ -779,8 +869,11 @@ export default class Workload extends WorkloadService {
779
869
 
780
870
  const scalingTypes = [WORKLOAD_TYPES.DEPLOYMENT, WORKLOAD_TYPES.STATEFUL_SET];
781
871
  const canScale = this.canUpdate && scalingTypes.includes(this.type);
872
+ const summaryData = this._summaries?.pods || null;
873
+ const hasPods = this.pods?.length > 0;
874
+ const hasSummary = summaryData?.count > 0;
782
875
 
783
- if (!this.pods || (this.pods.length === 0 && !canScale)) {
876
+ if (!hasPods && !hasSummary && !canScale) {
784
877
  return null;
785
878
  }
786
879
 
@@ -789,6 +882,7 @@ export default class Workload extends WorkloadService {
789
882
  props: {
790
883
  title: this.t('component.resource.detail.card.podsCard.title'),
791
884
  resources: this.pods,
885
+ summaryData,
792
886
  showScaling: canScale,
793
887
  onIncrease: () => this.scale(true),
794
888
  onDecrease: () => this.scale(false),
@@ -818,8 +912,9 @@ export default class Workload extends WorkloadService {
818
912
  return [
819
913
  this.podsCard,
820
914
  this.jobsCard,
915
+ this.resourcesCard,
821
916
  this.insightCard,
822
917
  ...this._cards
823
- ];
918
+ ].filter((c) => c);
824
919
  }
825
920
  }
@@ -5,8 +5,13 @@ import { WORKLOAD_TYPES, SERVICE } from '@shell/config/types';
5
5
  import { clone, get } from '@shell/utils/object';
6
6
  import SteveModel from '@shell/plugins/steve/steve-class';
7
7
  import { shortenedImage } from '@shell/utils/string';
8
+ import { stateDisplay } from '@shell/plugins/dashboard-store/resource-class';
8
9
 
9
10
  export default class WorkloadService extends SteveModel {
11
+ get stateDisplay() {
12
+ return stateDisplay(this.state, true);
13
+ }
14
+
10
15
  async getPortsWithServiceType() {
11
16
  const ports = [];
12
17
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rancher/shell",
3
- "version": "3.0.12-rc.3",
3
+ "version": "3.0.12-rc.4",
4
4
  "description": "Rancher Dashboard Shell",
5
5
  "repository": "https://github.com/rancher/dashboard",
6
6
  "license": "Apache-2.0",
@@ -33,13 +33,14 @@
33
33
  "@babel/preset-typescript": "7.16.7",
34
34
  "@novnc/novnc": "1.2.0",
35
35
  "@popperjs/core": "2.11.8",
36
- "@rancher/icons": "2.0.60",
36
+ "@rancher/icons": "2.0.62",
37
37
  "@smithy/fetch-http-handler": "5.1.1",
38
38
  "@types/is-url": "1.2.30",
39
39
  "@types/node": "25.3.3",
40
40
  "@types/semver": "^7.5.8",
41
41
  "@typescript-eslint/eslint-plugin": "5.62.0",
42
42
  "@typescript-eslint/parser": "5.62.0",
43
+ "@vee-validate/zod": "4.15.0",
43
44
  "@vue/cli-plugin-babel": "~5.0.0",
44
45
  "@vue/cli-plugin-typescript": "~5.0.0",
45
46
  "@vue/cli-service": "5.0.8",
@@ -47,7 +48,7 @@
47
48
  "@vue/vue3-jest": "27.0.0",
48
49
  "add": "2.0.6",
49
50
  "ansi_up": "5.0.0",
50
- "axios": "1.15.2",
51
+ "axios": "1.16.0",
51
52
  "axios-retry": "3.1.9",
52
53
  "babel-eslint": "10.1.0",
53
54
  "babel-preset-vue": "2.0.2",
@@ -80,14 +81,13 @@
80
81
  "eslint-plugin-n": "15.2.0",
81
82
  "eslint-plugin-vue": "9.32.0",
82
83
  "event-target-shim": "5.0.1",
83
- "express": "4.17.1",
84
- "file-saver": "2.0.2",
84
+ "express": "4.22.2",
85
+ "file-saver": "2.0.5",
85
86
  "floating-vue": "5.2.2",
86
87
  "focus-trap": "7.6.5",
87
88
  "frontmatter-markdown-loader": "3.7.0",
88
89
  "identicon.js": "2.3.3",
89
90
  "intl-messageformat": "7.8.4",
90
- "ip": "2.0.1",
91
91
  "is-url": "1.2.4",
92
92
  "jest": "27.5.1",
93
93
  "jest-serializer-vue": "2.0.2",
@@ -124,12 +124,13 @@
124
124
  "webpack-virtual-modules": "0.6.2",
125
125
  "worker-loader": "3.0.8",
126
126
  "xmlbuilder2": "4.0.1",
127
- "xterm": "5.2.1",
128
- "xterm-addon-canvas": "0.5.0",
129
- "xterm-addon-fit": "0.8.0",
130
- "xterm-addon-search": "0.13.0",
131
- "xterm-addon-web-links": "0.9.0",
132
- "xterm-addon-webgl": "0.16.0",
127
+ "zod": "3.24.3",
128
+ "@xterm/xterm": "6.0.0",
129
+ "@xterm/addon-fit": "0.11.0",
130
+ "@xterm/addon-search": "0.16.0",
131
+ "@xterm/addon-web-links": "0.12.0",
132
+ "@xterm/addon-webgl": "0.19.0",
133
+ "@xterm/addon-canvas": "0.7.0",
133
134
  "yarn": "1.22.22"
134
135
  },
135
136
  "resolutions": {
@@ -142,7 +143,7 @@
142
143
  "merge": "2.1.1",
143
144
  "node-forge": "1.3.1",
144
145
  "nth-check": "2.1.1",
145
- "qs": "6.11.1",
146
+ "qs": "6.15.2",
146
147
  "roarr": "7.0.4",
147
148
  "semver": "7.5.4",
148
149
  "@types/lodash": "4.17.5",
package/pages/about.vue CHANGED
@@ -10,10 +10,11 @@ import TabTitle from '@shell/components/TabTitle';
10
10
  import { PanelLocation, ExtensionPoint } from '@shell/core/types';
11
11
  import ExtensionPanel from '@shell/components/ExtensionPanel';
12
12
  import { getVersionInfo } from '@shell/utils/version';
13
+ import { RcButton } from '@components/RcButton';
13
14
 
14
15
  export default {
15
16
  components: {
16
- BackLink, ExtensionPanel, Loading, TabTitle
17
+ BackLink, ExtensionPanel, Loading, TabTitle, RcButton
17
18
  },
18
19
  mixins: [BackRoute],
19
20
  async fetch() {
@@ -85,16 +86,14 @@ export default {
85
86
  {{ t('about.title') }}
86
87
  </TabTitle>
87
88
  </h1>
88
- <router-link
89
+ <rc-button
90
+ size="large"
89
91
  :to="{ name: 'diagnostic' }"
90
- class="btn role-primary"
91
92
  data-testid="about__diagnostics_button"
92
- role="button"
93
93
  :aria-label="t('about.diagnostic.title')"
94
- @keyup.space="$router.push({ name: 'diagnostic' })"
95
94
  >
96
95
  {{ t('about.diagnostic.title') }}
97
- </router-link>
96
+ </rc-button>
98
97
  </div>
99
98
  <!-- Extensions area -->
100
99
  <ExtensionPanel
@@ -410,41 +410,6 @@ export default {
410
410
  k="setup.defaultPassword.intro"
411
411
  :raw="true"
412
412
  />
413
-
414
- <div>
415
- <t
416
- k="setup.defaultPassword.dockerPrefix"
417
- :raw="true"
418
- />
419
- </div>
420
- <ul>
421
- <li>
422
- <t
423
- k="setup.defaultPassword.dockerPs"
424
- :raw="true"
425
- />
426
- </li>
427
- <li>
428
- <CopyCode>
429
- docker logs <u>container-id</u> 2&gt;&amp;1 | grep "Bootstrap Password:"
430
- </CopyCode>
431
- </li>
432
- </ul>
433
- <div>
434
- <t
435
- k="setup.defaultPassword.dockerSuffix"
436
- :raw="true"
437
- />
438
- </div>
439
-
440
- <br>
441
- <div>
442
- <t
443
- k="setup.defaultPassword.helmPrefix"
444
- :raw="true"
445
- />
446
- </div>
447
- <br>
448
413
  <CopyCode>
449
414
  {{ kubectlCmd }}
450
415
  </CopyCode>
@@ -20,6 +20,7 @@ import FormValidation from '@shell/mixins/form-validation';
20
20
  import { isLocalhost, isValidUrl } from '@shell/utils/validators/setting';
21
21
  import Loading from '@shell/components/Loading';
22
22
  import { getBrandMeta } from '@shell/utils/brand';
23
+ import { findMe } from '@shell/utils/auth';
23
24
 
24
25
  const calcIsFirstLogin = (store) => {
25
26
  const firstLoginSetting = store.getters['management/byId'](MANAGEMENT.SETTING, SETTING.FIRST_LOGIN);
@@ -77,6 +78,16 @@ export default {
77
78
  // Always show setup if this is the first log in
78
79
  return;
79
80
  } else if (mustChangePassword) {
81
+ // Skip password change for non-local sessions
82
+ try {
83
+ const me = await findMe(this.$store);
84
+
85
+ if (me && me.provider !== 'local') {
86
+ return this.$router.replace('/');
87
+ }
88
+ } catch (e) {
89
+ }
90
+
80
91
  // If the password needs changing and this isn't the first log in ensure we have the password
81
92
  if (!!this.$store.getters['auth/initialPass']) {
82
93
  // Got it... show setup
@@ -3,7 +3,7 @@ import { reactive } from 'vue';
3
3
  import { RcItemCardAction } from '@components/RcItemCard';
4
4
  import { RcButton } from '@components/RcButton';
5
5
  import { isTruncated } from '@shell/utils/style';
6
- import RcIcon from '@components/RcIcon/RcIcon.vue';
6
+ import { RcIcon } from '@components/RcIcon';
7
7
  import type { RcIconType } from '@components/RcIcon/types';
8
8
 
9
9
  interface FooterItem {
@@ -195,7 +195,7 @@ function getTooltip(key: string, fallback?: string): string | undefined {
195
195
  }
196
196
  }
197
197
 
198
- button.variant-ghost.app-chart-card-footer-button {
198
+ button.rc-button.variant-ghost.app-chart-card-footer-button {
199
199
  padding: 0;
200
200
  gap: 0;
201
201
  min-height: 20px;
@@ -9,12 +9,16 @@ interface SubHeaderItem {
9
9
 
10
10
  defineProps<{
11
11
  items: SubHeaderItem[];
12
+ removeMarginBottom?: boolean;
12
13
  }>();
13
14
 
14
15
  </script>
15
16
 
16
17
  <template>
17
- <div class="app-chart-card-sub-header">
18
+ <div
19
+ class="app-chart-card-sub-header"
20
+ :class="{ 'no-margin-bottom': removeMarginBottom }"
21
+ >
18
22
  <div
19
23
  v-for="(subHeaderItem, i) in items"
20
24
  :key="i"
@@ -38,8 +42,13 @@ defineProps<{
38
42
  flex-wrap: wrap;
39
43
  gap: var(--gap) var(--gap-md);
40
44
  color: var(--link-text-secondary);
45
+ height: 22px;
41
46
  margin-bottom: 8px;
42
47
 
48
+ &.no-margin-bottom {
49
+ margin-bottom: 0;
50
+ }
51
+
43
52
  &-item {
44
53
  display: flex;
45
54
  align-items: center;