@rancher/shell 0.3.29 → 0.5.0

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 (301) hide show
  1. package/assets/images/providers/ovhcloudmks.svg +122 -0
  2. package/assets/images/providers/ovhcloudpubliccloud.svg +122 -0
  3. package/assets/styles/global/_layout.scss +99 -0
  4. package/assets/translations/en-us.yaml +31 -6
  5. package/assets/translations/zh-hans.yaml +2 -2
  6. package/babel.config.js +7 -1
  7. package/chart/monitoring/alerting/index.vue +7 -21
  8. package/chart/monitoring/grafana/index.vue +55 -0
  9. package/chart/monitoring/index.vue +51 -17
  10. package/chart/monitoring/prometheus/index.vue +37 -43
  11. package/chart/rancher-backup/index.vue +2 -1
  12. package/cloud-credential/azure.vue +4 -17
  13. package/components/AsyncButton.vue +17 -5
  14. package/components/Certificates.vue +164 -0
  15. package/components/CodeMirror.vue +19 -21
  16. package/components/CopyCode.vue +6 -2
  17. package/components/CopyToClipboard.vue +2 -1
  18. package/components/CopyToClipboardText.vue +14 -9
  19. package/components/CruResource.vue +1 -0
  20. package/components/DraggableZone.vue +2 -2
  21. package/components/EtcdInfoBanner.vue +5 -5
  22. package/components/ExplorerProjectsNamespaces.vue +25 -1
  23. package/components/IconOrSvg.vue +1 -1
  24. package/components/LandingPagePreference.vue +1 -4
  25. package/components/Markdown.vue +16 -12
  26. package/components/PodSecurityAdmission.vue +2 -2
  27. package/components/Questions/index.vue +1 -1
  28. package/components/ResourceDetail/Masthead.vue +25 -9
  29. package/components/ResourceTable.vue +14 -2
  30. package/components/ResourceYaml.vue +5 -0
  31. package/components/SideNav.vue +1 -1
  32. package/components/SingleClusterInfo.vue +1 -4
  33. package/components/StatusTable.vue +5 -1
  34. package/components/Tabbed/index.vue +12 -0
  35. package/components/__tests__/CopyCode.test.ts +5 -4
  36. package/components/fleet/FleetBundles.vue +5 -11
  37. package/components/fleet/FleetRepos.vue +62 -27
  38. package/components/fleet/FleetResources.vue +6 -1
  39. package/components/fleet/FleetSummary.vue +3 -3
  40. package/components/fleet/__tests__/FleetSummary.test.ts +316 -0
  41. package/components/form/ArrayListSelect.vue +10 -0
  42. package/components/form/Error.vue +3 -3
  43. package/components/form/Footer.vue +2 -2
  44. package/components/form/GitPicker.vue +83 -38
  45. package/components/form/KeyValue.vue +4 -0
  46. package/components/form/LabeledSelect.vue +4 -0
  47. package/components/form/Password.vue +3 -1
  48. package/components/formatter/Checked.vue +11 -3
  49. package/components/formatter/FleetClusterSummaryGraph.vue +27 -0
  50. package/components/formatter/FleetSummaryGraph.vue +23 -11
  51. package/components/formatter/LiveDuration.vue +1 -1
  52. package/components/formatter/PercentageBar.vue +1 -1
  53. package/components/formatter/__tests__/Checked.test.ts +19 -0
  54. package/components/nav/Group.vue +2 -2
  55. package/components/nav/Header.vue +1 -2
  56. package/components/nav/TopLevelMenu.vue +36 -6
  57. package/components/nav/Type.vue +1 -3
  58. package/components/nav/WindowManager/ContainerLogs.vue +101 -3
  59. package/components/nav/WindowManager/ContainerShell.vue +6 -1
  60. package/components/nav/WindowManager/__tests__/ContainerLogs.test.ts +186 -0
  61. package/components/nav/WindowManager/index.vue +11 -10
  62. package/components/nav/__tests__/TopLevelMenu.test.ts +33 -0
  63. package/components/nav/__tests__/Type.test.ts +1 -1
  64. package/components/nuxt/nuxt-child.js +14 -78
  65. package/components/nuxt/nuxt.js +1 -1
  66. package/{layouts → components/templates}/blank.vue +1 -1
  67. package/{layouts → components/templates}/default.vue +8 -98
  68. package/{layouts → components/templates}/error.vue +10 -19
  69. package/{layouts → components/templates}/home.vue +4 -1
  70. package/{layouts → components/templates}/plain.vue +4 -1
  71. package/{layouts → components/templates}/standalone.vue +1 -1
  72. package/{layouts → components/templates}/unauthenticated.vue +1 -1
  73. package/composables/useCompactInput.test.ts +36 -0
  74. package/composables/useCompactInput.ts +20 -0
  75. package/composables/useLabeledFormElement.test.ts +135 -0
  76. package/composables/useLabeledFormElement.ts +138 -0
  77. package/config/harvester-manager-types.js +2 -0
  78. package/config/home-links.js +1 -1
  79. package/config/private-label.js +22 -0
  80. package/config/product/explorer.js +3 -0
  81. package/config/product/fleet.js +6 -1
  82. package/config/product/manager.js +8 -2
  83. package/config/query-params.js +1 -0
  84. package/config/router.js +385 -364
  85. package/config/settings.ts +1 -0
  86. package/config/store.js +1 -1
  87. package/config/system-namespaces.js +3 -0
  88. package/config/table-headers.js +47 -0
  89. package/core/plugin-helpers.js +3 -5
  90. package/core/plugin-routes.ts +56 -114
  91. package/core/plugin.ts +16 -10
  92. package/core/plugins-loader.js +7 -9
  93. package/core/plugins.js +0 -3
  94. package/creators/app/files/.gitlab-ci.yml +14 -0
  95. package/creators/app/init +19 -0
  96. package/detail/fleet.cattle.io.cluster.vue +11 -1
  97. package/detail/provisioning.cattle.io.cluster.vue +4 -3
  98. package/dialog/ScaleMachineDownDialog.vue +34 -17
  99. package/edit/__tests__/service.test.ts +89 -0
  100. package/edit/auth/googleoauth.vue +1 -5
  101. package/edit/cloudcredential.vue +2 -0
  102. package/edit/configmap.vue +2 -1
  103. package/edit/management.cattle.io.podsecurityadmissionconfigurationtemplate.vue +2 -2
  104. package/edit/monitoring.coreos.com.prometheusrule/AlertingRule.vue +12 -3
  105. package/edit/monitoring.coreos.com.prometheusrule/GroupRules.vue +2 -1
  106. package/edit/networking.k8s.io.networkpolicy/__tests__/PolicyRuleTarget.spec.ts +1 -1
  107. package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +15 -7
  108. package/edit/provisioning.cattle.io.cluster/__tests__/Advanced.test.ts +112 -0
  109. package/edit/provisioning.cattle.io.cluster/__tests__/Basics.test.ts +473 -0
  110. package/edit/provisioning.cattle.io.cluster/__tests__/{CustomCommand.tests.ts → CustomCommand.test.ts} +6 -0
  111. package/edit/provisioning.cattle.io.cluster/__tests__/DrainOptions.test.ts +1 -1
  112. package/edit/provisioning.cattle.io.cluster/__tests__/index.test.ts +73 -0
  113. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +7 -1
  114. package/edit/provisioning.cattle.io.cluster/__tests__/utils/cluster.ts +386 -0
  115. package/edit/provisioning.cattle.io.cluster/import.vue +2 -2
  116. package/edit/provisioning.cattle.io.cluster/index.vue +92 -36
  117. package/edit/provisioning.cattle.io.cluster/rke2.vue +171 -583
  118. package/edit/provisioning.cattle.io.cluster/tabs/AddOnConfig.vue +137 -0
  119. package/edit/provisioning.cattle.io.cluster/tabs/Advanced.vue +157 -0
  120. package/edit/provisioning.cattle.io.cluster/{Basics.vue → tabs/Basics.vue} +94 -19
  121. package/edit/provisioning.cattle.io.cluster/{MachinePool.vue → tabs/MachinePool.vue} +1 -0
  122. package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +135 -0
  123. package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +189 -0
  124. package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +144 -0
  125. package/edit/provisioning.cattle.io.cluster/tabs/upgrade/index.vue +76 -0
  126. package/edit/service.vue +12 -0
  127. package/edit/workload/Upgrading.vue +3 -2
  128. package/edit/workload/mixins/workload.js +1 -1
  129. package/edit/workload/storage/persistentVolumeClaim/persistentvolumeclaim.vue +2 -1
  130. package/initialize/App.js +25 -71
  131. package/initialize/client.js +21 -162
  132. package/initialize/index.js +47 -124
  133. package/list/management.cattle.io.feature.vue +1 -7
  134. package/list/node.vue +1 -0
  135. package/machine-config/__tests__/vmwarevsphere.test.ts +100 -21
  136. package/machine-config/vmwarevsphere.vue +73 -51
  137. package/middleware/authenticated.js +10 -17
  138. package/mixins/auth-config.js +2 -7
  139. package/mixins/brand.js +29 -41
  140. package/mixins/create-edit-view/index.js +2 -2
  141. package/mixins/labeled-form-element.ts +6 -1
  142. package/models/__tests__/management.cattle.io.cluster.test.ts +4 -0
  143. package/models/__tests__/management.cattle.io.node.ts +85 -0
  144. package/models/__tests__/management.cattle.io.nodepool.ts +83 -0
  145. package/models/__tests__/namespace.test.ts +49 -9
  146. package/models/__tests__/workload.test.ts +91 -0
  147. package/models/cluster/node.js +4 -4
  148. package/models/cluster.x-k8s.io.machinedeployment.js +14 -0
  149. package/models/fleet.cattle.io.cluster.js +4 -0
  150. package/models/fleet.cattle.io.gitrepo.js +56 -13
  151. package/models/management.cattle.io.cluster.js +7 -3
  152. package/models/management.cattle.io.kontainerdriver.js +1 -1
  153. package/models/management.cattle.io.node.js +18 -14
  154. package/models/management.cattle.io.nodepool.js +17 -0
  155. package/models/namespace.js +1 -1
  156. package/models/pod.js +20 -0
  157. package/models/provisioning.cattle.io.cluster.js +39 -4
  158. package/models/secret.js +117 -18
  159. package/models/workload.js +16 -0
  160. package/models/workload.service.js +18 -0
  161. package/package.json +11 -10
  162. package/pages/about.vue +0 -1
  163. package/pages/account/create-key.vue +0 -1
  164. package/pages/account/index.vue +0 -1
  165. package/pages/auth/login.vue +0 -1
  166. package/pages/auth/logout.vue +0 -2
  167. package/pages/auth/setup.vue +0 -4
  168. package/pages/auth/verify.vue +14 -8
  169. package/pages/c/_cluster/apps/charts/index.vue +64 -43
  170. package/pages/c/_cluster/apps/charts/install.vue +4 -4
  171. package/pages/c/_cluster/apps/index.vue +0 -2
  172. package/pages/c/_cluster/auth/index.vue +0 -2
  173. package/pages/c/_cluster/ecm/index.vue +0 -2
  174. package/pages/c/_cluster/explorer/index.vue +28 -2
  175. package/pages/c/_cluster/fleet/index.vue +1 -1
  176. package/pages/c/_cluster/index.vue +0 -2
  177. package/pages/c/_cluster/settings/banners.vue +0 -2
  178. package/pages/c/_cluster/settings/brand.vue +0 -2
  179. package/pages/c/_cluster/settings/index.vue +0 -2
  180. package/pages/c/_cluster/settings/links.vue +0 -1
  181. package/pages/c/_cluster/settings/performance.vue +0 -1
  182. package/pages/c/_cluster/uiplugins/CatalogList/CatalogLoadDialog.vue +2 -1
  183. package/pages/c/_cluster/uiplugins/CatalogList/index.vue +10 -46
  184. package/pages/c/_cluster/uiplugins/index.vue +0 -2
  185. package/pages/diagnostic.vue +1 -2
  186. package/pages/fail-whale.vue +0 -1
  187. package/pages/prefs.vue +0 -1
  188. package/pages/support/index.vue +2 -8
  189. package/pkg/auto-import.js +1 -1
  190. package/plugins/axios.js +0 -36
  191. package/plugins/back-button.js +3 -5
  192. package/plugins/clean-html-directive.js +1 -19
  193. package/plugins/clean-html.js +53 -0
  194. package/plugins/clean-tooltip-directive.js +1 -1
  195. package/plugins/codemirror-loader.js +1 -1
  196. package/plugins/codemirror.js +41 -0
  197. package/plugins/dashboard-store/__tests__/{mutations.spec.ts → mutations.test.ts} +1 -1
  198. package/plugins/dashboard-store/__tests__/resource-class.test.ts +49 -0
  199. package/plugins/dashboard-store/__tests__/utils/store-mocks.ts +7 -0
  200. package/plugins/dashboard-store/actions.js +30 -4
  201. package/plugins/dashboard-store/classify.js +1 -18
  202. package/plugins/dashboard-store/getters.js +10 -5
  203. package/plugins/dashboard-store/index.js +0 -12
  204. package/plugins/dashboard-store/mutations.js +0 -4
  205. package/plugins/dashboard-store/resource-class.js +59 -18
  206. package/plugins/index.js +11 -0
  207. package/plugins/steve/__tests__/steve-class.spec.ts +59 -0
  208. package/plugins/steve/__tests__/utils/steve-mocks.ts +31 -0
  209. package/plugins/steve/getters.js +4 -1
  210. package/plugins/steve/norman-class.js +19 -0
  211. package/plugins/steve/steve-class.js +22 -0
  212. package/plugins/steve/subscribe.js +4 -10
  213. package/rancher-components/Accordion/Accordion.test.ts +45 -0
  214. package/rancher-components/Accordion/Accordion.vue +86 -0
  215. package/rancher-components/Accordion/index.ts +1 -0
  216. package/rancher-components/BadgeState/BadgeState.vue +3 -3
  217. package/rancher-components/Banner/Banner.vue +2 -2
  218. package/rancher-components/Card/Card.vue +3 -3
  219. package/rancher-components/Form/Checkbox/Checkbox.vue +3 -3
  220. package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +18 -1
  221. package/rancher-components/Form/LabeledInput/LabeledInput.vue +65 -24
  222. package/rancher-components/Form/Radio/RadioButton.test.ts +7 -3
  223. package/rancher-components/Form/Radio/RadioButton.vue +13 -7
  224. package/rancher-components/Form/Radio/RadioGroup.test.ts +30 -0
  225. package/rancher-components/Form/Radio/RadioGroup.vue +8 -3
  226. package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +6 -4
  227. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +7 -4
  228. package/rancher-components/LabeledTooltip/LabeledTooltip.vue +9 -4
  229. package/rancher-components/StringList/StringList.test.ts +270 -0
  230. package/rancher-components/StringList/StringList.vue +65 -26
  231. package/rancher-components/components/Accordion/Accordion.test.ts +45 -0
  232. package/rancher-components/components/Accordion/Accordion.vue +86 -0
  233. package/rancher-components/components/Accordion/index.ts +1 -0
  234. package/rancher-components/components/BadgeState/BadgeState.vue +3 -3
  235. package/rancher-components/components/Banner/Banner.vue +2 -2
  236. package/rancher-components/components/Card/Card.vue +3 -3
  237. package/rancher-components/components/Form/Checkbox/Checkbox.vue +3 -3
  238. package/rancher-components/components/Form/LabeledInput/LabeledInput.test.ts +18 -1
  239. package/rancher-components/components/Form/LabeledInput/LabeledInput.vue +57 -24
  240. package/rancher-components/components/Form/Radio/RadioButton.vue +13 -7
  241. package/rancher-components/components/Form/Radio/RadioGroup.vue +4 -3
  242. package/rancher-components/components/Form/TextArea/TextAreaAutoGrow.vue +6 -4
  243. package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.vue +7 -4
  244. package/rancher-components/components/LabeledTooltip/LabeledTooltip.vue +9 -4
  245. package/rancher-components/components/StringList/StringList.vue +8 -8
  246. package/scripts/.gitlab/workflows/build-extension-catalog.gitlab-ci.yml +50 -0
  247. package/scripts/extension/bundle +19 -7
  248. package/scripts/extension/helm/scripts/package +11 -3
  249. package/scripts/extension/parse-tag-name +2 -2
  250. package/scripts/extension/publish +20 -9
  251. package/scripts/publish-shell.sh +10 -0
  252. package/scripts/test-plugins-build.sh +85 -9
  253. package/server/har-file.js +183 -0
  254. package/store/catalog.js +1 -1
  255. package/store/features.js +1 -0
  256. package/store/i18n.js +11 -0
  257. package/store/index.js +13 -15
  258. package/store/prefs.js +33 -35
  259. package/store/type-map.js +8 -7
  260. package/tsconfig.json +35 -9
  261. package/tsconfig.paths.json +21 -0
  262. package/types/shell/index.d.ts +433 -234
  263. package/types/vue-shim.d.ts +42 -0
  264. package/utils/__tests__/create-yaml.test.ts +60 -0
  265. package/utils/axios.js +0 -19
  266. package/utils/azure.js +24 -0
  267. package/utils/clipboard.js +5 -0
  268. package/utils/create-yaml.js +17 -10
  269. package/utils/git.ts +1 -1
  270. package/utils/monitoring.js +1 -1
  271. package/utils/nuxt.js +18 -39
  272. package/utils/object.js +14 -0
  273. package/utils/router.scrollBehavior.js +12 -14
  274. package/utils/time.js +1 -1
  275. package/utils/url.ts +1 -1
  276. package/vue.config.js +23 -2
  277. package/.DS_Store +0 -0
  278. package/assets/images/providers/aks-black.svg +0 -28
  279. package/assets/images/providers/aks.svg +0 -31
  280. package/edit/provisioning.cattle.io.cluster/__tests__/Basics.tests.ts +0 -234
  281. package/initialize/layouts.ts +0 -26
  282. package/mixins/fetch.server.js +0 -73
  283. package/pages/c/index.vue +0 -9
  284. package/pages/rio/mesh.vue +0 -508
  285. package/plugins/transitions.js +0 -4
  286. package/plugins/vue-clipboard2.js +0 -4
  287. package/tsconfig.default.json +0 -46
  288. package/yarn-error.log +0 -200
  289. /package/components/form/__tests__/{NameNsDescription.ts → NameNsDescription.test.ts} +0 -0
  290. /package/edit/networking.k8s.io.networkpolicy/__tests__/utils/{selectors.ts → selectors.test.ts} +0 -0
  291. /package/edit/provisioning.cattle.io.cluster/{AgentConfiguration.vue → tabs/AgentConfiguration.vue} +0 -0
  292. /package/edit/provisioning.cattle.io.cluster/{MemberRoles.vue → tabs/MemberRoles.vue} +0 -0
  293. /package/edit/provisioning.cattle.io.cluster/{S3Config.vue → tabs/etcd/S3Config.vue} +0 -0
  294. /package/edit/provisioning.cattle.io.cluster/{ACE.vue → tabs/networking/ACE.vue} +0 -0
  295. /package/edit/provisioning.cattle.io.cluster/{RegistryConfigs.vue → tabs/registries/RegistryConfigs.vue} +0 -0
  296. /package/edit/provisioning.cattle.io.cluster/{RegistryMirrors.vue → tabs/registries/RegistryMirrors.vue} +0 -0
  297. /package/edit/provisioning.cattle.io.cluster/{DrainOptions.vue → tabs/upgrade/DrainOptions.vue} +0 -0
  298. /package/plugins/dashboard-store/__tests__/{actions.spec.ts → actions.test.ts} +0 -0
  299. /package/plugins/dashboard-store/__tests__/{getters.spec.ts → getters.test.ts} +0 -0
  300. /package/rancher-components/BadgeState/{BadgeState.spec.ts → BadgeState.test.ts} +0 -0
  301. /package/rancher-components/components/BadgeState/{BadgeState.spec.ts → BadgeState.test.ts} +0 -0
