@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
@@ -19,10 +19,11 @@ import { NAME as EXPLORER } from '@shell/config/product/explorer';
19
19
  import { TYPE_MODES } from '@shell/store/type-map';
20
20
  import { NAME as NAVLINKS } from '@shell/config/product/navlinks';
21
21
  import Group from '@shell/components/nav/Group';
22
+ import LocaleSelector from '@shell/components/LocaleSelector';
22
23
 
23
24
  export default {
24
25
  name: 'SideNav',
25
- components: { Group },
26
+ components: { Group, LocaleSelector },
26
27
  data() {
27
28
  return {
28
29
  groups: [],
@@ -112,9 +113,7 @@ export default {
112
113
  computed: {
113
114
  ...mapState(['managementReady', 'clusterReady']),
114
115
  ...mapGetters(['isStandaloneHarvester', 'productId', 'clusterId', 'currentProduct', 'rootProduct', 'isSingleProduct', 'namespaceMode', 'isExplorer', 'isVirtualCluster']),
115
- ...mapGetters({
116
- locale: 'i18n/selectedLocaleLabel', availableLocales: 'i18n/availableLocales', hasMultipleLocales: 'i18n/hasMultipleLocales'
117
- }),
116
+ ...mapGetters({ locale: 'i18n/selectedLocaleLabel', hasMultipleLocales: 'i18n/hasMultipleLocales' }),
118
117
  ...mapGetters('type-map', ['activeProducts']),
119
118
 
120
119
  favoriteTypes: mapPref(FAVORITE_TYPES),
@@ -360,10 +359,6 @@ export default {
360
359
  });
361
360
  },
362
361
 
363
- switchLocale(locale) {
364
- this.$store.dispatch('i18n/switchTo', locale);
365
- },
366
-
367
362
  syncNav() {
368
363
  const refs = this.$refs.groups;
369
364
 
@@ -427,6 +422,8 @@ export default {
427
422
  <router-link
428
423
  :to="supportLink"
429
424
  class="pull-right"
425
+ role="link"
426
+ :aria-label="t('nav.support', {hasSupport: true})"
430
427
  >
431
428
  {{ t('nav.support', {hasSupport: true}) }}
432
429
  </router-link>
@@ -439,36 +436,11 @@ export default {
439
436
  </span>
440
437
 
441
438
  <!-- locale selector -->
442
- <span v-if="isSingleProduct && hasMultipleLocales && !isStandaloneHarvester">
443
- <v-dropdown
444
- popperClass="localeSelector"
445
- placement="top"
446
- :triggers="['click']"
447
- >
448
- <a
449
- data-testid="locale-selector"
450
- class="locale-chooser"
451
- >
452
- {{ locale }}
453
- </a>
454
-
455
- <template #popper>
456
- <ul
457
- class="list-unstyled dropdown"
458
- style="margin: -1px;"
459
- >
460
- <li
461
- v-for="(label, name) in availableLocales"
462
- :key="name"
463
- class="hand"
464
- @click="switchLocale(name)"
465
- >
466
- {{ label }}
467
- </li>
468
- </ul>
469
- </template>
470
- </v-dropdown>
471
- </span>
439
+ <LocaleSelector
440
+ v-if="isSingleProduct && hasMultipleLocales && !isStandaloneHarvester"
441
+ mode="login"
442
+ :show-icon="false"
443
+ />
472
444
  </div>
473
445
  <!-- SideNav footer alternative -->
474
446
  <div
@@ -478,6 +450,8 @@ export default {
478
450
  <router-link
479
451
  v-if="singleProductAbout"
480
452
  :to="singleProductAbout"
453
+ role="link"
454
+ :aria-label="t('nav.ariaLabel.productAboutPage')"
481
455
  >
482
456
  {{ displayVersion }}
483
457
  </router-link>
@@ -1213,6 +1213,7 @@ export default {
1213
1213
  v-model="eventualSearchQuery"
1214
1214
  type="search"
1215
1215
  class="input-sm search-box"
1216
+ :aria-label="t('sortableTable.searchLabel')"
1216
1217
  :placeholder="t('sortableTable.search')"
1217
1218
  >
1218
1219
  <slot name="header-button" />
@@ -258,7 +258,6 @@ export default {
258
258
  role="tablist"
259
259
  class="tabs"
260
260
  :class="{'clearfix':!sideTabs, 'vertical': sideTabs, 'horizontal': !sideTabs}"
261
- tabindex="0"
262
261
  data-testid="tabbed-block"
263
262
  @keydown.right.prevent="selectNext(1)"
264
263
  @keydown.left.prevent="selectNext(-1)"
@@ -277,8 +276,11 @@ export default {
277
276
  :data-testid="`btn-${tab.name}`"
278
277
  :aria-controls="'#' + tab.name"
279
278
  :aria-selected="tab.active"
279
+ :aria-label="tab.labelDisplay || ''"
280
280
  role="tab"
281
+ tabindex="0"
281
282
  @click.prevent="select(tab.name, $event)"
283
+ @keyup.enter.space="select(tab.name, $event)"
282
284
  >
283
285
  <span>{{ tab.labelDisplay }}</span>
284
286
  <span
@@ -403,6 +405,12 @@ export default {
403
405
  text-decoration: underline;
404
406
  }
405
407
  }
408
+
409
+ &:focus-visible {
410
+ @include focus-outline;
411
+ outline-offset: -4px;
412
+ text-decoration: none;
413
+ }
406
414
  }
407
415
 
408
416
  .conditions-alert-icon {
@@ -126,6 +126,7 @@ export default {
126
126
  cm.indentSelection('subtract');
127
127
  }
128
128
  },
129
+ screenReaderLabel: this.t('import.editor.label'),
129
130
  // @TODO find a better way to display the outline
130
131
  // foldOptions: {
131
132
  // widget: (from, to) => {
@@ -1,35 +1,41 @@
1
1
  import { mount } from '@vue/test-utils';
2
2
  import Carousel from '@shell/components/Carousel.vue';
3
3
 
4
+ const sliders = [
5
+ {
6
+ key: 'key-0',
7
+ repoName: 'some-repo-name-0',
8
+ chartNameDisplay: 'chart-name-display-0',
9
+ chartDescription: 'chart-description-0'
10
+ },
11
+ {
12
+ key: 'key-1',
13
+ repoName: 'some-repo-name-1',
14
+ chartNameDisplay: 'chart-name-display-1',
15
+ chartDescription: 'chart-description-1'
16
+ },
17
+ {
18
+ key: 'key-2',
19
+ repoName: 'some-repo-name-2',
20
+ chartNameDisplay: 'chart-name-display-2',
21
+ chartDescription: 'chart-description-2'
22
+ },
23
+ {
24
+ key: 'key-3',
25
+ repoName: 'some-repo-name-3',
26
+ chartNameDisplay: 'chart-name-display-3',
27
+ chartDescription: 'chart-description-3'
28
+ },
29
+ {
30
+ key: 'key-4',
31
+ repoName: 'some-repo-name-4',
32
+ chartNameDisplay: 'chart-name-display-4',
33
+ chartDescription: 'chart-description-4'
34
+ }
35
+ ];
36
+
4
37
  describe('component: Carousel', () => {
5
38
  it('should render component with the correct data applied', async() => {
6
- const sliders = [
7
- {
8
- key: 'key-0',
9
- repoName: 'some-repo-name-0',
10
- chartNameDisplay: 'chart-name-display-0',
11
- chartDescription: 'chart-description-0'
12
- },
13
- {
14
- key: 'key-1',
15
- repoName: 'some-repo-name-1',
16
- chartNameDisplay: 'chart-name-display-1',
17
- chartDescription: 'chart-description-1'
18
- },
19
- {
20
- key: 'key-2',
21
- repoName: 'some-repo-name-2',
22
- chartNameDisplay: 'chart-name-display-2',
23
- chartDescription: 'chart-description-2'
24
- },
25
- {
26
- key: 'key-3',
27
- repoName: 'some-repo-name-3',
28
- chartNameDisplay: 'chart-name-display-3',
29
- chartDescription: 'chart-description-3'
30
- }
31
- ];
32
-
33
39
  const wrapper = mount(Carousel, {
34
40
  props: { sliders },
35
41
  global: { mocks: { $store: { getters: { clusterId: () => 'some-cluster-id' } } } }
@@ -40,4 +46,27 @@ describe('component: Carousel', () => {
40
46
  expect(wrapper.find(`#slide${ index } h1`).text()).toContain(slider.chartNameDisplay);
41
47
  });
42
48
  });
49
+
50
+ it.each([
51
+ [sliders.slice(0, 2)],
52
+ [sliders.slice(0, 3)],
53
+ [sliders.slice(0, 4)],
54
+ [sliders.slice(0, 5)]
55
+ ])('should have the correct width and left position', async(sliders) => {
56
+ const wrapper = mount(Carousel, {
57
+ props: { sliders },
58
+ global: { mocks: { $store: { getters: { clusterId: () => 'some-cluster-id' } } } }
59
+ });
60
+
61
+ const width = 60 * (wrapper.vm.slider.length + 2);
62
+ const initialLeft = -(40 + wrapper.vm.activeItemId * 60);
63
+
64
+ expect(wrapper.vm.trackStyle).toContain(`width: ${ width }%`);
65
+ expect(wrapper.vm.trackStyle).toContain(`left: ${ initialLeft }`);
66
+
67
+ wrapper.vm.activeItemId = wrapper.vm.activeItemId + 1; // next slide
68
+ expect(wrapper.vm.trackStyle).toContain(`left: ${ -(40 + wrapper.vm.activeItemId * 60) }`);
69
+ wrapper.vm.activeItemId = wrapper.vm.activeItemId - 1; // previous slide
70
+ expect(wrapper.vm.trackStyle).toContain(`left: ${ initialLeft }`);
71
+ });
43
72
  });
@@ -85,9 +85,11 @@ export default {
85
85
  class="name"
86
86
  >
87
87
  <table>
88
- <tr><td>{{ t('principal.name') }}: </td><td>{{ principal.name || principal.loginName }}</td></tr>
89
- <tr><td>{{ t('principal.loginName') }}: </td><td>{{ principal.loginName }}</td></tr>
90
- <tr><td>{{ t('principal.type') }}: </td><td>{{ principal.displayType }}</td></tr>
88
+ <tbody>
89
+ <tr><td>{{ t('principal.name') }}: </td><td>{{ principal.name || principal.loginName }}</td></tr>
90
+ <tr><td>{{ t('principal.loginName') }}: </td><td>{{ principal.loginName }}</td></tr>
91
+ <tr><td>{{ t('principal.type') }}: </td><td>{{ principal.displayType }}</td></tr>
92
+ </tbody>
91
93
  </table>
92
94
  </div>
93
95
  <template v-else>
@@ -1,10 +1,11 @@
1
1
  <script>
2
2
  import ResourceTable from '@shell/components/ResourceTable';
3
+ import Tag from '@shell/components/Tag.vue';
3
4
  import { STATE, NAME, AGE, FLEET_SUMMARY } from '@shell/config/table-headers';
4
5
  import { FLEET, MANAGEMENT } from '@shell/config/types';
5
6
 
6
7
  export default {
7
- components: { ResourceTable },
8
+ components: { ResourceTable, Tag },
8
9
 
9
10
  props: {
10
11
  rows: {
@@ -75,6 +76,12 @@ export default {
75
76
  pluralLabel: this.$store.getters['type-map/labelFor'](schema, 99),
76
77
  };
77
78
  },
79
+ },
80
+
81
+ methods: {
82
+ toggleCustomLabels(row) {
83
+ row['displayCustomLabels'] = !row.displayCustomLabels;
84
+ }
78
85
  }
79
86
  };
80
87
  </script>
@@ -85,6 +92,7 @@ export default {
85
92
  :schema="schema"
86
93
  :headers="headers"
87
94
  :rows="rows"
95
+ :sub-rows="true"
88
96
  :loading="loading"
89
97
  :use-query-params-for-simple-filtering="useQueryParamsForSimpleFiltering"
90
98
  key-field="_key"
@@ -123,5 +131,78 @@ export default {
123
131
  :class="{'text-error': !row.bundleInfo.total}"
124
132
  >{{ row.bundleInfo.total }}</span>
125
133
  </template>
134
+
135
+ <template #sub-row="{fullColspan, row, onRowMouseEnter, onRowMouseLeave}">
136
+ <tr
137
+ class="labels-row sub-row"
138
+ @mouseenter="onRowMouseEnter"
139
+ @mouseleave="onRowMouseLeave"
140
+ >
141
+ <template v-if="row.customLabels.length">
142
+ <td>&nbsp;</td>
143
+ <td>&nbsp;</td>
144
+ <td :colspan="fullColspan-2">
145
+ <span
146
+ v-if="row.customLabels.length"
147
+ class="mt-5"
148
+ > {{ t('fleet.cluster.labels') }}:
149
+ <span
150
+ v-for="(label, i) in row.customLabels"
151
+ :key="i"
152
+ class="mt-5 labels"
153
+ >
154
+ <Tag
155
+ v-if="i < 7"
156
+ class="mr-5 label"
157
+ >
158
+ {{ label }}
159
+ </Tag>
160
+ <Tag
161
+ v-else-if="i > 6 && row.displayCustomLabels"
162
+ class="mr-5 label"
163
+ >
164
+ {{ label }}
165
+ </Tag>
166
+ </span>
167
+ <a
168
+ v-if="row.customLabels.length > 7"
169
+ href="#"
170
+ @click.prevent="toggleCustomLabels(row)"
171
+ >
172
+ {{ t(`fleet.cluster.${row.displayCustomLabels? 'hideLabels' : 'showLabels'}`) }}
173
+ </a>
174
+ </span>
175
+ </td>
176
+ </template>
177
+ <td
178
+ v-else
179
+ :colspan="fullColspan"
180
+ >
181
+ &nbsp;
182
+ </td>
183
+ </tr>
184
+ </template>
126
185
  </ResourceTable>
127
186
  </template>
187
+
188
+ <style lang='scss' scoped>
189
+ .labels-row {
190
+ td {
191
+ padding-top:0;
192
+ .tag {
193
+ margin-right: 5px;
194
+ display: inline-block;
195
+ margin-top: 2px;
196
+ }
197
+ }
198
+ }
199
+ .labels {
200
+ display: inline;
201
+ flex-wrap: wrap;
202
+
203
+ .label {
204
+ display: inline-block;
205
+ margin-top: 2px;
206
+ }
207
+ }
208
+ </style>
@@ -6,17 +6,15 @@ import FleetIntro from '@shell/components/fleet/FleetIntro';
6
6
 
7
7
  import {
8
8
  AGE,
9
- STATE,
10
- NAME,
11
- FLEET_SUMMARY,
12
9
  FLEET_REPO,
13
- FLEET_REPO_TARGET,
14
- FLEET_REPO_CLUSTERS_READY,
15
10
  FLEET_REPO_CLUSTER_SUMMARY,
16
- FLEET_REPO_PER_CLUSTER_STATE
17
-
11
+ FLEET_REPO_CLUSTERS_READY,
12
+ FLEET_REPO_PER_CLUSTER_STATE,
13
+ FLEET_REPO_TARGET,
14
+ FLEET_SUMMARY,
15
+ NAME,
16
+ STATE,
18
17
  } from '@shell/config/table-headers';
19
- import { STATES_ENUM } from '@shell/plugins/dashboard-store/resource-class';
20
18
 
21
19
  // i18n-ignore repoDisplay
22
20
  export default {
@@ -77,31 +75,18 @@ export default {
77
75
 
78
76
  headers() {
79
77
  // Cluster summary is only shown in the cluster view
80
- const fleetClusterSummary = {
78
+ const summary = this.isClusterView ? [{
81
79
  ...FLEET_REPO_CLUSTER_SUMMARY,
82
- formatterOpts: {
83
- // Fleet uses labels to identify clusters
84
- clusterLabel: this.clusterId
85
- },
86
- };
80
+ formatterOpts: { clusterId: this.clusterId },
81
+ }] : [FLEET_REPO_CLUSTERS_READY, FLEET_SUMMARY];
87
82
 
88
83
  // if hasPerClusterState then use the repo state
89
- const fleetPerClusterState = {
84
+ const state = this.isClusterView ? {
90
85
  ...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;
97
- },
98
- };
86
+ value: (repo) => repo.clusterState(this.clusterId),
87
+ } : STATE;
99
88
 
100
- const summary = this.isClusterView ? [fleetClusterSummary] : [FLEET_REPO_CLUSTERS_READY, FLEET_SUMMARY];
101
-
102
- const state = this.isClusterView ? fleetPerClusterState : STATE;
103
-
104
- const out = [
89
+ return [
105
90
  state,
106
91
  NAME,
107
92
  FLEET_REPO,
@@ -109,8 +94,6 @@ export default {
109
94
  ...summary,
110
95
  AGE
111
96
  ];
112
-
113
- return out;
114
97
  },
115
98
  },
116
99
  methods: {
@@ -386,10 +386,10 @@ export default {
386
386
  <router-link
387
387
  :to="item.valueObj.detailLocation"
388
388
  >
389
- {{ item.valueObj.id }}
389
+ {{ item.valueObj.label }}
390
390
  </router-link>
391
391
  </span>
392
- <span v-else>{{ item.valueObj.id }}</span>
392
+ <span v-else>{{ item.valueObj.label }}</span>
393
393
  </td>
394
394
  <!-- state-badge template -->
395
395
  <td
@@ -407,6 +407,8 @@ export default {
407
407
  <Banner
408
408
  v-for="(err, i) in errorMessages"
409
409
  :key="i"
410
+ role="alert"
411
+ :aria-label="err"
410
412
  color="error"
411
413
  :label="err"
412
414
  class="mb-0"
@@ -73,7 +73,21 @@ export default {
73
73
  mounted() {
74
74
  // Ensures that if the default value is used, the model is updated with it
75
75
  this.$emit('update:value', this.inputValue);
76
- }
76
+ },
77
+
78
+ methods: {
79
+ handleKeyup(ev) {
80
+ if (this.isDisabled) {
81
+ return '';
82
+ }
83
+
84
+ return this.$refs.input.click(ev);
85
+ }
86
+ },
87
+
88
+ // according to https://www.w3.org/TR/html-aria/
89
+ // input type="color" has no applicable role
90
+ // and only aria-label and aria-disabled
77
91
  };
78
92
  </script>
79
93
 
@@ -82,6 +96,8 @@ export default {
82
96
  class="color-input"
83
97
  :class="{[mode]:mode, disabled: isDisabled}"
84
98
  :data-testid="componentTestid + '-color-input'"
99
+ :tabindex="isDisabled ? -1 : 0"
100
+ @keyup.enter.space.stop="handleKeyup($event)"
85
101
  >
86
102
  <label class="text-label"><t
87
103
  v-if="labelKey"
@@ -99,8 +115,11 @@ export default {
99
115
  >
100
116
  <input
101
117
  ref="input"
118
+ :aria-disabled="isDisabled ? 'true' : 'false'"
119
+ :aria-label="t('generic.colorPicker')"
102
120
  type="color"
103
121
  :disabled="isDisabled"
122
+ tabindex="-1"
104
123
  :value="inputValue"
105
124
  @input="$emit('update:value', $event.target.value)"
106
125
  >
@@ -116,6 +135,10 @@ export default {
116
135
  border-radius: var(--border-radius);
117
136
  padding: 10px;
118
137
 
138
+ &:focus-visible {
139
+ @include focus-outline;
140
+ }
141
+
119
142
  &.disabled, &.disabled .selected, &[disabled], &[disabled]:hover {
120
143
  color: var(--input-disabled-text);
121
144
  background-color: var(--input-disabled-bg);
@@ -148,7 +148,9 @@ export default {
148
148
  <button
149
149
  v-if="!isView"
150
150
  :disabled="disabled"
151
+ :aria-label="label"
151
152
  type="button"
153
+ role="button"
152
154
  class="file-selector btn"
153
155
  data-testid="file-selector__uploader-button"
154
156
  @click="selectFile"