@rancher/shell 0.1.3 → 0.1.21

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 (245) hide show
  1. package/assets/brand/suse/dark/rancher-logo.svg +1 -148
  2. package/assets/brand/suse/favicon.png +0 -0
  3. package/assets/brand/suse/rancher-logo.svg +1 -130
  4. package/assets/images/featured/img1.jpg +0 -0
  5. package/assets/images/featured.jpg +0 -0
  6. package/assets/images/generic-plugin.svg +1 -0
  7. package/assets/styles/themes/_dark.scss +3 -0
  8. package/assets/styles/themes/_light.scss +3 -0
  9. package/assets/styles/themes/_suse.scss +1 -1
  10. package/assets/translations/en-us.yaml +219 -47
  11. package/assets/translations/zh-hans.yaml +21 -24
  12. package/components/AsyncButton.vue +17 -2
  13. package/components/ButtonDropdown.vue +4 -0
  14. package/components/Carousel.vue +291 -0
  15. package/components/CommunityLinks.vue +64 -22
  16. package/components/CruResource.vue +11 -3
  17. package/components/Dialog.vue +102 -0
  18. package/components/ExplorerMembers.vue +2 -4
  19. package/components/ExplorerProjectsNamespaces.vue +25 -9
  20. package/components/IconMessage.vue +9 -1
  21. package/components/LazyImage.vue +21 -8
  22. package/components/LocaleSelector.vue +62 -29
  23. package/components/PromptRemove.vue +2 -2
  24. package/components/ResourceList/Masthead.vue +21 -1
  25. package/components/ResourceList/ResourceLoadingIndicator.vue +0 -8
  26. package/components/ResourceList/index.vue +9 -23
  27. package/components/ResourceTable.vue +7 -2
  28. package/components/SimpleBox.vue +6 -4
  29. package/components/SortableTable/index.vue +18 -25
  30. package/components/Tabbed/Tab.vue +5 -0
  31. package/components/Tabbed/index.vue +54 -9
  32. package/components/TypeDescription.vue +10 -1
  33. package/components/auth/Principal.vue +1 -0
  34. package/components/fleet/FleetBundles.vue +8 -3
  35. package/components/fleet/FleetClusters.vue +6 -0
  36. package/components/fleet/FleetRepos.vue +7 -1
  37. package/components/fleet/FleetSummary.vue +6 -0
  38. package/components/form/Command.vue +5 -0
  39. package/components/form/EnvVars.vue +5 -0
  40. package/components/form/KeyValue.vue +80 -58
  41. package/components/form/NameNsDescription.vue +13 -5
  42. package/components/form/NodeScheduling.vue +6 -1
  43. package/components/form/PodAffinity.vue +5 -0
  44. package/components/form/ResourceTabs/index.vue +5 -1
  45. package/components/form/ServiceNameSelect.vue +5 -0
  46. package/components/form/ValueFromResource.vue +7 -1
  47. package/components/formatter/ClusterLink.vue +3 -7
  48. package/components/nav/NamespaceFilter.vue +3 -3
  49. package/components/nav/TopLevelMenu.vue +12 -29
  50. package/config/home-links.js +155 -0
  51. package/config/labels-annotations.js +2 -1
  52. package/config/private-label.js +1 -1
  53. package/config/product/explorer.js +5 -4
  54. package/config/product/legacy.js +0 -47
  55. package/config/product/manager.js +0 -2
  56. package/config/product/multi-cluster-apps.js +0 -12
  57. package/config/product/settings.js +12 -1
  58. package/config/product/uiplugins.js +17 -0
  59. package/config/settings.js +23 -2
  60. package/config/types.js +5 -1
  61. package/config/uiplugins.js +117 -0
  62. package/config/version.js +17 -0
  63. package/content/docs/en-us/getting-started.md +1 -26
  64. package/core/plugin.ts +12 -0
  65. package/core/plugins.js +38 -2
  66. package/core/types.ts +6 -0
  67. package/creators/app/{.eslintignore → files/.eslintignore} +0 -0
  68. package/creators/app/{.eslintrc.js → files/.eslintrc.js} +0 -0
  69. package/creators/app/{.vscode → files/.vscode}/settings.json +0 -0
  70. package/creators/app/{babel.config.js → files/babel.config.js} +0 -0
  71. package/creators/app/{nuxt.config.js → files/nuxt.config.js} +0 -0
  72. package/creators/app/{tsconfig.json → files/tsconfig.json} +2 -1
  73. package/creators/app/init +16 -17
  74. package/creators/app/package.json +6 -0
  75. package/creators/pkg/{babel.config.js → files/babel.config.js} +0 -0
  76. package/creators/pkg/{index.ts → files/index.ts} +0 -0
  77. package/creators/pkg/{tsconfig.json → files/tsconfig.json} +13 -12
  78. package/creators/pkg/{vue.config.js → files/vue.config.js} +0 -0
  79. package/creators/pkg/init +1 -1
  80. package/creators/update/init +54 -0
  81. package/creators/update/package.json +20 -0
  82. package/creators/update/upgrade +56 -0
  83. package/creators/update/yarn-error.log +54 -0
  84. package/detail/provisioning.cattle.io.cluster.vue +3 -3
  85. package/detail/workload/index.vue +3 -2
  86. package/dialog/DiagnosticTimingsDialog.vue +116 -0
  87. package/dialog/RotateCertificatesDialog.vue +9 -3
  88. package/edit/auth/azuread.vue +28 -9
  89. package/edit/networking.k8s.io.ingress/index.vue +2 -2
  90. package/edit/persistentvolume/index.vue +51 -13
  91. package/edit/persistentvolumeclaim.vue +31 -13
  92. package/edit/pod.vue +27 -0
  93. package/edit/provisioning.cattle.io.cluster/rke2.vue +103 -24
  94. package/edit/service.vue +7 -5
  95. package/edit/workload/__tests__/Upgrading.test.ts +1 -0
  96. package/edit/workload/index.vue +32 -10
  97. package/edit/workload/mixins/workload.js +121 -126
  98. package/edit/workload/storage/ContainerMountPaths.vue +240 -0
  99. package/edit/workload/storage/Mount.vue +1 -0
  100. package/edit/workload/storage/awsElasticBlockStore.vue +20 -1
  101. package/edit/workload/storage/azureDisk.vue +22 -2
  102. package/edit/workload/storage/azureFile.vue +20 -2
  103. package/edit/workload/storage/csi/index.vue +23 -1
  104. package/edit/workload/storage/gcePersistentDisk.vue +20 -2
  105. package/edit/workload/storage/index.vue +33 -65
  106. package/edit/workload/storage/persistentVolumeClaim/index.vue +5 -0
  107. package/edit/workload/storage/secret.vue +6 -1
  108. package/edit/workload/storage/vsphereVolume.vue +11 -1
  109. package/layouts/default.vue +14 -8
  110. package/layouts/home.vue +9 -4
  111. package/layouts/plain.vue +10 -5
  112. package/list/catalog.cattle.io.app.vue +10 -9
  113. package/list/catalog.cattle.io.clusterrepo.vue +6 -61
  114. package/list/cis.cattle.io.clusterscan.vue +12 -12
  115. package/list/fleet.cattle.io.bundle.vue +33 -28
  116. package/list/fleet.cattle.io.cluster.vue +26 -22
  117. package/list/fleet.cattle.io.clustergroup.vue +6 -0
  118. package/list/fleet.cattle.io.clusterregistrationtoken.vue +28 -24
  119. package/list/fleet.cattle.io.gitrepo.vue +25 -14
  120. package/list/helm.cattle.io.projecthelmchart.vue +52 -33
  121. package/list/logging.banzaicloud.io.clusterflow.vue +7 -12
  122. package/list/logging.banzaicloud.io.flow.vue +7 -14
  123. package/list/management.cattle.io.cluster.vue +26 -15
  124. package/list/management.cattle.io.feature.vue +13 -8
  125. package/list/management.cattle.io.setting.vue +3 -3
  126. package/list/management.cattle.io.user.vue +38 -19
  127. package/list/monitoring.coreos.com.alertmanagerconfig.vue +8 -15
  128. package/list/namespace.vue +14 -1
  129. package/list/node.vue +13 -16
  130. package/list/persistentvolume.vue +16 -9
  131. package/list/persistentvolumeclaim.vue +5 -8
  132. package/list/provisioning.cattle.io.cluster.vue +35 -9
  133. package/list/service.vue +24 -12
  134. package/list/ui.cattle.io.navlink.vue +6 -0
  135. package/list/workload.vue +2 -2
  136. package/machine-config/harvester.vue +5 -3
  137. package/middleware/authenticated.js +6 -0
  138. package/mixins/resource-fetch.js +12 -18
  139. package/mixins/resource-manager.js +126 -0
  140. package/models/catalog.cattle.io.uiplugin.js +38 -0
  141. package/models/cluster/node.js +25 -2
  142. package/models/fleet.cattle.io.bundle.js +1 -1
  143. package/models/harvesterhci.io.management.cluster.js +11 -5
  144. package/models/pod.js +15 -5
  145. package/models/provisioning.cattle.io.cluster.js +16 -6
  146. package/models/workload.js +5 -3
  147. package/models/workload.service.js +10 -0
  148. package/nuxt.config.js +70 -25
  149. package/package.json +108 -109
  150. package/pages/auth/login.vue +11 -1
  151. package/pages/auth/verify.vue +9 -0
  152. package/pages/c/_cluster/apps/charts/index.vue +46 -1
  153. package/pages/c/_cluster/apps/charts/install.vue +10 -9
  154. package/pages/c/_cluster/explorer/index.vue +72 -9
  155. package/pages/c/_cluster/explorer/tools/index.vue +12 -5
  156. package/pages/c/_cluster/mcapps/index.vue +1 -1
  157. package/pages/c/_cluster/settings/DefaultLinksEditor.vue +108 -0
  158. package/pages/c/_cluster/settings/brand.vue +0 -40
  159. package/pages/c/_cluster/settings/links.vue +152 -0
  160. package/pages/c/_cluster/settings/performance.vue +90 -7
  161. package/pages/c/_cluster/uiplugins/DeveloperInstallDialog.vue +232 -0
  162. package/pages/c/_cluster/uiplugins/InstallDialog.vue +293 -0
  163. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +300 -0
  164. package/pages/c/_cluster/uiplugins/RemoveUIPlugins.vue +125 -0
  165. package/pages/c/_cluster/uiplugins/SetupUIPlugins.vue +261 -0
  166. package/pages/c/_cluster/uiplugins/UninstallDialog.vue +122 -0
  167. package/pages/c/_cluster/uiplugins/index.vue +808 -0
  168. package/pages/diagnostic.vue +185 -101
  169. package/pages/docs/_doc.vue +3 -1
  170. package/pages/home.vue +21 -56
  171. package/pages/prefs.vue +108 -88
  172. package/pages/safeMode.vue +17 -0
  173. package/pages/support/index.vue +34 -137
  174. package/pkg/dynamic-importer.lib.js +4 -0
  175. package/plugins/dashboard-store/actions.js +19 -0
  176. package/plugins/dashboard-store/getters.js +20 -3
  177. package/plugins/dashboard-store/mutations.js +13 -7
  178. package/plugins/dashboard-store/resource-class.js +2 -2
  179. package/plugins/formatters.js +15 -0
  180. package/plugins/plugin.js +61 -6
  181. package/plugins/steve/getters.js +12 -0
  182. package/plugins/steve/mutations.js +1 -1
  183. package/plugins/steve/subscribe.js +94 -72
  184. package/plugins/steve/web-worker.steve-sub-worker.js +24 -15
  185. package/plugins/version.js +21 -0
  186. package/promptRemove/management.cattle.io.globalrole.vue +47 -0
  187. package/promptRemove/management.cattle.io.roletemplate.vue +47 -0
  188. package/promptRemove/mixin/roleDeletionCheck.js +97 -0
  189. package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +6 -7
  190. package/rancher-components/components/BadgeState/BadgeState.spec.ts +12 -0
  191. package/rancher-components/components/BadgeState/BadgeState.vue +107 -0
  192. package/rancher-components/components/BadgeState/index.ts +1 -0
  193. package/rancher-components/components/Banner/Banner.test.ts +13 -0
  194. package/rancher-components/components/Banner/Banner.vue +163 -0
  195. package/rancher-components/components/Banner/index.ts +1 -0
  196. package/rancher-components/components/Card/Card.vue +150 -0
  197. package/rancher-components/components/Card/index.ts +1 -0
  198. package/rancher-components/components/Form/Checkbox/Checkbox.test.ts +77 -0
  199. package/rancher-components/components/Form/Checkbox/Checkbox.vue +395 -0
  200. package/rancher-components/components/Form/Checkbox/index.ts +1 -0
  201. package/rancher-components/components/Form/LabeledInput/LabeledInput.test.ts +29 -0
  202. package/rancher-components/components/Form/LabeledInput/LabeledInput.vue +343 -0
  203. package/rancher-components/components/Form/LabeledInput/index.ts +1 -0
  204. package/rancher-components/components/Form/Radio/RadioButton.vue +270 -0
  205. package/rancher-components/components/Form/Radio/RadioGroup.vue +235 -0
  206. package/rancher-components/components/Form/Radio/index.ts +2 -0
  207. package/rancher-components/components/Form/TextArea/TextAreaAutoGrow.vue +168 -0
  208. package/rancher-components/components/Form/TextArea/index.ts +1 -0
  209. package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.test.ts +107 -0
  210. package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.vue +137 -0
  211. package/rancher-components/components/Form/ToggleSwitch/index.ts +1 -0
  212. package/rancher-components/components/Form/index.ts +5 -0
  213. package/rancher-components/components/LabeledTooltip/LabeledTooltip.vue +137 -0
  214. package/rancher-components/components/LabeledTooltip/index.ts +1 -0
  215. package/scripts/publish-shell.sh +40 -7
  216. package/scripts/record-deps.js +37 -0
  217. package/scripts/sync-shell-deps +37 -0
  218. package/scripts/test-plugins-build.sh +8 -5
  219. package/scripts/typegen.sh +84 -0
  220. package/store/auth.js +3 -0
  221. package/store/catalog.js +9 -8
  222. package/store/i18n.js +10 -1
  223. package/store/index.js +12 -3
  224. package/store/prefs.js +16 -0
  225. package/store/type-map.js +32 -5
  226. package/store/uiplugins.ts +15 -61
  227. package/types/shell/index.d.ts +3046 -0
  228. package/utils/__tests__/object.test.ts +0 -24
  229. package/utils/__tests__/selector.test.ts +1 -1
  230. package/utils/dynamic-importer.js +4 -0
  231. package/utils/favicon.js +8 -2
  232. package/utils/gc/gc-interval.ts +40 -0
  233. package/utils/gc/gc-root-store.js +76 -0
  234. package/utils/gc/gc-route-changed.ts +44 -0
  235. package/utils/gc/gc-types.ts +21 -0
  236. package/utils/gc/gc.ts +282 -0
  237. package/utils/grafana.js +2 -6
  238. package/utils/socket.js +41 -20
  239. package/utils/string.js +1 -7
  240. package/utils/validators/formRules/__tests__/index.test.ts +108 -0
  241. package/utils/validators/formRules/index.ts +9 -1
  242. package/config/footer.js +0 -19
  243. package/creators/pkg/nuxt.config.js +0 -6
  244. package/pages/plugins.vue +0 -387
  245. package/server/verdaccio-middleware.js +0 -56
