@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
@@ -77,6 +77,7 @@ export const SETTING = {
77
77
  FAVICON: 'ui-favicon',
78
78
  UI_PERFORMANCE: 'ui-performance',
79
79
  UI_CUSTOM_LINKS: 'ui-custom-links',
80
+ UI_SUPPORTED_K8S_VERSIONS: 'ui-k8s-supported-versions-range',
80
81
  /**
81
82
  * Allow the backend to force a light/dark theme. Used in non-rancher world and results in the theme used
82
83
  * both pre and post log in. If not present defaults to the usual process
package/config/store.js CHANGED
@@ -40,7 +40,7 @@ let store = {};
40
40
 
41
41
  // If the environment supports hot reloading...
42
42
 
43
- if (process.client && module.hot) {
43
+ if (module.hot) {
44
44
  // Whenever any Vuex module is updated...
45
45
  module.hot.accept([
46
46
  '../store/action-menu.js',
@@ -12,4 +12,7 @@ export default [
12
12
  'linkerd',
13
13
  'security-scan',
14
14
  'tekton-pipelines',
15
+ 'cis-operator-system',
16
+ 'istio-system',
17
+ 'longhorn-system',
15
18
  ];
@@ -706,6 +706,29 @@ export const FLEET_SUMMARY = {
706
706
  width: 100,
707
707
  };
708
708
 
709
+ export const FLEET_REPO_CLUSTER_SUMMARY = {
710
+ name: 'clusterSummary',
711
+ labelKey: 'tableHeaders.clusterResources',
712
+ value: 'status.resourceCounts',
713
+ sort: false,
714
+ search: false,
715
+ formatter: 'FleetClusterSummaryGraph',
716
+ align: 'center',
717
+ width: 100,
718
+ };
719
+
720
+ export const FLEET_REPO_PER_CLUSTER_STATE = {
721
+ name: 'perClusterState',
722
+ labelKey: 'tableHeaders.repoPerClusterState',
723
+ tooltip: 'tableHeaders.repoPerClusterStateTooltip',
724
+ sort: ['stateSort', 'nameSort'],
725
+ width: 100,
726
+ default: 'unknown',
727
+ formatter: 'BadgeStateFormatter',
728
+ formatterOpts: { arbitrary: true }
729
+
730
+ };
731
+
709
732
  export const APP_SUMMARY = {
710
733
  name: 'summary',
711
734
  labelKey: 'tableHeaders.resources',
@@ -971,6 +994,30 @@ export const FLEET_BUNDLE_TYPE = {
971
994
  width: 100,
972
995
  };
973
996
 
997
+ export const FLEET_REPO_CLUSTERS_READY = {
998
+ name: 'clustersReady',
999
+ labelKey: 'tableHeaders.clustersReady',
1000
+ value: 'status.readyClusters',
1001
+ sort: 'status.readyClusters',
1002
+ search: false,
1003
+ };
1004
+
1005
+ export const FLEET_REPO_TARGET = {
1006
+ name: 'target',
1007
+ labelKey: 'tableHeaders.target',
1008
+ value: 'targetInfo.modeDisplay',
1009
+ sort: ['targetInfo.modeDisplay', 'targetInfo.cluster', 'targetInfo.clusterGroup'],
1010
+
1011
+ };
1012
+
1013
+ export const FLEET_REPO = {
1014
+ name: 'repo',
1015
+ labelKey: 'tableHeaders.repo',
1016
+ value: 'repoDisplay',
1017
+ sort: 'repoDisplay',
1018
+ search: ['spec.repo', 'status.commit'],
1019
+ };
1020
+
974
1021
  export const UI_PLUGIN_CATALOG = [
975
1022
  {
976
1023
  name: 'state',
@@ -7,13 +7,11 @@ import {
7
7
  import { getProductFromRoute } from '@shell/middleware/authenticated';
8
8
  import { isEqual } from '@shell/utils/object';
9
9
 
10
- function checkRouteProduct({ name, params, query }, locationConfigParam) {
11
- const product = getProductFromRoute({
12
- name, params, query
13
- });
10
+ function checkRouteProduct($route, locationConfigParam) {
11
+ const product = getProductFromRoute($route);
14
12
 
15
13
  // alias for the homepage
16
- if (locationConfigParam === 'home' && name === 'home') {
14
+ if (locationConfigParam === 'home' && $route.name === 'home') {
17
15
  return true;
18
16
  } else if (locationConfigParam === product) {
19
17
  return true;
@@ -6,20 +6,8 @@ interface RouteInfo {
6
6
  route: RouteConfig;
7
7
  }
8
8
 
9
- interface RouteInstallInfo {
10
- plugin: string;
11
- route: RouteConfig;
12
- }
13
-
14
- type RouteInstallHistory = {
15
- [route: string]: RouteInstallInfo[]
16
- }
17
-
18
9
  export class PluginRoutes {
19
10
  router: Router;
20
- pluginRoutes: RouteConfig[] = [];
21
-
22
- replacedRoutes: RouteInstallHistory = {};
23
11
 
24
12
  constructor(router: Router) {
25
13
  this.router = router;
@@ -34,70 +22,25 @@ export class PluginRoutes {
34
22
  });
35
23
  }
36
24
 
37
- // Ensure we put back any routes that the plugin that is being uninstalled added
38
- public uninstall(plugin: any) {
39
- // List of routes we need to restore
40
- const restore: RouteInfo[] = [];
41
-
42
- Object.keys(this.replacedRoutes).forEach((routeName) => {
43
- const info = this.replacedRoutes[routeName];
44
-
45
- for (let index = 0; index < info.length; index++) {
46
- const savedRoute = info[index];
47
-
48
- if (savedRoute.plugin === plugin.id) {
49
- // The plugin that is being uninstalled replaced an existing route that we will restore
50
- if (index === 0) {
51
- // Need to restore the previous route, since the plugin owned the active route
52
- info.shift();
53
-
54
- restore.push({ route: savedRoute.route });
55
-
56
- break;
57
- } else {
58
- // Need to update the previous item so that when it is removed, it restores the correct route
59
- const previous = info[index - 1];
60
-
61
- previous.route = savedRoute.route;
62
- info.splice(index, 1);
63
-
64
- break;
65
- }
66
- }
67
- }
68
- });
69
-
70
- // Remove routes from pluginRoutes, update matcher (to avoid dupes when re-adding plugin routes)
71
- this.pluginRoutes = this.pluginRoutes.filter((pR) => !plugin.routes.find((r: any) => pR === r.route));
72
- this.updateMatcher([], [
73
- ...this.pluginRoutes,
74
- ...(this.router.options.routes || [])
75
- ]);
76
-
77
- // Restore appropriate routes
78
- if (restore.length > 0) {
79
- this.addRoutes(null, restore);
80
- }
81
- }
82
-
83
- public addRoutes(plugin: any, routes: RouteInfo[]) {
25
+ public addRoutes(plugin: any, newRouteInfos: RouteInfo[]) {
84
26
  const allRoutes = [
85
- ...this.pluginRoutes,
86
27
  ...(this.router.options.routes || [])
87
28
  ];
88
29
 
89
30
  // Need to take into account if routes are being replaced
90
31
  // Despite what the docs say, routes are not replaced, so we use a workaround
91
32
  // Remove all routes that are being replaced
92
- routes.forEach((r: RouteInfo) => {
33
+ const newRoutes = newRouteInfos.map((ri) => ri.route);
34
+
35
+ this.forEachNestedRoutes(newRoutes, (r: RouteConfig) => {
93
36
  // Patch colliding legacy routes that start /:product
94
- if (r.route.path?.startsWith('/:product')) {
37
+ if (r.path?.startsWith('/:product')) {
95
38
  // Legacy pattern used by extensions - routes may collide, so modify them not to
96
39
  let productName;
97
40
 
98
41
  // If the route has a name (which is always the case for the extensions we have written), use it to get the product name
99
- if (r.route.name) {
100
- const nameParts = r.route.name.split('-');
42
+ if (r.name) {
43
+ const nameParts = r.name.split('-');
101
44
 
102
45
  // First part of the route name is the product name
103
46
  productName = nameParts[0];
@@ -107,74 +50,40 @@ export class PluginRoutes {
107
50
  productName = productName || plugin.name;
108
51
 
109
52
  // Replace the path - removing :product and using the actual product name instead - this avoids route collisions
110
- r.route.path = `/${ productName }${ r.route.path.substr(9) }`;
111
- r.route.meta = r.route.meta || {};
112
-
113
- r.route.meta.product = r.route.meta.product || productName;
114
- }
115
-
116
- // See if the route exists
117
- let existing: any;
118
-
119
- if (r.parent) {
120
- const pExisting = allRoutes.findIndex((route: any) => route.name === r.parent) as any;
121
- const path = `${ pExisting.path }${ r.route.path }`;
122
-
123
- // TODO: Validate
124
- existing = allRoutes.findIndex((route: any) => route.path === path);
125
- } else {
126
- // no parent route
127
- existing = allRoutes.findIndex((route: any) => route.name === r.route.name);
128
- }
129
-
130
- if (existing >= 0) {
131
- const existingRoute = allRoutes[existing];
132
-
133
- // Store the route so we can restore it on uninstall
134
- if (plugin && existingRoute?.name) {
135
- if (!this.replacedRoutes[existingRoute.name]) {
136
- this.replacedRoutes[existingRoute.name] = [];
137
- }
138
-
139
- this.replacedRoutes[existingRoute.name].unshift({
140
- plugin: plugin.id,
141
- route: existingRoute
142
- });
143
- }
53
+ r.path = `/${ productName }${ r.path.substr(9) }`;
54
+ r.meta = r.meta || {};
144
55
 
145
- allRoutes.splice(existing, 1);
56
+ r.meta.product = r.meta.product || productName;
146
57
  }
147
58
  });
148
59
 
149
- this.updateMatcher(routes, allRoutes);
60
+ this.updateMatcher(newRouteInfos, allRoutes);
150
61
  }
151
62
 
152
63
  private updateMatcher(newRoutes: RouteInfo[], allRoutes: RouteConfig[]) {
153
64
  // Note - Always use a new router and replace the existing router's matching
154
- // Using the existing router and adding routes to it will force nuxt middleware (specifically authenticated on default layout) to
65
+ // Using the existing router and adding routes to it will force nuxt middleware to
155
66
  // execute many times (nuxt middleware boils down to router.beforeEach). This issue was seen refreshing in a harvester cluster with a
156
67
  // dynamically loaded cluster
157
68
 
158
- const pluginRoutesWithParents: any[] = [];
159
69
  const orderedPluginRoutes: any[] = [];
160
70
 
161
- // separate plugin routes that have parent and not
162
- newRoutes.forEach((r: any) => {
71
+ // separate plugin routes that have parent and not, you want to push the new routes in REVERSE order to the front of the existing list so that the order of routes specified by the extension is preserved
72
+ newRoutes.reverse().forEach((r: any) => {
163
73
  let foundParentRoute;
164
74
 
165
75
  if (r.parent) {
166
- foundParentRoute = allRoutes.find((route) => route.name === r.parent);
76
+ foundParentRoute = this.findInNestedRoutes(allRoutes, (route: RouteConfig) => route.name === r.parent);
167
77
 
168
78
  if (foundParentRoute) {
169
- pluginRoutesWithParents.push(r);
79
+ foundParentRoute.children = foundParentRoute?.children || [];
80
+ foundParentRoute.children.unshift(r.route);
170
81
  }
171
82
  }
172
83
 
173
84
  if (!foundParentRoute) {
174
- orderedPluginRoutes.push(r.route);
85
+ orderedPluginRoutes.unshift(r.route);
175
86
  }
176
-
177
- this.pluginRoutes.push(r.route);
178
87
  });
179
88
 
180
89
  const newRouter: Router = new Router({
@@ -182,12 +91,45 @@ export class PluginRoutes {
182
91
  routes: [...orderedPluginRoutes, ...allRoutes]
183
92
  });
184
93
 
185
- // handle plugin routes with parent
186
- pluginRoutesWithParents.forEach((r: any) => {
187
- newRouter.addRoute(r.parent, r.route);
94
+ (this.router as any).matcher = (newRouter as any).matcher;
95
+ }
96
+
97
+ /**
98
+ * Traverse the entire tree of nested routes
99
+ *
100
+ * @param routes The routes we wish to traverse through
101
+ * @param fn -> Return true if you'd like to break the loop early (small)
102
+ * @returns {@boolean} -> Returns true if breaking early
103
+ */
104
+ private forEachNestedRoutes(routes: RouteConfig[] = [], fn: (route: RouteConfig) => boolean | undefined | void) {
105
+ for (let i = 0; i < routes.length; ++i) {
106
+ const route = routes[i];
107
+ const result = fn(route);
108
+
109
+ if (result || this.forEachNestedRoutes(route.children, fn)) {
110
+ return true;
111
+ }
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Find a route that matches the criteria defined by fn.
117
+ *
118
+ * @param routes The routes we wish to search through
119
+ * @param fn -> Returns true if the passed in route matches the expected criteria
120
+ * @returns The found route or undefined
121
+ */
122
+ private findInNestedRoutes(routes: RouteConfig[] = [], fn: (route: RouteConfig) => boolean): RouteConfig | undefined {
123
+ let found: any;
124
+
125
+ this.forEachNestedRoutes(routes, (route) => {
126
+ if (fn(route)) {
127
+ found = route;
128
+
129
+ return true;
130
+ }
188
131
  });
189
132
 
190
- // Typing is incorrect
191
- (this.router as any).matcher = (newRouter as any).matcher;
133
+ return found;
192
134
  }
193
135
  }
package/core/plugin.ts CHANGED
@@ -15,7 +15,6 @@ import {
15
15
  PluginRouteConfig, RegisterStore, UnregisterStore, CoreStoreSpecifics, CoreStoreConfig, OnNavToPackage, OnNavAwayFromPackage, OnLogOut
16
16
  } from './types';
17
17
  import coreStore, { coreStoreModule, coreStoreState } from '@shell/plugins/dashboard-store';
18
- import { registerLayout } from '@shell/initialize/layouts';
19
18
 
20
19
  export type ProductFunction = (plugin: IPlugin, store: any) => void;
21
20
 
@@ -120,12 +119,27 @@ export class Plugin implements IPlugin {
120
119
  const parent: string | undefined = hasParent ? parentOrRoute as string : undefined;
121
120
  const route: RouteConfig = hasParent ? optionalRoute as RouteConfig : parentOrRoute as RouteConfig;
122
121
 
122
+ let parentOverride;
123
+
124
+ if (!parent) {
125
+ // TODO: Inspecting the route object in the browser clearly indicates it's not a RouteConfig. The type needs to be changed or at least extended.
126
+ const typelessRoute: any = route;
127
+
128
+ if (typelessRoute.component?.layout) {
129
+ console.warn(`Layouts have been deprecated. We still have parent routes which use the same name and styling as the previous layouts. \n\nFound a component ${ typelessRoute.component.name } with the '${ typelessRoute.component.layout }' layout specified `); // eslint-disable-line no-console
130
+ parentOverride = typelessRoute.component.layout.toLowerCase();
131
+ } else {
132
+ console.warn(`Layouts have been deprecated. We still have parent routes which use the same name and styling as the previous layouts. You should specify a parent, we're currently setting the parent to 'default'`); // eslint-disable-line no-console
133
+ parentOverride = 'default';
134
+ }
135
+ }
136
+
123
137
  route.meta = {
124
138
  ...route?.meta,
125
139
  pkg: this.name,
126
140
  };
127
141
 
128
- this.routes.push({ parent, route });
142
+ this.routes.push({ parent: parentOverride || parent, route });
129
143
  }
130
144
 
131
145
  private _addUIConfig(type: string, where: string, when: LocationConfig | string, config: any) {
@@ -268,14 +282,6 @@ export class Plugin implements IPlugin {
268
282
  }
269
283
 
270
284
  this.l10n[name].push(fn);
271
- } else if (type === 'layouts') {
272
- fn().then((component: any) => {
273
- if (component.default) {
274
- registerLayout(name, component.default);
275
- } else {
276
- console.error(`Failed to load layout ${ name } because the file didn't export a default component.`); // eslint-disable-line no-console
277
- }
278
- });
279
285
  } else {
280
286
  if (!this.types[type]) {
281
287
  this.types[type] = {};
@@ -20,14 +20,12 @@ export default function({
20
20
  dynamicLoader.default($plugin);
21
21
  }
22
22
 
23
- if (process.client) {
24
- // The libraries we build have Vue externalised, so we need to expose Vue as a global for
25
- // them to pick up - see: https://cli.vuejs.org/guide/build-targets.html#library
26
- window.Vue = Vue;
23
+ // The libraries we build have Vue externalised, so we need to expose Vue as a global for
24
+ // them to pick up - see: https://cli.vuejs.org/guide/build-targets.html#library
25
+ window.Vue = Vue;
27
26
 
28
- // Global libraries - allows us to externalise these to reduce package bundle size
29
- window.$ = $;
30
- window.__jszip = JSZip;
31
- window.__jsyaml = jsyaml;
32
- }
27
+ // Global libraries - allows us to externalise these to reduce package bundle size
28
+ window.$ = $;
29
+ window.__jszip = JSZip;
30
+ window.__jsyaml = jsyaml;
33
31
  }
package/core/plugins.js CHANGED
@@ -222,9 +222,6 @@ export default function({
222
222
  promises.push(...this.removeTypeFromStore(store, 'management', Object.keys(plugin.types.models)));
223
223
  }
224
224
 
225
- // Uninstall routes
226
- pluginRoutes.uninstall(plugin);
227
-
228
225
  // Call plugin uninstall hooks
229
226
  plugin.uninstallHooks.forEach((fn) => fn(plugin, this.internal()));
230
227
 
@@ -0,0 +1,14 @@
1
+ image: registry.suse.com/bci/bci-base:latest
2
+
3
+ stages:
4
+ - check_version
5
+ - build_catalog
6
+
7
+ variables:
8
+ REGISTRY: $CI_REGISTRY
9
+ REGISTRY_USER: $CI_REGISTRY_USER
10
+ REGISTRY_PASSWORD: $CI_REGISTRY_PASSWORD
11
+ IMAGE_NAMESPACE: $CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME
12
+
13
+ include:
14
+ - remote: 'https://raw.githubusercontent.com/rancher/dashboard/master/shell/scripts/.gitlab/workflows/build-extension-catalog.gitlab-ci.yml'
package/creators/app/init CHANGED
@@ -34,6 +34,25 @@ if (args.length === 3) {
34
34
  fs.ensureDirSync(appFolder);
35
35
  }
36
36
 
37
+ let addGitlabWorkflow = false;
38
+
39
+ // Check for Gitlab integration option
40
+ if ( args.length > 3 ) {
41
+ for (let i = 3; i < args.length; i++) {
42
+ switch (args[i]) {
43
+ case '-l':
44
+ addGitlabWorkflow = true;
45
+ break;
46
+ default:
47
+ break;
48
+ }
49
+ }
50
+ }
51
+
52
+ if ( addGitlabWorkflow ) {
53
+ files.push('.gitlab-ci.yml');
54
+ }
55
+
37
56
  // Check that there is a package file
38
57
 
39
58
  let setName = false;
@@ -8,7 +8,7 @@ import { MANAGEMENT, FLEET } from '@shell/config/types';
8
8
  import { FLEET as FLEET_LABELS } from '@shell/config/labels-annotations';
9
9
 
10
10
  export default {
11
- name: 'DetailCluster',
11
+ name: 'FleetDetailCluster',
12
12
 
13
13
  components: {
14
14
  Loading,
@@ -36,6 +36,8 @@ export default {
36
36
  this.allRepos = await this.$store.dispatch('management/findAll', { type: FLEET.GIT_REPO });
37
37
 
38
38
  await this.$store.dispatch('management/findAll', { type: FLEET.WORKSPACE });
39
+
40
+ await this.$store.dispatch('management/findAll', { type: FLEET.BUNDLE_DEPLOYMENT });
39
41
  },
40
42
 
41
43
  data() {
@@ -43,6 +45,13 @@ export default {
43
45
  },
44
46
 
45
47
  computed: {
48
+ allBundleDeployments() {
49
+ return this.value.bundleDeployments;
50
+ },
51
+ clusterId() {
52
+ return this.value?.metadata?.labels[FLEET_LABELS.CLUSTER_NAME];
53
+ },
54
+
46
55
  repos() {
47
56
  return this.allRepos.filter((x) => {
48
57
  return x.targetClusters.includes(this.value);
@@ -76,6 +85,7 @@ export default {
76
85
  :weight="19"
77
86
  >
78
87
  <FleetRepos
88
+ :clusterId="clusterId"
79
89
  :rows="repos"
80
90
  :schema="repoSchema"
81
91
  :paging="true"
@@ -775,10 +775,10 @@ export default {
775
775
  v-clean-html="t('resourceTable.groupLabel.notInANodePool')"
776
776
  />
777
777
  <div
778
- v-if="group.ref && group.ref.template"
778
+ v-if="group.ref && group.ref.providerSummary"
779
779
  class="description text-muted text-small"
780
780
  >
781
- {{ group.ref.providerDisplay }} &ndash; {{ group.ref.providerLocation }} / {{ group.ref.providerSize }} ({{ group.ref.providerName }})
781
+ {{ group.ref.providerSummary }}
782
782
  </div>
783
783
  </div>
784
784
  <div
@@ -880,7 +880,7 @@ export default {
880
880
  <template v-if="group.ref.hasLink('update')">
881
881
  <button
882
882
  v-clean-tooltip="t('node.list.scaleDown')"
883
- :disabled="group.ref.spec.quantity < 2"
883
+ :disabled="!group.ref.canScaleDownPool()"
884
884
  type="button"
885
885
  class="btn btn-sm role-secondary"
886
886
  @click="toggleScaleDownModal($event, group.ref)"
@@ -1006,6 +1006,7 @@ export default {
1006
1006
  >
1007
1007
  <SortableTable
1008
1008
  class="snapshots"
1009
+ :data-testid="'cluster-snapshots-list'"
1009
1010
  :headers="value.isRke1 ? rke1SnapshotHeaders : rke2SnapshotHeaders"
1010
1011
  default-sort-by="age"
1011
1012
  :table-actions="value.isRke1"
@@ -1,6 +1,6 @@
1
1
  <script>
2
2
  import { CAPI as CAPI_LABELS } from '@shell/config/labels-annotations';
3
- import { CAPI } from '@shell/config/types';
3
+ import { MANAGEMENT, CAPI } from '@shell/config/types';
4
4
  import GenericPrompt from './GenericPrompt';
5
5
 
6
6
  export default {
@@ -14,30 +14,38 @@ export default {
14
14
  },
15
15
 
16
16
  async fetch() {
17
- await Promise.all([
18
- this.$store.dispatch('management/findAll', { type: CAPI.MACHINE_DEPLOYMENT }),
19
- this.$store.dispatch('management/findAll', { type: CAPI.MACHINE })
20
- ]);
17
+ if (this.isRke2) {
18
+ await Promise.all([
19
+ this.$store.dispatch('management/findAll', { type: CAPI.MACHINE_DEPLOYMENT }),
20
+ this.$store.dispatch('management/findAll', { type: CAPI.MACHINE })
21
+ ]);
22
+ } else {
23
+ await Promise.all([
24
+ this.$store.dispatch('management/findAll', { type: MANAGEMENT.NODE_POOL }),
25
+ this.$store.dispatch('management/findAll', { type: MANAGEMENT.NODE })
26
+ ]);
27
+ }
21
28
  },
22
29
 
23
30
  data() {
24
- const allToDelete = Array.isArray(this.resources) ? this.resources : [this.resources];
25
- const cluster = allToDelete[0].cluster;
31
+ const isRke2 = this.resources[0].cluster?.isRke2;
32
+ const cluster = isRke2 ? this.resources[0].cluster : this.resources[0].provisioningCluster;
26
33
 
27
34
  // Not all machines can be deleted, there must always be at least one left for roles control plane and etcd
28
35
  // First ensure that at least one control plane exists... and then check from the remaining machines that at least one etcd exists
29
36
  // This isn't optimisied, there may be cases that retaining a single machine with both roles would be better than retaining two with single roles
30
- const [ignoredControlPlane, safeControlePlaneMachinesToDelete] = this.deleteType('isControlPlane', allToDelete, cluster);
31
- const [ignoredEtcd, safeMachinesToDelete] = this.deleteType('isEtcd', safeControlePlaneMachinesToDelete, cluster);
37
+ const [ignoredControlPlane, safeControlePlaneMachinesToDelete] = this.deleteType('isControlPlane', this.resources, cluster, isRke2);
38
+ const [ignoredEtcd, safeMachinesToDelete] = this.deleteType('isEtcd', safeControlePlaneMachinesToDelete, cluster, isRke2);
32
39
  const ignored = [ignoredControlPlane, ignoredEtcd].filter((i) => !!i);
33
40
 
34
41
  return {
35
42
  cluster,
36
- allToDelete,
43
+ isRke2,
44
+ allToDelete: this.resources,
37
45
  safeMachinesToDelete,
38
46
  ignored,
39
- type: this.$store.getters['type-map/labelFor'](allToDelete[0].schema, allToDelete.length),
40
- config: {
47
+ type: this.$store.getters['type-map/labelFor'](this.resources[0].schema, this.resources.length),
48
+ config: {
41
49
  title: this.t('promptRemove.title'),
42
50
  applyMode: 'delete',
43
51
  applyAction: this.remove,
@@ -46,7 +54,7 @@ export default {
46
54
  },
47
55
 
48
56
  methods: {
49
- deleteType(type, allToDelete, cluster) {
57
+ deleteType(type, allToDelete, cluster, isRke2) {
50
58
  const allToDeleteByType = allToDelete.reduce((res, m) => {
51
59
  if (m[type]) {
52
60
  res.typed.push(m);
@@ -57,7 +65,8 @@ export default {
57
65
  return res;
58
66
  }, { typed: [], others: [] });
59
67
 
60
- const totalTypes = cluster.machines.filter((m) => m[type]).length;
68
+ const machines = isRke2 ? cluster.machines : cluster.nodes;
69
+ const totalTypes = machines.filter((m) => m[type]).length;
61
70
  const typesToDelete = allToDeleteByType.typed.length;
62
71
  // If we're attempting to remove all control plan machines.... ignore one
63
72
  const ignoredType = totalTypes - typesToDelete === 0 ? allToDeleteByType.typed.pop() : undefined;
@@ -67,6 +76,14 @@ export default {
67
76
  },
68
77
 
69
78
  async remove() {
79
+ if (!this.isRke2) {
80
+ await Promise.all(this.safeMachinesToDelete.map((node) => {
81
+ return node.norman?.doAction('scaledown');
82
+ }));
83
+
84
+ return;
85
+ }
86
+
70
87
  // Group machines into pools
71
88
  const poolInfo = this.safeMachinesToDelete.reduce((res, m) => {
72
89
  res.set(m.pool, res.get(m.pool) || []);
@@ -103,7 +120,7 @@ export default {
103
120
  <template slot="body">
104
121
  <div class="pl-10 pr-10 mt-20 mb-20 body">
105
122
  <div v-if="allToDelete.length === 1">
106
- {{ t('promptRemove.attemptingToRemove', { type }) }} <b>{{ safeMachinesToDelete[0].name }}</b>
123
+ {{ t('promptRemove.attemptingToRemove', { type }) }} <b>{{ safeMachinesToDelete[0].nameDisplay }}</b>
107
124
  </div>
108
125
  <div v-else>
109
126
  {{ t('promptScaleMachineDown.attemptingToRemove', { type, count: allToDelete.length }, true) }}
@@ -115,8 +132,8 @@ export default {
115
132
  <span class="mb-20">{{ t('promptScaleMachineDown.retainedMachine1') }}</span>
116
133
  <span
117
134
  v-for="i in ignored"
118
- :key="i.name"
119
- v-clean-html="t('promptScaleMachineDown.retainedMachine2', { name: i.name }, true)"
135
+ :key="i.nameDisplay"
136
+ v-clean-html="t('promptScaleMachineDown.retainedMachine2', { name: i.nameDisplay }, true)"
120
137
  />
121
138
  </div>
122
139
  </div>