@rancher/shell 3.0.2-rc.2 → 3.0.2-rc.4

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 (172) hide show
  1. package/assets/styles/base/_basic.scss +7 -8
  2. package/assets/styles/global/_button.scss +10 -0
  3. package/assets/styles/global/_form.scss +2 -1
  4. package/assets/styles/global/_tooltip.scss +2 -2
  5. package/assets/styles/themes/_dark.scss +15 -3
  6. package/assets/styles/themes/_light.scss +7 -2
  7. package/assets/styles/vendor/vue-select.scss +4 -0
  8. package/assets/translations/en-us.yaml +66 -9
  9. package/assets/translations/zh-hans.yaml +2 -3
  10. package/components/AppModal.vue +50 -0
  11. package/components/BannerGraphic.vue +0 -42
  12. package/components/ButtonMultiAction.vue +1 -1
  13. package/components/Carousel.vue +88 -74
  14. package/components/CommunityLinks.vue +6 -1
  15. package/components/CopyToClipboardText.vue +3 -0
  16. package/components/Dialog.vue +20 -1
  17. package/components/GrowlManager.vue +9 -2
  18. package/components/LocaleSelector.vue +8 -1
  19. package/components/PaginatedResourceTable.vue +4 -7
  20. package/components/ProgressBarMulti.vue +14 -0
  21. package/components/PromptChangePassword.vue +3 -0
  22. package/components/Questions/Reference.vue +57 -28
  23. package/components/ResourceDetail/Masthead.vue +1 -1
  24. package/components/SelectIconGrid.vue +12 -1
  25. package/components/SideNav.vue +12 -38
  26. package/components/SortableTable/index.vue +1 -0
  27. package/components/Tabbed/index.vue +9 -1
  28. package/components/YamlEditor.vue +1 -0
  29. package/components/__tests__/Carousel.test.ts +56 -27
  30. package/components/auth/Principal.vue +5 -3
  31. package/components/fleet/FleetClusters.vue +82 -1
  32. package/components/fleet/FleetRepos.vue +13 -30
  33. package/components/fleet/ForceDirectedTreeChart/index.vue +2 -2
  34. package/components/form/ChangePassword.vue +2 -0
  35. package/components/form/ColorInput.vue +24 -1
  36. package/components/form/FileSelector.vue +2 -0
  37. package/components/form/KeyValue.vue +230 -160
  38. package/components/form/LabeledSelect.vue +2 -2
  39. package/components/form/PlusMinus.vue +14 -2
  40. package/components/form/ResourceLabeledSelect.vue +13 -53
  41. package/components/form/ResourceSelector.vue +1 -0
  42. package/components/form/ResourceTabs/index.vue +79 -36
  43. package/components/form/SSHKnownHosts/KnownHostsEditDialog.vue +192 -0
  44. package/components/form/SSHKnownHosts/__tests__/KnownHostsEditDialog.test.ts +104 -0
  45. package/components/form/SSHKnownHosts/index.vue +101 -0
  46. package/components/form/SecretSelector.vue +2 -2
  47. package/components/form/Select.vue +1 -1
  48. package/components/form/SelectOrCreateAuthSecret.vue +43 -11
  49. package/components/form/__tests__/KeyValue.test.ts +1 -1
  50. package/components/form/__tests__/SSHKnownHosts.test.ts +59 -0
  51. package/components/formatter/FleetClusterSummaryGraph.vue +2 -2
  52. package/components/formatter/FleetSummaryGraph.vue +6 -7
  53. package/components/formatter/WorkloadHealthScale.vue +7 -0
  54. package/components/nav/Group.vue +30 -4
  55. package/components/nav/Header.vue +82 -114
  56. package/components/nav/HeaderPageActionMenu.vue +27 -131
  57. package/components/nav/NamespaceFilter.vue +1 -1
  58. package/components/nav/Type.vue +15 -0
  59. package/composables/focusTrap.ts +68 -0
  60. package/config/home-links.js +21 -13
  61. package/config/labels-annotations.js +2 -0
  62. package/config/page-actions.js +1 -0
  63. package/config/pagination-table-headers.js +15 -1
  64. package/config/product/explorer.js +7 -17
  65. package/config/table-headers.js +6 -0
  66. package/config/version.js +5 -1
  67. package/core/plugin.ts +41 -1
  68. package/core/plugins.js +125 -72
  69. package/core/types-provisioning.ts +91 -2
  70. package/core/types.ts +55 -0
  71. package/detail/__tests__/autoscaling.horizontalpodautoscaler.test.ts +12 -3
  72. package/detail/catalog.cattle.io.app.vue +1 -1
  73. package/detail/fleet.cattle.io.cluster.vue +3 -3
  74. package/detail/namespace.vue +13 -19
  75. package/detail/networking.k8s.io.ingress.vue +13 -53
  76. package/detail/provisioning.cattle.io.cluster.vue +12 -1
  77. package/detail/secret.vue +25 -0
  78. package/detail/workload/index.vue +3 -3
  79. package/dialog/AddCustomBadgeDialog.vue +5 -1
  80. package/edit/auth/ldap/__tests__/config.test.ts +18 -0
  81. package/edit/auth/ldap/config.vue +24 -0
  82. package/edit/auth/saml.vue +8 -6
  83. package/edit/fleet.cattle.io.gitrepo.vue +34 -23
  84. package/edit/logging-flow/index.vue +4 -19
  85. package/edit/networking.k8s.io.ingress/index.vue +18 -65
  86. package/edit/networking.k8s.io.networkpolicy/index.vue +4 -5
  87. package/edit/provisioning.cattle.io.cluster/index.vue +27 -8
  88. package/edit/provisioning.cattle.io.cluster/rke2.vue +31 -115
  89. package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +2 -2
  90. package/edit/provisioning.cattle.io.cluster/tabs/networking/ACE.vue +14 -28
  91. package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +25 -12
  92. package/edit/secret/index.vue +1 -1
  93. package/edit/secret/ssh.vue +21 -3
  94. package/edit/service.vue +1 -2
  95. package/list/networking.k8s.io.ingress.vue +1 -1
  96. package/list/node.vue +15 -8
  97. package/list/persistentvolume.vue +12 -4
  98. package/list/provisioning.cattle.io.cluster.vue +1 -0
  99. package/list/service.vue +1 -1
  100. package/list/workload.vue +4 -0
  101. package/mixins/chart.js +4 -1
  102. package/models/catalog.cattle.io.app.js +3 -1
  103. package/models/catalog.cattle.io.clusterrepo.js +56 -7
  104. package/models/fleet.cattle.io.bundle.js +0 -11
  105. package/models/fleet.cattle.io.cluster.js +17 -1
  106. package/models/fleet.cattle.io.gitrepo.js +88 -52
  107. package/models/provisioning.cattle.io.cluster.js +36 -1
  108. package/models/secret.js +5 -0
  109. package/models/service.js +1 -0
  110. package/models/workload.js +19 -1
  111. package/package.json +5 -4
  112. package/pages/account/index.vue +4 -0
  113. package/pages/c/_cluster/apps/charts/index.vue +4 -0
  114. package/pages/c/_cluster/explorer/ConfigBadge.vue +4 -2
  115. package/pages/c/_cluster/explorer/index.vue +13 -6
  116. package/pages/c/_cluster/fleet/GitRepoGraphConfig.js +3 -3
  117. package/pages/c/_cluster/fleet/index.vue +75 -89
  118. package/pages/c/_cluster/settings/links.vue +2 -2
  119. package/pages/c/_cluster/uiplugins/AddExtensionRepos.vue +3 -1
  120. package/pages/c/_cluster/uiplugins/CatalogList/CatalogLoadDialog.vue +3 -0
  121. package/pages/c/_cluster/uiplugins/CatalogList/CatalogUninstallDialog.vue +7 -1
  122. package/pages/c/_cluster/uiplugins/CatalogList/index.vue +3 -1
  123. package/pages/c/_cluster/uiplugins/DeveloperInstallDialog.vue +10 -7
  124. package/pages/c/_cluster/uiplugins/InstallDialog.vue +7 -0
  125. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +181 -106
  126. package/pages/c/_cluster/uiplugins/SetupUIPlugins.vue +2 -0
  127. package/pages/c/_cluster/uiplugins/UninstallDialog.vue +9 -1
  128. package/pages/c/_cluster/uiplugins/index.vue +50 -12
  129. package/pages/diagnostic.vue +17 -15
  130. package/pages/home.vue +32 -6
  131. package/plugins/clean-html.js +50 -0
  132. package/plugins/dashboard-store/resource-class.js +4 -0
  133. package/plugins/plugin.js +54 -49
  134. package/plugins/steve/mutations.js +1 -1
  135. package/plugins/steve/steve-class.js +8 -0
  136. package/plugins/steve/steve-pagination-utils.ts +3 -1
  137. package/rancher-components/Accordion/Accordion.vue +4 -4
  138. package/rancher-components/BadgeState/BadgeState.vue +7 -0
  139. package/rancher-components/Card/Card.vue +12 -0
  140. package/rancher-components/Form/Checkbox/Checkbox.vue +9 -2
  141. package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +18 -1
  142. package/rancher-components/Form/LabeledInput/LabeledInput.vue +19 -1
  143. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +39 -2
  144. package/rancher-components/RcButton/RcButton.vue +90 -0
  145. package/rancher-components/RcButton/index.ts +2 -0
  146. package/rancher-components/RcButton/types.ts +17 -0
  147. package/rancher-components/RcDropdown/RcDropdown.vue +122 -0
  148. package/rancher-components/RcDropdown/RcDropdownItem.vue +127 -0
  149. package/rancher-components/RcDropdown/RcDropdownSeparator.vue +6 -0
  150. package/rancher-components/RcDropdown/RcDropdownTrigger.vue +42 -0
  151. package/rancher-components/RcDropdown/index.ts +4 -0
  152. package/rancher-components/RcDropdown/types.ts +22 -0
  153. package/rancher-components/RcDropdown/useDropdownCollection.ts +46 -0
  154. package/rancher-components/RcDropdown/useDropdownContext.ts +110 -0
  155. package/scripts/test-plugins-build.sh +2 -0
  156. package/scripts/typegen.sh +2 -0
  157. package/store/catalog.js +1 -1
  158. package/tsconfig.json +2 -1
  159. package/types/components/paginatedResourceTable.ts +25 -0
  160. package/types/components/resourceLabeledSelect.ts +48 -0
  161. package/types/resources/fleet.d.ts +17 -0
  162. package/types/shell/index.d.ts +61 -0
  163. package/utils/auth.js +5 -1
  164. package/utils/cluster.js +106 -0
  165. package/utils/fleet.ts +35 -3
  166. package/utils/ingress.ts +64 -0
  167. package/utils/uiplugins.ts +56 -44
  168. package/utils/validators/cron-schedule.js +7 -2
  169. package/utils/validators/formRules/__tests__/index.test.ts +53 -17
  170. package/utils/validators/formRules/index.ts +20 -5
  171. package/vue.config.js +1 -1
  172. package/components/RelatedWorkloadsTable.vue +0 -50
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rancher/shell",
3
- "version": "3.0.2-rc.2",
3
+ "version": "3.0.2-rc.4",
4
4
  "description": "Rancher Dashboard Shell",
