@rancher/shell 0.3.4 → 0.3.6

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 (289) hide show
  1. package/assets/images/providers/outscale.svg +19 -0
  2. package/assets/styles/app.scss +1 -1
  3. package/assets/styles/base/_basic.scss +18 -0
  4. package/assets/styles/base/_mixins.scss +0 -11
  5. package/assets/styles/base/_variables.scss +2 -4
  6. package/assets/styles/fonts/_fontstack.scss +11 -11
  7. package/assets/styles/global/_button.scss +12 -2
  8. package/assets/styles/vendor/vue-js-modal.scss +3 -3
  9. package/assets/translations/en-us.yaml +113 -22
  10. package/assets/translations/zh-hans.yaml +113 -24
  11. package/babel.config.js +13 -0
  12. package/chart/gatekeeper.vue +78 -0
  13. package/chart/istio.vue +135 -112
  14. package/chart/logging/index.vue +13 -4
  15. package/chart/monitoring/index.vue +15 -5
  16. package/chart/monitoring/steps/uninstall-v1.vue +2 -2
  17. package/chart/rancher-backup/index.vue +10 -3
  18. package/cloud-credential/aws.vue +1 -1
  19. package/cloud-credential/digitalocean.vue +1 -1
  20. package/cloud-credential/gcp.vue +1 -1
  21. package/cloud-credential/generic.vue +2 -2
  22. package/cloud-credential/linode.vue +1 -1
  23. package/cloud-credential/pnap.vue +1 -1
  24. package/components/ActionMenu.vue +3 -4
  25. package/components/AssignTo.vue +1 -1
  26. package/components/AsyncButton.vue +1 -1
  27. package/components/BannerGraphic.vue +1 -1
  28. package/components/BrandImage.vue +1 -4
  29. package/components/ButtonDropdown.vue +2 -3
  30. package/components/Carousel.vue +85 -37
  31. package/components/ChartPsp.vue +76 -0
  32. package/components/CruResource.vue +6 -2
  33. package/components/DashboardMetrics.vue +12 -10
  34. package/components/DetailText.vue +1 -1
  35. package/components/DisableAuthProviderModal.vue +1 -1
  36. package/components/EmberPage.vue +1 -1
  37. package/components/EtcdInfoBanner.vue +12 -7
  38. package/components/ExplorerMembers.vue +101 -6
  39. package/components/ExplorerProjectsNamespaces.vue +46 -3
  40. package/components/FileDiff.vue +6 -7
  41. package/components/GrafanaDashboard.vue +27 -23
  42. package/components/LazyImage.vue +10 -12
  43. package/components/LogItem.vue +1 -1
  44. package/components/Markdown.vue +1 -1
  45. package/components/PromptRemove.vue +2 -2
  46. package/components/PromptRestore.vue +1 -1
  47. package/components/ResourceDetail/Masthead.vue +16 -0
  48. package/components/ResourceDetail/index.vue +21 -4
  49. package/components/ResourceList/index.vue +1 -1
  50. package/components/ResourceTable.vue +4 -1
  51. package/components/SingleClusterInfo.vue +2 -2
  52. package/components/SortableTable/THead.vue +1 -1
  53. package/components/SortableTable/index.vue +28 -13
  54. package/components/SortableTable/selection.js +58 -50
  55. package/components/Wizard.vue +4 -2
  56. package/components/__tests__/AsyncButton.test.ts +3 -1
  57. package/components/__tests__/ChartPsp.test.ts +75 -0
  58. package/components/__tests__/CruResource.test.ts +3 -1
  59. package/components/auth/Principal.vue +1 -1
  60. package/components/auth/RoleDetailEdit.vue +2 -2
  61. package/components/fleet/FleetBundles.vue +3 -1
  62. package/components/fleet/FleetClusters.vue +1 -2
  63. package/components/fleet/FleetIntro.vue +9 -1
  64. package/components/fleet/FleetNoWorkspaces.vue +62 -0
  65. package/components/fleet/FleetSummary.vue +7 -1
  66. package/components/form/HookOption.vue +14 -10
  67. package/components/form/LabeledSelect.vue +14 -11
  68. package/components/form/Labels.vue +32 -27
  69. package/components/form/MatchExpressions.vue +19 -4
  70. package/components/form/Members/ClusterPermissionsEditor.vue +32 -7
  71. package/components/form/NameNsDescription.vue +32 -46
  72. package/components/form/ProjectMemberEditor.vue +46 -21
  73. package/components/form/ResourceSelector.vue +1 -1
  74. package/components/form/SecretSelector.vue +5 -1
  75. package/components/form/ServiceNameSelect.vue +1 -1
  76. package/components/form/SimpleSecretSelector.vue +9 -9
  77. package/components/form/Tolerations.vue +4 -1
  78. package/components/form/ValueFromResource.vue +14 -9
  79. package/components/form/WorkloadPorts.vue +2 -2
  80. package/components/form/__tests__/LabeledSelect.test.ts +138 -0
  81. package/components/form/__tests__/NameNsDescription.ts +59 -0
  82. package/components/formatter/InternalExternalIP.vue +6 -0
  83. package/components/formatter/InvolvedObjectLink.vue +54 -0
  84. package/components/formatter/Link.vue +20 -4
  85. package/components/formatter/LinkName.vue +6 -1
  86. package/components/formatter/ServiceTargets.vue +1 -1
  87. package/components/formatter/WorkloadHealthScale.vue +8 -2
  88. package/components/nav/Group.vue +2 -2
  89. package/components/nav/NamespaceFilter.vue +23 -11
  90. package/components/nav/TopLevelMenu.vue +2 -4
  91. package/components/nav/Type.vue +1 -1
  92. package/components/nav/WorkspaceSwitcher.vue +46 -5
  93. package/components/nuxt/nuxt-build-indicator.vue +143 -0
  94. package/components/nuxt/nuxt-child.js +122 -0
  95. package/components/nuxt/nuxt-error.vue +98 -0
  96. package/components/nuxt/nuxt-link.client.js +98 -0
  97. package/components/nuxt/nuxt-link.server.js +16 -0
  98. package/components/nuxt/nuxt-loading.vue +154 -0
  99. package/components/nuxt/nuxt.js +101 -0
  100. package/config/labels-annotations.js +17 -0
  101. package/config/middleware.js +12 -0
  102. package/config/product/auth.js +3 -2
  103. package/config/product/explorer.js +34 -6
  104. package/config/product/fleet.js +2 -0
  105. package/config/query-params.js +1 -0
  106. package/config/router.js +414 -0
  107. package/config/store.js +181 -0
  108. package/config/table-headers.js +54 -12
  109. package/config/types.js +18 -8
  110. package/config/uiplugins.js +30 -0
  111. package/content/docs/en-us/whats-new.md +10 -0
  112. package/content/docs/zh-hans/whats-new.md +11 -1
  113. package/core/plugin-routes.ts +23 -0
  114. package/core/plugin.ts +4 -2
  115. package/core/types.ts +258 -1
  116. package/creators/app/app.package.json +2 -1
  117. package/creators/app/files/.eslintrc.js +1 -1
  118. package/creators/app/files/babel.config.js +1 -18
  119. package/creators/app/files/tsconfig.json +0 -1
  120. package/creators/app/files/vue.config.js +6 -0
  121. package/creators/app/init +5 -5
  122. package/creators/pkg/files/.github/workflows/build-extension.yml +110 -0
  123. package/creators/pkg/files/tsconfig.json +0 -1
  124. package/creators/pkg/init +35 -4
  125. package/creators/pkg/pkg.package.json +3 -3
  126. package/creators/update/init +1 -1
  127. package/detail/constraints.gatekeeper.sh.constraint.vue +34 -17
  128. package/detail/fleet.cattle.io.clustergroup.vue +7 -1
  129. package/detail/fleet.cattle.io.gitrepo.vue +19 -11
  130. package/detail/harvesterhci.io.management.cluster.vue +3 -3
  131. package/detail/provisioning.cattle.io.cluster.vue +54 -12
  132. package/detail/workload/index.vue +3 -3
  133. package/dialog/AddClusterMemberDialog.vue +1 -1
  134. package/dialog/AddProjectMemberDialog.vue +2 -2
  135. package/dialog/AddonConfigConfirmationDialog.vue +27 -15
  136. package/dialog/DiagnosticTimingsDialog.vue +1 -1
  137. package/dialog/ForceMachineRemoveDialog.vue +1 -1
  138. package/dialog/GenericPrompt.vue +18 -6
  139. package/dialog/RotateEncryptionKeyDialog.vue +1 -1
  140. package/dialog/SaveAsRKETemplateDialog.vue +1 -1
  141. package/dialog/ScaleMachineDownDialog.vue +1 -1
  142. package/edit/auth/github.vue +8 -8
  143. package/edit/auth/googleoauth.vue +5 -5
  144. package/edit/auth/ldap/index.vue +1 -1
  145. package/edit/auth/oidc.vue +1 -1
  146. package/edit/auth/saml.vue +1 -1
  147. package/edit/cis.cattle.io.clusterscan.vue +1 -1
  148. package/edit/fleet.cattle.io.clustergroup.vue +6 -4
  149. package/edit/fleet.cattle.io.gitrepo.vue +32 -4
  150. package/edit/helm.cattle.io.projecthelmchart.vue +5 -1
  151. package/edit/logging.banzaicloud.io.output/index.vue +18 -5
  152. package/edit/logging.banzaicloud.io.output/providers/loki.vue +1 -0
  153. package/edit/management.cattle.io.fleetworkspace.vue +141 -6
  154. package/edit/management.cattle.io.podsecurityadmissionconfigurationtemplate.vue +4 -1
  155. package/edit/management.cattle.io.setting.vue +1 -1
  156. package/edit/monitoring.coreos.com.alertmanagerconfig/types/webhook.vue +2 -2
  157. package/edit/monitoring.coreos.com.receiver/tls.vue +18 -18
  158. package/edit/monitoring.coreos.com.receiver/types/webhook.banner.vue +4 -4
  159. package/edit/monitoring.coreos.com.receiver/types/webhook.vue +1 -1
  160. package/edit/namespace.vue +14 -10
  161. package/edit/networking.k8s.io.networkpolicy/PolicyRuleTarget.vue +126 -45
  162. package/edit/networking.k8s.io.networkpolicy/index.vue +1 -1
  163. package/edit/provisioning.cattle.io.cluster/MachinePool.vue +21 -4
  164. package/edit/provisioning.cattle.io.cluster/RegistryConfigs.vue +1 -0
  165. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +202 -2
  166. package/edit/provisioning.cattle.io.cluster/import.vue +23 -25
  167. package/edit/provisioning.cattle.io.cluster/rke2.vue +344 -102
  168. package/edit/resources.cattle.io.backup.vue +1 -1
  169. package/edit/service.vue +1 -1
  170. package/edit/storage.k8s.io.storageclass/provisioners/driver.harvesterhci.io.vue +2 -2
  171. package/edit/workload/__tests__/Job.test.ts +3 -1
  172. package/edit/workload/index.vue +8 -3
  173. package/edit/workload/mixins/workload.js +22 -7
  174. package/edit/workload/storage/Mount.vue +3 -3
  175. package/initialize/App.js +206 -0
  176. package/initialize/client.js +863 -0
  177. package/initialize/index.js +364 -0
  178. package/layouts/default.vue +7 -3
  179. package/layouts/standalone.vue +13 -0
  180. package/list/catalog.cattle.io.clusterrepo.vue +1 -0
  181. package/list/fleet.cattle.io.bundle.vue +6 -3
  182. package/list/fleet.cattle.io.clusterregistrationtoken.vue +3 -1
  183. package/list/fleet.cattle.io.gitrepo.vue +44 -5
  184. package/list/management.cattle.io.fleetworkspace.vue +45 -0
  185. package/list/node.vue +69 -16
  186. package/list/provisioning.cattle.io.cluster.vue +30 -1
  187. package/list/rbac.authorization.k8s.io.clusterrolebinding.vue +48 -0
  188. package/list/workload.vue +6 -4
  189. package/machine-config/azure.vue +97 -38
  190. package/middleware/authenticated.js +34 -0
  191. package/mixins/chart.js +101 -2
  192. package/mixins/fetch.client.js +95 -0
  193. package/mixins/fetch.server.js +73 -0
  194. package/mixins/labeled-form-element.ts +2 -2
  195. package/mixins/resource-fetch.js +2 -2
  196. package/models/apps.statefulset.js +28 -0
  197. package/models/cluster/node.js +23 -2
  198. package/models/cluster.x-k8s.io.machine.js +4 -2
  199. package/models/clusterroletemplatebinding.js +7 -0
  200. package/models/constraints.gatekeeper.sh.constraint.js +46 -0
  201. package/models/fleet.cattle.io.cluster.js +19 -10
  202. package/models/fleet.cattle.io.gitrepo.js +7 -2
  203. package/models/management.cattle.io.cluster.js +1 -1
  204. package/models/management.cattle.io.fleetworkspace.js +12 -0
  205. package/models/management.cattle.io.gitreporestriction.js +5 -0
  206. package/models/management.cattle.io.podsecurityadmissionconfigurationtemplate.js +3 -0
  207. package/models/pod.js +4 -0
  208. package/models/provisioning.cattle.io.cluster.js +7 -5
  209. package/models/rbac.authorization.k8s.io.clusterrolebinding.js +16 -0
  210. package/models/rbac.authorization.k8s.io.rolebinding.js +16 -0
  211. package/package.json +13 -21
  212. package/pages/auth/setup.vue +2 -2
  213. package/pages/c/_cluster/apps/charts/__tests__/install.helper.test.ts +33 -0
  214. package/pages/c/_cluster/apps/charts/chart.vue +4 -4
  215. package/pages/c/_cluster/apps/charts/install.helpers.js +26 -0
  216. package/pages/c/_cluster/apps/charts/install.vue +98 -102
  217. package/pages/c/_cluster/explorer/EventsTable.vue +5 -19
  218. package/pages/c/_cluster/explorer/index.vue +29 -25
  219. package/pages/c/_cluster/explorer/tools/index.vue +8 -8
  220. package/pages/c/_cluster/fleet/index.vue +95 -34
  221. package/pages/c/_cluster/gatekeeper/index.vue +1 -1
  222. package/pages/c/_cluster/istio/index.vue +5 -5
  223. package/pages/c/_cluster/manager/cloudCredential/index.vue +1 -1
  224. package/pages/c/_cluster/monitoring/index.vue +7 -0
  225. package/pages/c/_cluster/uiplugins/InstallDialog.vue +8 -8
  226. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +20 -7
  227. package/pages/c/_cluster/uiplugins/index.vue +49 -17
  228. package/pages/diagnostic.vue +32 -25
  229. package/pages/home.vue +9 -4
  230. package/pages/index.vue +10 -1
  231. package/pages/rio/mesh.vue +1 -2
  232. package/pkg/tsconfig.json +0 -1
  233. package/plugins/clean-html-directive.js +34 -0
  234. package/plugins/dashboard-store/actions.js +32 -9
  235. package/plugins/dashboard-store/index.js +1 -1
  236. package/plugins/dashboard-store/mutations.js +5 -2
  237. package/plugins/dashboard-store/resource-class.js +8 -1
  238. package/plugins/plugin.js +0 -14
  239. package/plugins/portal-vue.js +4 -0
  240. package/plugins/steve/mutations.js +3 -2
  241. package/plugins/steve/steve-description-class.js +5 -1
  242. package/plugins/steve/subscribe.js +63 -54
  243. package/plugins/steve-create-worker.js +14 -0
  244. package/promptRemove/management.cattle.io.globalrole.vue +2 -2
  245. package/promptRemove/management.cattle.io.project.vue +2 -2
  246. package/promptRemove/management.cattle.io.roletemplate.vue +2 -2
  247. package/promptRemove/pod.vue +1 -1
  248. package/public/index.html +65 -0
  249. package/rancher-components/components/Banner/Banner.test.ts +7 -1
  250. package/rancher-components/components/Banner/Banner.vue +2 -1
  251. package/rancher-components/components/Form/Checkbox/Checkbox.vue +2 -0
  252. package/rancher-components/components/Form/Radio/RadioButton.test.ts +31 -0
  253. package/rancher-components/components/Form/Radio/RadioButton.vue +14 -3
  254. package/scripts/build-pkg.sh +1 -0
  255. package/scripts/clean +6 -0
  256. package/scripts/extension/bundle +58 -0
  257. package/scripts/extension/helmpatch +89 -0
  258. package/scripts/extension/publish +333 -0
  259. package/scripts/serve-pkgs +6 -2
  260. package/scripts/test-plugins-build.sh +4 -0
  261. package/store/__tests__/index.test.ts +110 -0
  262. package/store/index.js +145 -58
  263. package/store/type-map.js +6 -2
  264. package/tsconfig.default.json +36 -0
  265. package/tsconfig.json +23 -0
  266. package/types/rancher/index.d.ts +2 -0
  267. package/types/shell/index.d.ts +466 -320
  268. package/utils/__tests__/grafana.test.ts +44 -0
  269. package/utils/__tests__/string.test.ts +12 -0
  270. package/utils/auth.js +65 -0
  271. package/utils/axios.js +190 -0
  272. package/utils/cookie-universal-nuxt.js +10 -0
  273. package/utils/dom.js +15 -0
  274. package/utils/grafana.js +35 -16
  275. package/utils/monitoring.js +2 -1
  276. package/utils/nuxt.js +659 -0
  277. package/utils/position.js +5 -8
  278. package/utils/router.scrollBehavior.js +80 -0
  279. package/utils/select.js +1 -3
  280. package/utils/socket.js +1 -0
  281. package/utils/string.js +13 -0
  282. package/utils/time.js +9 -0
  283. package/vue.config.js +690 -0
  284. package/chart/rancher-alerting-drivers.vue +0 -53
  285. package/chart/rancher-gatekeeper.vue +0 -37
  286. package/creators/app/files/nuxt.config.js +0 -6
  287. package/models/management.cattle.io.podsecurityadmissionconfigurationtemplate.ts +0 -4
  288. package/nuxt.config.js +0 -798
  289. package/plugins/dashboard-store/extensions.js +0 -22
