@rancher/shell 0.4.0 → 0.5.1

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 (243) 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 +30 -5
  5. package/assets/translations/zh-hans.yaml +1 -1
  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/Certificates.vue +164 -0
  14. package/components/CodeMirror.vue +19 -21
  15. package/components/CruResource.vue +1 -0
  16. package/components/EtcdInfoBanner.vue +1 -1
  17. package/components/ExplorerProjectsNamespaces.vue +25 -1
  18. package/components/IconOrSvg.vue +1 -1
  19. package/components/LandingPagePreference.vue +1 -4
  20. package/components/Questions/index.vue +1 -1
  21. package/components/ResourceDetail/Masthead.vue +16 -3
  22. package/components/ResourceTable.vue +14 -2
  23. package/components/ResourceYaml.vue +5 -0
  24. package/components/SideNav.vue +1 -1
  25. package/components/SingleClusterInfo.vue +1 -4
  26. package/components/Tabbed/index.vue +12 -0
  27. package/components/fleet/FleetRepos.vue +62 -27
  28. package/components/fleet/FleetResources.vue +6 -1
  29. package/components/form/ArrayListSelect.vue +10 -0
  30. package/components/form/KeyValue.vue +4 -0
  31. package/components/form/LabeledSelect.vue +4 -0
  32. package/components/formatter/Checked.vue +11 -3
  33. package/components/formatter/FleetClusterSummaryGraph.vue +27 -0
  34. package/components/formatter/FleetSummaryGraph.vue +23 -11
  35. package/components/formatter/LiveDuration.vue +1 -1
  36. package/components/formatter/PercentageBar.vue +1 -1
  37. package/components/formatter/__tests__/Checked.test.ts +19 -0
  38. package/components/nav/Group.vue +2 -2
  39. package/components/nav/Header.vue +0 -1
  40. package/components/nav/TopLevelMenu.vue +36 -6
  41. package/components/nav/Type.vue +1 -3
  42. package/components/nav/WindowManager/ContainerLogs.vue +101 -3
  43. package/components/nav/WindowManager/ContainerShell.vue +6 -1
  44. package/components/nav/WindowManager/__tests__/ContainerLogs.test.ts +186 -0
  45. package/components/nav/WindowManager/index.vue +11 -10
  46. package/components/nav/__tests__/TopLevelMenu.test.ts +33 -0
  47. package/components/nav/__tests__/Type.test.ts +1 -1
  48. package/components/nuxt/nuxt-child.js +14 -78
  49. package/components/nuxt/nuxt.js +1 -1
  50. package/{layouts → components/templates}/blank.vue +1 -1
  51. package/{layouts → components/templates}/default.vue +8 -98
  52. package/{layouts → components/templates}/error.vue +10 -19
  53. package/{layouts → components/templates}/home.vue +4 -1
  54. package/{layouts → components/templates}/plain.vue +4 -1
  55. package/{layouts → components/templates}/standalone.vue +1 -1
  56. package/{layouts → components/templates}/unauthenticated.vue +1 -1
  57. package/composables/useCompactInput.ts +20 -0
  58. package/composables/useLabeledFormElement.ts +138 -0
  59. package/config/harvester-manager-types.js +2 -0
  60. package/config/private-label.js +22 -0
  61. package/config/product/explorer.js +3 -0
  62. package/config/product/fleet.js +6 -1
  63. package/config/product/manager.js +8 -2
  64. package/config/query-params.js +1 -0
  65. package/config/router.js +385 -364
  66. package/config/settings.ts +1 -0
  67. package/config/store.js +1 -1
  68. package/config/system-namespaces.js +3 -0
  69. package/config/table-headers.js +47 -0
  70. package/core/plugin-routes.ts +56 -114
  71. package/core/plugin.ts +16 -10
  72. package/core/plugins-loader.js +7 -9
  73. package/core/plugins.js +0 -3
  74. package/creators/app/files/.gitlab-ci.yml +1 -1
  75. package/detail/fleet.cattle.io.cluster.vue +11 -1
  76. package/detail/provisioning.cattle.io.cluster.vue +4 -3
  77. package/dialog/ScaleMachineDownDialog.vue +34 -17
  78. package/edit/__tests__/service.test.ts +89 -0
  79. package/edit/auth/googleoauth.vue +1 -5
  80. package/edit/catalog.cattle.io.clusterrepo.vue +18 -0
  81. package/edit/cloudcredential.vue +2 -0
  82. package/edit/configmap.vue +2 -1
  83. package/edit/networking.k8s.io.networkpolicy/__tests__/PolicyRuleTarget.spec.ts +1 -1
  84. package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +15 -7
  85. package/edit/provisioning.cattle.io.cluster/__tests__/Advanced.test.ts +112 -0
  86. package/edit/provisioning.cattle.io.cluster/__tests__/Basics.test.ts +473 -0
  87. package/edit/provisioning.cattle.io.cluster/__tests__/{CustomCommand.tests.ts → CustomCommand.test.ts} +4 -0
  88. package/edit/provisioning.cattle.io.cluster/__tests__/DrainOptions.test.ts +1 -1
  89. package/edit/provisioning.cattle.io.cluster/__tests__/index.test.ts +73 -0
  90. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +7 -1
  91. package/edit/provisioning.cattle.io.cluster/__tests__/utils/cluster.ts +386 -0
  92. package/edit/provisioning.cattle.io.cluster/import.vue +2 -2
  93. package/edit/provisioning.cattle.io.cluster/index.vue +92 -36
  94. package/edit/provisioning.cattle.io.cluster/rke2.vue +171 -583
  95. package/edit/provisioning.cattle.io.cluster/tabs/AddOnConfig.vue +137 -0
  96. package/edit/provisioning.cattle.io.cluster/tabs/Advanced.vue +157 -0
  97. package/edit/provisioning.cattle.io.cluster/{Basics.vue → tabs/Basics.vue} +94 -19
  98. package/edit/provisioning.cattle.io.cluster/{MachinePool.vue → tabs/MachinePool.vue} +1 -0
  99. package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +135 -0
  100. package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +189 -0
  101. package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +144 -0
  102. package/edit/provisioning.cattle.io.cluster/tabs/upgrade/index.vue +76 -0
  103. package/edit/service.vue +12 -0
  104. package/edit/workload/mixins/workload.js +1 -1
  105. package/initialize/App.js +25 -71
  106. package/initialize/client.js +21 -162
  107. package/initialize/index.js +27 -123
  108. package/list/management.cattle.io.feature.vue +1 -7
  109. package/list/node.vue +1 -0
  110. package/machine-config/__tests__/vmwarevsphere.test.ts +100 -21
  111. package/machine-config/vmwarevsphere.vue +73 -51
  112. package/middleware/authenticated.js +10 -17
  113. package/mixins/auth-config.js +2 -7
  114. package/mixins/brand.js +29 -41
  115. package/mixins/labeled-form-element.ts +6 -1
  116. package/models/__tests__/management.cattle.io.node.ts +85 -0
  117. package/models/__tests__/management.cattle.io.nodepool.ts +83 -0
  118. package/models/__tests__/namespace.test.ts +49 -9
  119. package/models/__tests__/workload.test.ts +91 -0
  120. package/models/cluster/node.js +4 -4
  121. package/models/cluster.x-k8s.io.machinedeployment.js +14 -0
  122. package/models/fleet.cattle.io.cluster.js +4 -0
  123. package/models/fleet.cattle.io.gitrepo.js +56 -13
  124. package/models/management.cattle.io.kontainerdriver.js +1 -1
  125. package/models/management.cattle.io.node.js +18 -14
  126. package/models/management.cattle.io.nodepool.js +17 -0
  127. package/models/namespace.js +1 -1
  128. package/models/pod.js +20 -0
  129. package/models/provisioning.cattle.io.cluster.js +20 -3
  130. package/models/secret.js +117 -18
  131. package/models/workload.js +16 -0
  132. package/models/workload.service.js +18 -0
  133. package/package.json +10 -9
  134. package/pages/about.vue +0 -1
  135. package/pages/account/create-key.vue +0 -1
  136. package/pages/account/index.vue +0 -1
  137. package/pages/auth/login.vue +0 -1
  138. package/pages/auth/logout.vue +0 -2
  139. package/pages/auth/setup.vue +0 -4
  140. package/pages/auth/verify.vue +14 -8
  141. package/pages/c/_cluster/apps/charts/install.vue +4 -4
  142. package/pages/c/_cluster/apps/index.vue +0 -2
  143. package/pages/c/_cluster/auth/index.vue +0 -2
  144. package/pages/c/_cluster/ecm/index.vue +0 -2
  145. package/pages/c/_cluster/explorer/index.vue +28 -2
  146. package/pages/c/_cluster/fleet/index.vue +1 -1
  147. package/pages/c/_cluster/index.vue +0 -2
  148. package/pages/c/_cluster/settings/banners.vue +0 -2
  149. package/pages/c/_cluster/settings/brand.vue +0 -2
  150. package/pages/c/_cluster/settings/index.vue +0 -2
  151. package/pages/c/_cluster/settings/links.vue +0 -1
  152. package/pages/c/_cluster/settings/performance.vue +0 -1
  153. package/pages/c/_cluster/uiplugins/CatalogList/CatalogLoadDialog.vue +2 -1
  154. package/pages/c/_cluster/uiplugins/CatalogList/index.vue +10 -46
  155. package/pages/c/_cluster/uiplugins/index.vue +0 -2
  156. package/pages/diagnostic.vue +1 -2
  157. package/pages/fail-whale.vue +0 -1
  158. package/pages/prefs.vue +0 -1
  159. package/pages/support/index.vue +2 -8
  160. package/pkg/auto-import.js +1 -1
  161. package/plugins/axios.js +0 -36
  162. package/plugins/back-button.js +3 -5
  163. package/plugins/codemirror-loader.js +1 -1
  164. package/plugins/codemirror.js +41 -0
  165. package/plugins/dashboard-store/__tests__/{mutations.spec.ts → mutations.test.ts} +1 -1
  166. package/plugins/dashboard-store/__tests__/resource-class.test.ts +49 -0
  167. package/plugins/dashboard-store/__tests__/utils/store-mocks.ts +7 -0
  168. package/plugins/dashboard-store/actions.js +30 -4
  169. package/plugins/dashboard-store/classify.js +1 -18
  170. package/plugins/dashboard-store/getters.js +10 -5
  171. package/plugins/dashboard-store/index.js +0 -12
  172. package/plugins/dashboard-store/mutations.js +0 -4
  173. package/plugins/dashboard-store/resource-class.js +59 -18
  174. package/plugins/steve/__tests__/steve-class.spec.ts +59 -0
  175. package/plugins/steve/__tests__/utils/steve-mocks.ts +31 -0
  176. package/plugins/steve/getters.js +4 -1
  177. package/plugins/steve/norman-class.js +19 -0
  178. package/plugins/steve/steve-class.js +22 -0
  179. package/plugins/steve/subscribe.js +4 -10
  180. package/rancher-components/Accordion/Accordion.test.ts +45 -0
  181. package/rancher-components/Accordion/Accordion.vue +85 -0
  182. package/rancher-components/Accordion/index.ts +1 -0
  183. package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +19 -2
  184. package/rancher-components/Form/LabeledInput/LabeledInput.vue +12 -1
  185. package/rancher-components/Form/Radio/RadioButton.test.ts +7 -3
  186. package/rancher-components/Form/Radio/RadioGroup.test.ts +30 -0
  187. package/rancher-components/Form/Radio/RadioGroup.vue +4 -0
  188. package/rancher-components/StringList/StringList.test.ts +270 -0
  189. package/rancher-components/StringList/StringList.vue +57 -18
  190. package/rancher-components/components/Accordion/Accordion.test.ts +45 -0
  191. package/rancher-components/components/Accordion/Accordion.vue +85 -0
  192. package/rancher-components/components/Accordion/index.ts +1 -0
  193. package/rancher-components/components/Form/LabeledInput/LabeledInput.test.ts +19 -2
  194. package/rancher-components/components/Form/LabeledInput/LabeledInput.vue +4 -1
  195. package/scripts/.gitlab/workflows/build-extension-catalog.gitlab-ci.yml +50 -0
  196. package/scripts/extension/parse-tag-name +2 -2
  197. package/scripts/publish-shell.sh +10 -0
  198. package/scripts/test-plugins-build.sh +85 -9
  199. package/server/har-file.js +183 -0
  200. package/store/catalog.js +1 -1
  201. package/store/features.js +1 -0
  202. package/store/i18n.js +11 -0
  203. package/store/index.js +10 -11
  204. package/store/prefs.js +33 -35
  205. package/store/type-map.js +8 -7
  206. package/tsconfig.json +35 -9
  207. package/tsconfig.paths.json +18 -0
  208. package/types/shell/index.d.ts +345 -214
  209. package/utils/__tests__/create-yaml.test.ts +60 -0
  210. package/utils/axios.js +0 -19
  211. package/utils/azure.js +24 -0
  212. package/utils/create-yaml.js +17 -10
  213. package/utils/monitoring.js +1 -1
  214. package/utils/nuxt.js +18 -39
  215. package/utils/object.js +14 -0
  216. package/utils/router.scrollBehavior.js +12 -14
  217. package/utils/time.js +1 -1
  218. package/utils/url.ts +1 -1
  219. package/vue.config.js +23 -2
  220. package/.DS_Store +0 -0
  221. package/assets/images/providers/aks-black.svg +0 -28
  222. package/assets/images/providers/aks.svg +0 -31
  223. package/edit/provisioning.cattle.io.cluster/__tests__/Basics.tests.ts +0 -234
  224. package/initialize/layouts.ts +0 -26
  225. package/mixins/fetch.server.js +0 -73
  226. package/pages/c/index.vue +0 -9
  227. package/pages/rio/mesh.vue +0 -508
  228. package/plugins/transitions.js +0 -4
  229. package/scripts/.DS_Store +0 -0
  230. package/scripts/verdaccio.log +0 -205
  231. package/tsconfig.default.json +0 -46
  232. package/yarn-error.log +0 -200
  233. /package/components/form/__tests__/{NameNsDescription.ts → NameNsDescription.test.ts} +0 -0
  234. /package/edit/networking.k8s.io.networkpolicy/__tests__/utils/{selectors.ts → selectors.test.ts} +0 -0
  235. /package/edit/provisioning.cattle.io.cluster/{AgentConfiguration.vue → tabs/AgentConfiguration.vue} +0 -0
  236. /package/edit/provisioning.cattle.io.cluster/{MemberRoles.vue → tabs/MemberRoles.vue} +0 -0
  237. /package/edit/provisioning.cattle.io.cluster/{S3Config.vue → tabs/etcd/S3Config.vue} +0 -0
  238. /package/edit/provisioning.cattle.io.cluster/{ACE.vue → tabs/networking/ACE.vue} +0 -0
  239. /package/edit/provisioning.cattle.io.cluster/{RegistryConfigs.vue → tabs/registries/RegistryConfigs.vue} +0 -0
  240. /package/edit/provisioning.cattle.io.cluster/{RegistryMirrors.vue → tabs/registries/RegistryMirrors.vue} +0 -0
  241. /package/edit/provisioning.cattle.io.cluster/{DrainOptions.vue → tabs/upgrade/DrainOptions.vue} +0 -0
  242. /package/plugins/dashboard-store/__tests__/{actions.spec.ts → actions.test.ts} +0 -0
  243. /package/plugins/dashboard-store/__tests__/{getters.spec.ts → getters.test.ts} +0 -0