5
5
  "repository": "https://github.com/rancherlabs/dashboard",
6
6
  "license": "Apache-2.0",
@@ -31,7 +31,7 @@
31
31
  "@aws-sdk/client-eks": "3.1.0",
32
32
  "@aws-sdk/client-iam": "3.658.1",
33
33
  "@aws-sdk/client-kms": "3.8.1",
34
- "@babel/plugin-proposal-optional-chaining": "7.14.5",
34
+ "@babel/plugin-proposal-optional-chaining": "7.21.0",
35
35
  "@babel/plugin-proposal-private-methods": "7.18.6",
36
36
  "@babel/plugin-proposal-private-property-in-object": "7.14.5",
37
37
  "@babel/preset-typescript": "7.16.7",
@@ -64,7 +64,7 @@
64
64
  "cookie": "0.7.0",
65
65
  "core-js": "3.40.0",
66
66
  "cron-validator": "1.3.1",
67
- "cronstrue": "2.50.0",
67
+ "cronstrue": "2.53.0",
68
68
  "cross-env": "7.0.3",
69
69
  "css-loader": "6.7.3",
70
70
  "csv-loader": "3.0.3",
@@ -91,6 +91,7 @@
91
91
  "express": "4.17.1",
92
92
  "file-saver": "2.0.2",
