@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
@@ -1,14 +1,17 @@
1
1
  <script>
2
2
  import { CAPI } from '@shell/config/types';
3
3
  import AsyncButton from '@shell/components/AsyncButton';
4
+ import PromptModal from '@shell/components/PromptModal';
4
5
  import { downloadFile } from '@shell/utils/download';
5
6
  import { filterOnlyKubernetesClusters, filterHiddenLocalCluster } from '@shell/utils/cluster';
6
7
  import { sortBy } from '@shell/utils/sort';
7
- import { Checkbox } from '@components/Form/Checkbox';
8
8
 
9
9
  export default {
10
- layout: 'plain',
11
- components: { AsyncButton, Checkbox },
10
+ name: 'Diagnostic',
11
+ layout: 'plain',
12
+
13
+ components: { AsyncButton, PromptModal },
14
+
12
15
  async fetch() {
13
16
  const provClusters = await this.$store.dispatch('management/findAll', { type: CAPI.RANCHER_CLUSTER });
14
17
  const readyClusters = provClusters.filter(c => c.mgmt?.isReady);
@@ -20,9 +23,11 @@ export default {
20
23
  clusterForCounts.forEach((cluster, i) => {
21
24
  finalCounts.push({
22
25
  id: cluster.id,
26
+ name: cluster.metadata?.name,
27
+ namespace: cluster.metadata?.namespace,
23
28
  capiId: cluster.mgmt?.id,
24
29
  counts: null,
25
- isTableVisible: i === 0
30
+ isTableVisible: !!(i === 0 && clusterForCounts.length === 1)
26
31
  });
27
32
  promises.push(this.$store.dispatch('management/request', { url: `/k8s/clusters/${ cluster.mgmt?.id }/v1/counts` }));
28
33
  });
@@ -47,7 +52,7 @@ export default {
47
52
 
48
53
  topTenForResponseTime = topTenForResponseTime.concat(sortedCount);
49
54
  topTenForResponseTime = sortBy(topTenForResponseTime, 'count:desc');
50
- topTenForResponseTime = topTenForResponseTime.splice(0, 10);
55
+ topTenForResponseTime = topTenForResponseTime.splice(0, 15);
51
56
 
52
57
  topTenForResponseTime.forEach((item, i) => {
53
58
  topTenForResponseTime[i].id = finalCounts[index].id;
@@ -63,58 +68,50 @@ export default {
63
68
  },
64
69
 
65
70
  data() {
71
+ const {
72
+ userAgent,
73
+ userAgentData,
74
+ language,
75
+ cookieEnabled,
76
+ hardwareConcurrency,
77
+ deviceMemory
78
+ } = window?.navigator;
79
+
66
80
  const systemInformation = {
67
- browserUserAgent: {
68
- label: this.t('about.diagnostic.systemInformation.browserUserAgent'),
69
- value: window?.navigator?.userAgent
81
+ browser: {
82
+ label: this.t('about.diagnostic.systemInformation.browser'),
83
+ value: this.t('about.diagnostic.systemInformation.browserInfo', {
84
+ userAgent, language, cookieEnabled
85
+ })
70
86
  },
71
- browserLanguage: {
72
- label: this.t('about.diagnostic.systemInformation.browserLanguage'),
73
- value: window?.navigator?.language
74
- },
75
- cookieEnabled: {
76
- label: this.t('about.diagnostic.systemInformation.cookieEnabled'),
77
- value: window?.navigator?.cookieEnabled
78
- },
79
- hardwareConcurrency: {
80
- label: this.t('about.diagnostic.systemInformation.hardwareConcurrency'),
81
- value: window?.navigator?.hardwareConcurrency
87
+ system: {
88
+ label: this.t('about.diagnostic.systemInformation.system'),
89
+ value: this.t('about.diagnostic.systemInformation.hardwareConcurrency', { hardwareConcurrency })
82
90
  },
91
+ jsMemory: {
92
+ label: this.t('about.diagnostic.systemInformation.jsMemory'),
93
+ value: ''
94
+ }
83
95
  };
84
96
 
85
- if (window?.navigator?.userAgentData?.platform) {
86
- systemInformation.os = {
87
- label: this.t('about.diagnostic.systemInformation.os'),
88
- value: window?.navigator?.userAgentData?.platform
89
- };
97
+ if ( userAgentData?.platform ) {
98
+ systemInformation.system.value = systemInformation.system.value.concat(', ', this.t('about.diagnostic.systemInformation.os', { platform: userAgentData.platform }));
90
99
  }
91
100
 
92
- if (window?.navigator?.deviceMemory) {
93
- systemInformation.deviceMemory = {
94
- label: this.t('about.diagnostic.systemInformation.deviceMemory'),
95
- value: window?.navigator?.deviceMemory
96
- };
101
+ if ( deviceMemory ) {
102
+ systemInformation.system.value = systemInformation.system.value.concat(', ', this.t('about.diagnostic.systemInformation.deviceMemory', { deviceMemory }));
97
103
  }
98
104
 
99
- if (window?.performance?.memory?.jsHeapSizeLimit) {
100
- systemInformation.memJsHeapLimit = {
101
- label: this.t('about.diagnostic.systemInformation.memJsHeapLimit'),
102
- value: window?.performance?.memory?.jsHeapSizeLimit
103
- };
105
+ if ( window?.performance?.memory?.jsHeapSizeLimit ) {
106
+ systemInformation.jsMemory.value += this.t('about.diagnostic.systemInformation.memJsHeapLimit', { jsHeapSizeLimit: window?.performance?.memory?.jsHeapSizeLimit });
104
107
  }
105
108
 
106
- if (window?.performance?.memory?.totalJSHeapSize) {
107
- systemInformation.memTotalJsHeapSize = {
108
- label: this.t('about.diagnostic.systemInformation.memTotalJsHeapSize'),
109
- value: window?.performance?.memory?.totalJSHeapSize
110
- };
109
+ if ( window?.performance?.memory?.totalJSHeapSize ) {
110
+ systemInformation.jsMemory.value += `, ${ this.t('about.diagnostic.systemInformation.memTotalJsHeapSize', { totalJSHeapSize: window?.performance?.memory?.totalJSHeapSize }) }`;
111
111
  }
112
112
 
113
- if (window?.performance?.memory?.usedJSHeapSize) {
114
- systemInformation.memUsedJsHeapSize = {
115
- label: this.t('about.diagnostic.systemInformation.memUsedJsHeapSize'),
116
- value: window?.performance?.memory?.usedJSHeapSize
117
- };
113
+ if ( window?.performance?.memory?.usedJSHeapSize ) {
114
+ systemInformation.jsMemory.value += `, ${ this.t('about.diagnostic.systemInformation.memUsedJsHeapSize', { usedJSHeapSize: window?.performance?.memory?.usedJSHeapSize }) }`;
118
115
  }
119
116
 
120
117
  // scroll logs container to the bottom
@@ -123,22 +120,26 @@ export default {
123
120
  return {
124
121
  systemInformation,
125
122
  topTenForResponseTime: null,
123
+ responseTimes: null,
126
124
  finalCounts: null,
127
125
  includeResponseTimes: true,
128
126
  storeMapping: this.$store?._modules?.root?.state,
129
127
  latestLogs: console.logs // eslint-disable-line no-console
130
128
  };
131
129
  },
130
+
132
131
  watch: {
133
132
  latestLogs() {
134
133
  this.scrollLogsToBottom();
135
134
  }
136
135
  },
136
+
137
137
  computed: {
138
- name() {
139
- return this.data;
138
+ clusterCount() {
139
+ return this.finalCounts?.length;
140
140
  }
141
141
  },
142
+
142
143
  methods: {
143
144
  scrollLogsToBottom() {
144
145
  this.$nextTick(() => {
@@ -147,12 +148,14 @@ export default {
147
148
  logsContainer.scrollTop = logsContainer.scrollHeight;
148
149
  });
149
150
  },
151
+
150
152
  generateKey(data) {
151
153
  const randomize = Math.random() * 10000;
152
154
 
153
155
  return `key_${ randomize }_${ data }`;
154
156
  },
155
- async downloadData(btnCb) {
157
+
158
+ downloadData(btnCb) {
156
159
  const date = new Date().toLocaleDateString();
157
160
  const time = new Date().toLocaleTimeString();
158
161
  const fileName = `rancher-diagnostic-data-${ date }-${ time.replaceAll(':', '_') }.json`;
@@ -160,25 +163,45 @@ export default {
160
163
  systemInformation: this.systemInformation,
161
164
  logs: this.latestLogs,
162
165
  storeMapping: this.parseStoreData(this.storeMapping),
163
- resourceCounts: this.finalCounts
166
+ resourceCounts: this.finalCounts,
167
+ responseTimes: this.responseTimes
164
168
  };
165
169
 
166
- if (this.includeResponseTimes) {
167
- const responseTimes = await this.gatherResponseTimes();
168
-
169
- data.responseTimes = responseTimes;
170
- }
171
-
172
170
  downloadFile(fileName, JSON.stringify(data), 'application/json')
173
171
  .then(() => btnCb(true))
174
172
  .catch(() => btnCb(false));
175
173
  },
174
+
175
+ setResourceResponseTiming(responseTimes) {
176
+ responseTimes?.forEach((res) => {
177
+ if ( res.outcome === 'success' ) {
178
+ const cluster = this.finalCounts.find(c => c.capiId === res.item.capiId);
179
+ const countIndex = cluster?.counts?.findIndex(c => c.resource === res.item.resource);
180
+
181
+ if ( (countIndex && countIndex !== -1) || countIndex === 0 ) {
182
+ this.$set(cluster?.counts[countIndex], 'durationMs', res.durationMs);
183
+ }
184
+ }
185
+ });
186
+ },
187
+
188
+ sumResourceCount(counts) {
189
+ return counts.reduce((a, b) => (a + b.count), 0);
190
+ },
191
+
192
+ nodeCount(counts) {
193
+ const resource = counts.findIndex(c => c.resource === 'node');
194
+
195
+ return counts[resource]?.count;
196
+ },
197
+
176
198
  toggleTable(area) {
177
199
  const itemIndex = this.finalCounts.findIndex(item => item.id === area);
178
200
 
179
201
  this.finalCounts[itemIndex].isTableVisible = !this.finalCounts[itemIndex].isTableVisible;
180
202
  },
181
- async gatherResponseTimes() {
203
+
204
+ async gatherResponseTimes(btnCb) {
182
205
  return await Promise.all(this.topTenForResponseTime.map((item) => {
183
206
  const t = Date.now();
184
207
 
@@ -190,11 +213,14 @@ export default {
190
213
  outcome: 'error', item, durationMs: Date.now() - t
191
214
  }));
192
215
  })).then((responseTimes) => {
193
- return responseTimes;
194
- });
216
+ this.responseTimes = responseTimes;
217
+ this.setResourceResponseTiming(responseTimes);
218
+ btnCb(true);
219
+ }).catch(() => btnCb(false));
195
220
  },
221
+
196
222
  parseStoreData(rootStore) {
197
- // clear potencial sensitive data
223
+ // clear potential sensitive data
198
224
  const disallowedDataKeys = [
199
225
  'aws',
200
226
  'digitalocean',
@@ -252,6 +278,21 @@ export default {
252
278
  });
253
279
 
254
280
  return cleanRootStore;
281
+ },
282
+
283
+ promptDownload(btnCb) {
284
+ const resources = [{ downloadData: this.downloadData, gatherResponseTimes: this.gatherResponseTimes }];
285
+
286
+ if ( !this.responseTimes ) {
287
+ this.$store.dispatch('management/promptModal', {
288
+ component: 'DiagnosticTimingsDialog',
289
+ resources
290
+ })
291
+ .then(() => btnCb(true))
292
+ .catch(() => btnCb(false));
293
+ } else {
294
+ this.downloadData(btnCb);
295
+ }
255
296
  }
256
297
  },
257
298
  };
@@ -260,27 +301,25 @@ export default {
260
301
  <template>
261
302
  <div>
262
303
  <div class="title-block mt-20 mb-40">
263
- <h1
264
- v-t="'about.diagnostic.title'"
265
- class="mt-20 mb-40"
266
- />
267
304
  <div>
268
- <Checkbox
269
- v-model="includeResponseTimes"
270
- v-tooltip.left="t('about.diagnostic.checkboxTooltip')"
271
- :label="t('about.diagnostic.checkboxLabel')"
305
+ <AsyncButton
306
+ mode="timing"
307
+ class="mr-20"
308
+ @click="gatherResponseTimes"
272
309
  />
273
310
  <AsyncButton
274
311
  mode="diagnostic"
275
- @click="downloadData"
312
+ @click="promptDownload"
276
313
  />
277
314
  </div>
278
315
  </div>
316
+
317
+ <!-- System info -->
279
318
  <div class="mb-40">
280
319
  <h2 class="mb-20">
281
320
  {{ t('about.diagnostic.systemInformation.subtitle') }}
282
321
  </h2>
283
- <table>
322
+ <table class="full-width">
284
323
  <thead>
285
324
  <tr>
286
325
  <th>Type</th>
@@ -289,33 +328,19 @@ export default {
289
328
  </thead>
290
329
  <tbody>
291
330
  <tr v-for="(item, objKey) in systemInformation" :key="objKey">
292
- <td>{{ item.label }}</td>
293
- <td>{{ item.value }}</td>
331
+ <template v-if="item.value.length">
332
+ <td>{{ item.label }}</td>
333
+ <td>{{ item.value }}</td>
334
+ </template>
294
335
  </tr>
295
336
  </tbody>
296
337
  </table>
297
338
  </div>
339
+
340
+ <!-- Resources -->
298
341
  <div class="mb-40">
299
342
  <h2 class="mb-20">
300
- {{ t('about.diagnostic.logs.subtitle') }}
301
- </h2>
302
- <ul class="logs-container">
303
- <li
304
- v-for="logEntry in latestLogs"
305
- :key="generateKey(logEntry.timestamp)"
306
- :class="logEntry.type"
307
- >
308
- <span class="log-entry-type">{{ logEntry.type }} :: </span>
309
- <span
310
- v-for="(arg, i) in logEntry.data"
311
- :key="i"
312
- >{{ arg }}</span>
313
- </li>
314
- </ul>
315
- </div>
316
- <div class="mb-40">
317
- <h2 class="mb-20">
318
- {{ t('about.diagnostic.resourceCounts.subtitle') }}
343
+ {{ t('about.diagnostic.resourceCounts', { count: clusterCount }) }}
319
344
  </h2>
320
345
  <div class="resources-count-container">
321
346
  <table
@@ -324,9 +349,12 @@ export default {
324
349
  class="full-width"
325
350
  >
326
351
  <thead @click="toggleTable(cluster.id)">
327
- <th colspan="2">
328
- <div>
329
- <span>{{ cluster.id }}</span>
352
+ <th colspan="4">
353
+ <div class="cluster-row">
354
+ <span>Cluster: <b>{{ cluster.name }}</b></span>
355
+ <span>Namespace: <b>{{ cluster.namespace }}</b></span>
356
+ <span>Total Resources: <b>{{ sumResourceCount(cluster.counts) }}</b></span>
357
+ <span>Nodes: <b>{{ nodeCount(cluster.counts) }}</b></span>
330
358
  <i
331
359
  class="icon"
332
360
  :class="{
@@ -338,21 +366,60 @@ export default {
338
366
  </th>
339
367
  </thead>
340
368
  <tbody v-show="cluster.isTableVisible">
369
+ <tr>
370
+ <th>
371
+ Resource
372
+ </th>
373
+ <th>
374
+ Count
375
+ </th>
376
+ <th>
377
+ Resource Timing (ms)
378
+ </th>
379
+ </tr>
380
+
341
381
  <tr v-for="item in cluster.counts" :key="item.resource">
342
- <td>{{ item.resource }}</td>
343
- <td>{{ item.count }}</td>
382
+ <template v-if="item.count > 0">
383
+ <td scope="row">
384
+ {{ item.resource }}
385
+ </td>
386
+ <td>{{ item.count }}</td>
387
+ <td>{{ item.durationMs || '-' }}</td>
388
+ </template>
344
389
  </tr>
345
390
  </tbody>
346
391
  </table>
347
392
  </div>
348
393
  </div>
394
+
395
+ <!-- Logs -->
396
+ <div class="mb-40">
397
+ <h2 class="mb-20">
398
+ {{ t('about.diagnostic.logs.subtitle') }}
399
+ </h2>
400
+ <ul class="logs-container">
401
+ <li
402
+ v-for="logEntry in latestLogs"
403
+ :key="generateKey(logEntry.timestamp)"
404
+ :class="logEntry.type"
405
+ >
406
+ <span class="log-entry-type">{{ logEntry.type }} :: </span>
407
+ <span
408
+ v-for="(arg, i) in logEntry.data"
409
+ :key="i"
410
+ >{{ arg }}</span>
411
+ </li>
412
+ </ul>
413
+ </div>
414
+
415
+ <PromptModal />
349
416
  </div>
350
417
  </template>
351
418
 
352
419
  <style lang="scss" scoped>
353
420
  .title-block {
354
421
  display: flex;
355
- justify-content: space-between;
422
+ justify-content: right;
356
423
  align-items: center;
357
424
 
358
425
  h1 {
@@ -383,6 +450,10 @@ table {
383
450
  justify-content: space-between;
384
451
  }
385
452
  }
453
+
454
+ tbody {
455
+ border-bottom: 1px solid var(--sortable-table-top-divider);
456
+ }
386
457
  }
387
458
 
388
459
  tr > td:first-of-type {
@@ -398,7 +469,7 @@ table {
398
469
 
399
470
  th {
400
471
  background-color: var(--sortable-table-top-divider);
401
- border-bottom: 1px solid var(--sortable-table-top-divider);
472
+ border-bottom: 1px solid var(--sortable-table-header-bg);
402
473
  }
403
474
 
404
475
  a {
@@ -458,11 +529,24 @@ table {
458
529
  }
459
530
 
460
531
  .resources-count-container {
461
- table:nth-child(even) {
462
- th {
463
- background-color: rgb(239, 239, 239);
464
- color: #000;
465
- }
532
+ .cluster-row {
533
+ display: grid;
534
+ grid-template-columns: repeat(4, 1fr) 20px;
535
+ grid-template-rows: 1fr;
536
+ align-content: center;
537
+ font-weight: normal;
538
+ }
539
+
540
+ tbody tr, tbody tr th {
541
+ background-color: var(--sortable-table-header-bg);
542
+ }
543
+
544
+ tbody tr th {
545
+ border-bottom: 1px solid var(--sortable-table-top-divider);
546
+ }
547
+
548
+ tbody tr:hover {
549
+ background-color: var(--sortable-table-top-divider);
466
550
  }
467
551
  }
468
552
  </style>
@@ -301,10 +301,12 @@ export default {
301
301
 
302
302
  thead > tr > th {
303
303
  background-color: var(--sortable-table-header-bg);
304
+ line-height: 1.75em;
304
305
  }
305
306
 
306
307
  tbody > tr.table-group > td {
307
- background-color: var(--sortable-table-selected-bg);
308
+ background-color: var(--sortable-table-header-bg);
309
+ font-weight: bold;
308
310
  }
309
311
 
310
312
  thead, tbody {
package/pages/home.vue CHANGED
@@ -6,7 +6,6 @@ import IndentedPanel from '@shell/components/IndentedPanel';
6
6
  import SortableTable from '@shell/components/SortableTable';
7
7
  import { BadgeState } from '@components/BadgeState';
8
8
  import CommunityLinks from '@shell/components/CommunityLinks';
9
- import SimpleBox from '@shell/components/SimpleBox';
10
9
  import SingleClusterInfo from '@shell/components/SingleClusterInfo';
11
10
  import { mapGetters, mapState } from 'vuex';
12
11
  import { MANAGEMENT, CAPI } from '@shell/config/types';
@@ -18,7 +17,6 @@ import { getVersionInfo, readReleaseNotes, markReadReleaseNotes, markSeenRelease
18
17
  import PageHeaderActions from '@shell/mixins/page-actions';
19
18
  import { getVendor } from '@shell/config/private-label';
20
19
  import { mapFeature, MULTI_CLUSTER } from '@shell/store/features';
21
- import { SETTING } from '@shell/config/settings';
22
20
  import { BLANK_CLUSTER } from '@shell/store';
23
21
  import { filterOnlyKubernetesClusters, filterHiddenLocalCluster } from '@shell/utils/cluster';
24
22
 
@@ -34,7 +32,6 @@ export default {
34
32
  SortableTable,
35
33
  BadgeState,
36
34
  CommunityLinks,
37
- SimpleBox,
38
35
  SingleClusterInfo,
39
36
  },
40
37
 
@@ -114,10 +111,6 @@ export default {
114
111
  return this.homePageCards?.setLoginPage;
115
112
  },
116
113
 
117
- showSidePanel() {
118
- return this.showCommercialSupport || this.showCommunityLinks;
119
- },
120
-
121
114
  clusterHeaders() {
122
115
  return [
123
116
  STATE,
@@ -170,24 +163,6 @@ export default {
170
163
  ];
171
164
  },
172
165
 
173
- showCommercialSupport() {
174
- const canEditSettings = (this.$store.getters['management/schemaFor'](MANAGEMENT.SETTING)?.resourceMethods || []).includes('PUT');
175
-
176
- const hasSupport = this.$store.getters['management/byId'](MANAGEMENT.SETTING, SETTING.SUPPORTED) || {};
177
-
178
- return !this.homePageCards.commercialSupportTip && hasSupport.value !== 'true' && canEditSettings;
179
- },
180
-
181
- showCommunityLinks() {
182
- const uiIssuesSetting = this.$store.getters['management/byId'](MANAGEMENT.SETTING, SETTING.UI_ISSUES) || {};
183
- const communityLinksSetting = this.$store.getters['management/byId'](MANAGEMENT.SETTING, SETTING.COMMUNITY_LINKS) || {};
184
-
185
- const hasSomethingToShow = communityLinksSetting?.value !== 'false' || !!( uiIssuesSetting.value && uiIssuesSetting.value !== '');
186
- const hiddenByPreference = this.homePageCards.communitySupportTip === true;
187
-
188
- return hasSomethingToShow && !hiddenByPreference;
189
- },
190
-
191
166
  ...mapGetters(['currentCluster', 'defaultClusterId']),
192
167
 
193
168
  kubeClusters() {
@@ -289,26 +264,9 @@ export default {
289
264
  </div>
290
265
  </div>
291
266
 
292
- <div class="row">
293
- <div :class="{'span-9': showSidePanel, 'span-12': !showSidePanel }" class="col">
294
- <SimpleBox
295
- id="migration"
296
- class="panel"
297
- :title="t('landing.gettingStarted.title')"
298
- :pref="HIDE_HOME_PAGE_CARDS"
299
- pref-key="migrationTip"
300
- >
301
- <div class="getting-started">
302
- <span>
303
- {{ t('landing.gettingStarted.body') }}
304
- </span>
305
- <nuxt-link :to="{name: 'docs-doc', params: {doc: 'getting-started'}}" class="getting-started-btn">
306
- {{ t('landing.learnMore') }}
307
- </nuxt-link>
308
- </div>
309
- </SimpleBox>
310
-
311
- <div v-if="!showSetLoginBanner" class="mt-5 mb-10 row">
267
+ <div class="row home-panels">
268
+ <div class="col main-panel">
269
+ <div v-if="!showSetLoginBanner" class="mb-10 row">
312
270
  <div class="col span-12">
313
271
  <Banner color="set-login-page" :closable="true" @close="closeSetLoginBanner()">
314
272
  <div>{{ t('landing.landingPrefs.title') }}</div>
@@ -316,7 +274,6 @@ export default {
316
274
  </Banner>
317
275
  </div>
318
276
  </div>
319
-
320
277
  <div class="row panel">
321
278
  <div v-if="mcm" class="col span-12">
322
279
  <SortableTable
@@ -354,7 +311,7 @@ export default {
354
311
  <template #col:name="{row}">
355
312
  <td>
356
313
  <span v-if="row.mgmt">
357
- <n-link v-if="row.mgmt.isReady" :to="{ name: 'c-cluster-explorer', params: { cluster: row.mgmt.id }}">
314
+ <n-link v-if="row.mgmt.isReady && !row.hasError" :to="{ name: 'c-cluster-explorer', params: { cluster: row.mgmt.id }}">
358
315
  {{ row.nameDisplay }}
359
316
  </n-link>
360
317
  <span v-else>{{ row.nameDisplay }}</span>
@@ -392,22 +349,30 @@ export default {
392
349
  </div>
393
350
  </div>
394
351
  </div>
395
- <div v-if="showSidePanel" class="col span-3">
396
- <CommunityLinks v-if="showCommunityLinks" :pref="HIDE_HOME_PAGE_CARDS" pref-key="communitySupportTip" class="mb-20" />
397
- <SimpleBox v-if="showCommercialSupport" :pref="HIDE_HOME_PAGE_CARDS" pref-key="commercialSupportTip" :title="t('landing.commercial.title')">
398
- <nuxt-link :to="{ path: 'support'}">
399
- {{ t('landing.commercial.body') }}
400
- </nuxt-link>
401
- </SimpleBox>
402
- </div>
352
+ <CommunityLinks class="col span-3 side-panel" />
403
353
  </div>
404
354
  </IndentedPanel>
405
355
  </div>
406
356
  </template>
407
357
  <style lang='scss' scoped>
358
+ .home-panels {
359
+ display: flex;
360
+ align-items: stretch;
361
+ .col {
362
+ margin: 0
363
+ }
364
+ .main-panel {
365
+ flex: auto;
366
+ }
367
+
368
+ .side-panel {
369
+ margin-left: 1.75%;
370
+ }
371
+ }
372
+
408
373
  .banner.info.whats-new, .banner.set-login-page {
409
374
  border: 0;
410
- margin-top: 10px;
375
+ margin-top: 0;
411
376
  display: flex;
412
377
  align-items: center;
413
378
  flex-direction: row;