@@ -1,4 +1,3 @@
1
- import Vue from 'vue';
2
1
  import { CATALOG, CLUSTER_BADGE } from '@shell/config/labels-annotations';
3
2
  import { NODE, FLEET, MANAGEMENT, CAPI } from '@shell/config/types';
4
3
  import { insertAt, addObject, removeObject } from '@shell/utils/array';
@@ -15,6 +14,7 @@ import HybridModel from '@shell/plugins/steve/hybrid-class';
15
14
  import { LINUX, WINDOWS } from '@shell/store/catalog';
16
15
  import { KONTAINER_TO_DRIVER } from './management.cattle.io.kontainerdriver';
17
16
  import { PINNED_CLUSTERS } from '@shell/store/prefs';
17
+ import { copyTextToClipboard } from '@shell/utils/clipboard';
18
18
 
19
19
  // See translation file cluster.providers for list of providers
20
20
  // If the logo is not named with the provider name, add an override here
@@ -408,9 +408,13 @@ export default class MgmtCluster extends HybridModel {
408
408
  }
409
409
 
410
410
  async copyKubeConfig() {
411
- const config = await this.generateKubeConfig();
411
+ try {
412
+ const config = await this.generateKubeConfig();
412
413
 
413
- Vue.prototype.$copyText(config);
414
+ if (config) {
415
+ await copyTextToClipboard(config);
416
+ }
417
+ } catch {}
414
418
  }