93
93
  "floating-vue": "5.2.2",
94
+ "focus-trap": "7.6.2",
94
95
  "frontmatter-markdown-loader": "3.7.0",
95
96
  "identicon.js": "2.3.3",
96
97
  "intl-messageformat": "7.8.4",
@@ -120,7 +121,7 @@
120
121
  "set-cookie-parser": "2.4.6",
121
122
  "shell-quote": "1.7.3",
122
123
  "sinon": "8.1.1",
123
- "start-server-and-test": "1.13.1",
124
+ "start-server-and-test": "2.0.10",
124
125
  "style-loader": "1.2.1",
125
126
  "ts-node": "8.10.2",
126
127
  "typescript": "5.6.3",
@@ -160,6 +160,8 @@ export default {
160
160
  <div>
161
161
  <button
162
162
  v-if="canChangePassword"
163
+ role="button"
164
+ :aria-label="t('accountAndKeys.account.change')"
163
165
  type="button"
164
166
  class="btn role-primary"
165
167
  data-testid="account_change_password"
@@ -182,6 +184,8 @@ export default {
182
184
  </div>
183
185
  <button
184
186
  v-if="apiKeySchema"
187
+ role="button"
188
+ :aria-label="t('accountAndKeys.apiKeys.add.label')"
185
189
  class="btn role-primary add mb-20"
186
190
  data-testid="account_create_api_keys"
187
191
  @click="addKey"
@@ -455,6 +455,8 @@ export default {
455
455
  class="input-sm"
456
456
  :placeholder="t('catalog.charts.search')"
457
457
  data-testid="charts-filter-input"
458
+ :aria-label="t('catalog.charts.search')"
459
+ role="textbox"
458
460
  >
459
461
 
460
462
  <button
@@ -463,6 +465,8 @@ export default {
463
465
  @shortkey="focusSearch()"
464
466
  />
465
467
  <AsyncButton
468
+ role="button"
469
+ :aria-label="t('catalog.charts.refresh')"
466
470
  class="refresh-btn"
467
471
  mode="refresh"
468
472
  size="sm"
@@ -26,16 +26,18 @@ export default {
26
26
  <template>
27
27
  <div class="config-badge">
28
28
  <div>
29
- <a
29
+ <button
30
30
  class="badge-install btn btn-sm role-secondary"
31
31
  data-testid="add-custom-cluster-badge"
32
+ role="button"
33
+ tabindex="0"
32
34
  @click="customBadgeDialog"
33
35
  >
34
36
  <i
35
37
  v-clean-tooltip="tooltip"
36
38
  class="icon icon-brush-icon"
37
39
  />
38
- </a>
40
+ </button>
39
41
  </div>
40
42
  </div>
41
43
  </template>
@@ -641,12 +641,14 @@ export default {
641
641
  <div data-testid="clusterProvider__label">
642
642
  <label>{{ t('glance.provider') }}: </label>
643
643
  <span v-if="isHarvesterCluster">
644
- <a
644
+ <button
645
+ class="btn role-link harvester-cluster-link"
645
646
  role="button"
647
+ :aria-label="displayProvider"
646
648
  @click="goToHarvesterCluster"
647
649
  >
648
650
  {{ displayProvider }}
649
- </a>
651
+ </button>
650
652
  </span>
651
653
  <span v-else>
652
654
  {{ displayProvider }}
@@ -682,6 +684,8 @@ export default {
682
684
  <router-link
683
685
  :to="{name: 'c-cluster-explorer-tools'}"
684
686
  class="cluster-tools-link"
687
+ role="link"
688
+ :aria-label="t('nav.clusterTools')"
685
689
  >
686
690
  <span>{{ t('nav.clusterTools') }}</span>
687
691
  </router-link>
@@ -871,6 +875,13 @@ export default {
871
875
  grid-row-gap: 20px;
872
876
  }
873
877
 
878
+ .harvester-cluster-link {
879
+ line-height: inherit;
880
+ min-height: inherit;
881
+ padding: 0;
882
+ vertical-align: bottom;
883
+ }
884
+
874
885
  @media only screen and (max-width: map-get($breakpoints, "--viewport-9")) {
875
886
  .extension-card-container {
876
887
  grid-template-columns: 1fr !important;
@@ -935,10 +946,6 @@ export default {
935
946
  line-height: inherit;
936
947
  margin-right: 4px;
937
948
  }
938
-
939
- &:focus {
940
- outline: 0;
941
- }
942
949
  }
943
950
 
944
951
  .cert-table-link {
@@ -77,7 +77,7 @@ export const gitRepoGraphConfig = {
77
77
  id: bd.id,
78
78
  matchingId: bd.id,
79
79
  type: bd.type,
80
- clusterId: cluster ? cluster.id : undefined,
80
+ clusterLabel: cluster ? cluster.namespacedName : undefined,
81
81
  clusterDetailLocation: cluster ? cluster.detailLocation : undefined,
82
82
  state: bd.state,
83
83
  stateLabel: bd.stateDisplay,
@@ -210,7 +210,7 @@ export const gitRepoGraphConfig = {
210
210
  type: 'title-link',
211
211
  labelKey: 'fleet.fdc.id',
212
212
  valueObj: {
213
- id: data.id,
213
+ label: data.id,
214
214
  detailLocation: data.detailLocation
215
215
  }
216
216
  }
@@ -221,7 +221,7 @@ export const gitRepoGraphConfig = {
221
221
  type: 'title-link',
222
222
  labelKey: 'fleet.fdc.cluster',
223
223
  valueObj: {
224
- id: data.clusterId,
224
+ label: data.clusterLabel,
225
225
  detailLocation: data.clusterDetailLocation
226
226
  }
227
227
  });
@@ -2,7 +2,12 @@
2
2
  import { mapState } from 'vuex';
3
3
  import { FLEET } from '@shell/config/types';
4
4
  import { WORKSPACE } from '@shell/store/prefs';
5
- import { STATES_ENUM, STATES, getStateLabel } from '@shell/plugins/dashboard-store/resource-class';
5
+ import {
6
+ getStateLabel,
7
+ primaryDisplayStatusFromCount,
8
+ STATES,
9
+ STATES_ENUM,
10
+ } from '@shell/plugins/dashboard-store/resource-class';
6
11
  import Loading from '@shell/components/Loading';
7
12
  import CollapsibleCard from '@shell/components/CollapsibleCard.vue';
8
13
  import ResourceTable from '@shell/components/ResourceTable';
@@ -37,10 +42,15 @@ export default {
37
42
  inStoreType: 'management',
38
43
  type: FLEET.CLUSTER_GROUP
39
44
  },
45
+ allBundleDeployments: {
46
+ inStoreType: 'management',
47
+ type: FLEET.BUNDLE_DEPLOYMENT,
48
+ },
40
49
  allBundles: {
41
50
  inStoreType: 'management',
42
51
  type: FLEET.BUNDLE,
43
52
  opt: { excludeFields: ['metadata.managedFields', 'spec.resources'] },
53
+ skipWait: true,
44
54
  },
45
55
  gitRepos: {
46
56
  inStoreType: 'management',
@@ -98,7 +108,6 @@ export default {
98
108
  }
99
109
  ],
100
110
  schema: {},
101
- allBundles: [],
102
111
  gitRepos: [],
103
112
  fleetWorkspacesData: [],
104
113
  isCollapsed: {},
@@ -138,14 +147,24 @@ export default {
138
147
  });
139
148
  },
140
149
  workspacesData() {
141
- return this.fleetWorkspaces.filter((ws) => ws.repos && ws.repos.length);
150
+ return this.fleetWorkspaces.filter((ws) => ws.counts.gitRepos > 0);
142
151
  },
143
152
  emptyWorkspaces() {
144
- return this.fleetWorkspaces.filter((ws) => !ws.repos || !ws.repos.length);
153
+ return this.fleetWorkspaces.filter((ws) => ws.counts.gitRepos === 0);
145
154
  },
146
155
  areAllCardsExpanded() {
147
156
  return Object.keys(this.isCollapsed).every((key) => !this.isCollapsed[key]);
148
- }
157
+ },
158
+ gitReposCounts() {
159
+ return this.gitRepos.reduce((prev, gitRepo) => {
160
+ prev[gitRepo.id] = {
161
+ bundles: gitRepo.allBundlesStatuses,
162
+ resources: gitRepo.allResourceStatuses,
163
+ };
164
+
165
+ return prev;
166
+ }, {});
167
+ },
149
168
  },
150
169
  methods: {
151
170
  setWorkspaceFilterAndLinkToGitRepo(value) {
@@ -160,108 +179,71 @@ export default {
160
179
  },
161
180
  });
162
181
  },
163
- getStatusInfo(area, row) {
182
+ getStatusInfo(area, row, rowCounts) {
164
183
  const defaultStatusInfo = {
165
184
  badgeClass: `${ STATES[STATES_ENUM.NOT_READY].color } badge-class-default`,
166
185
  icon: STATES[STATES_ENUM.NOT_READY].compoundIcon
167
186
  };
168
187
 
169
188
  // classes are defined in the themes SASS files...
170
- return this.getBadgeClassAndIcon(area, row) || defaultStatusInfo;
189
+ return this.getBadgeClassAndIcon(area, row, rowCounts) || defaultStatusInfo;
171
190
  },
172
- getBadgeClassAndIcon(area, row) {
173
- let group;
174
-
191
+ getBadgeClassAndIcon(area, row, rowCounts) {
175
192
  if (!this.admissableAreas.includes(area)) {
176
193
  return false;
177
194
  }
178
195
 
196
+ let group;
197
+
179
198
  if (area === 'clusters') {
180
- if (row.clusterInfo?.ready === row.clusterInfo?.total && row.clusterInfo?.ready) {
181
- return {
182
- badgeClass: STATES[STATES_ENUM.ACTIVE].color,
183
- icon: STATES[STATES_ENUM.ACTIVE].compoundIcon
184
- };
185
- }
186
- } else if (area === 'bundles') {
187
- group = row.bundles;
188
- } else if (area === 'resources') {
189
- group = row.status?.resources;
190
- }
199
+ const clusterInfo = row.clusterInfo;
200
+ const state = clusterInfo.ready === clusterInfo.total ? STATES_ENUM.ACTIVE : STATES_ENUM.NOT_READY;
191
201
 
192
- if (group?.length && group?.every((item) => item.state?.toLowerCase() === STATES_ENUM.ACTIVE)) {
193
- return {
194
- badgeClass: STATES[STATES_ENUM.ACTIVE].color ? STATES[STATES_ENUM.ACTIVE].color : `${ STATES[STATES_ENUM.UNKNOWN].color } bg-unmapped-state`,
195
- icon: STATES[STATES_ENUM.ACTIVE].compoundIcon ? STATES[STATES_ENUM.ACTIVE].compoundIcon : `${ STATES[STATES_ENUM.UNKNOWN].compoundIcon } unmapped-icon`
196
- };
197
- }
198
- if (group?.length && group?.some((item) => item.state?.toLowerCase() === STATES_ENUM.ERR_APPLIED)) {
199
202
  return {
200
- badgeClass: STATES[STATES_ENUM.ERR_APPLIED].color ? STATES[STATES_ENUM.ERR_APPLIED].color : `${ STATES[STATES_ENUM.UNKNOWN].color } bg-unmapped-state`,
201
- icon: STATES[STATES_ENUM.ERR_APPLIED].compoundIcon ? STATES[STATES_ENUM.ERR_APPLIED].compoundIcon : `${ STATES[STATES_ENUM.UNKNOWN].compoundIcon } unmapped-icon`
203
+ badgeClass: `${ STATES[state].color } badge-class-area-${ area }`,
204
+ icon: STATES[state].compoundIcon
202
205
  };
206
+ } else if (area === 'bundles') {
207
+ group = rowCounts[row.id].bundles;
208
+ } else if (area === 'resources') {
209
+ group = rowCounts[row.id].resources;
210
+ } else {
211
+ // unreachable
212
+ return false;
203
213
  }
204
- if (group?.length && group?.some((item) => item.state?.toLowerCase() === STATES_ENUM.NOT_READY)) {
214
+
215
+ if (group.total === group.states.ready) {
205
216
  return {
206
- badgeClass: STATES[STATES_ENUM.NOT_READY].color ? STATES[STATES_ENUM.NOT_READY].color : `${ STATES[STATES_ENUM.UNKNOWN].color } bg-unmapped-state`,
207
- icon: STATES[STATES_ENUM.NOT_READY].compoundIcon ? STATES[STATES_ENUM.NOT_READY].compoundIcon : `${ STATES[STATES_ENUM.UNKNOWN].compoundIcon } unmapped-icon`
217
+ badgeClass: STATES[STATES_ENUM.ACTIVE].color,
218
+ icon: STATES[STATES_ENUM.ACTIVE].compoundIcon,
208
219
  };
209
220
  }
210
-
211
- if (area === 'resources') {
212
- if (row.status?.resourceCounts?.desiredReady === row.status?.resourceCounts?.ready && row.status?.resourceCounts?.desiredReady) {
213
- return {
214
- badgeClass: STATES[STATES_ENUM.ACTIVE].color,
215
- icon: STATES[STATES_ENUM.ACTIVE].compoundIcon
216
- };
217
- }
218
- }
221
+ const state = primaryDisplayStatusFromCount(group.states);
219
222
 
220
223
  return {
221
- badgeClass: `${ STATES[STATES_ENUM.NOT_READY].color } badge-class-area-${ area }`,
222
- icon: STATES[STATES_ENUM.NOT_READY].compoundIcon
224
+ badgeClass: STATES[state].color ? STATES[state].color : `${ STATES[STATES_ENUM.UNKNOWN].color } bg-unmapped-state`,
225
+ icon: STATES[state].compoundIcon ? STATES[state].compoundIcon : `${ STATES[STATES_ENUM.UNKNOWN].compoundIcon } unmapped-icon`
223
226
  };
224
227
  },
225
- getTooltipInfo(area, row) {
226
- let group;
227
-
228
+ getTooltipInfo(area, row, rowCounts) {
228
229
  if (!this.admissableAreas.includes(area)) {
229
230
  return {};
230
231
  }
231
232
 
232
- if (area === 'clusters') {
233
- group = '';
234
- } else if (area === 'bundles') {
235
- group = row.bundles;
233
+ if (area === 'bundles') {
234
+ return this.generateTooltipData(rowCounts[row.id].bundles.states);
236
235
  } else if (area === 'resources') {
237
- group = row.status?.resources;
238
- }
239
-
240
- if (group?.length) {
241
- return this.generateTooltipData(group);
236
+ return this.generateTooltipData(rowCounts[row.id].resources.states);
242
237
  }
243
238
 
244
239
  return '';
245
240
  },
246
- generateTooltipData(data) {
247
- const infoObj = {};
248
- let tooltipData = '';
249
-
250
- data.forEach((item) => {
251
- if (!infoObj[item.state]) {
252
- infoObj[item.state] = 0;
253
- }
254
-
255
- infoObj[item.state]++;
256
- });
257
-
258
- Object.keys(infoObj).forEach((key) => {
259
- tooltipData += `${ getStateLabel(key) }: ${ infoObj[key] }<br>`;
260
- });
261
-
262
- return tooltipData;
241
+ generateTooltipData(infoObj) {
242
+ return Object.keys(infoObj)
243
+ .filter((key) => infoObj[key] > 0) // filter zero values
244
+ .map((key) => `${ getStateLabel(key) }: ${ infoObj[key] }<br>`).join('');
263
245
  },
264
- getBadgeValue(area, row) {
246
+ getBadgeValue(area, row, rowCounts) {
265
247
  let value;
266
248
 
267
249
  if (!this.admissableAreas.includes(area)) {
@@ -269,11 +251,15 @@ export default {
269
251
  }
270
252
 
271
253
  if (area === 'clusters') {
272
- return `${ row.clusterInfo.ready }/${ row.clusterInfo.total }`;
254
+ value = `${ row.clusterInfo.ready }/${ row.clusterInfo.total }`;
273
255
  } else if (area === 'bundles') {
274
- value = xOfy(row.bundlesReady?.length, row.bundles?.length);
256
+ const bundles = rowCounts[row.id].bundles;
257
+
258
+ value = xOfy(bundles.states.ready || 0, bundles.total);
275
259
  } else if (area === 'resources') {
276
- value = xOfy(row.status?.resourceCounts?.ready, row.status?.resourceCounts?.desiredReady);
260
+ const resources = rowCounts[row.id].resources;
261
+
262
+ value = xOfy(resources.states.ready || 0, resources.total);
277
263
  }
278
264
 
279
265
  return value;
@@ -413,10 +399,10 @@ export default {
413
399
  <CompoundStatusBadge
414
400
  v-else
415
401
  data-testid="clusters-ready"
416
- :tooltip-text="getTooltipInfo('clusters', row)"
417
- :badge-class="getStatusInfo('clusters', row).badgeClass"
418
- :icon="getStatusInfo('clusters', row).icon"
419
- :value="getBadgeValue('clusters', row)"
402
+ :tooltip-text="getTooltipInfo('clusters', row, gitReposCounts)"
403
+ :badge-class="getStatusInfo('clusters', row, gitReposCounts).badgeClass"
404
+ :icon="getStatusInfo('clusters', row, gitReposCounts).icon"
405
+ :value="getBadgeValue('clusters', row, gitReposCounts)"
420
406
  />
421
407
  </template>
422
408
  <template #cell:bundlesReady="{row}">
@@ -424,19 +410,19 @@ export default {
424
410
  <CompoundStatusBadge
425
411
  v-else
426
412
  data-testid="bundles-ready"
427
- :tooltip-text="getTooltipInfo('bundles', row)"
428
- :badge-class="getStatusInfo('bundles', row).badgeClass"
429
- :icon="getStatusInfo('bundles', row).icon"
430
- :value="getBadgeValue('bundles', row)"
413
+ :tooltip-text="getTooltipInfo('bundles', row, gitReposCounts)"
414
+ :badge-class="getStatusInfo('bundles', row, gitReposCounts).badgeClass"
415
+ :icon="getStatusInfo('bundles', row, gitReposCounts).icon"
416
+ :value="getBadgeValue('bundles', row, gitReposCounts)"
431
417
  />
432
418
  </template>
433
419
  <template #cell:resourcesReady="{row}">
434
420
  <CompoundStatusBadge
435
421
  data-testid="resources-ready"
436
- :tooltip-text="getTooltipInfo('resources', row)"
437
- :badge-class="getStatusInfo('resources', row).badgeClass"
438
- :icon="getStatusInfo('resources', row).icon"
439
- :value="getBadgeValue('resources', row)"
422
+ :tooltip-text="getTooltipInfo('resources', row, gitReposCounts)"
423
+ :badge-class="getStatusInfo('resources', row, gitReposCounts).badgeClass"
424
+ :icon="getStatusInfo('resources', row, gitReposCounts).icon"
425
+ :value="getBadgeValue('resources', row, gitReposCounts)"
440
426
  />
441
427
  </template>
442
428
 
@@ -10,7 +10,7 @@ import KeyValue from '@shell/components/form/KeyValue';
10
10
  import { mapGetters } from 'vuex';
11
11
  import { isRancherPrime } from '@shell/config/version';
12
12
  import DefaultLinksEditor from './DefaultLinksEditor';
13
- import { CUSTOM_LINKS_COLLECTIVE_VERSION, fetchLinks } from '@shell/config/home-links';
13
+ import { CUSTOM_LINKS_APP_CO_VERSION, fetchLinks } from '@shell/config/home-links';
14
14
  import TabTitle from '@shell/components/TabTitle';
15
15
 
16
16
  export default {
@@ -47,7 +47,7 @@ export default {
47
47
 
48
48
  allValues() {
49
49
  return {
50
- version: CUSTOM_LINKS_COLLECTIVE_VERSION,
50
+ version: CUSTOM_LINKS_APP_CO_VERSION,
51
51
  defaults: this.value.defaults.filter((obj) => obj.enabled).map((obj) => obj.key),
52
52
  custom: this.value.custom
53
53
  };
@@ -42,7 +42,8 @@ export default {
42
42
  branch: UI_PLUGINS_REPOS.PARTNERS.BRANCH,
43
43
  }
44
44
  },
45
- isDialogActive: false,
45
+ isDialogActive: false,
46
+ returnFocusSelector: '[data-testid="extensions-page-menu"]'
46
47
  };
47
48
  },
48
49
 
@@ -109,6 +110,7 @@ export default {
109
110
  :title="t('plugins.addRepos.title')"
110
111
  mode="add"
111
112
  data-testid="add-extensions-repos-modal"
113
+ :return-focus-selector="returnFocusSelector"
112
114
  @okay="doAddRepos"
113
115
  @closed="isDialogActive = false"
114
116
  >
@@ -128,6 +128,7 @@ export default {
128
128
  ...initialState(),
129
129
  secondaryResourceData: null,
130
130
  showModal: false,
131
+ returnFocusSelector: '[data-testid="extensions-catalog-load-dialog"]'
131
132
  };
132
133
  },
133
134
 
@@ -434,6 +435,8 @@ export default {
434
435
  name="catalogLoadDialog"
435
436
  height="auto"
436
437
  :scrollable="true"
438
+ :trigger-focus-trap="true"
439
+ :return-focus-selector="returnFocusSelector"
437
440
  @close="closeDialog()"
438
441
  >
439
442
  <Loading
@@ -23,7 +23,11 @@ export default {
23
23
 
24
24
  data() {
25
25
  return {
26
- catalog: undefined, busy: false, plugins: null, showModal: false,
26
+ catalog: undefined,
27
+ busy: false,
28
+ plugins: null,
29
+ showModal: false,
30
+ returnFocusSelector: '[data-testid="extensions-catalog-load-dialog"]'
27
31
  };
28
32
  },
29
33
 
@@ -121,6 +125,8 @@ export default {
121
125
  name="uninstallCatalogDialog"
122
126
  height="auto"
123
127
  :scrollable="true"
128
+ :trigger-focus-trap="true"
129
+ :return-focus-selector="returnFocusSelector"
124
130
  @close="closeDialog(false)"
125
131
  >
126
132
  <div
@@ -95,10 +95,12 @@ export default {
95
95
  <template #header-left>
96
96
  <div>
97
97
  <button
98
- class="btn bg-primary mr-10"
98
+ class="btn role-primary mr-10"
99
99
  type="button"
100
100
  aria-haspopup="dialog"
101
101
  data-testid="extensions-catalog-load-dialog"
102
+ role="button"
103
+ :aria-label="t('plugins.manageCatalog.imageLoad.load')"
102
104
  @click="$emit('showCatalogLoadDialog')"
103
105
  >
104
106
  {{ t('plugins.manageCatalog.imageLoad.load') }}
@@ -18,17 +18,18 @@ export default {
18
18
 
19
19
  data() {
20
20
  return {
21
- name: '',
22
- location: '',
23
- persist: false,
24
- canModifyName: true,
25
- canModifyLocation: true,
26
- showModal: false,
21
+ name: '',
22
+ location: '',
23
+ persist: false,
24
+ canModifyName: true,
25
+ canModifyLocation: true,
26
+ showModal: false,
27
+ returnFocusSelector: '[data-testid="extensions-page-menu"]'
27
28
  };
28
29
  },
29
30
 
30
31
  watch: {
31
- name(neu, old) {
32
+ name(neu) {
32
33
  if (this.canModifyLocation) {
33
34
  this.location = `/pkg/${ neu }/${ neu }.umd.min.js`;
34
35
  }
@@ -154,6 +155,8 @@ export default {
154
155
  name="developerInstallPluginDialog"
155
156
  height="auto"
156
157
  :scrollable="true"
158
+ :trigger-focus-trap="true"
159
+ :return-focus-selector="returnFocusSelector"
157
160
  @close="closeDialog()"
158
161
  >
159
162
  <div class="plugin-install-dialog">
@@ -74,6 +74,10 @@ export default {
74
74
 
75
75
  chartVersionLoadsWithoutAuth() {
76
76
  return this.chartVersionInfo?.values?.plugin?.noAuth;
77
+ },
78
+
79
+ returnFocusSelector() {
80
+ return `[data-testid="extension-card-${ this.mode }-btn-${ this.plugin?.name }"]`;
77
81
  }
78
82
  },
79
83
 
@@ -251,6 +255,9 @@ export default {
251
255
  name="installPluginDialog"
252
256
  height="auto"
253
257
  :scrollable="true"
258
+ :trigger-focus-trap="true"
259
+ :return-focus-selector="returnFocusSelector"
260
+ :return-focus-first-iterable-node-selector="'#extensions-main-page'"
254
261
  @close="closeDialog(false)"
255
262
  >
256
263
  <div