package/mixins/chart.js CHANGED
@@ -14,6 +14,8 @@ import { CAPI, CATALOG } from '@shell/config/types';
14
14
  import { isPrerelease } from '@shell/utils/version';
15
15
  import difference from 'lodash/difference';
16
16
  import { LINUX } from '@shell/store/catalog';
17
+ import { clone } from 'utils/object';
18
+ import { merge } from 'lodash';
17
19
 
18
20
  export default {
19
21
  data() {
@@ -292,7 +294,13 @@ export default {
292
294
  // use the first version provided by the Helm chart
293
295
  // as the default.
294
296
  if ( !this.query.versionName && this.chart.versions?.length ) {
295
- this.query.versionName = this.chart.versions[0].version;
297
+ if (this.showPreRelease) {
298
+ this.query.versionName = this.chart.versions[0].version;
299
+ } else {
300
+ const firstRelease = this.chart.versions.find(v => !isPrerelease(v.version));
301
+
302
+ this.query.versionName = firstRelease?.version || this.chart.versions[0].version;
303
+ }
296
304
  }
297
305
 
298
306
  if ( !this.query.versionName ) {
@@ -341,6 +349,97 @@ export default {
341
349
  }
342
350
  }, // End of fetchChart
343
351
 
352
+ // Charts have an annotation that specifies any additional charts that should be installed at the same time eg CRDs
353
+ async fetchAutoInstallInfo() {
354
+ const out = [];
355
+ /*
356
+ An example value for auto is ["rancher-monitoring-crd=match"].
357
+ It is an array of chart names that lets Rancher know of other
358
+ charts that should be auto-installed at the same time.
359
+ */
360
+ const auto = (this.version?.annotations?.[CATALOG_ANNOTATIONS.AUTO_INSTALL] || '').split(/\s*,\s*/).filter(x => !!x).reverse();
361
+
362
+ for ( const constraint of auto ) {
363
+ const provider = this.$store.getters['catalog/versionSatisfying']({
364
+ constraint,
365
+ repoName: this.chart.repoName,
366
+ repoType: this.chart.repoType,
367
+ chartVersion: this.version.version,
368
+ });
369
+ /* An example return value for "provider":
370
+ [
371
+ {
372
+ "name": "rancher-monitoring-crd",
373
+ "version": "100.1.3+up19.0.3",
374
+ "description": "Installs the CRDs for rancher-monitoring.",
375
+ "apiVersion": "v1",
376
+ "annotations": {
377
+ "catalog.cattle.io/certified": "rancher",
378
+ "catalog.cattle.io/hidden": "true",
379
+ "catalog.cattle.io/namespace": "cattle-monitoring-system",
380
+ "catalog.cattle.io/release-name": "rancher-monitoring-crd"
381
+ },
382
+ "type": "application",
383
+ "urls": [
384
+ "https://192.168.0.18:8005/k8s/clusters/c-m-hhpg69fv/v1/catalog.cattle.io.clusterrepos/rancher-charts?chartName=rancher-monitoring-crd&link=chart&version=100.1.3%2Bup19.0.3"
385
+ ],
386
+ "created": "2022-04-27T10:04:18.343124-07:00",
387
+ "digest": "ecf07ba23a9cdaa7ffbbb14345d94ea1240b7f3b8e0ce9be4640e3e585c484e2",
388
+ "key": "cluster/rancher-charts/rancher-monitoring-crd/100.1.3+up19.0.3",
389
+ "repoType": "cluster",
390
+ "repoName": "rancher-charts"
391
+ }
392
+ ]
393
+ */
394
+
395
+ if ( provider ) {
396
+ try {
397
+ const crdVersionInfo = await this.$store.dispatch('catalog/getVersionInfo', {
398
+ repoType: provider.repoType,
399
+ repoName: provider.repoName,
400
+ chartName: provider.name,
401
+ versionName: provider.version
402
+ });
403
+ let existingCRDApp;
404
+
405
+ // search for an existing crd app to track any non-default values used on the previous install/upgrade
406
+ if (this.mode === _EDIT) {
407
+ const targetNamespace = crdVersionInfo?.chart?.annotations?.[CATALOG_ANNOTATIONS.NAMESPACE];
408
+ const targetName = crdVersionInfo?.chart?.annotations?.[CATALOG_ANNOTATIONS.RELEASE_NAME];
409
+
410
+ if (targetName && targetNamespace) {
411
+ existingCRDApp = await this.$store.dispatch('cluster/find', {
412
+ type: CATALOG.APP,
413
+ id: `${ targetNamespace }/${ targetName }`,
414
+ });
415
+ }
416
+ }
417
+ if (existingCRDApp) {
418
+ // spec.values are any non-default values the user configured
419
+ // the installation form should show these, as well as any default values from the chart
420
+ const existingValues = clone(existingCRDApp.spec?.values || {});
421
+ const defaultValues = clone(existingCRDApp.spec?.chart?.values || {});
422
+
423
+ crdVersionInfo.existingValues = existingValues;
424
+ crdVersionInfo.allValues = merge(defaultValues, existingValues);
425
+ } else {
426
+ // allValues will potentially be updated in the UI - we want to track this separately from values to avoid mutating the chart object in the store
427
+ // this is similar to userValues for the main chart
428
+ crdVersionInfo.allValues = clone(crdVersionInfo.values);
429
+ }
430
+
431
+ out.push(crdVersionInfo);
432
+ } catch (e) {
433
+ console.error('Unable to fetch VersionInfo: ', e); // eslint-disable-line no-console
434
+ }
435
+ } else {
436
+ this.errors.push(`This chart requires ${ constraint } but no matching chart was found`);
437
+ }
438
+ }
439
+
440
+ this.$set(this, 'autoInstallInfo', out);
441
+ },
442
+
344
443
  selectVersion({ id: version }) {
345
444
  this.$router.applyQuery({ [VERSION]: version });
346
445
  },
@@ -361,7 +460,7 @@ export default {
361
460
  repoType: this.chart.repoType,
362
461
  repoName: this.chart.repoName,
363
462
  name: this.chart.chartName,
364
- version: this.chart.versionName,
463
+ version: this.query.versionName,
365
464
  };
366
465
 
367
466
  return {
@@ -0,0 +1,95 @@
1
+ import Vue from 'vue';
2
+ import { hasFetch, normalizeError, addLifecycleHook } from '../utils/nuxt';
3
+
4
+ const isSsrHydration = vm => vm.$vnode && vm.$vnode.elm && vm.$vnode.elm.dataset && vm.$vnode.elm.dataset.fetchKey;
5
+ const nuxtState = window.__NUXT__;
6
+
7
+ export default {
8
+ beforeCreate() {
9
+ if (!hasFetch(this)) {
10
+ return;
11
+ }
12
+
13
+ this._fetchDelay = typeof this.$options.fetchDelay === 'number' ? this.$options.fetchDelay : 200;
14
+
15
+ Vue.util.defineReactive(this, '$fetchState', {
16
+ pending: false,
17
+ error: null,
18
+ timestamp: Date.now()
19
+ });
20
+
21
+ this.$fetch = $fetch.bind(this);
22
+ addLifecycleHook(this, 'created', created);
23
+ addLifecycleHook(this, 'beforeMount', beforeMount);
24
+ }
25
+ };
26
+
27
+ function beforeMount() {
28
+ if (!this._hydrated) {
29
+ return this.$fetch();
30
+ }
31
+ }
32
+
33
+ function created() {
34
+ if (!isSsrHydration(this)) {
35
+ return;
36
+ }
37
+
38
+ // Hydrate component
39
+ this._hydrated = true;
40
+ this._fetchKey = this.$vnode.elm.dataset.fetchKey;
41
+ const data = nuxtState.fetch[this._fetchKey];
42
+
43
+ // If fetch error
44
+ if (data && data._error) {
45
+ this.$fetchState.error = data._error;
46
+
47
+ return;
48
+ }
49
+
50
+ // Merge data
51
+ for (const key in data) {
52
+ Vue.set(this.$data, key, data[key]);
53
+ }
54
+ }
55
+
56
+ function $fetch() {
57
+ if (!this._fetchPromise) {
58
+ this._fetchPromise = $_fetch.call(this)
59
+ .then(() => {
60
+ delete this._fetchPromise;
61
+ });
62
+ }
63
+
64
+ return this._fetchPromise;
65
+ }
66
+
67
+ async function $_fetch() { // eslint-disable-line camelcase
68
+ this.$nuxt.nbFetching++;
69
+ this.$fetchState.pending = true;
70
+ this.$fetchState.error = null;
71
+ this._hydrated = false;
72
+ let error = null;
73
+ const startTime = Date.now();
74
+
75
+ try {
76
+ await this.$options.fetch.call(this);
77
+ } catch (err) {
78
+ if (process.dev) {
79
+ console.error('Error in fetch():', err); // eslint-disable-line no-console
80
+ }
81
+ error = normalizeError(err);
82
+ }
83
+
84
+ const delayLeft = this._fetchDelay - (Date.now() - startTime);
85
+
86
+ if (delayLeft > 0) {
87
+ await new Promise(resolve => setTimeout(resolve, delayLeft));
88
+ }
89
+
90
+ this.$fetchState.error = error;
91
+ this.$fetchState.pending = false;
92
+ this.$fetchState.timestamp = Date.now();
93
+
94
+ this.$nextTick(() => this.$nuxt.nbFetching--);
95
+ }
@@ -0,0 +1,73 @@
1
+ import Vue from 'vue';
2
+ import {
3
+ hasFetch, normalizeError, addLifecycleHook, purifyData, createGetCounter
4
+ } from '../../utils/nuxt';
5
+
6
+ async function serverPrefetch() {
7
+ if (!this._fetchOnServer) {
8
+ return;
9
+ }
10
+
11
+ // Call and await on $fetch
12
+ try {
13
+ await this.$options.fetch.call(this);
14
+ } catch (err) {
15
+ if (process.dev) {
16
+ console.error('Error in fetch():', err); // eslint-disable-line no-console
17
+ }
18
+ this.$fetchState.error = normalizeError(err);
19
+ }
20
+ this.$fetchState.pending = false;
21
+
22
+ // Define an ssrKey for hydration
23
+ this._fetchKey = this._fetchKey || this.$ssrContext.fetchCounters['']++;
24
+
25
+ // Add data-fetch-key on parent element of Component
26
+ const attrs = this.$vnode.data.attrs = this.$vnode.data.attrs || {};
27
+
28
+ attrs['data-fetch-key'] = this._fetchKey;
29
+
30
+ // Add to ssrContext for window.__NUXT__.fetch
31
+
32
+ if (this.$ssrContext.nuxt.fetch[this._fetchKey] !== undefined) {
33
+ console.warn(`Duplicate fetch key detected (${ this._fetchKey }). This may lead to unexpected results.`); // eslint-disable-line no-console
34
+ }
35
+
36
+ this.$ssrContext.nuxt.fetch[this._fetchKey] =
37
+ this.$fetchState.error ? { _error: this.$fetchState.error } : purifyData(this._data);
38
+ }
39
+
40
+ export default {
41
+ created() {
42
+ if (!hasFetch(this)) {
43
+ return;
44
+ }
45
+
46
+ if (typeof this.$options.fetchOnServer === 'function') {
47
+ this._fetchOnServer = this.$options.fetchOnServer.call(this) !== false;
48
+ } else {
49
+ this._fetchOnServer = this.$options.fetchOnServer !== false;
50
+ }
51
+
52
+ const defaultKey = this.$options._scopeId || this.$options.name || '';
53
+ const getCounter = createGetCounter(this.$ssrContext.fetchCounters, defaultKey);
54
+
55
+ if (typeof this.$options.fetchKey === 'function') {
56
+ this._fetchKey = this.$options.fetchKey.call(this, getCounter);
57
+ } else {
58
+ const key = typeof this.$options.fetchKey === 'string' ? this.$options.fetchKey : defaultKey;
59
+
60
+ this._fetchKey = key ? `${ key }:${ getCounter(key) }` : String(getCounter(key));
61
+ }
62
+
63
+ // Added for remove vue undefined warning while ssr
64
+ this.$fetch = () => {}; // issue #8043
65
+ Vue.util.defineReactive(this, '$fetchState', {
66
+ pending: true,
67
+ error: null,
68
+ timestamp: Date.now()
69
+ });
70
+
71
+ addLifecycleHook(this, 'serverPrefetch', serverPrefetch);
72
+ }
73
+ };
@@ -122,7 +122,7 @@ export default Vue.extend({
122
122
  },
123
123
  validationMessage(): string | undefined {
124
124
  // we want to grab the required rule passed in if we can but if it's not there then we can just grab it from the formRulesGenerator
125
- const requiredRule = this.rules.find((rule: any) => rule?.name === 'required');
125
+ const requiredRule = this.rules.find((rule: any) => rule?.name === 'required') as Function;
126
126
  const ruleMessages = [];
127
127
  const value = this?.value;
128
128
 
@@ -134,7 +134,7 @@ export default Vue.extend({
134
134
  }
135
135
  }
136
136
 
137
- for (const rule of this.rules) {
137
+ for (const rule of this.rules as Function[]) {
138
138
  const message = rule(value);
139
139
 
140
140
  if (!!message && rule.name !== 'required') { // we're catching 'required' above so we can ignore it here
@@ -131,8 +131,8 @@ export default {
131
131
 
132
132
  const schema = this.$store.getters[`${ currStore }/schemaFor`](type);
133
133
 
134
- if (schema?.attributes?.namespaced) {
135
- opt.namespaced = this.namespaceFilter;
134
+ if (schema?.attributes?.namespaced) { // Is this specific resource namespaced (could be primary or secondary resource)?
135
+ opt.namespaced = this.namespaceFilter; // namespaceFilter will only be populated if applicable for primary resource
136
136
  }
137
137
 
138
138
  return this.$store.dispatch(`${ currStore }/findAll`, {
@@ -1,4 +1,6 @@
1
1
  import Workload from './workload';
2
+ import { WORKLOAD_TYPES, POD } from '@shell/config/types';
3
+ import { WORKLOAD_TYPE_TO_KIND_MAPPING } from '@shell/detail/workload/index';
2
4
 
3
5
  export default class StatefulSet extends Workload {
4
6
  async rollBack(cluster, statefulSet, revision) {
@@ -19,4 +21,30 @@ export default class StatefulSet extends Workload {
19
21
 
20
22
  await this.rollBackWorkload(cluster, statefulSet, 'statefulsets', body);
21
23
  }
24
+
25
+ // we need to provide a new pods getter for statefulsets because the relationship
26
+ // done on the parent model "workload" is not correct
27
+ get pods() {
28
+ const relationships = this.metadata?.relationships || [];
29
+ const podRelationship = relationships.filter(relationship => relationship.toType === POD)[0];
30
+
31
+ if (podRelationship) {
32
+ const pods = this.$getters['podsByNamespace'](this.metadata.namespace);
33
+
34
+ return pods.filter((pod) => {
35
+ // a bit of a duplication of podRelationship, but always safe to check...
36
+ if (pod.metadata?.ownerReferences?.length) {
37
+ const ownerReferencesStatefulSet = pod.metadata?.ownerReferences?.find(own => own.kind === WORKLOAD_TYPE_TO_KIND_MAPPING[WORKLOAD_TYPES.STATEFUL_SET]);
38
+
39
+ if (ownerReferencesStatefulSet) {
40
+ return `${ pod.metadata.namespace }/${ ownerReferencesStatefulSet.name }` === this.id;
41
+ }
42
+ }
43
+
44
+ return false;
45
+ });
46
+ }
47
+
48
+ return [];
49
+ }
22
50
  }
@@ -1,5 +1,5 @@
1
1
  import { formatPercent } from '@shell/utils/string';
2
- import { CAPI as CAPI_ANNOTATIONS, NODE_ROLES, RKE } from '@shell/config/labels-annotations.js';
2
+ import { CAPI as CAPI_ANNOTATIONS, NODE_ROLES, RKE, SYSTEM_LABELS } from '@shell/config/labels-annotations.js';
3
3
  import {
4
4
  CAPI, MANAGEMENT, METRIC, NORMAN, POD
5
5
  } from '@shell/config/types';
@@ -76,7 +76,8 @@ export default class ClusterNode extends SteveModel {
76
76
  }
77
77
 
78
78
  openSsh() {
79
- this.provisionedMachine.openSsh();
79
+ // Pass in the name of the node, so we display that rather than the name of the provisioned machine
80
+ this.provisionedMachine.openSsh(this.nameDisplay);
80
81
  }
81
82
 
82
83
  downloadKeys() {
@@ -109,6 +110,26 @@ export default class ClusterNode extends SteveModel {
109
110
  return this.metadata?.labels || {};
110
111
  }
111
112
 
113
+ get customLabelCount() {
114
+ return this.customLabels.length;
115
+ }
116
+
117
+ get customLabels() {
118
+ const parsedLabels = [];
119
+
120
+ if (this.labels) {
121
+ for (const k in this.labels) {
122
+ const [prefix] = k.split('/');
123
+
124
+ if (!SYSTEM_LABELS.includes(prefix)) {
125
+ parsedLabels.push(`${ k }=${ this.labels[k] }`);
126
+ }
127
+ }
128
+ }
129
+
130
+ return parsedLabels;
131
+ }
132
+
112
133
  get isWorker() {
113
134
  return this.managementNode ? this.managementNode.isWorker : `${ this.labels[NODE_ROLES.WORKER] }` === 'true';
114
135
  }
@@ -98,10 +98,12 @@ export default class CapiMachine extends SteveModel {
98
98
  return false;
99
99
  }
100
100
 
101
- openSsh() {
101
+ openSsh(name) {
102
+ const label = name || this.nameDisplay;
103
+
102
104
  this.$dispatch('wm/open', {
103
105
  id: `${ this.id }-ssh`,
104
- label: this.nameDisplay,
106
+ label,
105
107
  icon: 'terminal',
106
108
  component: 'MachineSsh',
107
109
  attrs: { machine: this, pod: {} }
@@ -21,4 +21,11 @@ export default class CRTB extends NormanModel {
21
21
  get clusterroletemplatebinding() {
22
22
  return this.$rootGetters[`management/byId`](MANAGEMENT.CLUSTER_ROLE_TEMPLATE_BINDING, this.id?.replace(':', '/'));
23
23
  }
24
+
25
+ get steve() {
26
+ return this.$dispatch(`management/find`, {
27
+ type: MANAGEMENT.CLUSTER_ROLE_TEMPLATE_BINDING,
28
+ id: this.id?.replace(':', '/')
29
+ }, { root: true });
30
+ }
24
31
  }
@@ -1,5 +1,6 @@
1
1
  import jsyaml from 'js-yaml';
2
2
  import SteveModel from '@shell/plugins/steve/steve-class';
3
+ import { downloadFile } from '@shell/utils/download';
3
4
 
4
5
  export const ENFORCEMENT_ACTION_VALUES = {
5
6
  DENY: 'deny',
@@ -7,21 +8,62 @@ export const ENFORCEMENT_ACTION_VALUES = {
7
8
  };
8
9
 
9
10
  export default class GateKeeperConstraint extends SteveModel {
11
+ get _availableActions() {
12
+ const out = super._availableActions;
13
+
14
+ const t = this.$rootGetters['i18n/t'];
15
+
16
+ const downloadViolations = {
17
+ action: 'downloadViolations',
18
+ icon: 'icon icon-fw icon-download',
19
+ label: t('gatekeeperConstraint.downloadViolations'),
20
+ total: 1,
21
+ };
22
+
23
+ out.unshift(downloadViolations);
24
+
25
+ return out;
26
+ }
27
+
10
28
  async save() {
11
29
  let constraint;
30
+ let resourceVersion;
12
31
 
13
32
  if (this.constraint) {
14
33
  constraint = await this.findLatestConstraint();
34
+ resourceVersion = constraint?.metadata?.resourceVersion;
15
35
  } else {
16
36
  constraint = await this.$dispatch('cluster/create', { type: `constraints.gatekeeper.sh.${ this.kind.toLowerCase() }` }, { root: true });
17
37
  }
18
38
 
19
39
  constraint.spec = this.spec;
20
40
  constraint.metadata = this.metadata;
41
+ if (resourceVersion) {
42
+ constraint.metadata.resourceVersion = resourceVersion;
43
+ }
21
44
 
22
45
  await constraint.save();
23
46
  }
24
47
 
48
+ async downloadViolations() {
49
+ const Papa = await import(/* webpackChunkName: "csv" */'papaparse');
50
+
51
+ try {
52
+ const violations = (this.violations || []).map((violation) => {
53
+ delete violation.resourceLink;
54
+ delete violation.constraintLink;
55
+
56
+ return violation;
57
+ });
58
+
59
+ const csv = Papa.unparse(violations);
60
+
61
+ downloadFile(`violations-${ this.name }.csv`, csv, 'application/csv');
62
+ } catch (err) {
63
+ this.$dispatch('growl/fromError', { title: 'Error downloading file', err }, { root: true });
64
+ }
65
+ }
66
+
25
67
  cleanForNew() {
26
68
  this.$dispatch(`cleanForNew`, this);
27
69
 
@@ -50,6 +92,10 @@ export default class GateKeeperConstraint extends SteveModel {
50
92
  }, { root: true });
51
93
  }
52
94
 
95
+ get totalViolations() {
96
+ return this.status?.totalViolations || this.violations.length;
97
+ }
98
+
53
99
  get violations() {
54
100
  const violations = this.status?.violations || [];
55
101
 
@@ -1,8 +1,9 @@
1
1
  import { MANAGEMENT, NORMAN } from '@shell/config/types';
2
+ import { CAPI, FLEET as FLEET_LABELS } from '@shell/config/labels-annotations';
3
+ import { _RKE2 } from '@shell/store/prefs';
4
+ import SteveModel from '@shell/plugins/steve/steve-class';
2
5
  import { escapeHtml } from '@shell/utils/string';
3
6
  import { insertAt } from '@shell/utils/array';
4
- import { FLEET as FLEET_LABELS } from '@shell/config/labels-annotations';
5
- import SteveModel from '@shell/plugins/steve/steve-class';
6
7
 
7
8
  export default class FleetCluster extends SteveModel {
8
9
  get _availableActions() {
@@ -32,14 +33,16 @@ export default class FleetCluster extends SteveModel {
32
33
  enabled: !!this.links.update
33
34
  });
34
35
 
35
- insertAt(out, 3, {
36
- action: 'assignTo',
37
- label: 'Change workspace',
38
- icon: 'icon icon-copy',
39
- bulkable: true,
40
- bulkAction: 'assignToBulk',
41
- enabled: !!this.links.update && !!this.mgmt,
42
- });
36
+ if (!this.isRke2) {
37
+ insertAt(out, 3, {
38
+ action: 'assignTo',
39
+ label: 'Change workspace',
40
+ icon: 'icon icon-copy',
41
+ bulkable: true,
42
+ bulkAction: 'assignToBulk',
43
+ enabled: !!this.links.update && !!this.mgmt,
44
+ });
45
+ }
43
46
 
44
47
  insertAt(out, 4, { divider: true });
45
48
 
@@ -75,6 +78,12 @@ export default class FleetCluster extends SteveModel {
75
78
  return false;
76
79
  }
77
80
 
81
+ get isRke2() {
82
+ const provider = this?.metadata?.labels?.[CAPI.PROVIDER] || this?.status?.provider;
83
+
84
+ return provider === _RKE2;
85
+ }
86
+
78
87
  get nameDisplay() {
79
88
  return this.metadata?.labels?.[FLEET_LABELS.CLUSTER_DISPLAY_NAME] || this.metadata?.name || this.id;
80
89
  }
@@ -96,9 +96,8 @@ export default class GitRepo extends SteveModel {
96
96
  const workspace = this.$getters['byId'](FLEET.WORKSPACE, this.metadata.namespace);
97
97
  const clusters = workspace?.clusters || [];
98
98
  const groups = workspace?.clusterGroups || [];
99
- const out = [];
100
99
 
101
- if ( workspace.id === 'fleet-local' ) {
100
+ if ( workspace?.id === 'fleet-local' ) {
102
101
  const local = findBy(groups, 'id', 'fleet-local/default');
103
102
 
104
103
  if ( local ) {
@@ -108,6 +107,12 @@ export default class GitRepo extends SteveModel {
108
107
  return [];
109
108
  }
110
109
 
110
+ if (!this.spec.targets) {
111
+ return [];
112
+ }
113
+
114
+ const out = [];
115
+
111
116
  for ( const tgt of this.spec.targets ) {
112
117
  if ( tgt.clusterName ) {
113
118
  const cluster = findBy(clusters, 'metadata.name', tgt.clusterName);
@@ -196,7 +196,7 @@ export default class MgmtCluster extends HybridModel {
196
196
  }
197
197
 
198
198
  get kubernetesVersionExtension() {
199
- if ( this.kubernetesVersion.match(/[+-]]/) ) {
199
+ if ( this.kubernetesVersion.match(/[+-]/) ) {
200
200
  return this.kubernetesVersion.replace(/^.*([+-])/, '$1');
201
201
  }
202
202
 
@@ -66,6 +66,18 @@ export default class Workspace extends HybridModel {
66
66
  await norman.save();
67
67
  }
68
68
 
69
+ waitForWorkspaceSchema(timeout = 20000, schemaCallback) {
70
+ return this.waitForTestFn(() => {
71
+ const schema = this.$rootGetters['management/schemaFor'](FLEET.WORKSPACE);
72
+
73
+ if (!schemaCallback) {
74
+ return schema;
75
+ }
76
+
77
+ return schemaCallback(schema);
78
+ }, this.$rootGetters['i18n/t']('fleet.workspaces.timeout'), timeout);
79
+ }
80
+
69
81
  async remove() {
70
82
  const norman = await this.norman;
71
83
 
@@ -0,0 +1,5 @@
1
+ import SteveModel from '@shell/plugins/steve/steve-class';
2
+
3
+ export default class GitRepoRestriction extends SteveModel {
4
+
5
+ }
@@ -0,0 +1,3 @@
1
+ import SteveDescriptionModel from '@shell/plugins/steve/steve-description-class';
2
+
3
+ export default class PodSecurityAdmissionTemplate extends SteveDescriptionModel { }
package/models/pod.js CHANGED
@@ -129,6 +129,10 @@ export default class Pod extends WorkloadService {
129
129
  return workloads[0];
130
130
  }
131
131
 
132
+ get ownedByWorkload() {
133
+ return !!this.workloadRef;
134
+ }
135
+
132
136
  get details() {
133
137
  const out = [
134
138
  {