415
419
 
416
420
  async fetchNodeMetrics() {
@@ -1,6 +1,6 @@
1
1
  import HybridModel from '@shell/plugins/steve/hybrid-class';
2
2
 
3
- const HIDDEN = ['rke', 'rancherkubernetesengine'];
3
+ const HIDDEN = ['rke', 'rancherkubernetesengine', 'azureaks'];
4
4
  const V2 = ['amazoneks', 'googlegke', 'azureaks'];
5
5
  const IMPORTABLE = ['amazoneks', 'googlegke', 'azureaks'];
6
6
 
@@ -8,6 +8,7 @@ import { insertAt } from '@shell/utils/array';
8
8
  import { downloadUrl } from '@shell/utils/download';
9
9
  import findLast from 'lodash/findLast';
10
10
  import HybridModel from '@shell/plugins/steve/hybrid-class';
11
+ import { notOnlyOfRole } from '@shell/models/cluster.x-k8s.io.machine';
11
12
 
12
13
  export default class MgmtNode extends HybridModel {
13
14
  get _availableActions() {
@@ -21,11 +22,12 @@ export default class MgmtNode extends HybridModel {
21
22
  };
22
23
 
23
24
  const scaleDown = {
24
- action: 'scaleDown',
25
- enabled: !!this.canScaleDown,
26
- icon: 'icon icon-minus icon-fw',
27
- label: this.t('node.actions.scaleDown'),
28
- bulkable: true,
25
+ action: 'scaleDown',
26
+ bulkAction: 'scaleDown',
27
+ enabled: !!this.canScaleDown,
28
+ icon: 'icon icon-minus icon-fw',
29
+ label: this.t('node.actions.scaleDown'),
30
+ bulkable: true,
29
31
  };
30
32
 
31
33
  insertAt(out, 0, { divider: true });
@@ -105,12 +107,12 @@ export default class MgmtNode extends HybridModel {
105
107
  }
106
108
  }
107
109
 
108
- async scaleDown(resources) {
109
- const safeResources = Array.isArray(resources) ? resources : [this];
110
-
111
- await Promise.all(safeResources.map((node) => {
112
- return node.norman?.doAction('scaledown');
113
- }));
110
+ async scaleDown(resources = this) {
111
+ this.$dispatch('promptModal', {
112
+ resources,
113
+ component: 'ScaleMachineDownDialog',
114
+ modalWidth: '450px'
115
+ });
114
116
  }
115
117
 
116
118
  get provisioningCluster() {
@@ -166,10 +168,12 @@ export default class MgmtNode extends HybridModel {
166
168
  }
167
169
 
168
170
  get canScaleDown() {
169
- const isInOnlyPool = this.pool?.provisioningCluster?.pools?.length === 1;
170
- const isOnlyNode = this.pool?.nodes?.length === 1;
171
+ if (!this.isEtcd && !this.isControlPlane) {
172
+ return true;
173
+ }
174
+
171
175
  const hasAction = this.norman?.actions?.scaledown;
172
176
 
173
- return hasAction && (!isInOnlyPool || !isOnlyNode);
177
+ return hasAction && notOnlyOfRole(this, this.provisioningCluster?.nodes);
174
178
  }
175
179
  }
@@ -1,6 +1,7 @@
1
1
  import { CAPI, MANAGEMENT, NORMAN } from '@shell/config/types';
2
2
  import { sortBy } from '@shell/utils/sort';
3
3
  import HybridModel from '@shell/plugins/steve/hybrid-class';
4
+ import { notOnlyOfRole } from '@shell/models/cluster.x-k8s.io.machine';
4
5
 
5
6
  export default class MgmtNodePool extends HybridModel {
6
7
  get nodeTemplate() {
@@ -161,6 +162,22 @@ export default class MgmtNodePool extends HybridModel {
161
162
  return this.norman?.hasLink('update');
162
163
  }
163
164
 
165
+ get isControlPlane() {
166
+ return this.spec?.controlPlane === true;
167
+ }
168
+
169
+ get isEtcd() {
170
+ return this.spec?.etcd === true;
171
+ }
172
+
173
+ canScaleDownPool() {
174
+ if (!this.isEtcd && !this.isControlPlane) {
175
+ return true;
176
+ }
177
+
178
+ return notOnlyOfRole(this, this?.provisioningCluster?.nodes);
179
+ }
180
+
164
181
  remove() {
165
182
  return this.norman?.remove();
166
183
  }
@@ -87,7 +87,7 @@ export default class Namespace extends SteveModel {
87
87
  return true;
88
88
  }
89
89
 
90
- if ( this.metadata.name.endsWith('-system') ) {
90
+ if ( this.metadata.name.startsWith('cattle-') && this.metadata.name.endsWith('-system') ) {
91
91
  return true;
92
92
  }
93
93
 
package/models/pod.js CHANGED
@@ -3,6 +3,7 @@ import { colorForState, stateDisplay } from '@shell/plugins/dashboard-store/reso
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
+ import { deleteProperty } from '@shell/utils/object';
6
7
 
7
8
  export const WORKLOAD_PRIORITY = {
8
9
  [WORKLOAD_TYPES.DEPLOYMENT]: 1,
@@ -256,4 +257,23 @@ export default class Pod extends WorkloadService {
256
257
  return Promise.reject(e);
257
258
  });
258
259
  }
260
+
261
+ cleanForSave(data) {
262
+ const val = super.cleanForSave(data);
263
+
264
+ // remove fields from containers
265
+ val.spec?.containers?.forEach((container) => {
266
+ this.cleanContainerForSave(container);
267
+ });
268
+
269
+ // remove fields from initContainers
270
+ val.spec?.initContainers?.forEach((container) => {
271
+ this.cleanContainerForSave(container);
272
+ });
273
+
274
+ // This is probably added by generic workload components that shouldn't be added to pods
275
+ deleteProperty(val, 'spec.selector');
276
+
277
+ return val;
278
+ }
259
279
  }
@@ -1,5 +1,5 @@
1
1
  import {
2
- CAPI, MANAGEMENT, NORMAN, SNAPSHOT, HCI
2
+ CAPI, MANAGEMENT, NAMESPACE, NORMAN, SNAPSHOT, HCI, LOCAL_CLUSTER
3
3
  } from '@shell/config/types';
4
4
  import SteveModel from '@shell/plugins/steve/steve-class';
5
5
  import { findBy } from '@shell/utils/array';
@@ -180,6 +180,16 @@ export default class ProvCluster extends SteveModel {
180
180
  return out;
181
181
  }
182
182
 
183
+ async findNormanCluster() {
184
+ const name = this.status?.clusterName;
185
+
186
+ if ( !name ) {
187
+ return null;
188
+ }
189
+
190
+ return await this.$dispatch('rancher/find', { type: NORMAN.CLUSTER, id: name }, { root: true });
191
+ }
192
+
183
193
  explore() {
184
194
  const location = {
185
195
  name: 'c-cluster',
@@ -284,7 +294,7 @@ export default class ProvCluster extends SteveModel {
284
294
  }
285
295
 
286
296
  get isK3s() {
287
- return this.mgmt?.status?.provider === 'k3s';
297
+ return this.mgmt?.status ? this.mgmt?.status.provider === 'k3s' : (this.spec?.kubernetesVersion || '').includes('k3s') ;
288
298
  }
289
299
 
290
300
  get isRke2() {
@@ -827,11 +837,11 @@ export default class ProvCluster extends SteveModel {
827
837
  get agentConfig() {
828
838
  // The one we want is the first one with no selector.
829
839
  // If there are multiple with no selector, that will fall under the unsupported message below.
830
- return this.spec.rkeConfig.machineSelectorConfig.find((x) => !x.machineLabelSelector).config;
840
+ return this.spec.rkeConfig.machineSelectorConfig.find((x) => !x.machineLabelSelector)?.config;
831
841
  }
832
842
 
833
843
  get cloudProvider() {
834
- return this.agentConfig['cloud-provider-name'];
844
+ return this.agentConfig?.['cloud-provider-name'];
835
845
  }
836
846
 
837
847
  get canClone() {
@@ -883,4 +893,29 @@ export default class ProvCluster extends SteveModel {
883
893
  get hasError() {
884
894
  return this.status?.conditions?.some((condition) => condition.error === true);
885
895
  }
896
+
897
+ get namespaceLocation() {
898
+ const localCluster = this.$rootGetters['management/byId'](MANAGEMENT.CLUSTER, LOCAL_CLUSTER);
899
+
900
+ if (localCluster) {
901
+ return {
902
+ name: 'c-cluster-product-resource-id',
903
+ params: {
904
+ cluster: localCluster.id,
905
+ product: this.$rootGetters['productId'],
906
+ resource: NAMESPACE,
907
+ id: this.namespace
908
+ }
909
+ };
910
+ }
911
+
912
+ return null;
913
+ }
914
+
915
+ // JSON Paths that should be folded in the YAML editor by default
916
+ get yamlFolding() {
917
+ return [
918
+ 'spec.rkeConfig.machinePools.dynamicSchemaSpec',
919
+ ];
920
+ }
886
921
  }
package/models/secret.js CHANGED
@@ -6,6 +6,9 @@ import { SERVICE_ACCOUNT } from '@shell/config/types';
6
6
  import { set } from '@shell/utils/object';
7
7
  import { NAME as MANAGER } from '@shell/config/product/manager';
8
8
  import SteveModel from '@shell/plugins/steve/steve-class';
9
+ import { colorForState, stateDisplay, STATES_ENUM } from '@shell/plugins/dashboard-store/resource-class';
10
+ import { diffFrom } from '@shell/utils/time';
11
+ import day from 'dayjs';
9
12
 
10
13
  export const TYPES = {
11
14
  OPAQUE: 'Opaque',
@@ -23,7 +26,12 @@ export const TYPES = {
23
26
  RKE_AUTH_CONFIG: 'rke.cattle.io/auth-config'
24
27
  };
25
28
 
29
+ /** Class a cert as expiring if in eight days */
30
+ const certExpiringPeriod = 1000 * 60 * 60 * 24 * 8;
31
+
26
32
  export default class Secret extends SteveModel {
33
+ _cachedCertInfo;
34
+
27
35
  get hasSensitiveData() {
28
36
  return true;
29
37
  }
@@ -46,7 +54,7 @@ export default class Secret extends SteveModel {
46
54
  if (annotations[CERTMANAGER.ISSUER]) {
47
55
  return annotations[CERTMANAGER.ISSUER];
48
56
  } else if (this.isCertificate) {
49
- return this.certInfo?.issuer;
57
+ return this.cachedCertInfo?.issuer;
50
58
  } else {
51
59
  return null;
52
60
  }
@@ -54,7 +62,7 @@ export default class Secret extends SteveModel {
54
62
 
55
63
  get notAfter() {
56
64
  if (this.isCertificate) {
57
- return this.certInfo?.notAfter;
65
+ return this.cachedCertInfo?.notAfter;
58
66
  } else {
59
67
  return null;
60
68
  }
@@ -62,7 +70,7 @@ export default class Secret extends SteveModel {
62
70
 
63
71
  get cn() {
64
72
  if (this.isCertificate) {
65
- return this.certInfo?.cn;
73
+ return this.cachedCertInfo?.cn;
66
74
  }
67
75
 
68
76
  return null;
@@ -80,14 +88,13 @@ export default class Secret extends SteveModel {
80
88
  // use text-warning' or 'text-error' if cert is expiring within 8 days or is expired
81
89
  get dateClass() {
82
90
  if (this.isCertificate) {
83
- const eightDays = 691200000;
84
-
85
- if (this.timeTilExpiration > eightDays ) {
86
- return '';
87
- } else if (this.timeTilExpiration > 0) {
91
+ switch (this.certState) {
92
+ case STATES_ENUM.EXPIRING:
88
93
  return 'text-warning';
89
- } else {
94
+ case STATES_ENUM.EXPIRED:
90
95
  return 'text-error';
96
+ default:
97
+ return '';
91
98
  }
92
99
  }
93
100
 
@@ -248,7 +255,7 @@ export default class Secret extends SteveModel {
248
255
  // parse TLS certs and return issuer, notAfter, cn, sans
249
256
  get certInfo() {
250
257
  const pem = base64Decode(this.data['tls.crt']);
251
- let issuer, notAfter, cn, sans, x;
258
+ let issuer, notBefore, notAfter, cn, sans, x;
252
259
  const END_MARKER = '-----END CERTIFICATE-----';
253
260
 
254
261
  if (pem) {
@@ -266,6 +273,7 @@ export default class Secret extends SteveModel {
266
273
  const issuerString = x.getIssuerString();
267
274
 
268
275
  issuer = issuerString.slice(issuerString.indexOf('CN=') + 3);
276
+ notBefore = r.zulutodate(x.getNotBefore());
269
277
  notAfter = r.zulutodate(x.getNotAfter());
270
278
 
271
279
  const cnString = x.getSubjectString();
@@ -281,25 +289,39 @@ export default class Secret extends SteveModel {
281
289
  sans = [];
282
290
  }
283
291
 
284
- return {
285
- issuer, notAfter, cn, sans
292
+ const certInfo = {
293
+ issuer, notBefore, notAfter, cn, sans
286
294
  };
295
+
296
+ return certInfo;
287
297
  }
288
298
 
289
299
  return null;
290
300
  }
291
301
 
302
+ get cachedCertInfo() {
303
+ if (!this._cachedCertInfo) {
304
+ this._cachedCertInfo = this.certInfo;
305
+ }
306
+
307
+ return this._cachedCertInfo;
308
+ }
309
+
292
310
  // use for + n more name display
293
311
  get unrepeatedSans() {
294
312
  if (this._type === TYPES.TLS ) {
295
- if (this.certInfo?.sans?.filter) {
296
- const commonBases = this.certInfo?.sans.filter((name) => name.indexOf('*.') === 0 || name.indexOf('www.') === 0).map((name) => name.substr(name.indexOf('.')));
297
- const displaySans = removeObjects(this.certInfo?.sans, commonBases);
313
+ const certInfo = this.cachedCertInfo;
314
+
315
+ if (certInfo?.sans?.filter) {
316
+ const commonBases = certInfo?.sans
317
+ .filter((name) => name.indexOf('*.') === 0 || name.indexOf('www.') === 0)
318
+ .map((name) => name.substr(name.indexOf('.')));
319
+ const displaySans = removeObjects(certInfo?.sans, commonBases);
298
320
 
299
321
  return displaySans;
300
322
  }
301
323
 
302
- return this.certInfo?.sans || [];
324
+ return certInfo?.sans?.array || certInfo?.sans || [];
303
325
  }
304
326
 
305
327
  return null;
@@ -307,16 +329,28 @@ export default class Secret extends SteveModel {
307
329
 
308
330
  get timeTilExpiration() {
309
331
  if (this._type === TYPES.TLS) {
310
- const expiration = this.certInfo.notAfter;
332
+ const certInfo = this.cachedCertInfo;
333
+
334
+ if (!certInfo?.notAfter) {
335
+ return null;
336
+ }
337
+
338
+ const expiration = certInfo.notAfter;
311
339
  const timeThen = expiration.valueOf();
312
340
  const timeNow = Date.now();
313
341
 
314
- return timeThen - timeNow;
342
+ const timeTilExpiration = timeThen - timeNow;
343
+
344
+ return timeTilExpiration < 0 ? 0 : timeTilExpiration;
315
345
  }
316
346
 
317
347
  return null;
318
348
  }
319
349
 
350
+ get timeTilExpirationDate() {
351
+ return this.timeTilExpiration > 0 ? this.cachedCertInfo?.notAfter?.valueOf() : null;
352
+ }
353
+
320
354
  get decodedData() {
321
355
  const out = {};
322
356
 
@@ -357,4 +391,69 @@ export default class Secret extends SteveModel {
357
391
  return 'c-cluster-product-resource';
358
392
  }
359
393
  }
394
+
395
+ get certLifetime() {
396
+ if (this._type === TYPES.TLS) {
397
+ const certInfo = this.cachedCertInfo;
398
+
399
+ if (certInfo) {
400
+ return diffFrom(day(certInfo.notBefore), day(certInfo.notAfter), (key, args) => this.t(key, args)).string;
401
+ }
402
+ }
403
+
404
+ return null;
405
+ }
406
+
407
+ /**
408
+ * Get the model `state` for secrets of type cert
409
+ */
410
+ get certState() {
411
+ if (this._type !== TYPES.TLS) {
412
+ return undefined;
413
+ }
414
+
415
+ if (typeof this.timeTilExpiration !== 'number' || this.timeTilExpiration > certExpiringPeriod ) {
416
+ return '';
417
+ } else if (this.timeTilExpiration > 0) {
418
+ return STATES_ENUM.EXPIRING;
419
+ } else {
420
+ return STATES_ENUM.EXPIRED;
421
+ }
422
+ }
423
+
424
+ /**
425
+ * Get the model `state display` for secrets of type cert
426
+ */
427
+ get certStateDisplay() {
428
+ if (this._type !== TYPES.TLS) {
429
+ return undefined;
430
+ }
431
+
432
+ return stateDisplay(this.certState);
433
+ }
434
+
435
+ /**
436
+ * Get the model `state background` for secrets of type cert
437
+ */
438
+ get certStateBackground() {
439
+ if (this._type !== TYPES.TLS) {
440
+ return undefined;
441
+ }
442
+
443
+ const color = colorForState(this.certState);
444
+
445
+ return color.replace('text-', 'bg-');
446
+ }
447
+
448
+ cleanForSave(data, forNew) {
449
+ const val = super.cleanForSave(data, forNew);
450
+
451
+ // Secrets on create with _type will return validation error
452
+ // Secrets on edit without _type will return http error
453
+ if (forNew) {
454
+ delete val._type;
455
+ }
456
+
457
+ return val;
458
+ }
360
459
  }
@@ -649,4 +649,20 @@ export default class Workload extends WorkloadService {
649
649
 
650
650
  return matching(allInNamespace, selector);
651
651
  }
652
+
653
+ cleanForSave(data) {
654
+ const val = super.cleanForSave(data);
655
+
656
+ // remove fields from containers
657
+ val.spec?.template?.spec?.containers?.forEach((container) => {
658
+ this.cleanContainerForSave(container);
659
+ });
660
+
661
+ // remove fields from initContainers
662
+ val.spec?.template?.spec?.initContainers?.forEach((container) => {
663
+ this.cleanContainerForSave(container);
664
+ });
665
+
666
+ return val;
667
+ }
652
668
  }
@@ -320,4 +320,22 @@ export default class WorkloadService extends SteveModel {
320
320
 
321
321
  return { toSave, toRemove };
322
322
  }
323
+
324
+ cleanForSave(data) {
325
+ const val = super.cleanForSave(data);
326
+
327
+ delete val.__active;
328
+ delete val.type;
329
+
330
+ return val;
331
+ }
332
+
333
+ cleanContainerForSave(container) {
334
+ delete container.__active;
335
+ delete container.active;
336
+ delete container._init;
337
+ delete container.error;
338
+
339
+ return container;
340
+ }
323
341
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rancher/shell",
3
- "version": "0.3.29",
3
+ "version": "0.5.0",
4
4
  "description": "Rancher Dashboard Shell",
5
5
  "repository": "https://github.com/rancherlabs/dashboard",
6
6
  "license": "Apache-2.0",
@@ -116,11 +116,11 @@
116
116
  "start-server-and-test": "1.13.1",
117
117
  "style-loader": "1.2.1",
118
118
  "ts-node": "8.10.2",
119
- "typescript": "4.1.6",
119
+ "typescript": "4.5.5",
120
120
  "url-parse": "1.5.10",
121
121
  "v-tooltip": "2.0.3",
122
122
  "vue": "2.7.14",
123
- "vue-clipboard2": "0.3.1",
123
+ "clipboard-polyfill": "4.0.1",
124
124
  "vue-codemirror": "4.0.6",
125
125
  "vue-js-modal": "1.3.35",
126
126
  "vue-resize": "0.4.5",
@@ -129,16 +129,16 @@
129
129
  "vue-shortkey": "3.1.7",
130
130
  "vue-template-compiler": "2.7.14",
131
131
  "vue-virtual-scroll-list": "^2.3.4",
132
- "vue2-transitions": "0.3.0",
133
132
  "vuedraggable": "2.24.3",
134
133
  "vuex": "3.6.2",
135
134
  "webpack-bundle-analyzer": "4.5.0",
136
135
  "webpack-virtual-modules": "0.4.3",
137
- "xterm": "5.0.0",
138
- "xterm-addon-fit": "0.6.0",
139
- "xterm-addon-search": "0.10.0",
140
- "xterm-addon-web-links": "0.7.0",
141
- "xterm-addon-webgl": "0.13.0",
136
+ "xterm": "5.2.1",
137
+ "xterm-addon-canvas": "^0.5.0",
138
+ "xterm-addon-fit": "0.8.0",
139
+ "xterm-addon-search": "0.13.0",
140
+ "xterm-addon-web-links": "0.9.0",
141
+ "xterm-addon-webgl": "0.16.0",
142
142
  "worker-loader": "3.0.8",
143
143
  "yarn": "1.22.18"
144
144
  },
@@ -151,7 +151,8 @@
151
151
  "qs": ">=6.7.3",
152
152
  "nth-check": ">=2.0.1",
153
153
  "follow-redirects": ">=1.14.7",
154
- "merge": ">=2.1.1"
154
+ "merge": ">=2.1.1",
155
+ "semver": ">=7.5.2"
155
156
  },
156
157
  "nyc": {
157
158
  "extension": [
package/pages/about.vue CHANGED
@@ -9,7 +9,6 @@ import { downloadFile } from '@shell/utils/download';
9
9
  import { mapGetters } from 'vuex';
10
10
 
11
11
  export default {
12
- layout: 'plain',
13
12
  components: { BackLink, Loading },
14
13
  mixins: [BackRoute],
15
14
  async fetch() {
@@ -3,7 +3,6 @@ import ResourceDetail from '@shell/components/ResourceDetail';
3
3
 
4
4
  export default {
5
5
  name: 'APIKeyCreate',
6
- layout: 'plain',
7
6
  components: { ResourceDetail },
8
7
  };
9
8
  </script>
@@ -15,7 +15,6 @@ import CopyToClipboardText from '@shell/components/CopyToClipboardText';
15
15
  const API_ENDPOINT = '/v3';
16
16
 
17
17
  export default {
18
- layout: 'plain',
19
18
  components: {
20
19
  CopyToClipboardText, BackLink, Banner, PromptChangePassword, Loading, ResourceTable, Principal
21
20
  },
@@ -29,7 +29,6 @@ import loadPlugins from '@shell/plugins/plugin';
29
29
 
30
30
  export default {
31
31
  name: 'Login',
32
- layout: 'unauthenticated',
33
32
  components: {
34
33
  LabeledInput, AsyncButton, Checkbox, BrandImage, Banner, InfoBox, CopyCode, Password, LocaleSelector
35
34
  },
@@ -1,8 +1,6 @@
1
1
  <script>
2
2
 
3
3
  export default {
4
- layout: 'unauthenticated',
5
-
6
4
  async asyncData({ redirect, store, router }) {
7
5
  await store.dispatch('auth/logout', null, { root: true });
8
6
  }
@@ -38,8 +38,6 @@ const calcMustChangePassword = async(store) => {
38
38
  };
39
39
 
40
40
  export default {
41
- layout: 'unauthenticated',
42
-
43
41
  mixins: [FormValidation],
44
42
 
45
43
  data() {
@@ -146,8 +144,6 @@ export default {
146
144
 
147
145
  if (serverUrlSetting?.value) {
148
146
  serverUrl = serverUrlSetting.value;
149
- } else if ( process.server ) {
150
- serverUrl = req.headers.host;
151
147
  } else {
152
148
  serverUrl = window.location.origin;
153
149
  }