@@ -97,6 +97,14 @@ export default {
97
97
  default: 'sortableTable.paging.resource',
98
98
  },
99
99
 
100
+ /**
101
+ * Additional params to pass to the pagingLabel translation
102
+ */
103
+ pagingParams: {
104
+ type: Object,
105
+ default: null,
106
+ },
107
+
100
108
  rowActions: {
101
109
  type: Boolean,
102
110
  default: true,
@@ -392,7 +400,11 @@ export default {
392
400
  return standard.concat(this.listGroups);
393
401
  },
394
402
 
395
- pagingParams() {
403
+ parsedPagingParams() {
404
+ if (this.pagingParams) {
405
+ return this.pagingParams;
406
+ }
407
+
396
408
  if ( !this.schema ) {
397
409
  return {
398
410
  singularLabel: '',
@@ -482,7 +494,7 @@ export default {
482
494
  :group-options="groupOptions"
483
495
  :search="search"
484
496
  :paging="true"
485
- :paging-params="pagingParams"
497
+ :paging-params="parsedPagingParams"
486
498
  :paging-label="pagingLabel"
487
499
  :row-actions="rowActions"
488
500
  :table-actions="_showBulkActions"
@@ -190,6 +190,11 @@ export default {
190
190
 
191
191
  cm.foldLinesMatching(/managedFields/);
192
192
 
193
+ // Allow the model to supply an array of json paths to fold other sections in the YAML for the given resource type
194
+ if (this.value?.yamlFolding) {
195
+ this.value.yamlFolding.forEach((path) => cm.foldYaml(path));
196
+ }
197
+
193
198
  // regardless of edit or create we should probably fold all the comments so they dont get out of hand.
194
199
  const saved = cm.getMode().fold;
195
200
 
@@ -583,7 +583,7 @@ export default {
583
583
  }
584
584
  }
585
585
 
586
- &.nuxt-link-active:not(:hover) {
586
+ &.router-link-active:not(:hover) {
587
587
  A {
588
588
  background-color: var(--nav-active);
589
589
  }
@@ -13,10 +13,7 @@ export default {
13
13
  },
14
14
 
15
15
  async fetch() {
16
- this.clusters = await this.$store.dispatch('management/findAll', {
17
- type: MANAGEMENT.CLUSTER,
18
- opt: { url: MANAGEMENT.CLUSTER }
19
- });
16
+ this.clusters = await this.$store.dispatch('management/findAll', { type: MANAGEMENT.CLUSTER });
20
17
  },
21
18
 
22
19
  data() {
@@ -19,6 +19,11 @@ export default {
19
19
  default: false
20
20
  },
21
21
 
22
+ hideSingleTab: {
23
+ type: Boolean,
24
+ default: false
25
+ },
26
+
22
27
  showTabsAddRemove: {
23
28
  type: Boolean,
24
29
  default: false
@@ -86,6 +91,11 @@ export default {
86
91
  sortedTabs() {
87
92
  return sortBy(this.tabs, ['weight:desc', 'labelDisplay', 'name']);
88
93
  },
94
+
95
+ // hide tabs based on tab count IF flag is active
96
+ hideTabs() {
97
+ return this.hideSingleTab && this.sortedTabs.length === 1;
98
+ }
89
99
  },
90
100
 
91
101
  watch: {
@@ -225,11 +235,13 @@ export default {
225
235
  <template>
226
236
  <div :class="{'side-tabs': !!sideTabs, 'tabs-only': tabsOnly }">
227
237
  <ul
238
+ v-if="!hideTabs"
228
239
  ref="tablist"
229
240
  role="tablist"
230
241
  class="tabs"
231
242
  :class="{'clearfix':!sideTabs, 'vertical': sideTabs, 'horizontal': !sideTabs}"
232
243
  tabindex="0"
244
+ data-testid="tabbed-block"
233
245
  @keydown.right.prevent="selectNext(1)"
234
246
  @keydown.left.prevent="selectNext(-1)"
235
247
  @keydown.down.prevent="selectNext(1)"
@@ -8,8 +8,16 @@ import {
8
8
  AGE,
9
9
  STATE,
10
10
  NAME,
11
- FLEET_SUMMARY
11
+ FLEET_SUMMARY,
12
+ FLEET_REPO,
13
+ FLEET_REPO_TARGET,
14
+ FLEET_REPO_CLUSTERS_READY,
15
+ FLEET_REPO_CLUSTER_SUMMARY,
16
+ FLEET_REPO_PER_CLUSTER_STATE
17
+
12
18
  } from '@shell/config/table-headers';
19
+ import { FLEET } from '@shell/config/labels-annotations';
20
+ import { STATES_ENUM } from '@shell/plugins/dashboard-store/resource-class';
13
21
 
14
22
  export default {
15
23
 
@@ -19,6 +27,11 @@ export default {
19
27
  ResourceTable, Link, Shortened, FleetIntro
20
28
  },
21
29
  props: {
30
+ clusterId: {
31
+ type: String,
32
+ required: false,
33
+ default: null,
34
+ },
22
35
  rows: {
23
36
  type: Array,
24
37
  required: true,
@@ -54,35 +67,46 @@ export default {
54
67
  });
55
68
  },
56
69
 
70
+ isClusterView() {
71
+ return !!this.clusterId;
72
+ },
73
+
57
74
  noRows() {
58
75
  return !this.filteredRows.length;
59
76
  },
60
77
 
61
78
  headers() {
62
- const out = [
63
- STATE,
64
- NAME,
65
- {
66
- name: 'repo',
67
- labelKey: 'tableHeaders.repo',
68
- value: 'repoDisplay',
69
- sort: 'repoDisplay',
70
- search: ['spec.repo', 'status.commit'],
79
+ // Cluster summary is only shown in the cluster view
80
+ const fleetClusterSummary = {
81
+ ...FLEET_REPO_CLUSTER_SUMMARY,
82
+ formatterOpts: {
83
+ // Fleet uses labels to identify clusters
84
+ clusterLabel: this.clusterId
71
85
  },
72
- {
73
- name: 'target',
74
- labelKey: 'tableHeaders.target',
75
- value: 'targetInfo.modeDisplay',
76
- sort: ['targetInfo.modeDisplay', 'targetInfo.cluster', 'targetInfo.clusterGroup'],
77
- },
78
- {
79
- name: 'clustersReady',
80
- labelKey: 'tableHeaders.clustersReady',
81
- value: 'status.readyClusters',
82
- sort: 'status.readyClusters',
83
- search: false,
86
+ };
87
+
88
+ // if hasPerClusterState then use the repo state
89
+ const fleetPerClusterState = {
90
+ ...FLEET_REPO_PER_CLUSTER_STATE,
91
+ value: (row) => {
92
+ const statePerCluster = row.clusterResourceStatus?.find((c) => {
93
+ return c.clusterLabel === this.clusterId;
94
+ });
95
+
96
+ return statePerCluster ? statePerCluster?.status?.displayStatus : STATES_ENUM.ACTIVE;
84
97
  },
85
- FLEET_SUMMARY,
98
+ };
99
+
100
+ const summary = this.isClusterView ? [fleetClusterSummary] : [FLEET_REPO_CLUSTERS_READY, FLEET_SUMMARY];
101
+
102
+ const state = this.isClusterView ? fleetPerClusterState : STATE;
103
+
104
+ const out = [
105
+ state,
106
+ NAME,
107
+ FLEET_REPO,
108
+ FLEET_REPO_TARGET,
109
+ ...summary,
86
110
  AGE
87
111
  ];
88
112
 
@@ -92,6 +116,12 @@ export default {
92
116
  methods: {
93
117
  parseTargetMode(row) {
94
118
  return row.targetInfo?.mode === 'clusterGroup' ? this.t('fleet.gitRepo.warningTooltip.clusterGroup') : this.t('fleet.gitRepo.warningTooltip.cluster');
119
+ },
120
+
121
+ clusterViewResourceStatus(row) {
122
+ return row.clusterResourceStatus.find((c) => {
123
+ return c.metadata?.labels[FLEET.CLUSTER_NAME] === this.clusterId;
124
+ });
95
125
  }
96
126
  },
97
127
  };
@@ -111,7 +141,7 @@ export default {
111
141
  key-field="_key"
112
142
  v-on="$listeners"
113
143
  >
114
- <template #cell:repo="{row}">
144
+ <template #cell:repo="{ row }">
115
145
  <Link
116
146
  :row="row"
117
147
  :value="row.spec.repo"
@@ -119,6 +149,7 @@ export default {
119
149
  before-icon-key="repoIcon"
120
150
  url-key="spec.repo"
121
151
  />
152
+ {{ row.cluster }}
122
153
  <template v-if="row.commitDisplay">
123
154
  <div class="text-muted">
124
155
  <Shortened
@@ -130,7 +161,10 @@ export default {
130
161
  </template>
131
162
  </template>
132
163
 
133
- <template #cell:clustersReady="{row}">
164
+ <template
165
+ v-if="!isClusterView"
166
+ #cell:clustersReady="{ row }"
167
+ >
134
168
  <span
135
169
  v-if="!row.clusterInfo"
136
170
  class="text-muted"
@@ -138,7 +172,8 @@ export default {
138
172
  <span
139
173
  v-else-if="row.clusterInfo.unready"
140
174
  class="text-warning"
141
- >{{ row.clusterInfo.ready }}/{{ row.clusterInfo.total }}</span>
175
+ >{{ row.clusterInfo.ready }}/{{
176
+ row.clusterInfo.total }}</span>
142
177
  <span
143
178
  v-else
144
179
  class="cluster-count-info"
@@ -152,7 +187,7 @@ export default {
152
187
  </span>
153
188
  </template>
154
189
 
155
- <template #cell:target="{row}">
190
+ <template #cell:target="{ row }">
156
191
  {{ row.targetInfo.modeDisplay }}
157
192
  </template>
158
193
  </ResourceTable>
@@ -11,7 +11,12 @@ export default {
11
11
  value: {
12
12
  type: Object,
13
13
  required: true,
14
- }
14
+ },
15
+ clusterId: {
16
+ type: String,
17
+ required: false,
18
+ default: null,
19
+ },
15
20
  },
16
21
 
17
22
  computed: {
@@ -24,6 +24,10 @@ export default {
24
24
  loading: {
25
25
  type: Boolean,
26
26
  default: false
27
+ },
28
+ disabled: {
29
+ type: Boolean,
30
+ default: true
27
31
  }
28
32
  },
29
33
  computed: {
@@ -34,6 +38,10 @@ export default {
34
38
 
35
39
  addAllowed() {
36
40
  return this.filteredOptions.length > 0;
41
+ },
42
+
43
+ defaultAddValue() {
44
+ return this.options[0]?.value;
37
45
  }
38
46
  },
39
47
 
@@ -62,6 +70,8 @@ export default {
62
70
  class="array-list-select"
63
71
  :add-allowed="addAllowed || loading"
64
72
  :loading="loading"
73
+ :defaultAddValue="defaultAddValue"
74
+ :disabled="disabled"
65
75
  @input="$emit('input', $event)"
66
76
  >
67
77
  <template v-slot:columns="scope">
@@ -343,6 +343,7 @@ export default {
343
343
 
344
344
  for ( const row of input ) {
345
345
  let value = row[this.valueName] || '';
346
+
346
347
  const decodedValue = base64Decode(row[this.valueName]);
347
348
  const asciiValue = asciiLike(decodedValue);
348
349
 
@@ -644,6 +645,7 @@ export default {
644
645
  :clearable="false"
645
646
  :taggable="keyTaggable"
646
647
  :options="calculateOptions(row[keyName])"
648
+ :data-testid="`select-kv-item-key-${i}`"
647
649
  @input="queueUpdate"
648
650
  />
649
651
  <input
@@ -652,6 +654,7 @@ export default {
652
654
  v-model="row[keyName]"
653
655
  :disabled="isView || disabled || !keyEditable || isProtected(row.key)"
654
656
  :placeholder="keyPlaceholder"
657
+ :data-testid="`input-kv-item-key-${i}`"
655
658
  @input="queueUpdate"
656
659
  @paste="onPaste(i, $event)"
657
660
  >
@@ -661,6 +664,7 @@ export default {
661
664
  <!-- Value -->
662
665
  <div
663
666
  :key="i+'value'"
667
+ :data-testid="`kv-item-value-${i}`"
664
668
  class="kv-item value"
665
669
  >
666
670
  <slot
@@ -88,6 +88,10 @@ export default {
88
88
  default: null,
89
89
  type: [String, Object, Number, Array, Boolean]
90
90
  },
91
+ options: {
92
+ type: Array,
93
+ required: true
94
+ },
91
95
  closeOnSelect: {
92
96
  type: Boolean,
93
97
  default: true
@@ -2,16 +2,24 @@
2
2
 
3
3
  export default {
4
4
  props: {
5
+ // When sortabletable calculates these values it converts null and undefined to ''
6
+ // passing '' to a prop typed as Boolean coerces it to true
5
7
  value: {
6
- type: Boolean,
8
+ type: [String, Boolean],
7
9
  default: true
8
10
  },
9
- }
11
+ },
12
+
13
+ computed: {
14
+ checked() {
15
+ return this.value === true || this.value === 'true';
16
+ }
17
+ },
10
18
  };
11
19
  </script>
12
20
 
13
21
  <template>
14
- <span v-if="value">
22
+ <span v-if="checked">
15
23
  <i class="icon icon-checkmark" />
16
24
  </span>
17
25
  <span
@@ -0,0 +1,27 @@
1
+ <script>
2
+ import FleetSummaryGraph from '@shell/components/formatter/FleetSummaryGraph';
3
+
4
+ export default {
5
+ name: 'FleetClusterSummaryGraph',
6
+ components: { FleetSummaryGraph },
7
+
8
+ props: {
9
+ row: {
10
+ type: Object,
11
+ required: true
12
+ },
13
+
14
+ clusterLabel: {
15
+ type: String,
16
+ required: true
17
+ }
18
+ },
19
+ };
20
+ </script>
21
+
22
+ <template>
23
+ <FleetSummaryGraph
24
+ :row="row"
25
+ :clusterLabel="clusterLabel"
26
+ />
27
+ </template>
@@ -12,10 +12,22 @@ export default {
12
12
  type: Object,
13
13
  required: true
14
14
  },
15
+
16
+ clusterLabel: {
17
+ type: String,
18
+ required: false,
19
+ default: null,
20
+ }
15
21
  },
16
22
 
17
23
  computed: {
18
24
  summary() {
25
+ if (this.clusterLabel) {
26
+ return this.row.clusterResourceStatus.find((x) => {
27
+ return x.clusterLabel === this.clusterLabel;
28
+ })?.status.resourceCounts || {};
29
+ }
30
+
19
31
  return this.row.status?.resourceCounts || {};
20
32
  },
21
33
 
@@ -73,7 +85,7 @@ export default {
73
85
  >
74
86
  <td
75
87
  class="text-left pr-20"
76
- :class="{[obj.textColor]: true}"
88
+ :class="{ [obj.textColor]: true }"
77
89
  >
78
90
  {{ obj.label }}
79
91
  </td>
@@ -94,17 +106,17 @@ export default {
94
106
  </template>
95
107
 
96
108
  <style lang="scss">
97
- .col-scale {
98
- position: relative;
109
+ .col-scale {
110
+ position: relative;
99
111
 
100
- .trigger {
101
- width: 100%;
102
- }
112
+ .trigger {
113
+ width: 100%;
103
114
  }
115
+ }
104
116
 
105
- .scale {
106
- margin: 0;
107
- padding: 0;
108
- line-height: initial;
109
- }
117
+ .scale {
118
+ margin: 0;
119
+ padding: 0;
120
+ line-height: initial;
121
+ }
110
122
  </style>
@@ -57,7 +57,7 @@ export default {
57
57
  const now = day();
58
58
 
59
59
  from = from || now;
60
- const seconds = Math.abs(value.diff(now, 'seconds'));
60
+ const seconds = Math.abs(value.diff(from, 'seconds'));
61
61
 
62
62
  return elapsedTime(seconds);
63
63
  },
@@ -30,7 +30,7 @@ export default {
30
30
  </script>
31
31
 
32
32
  <template>
33
- <p v-if="!value || value === '0'">
33
+ <p v-if="!value || value === '0' || isNaN(value)">
34
34
  {{ t('generic.na') }}
35
35
  </p>
36
36
  <PercentageBarComponent
@@ -0,0 +1,19 @@
1
+ import { mount } from '@vue/test-utils';
2
+ import Checked from '@shell/components/formatter/Checked.vue';
3
+
4
+ describe('component: Checked', () => {
5
+ it.each([true, 'true'])('should display a checkmark when the value is true or "true"', (value: any) => {
6
+ const wrapper = mount(Checked, { propsData: { value } });
7
+ const checkmark = wrapper.find('.icon-checkmark');
8
+
9
+ expect(checkmark.exists()).toBe(true);
10
+ });
11
+
12
+ it.each([false, '', 'abc'])('should not display a checkmark when the value is anything other than true or "true"', (value: any) => {
13
+ const wrapper = mount(Checked, { propsData: { value } });
14
+
15
+ const checkmark = wrapper.find('.icon-checkmark');
16
+
17
+ expect(checkmark.exists()).toBe(false);
18
+ });
19
+ });
@@ -390,8 +390,8 @@ export default {
390
390
  }
391
391
  }
392
392
 
393
- .body ::v-deep > .child.nuxt-link-active,
394
- .header ::v-deep > .child.nuxt-link-exact-active {
393
+ .body ::v-deep > .child.router-link-active,
394
+ .header ::v-deep > .child.router-link-exact-active {
395
395
  padding: 0;
396
396
 
397
397
  A, A I {
@@ -441,7 +441,6 @@ export default {
441
441
 
442
442
  <div class="rd-header-right">
443
443
  <component :is="navHeaderRight" />
444
-
445
444
  <div
446
445
  v-if="showFilter"
447
446
  class="top"
@@ -13,6 +13,7 @@ import { getVersionInfo } from '@shell/utils/version';
13
13
  import { LEGACY } from '@shell/store/features';
14
14
  import { SETTING } from '@shell/config/settings';
15
15
  import { filterOnlyKubernetesClusters, filterHiddenLocalCluster } from '@shell/utils/cluster';
16
+ import { getProductFromRoute } from '@shell/middleware/authenticated';
16
17
  import { isRancherPrime } from '@shell/config/version';
17
18
  import Pinned from '@shell/components/nav/Pinned';
18
19
 
@@ -72,12 +73,17 @@ export default {
72
73
  if (bannerSettings) {
73
74
  const parsed = JSON.parse(bannerSettings.value);
74
75
  const {
75
- showFooter, showHeader, bannerFooter, bannerHeader
76
+ showFooter, showHeader, bannerFooter, bannerHeader, banner
76
77
  } = parsed;
77
78
 
79
+ // add defaults to accomodate older JSON structures for banner definitions without breaking the UI
80
+ // https://github.com/rancher/dashboard/issues/10140
81
+ const bannerHeaderFontSize = bannerHeader?.fontSize || banner?.fontSize || '14px';
82
+ const bannerFooterFontSize = bannerFooter?.fontSize || banner?.fontSize || '14px';
83
+
78
84
  return {
79
- headerFont: showHeader === 'true' ? this.pxToEm(bannerHeader.fontSize) : '0px',
80
- footerFont: showFooter === 'true' ? this.pxToEm(bannerFooter.fontSize) : '0px'
85
+ headerFont: showHeader === 'true' ? this.pxToEm(bannerHeaderFontSize) : '0px',
86
+ footerFont: showFooter === 'true' ? this.pxToEm(bannerFooterFontSize) : '0px'
81
87
  };
82
88
  }
83
89
 
@@ -242,7 +248,15 @@ export default {
242
248
 
243
249
  hasSupport() {
244
250
  return isRancherPrime() || this.$store.getters['management/byId'](MANAGEMENT.SETTING, SETTING.SUPPORTED )?.value === 'true';
245
- }
251
+ },
252
+
253
+ isCurrRouteClusterExplorer() {
254
+ return this.$route?.name?.startsWith('c-cluster');
255
+ },
256
+
257
+ productFromRoute() {
258
+ return getProductFromRoute(this.$route);
259
+ },
246
260
  },
247
261
 
248
262
  watch: {
@@ -273,6 +287,16 @@ export default {
273
287
  return `${ lineHeightInEm }em`;
274
288
  },
275
289
 
290
+ checkActiveRoute(obj, isClusterRoute) {
291
+ // for Cluster links in main nav: check if route is a cluster explorer one + check if route cluster matches cluster obj id + check if curr product matches route product
292
+ if (isClusterRoute) {
293
+ return this.isCurrRouteClusterExplorer && this.$route?.params?.cluster === obj?.id && this.productFromRoute === this.currentProduct?.name;
294
+ }
295
+
296
+ // for remaining main nav items, check if curr product matches route product is enough
297
+ return this.productFromRoute === obj?.value;
298
+ },
299
+
276
300
  handler(e) {
277
301
  if (e.keyCode === KEY.ESCAPE ) {
278
302
  this.hide();
@@ -435,6 +459,7 @@ export default {
435
459
  <nuxt-link
436
460
  class="option"
437
461
  :to="a.to"
462
+ :class="{'active-menu-link': checkActiveRoute(a) }"
438
463
  >
439
464
  <IconOrSvg
440
465
  :icon="a.icon"
@@ -466,6 +491,7 @@ export default {
466
491
  v-if="c.ready"
467
492
  :data-testid="`menu-cluster-${ c.id }`"
468
493
  class="cluster selector option"
494
+ :class="{'active-menu-link': checkActiveRoute(c, true) }"
469
495
  :to="{ name: 'c-cluster-explorer', params: { cluster: c.id } }"
470
496
  >
471
497
  <ClusterIconMenu
@@ -515,6 +541,7 @@ export default {
515
541
  v-if="c.ready"
516
542
  :data-testid="`menu-cluster-${ c.id }`"
517
543
  class="cluster selector option"
544
+ :class="{'active-menu-link': checkActiveRoute(c, true) }"
518
545
  :to="{ name: 'c-cluster-explorer', params: { cluster: c.id } }"
519
546
  >
520
547
  <ClusterIconMenu
@@ -592,6 +619,7 @@ export default {
592
619
  >
593
620
  <nuxt-link
594
621
  class="option"
622
+ :class="{'active-menu-link': checkActiveRoute(a) }"
595
623
  :to="a.to"
596
624
  >
597
625
  <IconOrSvg
@@ -619,6 +647,7 @@ export default {
619
647
  >
620
648
  <nuxt-link
621
649
  class="option"
650
+ :class="{'active-menu-link': checkActiveRoute(a) }"
622
651
  :to="a.to"
623
652
  >
624
653
  <IconOrSvg
@@ -648,6 +677,7 @@ export default {
648
677
  >
649
678
  <nuxt-link
650
679
  class="option"
680
+ :class="{'active-menu-link': checkActiveRoute(a) }"
651
681
  :to="a.to"
652
682
  >
653
683
  <IconOrSvg
@@ -867,7 +897,7 @@ export default {
867
897
  margin-right: 16px;
868
898
  }
869
899
 
870
- &.nuxt-link-active {
900
+ &.router-link-active, &.active-menu-link {
871
901
  background: var(--primary-hover-bg);
872
902
  color: var(--primary-hover-text);
873
903
 
@@ -991,7 +1021,7 @@ export default {
991
1021
  font-size: 14px;
992
1022
  }
993
1023
 
994
- .nuxt-link-active {
1024
+ .router-link-active {
995
1025
  &:hover {
996
1026
  text-decoration: none;
997
1027
  }
@@ -1,7 +1,6 @@
1
1
  <script>
2
2
  import Favorite from '@shell/components/nav/Favorite';
3
3
  import { FAVORITE, USED } from '@shell/store/type-map';
4
- import { linkActiveClass } from '@shell/config/router';
5
4
 
6
5
  const showFavoritesFor = [FAVORITE, USED];
7
6
 
@@ -31,7 +30,6 @@ export default {
31
30
  near: false,
32
31
  over: false,
33
32
  menuPath: this.type.route ? this.$router.resolve(this.type.route)?.route?.path : undefined,
34
- linkActiveClass
35
33
  };
36
34
  },
37
35
 
@@ -134,7 +132,7 @@ export default {
134
132
  :to="type.route"
135
133
  tag="li"
136
134
  class="child nav-type"
137
- :class="{'root': isRoot, [`depth-${depth}`]: true, [linkActiveClass]: isCurrent}"
135
+ :class="{'root': isRoot, [`depth-${depth}`]: true, 'router-link-active': isCurrent}"
138
136
  :exact="type.exact"
139
137
  >
140
138
  <a