@@ -8,17 +8,35 @@ import { MODE, _IMPORT } from '@shell/config/query-params';
8
8
  import { filterOnlyKubernetesClusters, filterHiddenLocalCluster } from '@shell/utils/cluster';
9
9
  import { mapFeature, HARVESTER as HARVESTER_FEATURE } from '@shell/store/features';
10
10
  import { NAME as EXPLORER } from '@shell/config/product/explorer';
11
+ import ResourceFetch from '@shell/mixins/resource-fetch';
11
12
 
12
13
  export default {
13
14
  components: {
14
15
  Banner, ResourceTable, Masthead
15
16
  },
17
+ mixins: [ResourceFetch],
18
+ props: {
19
+ loadResources: {
20
+ type: Array,
21
+ default: () => []
22
+ },
23
+
24
+ loadIndeterminate: {
25
+ type: Boolean,
26
+ default: false
27
+ },
28
+
29
+ incrementalLoadingIndicator: {
30
+ type: Boolean,
31
+ default: false
32
+ },
33
+ },
16
34
 
17
35
  async fetch() {
18
36
  const hash = {
37
+ rancherClusters: this.$fetchType(CAPI.RANCHER_CLUSTER),
19
38
  normanClusters: this.$store.dispatch('rancher/findAll', { type: NORMAN.CLUSTER }),
20
39
  mgmtClusters: this.$store.dispatch('management/findAll', { type: MANAGEMENT.CLUSTER }),
21
- rancherClusters: this.$store.dispatch('management/findAll', { type: CAPI.RANCHER_CLUSTER }),
22
40
  };
23
41
 
24
42
  if ( this.$store.getters['management/canList'](SNAPSHOT) ) {
@@ -50,7 +68,6 @@ export default {
50
68
  const res = await allHash(hash);
51
69
 
52
70
  this.mgmtClusters = res.mgmtClusters;
53
- this.rancherClusters = res.rancherClusters;
54
71
  },
55
72
 
56
73
  data() {
@@ -58,19 +75,18 @@ export default {
58
75
  resource: CAPI.RANCHER_CLUSTER,
59
76
  schema: this.$store.getters['management/schemaFor'](CAPI.RANCHER_CLUSTER),
60
77
  mgmtClusters: [],
61
- rancherClusters: [],
62
78
  };
63
79
  },
64
80
 
65
81
  computed: {
66
- rows() {
82
+ filteredRows() {
67
83
  // If Harvester feature is enabled, hide Harvester Clusters
68
84
  if (this.harvesterEnabled) {
69
- return filterHiddenLocalCluster(filterOnlyKubernetesClusters(this.rancherClusters), this.$store);
85
+ return filterHiddenLocalCluster(filterOnlyKubernetesClusters(this.rows), this.$store);
70
86
  }
71
87
 
72
88
  // Otherwise, show Harvester clusters - these will be shown with a warning
73
- return filterHiddenLocalCluster(this.rancherClusters, this.$store);
89
+ return filterHiddenLocalCluster(this.rows, this.$store);
74
90
  },
75
91
 
76
92
  hiddenHarvesterCount() {
@@ -82,7 +98,7 @@ export default {
82
98
  return 0;
83
99
  }
84
100
 
85
- return this.rancherClusters.length - filterOnlyKubernetesClusters(this.rancherClusters).length;
101
+ return this.rows.length - filterOnlyKubernetesClusters(this.rows).length;
86
102
  },
87
103
 
88
104
  createLocation() {
@@ -115,6 +131,13 @@ export default {
115
131
  harvesterEnabled: mapFeature(HARVESTER_FEATURE),
116
132
  },
117
133
 
134
+ $loadingResources() {
135
+ return {
136
+ loadResources: [CAPI.RANCHER_CLUSTER],
137
+ loadIndeterminate: true, // results are filtered so we wouldn't get the correct count on indicator...
138
+ };
139
+ },
140
+
118
141
  mounted() {
119
142
  window.c = this;
120
143
  },
@@ -130,6 +153,9 @@ export default {
130
153
  :resource="resource"
131
154
  :create-location="createLocation"
132
155
  component-testid="cluster-manager-list"
156
+ :show-incremental-loading-indicator="incrementalLoadingIndicator"
157
+ :load-resources="loadResources"
158
+ :load-indeterminate="loadIndeterminate"
133
159
  >
134
160
  <template v-if="canImport" slot="extraActions">
135
161
  <n-link
@@ -142,14 +168,14 @@ export default {
142
168
  </template>
143
169
  </Masthead>
144
170
 
145
- <ResourceTable :schema="schema" :rows="rows" :namespaced="false" :loading="$fetchState.pending">
171
+ <ResourceTable :schema="schema" :rows="filteredRows" :namespaced="false" :loading="loading">
146
172
  <template #cell:summary="{row}">
147
173
  <span v-if="!row.stateParts.length">{{ row.nodes.length }}</span>
148
174
  </template>
149
175
  <template #cell:explorer="{row}">
150
176
  <span v-if="row.mgmt && row.mgmt.isHarvester"></span>
151
177
  <n-link
152
- v-else-if="row.mgmt && row.mgmt.isReady"
178
+ v-else-if="row.mgmt && row.mgmt.isReady && !row.hasError"
153
179
  data-testid="cluster-manager-list-explore-management"
154
180
  class="btn btn-sm role-secondary"
155
181
  :to="{name: 'c-cluster', params: {cluster: row.mgmt.id}}"
package/list/service.vue CHANGED
@@ -1,12 +1,25 @@
1
1
  <script>
2
2
  import ResourceTable from '@shell/components/ResourceTable';
3
- import Loading from '@shell/components/Loading';
4
3
  import { NODE } from '@shell/config/types';
5
4
  import { allHash } from '@shell/utils/promise';
5
+ import ResourceFetch from '@shell/mixins/resource-fetch';
6
6
 
7
7
  export default {
8
8
  name: 'ListService',
9
- components: { Loading, ResourceTable },
9
+ components: { ResourceTable },
10
+ mixins: [ResourceFetch],
11
+ props: {
12
+ resource: {
13
+ type: String,
14
+ required: true,
15
+ },
16
+
17
+ schema: {
18
+ type: Object,
19
+ required: true,
20
+ },
21
+ },
22
+
10
23
  // fetch nodes before loading this page, as they may be referenced in the Target table column
11
24
  async fetch() {
12
25
  const store = this.$store;
@@ -21,23 +34,22 @@ export default {
21
34
  }
22
35
  } catch {}
23
36
 
24
- const hash = { rows: store.dispatch(`${ inStore }/findAll`, { type: this.$attrs.resource }) };
37
+ const hash = { rows: this.$fetchType(this.resource) };
25
38
 
26
39
  if (hasNodes) {
27
40
  hash.nodes = store.dispatch(`${ inStore }/findAll`, { type: NODE });
28
41
  }
29
- const res = await allHash(hash);
30
-
31
- this.rows = res.rows;
32
- },
33
-
34
- data() {
35
- return { rows: [] };
42
+ await allHash(hash);
36
43
  }
37
44
  };
38
45
  </script>
39
46
 
40
47
  <template>
41
- <Loading v-if="$fetchState.pending" />
42
- <ResourceTable v-else :schema="$attrs.schema" :rows="rows" :headers="$attrs.headers" :group-by="$attrs.groupBy" />
48
+ <ResourceTable
49
+ :schema="schema"
50
+ :rows="rows"
51
+ :headers="$attrs.headers"
52
+ :group-by="$attrs.groupBy"
53
+ :loading="loading"
54
+ />
43
55
  </template>
@@ -16,6 +16,11 @@ export default {
16
16
  type: Array,
17
17
  required: true,
18
18
  },
19
+
20
+ loading: {
21
+ type: Boolean,
22
+ required: false,
23
+ },
19
24
  },
20
25
 
21
26
  computed: { ...mapGetters(['clusterId']) }
@@ -26,6 +31,7 @@ export default {
26
31
  <ResourceTable
27
32
  :schema="schema"
28
33
  :rows="rows"
34
+ :loading="loading"
29
35
  >
30
36
  <template #cell:to="{row}">
31
37
  <template v-if="row.spec && row.spec.toService">
package/list/workload.vue CHANGED
@@ -76,7 +76,7 @@ export default {
76
76
  return schema;
77
77
  },
78
78
 
79
- rows() {
79
+ filteredRows() {
80
80
  const out = [];
81
81
 
82
82
  for ( const typeRows of this.resources ) {
@@ -151,5 +151,5 @@ export default {
151
151
  </script>
152
152
 
153
153
  <template>
154
- <ResourceTable :loading="$fetchState.pending" :schema="schema" :rows="rows" :overflow-y="true" />
154
+ <ResourceTable :loading="$fetchState.pending" :schema="schema" :rows="filteredRows" :overflow-y="true" />
155
155
  </template>
@@ -170,8 +170,10 @@ export default {
170
170
  };
171
171
  });
172
172
 
173
- (res.namespaces.value.data || []).forEach((namespace) => {
174
- if (!namespace.isSystem) {
173
+ (res.namespaces.value.data || []).forEach(async(namespace) => {
174
+ const proxyNamespace = await this.$store.dispatch('cluster/create', namespace);
175
+
176
+ if (!proxyNamespace.isSystem && namespace.links.update) {
175
177
  const value = namespace.metadata.name;
176
178
  const label = namespace.metadata.name;
177
179
 
@@ -519,7 +521,7 @@ export default {
519
521
  :options="imageOptions"
520
522
  :required="true"
521
523
  :searchable="true"
522
- :disabled="disabledEdit"
524
+ :disabled="disabled"
523
525
  label-key="cluster.credential.harvester.image"
524
526
  :placeholder="t('cluster.harvester.machinePool.image.placeholder')"
525
527
  @on-open="onOpen"
@@ -234,6 +234,8 @@ export default async function({
234
234
  }
235
235
  }
236
236
  }
237
+
238
+ store.dispatch('gcStartIntervals');
237
239
  }
238
240
 
239
241
  if (!process.server) {
@@ -245,6 +247,10 @@ export default async function({
245
247
  window.location.href = backTo;
246
248
  }
247
249
  }
250
+
251
+ // GC should be notified of route change before any find/get request is made that might be used for that page
252
+ store.dispatch('gcRouteChanged', route);
253
+
248
254
  // Load stuff
249
255
  await applyProducts(store, $plugin);
250
256
  // Setup a beforeEach hook once to keep track of the current product
@@ -1,26 +1,10 @@
1
1
  import { mapGetters } from 'vuex';
2
- import {
3
- COUNT, MANAGEMENT, POD, WORKLOAD_TYPES, WORKLOAD, SECRET
4
- } from '@shell/config/types';
2
+ import { COUNT, MANAGEMENT } from '@shell/config/types';
5
3
  import { SETTING, DEFAULT_PERF_SETTING } from '@shell/config/settings';
6
4
 
7
5
  // Number of pages to fetch when loading incrementally
8
6
  const PAGES = 4;
9
7
 
10
- // restrict advanced features of manual refresh and incremental loading to these resource types
11
- export const TYPES_RESTRICTED = [
12
- SECRET,
13
- POD,
14
- WORKLOAD_TYPES.DEPLOYMENT,
15
- WORKLOAD_TYPES.CRON_JOB,
16
- WORKLOAD_TYPES.DAEMON_SET,
17
- WORKLOAD_TYPES.JOB,
18
- WORKLOAD_TYPES.STATEFUL_SET,
19
- WORKLOAD_TYPES.REPLICA_SET,
20
- WORKLOAD_TYPES.REPLICATION_CONTROLLER,
21
- WORKLOAD
22
- ];
23
-
24
8
  export default {
25
9
  data() {
26
10
  // fetching the settings related to manual refresh from global settings
@@ -66,7 +50,17 @@ export default {
66
50
  }
67
51
  },
68
52
 
69
- computed: { ...mapGetters({ refreshFlag: 'resource-fetch/refreshFlag' }) },
53
+ computed: {
54
+ ...mapGetters({ refreshFlag: 'resource-fetch/refreshFlag' }),
55
+ rows() {
56
+ const inStore = this.$store.getters['currentStore'](this.resource);
57
+
58
+ return this.$store.getters[`${ inStore }/all`](this.resource);
59
+ },
60
+ loading() {
61
+ return this.rows.length ? false : this.$fetchState.pending;
62
+ },
63
+ },
70
64
  watch: {
71
65
  refreshFlag(neu) {
72
66
  // this is where the data assignment will trigger the update of the list view...
@@ -0,0 +1,126 @@
1
+ import { mapGetters } from 'vuex';
2
+ import { allHashSettled } from '@shell/utils/promise';
3
+
4
+ export default {
5
+ computed: { ...mapGetters(['currentCluster']) },
6
+ data() {
7
+ return { isLoadingSecondaryResources: false };
8
+ },
9
+ methods: {
10
+ /**
11
+ *
12
+ * Function resourceManagerFetchSecondaryResources
13
+ * This method is used to fetch what is called "secondary resources", which can be defined as resources that are needed to populate
14
+ * the page/component itself (ex: used as options on a Select) but don't need to be put into Vuex store or watched to get constant updates.
15
+ * This method allows to fetch resources for a given namespace to reduce the amount of results instead of needing to fetch all and filtering afterwards.
16
+ *
17
+ *
18
+ * @param {String} resourceData.namespace - Namespace identifier
19
+ * @param {Object} resourceData.data - Object containing info about the data needed to be fetched and how it should be parsed. Note: The KEY NEEDS to be the resource TYPE!
20
+ * @param {Array} resourceData.data[TYPE].applyTo - The array of operations needed to be performed for the specific data TYPE
21
+ * @param {String} resourceData.data[TYPE].applyTo[x].var - The 'this' property name that should be populated with the data fetched
22
+ * @param {Boolean} resourceData.data[TYPE].applyTo[x].classify - Whether the data fetched should have a model applied to it
23
+ * @param {Function} resourceData.data[TYPE].applyTo[x].parsingFunc - Optional parsing function if the fetched data needs to be parsed
24
+ * @param {Boolean} onlyNamespaced - Only fetch namespaced resources
25
+ */
26
+ async resourceManagerFetchSecondaryResources(resourceData, onlyNamespaced = false) {
27
+ const requests = {};
28
+ const namespace = resourceData.namespace;
29
+
30
+ // Only fetch types if the user is allowed to...
31
+ Object.keys(resourceData.data).forEach((type) => {
32
+ const schema = this.$store.getters['cluster/schemaFor'](type);
33
+
34
+ if (schema) {
35
+ let url = schema.links.collection;
36
+
37
+ if (schema?.attributes?.namespaced && namespace) {
38
+ const parts = url.split('/');
39
+
40
+ parts.splice(parts.length - 2, 0, `api`);
41
+ parts.splice(parts.length - 1, 0, `namespaces/${ namespace }`);
42
+ url = parts.join('/');
43
+ } else if (onlyNamespaced) {
44
+ // Type isn't namespaced and we've been requested to only fetch namespaced types
45
+ return;
46
+ }
47
+
48
+ requests[type] = this.$store.dispatch('cluster/request', { url });
49
+ }
50
+ });
51
+
52
+ if (Object.keys(requests).length) {
53
+ // this is the flag/variable that we need to apply to all places that rely on this data. Ex: LabeledSelect
54
+ this.isLoadingSecondaryResources = true;
55
+ const hash = await allHashSettled(requests);
56
+ const types = Object.keys(hash);
57
+
58
+ for (let i = 0; i < types.length; i++) {
59
+ const type = types[i];
60
+ const status = hash[type].status;
61
+ // if it's namespaced, we get the data on 'items' prop, for non-namespaced it's 'data' prop...
62
+ const requestData = hash[type].value.items || hash[type].value.data || hash[type].value;
63
+ const schema = this.$store.getters['cluster/schemaFor'](type);
64
+
65
+ if (status === 'fulfilled' && resourceData.data[type] && resourceData.data[type].applyTo?.length) {
66
+ for (let y = 0; y < resourceData.data[type].applyTo.length; y++) {
67
+ const apply = resourceData.data[type].applyTo[y];
68
+ let resources = requestData;
69
+
70
+ if (schema?.attributes?.namespaced) {
71
+ // The resources returned when requesting namespaced types do not contain id, type and links properties.
72
+ // This isn't perfect, or universally applicable, but will work for the current set of use cases
73
+ // To make this more generic
74
+ // - id param = this.$store.getters['cluster/keyFieldForType'](type)
75
+ // - id value = new dashboard-store getter, overwritten by steve store getter
76
+ requestData.forEach((item) => {
77
+ item.type = type;
78
+ item.id = `${ item.metadata.namespace }/${ item.metadata.name }`;
79
+ });
80
+ }
81
+
82
+ if (apply.classify) {
83
+ resources = await this.$store.dispatch('cluster/createMany', requestData);
84
+ }
85
+
86
+ if (apply.parsingFunc) {
87
+ this[apply.var] = apply.parsingFunc(resources);
88
+ } else {
89
+ this[apply.var] = resources;
90
+ }
91
+ }
92
+ } else if (status === 'rejected') {
93
+ console.error(`Resource Manager - secondary data request for type ${ type } has failed`, status.error); // eslint-disable-line no-console
94
+ }
95
+ }
96
+
97
+ this.isLoadingSecondaryResources = false;
98
+ }
99
+ },
100
+
101
+ /**
102
+ * Clear the cached secondary resources
103
+ *
104
+ * @param {*} resourceData See resourceManagerFetchSecondaryResources
105
+ * @param {*} onlyNamespaced Clear only namespaced resources
106
+ */
107
+ resourceManagerClearSecondaryResources(resourceData, onlyNamespaced = false) {
108
+ Object.keys(resourceData.data).forEach((type) => {
109
+ const schema = this.$store.getters['cluster/schemaFor'](type);
110
+
111
+ if (schema) {
112
+ if (!schema?.attributes?.namespaced && onlyNamespaced) {
113
+ // resource isn't namespaced and we're only interested in namespaced resources
114
+ return;
115
+ }
116
+
117
+ for (let y = 0; y < resourceData.data[type].applyTo.length; y++) {
118
+ const apply = resourceData.data[type].applyTo[y];
119
+
120
+ this[apply.var] = [];
121
+ }
122
+ }
123
+ });
124
+ }
125
+ },
126
+ };
@@ -0,0 +1,38 @@
1
+ import SteveModel from '@shell/plugins/steve/steve-class';
2
+
3
+ const CACHED_STATUS = 'cached';
4
+
5
+ export default class UIPlugin extends SteveModel {
6
+ get name() {
7
+ return this.spec?.plugin?.name;
8
+ }
9
+
10
+ get description() {
11
+ return this.spec?.plugin?.description;
12
+ }
13
+
14
+ get version() {
15
+ return this.spec?.plugin?.version;
16
+ }
17
+
18
+ get willBeCached() {
19
+ return this.spec?.plugin?.noCache === false;
20
+ }
21
+
22
+ // Has the plugin been cached?
23
+ get isCached() {
24
+ return !this.willBeCached || (this.willBeCached && this.status?.cacheState === CACHED_STATUS);
25
+ }
26
+
27
+ get pluginMetadata() {
28
+ return this.spec?.plugin?.metadata || {};
29
+ }
30
+
31
+ get isDeveloper() {
32
+ return this.pluginMetadata?.developer === 'true';
33
+ }
34
+
35
+ get plugin() {
36
+ return this.spec?.plugin || {};
37
+ }
38
+ }
@@ -153,6 +153,14 @@ export default class ClusterNode extends SteveModel {
153
153
  }
154
154
 
155
155
  get cpuUsage() {
156
+ /*
157
+ With EKS nodes that have been migrated from norman,
158
+ cpu/memory usage is by the annotation `management.cattle.io/pod-requests`
159
+ */
160
+ if ( this.isFromNorman && this.provider === 'eks' ) {
161
+ return parseSi(this.podRequests.cpu || '0');
162
+ }
163
+
156
164
  return parseSi(this.$rootGetters['cluster/byId'](METRIC.NODE, this.id)?.usage?.cpu || '0');
157
165
  }
158
166
 
@@ -165,6 +173,10 @@ export default class ClusterNode extends SteveModel {
165
173
  }
166
174
 
167
175
  get ramUsage() {
176
+ if ( this.isFromNorman && this.provider === 'eks' ) {
177
+ return parseSi(this.podRequests.memory || '0');
178
+ }
179
+
168
180
  return parseSi(this.$rootGetters['cluster/byId'](METRIC.NODE, this.id)?.usage?.memory || '0');
169
181
  }
170
182
 
@@ -192,6 +204,10 @@ export default class ClusterNode extends SteveModel {
192
204
  return this.pods.length;
193
205
  }
194
206
 
207
+ get podRequests() {
208
+ return JSON.parse(this.metadata.annotations['management.cattle.io/pod-requests'] || '{}');
209
+ }
210
+
195
211
  get isPidPressureOk() {
196
212
  return this.isCondition('PIDPressure', 'False');
197
213
  }
@@ -368,14 +384,13 @@ export default class ClusterNode extends SteveModel {
368
384
  }
369
385
 
370
386
  get canDelete() {
371
- const provider = this.$rootGetters['currentCluster'].provisioner.toLowerCase();
372
387
  const cloudProviders = [
373
388
  'aks', 'azureaks', 'azurekubernetesservice',
374
389
  'eks', 'amazoneks',
375
390
  'gke', 'googlegke'
376
391
  ];
377
392
 
378
- return !cloudProviders.includes(provider);
393
+ return !cloudProviders.includes(this.provider);
379
394
  }
380
395
 
381
396
  // You need to preload CAPI.MACHINEs to use this
@@ -389,6 +404,14 @@ export default class ClusterNode extends SteveModel {
389
404
 
390
405
  return null;
391
406
  }
407
+
408
+ get isFromNorman() {
409
+ return (this.$rootGetters['currentCluster'].metadata.labels || {})['cattle.io/creator'] === 'norman';
410
+ }
411
+
412
+ get provider() {
413
+ return this.$rootGetters['currentCluster'].provisioner.toLowerCase();
414
+ }
392
415
  }
393
416
 
394
417
  function calculatePercentage(allocatable, capacity) {
@@ -18,7 +18,7 @@ export default class FleetBundle extends SteveModel {
18
18
  }
19
19
 
20
20
  get lastUpdateTime() {
21
- return this.status.conditions[0].lastUpdateTime;
21
+ return this.status?.conditions?.[0].lastUpdateTime;
22
22
  }
23
23
 
24
24
  get bundleType() {
@@ -79,11 +79,11 @@ export default class HciCluster extends ProvCluster {
79
79
  const pkgName = `${ HARVESTER_NAME }-1.0.3`;
80
80
 
81
81
  if (uiOfflinePreferred === 'true') {
82
- // Embedded (aka give me the version of the embedded plugin that was in the last release)
83
- const embeddedPath = `dashboard/${ pkgName }/${ pkgName }.umd.min.js`;
82
+ // Embedded (aka give me the embedded plugin that was in the last rancher release)
83
+ const embeddedPath = `${ pkgName }/${ pkgName }.umd.min.js`;
84
84
 
85
85
  return {
86
- pkgUrl: process.env.dev ? `${ process.env.api }/${ embeddedPath }` : embeddedPath,
86
+ pkgUrl: process.env.dev ? `${ process.env.api }/dashboard/${ embeddedPath }` : embeddedPath,
87
87
  pkgName
88
88
  };
89
89
  }
@@ -111,15 +111,21 @@ export default class HciCluster extends ProvCluster {
111
111
  * Determine the harvester plugin's package name and url for clusters that provide the plugin
112
112
  */
113
113
  _supportedClusterPkgDetails(uiInfo, clusterId) {
114
- const pkgName = `${ HARVESTER_NAME }-${ uiInfo['ui-plugin-bundled-version'] }`;
114
+ let pkgName = `${ HARVESTER_NAME }-${ uiInfo['ui-plugin-bundled-version'] }`;
115
115
  const fileName = `${ pkgName }.umd.min.js`;
116
116
  let pkgUrl;
117
117
 
118
118
  if (uiInfo['ui-source'] === 'bundled' ) { // offline bundled
119
- pkgUrl = `k8s/clusters/${ clusterId }/v1/harvester/plugin-assets/${ fileName }`;
119
+ pkgUrl = `/k8s/clusters/${ clusterId }/v1/harvester/plugin-assets/${ fileName }`;
120
120
  } else if (uiInfo['ui-source'] === 'external') {
121
121
  if (uiInfo['ui-plugin-index']) {
122
122
  pkgUrl = uiInfo['ui-plugin-index'];
123
+
124
+ // When using an external address, the pkgName should also be get from the url
125
+ const names = pkgUrl.split('/');
126
+ const jsName = names[names.length - 1];
127
+
128
+ pkgName = jsName?.split('.umd.min.js')[0];
123
129
  } else {
124
130
  throw new Error('Harvester cluster requested the plugin at `ui-plugin-index` is used, however did not provide a value for it');
125
131
  }
package/models/pod.js CHANGED
@@ -182,19 +182,29 @@ export default class Pod extends WorkloadService {
182
182
  }
183
183
 
184
184
  save() {
185
+ const prev = { ...this };
186
+
185
187
  const { metadata, spec } = this.spec.template;
186
188
 
187
189
  this.spec = {
188
190
  ...this.spec,
189
- metadata: {
190
- ...this.metadata,
191
- ...metadata
192
- },
193
191
  ...spec
194
192
  };
195
193
 
194
+ this.metadata = {
195
+ ...this.metadata,
196
+ ...metadata
197
+ };
198
+
196
199
  delete this.spec.template;
197
200
 
198
- return this._save(...arguments);
201
+ // IF there is an error POD world model get overwritten
202
+ // For the workloads this need be reset back
203
+ return this._save(...arguments).catch((e) => {
204
+ this.spec = prev.spec;
205
+ this.metadata = prev.metadata;
206
+
207
+ return Promise.reject(e);
208
+ });
199
209
  }
200
210
  }
@@ -197,12 +197,10 @@ export default class ProvCluster extends SteveModel {
197
197
  return super.canEditYaml;
198
198
  }
199
199
 
200
- get isAKS() {
201
- return this.provisioner === 'AKS';
202
- }
200
+ get isHostedKubernetesProvider() {
201
+ const providers = ['AKS', 'EKS', 'GKE'];
203
202
 
204
- get isEKS() {
205
- return this.provisioner === 'EKS';
203
+ return providers.includes(this.provisioner);
206
204
  }
207
205
 
208
206
  get isImported() {
@@ -230,13 +228,17 @@ export default class ProvCluster extends SteveModel {
230
228
  get isImportedK3s() {
231
229
  // As of Rancher v2.6.7, this returns false for imported K3s clusters,
232
230
  // in which this.provisioner is `k3s`.
233
- return this.isImported && this.mgmt?.status?.provider === 'k3s';
231
+ return this.isImported && this.isK3s;
234
232
  }
235
233
 
236
234
  get isImportedRke2() {
237
235
  return this.isImported && this.mgmt?.status?.provider?.startsWith('rke2');
238
236
  }
239
237
 
238
+ get isK3s() {
239
+ return this.mgmt?.status?.provider === 'k3s';
240
+ }
241
+
240
242
  get isRke2() {
241
243
  return !!this.spec?.rkeConfig;
242
244
  }
@@ -677,6 +679,10 @@ export default class ProvCluster extends SteveModel {
677
679
  }
678
680
 
679
681
  get supportsWindows() {
682
+ if (this.isK3s || this.isImportedK3s) {
683
+ return false;
684
+ }
685
+
680
686
  if ( this.isRke1 ) {
681
687
  return this.mgmt?.spec?.windowsPreferedCluster || false;
682
688
  }
@@ -764,4 +770,8 @@ export default class ProvCluster extends SteveModel {
764
770
  await this.$dispatch('ws.resource.remove', { data: this });
765
771
  }
766
772
  }
773
+
774
+ get hasError() {
775
+ return this.status?.conditions?.some(condition => condition.error === true);
776
+ }
767
777
  }