@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.
- package/assets/styles/base/_basic.scss +7 -8
- package/assets/styles/global/_button.scss +10 -0
- package/assets/styles/global/_form.scss +2 -1
- package/assets/styles/global/_tooltip.scss +2 -2
- package/assets/styles/themes/_dark.scss +15 -3
- package/assets/styles/themes/_light.scss +7 -2
- package/assets/styles/vendor/vue-select.scss +4 -0
- package/assets/translations/en-us.yaml +66 -9
- package/assets/translations/zh-hans.yaml +2 -3
- package/components/AppModal.vue +50 -0
- package/components/BannerGraphic.vue +0 -42
- package/components/ButtonMultiAction.vue +1 -1
- package/components/Carousel.vue +88 -74
- package/components/CommunityLinks.vue +6 -1
- package/components/CopyToClipboardText.vue +3 -0
- package/components/Dialog.vue +20 -1
- package/components/GrowlManager.vue +9 -2
- package/components/LocaleSelector.vue +8 -1
- package/components/PaginatedResourceTable.vue +4 -7
- package/components/ProgressBarMulti.vue +14 -0
- package/components/PromptChangePassword.vue +3 -0
- package/components/Questions/Reference.vue +57 -28
- package/components/ResourceDetail/Masthead.vue +1 -1
- package/components/SelectIconGrid.vue +12 -1
- package/components/SideNav.vue +12 -38
- package/components/SortableTable/index.vue +1 -0
- package/components/Tabbed/index.vue +9 -1
- package/components/YamlEditor.vue +1 -0
- package/components/__tests__/Carousel.test.ts +56 -27
- package/components/auth/Principal.vue +5 -3
- package/components/fleet/FleetClusters.vue +82 -1
- package/components/fleet/FleetRepos.vue +13 -30
- package/components/fleet/ForceDirectedTreeChart/index.vue +2 -2
- package/components/form/ChangePassword.vue +2 -0
- package/components/form/ColorInput.vue +24 -1
- package/components/form/FileSelector.vue +2 -0
- package/components/form/KeyValue.vue +230 -160
- package/components/form/LabeledSelect.vue +2 -2
- package/components/form/PlusMinus.vue +14 -2
- package/components/form/ResourceLabeledSelect.vue +13 -53
- package/components/form/ResourceSelector.vue +1 -0
- package/components/form/ResourceTabs/index.vue +79 -36
- package/components/form/SSHKnownHosts/KnownHostsEditDialog.vue +192 -0
- package/components/form/SSHKnownHosts/__tests__/KnownHostsEditDialog.test.ts +104 -0
- package/components/form/SSHKnownHosts/index.vue +101 -0
- package/components/form/SecretSelector.vue +2 -2
- package/components/form/Select.vue +1 -1
- package/components/form/SelectOrCreateAuthSecret.vue +43 -11
- package/components/form/__tests__/KeyValue.test.ts +1 -1
- package/components/form/__tests__/SSHKnownHosts.test.ts +59 -0
- package/components/formatter/FleetClusterSummaryGraph.vue +2 -2
- package/components/formatter/FleetSummaryGraph.vue +6 -7
- package/components/formatter/WorkloadHealthScale.vue +7 -0
- package/components/nav/Group.vue +30 -4
- package/components/nav/Header.vue +82 -114
- package/components/nav/HeaderPageActionMenu.vue +27 -131
- package/components/nav/NamespaceFilter.vue +1 -1
- package/components/nav/Type.vue +15 -0
- package/composables/focusTrap.ts +68 -0
- package/config/home-links.js +21 -13
- package/config/labels-annotations.js +2 -0
- package/config/page-actions.js +1 -0
- package/config/pagination-table-headers.js +15 -1
- package/config/product/explorer.js +7 -17
- package/config/table-headers.js +6 -0
- package/config/version.js +5 -1
- package/core/plugin.ts +41 -1
- package/core/plugins.js +125 -72
- package/core/types-provisioning.ts +91 -2
- package/core/types.ts +55 -0
- package/detail/__tests__/autoscaling.horizontalpodautoscaler.test.ts +12 -3
- package/detail/catalog.cattle.io.app.vue +1 -1
- package/detail/fleet.cattle.io.cluster.vue +3 -3
- package/detail/namespace.vue +13 -19
- package/detail/networking.k8s.io.ingress.vue +13 -53
- package/detail/provisioning.cattle.io.cluster.vue +12 -1
- package/detail/secret.vue +25 -0
- package/detail/workload/index.vue +3 -3
- package/dialog/AddCustomBadgeDialog.vue +5 -1
- package/edit/auth/ldap/__tests__/config.test.ts +18 -0
- package/edit/auth/ldap/config.vue +24 -0
- package/edit/auth/saml.vue +8 -6
- package/edit/fleet.cattle.io.gitrepo.vue +34 -23
- package/edit/logging-flow/index.vue +4 -19
- package/edit/networking.k8s.io.ingress/index.vue +18 -65
- package/edit/networking.k8s.io.networkpolicy/index.vue +4 -5
- package/edit/provisioning.cattle.io.cluster/index.vue +27 -8
- package/edit/provisioning.cattle.io.cluster/rke2.vue +31 -115
- package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +2 -2
- package/edit/provisioning.cattle.io.cluster/tabs/networking/ACE.vue +14 -28
- package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +25 -12
- package/edit/secret/index.vue +1 -1
- package/edit/secret/ssh.vue +21 -3
- package/edit/service.vue +1 -2
- package/list/networking.k8s.io.ingress.vue +1 -1
- package/list/node.vue +15 -8
- package/list/persistentvolume.vue +12 -4
- package/list/provisioning.cattle.io.cluster.vue +1 -0
- package/list/service.vue +1 -1
- package/list/workload.vue +4 -0
- package/mixins/chart.js +4 -1
- package/models/catalog.cattle.io.app.js +3 -1
- package/models/catalog.cattle.io.clusterrepo.js +56 -7
- package/models/fleet.cattle.io.bundle.js +0 -11
- package/models/fleet.cattle.io.cluster.js +17 -1
- package/models/fleet.cattle.io.gitrepo.js +88 -52
- package/models/provisioning.cattle.io.cluster.js +36 -1
- package/models/secret.js +5 -0
- package/models/service.js +1 -0
- package/models/workload.js +19 -1
- package/package.json +5 -4
- package/pages/account/index.vue +4 -0
- package/pages/c/_cluster/apps/charts/index.vue +4 -0
- package/pages/c/_cluster/explorer/ConfigBadge.vue +4 -2
- package/pages/c/_cluster/explorer/index.vue +13 -6
- package/pages/c/_cluster/fleet/GitRepoGraphConfig.js +3 -3
- package/pages/c/_cluster/fleet/index.vue +75 -89
- package/pages/c/_cluster/settings/links.vue +2 -2
- package/pages/c/_cluster/uiplugins/AddExtensionRepos.vue +3 -1
- package/pages/c/_cluster/uiplugins/CatalogList/CatalogLoadDialog.vue +3 -0
- package/pages/c/_cluster/uiplugins/CatalogList/CatalogUninstallDialog.vue +7 -1
- package/pages/c/_cluster/uiplugins/CatalogList/index.vue +3 -1
- package/pages/c/_cluster/uiplugins/DeveloperInstallDialog.vue +10 -7
- package/pages/c/_cluster/uiplugins/InstallDialog.vue +7 -0
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +181 -106
- package/pages/c/_cluster/uiplugins/SetupUIPlugins.vue +2 -0
- package/pages/c/_cluster/uiplugins/UninstallDialog.vue +9 -1
- package/pages/c/_cluster/uiplugins/index.vue +50 -12
- package/pages/diagnostic.vue +17 -15
- package/pages/home.vue +32 -6
- package/plugins/clean-html.js +50 -0
- package/plugins/dashboard-store/resource-class.js +4 -0
- package/plugins/plugin.js +54 -49
- package/plugins/steve/mutations.js +1 -1
- package/plugins/steve/steve-class.js +8 -0
- package/plugins/steve/steve-pagination-utils.ts +3 -1
- package/rancher-components/Accordion/Accordion.vue +4 -4
- package/rancher-components/BadgeState/BadgeState.vue +7 -0
- package/rancher-components/Card/Card.vue +12 -0
- package/rancher-components/Form/Checkbox/Checkbox.vue +9 -2
- package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +18 -1
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +19 -1
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +39 -2
- package/rancher-components/RcButton/RcButton.vue +90 -0
- package/rancher-components/RcButton/index.ts +2 -0
- package/rancher-components/RcButton/types.ts +17 -0
- package/rancher-components/RcDropdown/RcDropdown.vue +122 -0
- package/rancher-components/RcDropdown/RcDropdownItem.vue +127 -0
- package/rancher-components/RcDropdown/RcDropdownSeparator.vue +6 -0
- package/rancher-components/RcDropdown/RcDropdownTrigger.vue +42 -0
- package/rancher-components/RcDropdown/index.ts +4 -0
- package/rancher-components/RcDropdown/types.ts +22 -0
- package/rancher-components/RcDropdown/useDropdownCollection.ts +46 -0
- package/rancher-components/RcDropdown/useDropdownContext.ts +110 -0
- package/scripts/test-plugins-build.sh +2 -0
- package/scripts/typegen.sh +2 -0
- package/store/catalog.js +1 -1
- package/tsconfig.json +2 -1
- package/types/components/paginatedResourceTable.ts +25 -0
- package/types/components/resourceLabeledSelect.ts +48 -0
- package/types/resources/fleet.d.ts +17 -0
- package/types/shell/index.d.ts +61 -0
- package/utils/auth.js +5 -1
- package/utils/cluster.js +106 -0
- package/utils/fleet.ts +35 -3
- package/utils/ingress.ts +64 -0
- package/utils/uiplugins.ts +56 -44
- package/utils/validators/cron-schedule.js +7 -2
- package/utils/validators/formRules/__tests__/index.test.ts +53 -17
- package/utils/validators/formRules/index.ts +20 -5
- package/vue.config.js +1 -1
- package/components/RelatedWorkloadsTable.vue +0 -50
package/components/SideNav.vue
CHANGED
|
@@ -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
|
-
<
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
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>
|
|
@@ -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 {
|
|
@@ -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
|
-
<
|
|
89
|
-
|
|
90
|
-
|
|
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> </td>
|
|
143
|
+
<td> </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
|
+
|
|
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
|
-
|
|
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
|
|
78
|
+
const summary = this.isClusterView ? [{
|
|
81
79
|
...FLEET_REPO_CLUSTER_SUMMARY,
|
|
82
|
-
formatterOpts: {
|
|
83
|
-
|
|
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
|
|
84
|
+
const state = this.isClusterView ? {
|
|
90
85
|
...FLEET_REPO_PER_CLUSTER_STATE,
|
|
91
|
-
value: (
|
|
92
|
-
|
|
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
|
-
|
|
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.
|
|
389
|
+
{{ item.valueObj.label }}
|
|
390
390
|
</router-link>
|
|
391
391
|
</span>
|
|
392
|
-
<span v-else>{{ item.valueObj.
|
|
392
|
+
<span v-else>{{ item.valueObj.label }}</span>
|
|
393
393
|
</td>
|
|
394
394
|
<!-- state-badge template -->
|
|
395
395
|
<td
|
|
@@ -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);
|