@rancher/shell 3.0.9-rc.6 → 3.0.10
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/_color.scss +4 -0
- package/assets/styles/themes/_light.scss +6 -6
- package/assets/styles/themes/_modern.scss +14 -6
- package/assets/translations/en-us.yaml +2 -5
- package/components/CopyToClipboard.vue +28 -0
- package/components/CopyToClipboardText.vue +4 -0
- package/components/CruResource.vue +1 -0
- package/components/GlobalRoleBindings.vue +1 -5
- package/components/IconOrSvg.vue +61 -42
- package/components/ResourceDetail/index.vue +0 -21
- package/components/SortableTable/index.vue +2 -2
- package/components/__tests__/CruResource.test.ts +35 -1
- package/components/form/BannerSettings.vue +2 -2
- package/components/form/NotificationSettings.vue +2 -2
- package/composables/useIsNewDetailPageEnabled.test.ts +98 -0
- package/composables/useIsNewDetailPageEnabled.ts +12 -0
- package/config/product/explorer.js +11 -1
- package/config/product/manager.js +0 -1
- package/config/table-headers.js +0 -9
- package/config/types.js +0 -1
- package/detail/fleet.cattle.io.cluster.vue +1 -1
- package/dialog/FeatureFlagListDialog.vue +1 -1
- package/edit/auth/github-app-steps.vue +2 -0
- package/edit/auth/github-steps.vue +2 -0
- package/edit/catalog.cattle.io.clusterrepo.vue +1 -1
- package/edit/management.cattle.io.user.vue +60 -35
- package/edit/monitoring.coreos.com.alertmanagerconfig/__tests__/auth.spec.ts +145 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/__tests__/index.test.ts +202 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/__tests__/tls.spec.ts +226 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/auth.vue +24 -21
- package/edit/monitoring.coreos.com.alertmanagerconfig/types/__tests__/opsgenie.spec.ts +157 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/types/__tests__/pagerduty.spec.ts +132 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/types/__tests__/slack.spec.ts +108 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/types/pagerduty.vue +2 -1
- package/edit/monitoring.coreos.com.receiver/__tests__/auth.spec.ts +165 -0
- package/edit/monitoring.coreos.com.receiver/__tests__/index.test.ts +153 -0
- package/edit/monitoring.coreos.com.receiver/__tests__/tls.spec.ts +115 -0
- package/edit/monitoring.coreos.com.receiver/types/__tests__/email.spec.ts +86 -0
- package/edit/monitoring.coreos.com.receiver/types/__tests__/opsgenie.spec.ts +209 -0
- package/edit/monitoring.coreos.com.receiver/types/__tests__/pagerduty.spec.ts +105 -0
- package/edit/monitoring.coreos.com.receiver/types/__tests__/slack.spec.ts +92 -0
- package/edit/monitoring.coreos.com.receiver/types/__tests__/webhook.spec.ts +131 -0
- package/edit/provisioning.cattle.io.cluster/ingress/IngressCards.vue +14 -12
- package/edit/provisioning.cattle.io.cluster/rke2.vue +4 -5
- package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +18 -3
- package/edit/provisioning.cattle.io.cluster/tabs/Ingress.vue +100 -76
- package/edit/token.vue +29 -68
- package/list/provisioning.cattle.io.cluster.vue +2 -2
- package/models/__tests__/chart.test.ts +2 -2
- package/models/chart.js +3 -3
- package/models/token.js +0 -4
- package/package.json +8 -8
- package/pages/account/index.vue +67 -96
- package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +108 -24
- package/pages/c/_cluster/apps/charts/index.vue +1 -11
- package/pages/c/_cluster/explorer/index.vue +2 -19
- package/pages/c/_cluster/explorer/tools/index.vue +1 -1
- package/pages/c/_cluster/manager/cloudCredential/index.vue +1 -1
- package/pages/c/_cluster/uiplugins/index.vue +1 -1
- package/pkg/auto-import.js +41 -0
- package/plugins/dashboard-store/resource-class.js +2 -2
- package/plugins/steve/__tests__/steve-class.test.ts +1 -1
- package/plugins/steve/steve-class.js +3 -3
- package/plugins/steve/steve-pagination-utils.ts +2 -4
- package/rancher-components/Pill/RcCounterBadge/RcCounterBadge.vue +7 -7
- package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.vue +5 -2
- package/rancher-components/RcIcon/types.ts +2 -2
- package/rancher-components/RcItemCard/RcItemCard.vue +8 -1
- package/rancher-components/RcSection/RcSection.test.ts +323 -0
- package/rancher-components/RcSection/RcSection.vue +252 -0
- package/rancher-components/RcSection/RcSectionActions.test.ts +212 -0
- package/rancher-components/RcSection/RcSectionActions.vue +85 -0
- package/rancher-components/RcSection/RcSectionBadges.test.ts +149 -0
- package/rancher-components/RcSection/RcSectionBadges.vue +29 -0
- package/rancher-components/RcSection/index.ts +12 -0
- package/rancher-components/RcSection/types.ts +86 -0
- package/scripts/test-plugins-build.sh +5 -4
- package/types/shell/index.d.ts +93 -108
- package/utils/style.ts +17 -0
- package/utils/svg-filter.js +4 -3
- package/utils/units.js +14 -5
- package/models/ext.cattle.io.token.js +0 -48
|
@@ -571,17 +571,17 @@
|
|
|
571
571
|
--rc-success: #{$green001};
|
|
572
572
|
--rc-success-secondary: #{$green002};
|
|
573
573
|
|
|
574
|
-
--rc-warning: #{$
|
|
575
|
-
--rc-warning-secondary: #{$
|
|
574
|
+
--rc-warning: #{$yellow002};
|
|
575
|
+
--rc-warning-secondary: #{$yellow001};
|
|
576
576
|
|
|
577
577
|
--rc-error: #{$red001};
|
|
578
578
|
--rc-error-secondary: #{$red002};
|
|
579
579
|
|
|
580
|
-
--rc-unknown: #{$
|
|
581
|
-
--rc-unknown-secondary: #{$
|
|
580
|
+
--rc-unknown: #{$gray004};
|
|
581
|
+
--rc-unknown-secondary: #{$gray001};
|
|
582
582
|
|
|
583
|
-
--rc-none: #{$
|
|
584
|
-
--rc-none-secondary: #{$
|
|
583
|
+
--rc-none: #{$gray004};
|
|
584
|
+
--rc-none-secondary: #{$gray002};
|
|
585
585
|
|
|
586
586
|
--rc-primary-hover: #{$blue003};
|
|
587
587
|
|
|
@@ -701,17 +701,17 @@ BODY, .theme-light {
|
|
|
701
701
|
--rc-success: #{$green001};
|
|
702
702
|
--rc-success-secondary: #{$green002};
|
|
703
703
|
|
|
704
|
-
--rc-warning: #{$
|
|
705
|
-
--rc-warning-secondary: #{$
|
|
704
|
+
--rc-warning: #{$yellow002};
|
|
705
|
+
--rc-warning-secondary: #{$yellow001};
|
|
706
706
|
|
|
707
707
|
--rc-error: #{$red001};
|
|
708
708
|
--rc-error-secondary: #{$red002};
|
|
709
709
|
|
|
710
|
-
--rc-unknown: #{$
|
|
711
|
-
--rc-unknown-secondary: #{$
|
|
710
|
+
--rc-unknown: #{$gray004};
|
|
711
|
+
--rc-unknown-secondary: #{$gray001};
|
|
712
712
|
|
|
713
|
-
--rc-none: #{$
|
|
714
|
-
--rc-none-secondary: #{$
|
|
713
|
+
--rc-none: #{$gray004};
|
|
714
|
+
--rc-none-secondary: #{$gray002};
|
|
715
715
|
|
|
716
716
|
--rc-primary-hover: #{$blue003};
|
|
717
717
|
|
|
@@ -724,6 +724,10 @@ BODY, .theme-light {
|
|
|
724
724
|
--rc-disabled-background: #{$gray001};
|
|
725
725
|
--rc-disabled-text-color: #{$gray004};
|
|
726
726
|
|
|
727
|
+
--rc-section-background-primary: #{$lightest};
|
|
728
|
+
--rc-section-background-secondary: #{$lighter};
|
|
729
|
+
--rc-section-action-color: #{$gray009};
|
|
730
|
+
|
|
727
731
|
--rc-image-bg: #{$lightest};
|
|
728
732
|
--rc-image-color: #{$darkest};
|
|
729
733
|
|
|
@@ -1068,6 +1072,10 @@ BODY, .theme-dark {
|
|
|
1068
1072
|
--rc-disabled-background: #{$gray005};
|
|
1069
1073
|
--rc-disabled-text-color: #{$gray004};
|
|
1070
1074
|
|
|
1075
|
+
--rc-section-background-primary: #{$gray007};
|
|
1076
|
+
--rc-section-background-secondary: #{$gray008};
|
|
1077
|
+
--rc-section-action-color: #{$gray010};
|
|
1078
|
+
|
|
1071
1079
|
--rc-image-bg: #{$lightest};
|
|
1072
1080
|
--rc-image-color: #{$darkest};
|
|
1073
1081
|
|
|
@@ -30,6 +30,7 @@ generic:
|
|
|
30
30
|
comma: ', '
|
|
31
31
|
copy: Copy
|
|
32
32
|
copyToClipboard: Copy text to Clipboard
|
|
33
|
+
copyValueToClipboard: 'Copy {value} to Clipboard'
|
|
33
34
|
copiedToClipboard: Text copied to Clipboard
|
|
34
35
|
create: Create
|
|
35
36
|
created: Created
|
|
@@ -438,7 +439,6 @@ accountAndKeys:
|
|
|
438
439
|
notAllowed: You do not have permission to manage API Keys
|
|
439
440
|
apiEndpoint: "API Endpoint:"
|
|
440
441
|
copyApiEnpoint: Copy API Endpoint to clipboard
|
|
441
|
-
normanTokenDeprecation: The API Keys feature is being migrated to a new API. Any existing API Keys from the legacy API will continue to work, but new API Keys will be created using the new API.
|
|
442
442
|
add:
|
|
443
443
|
description:
|
|
444
444
|
label: Description
|
|
@@ -464,9 +464,7 @@ accountAndKeys:
|
|
|
464
464
|
month: Months
|
|
465
465
|
year: Years
|
|
466
466
|
scope: Scope
|
|
467
|
-
userPrincipal: User Principal
|
|
468
467
|
noScope: No Scope
|
|
469
|
-
enabled: Token enabled
|
|
470
468
|
info:
|
|
471
469
|
accessKey: Access Key
|
|
472
470
|
secretKey: Secret Key
|
|
@@ -475,7 +473,7 @@ accountAndKeys:
|
|
|
475
473
|
keyCreated: A new API Key has been created
|
|
476
474
|
bearerTokenTip: "Access Key and Secret Key can be sent as the username and password for HTTP Basic auth to authorize requests. You can also combine them to use as a Bearer token:"
|
|
477
475
|
ttlLimitedWarning: The Expiry time for this API Key was reduced due to system configuration
|
|
478
|
-
|
|
476
|
+
|
|
479
477
|
addClusterMemberDialog:
|
|
480
478
|
title: Add Cluster Member
|
|
481
479
|
|
|
@@ -6857,7 +6855,6 @@ storageClass:
|
|
|
6857
6855
|
tooltip: By default the default storage class on the host Harvester cluster is used.
|
|
6858
6856
|
|
|
6859
6857
|
tableHeaders:
|
|
6860
|
-
isLegacy: Legacy
|
|
6861
6858
|
assuredConcurrencyShares: Assured Concurrency Shares
|
|
6862
6859
|
autoscaler: Autoscaler
|
|
6863
6860
|
accessKey: Access Key
|
|
@@ -38,7 +38,35 @@ export default {
|
|
|
38
38
|
success-label="Copied!"
|
|
39
39
|
error-label="Error Copying"
|
|
40
40
|
v-bind="$attrs"
|
|
41
|
+
:success-color="$attrs['action-color'] || 'role-primary'"
|
|
42
|
+
:waiting-color="$attrs['action-color'] || 'role-primary'"
|
|
41
43
|
:delay="2000"
|
|
42
44
|
@click="clicked"
|
|
43
45
|
/>
|
|
44
46
|
</template>
|
|
47
|
+
|
|
48
|
+
<style lang="scss" scoped>
|
|
49
|
+
.icon-btn {
|
|
50
|
+
min-height: 24px;
|
|
51
|
+
min-width: 24px;
|
|
52
|
+
justify-content: center;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.bg-transparent {
|
|
56
|
+
&:active {
|
|
57
|
+
background-color: var(--primary-keyboard-focus);
|
|
58
|
+
color: var(--primary-text);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
&:focus-visible {
|
|
62
|
+
@include focus-outline;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.role-primary {
|
|
67
|
+
&:active {
|
|
68
|
+
background-color: var(--primary-keyboard-focus);
|
|
69
|
+
color: var(--primary-text);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
</style>
|
|
@@ -49,10 +49,6 @@ export default {
|
|
|
49
49
|
userId: {
|
|
50
50
|
type: String,
|
|
51
51
|
default: ''
|
|
52
|
-
},
|
|
53
|
-
watchOverride: {
|
|
54
|
-
type: Boolean,
|
|
55
|
-
default: true,
|
|
56
52
|
}
|
|
57
53
|
},
|
|
58
54
|
async fetch() {
|
|
@@ -142,7 +138,7 @@ export default {
|
|
|
142
138
|
this.update();
|
|
143
139
|
},
|
|
144
140
|
userId(userId, oldUserId) {
|
|
145
|
-
if (userId === oldUserId
|
|
141
|
+
if (userId === oldUserId) {
|
|
146
142
|
return;
|
|
147
143
|
}
|
|
148
144
|
this.update();
|
package/components/IconOrSvg.vue
CHANGED
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
*/
|
|
19
19
|
import { Solver } from '@shell/utils/svg-filter';
|
|
20
20
|
import { colorToRgb, mapStandardColors, normalizeHex } from '@shell/utils/color';
|
|
21
|
+
import { mapGetters } from 'vuex';
|
|
21
22
|
|
|
22
23
|
const filterCache = {};
|
|
23
|
-
const cssCache = {};
|
|
24
24
|
|
|
25
25
|
const colors = {
|
|
26
26
|
header: {
|
|
@@ -33,7 +33,7 @@ const colors = {
|
|
|
33
33
|
},
|
|
34
34
|
primary: {
|
|
35
35
|
color: '--on-tertiary',
|
|
36
|
-
hover: '--
|
|
36
|
+
hover: '--tertiary-hover-app-bar',
|
|
37
37
|
colorFallback: '--on-tertiary',
|
|
38
38
|
hoverFallback: '--primary-hover-text',
|
|
39
39
|
active: '--on-active',
|
|
@@ -63,7 +63,12 @@ export default {
|
|
|
63
63
|
},
|
|
64
64
|
|
|
65
65
|
data() {
|
|
66
|
-
return {
|
|
66
|
+
return {
|
|
67
|
+
className: '',
|
|
68
|
+
mainFilter: null,
|
|
69
|
+
hoverFilter: null,
|
|
70
|
+
activeFilter: null,
|
|
71
|
+
};
|
|
67
72
|
},
|
|
68
73
|
|
|
69
74
|
created() {
|
|
@@ -72,6 +77,18 @@ export default {
|
|
|
72
77
|
}
|
|
73
78
|
},
|
|
74
79
|
|
|
80
|
+
computed: {
|
|
81
|
+
...mapGetters({
|
|
82
|
+
brand: 'management/brand',
|
|
83
|
+
theme: 'prefs/theme',
|
|
84
|
+
})
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
watch: {
|
|
88
|
+
brand: 'recomputeColor',
|
|
89
|
+
theme: 'recomputeColor',
|
|
90
|
+
},
|
|
91
|
+
|
|
75
92
|
methods: {
|
|
76
93
|
getComputedStyleFor(cssVar, fallback) {
|
|
77
94
|
const value = window.getComputedStyle(document.body).getPropertyValue(cssVar).trim();
|
|
@@ -86,11 +103,11 @@ export default {
|
|
|
86
103
|
|
|
87
104
|
const solver = new Solver(rgb);
|
|
88
105
|
const res = solver.solve();
|
|
89
|
-
const
|
|
106
|
+
const filterVal = res?.filterVal;
|
|
90
107
|
|
|
91
|
-
filterCache[cacheKey] =
|
|
108
|
+
filterCache[cacheKey] = filterVal;
|
|
92
109
|
|
|
93
|
-
return
|
|
110
|
+
return filterVal;
|
|
94
111
|
},
|
|
95
112
|
|
|
96
113
|
setColor() {
|
|
@@ -111,43 +128,23 @@ export default {
|
|
|
111
128
|
|
|
112
129
|
const className = `svg-icon-${ uiColorStr }-${ hoverColorStr }`;
|
|
113
130
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const activeFilter = this.resolveColorFilter(activeColor, activeColorRGB);
|
|
118
|
-
|
|
119
|
-
// Add stylesheet (added as global styles)
|
|
120
|
-
const styles = `
|
|
121
|
-
img.${ className } {
|
|
122
|
-
${ mainFilter };
|
|
123
|
-
}
|
|
124
|
-
img.${ className }:hover {
|
|
125
|
-
${ hoverFilter };
|
|
126
|
-
}
|
|
127
|
-
button:hover > img.${ className } {
|
|
128
|
-
${ hoverFilter };
|
|
129
|
-
}
|
|
130
|
-
li:hover > img.${ className } {
|
|
131
|
-
${ hoverFilter };
|
|
132
|
-
}
|
|
133
|
-
a.option:hover > img.${ className } {
|
|
134
|
-
${ hoverFilter };
|
|
135
|
-
}
|
|
136
|
-
a.option.active-menu-link > img.${ className } {
|
|
137
|
-
${ activeFilter };
|
|
138
|
-
}
|
|
139
|
-
`;
|
|
140
|
-
|
|
141
|
-
const styleSheet = document.createElement('style');
|
|
142
|
-
|
|
143
|
-
styleSheet.innerText = styles;
|
|
144
|
-
document.head.appendChild(styleSheet);
|
|
145
|
-
|
|
146
|
-
cssCache[className] = true;
|
|
147
|
-
}
|
|
131
|
+
this.hoverFilter = this.resolveColorFilter(hoverColor, hoverColorRGB);
|
|
132
|
+
this.mainFilter = this.resolveColorFilter(uiColor, uiColorRGB);
|
|
133
|
+
this.activeFilter = this.resolveColorFilter(activeColor, activeColorRGB);
|
|
148
134
|
|
|
149
135
|
this['className'] = className;
|
|
150
|
-
}
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
recomputeColor() {
|
|
139
|
+
if (!this.src) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
this.mainFilter = null;
|
|
144
|
+
this.hoverFilter = null;
|
|
145
|
+
this.activeFilter = null;
|
|
146
|
+
this.setColor();
|
|
147
|
+
},
|
|
151
148
|
}
|
|
152
149
|
};
|
|
153
150
|
</script>
|
|
@@ -172,8 +169,30 @@ export default {
|
|
|
172
169
|
</template>
|
|
173
170
|
|
|
174
171
|
<style lang="scss" scoped>
|
|
175
|
-
.svg-icon {
|
|
172
|
+
img.svg-icon {
|
|
173
|
+
filter: v-bind(mainFilter);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
button:hover > img.svg-icon,
|
|
177
|
+
li:hover > img.svg-icon {
|
|
178
|
+
filter: v-bind(hoverFilter);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.side-menu .category div a > img.svg-icon {
|
|
176
182
|
height: 24px;
|
|
177
183
|
width: 24px;
|
|
184
|
+
filter: v-bind(mainFilter);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.side-menu .category div a:hover > img.svg-icon {
|
|
188
|
+
filter: v-bind(hoverFilter);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.side-menu .category div a.active-menu-link > img.svg-icon {
|
|
192
|
+
filter: v-bind(activeFilter);
|
|
193
|
+
|
|
194
|
+
&:hover {
|
|
195
|
+
filter: v-bind(activeFilter);
|
|
196
|
+
}
|
|
178
197
|
}
|
|
179
198
|
</style>
|
|
@@ -403,25 +403,6 @@ export default {
|
|
|
403
403
|
// Remove id? How does subtype get in (cluster/node)
|
|
404
404
|
this.detailComponent = this.$store.getters['type-map/importDetail'](detailResource, id);
|
|
405
405
|
this.editComponent = this.$store.getters['type-map/importEdit'](editResource, id);
|
|
406
|
-
},
|
|
407
|
-
/**
|
|
408
|
-
* Sets the mode and initializes the resource components.
|
|
409
|
-
*
|
|
410
|
-
* This method sets the mode of the component and configures the resource
|
|
411
|
-
* components based on the provided user and resource.
|
|
412
|
-
*
|
|
413
|
-
* @param {Object} payload - An object containing the mode, user, and
|
|
414
|
-
* resource properties.
|
|
415
|
-
* @param {string} payload.mode - The mode to set.
|
|
416
|
-
* @param {Object} payload.user - The user object containing user-specific
|
|
417
|
-
* information.
|
|
418
|
-
* @param {string} payload.resource - The resource string to use for
|
|
419
|
-
* initialization.
|
|
420
|
-
*/
|
|
421
|
-
setMode({ mode, userId, resource }) {
|
|
422
|
-
this.mode = mode;
|
|
423
|
-
this.value.id = userId;
|
|
424
|
-
this.configureResource(userId, resource);
|
|
425
406
|
}
|
|
426
407
|
}
|
|
427
408
|
};
|
|
@@ -444,7 +425,6 @@ export default {
|
|
|
444
425
|
:class="{'flex-content': flexContent}"
|
|
445
426
|
:resource-errors="errors"
|
|
446
427
|
@update:value="$emit('input', $event)"
|
|
447
|
-
@update:mode="setMode"
|
|
448
428
|
@set-subtype="setSubtype"
|
|
449
429
|
/>
|
|
450
430
|
<div v-else>
|
|
@@ -514,7 +494,6 @@ export default {
|
|
|
514
494
|
:real-mode="realMode"
|
|
515
495
|
:class="{'flex-content': flexContent}"
|
|
516
496
|
@update:value="$emit('input', $event)"
|
|
517
|
-
@update:mode="setMode"
|
|
518
497
|
@set-subtype="setSubtype"
|
|
519
498
|
/>
|
|
520
499
|
|
|
@@ -2099,13 +2099,13 @@ export default {
|
|
|
2099
2099
|
|
|
2100
2100
|
$header-padding: 20px;
|
|
2101
2101
|
.sub-header-row {
|
|
2102
|
-
padding: 0 0 $header-padding / 2 0;
|
|
2102
|
+
padding: 0 0 calc($header-padding / 2) 0;
|
|
2103
2103
|
}
|
|
2104
2104
|
|
|
2105
2105
|
.fixed-header-actions {
|
|
2106
2106
|
padding: 0 0 $header-padding 0;
|
|
2107
2107
|
&.with-sub-header {
|
|
2108
|
-
padding: 0 0 $header-padding / 4 0;
|
|
2108
|
+
padding: 0 0 calc($header-padding / 4) 0;
|
|
2109
2109
|
}
|
|
2110
2110
|
|
|
2111
2111
|
width: 100%;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { mount } from '@vue/test-utils';
|
|
2
2
|
import CruResource from '@shell/components/CruResource.vue';
|
|
3
|
-
import { _EDIT, _YAML } from '@shell/config/query-params';
|
|
3
|
+
import { _CREATE, _EDIT, _VIEW, _YAML } from '@shell/config/query-params';
|
|
4
4
|
import TextAreaAutoGrow from '@components/Form/TextArea/TextAreaAutoGrow.vue';
|
|
5
5
|
|
|
6
6
|
describe('component: CruResource', () => {
|
|
@@ -171,6 +171,40 @@ describe('component: CruResource', () => {
|
|
|
171
171
|
expect(event.preventDefault).toHaveBeenCalledWith();
|
|
172
172
|
});
|
|
173
173
|
|
|
174
|
+
it.each([
|
|
175
|
+
[_EDIT, true],
|
|
176
|
+
[_CREATE, true],
|
|
177
|
+
[_VIEW, false],
|
|
178
|
+
])('should render CruResourceFooter when mode is %s: %s', (mode: string, shouldRender: boolean) => {
|
|
179
|
+
const wrapper = mount(CruResource, {
|
|
180
|
+
props: {
|
|
181
|
+
canYaml: false,
|
|
182
|
+
mode,
|
|
183
|
+
resource: {}
|
|
184
|
+
},
|
|
185
|
+
global: {
|
|
186
|
+
mocks: {
|
|
187
|
+
$store: {
|
|
188
|
+
getters: {
|
|
189
|
+
currentStore: () => 'current_store',
|
|
190
|
+
'current_store/schemaFor': jest.fn(),
|
|
191
|
+
'current_store/all': jest.fn(),
|
|
192
|
+
'i18n/t': jest.fn(),
|
|
193
|
+
'i18n/exists': jest.fn(),
|
|
194
|
+
},
|
|
195
|
+
dispatch: jest.fn(),
|
|
196
|
+
},
|
|
197
|
+
$route: { query: { AS: _YAML } },
|
|
198
|
+
$router: { applyQuery: jest.fn() },
|
|
199
|
+
},
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
const footer = wrapper.find('.cru-resource-footer');
|
|
204
|
+
|
|
205
|
+
expect(footer.exists()).toBe(shouldRender);
|
|
206
|
+
});
|
|
207
|
+
|
|
174
208
|
it('should not prevent default events on keypress Enter', async() => {
|
|
175
209
|
const event = { preventDefault: jest.fn() };
|
|
176
210
|
const wrapper = mount(CruResource, {
|
|
@@ -9,7 +9,7 @@ import { ToggleSwitch } from '@components/Form/ToggleSwitch';
|
|
|
9
9
|
import { TextAreaAutoGrow } from '@components/Form/TextArea';
|
|
10
10
|
import { Banner } from '@components/Banner';
|
|
11
11
|
|
|
12
|
-
export default
|
|
12
|
+
export default {
|
|
13
13
|
name: 'BannerSettings',
|
|
14
14
|
|
|
15
15
|
props: {
|
|
@@ -112,7 +112,7 @@ export default ({
|
|
|
112
112
|
return this.bannerType === 'bannerConsent';
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
|
-
}
|
|
115
|
+
};
|
|
116
116
|
</script>
|
|
117
117
|
|
|
118
118
|
<template>
|
|
@@ -3,7 +3,7 @@ import { LabeledInput } from '@components/Form/LabeledInput';
|
|
|
3
3
|
import { Checkbox } from '@components/Form/Checkbox';
|
|
4
4
|
import { _EDIT, _VIEW } from '@shell/config/query-params';
|
|
5
5
|
|
|
6
|
-
export default
|
|
6
|
+
export default {
|
|
7
7
|
|
|
8
8
|
name: 'NotificationSettings',
|
|
9
9
|
|
|
@@ -29,7 +29,7 @@ export default ({
|
|
|
29
29
|
},
|
|
30
30
|
},
|
|
31
31
|
|
|
32
|
-
}
|
|
32
|
+
};
|
|
33
33
|
</script>
|
|
34
34
|
|
|
35
35
|
<template>
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { useIsNewDetailPageEnabled } from '@shell/composables/useIsNewDetailPageEnabled';
|
|
2
|
+
|
|
3
|
+
const mockStore: any = { getters: {} };
|
|
4
|
+
const mockRoute: any = { query: {} };
|
|
5
|
+
|
|
6
|
+
jest.mock('vuex', () => ({ useStore: () => mockStore }));
|
|
7
|
+
jest.mock('vue-router', () => ({ useRoute: () => mockRoute }));
|
|
8
|
+
|
|
9
|
+
const mockGetVersionInfo = jest.fn(() => ({ fullVersion: '2.12.0' }));
|
|
10
|
+
|
|
11
|
+
jest.mock('@shell/utils/version', () => ({ getVersionInfo: (...args: any[]) => mockGetVersionInfo(...args) }));
|
|
12
|
+
|
|
13
|
+
describe('useIsNewDetailPageEnabled', () => {
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
mockRoute.query = {};
|
|
16
|
+
mockGetVersionInfo.mockReturnValue({ fullVersion: '2.12.0' });
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe('version gating', () => {
|
|
20
|
+
it('should return false when version is below 2.12.0', () => {
|
|
21
|
+
mockGetVersionInfo.mockReturnValue({ fullVersion: '2.11.9' });
|
|
22
|
+
const result = useIsNewDetailPageEnabled();
|
|
23
|
+
|
|
24
|
+
expect(result.value).toBe(false);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('should return false when version is 2.10.0', () => {
|
|
28
|
+
mockGetVersionInfo.mockReturnValue({ fullVersion: '2.10.0' });
|
|
29
|
+
const result = useIsNewDetailPageEnabled();
|
|
30
|
+
|
|
31
|
+
expect(result.value).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should return true when version is exactly 2.12.0 and no legacy query', () => {
|
|
35
|
+
mockGetVersionInfo.mockReturnValue({ fullVersion: '2.12.0' });
|
|
36
|
+
const result = useIsNewDetailPageEnabled();
|
|
37
|
+
|
|
38
|
+
expect(result.value).toBe(true);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should return true when version is above 2.12.0', () => {
|
|
42
|
+
mockGetVersionInfo.mockReturnValue({ fullVersion: '2.13.0' });
|
|
43
|
+
const result = useIsNewDetailPageEnabled();
|
|
44
|
+
|
|
45
|
+
expect(result.value).toBe(true);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should return false when version is undefined', () => {
|
|
49
|
+
mockGetVersionInfo.mockReturnValue({ fullVersion: undefined });
|
|
50
|
+
const result = useIsNewDetailPageEnabled();
|
|
51
|
+
|
|
52
|
+
expect(result.value).toBe(false);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('should return false when version is null', () => {
|
|
56
|
+
mockGetVersionInfo.mockReturnValue({ fullVersion: null });
|
|
57
|
+
const result = useIsNewDetailPageEnabled();
|
|
58
|
+
|
|
59
|
+
expect(result.value).toBe(false);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should handle pre-release version strings', () => {
|
|
63
|
+
mockGetVersionInfo.mockReturnValue({ fullVersion: 'v2.12.1-rc1' });
|
|
64
|
+
const result = useIsNewDetailPageEnabled();
|
|
65
|
+
|
|
66
|
+
expect(result.value).toBe(true);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe('legacy query param (with version >= 2.12.0)', () => {
|
|
71
|
+
it('should return true when no legacy query param is present', () => {
|
|
72
|
+
const result = useIsNewDetailPageEnabled();
|
|
73
|
+
|
|
74
|
+
expect(result.value).toBe(true);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should return false when legacy query param is "true"', () => {
|
|
78
|
+
mockRoute.query = { legacy: 'true' };
|
|
79
|
+
const result = useIsNewDetailPageEnabled();
|
|
80
|
+
|
|
81
|
+
expect(result.value).toBe(false);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should return true when legacy query param is "false"', () => {
|
|
85
|
+
mockRoute.query = { legacy: 'false' };
|
|
86
|
+
const result = useIsNewDetailPageEnabled();
|
|
87
|
+
|
|
88
|
+
expect(result.value).toBe(true);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('should return true when legacy query param has an unexpected value', () => {
|
|
92
|
+
mockRoute.query = { legacy: 'something' };
|
|
93
|
+
const result = useIsNewDetailPageEnabled();
|
|
94
|
+
|
|
95
|
+
expect(result.value).toBe(true);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
});
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { useRoute } from 'vue-router';
|
|
2
2
|
import { LEGACY } from '@shell/config/query-params';
|
|
3
3
|
import { computed } from 'vue';
|
|
4
|
+
import { getVersionInfo } from '@shell/utils/version';
|
|
5
|
+
import semver from 'semver';
|
|
6
|
+
import { useStore } from 'vuex';
|
|
4
7
|
|
|
5
8
|
const enabledByDefault = true;
|
|
6
9
|
|
|
@@ -8,6 +11,15 @@ export const useIsNewDetailPageEnabled = () => {
|
|
|
8
11
|
const route = useRoute();
|
|
9
12
|
|
|
10
13
|
return computed(() => {
|
|
14
|
+
const store = useStore();
|
|
15
|
+
const { fullVersion } = getVersionInfo(store);
|
|
16
|
+
|
|
17
|
+
const coerced = semver.coerce(fullVersion) || { version: '0.0.0' };
|
|
18
|
+
|
|
19
|
+
if (!semver.gte(coerced.version, '2.12.0')) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
|
|
11
23
|
if (enabledByDefault) {
|
|
12
24
|
return route?.query?.[LEGACY] !== 'true';
|
|
13
25
|
}
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
USER_ID, USERNAME, USER_DISPLAY_NAME, USER_PROVIDER, USER_LAST_LOGIN, USER_DISABLED_IN, USER_DELETED_IN, WORKLOAD_ENDPOINTS, STORAGE_CLASS_DEFAULT,
|
|
20
20
|
STORAGE_CLASS_PROVISIONER, PERSISTENT_VOLUME_SOURCE,
|
|
21
21
|
HPA_REFERENCE, MIN_REPLICA, MAX_REPLICA, CURRENT_REPLICA,
|
|
22
|
-
DESCRIPTION, SUB_TYPE, PERSISTENT_VOLUME_CLAIM, RECLAIM_POLICY, PV_REASON, WORKLOAD_HEALTH_SCALE, POD_RESTARTS,
|
|
22
|
+
ACCESS_KEY, DESCRIPTION, EXPIRES, EXPIRY_STATE, LAST_USED, SUB_TYPE, AGE_NORMAN, SCOPE_NORMAN, PERSISTENT_VOLUME_CLAIM, RECLAIM_POLICY, PV_REASON, WORKLOAD_HEALTH_SCALE, POD_RESTARTS,
|
|
23
23
|
DURATION, MESSAGE, REASON, EVENT_TYPE, OBJECT, ROLE, ROLES, VERSION, INTERNAL_EXTERNAL_IP, KUBE_NODE_OS, CPU, RAM, SECRET_DATA,
|
|
24
24
|
EVENT_LAST_SEEN_TIME,
|
|
25
25
|
EVENT_FIRST_SEEN_TIME,
|
|
@@ -546,6 +546,16 @@ export function init(store) {
|
|
|
546
546
|
AGE
|
|
547
547
|
]);
|
|
548
548
|
|
|
549
|
+
headers(NORMAN.TOKEN, [
|
|
550
|
+
EXPIRY_STATE,
|
|
551
|
+
ACCESS_KEY,
|
|
552
|
+
DESCRIPTION,
|
|
553
|
+
SCOPE_NORMAN,
|
|
554
|
+
LAST_USED,
|
|
555
|
+
EXPIRES,
|
|
556
|
+
AGE_NORMAN
|
|
557
|
+
]);
|
|
558
|
+
|
|
549
559
|
virtualType({
|
|
550
560
|
label: store.getters['i18n/t']('clusterIndexPage.header'),
|
|
551
561
|
group: 'Root',
|
package/config/table-headers.js
CHANGED
|
@@ -1033,15 +1033,6 @@ export const SCOPE_NORMAN = {
|
|
|
1033
1033
|
sort: ['clusterId'],
|
|
1034
1034
|
};
|
|
1035
1035
|
|
|
1036
|
-
export const NORMAN_KEY_DEPRECATION = {
|
|
1037
|
-
name: 'isNormanKeyDeprecated',
|
|
1038
|
-
labelKey: 'tableHeaders.isLegacy',
|
|
1039
|
-
value: (row) => row.isDeprecated ? 'True' : undefined,
|
|
1040
|
-
sort: 'isDeprecated',
|
|
1041
|
-
align: 'left',
|
|
1042
|
-
dashIfEmpty: true,
|
|
1043
|
-
};
|
|
1044
|
-
|
|
1045
1036
|
export const EXPIRES = {
|
|
1046
1037
|
name: 'expires',
|
|
1047
1038
|
value: 'expiresAt',
|
package/config/types.js
CHANGED
|
@@ -269,7 +269,6 @@ export const EXT = {
|
|
|
269
269
|
GROUP_MEMBERSHIP_REFRESH_REQUESTS: 'ext.cattle.io.groupmembershiprefreshrequest',
|
|
270
270
|
PASSWORD_CHANGE_REQUESTS: 'ext.cattle.io.passwordchangerequest',
|
|
271
271
|
KUBECONFIG: 'ext.cattle.io.kubeconfig',
|
|
272
|
-
TOKEN: 'ext.cattle.io.token',
|
|
273
272
|
};
|
|
274
273
|
|
|
275
274
|
export const CAPI = {
|