@rancher/shell 3.0.12-rc.5 → 3.0.12-rc.6
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/apis/intf/resources-api/resource-base.ts +42 -2
- package/apis/intf/resources-api/resource-instance.ts +101 -0
- package/apis/intf/resources-api/resources-api.ts +177 -23
- package/apis/intf/resources.ts +8 -6
- package/apis/resources/__tests__/resources-api-class.test.ts +309 -28
- package/apis/resources/resources-api-class.ts +232 -43
- package/assets/images/providers/traefik.png +0 -0
- package/assets/translations/en-us.yaml +10 -4
- package/chart/__tests__/rancher-monitoring-dashboards-index.test.ts +269 -0
- package/chart/rancher-monitoring-dashboards/index.vue +155 -0
- package/cloud-credential/__tests__/generic.test.ts +132 -0
- package/cloud-credential/generic.vue +33 -3
- package/components/EtcdInfoBanner.vue +2 -12
- package/components/GrafanaDashboard.vue +2 -8
- package/components/Resource/Detail/Masthead/__tests__/index.test.ts +68 -14
- package/components/Resource/Detail/Masthead/index.vue +8 -3
- package/components/form/Security.vue +1 -1
- package/components/formatter/Translate.vue +22 -1
- package/components/nav/Group.vue +5 -10
- package/components/nav/TopLevelMenu.vue +1 -30
- package/components/nav/__tests__/Group.test.ts +61 -0
- package/config/labels-annotations.js +1 -0
- package/config/table-headers.js +5 -2
- package/core/__tests__/plugin-products-apply.test.ts +787 -0
- package/core/__tests__/plugin-products-extend.test.ts +189 -0
- package/core/__tests__/plugin-products-helpers.test.ts +81 -78
- package/core/__tests__/plugin-products-new.test.ts +389 -0
- package/core/__tests__/plugin-products-scenarios.test.ts +980 -0
- package/core/__tests__/plugin-products-side-menu.test.ts +1935 -0
- package/core/plugin-products-base.ts +201 -93
- package/core/plugin-products-extending.ts +1 -1
- package/core/plugin-products-external.ts +380 -0
- package/core/plugin-products-helpers.ts +28 -24
- package/core/plugin-products-internal.ts +207 -0
- package/core/plugin-products-top-level.ts +10 -5
- package/core/plugin-products-type-guards.ts +17 -6
- package/core/plugin-products.ts +5 -7
- package/core/plugin-types.ts +1 -389
- package/core/plugin.ts +10 -11
- package/core/types.ts +6 -202
- package/detail/__tests__/provisioning.cattle.io.cluster.test.ts +52 -0
- package/detail/pod.vue +1 -1
- package/detail/provisioning.cattle.io.cluster.vue +0 -2
- package/edit/auth/AuthProviderWarningBanners.vue +12 -0
- package/edit/auth/__tests__/AuthProviderWarningBanners.test.ts +10 -1
- package/edit/auth/__tests__/azuread.test.ts +1 -0
- package/edit/auth/__tests__/github.test.ts +1 -0
- package/edit/auth/__tests__/oidc.test.ts +1 -0
- package/edit/auth/__tests__/saml.test.ts +1 -0
- package/edit/auth/ldap/__tests__/index.test.ts +1 -0
- package/edit/provisioning.cattle.io.cluster/index.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/rke2.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +2 -2
- package/list/management.cattle.io.user.vue +24 -5
- package/list/utils/management.cattle.io.cluster.utils.ts +1 -1
- package/machine-config/__tests__/generic.test.ts +163 -0
- package/machine-config/components/EC2Networking.vue +31 -7
- package/machine-config/components/__tests__/EC2Networking.test.ts +38 -15
- package/machine-config/generic.vue +32 -5
- package/mixins/resource-fetch.js +1 -1
- package/models/__tests__/rke-machine.cattle.io.vmwarevspheremachinetemplate.test.ts +22 -0
- package/models/pod.js +12 -10
- package/models/rke-machine.cattle.io.vmwarevspheremachinetemplate.js +9 -0
- package/package.json +1 -1
- package/pages/auth/login.vue +1 -1
- package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +110 -0
- package/pages/c/_cluster/apps/charts/install.vue +29 -0
- package/pages/c/_cluster/auth/config/index.vue +11 -4
- package/pages/c/_cluster/monitoring/index.vue +6 -1
- package/plugins/dashboard-store/resource-class.js +10 -3
- package/plugins/steve/__tests__/steve-class-resource-api.test.ts +147 -0
- package/plugins/steve/steve-class.js +43 -0
- package/plugins/steve/subscribe.js +11 -0
- package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +115 -0
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +83 -3
- package/store/__tests__/auth.test.ts +18 -0
- package/store/__tests__/notifications.test.ts +466 -1
- package/store/__tests__/ui-context.test.ts +255 -0
- package/store/auth.js +11 -1
- package/store/features.js +1 -0
- package/store/plugins.js +6 -0
- package/types/rancher/steve.api.ts +2 -2
- package/types/shell/index.d.ts +58 -0
- package/types/store/dashboard-store.types.ts +2 -2
- package/types/store/type-map.ts +262 -1
- package/utils/async.ts +2 -0
- package/utils/grafana.js +2 -17
- package/utils/monitoring.js +38 -1
- package/core/__tests__/plugin-products.test.ts +0 -4694
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { mount } from '@vue/test-utils';
|
|
2
2
|
import Masthead from '@shell/components/Resource/Detail/Masthead/index.vue';
|
|
3
|
+
import TitleBar from '@shell/components/Resource/Detail/TitleBar/index.vue';
|
|
4
|
+
import Metadata from '@shell/components/Resource/Detail/Metadata/index.vue';
|
|
3
5
|
import Cards from '@shell/components/Resource/Detail/Cards.vue';
|
|
4
6
|
|
|
5
7
|
jest.mock('@shell/utils/clipboard', () => ({ copyTextToClipboard: jest.fn() }));
|
|
@@ -19,16 +21,18 @@ describe('component: Masthead/index', () => {
|
|
|
19
21
|
metadataProps: { items: [] }
|
|
20
22
|
};
|
|
21
23
|
|
|
24
|
+
const globalStubs = {
|
|
25
|
+
stubs: {
|
|
26
|
+
TitleBar: true,
|
|
27
|
+
Metadata: true,
|
|
28
|
+
Cards: true
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
22
32
|
it('should render the Cards component', () => {
|
|
23
33
|
const wrapper = mount(Masthead, {
|
|
24
34
|
props: defaultProps,
|
|
25
|
-
global:
|
|
26
|
-
stubs: {
|
|
27
|
-
TitleBar: true,
|
|
28
|
-
Metadata: true,
|
|
29
|
-
Cards: true
|
|
30
|
-
}
|
|
31
|
-
}
|
|
35
|
+
global: globalStubs
|
|
32
36
|
});
|
|
33
37
|
|
|
34
38
|
expect(wrapper.findComponent(Cards).exists()).toBe(true);
|
|
@@ -37,17 +41,67 @@ describe('component: Masthead/index', () => {
|
|
|
37
41
|
it('should pass the resource from titleBarProps to Cards', () => {
|
|
38
42
|
const wrapper = mount(Masthead, {
|
|
39
43
|
props: defaultProps,
|
|
40
|
-
global:
|
|
41
|
-
stubs: {
|
|
42
|
-
TitleBar: true,
|
|
43
|
-
Metadata: true,
|
|
44
|
-
Cards: true
|
|
45
|
-
}
|
|
46
|
-
}
|
|
44
|
+
global: globalStubs
|
|
47
45
|
});
|
|
48
46
|
|
|
49
47
|
const cardsComponent = wrapper.findComponent(Cards);
|
|
50
48
|
|
|
51
49
|
expect(cardsComponent.props('resource')).toStrictEqual(mockResource);
|
|
52
50
|
});
|
|
51
|
+
|
|
52
|
+
it('should render TitleBar when titleBarProps is provided', () => {
|
|
53
|
+
const wrapper = mount(Masthead, {
|
|
54
|
+
props: defaultProps,
|
|
55
|
+
global: globalStubs
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
expect(wrapper.findComponent(TitleBar).exists()).toBe(true);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should render Metadata when metadataProps is provided', () => {
|
|
62
|
+
const wrapper = mount(Masthead, {
|
|
63
|
+
props: defaultProps,
|
|
64
|
+
global: globalStubs
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
expect(wrapper.findComponent(Metadata).exists()).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should not render TitleBar when titleBarProps is undefined', () => {
|
|
71
|
+
const wrapper = mount(Masthead, {
|
|
72
|
+
props: { titleBarProps: undefined, metadataProps: { items: [] } },
|
|
73
|
+
global: globalStubs
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
expect(wrapper.findComponent(TitleBar).exists()).toBe(false);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should not render Metadata when metadataProps is undefined', () => {
|
|
80
|
+
const wrapper = mount(Masthead, {
|
|
81
|
+
props: { titleBarProps: defaultProps.titleBarProps, metadataProps: undefined },
|
|
82
|
+
global: globalStubs
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
expect(wrapper.findComponent(Metadata).exists()).toBe(false);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should not render Cards when titleBarProps is undefined', () => {
|
|
89
|
+
const wrapper = mount(Masthead, {
|
|
90
|
+
props: { titleBarProps: undefined, metadataProps: undefined },
|
|
91
|
+
global: globalStubs
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
expect(wrapper.findComponent(Cards).exists()).toBe(false);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should not render any children when both props are undefined', () => {
|
|
98
|
+
const wrapper = mount(Masthead, {
|
|
99
|
+
props: { titleBarProps: undefined, metadataProps: undefined },
|
|
100
|
+
global: globalStubs
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
expect(wrapper.findComponent(TitleBar).exists()).toBe(false);
|
|
104
|
+
expect(wrapper.findComponent(Metadata).exists()).toBe(false);
|
|
105
|
+
expect(wrapper.findComponent(Cards).exists()).toBe(false);
|
|
106
|
+
});
|
|
53
107
|
});
|
|
@@ -4,8 +4,8 @@ import Metadata, { MetadataProps } from '@shell/components/Resource/Detail/Metad
|
|
|
4
4
|
import Cards from '@shell/components/Resource/Detail/Cards.vue';
|
|
5
5
|
|
|
6
6
|
export interface MastheadProps {
|
|
7
|
-
titleBarProps
|
|
8
|
-
metadataProps
|
|
7
|
+
titleBarProps?: TitleBarProps;
|
|
8
|
+
metadataProps?: MetadataProps;
|
|
9
9
|
}
|
|
10
10
|
</script>
|
|
11
11
|
|
|
@@ -15,7 +15,10 @@ const props = defineProps<MastheadProps>();
|
|
|
15
15
|
</script>
|
|
16
16
|
<template>
|
|
17
17
|
<div class="masthead">
|
|
18
|
-
<TitleBar
|
|
18
|
+
<TitleBar
|
|
19
|
+
v-if="props.titleBarProps"
|
|
20
|
+
v-bind="props.titleBarProps"
|
|
21
|
+
>
|
|
19
22
|
<template
|
|
20
23
|
v-if="$slots['additional-actions']"
|
|
21
24
|
#additional-actions
|
|
@@ -24,10 +27,12 @@ const props = defineProps<MastheadProps>();
|
|
|
24
27
|
</template>
|
|
25
28
|
</TitleBar>
|
|
26
29
|
<Metadata
|
|
30
|
+
v-if="props.metadataProps"
|
|
27
31
|
class="metadata-section"
|
|
28
32
|
v-bind="props.metadataProps"
|
|
29
33
|
/>
|
|
30
34
|
<Cards
|
|
35
|
+
v-if="props.titleBarProps"
|
|
31
36
|
class="cards-section"
|
|
32
37
|
:resource="props.titleBarProps.resource"
|
|
33
38
|
/>
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script>
|
|
2
|
+
import { get } from '@shell/utils/object';
|
|
3
|
+
|
|
2
4
|
export default {
|
|
3
5
|
props: {
|
|
4
6
|
row: {
|
|
@@ -6,6 +8,11 @@ export default {
|
|
|
6
8
|
required: true,
|
|
7
9
|
},
|
|
8
10
|
|
|
11
|
+
fallbackPath: {
|
|
12
|
+
type: String,
|
|
13
|
+
default: '',
|
|
14
|
+
},
|
|
15
|
+
|
|
9
16
|
prefix: {
|
|
10
17
|
type: String,
|
|
11
18
|
default: '',
|
|
@@ -18,8 +25,22 @@ export default {
|
|
|
18
25
|
},
|
|
19
26
|
|
|
20
27
|
computed: {
|
|
28
|
+
l10nId() {
|
|
29
|
+
return `${ this.prefix ? `${ this.prefix }.` : '' }${ this.value || this.row.id }`;
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
l10nFallback() {
|
|
33
|
+
const fallback = this.value;
|
|
34
|
+
|
|
35
|
+
if (this.fallbackPath) {
|
|
36
|
+
return get(this.row, this.fallbackPath) || fallback;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return fallback;
|
|
40
|
+
},
|
|
41
|
+
|
|
21
42
|
text() {
|
|
22
|
-
return this.$store.getters['i18n/withFallback'](
|
|
43
|
+
return this.$store.getters['i18n/withFallback'](this.l10nId, null, this.l10nFallback);
|
|
23
44
|
},
|
|
24
45
|
},
|
|
25
46
|
};
|
package/components/nav/Group.vue
CHANGED
|
@@ -384,14 +384,12 @@ export default {
|
|
|
384
384
|
user-select: none;
|
|
385
385
|
text-transform: none;
|
|
386
386
|
font-size: 14px;
|
|
387
|
+
height: 100%;
|
|
388
|
+
padding: 8px 0 8px 16px;
|
|
389
|
+
display: inline-flex;
|
|
390
|
+
align-items: center;
|
|
387
391
|
}
|
|
388
392
|
|
|
389
|
-
> H6 {
|
|
390
|
-
text-transform: none;
|
|
391
|
-
height: 100%;
|
|
392
|
-
padding: 8px 0 8px 16px;
|
|
393
|
-
}
|
|
394
|
-
|
|
395
393
|
> A {
|
|
396
394
|
display: block;
|
|
397
395
|
box-sizing:border-box;
|
|
@@ -403,10 +401,6 @@ export default {
|
|
|
403
401
|
&:focus{
|
|
404
402
|
outline:none;
|
|
405
403
|
}
|
|
406
|
-
> H6 {
|
|
407
|
-
text-transform: none;
|
|
408
|
-
padding: 8px 0 8px 16px;
|
|
409
|
-
}
|
|
410
404
|
}
|
|
411
405
|
}
|
|
412
406
|
|
|
@@ -574,6 +568,7 @@ export default {
|
|
|
574
568
|
padding-left: 24px;
|
|
575
569
|
display: flex;
|
|
576
570
|
justify-content: space-between;
|
|
571
|
+
align-items: center;
|
|
577
572
|
}
|
|
578
573
|
|
|
579
574
|
A:focus {
|
|
@@ -955,19 +955,6 @@ export default {
|
|
|
955
955
|
<div
|
|
956
956
|
class="footer"
|
|
957
957
|
>
|
|
958
|
-
<div
|
|
959
|
-
v-if="canEditSettings"
|
|
960
|
-
class="support"
|
|
961
|
-
@click="hide()"
|
|
962
|
-
>
|
|
963
|
-
<router-link
|
|
964
|
-
:to="{name: 'support'}"
|
|
965
|
-
role="link"
|
|
966
|
-
:aria-label="t('nav.ariaLabel.support')"
|
|
967
|
-
>
|
|
968
|
-
{{ t('nav.support', {hasSupport}) }}
|
|
969
|
-
</router-link>
|
|
970
|
-
</div>
|
|
971
958
|
<div
|
|
972
959
|
class="version"
|
|
973
960
|
:class="{'version-small': largeAboutText}"
|
|
@@ -1574,10 +1561,6 @@ export default {
|
|
|
1574
1561
|
margin: 20px 10px;
|
|
1575
1562
|
width: 50px;
|
|
1576
1563
|
|
|
1577
|
-
.support {
|
|
1578
|
-
display: none;
|
|
1579
|
-
}
|
|
1580
|
-
|
|
1581
1564
|
.version{
|
|
1582
1565
|
text-align: center;
|
|
1583
1566
|
|
|
@@ -1597,19 +1580,7 @@ export default {
|
|
|
1597
1580
|
> * {
|
|
1598
1581
|
flex: 1;
|
|
1599
1582
|
color: var(--link);
|
|
1600
|
-
|
|
1601
|
-
&:first-child {
|
|
1602
|
-
text-align: left;
|
|
1603
|
-
}
|
|
1604
|
-
&:last-child {
|
|
1605
|
-
text-align: right;
|
|
1606
|
-
}
|
|
1607
|
-
text-align: center;
|
|
1608
|
-
}
|
|
1609
|
-
|
|
1610
|
-
.support a:focus-visible {
|
|
1611
|
-
@include focus-outline;
|
|
1612
|
-
outline-offset: 4px;
|
|
1583
|
+
text-align: left;
|
|
1613
1584
|
}
|
|
1614
1585
|
|
|
1615
1586
|
.version {
|
|
@@ -64,4 +64,65 @@ describe('component: Group', () => {
|
|
|
64
64
|
|
|
65
65
|
expect((wrapper.vm as any).hasActiveRoute()).toBe(true);
|
|
66
66
|
});
|
|
67
|
+
|
|
68
|
+
describe('group header label', () => {
|
|
69
|
+
const mountGroup = (group: any) => shallowMount(Group as any, {
|
|
70
|
+
props: {
|
|
71
|
+
group, canCollapse: true, idPrefix: ''
|
|
72
|
+
},
|
|
73
|
+
global: {
|
|
74
|
+
stubs: { 'router-link': { template: '<a><slot /></a>' } },
|
|
75
|
+
mocks: {
|
|
76
|
+
$route: {
|
|
77
|
+
params: {}, path: '/test/route', fullPath: '/test/route', matched: []
|
|
78
|
+
},
|
|
79
|
+
$router: {
|
|
80
|
+
resolve: jest.fn().mockReturnValue({ path: '/test/route', fullPath: '/test/route' }),
|
|
81
|
+
getRoutes: jest.fn().mockReturnValue([])
|
|
82
|
+
},
|
|
83
|
+
t: (key: string) => key
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('renders the label in an h6 for a non-linked group header', () => {
|
|
89
|
+
const group = {
|
|
90
|
+
name: 'test',
|
|
91
|
+
label: 'My Group',
|
|
92
|
+
children: [
|
|
93
|
+
{ route: { name: 'child-route', params: {} } }
|
|
94
|
+
]
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const wrapper = mountGroup(group);
|
|
98
|
+
const header = wrapper.find('.header');
|
|
99
|
+
const h6 = header.find('h6');
|
|
100
|
+
|
|
101
|
+
// Non-linked header: the label sits in a bare h6, not wrapped in a router-link
|
|
102
|
+
expect(header.find('a').exists()).toBe(false);
|
|
103
|
+
expect(h6.exists()).toBe(true);
|
|
104
|
+
expect(h6.find('span').html()).toContain('My Group');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('renders the label in an h6 wrapped in a router-link for a group header with overview', () => {
|
|
108
|
+
const group = {
|
|
109
|
+
name: 'test',
|
|
110
|
+
label: 'My Group',
|
|
111
|
+
children: [
|
|
112
|
+
{
|
|
113
|
+
route: { name: 'overview-route' }, overview: true, exact: true
|
|
114
|
+
}
|
|
115
|
+
]
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const wrapper = mountGroup(group);
|
|
119
|
+
const link = wrapper.find('.header a');
|
|
120
|
+
const h6 = link.find('h6');
|
|
121
|
+
|
|
122
|
+
// Linked header: the same h6 label markup is wrapped in a router-link
|
|
123
|
+
expect(link.exists()).toBe(true);
|
|
124
|
+
expect(h6.exists()).toBe(true);
|
|
125
|
+
expect(h6.find('span').html()).toContain('My Group');
|
|
126
|
+
});
|
|
127
|
+
});
|
|
67
128
|
});
|
|
@@ -20,6 +20,7 @@ export const IMPORTED_CLUSTER_VERSION_MANAGEMENT = 'rancher.io/imported-cluster-
|
|
|
20
20
|
export const UI_PROJECT_SECRET = 'management.cattle.io/project-scoped-secret';
|
|
21
21
|
export const UI_PROJECT_SECRET_COPY = 'management.cattle.io/project-scoped-secret-copy';
|
|
22
22
|
export const SERVICE_LINKS = 'ui.rancher/service-links';
|
|
23
|
+
export const NODE_DRIVER_FIELD_HINTS = 'io.cattle.nodedriver/ui-field-hints';
|
|
23
24
|
|
|
24
25
|
export const KUBERNETES = {
|
|
25
26
|
SERVICE_ACCOUNT_UID: 'kubernetes.io/service-account.uid',
|
package/config/table-headers.js
CHANGED
|
@@ -1072,11 +1072,14 @@ export const ROLE = {
|
|
|
1072
1072
|
export const FEATURE_DESCRIPTION = {
|
|
1073
1073
|
name: 'description',
|
|
1074
1074
|
labelKey: 'tableHeaders.description',
|
|
1075
|
-
value: '
|
|
1075
|
+
value: 'id',
|
|
1076
1076
|
align: 'left',
|
|
1077
1077
|
sort: ['status.description'],
|
|
1078
1078
|
formatter: 'Translate',
|
|
1079
|
-
formatterOpts: {
|
|
1079
|
+
formatterOpts: {
|
|
1080
|
+
prefix: 'featureFlags.description',
|
|
1081
|
+
fallbackPath: 'status.description'
|
|
1082
|
+
},
|
|
1080
1083
|
};
|
|
1081
1084
|
|
|
1082
1085
|
export const STATE_NORMAN = {
|