@rancher/shell 3.0.4 → 3.0.5-rc.1
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 +6 -0
- package/assets/styles/global/_button.scss +1 -0
- package/assets/translations/en-us.yaml +37 -3
- package/cloud-credential/aws.vue +2 -0
- package/components/AssignTo.vue +25 -11
- package/components/AsyncButton.vue +24 -7
- package/components/BannerGraphic.vue +1 -0
- package/components/CommunityLinks.vue +3 -3
- package/components/CopyToClipboardText.vue +2 -1
- package/components/DetailText.vue +5 -0
- package/components/DisableAuthProviderModal.vue +1 -0
- package/components/ExplorerMembers.vue +1 -1
- package/components/ExplorerProjectsNamespaces.vue +56 -14
- package/components/LandingPagePreference.vue +5 -3
- package/components/LocaleSelector.vue +38 -94
- package/components/ModalWithCard.vue +1 -0
- package/components/MoveModal.vue +1 -0
- package/components/PromptRemove.vue +1 -0
- package/components/PromptRestore.vue +1 -0
- package/components/ResourceCancelModal.vue +1 -0
- package/components/SortableTable/index.vue +10 -11
- package/components/__tests__/AsyncButton.test.ts +2 -2
- package/components/auth/__tests__/RoleDetailEdit.test.ts +3 -2
- package/components/form/ArrayList.vue +66 -54
- package/components/form/Command.vue +6 -15
- package/components/form/EnvVars.vue +15 -8
- package/components/form/HealthCheck.vue +3 -3
- package/components/form/HookOption.vue +11 -16
- package/components/form/LabeledSelect.vue +2 -1
- package/components/form/LifecycleHooks.vue +3 -3
- package/components/form/MatchExpressions.vue +10 -7
- package/components/form/NameNsDescription.vue +123 -103
- package/components/form/Networking.vue +20 -12
- package/components/form/NodeAffinity.vue +31 -23
- package/components/form/NodeScheduling.vue +13 -3
- package/components/form/PodAffinity.vue +43 -43
- package/components/form/Probe.vue +67 -66
- package/components/form/ResourceQuota/Project.vue +5 -1
- package/components/form/ResourceSelector.vue +7 -9
- package/components/form/SSHKnownHosts/KnownHostsEditDialog.vue +6 -3
- package/components/form/SSHKnownHosts/__tests__/KnownHostsEditDialog.test.ts +12 -1
- package/components/form/SSHKnownHosts/index.vue +16 -2
- package/components/form/Security.vue +54 -56
- package/components/form/Select.vue +31 -6
- package/components/form/ShellInput.vue +5 -1
- package/components/form/Tolerations.vue +5 -1
- package/components/form/ValueFromResource.vue +134 -121
- package/components/form/WorkloadPorts.vue +18 -18
- package/components/form/__tests__/ArrayList.test.ts +3 -0
- package/components/form/__tests__/MatchExpressions.test.ts +12 -12
- package/components/form/__tests__/NameNsDescription.test.ts +115 -14
- package/components/form/__tests__/Probe.test.ts +12 -8
- package/components/form/__tests__/SSHKnownHosts.test.ts +11 -0
- package/components/form/__tests__/Select.test.ts +37 -0
- package/components/formatter/InternalExternalIP.vue +2 -0
- package/components/formatter/SecretData.vue +20 -7
- package/components/nav/Group.vue +15 -1
- package/components/nav/Header.vue +1 -0
- package/components/nav/Type.vue +12 -1
- package/components/templates/blank.vue +4 -1
- package/components/templates/default.vue +2 -0
- package/components/templates/home.vue +4 -1
- package/components/templates/plain.vue +4 -1
- package/composables/useRuntimeFlag.ts +29 -0
- package/config/router/routes.js +20 -13
- package/core/types.ts +5 -0
- package/dialog/AddCustomBadgeDialog.vue +1 -0
- package/dialog/DeactivateDriverDialog.vue +1 -0
- package/dialog/ForceMachineRemoveDialog.vue +4 -1
- package/edit/__tests__/monitoring.coreos.com.prometheusrule.test.ts +16 -3
- package/edit/auth/__tests__/oidc.test.ts +152 -109
- package/edit/auth/azuread.vue +1 -0
- package/edit/auth/googleoauth.vue +4 -0
- package/edit/auth/oidc.vue +37 -4
- package/edit/cloudcredential.vue +1 -0
- package/edit/logging.banzaicloud.io.output/__tests__/logging.banzaicloud.io.output.test.ts +40 -9
- package/edit/networking.k8s.io.ingress/IngressClass.vue +7 -3
- package/edit/networking.k8s.io.ingress/__tests__/IngressClass.test.ts +58 -0
- package/edit/persistentvolume/__tests__/persistentvolume.test.ts +14 -2
- package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +1 -0
- package/edit/provisioning.cattle.io.cluster/rke2.vue +25 -34
- package/edit/provisioning.cattle.io.cluster/tabs/AgentConfiguration.vue +6 -1
- package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +29 -1
- package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +2 -2
- package/edit/token.vue +2 -0
- package/edit/workload/index.vue +1 -0
- package/edit/workload/mixins/workload.js +0 -2
- package/list/management.cattle.io.feature.vue +1 -0
- package/list/provisioning.cattle.io.cluster.vue +20 -12
- package/models/__tests__/namespace.test.ts +25 -1
- package/models/cloudcredential.js +5 -0
- package/models/kontainerdriver.js +6 -3
- package/models/management.cattle.io.node.js +3 -3
- package/models/namespace.js +4 -5
- package/models/nodedriver.js +6 -3
- package/models/workload.js +4 -1
- package/package.json +3 -3
- package/pages/account/index.vue +4 -1
- package/pages/auth/login.vue +11 -3
- package/pages/auth/logout.vue +4 -1
- package/pages/auth/setup.vue +1 -0
- package/pages/auth/verify.vue +4 -1
- package/pages/c/_cluster/apps/charts/chart.vue +1 -1
- package/pages/diagnostic.vue +47 -2
- package/pages/fail-whale.vue +6 -3
- package/pages/home.vue +24 -18
- package/pages/support/index.vue +4 -1
- package/rancher-components/Form/Radio/RadioGroup.vue +25 -23
- package/rancher-components/RcDropdown/RcDropdown.vue +3 -2
- package/rancher-components/RcDropdown/RcDropdownTrigger.vue +10 -0
- package/rancher-components/RcDropdown/useDropdownCollection.ts +8 -0
- package/rancher-components/RcDropdown/useDropdownContext.ts +9 -3
- package/scripts/extension/publish +1 -0
- package/server/har-file.js +25 -3
- package/store/features.js +2 -1
- package/store/type-map.js +4 -0
- package/types/shell/index.d.ts +8 -1
- package/utils/cluster.js +35 -0
- package/utils/validators/machine-pool.ts +20 -0
- package/components/formatter/ExtensionCache.vue +0 -74
- package/components/formatter/Port.vue +0 -24
- package/components/formatter/SecretType.vue +0 -41
package/pages/auth/verify.vue
CHANGED
|
@@ -182,7 +182,10 @@ export default {
|
|
|
182
182
|
</script>
|
|
183
183
|
|
|
184
184
|
<template>
|
|
185
|
-
<main
|
|
185
|
+
<main
|
|
186
|
+
class="main-layout"
|
|
187
|
+
:aria-label="t('layouts.verify')"
|
|
188
|
+
>
|
|
186
189
|
<h1 class="text-center mt-50">
|
|
187
190
|
<span v-if="testing">
|
|
188
191
|
Testing Configuration…
|
package/pages/diagnostic.vue
CHANGED
|
@@ -17,6 +17,7 @@ export default {
|
|
|
17
17
|
const finalCounts = [];
|
|
18
18
|
const promises = [];
|
|
19
19
|
const topFifteenForResponseTime = [];
|
|
20
|
+
const schemaPromises = [];
|
|
20
21
|
|
|
21
22
|
clusterForCounts.forEach((cluster, i) => {
|
|
22
23
|
// Necessary to retrieve the proper display name of the cluster
|
|
@@ -31,9 +32,11 @@ export default {
|
|
|
31
32
|
isTableVisible: !!(i === 0 && clusterForCounts.length === 1)
|
|
32
33
|
});
|
|
33
34
|
promises.push(this.$store.dispatch('management/request', { url: `/k8s/clusters/${ cluster.mgmt?.id }/v1/counts` }));
|
|
35
|
+
schemaPromises.push(this.$store.dispatch('management/request', { url: `/k8s/clusters/${ cluster.mgmt?.id }/v1/schemas?exclude=metadata.managedFields` }));
|
|
34
36
|
});
|
|
35
37
|
|
|
36
38
|
const countsPerCluster = await Promise.all(promises);
|
|
39
|
+
const schemasPerCluster = await Promise.all(schemaPromises);
|
|
37
40
|
|
|
38
41
|
countsPerCluster.forEach((clusterCount, index) => {
|
|
39
42
|
const counts = clusterCount.data?.[0]?.counts;
|
|
@@ -69,6 +72,14 @@ export default {
|
|
|
69
72
|
|
|
70
73
|
this.topFifteenForResponseTime = topFifteenForResponseTime;
|
|
71
74
|
this.finalCounts = finalCounts;
|
|
75
|
+
|
|
76
|
+
// Schemas
|
|
77
|
+
schemasPerCluster.forEach((schemas, index) => {
|
|
78
|
+
finalCounts[index].schemaCount = schemas?.data?.length || 0;
|
|
79
|
+
finalCounts[index].customSchemas = (schemas?.data?.filter((schema) => {
|
|
80
|
+
return schema.attributes?.group.includes('.') && !schema.attributes?.group.includes('.cattle.io') && !schema.attributes?.group.includes('.k8s.io');
|
|
81
|
+
}).map((schema) => schema.id) || []).sort();
|
|
82
|
+
});
|
|
72
83
|
},
|
|
73
84
|
|
|
74
85
|
data() {
|
|
@@ -148,7 +159,7 @@ export default {
|
|
|
148
159
|
systemInformation: this.systemInformation,
|
|
149
160
|
storeMapping: this.parseStoreData(this.storeMapping),
|
|
150
161
|
resourceCounts: this.finalCounts,
|
|
151
|
-
responseTimes: this.responseTimes
|
|
162
|
+
responseTimes: this.responseTimes,
|
|
152
163
|
};
|
|
153
164
|
|
|
154
165
|
downloadFile(fileName, JSON.stringify(data), 'application/json')
|
|
@@ -352,6 +363,7 @@ export default {
|
|
|
352
363
|
<span>Cluster: <b>{{ cluster.name }}</b></span>
|
|
353
364
|
<span>Namespace: <b>{{ cluster.namespace }}</b></span>
|
|
354
365
|
<span>Total Resources: <b>{{ sumResourceCount(cluster.counts) }}</b></span>
|
|
366
|
+
<span>Total Schemas: <b>{{ cluster.schemaCount }}</b></span>
|
|
355
367
|
<span>Nodes: <b>{{ nodeCount(cluster.counts) }}</b></span>
|
|
356
368
|
<i
|
|
357
369
|
class="icon"
|
|
@@ -365,6 +377,22 @@ export default {
|
|
|
365
377
|
</tr>
|
|
366
378
|
</thead>
|
|
367
379
|
<tbody v-show="cluster.isTableVisible">
|
|
380
|
+
<tr>
|
|
381
|
+
<td colspan="3">
|
|
382
|
+
<div class="schema-title">
|
|
383
|
+
Custom Schemas
|
|
384
|
+
</div>
|
|
385
|
+
<div class="custom-schemas">
|
|
386
|
+
<div
|
|
387
|
+
v-for="name in cluster.customSchemas"
|
|
388
|
+
:key="name"
|
|
389
|
+
class="schema-name"
|
|
390
|
+
>
|
|
391
|
+
{{ name }}
|
|
392
|
+
</div>
|
|
393
|
+
</div>
|
|
394
|
+
</td>
|
|
395
|
+
</tr>
|
|
368
396
|
<tr>
|
|
369
397
|
<th>
|
|
370
398
|
Resource
|
|
@@ -445,6 +473,23 @@ table {
|
|
|
445
473
|
padding: 8px 5px;
|
|
446
474
|
min-width: 150px;
|
|
447
475
|
text-align: left;
|
|
476
|
+
|
|
477
|
+
.schema-title {
|
|
478
|
+
font-weight: bold;
|
|
479
|
+
margin-bottom: 4px;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
.custom-schemas {
|
|
483
|
+
display: flex;
|
|
484
|
+
flex-wrap: wrap;
|
|
485
|
+
|
|
486
|
+
> .schema-name {
|
|
487
|
+
margin-right: 5px;
|
|
488
|
+
margin-bottom: 2px;
|
|
489
|
+
border: 1px solid var(--border);
|
|
490
|
+
padding: 2px 5px;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
448
493
|
}
|
|
449
494
|
|
|
450
495
|
th {
|
|
@@ -511,7 +556,7 @@ table {
|
|
|
511
556
|
.resources-count-container {
|
|
512
557
|
.cluster-row {
|
|
513
558
|
display: grid;
|
|
514
|
-
grid-template-columns: repeat(
|
|
559
|
+
grid-template-columns: repeat(5, 1fr) 20px;
|
|
515
560
|
grid-template-rows: 1fr;
|
|
516
561
|
align-content: center;
|
|
517
562
|
font-weight: normal;
|
package/pages/fail-whale.vue
CHANGED
|
@@ -70,12 +70,15 @@ export default {
|
|
|
70
70
|
:simple="true"
|
|
71
71
|
/>
|
|
72
72
|
|
|
73
|
-
<main
|
|
73
|
+
<main
|
|
74
|
+
class="main-layout"
|
|
75
|
+
aria-label="Fail whale layout"
|
|
76
|
+
>
|
|
74
77
|
<div
|
|
75
78
|
v-if="error"
|
|
76
79
|
class="outlet"
|
|
77
80
|
>
|
|
78
|
-
<
|
|
81
|
+
<div class="main-layout error">
|
|
79
82
|
<div class="text-center">
|
|
80
83
|
<BrandImage
|
|
81
84
|
file-name="error-desert-landscape.svg"
|
|
@@ -115,7 +118,7 @@ export default {
|
|
|
115
118
|
</a>
|
|
116
119
|
</p>
|
|
117
120
|
</div>
|
|
118
|
-
</
|
|
121
|
+
</div>
|
|
119
122
|
</div>
|
|
120
123
|
</main>
|
|
121
124
|
</div>
|
package/pages/home.vue
CHANGED
|
@@ -49,6 +49,21 @@ export default defineComponent({
|
|
|
49
49
|
mixins: [PageHeaderActions],
|
|
50
50
|
|
|
51
51
|
data() {
|
|
52
|
+
const options = this.$store.getters[`type-map/optionsFor`](CAPI.RANCHER_CLUSTER)?.custom || {};
|
|
53
|
+
const params = {
|
|
54
|
+
product: MANAGER,
|
|
55
|
+
cluster: BLANK_CLUSTER,
|
|
56
|
+
resource: CAPI.RANCHER_CLUSTER
|
|
57
|
+
};
|
|
58
|
+
const defaultCreateLocation = {
|
|
59
|
+
name: 'c-cluster-product-resource-create',
|
|
60
|
+
params,
|
|
61
|
+
};
|
|
62
|
+
const defaultImportLocation = {
|
|
63
|
+
...defaultCreateLocation,
|
|
64
|
+
query: { [MODE]: _IMPORT }
|
|
65
|
+
};
|
|
66
|
+
|
|
52
67
|
return {
|
|
53
68
|
HIDE_HOME_PAGE_CARDS,
|
|
54
69
|
fullVersion: getVersionInfo(this.$store).fullVersion,
|
|
@@ -87,24 +102,9 @@ export default defineComponent({
|
|
|
87
102
|
},
|
|
88
103
|
},
|
|
89
104
|
|
|
90
|
-
createLocation:
|
|
91
|
-
name: 'c-cluster-product-resource-create',
|
|
92
|
-
params: {
|
|
93
|
-
product: MANAGER,
|
|
94
|
-
cluster: BLANK_CLUSTER,
|
|
95
|
-
resource: CAPI.RANCHER_CLUSTER
|
|
96
|
-
},
|
|
97
|
-
},
|
|
105
|
+
createLocation: options.createLocation ? options.createLocation(params) : defaultCreateLocation,
|
|
98
106
|
|
|
99
|
-
importLocation:
|
|
100
|
-
name: 'c-cluster-product-resource-create',
|
|
101
|
-
params: {
|
|
102
|
-
product: MANAGER,
|
|
103
|
-
cluster: BLANK_CLUSTER,
|
|
104
|
-
resource: CAPI.RANCHER_CLUSTER
|
|
105
|
-
},
|
|
106
|
-
query: { [MODE]: _IMPORT }
|
|
107
|
-
},
|
|
107
|
+
importLocation: options.importLocation ? options.importLocation(params) : defaultImportLocation,
|
|
108
108
|
|
|
109
109
|
headers: [
|
|
110
110
|
STATE,
|
|
@@ -512,7 +512,7 @@ export default defineComponent({
|
|
|
512
512
|
:show-child="false"
|
|
513
513
|
:breadcrumb="false"
|
|
514
514
|
>
|
|
515
|
-
{{ vendor }}
|
|
515
|
+
{{ `${vendor} - ${t('landing.homepage')}` }}
|
|
516
516
|
</TabTitle>
|
|
517
517
|
<BannerGraphic
|
|
518
518
|
:small="true"
|
|
@@ -805,6 +805,12 @@ export default defineComponent({
|
|
|
805
805
|
.cluster-name {
|
|
806
806
|
display: flex;
|
|
807
807
|
align-items: center;
|
|
808
|
+
|
|
809
|
+
// Ensure long cluster names truncate with ellipsis
|
|
810
|
+
> A {
|
|
811
|
+
overflow: hidden;
|
|
812
|
+
text-overflow: ellipsis;
|
|
813
|
+
}
|
|
808
814
|
}
|
|
809
815
|
|
|
810
816
|
.cluster-description {
|
package/pages/support/index.vue
CHANGED
|
@@ -118,7 +118,10 @@ export default {
|
|
|
118
118
|
</script>
|
|
119
119
|
<template>
|
|
120
120
|
<div>
|
|
121
|
-
<BannerGraphic
|
|
121
|
+
<BannerGraphic
|
|
122
|
+
:title="t(title, {}, true)"
|
|
123
|
+
:alt="t('support.bannerImage')"
|
|
124
|
+
/>
|
|
122
125
|
|
|
123
126
|
<IndentedPanel>
|
|
124
127
|
<div class="content mt-20">
|
|
@@ -199,33 +199,35 @@ export default defineComponent({
|
|
|
199
199
|
</script>
|
|
200
200
|
|
|
201
201
|
<template>
|
|
202
|
-
<
|
|
202
|
+
<fieldset>
|
|
203
203
|
<!-- Label -->
|
|
204
204
|
<div
|
|
205
205
|
v-if="label || labelKey || tooltip || tooltipKey || $slots.label"
|
|
206
206
|
class="radio-group label"
|
|
207
207
|
>
|
|
208
|
-
<
|
|
209
|
-
<
|
|
210
|
-
<
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
208
|
+
<legend>
|
|
209
|
+
<slot name="label">
|
|
210
|
+
<h3>
|
|
211
|
+
<t
|
|
212
|
+
v-if="labelKey"
|
|
213
|
+
:k="labelKey"
|
|
214
|
+
/>
|
|
215
|
+
<template v-else-if="label">
|
|
216
|
+
{{ label }}
|
|
217
|
+
</template>
|
|
218
|
+
<i
|
|
219
|
+
v-if="tooltipKey"
|
|
220
|
+
v-clean-tooltip="t(tooltipKey)"
|
|
221
|
+
class="icon icon-info icon-lg"
|
|
222
|
+
/>
|
|
223
|
+
<i
|
|
224
|
+
v-else-if="tooltip"
|
|
225
|
+
v-clean-tooltip="tooltip"
|
|
226
|
+
class="icon icon-info icon-lg"
|
|
227
|
+
/>
|
|
228
|
+
</h3>
|
|
229
|
+
</slot>
|
|
230
|
+
</legend>
|
|
229
231
|
</div>
|
|
230
232
|
|
|
231
233
|
<!-- Group -->
|
|
@@ -266,7 +268,7 @@ export default defineComponent({
|
|
|
266
268
|
</slot>
|
|
267
269
|
</div>
|
|
268
270
|
</div>
|
|
269
|
-
</
|
|
271
|
+
</fieldset>
|
|
270
272
|
</template>
|
|
271
273
|
|
|
272
274
|
<style lang='scss'>
|
|
@@ -49,7 +49,7 @@ useClickOutside(dropdownTarget, () => showMenu(false));
|
|
|
49
49
|
|
|
50
50
|
const applyShow = () => {
|
|
51
51
|
registerDropdownCollection(dropdownTarget.value);
|
|
52
|
-
setFocus();
|
|
52
|
+
setFocus('down');
|
|
53
53
|
};
|
|
54
54
|
|
|
55
55
|
</script>
|
|
@@ -78,7 +78,8 @@ const applyShow = () => {
|
|
|
78
78
|
dropdown-menu-collection
|
|
79
79
|
:aria-label="ariaLabel || 'Dropdown Menu'"
|
|
80
80
|
@keydown="handleKeydown"
|
|
81
|
-
@keydown.down="setFocus()"
|
|
81
|
+
@keydown.down="setFocus('down')"
|
|
82
|
+
@keydown.up="setFocus('up')"
|
|
82
83
|
>
|
|
83
84
|
<slot name="dropdownCollection">
|
|
84
85
|
<!--Empty slot content-->
|
|
@@ -35,8 +35,18 @@ defineExpose({ focus });
|
|
|
35
35
|
@keydown.enter.space="handleKeydown"
|
|
36
36
|
@click="showMenu(true)"
|
|
37
37
|
>
|
|
38
|
+
<template #before>
|
|
39
|
+
<slot name="before">
|
|
40
|
+
<!-- Empty Content -->
|
|
41
|
+
</slot>
|
|
42
|
+
</template>
|
|
38
43
|
<slot name="default">
|
|
39
44
|
<!--Empty slot content-->
|
|
40
45
|
</slot>
|
|
46
|
+
<template #after>
|
|
47
|
+
<slot name="after">
|
|
48
|
+
<!-- Empty Content -->
|
|
49
|
+
</slot>
|
|
50
|
+
</template>
|
|
41
51
|
</RcButton>
|
|
42
52
|
</template>
|
|
@@ -10,6 +10,7 @@ export const useDropdownCollection = () => {
|
|
|
10
10
|
const dropdownItems = ref<Element[]>([]);
|
|
11
11
|
const dropdownContainer = ref<HTMLElement | null>(null);
|
|
12
12
|
const firstDropdownItem = ref<HTMLElement | null>(null);
|
|
13
|
+
const lastDropdownItem = ref<HTMLElement | null>(null);
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Registers the dropdown container and initializes dropdown items.
|
|
@@ -22,6 +23,12 @@ export const useDropdownCollection = () => {
|
|
|
22
23
|
if (dropdownItems.value[0] instanceof HTMLElement) {
|
|
23
24
|
firstDropdownItem.value = dropdownItems.value[0];
|
|
24
25
|
}
|
|
26
|
+
|
|
27
|
+
const lastItem = dropdownItems.value[dropdownItems.value.length - 1];
|
|
28
|
+
|
|
29
|
+
if (lastItem instanceof HTMLElement) {
|
|
30
|
+
lastDropdownItem.value = lastItem;
|
|
31
|
+
}
|
|
25
32
|
}
|
|
26
33
|
};
|
|
27
34
|
|
|
@@ -40,6 +47,7 @@ export const useDropdownCollection = () => {
|
|
|
40
47
|
return {
|
|
41
48
|
dropdownItems,
|
|
42
49
|
firstDropdownItem,
|
|
50
|
+
lastDropdownItem,
|
|
43
51
|
dropdownContainer,
|
|
44
52
|
registerDropdownCollection,
|
|
45
53
|
};
|
|
@@ -17,6 +17,7 @@ export const useDropdownContext = (emit: typeof rcDropdownEmits) => {
|
|
|
17
17
|
const {
|
|
18
18
|
dropdownItems,
|
|
19
19
|
firstDropdownItem,
|
|
20
|
+
lastDropdownItem,
|
|
20
21
|
dropdownContainer,
|
|
21
22
|
registerDropdownCollection,
|
|
22
23
|
} = useDropdownCollection();
|
|
@@ -70,7 +71,7 @@ export const useDropdownContext = (emit: typeof rcDropdownEmits) => {
|
|
|
70
71
|
/**
|
|
71
72
|
* Sets focus to the first dropdown item if a keydown event has occurred.
|
|
72
73
|
*/
|
|
73
|
-
const setFocus = () => {
|
|
74
|
+
const setFocus = (direction: 'down' | 'up') => {
|
|
74
75
|
nextTick(() => {
|
|
75
76
|
if (!didKeydown.value) {
|
|
76
77
|
dropdownContainer.value?.focus();
|
|
@@ -78,7 +79,12 @@ export const useDropdownContext = (emit: typeof rcDropdownEmits) => {
|
|
|
78
79
|
return;
|
|
79
80
|
}
|
|
80
81
|
|
|
81
|
-
|
|
82
|
+
if (direction === 'down') {
|
|
83
|
+
firstDropdownItem.value?.focus();
|
|
84
|
+
} else if (direction === 'up') {
|
|
85
|
+
lastDropdownItem.value?.focus();
|
|
86
|
+
}
|
|
87
|
+
|
|
82
88
|
didKeydown.value = false;
|
|
83
89
|
});
|
|
84
90
|
};
|
|
@@ -95,7 +101,7 @@ export const useDropdownContext = (emit: typeof rcDropdownEmits) => {
|
|
|
95
101
|
dropdownItems,
|
|
96
102
|
close: () => returnFocus(),
|
|
97
103
|
focusFirstElement: () => {
|
|
98
|
-
setFocus();
|
|
104
|
+
setFocus('down');
|
|
99
105
|
},
|
|
100
106
|
handleKeydown,
|
|
101
107
|
});
|
package/server/har-file.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
+
const querystring = require('querystring');
|
|
3
4
|
|
|
4
5
|
// When we receive a request to this URL we will reset the session to replay again from the HAR file
|
|
5
6
|
// This allows the user to refresh the browser and replay the HAR file again
|
|
6
7
|
const RESET_URL = '/api/v1/namespaces/cattle-ui-plugin-system/services/http:ui-plugin-operator:80/proxy/index.json';
|
|
7
8
|
|
|
8
|
-
const
|
|
9
|
+
const EXCLUDE_QS = 'exclude';
|
|
10
|
+
|
|
11
|
+
const LEGACY_UI_PLUGIN_INDEX = '/api/v1/namespaces/cattle-ui-plugin-system/services/http:ui-plugin-operator:80/proxy/index.json';
|
|
12
|
+
const NEW_UI_PLUGIN_INDEX = '/v1/uiplugins';
|
|
9
13
|
|
|
10
14
|
/**
|
|
11
15
|
* Load the network requests/responses from the har file
|
|
@@ -113,10 +117,28 @@ function harProxy(responses, folder) {
|
|
|
113
117
|
const url = decodeURIComponent(req.originalUrl);
|
|
114
118
|
let playback = session[req.originalUrl];
|
|
115
119
|
|
|
120
|
+
// Handle case where HAR file was created with older UI Extension API that used the operator
|
|
121
|
+
if (!playback && req.originalUrl.includes(NEW_UI_PLUGIN_INDEX)) {
|
|
122
|
+
// Look for new URl for UI plugins
|
|
123
|
+
playback = session[LEGACY_UI_PLUGIN_INDEX];
|
|
124
|
+
}
|
|
125
|
+
|
|
116
126
|
// If it did not match, try without the metadata excludes query string that was adding in 2.8.0
|
|
117
127
|
// This might allow HAR captures with Rancher < 2.8.0 to be replayed on >= 2.8.0
|
|
118
|
-
if (!playback && req.originalUrl.
|
|
119
|
-
|
|
128
|
+
if (!playback && req.originalUrl.includes('?')) {
|
|
129
|
+
const urlParts = req.originalUrl.split('?');
|
|
130
|
+
|
|
131
|
+
if (urlParts.length > 1) {
|
|
132
|
+
const queryString = urlParts[1];
|
|
133
|
+
const qs = querystring.parse(queryString);
|
|
134
|
+
|
|
135
|
+
delete qs[EXCLUDE_QS];
|
|
136
|
+
|
|
137
|
+
const newQs = querystring.stringify(qs);
|
|
138
|
+
const newUrl = newQs.length ? `${ urlParts[0] }?${ newQs }` : urlParts[0];
|
|
139
|
+
|
|
140
|
+
playback = session[newUrl];
|
|
141
|
+
}
|
|
120
142
|
}
|
|
121
143
|
|
|
122
144
|
if (playback && playback[req.method] && playback[req.method].length) {
|
package/store/features.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { MANAGEMENT } from '@shell/config/types';
|
|
2
|
+
import { SCHEDULING_CUSTOMIZATION as SCHEDULING_CUSTOMIZATION_FEATURE } from '@shell/config/features';
|
|
2
3
|
|
|
3
4
|
const definitions = {};
|
|
4
5
|
|
|
@@ -36,7 +37,7 @@ export const FLEET_WORKSPACE_BACK = create('provisioningv2-fleet-workspace-back-
|
|
|
36
37
|
export const STEVE_CACHE = create('ui-sql-cache', false);
|
|
37
38
|
export const UIEXTENSION = create('uiextension', true);
|
|
38
39
|
export const PROVISIONING_PRE_BOOTSTRAP = create('provisioningprebootstrap', false);
|
|
39
|
-
export const SCHEDULING_CUSTOMIZATION = create(
|
|
40
|
+
export const SCHEDULING_CUSTOMIZATION = create(SCHEDULING_CUSTOMIZATION_FEATURE, false);
|
|
40
41
|
|
|
41
42
|
// Not currently used.. no point defining ones we don't use
|
|
42
43
|
// export const EMBEDDED_CLUSTER_API = create('embedded-cluster-api', true);
|
package/store/type-map.js
CHANGED
|
@@ -107,6 +107,7 @@
|
|
|
107
107
|
// graphConfig: undefined -- Use this to pass along the graph configuration
|
|
108
108
|
// notFilterNamespace: undefined -- Define namespaces that do not need to be filtered
|
|
109
109
|
// localOnly: False -- Hide this type from the nav/search bar on downstream clusters
|
|
110
|
+
// custom: any - Custom options for a given type
|
|
110
111
|
// }
|
|
111
112
|
// )
|
|
112
113
|
// ignoreGroup(group): Never show group or any types in it
|
|
@@ -524,6 +525,7 @@ export const getters = {
|
|
|
524
525
|
depaginate: false,
|
|
525
526
|
customRoute: undefined,
|
|
526
527
|
resourceEditMasthead: true,
|
|
528
|
+
custom: {},
|
|
527
529
|
};
|
|
528
530
|
|
|
529
531
|
return (schemaOrType, pagination) => {
|
|
@@ -1729,6 +1731,8 @@ export const mutations = {
|
|
|
1729
1731
|
let obj = { ...options, match };
|
|
1730
1732
|
|
|
1731
1733
|
if ( idx >= 0 ) {
|
|
1734
|
+
// Merge the custom data object - multiple configures will update existing rather than overwrite
|
|
1735
|
+
obj.custom = Object.assign(state.typeOptions[idx].custom || {}, obj.custom || {});
|
|
1732
1736
|
obj = Object.assign(state.typeOptions[idx], obj);
|
|
1733
1737
|
state.typeOptions.splice(idx, 1, obj);
|
|
1734
1738
|
} else {
|
package/types/shell/index.d.ts
CHANGED
|
@@ -2475,7 +2475,7 @@ export default class Namespace {
|
|
|
2475
2475
|
get isObscure(): any;
|
|
2476
2476
|
get projectId(): any;
|
|
2477
2477
|
get project(): any;
|
|
2478
|
-
get
|
|
2478
|
+
get groupById(): any;
|
|
2479
2479
|
get projectNameSort(): any;
|
|
2480
2480
|
get istioInstalled(): boolean;
|
|
2481
2481
|
get injectionEnabled(): boolean;
|
|
@@ -3498,6 +3498,13 @@ export function abbreviateClusterName(input: string): string;
|
|
|
3498
3498
|
export function labelForAddon(store: any, name: any, configuration?: boolean): any;
|
|
3499
3499
|
export function filterOutDeprecatedPatchVersions(allVersions: any, currentVersion: any): any;
|
|
3500
3500
|
export function getAllOptionsAfterCurrentVersion(store: any, versions: any, currentVersion: any, defaultVersion: any): any;
|
|
3501
|
+
export function initSchedulingCustomization(value: any, features: any, store: any, mode: any): Promise<{
|
|
3502
|
+
clusterAgentDefaultPC: any;
|
|
3503
|
+
clusterAgentDefaultPDB: any;
|
|
3504
|
+
schedulingCustomizationFeatureEnabled: any;
|
|
3505
|
+
schedulingCustomizationOriginallyEnabled: boolean;
|
|
3506
|
+
errors: any[];
|
|
3507
|
+
}>;
|
|
3501
3508
|
}
|
|
3502
3509
|
|
|
3503
3510
|
// @shell/utils/color
|
package/utils/cluster.js
CHANGED
|
@@ -6,6 +6,10 @@ import { SETTING } from '@shell/config/settings';
|
|
|
6
6
|
import { PaginationFilterField, PaginationParamFilter } from '@shell/types/store/pagination.types';
|
|
7
7
|
import { compare, sortable } from '@shell/utils/version';
|
|
8
8
|
import { sortBy } from '@shell/utils/sort';
|
|
9
|
+
import { SCHEDULING_CUSTOMIZATION } from '@shell/store/features';
|
|
10
|
+
import { _CREATE, _EDIT } from '@shell/config/query-params';
|
|
11
|
+
import isEmpty from 'lodash/isEmpty';
|
|
12
|
+
import { set } from '@shell/utils/object';
|
|
9
13
|
|
|
10
14
|
/**
|
|
11
15
|
* Combination of paginationFilterHiddenLocalCluster and paginationFilterOnlyKubernetesClusters
|
|
@@ -296,3 +300,34 @@ export function getAllOptionsAfterCurrentVersion(store, versions, currentVersion
|
|
|
296
300
|
|
|
297
301
|
return sortedWithDeprecatedLabel;
|
|
298
302
|
}
|
|
303
|
+
|
|
304
|
+
export async function initSchedulingCustomization(value, features, store, mode) {
|
|
305
|
+
const schedulingCustomizationFeatureEnabled = features(SCHEDULING_CUSTOMIZATION);
|
|
306
|
+
let clusterAgentDefaultPC = null;
|
|
307
|
+
let clusterAgentDefaultPDB = null;
|
|
308
|
+
let schedulingCustomizationOriginallyEnabled = false;
|
|
309
|
+
const errors = [];
|
|
310
|
+
|
|
311
|
+
try {
|
|
312
|
+
clusterAgentDefaultPC = JSON.parse((await store.dispatch('management/find', { type: MANAGEMENT.SETTING, id: SETTING.CLUSTER_AGENT_DEFAULT_PRIORITY_CLASS })).value) || null;
|
|
313
|
+
} catch (e) {
|
|
314
|
+
errors.push(e);
|
|
315
|
+
}
|
|
316
|
+
try {
|
|
317
|
+
clusterAgentDefaultPDB = JSON.parse((await store.dispatch('management/find', { type: MANAGEMENT.SETTING, id: SETTING.CLUSTER_AGENT_DEFAULT_POD_DISTRIBUTION_BUDGET })).value) || null;
|
|
318
|
+
} catch (e) {
|
|
319
|
+
errors.push(e);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (schedulingCustomizationFeatureEnabled && mode === _CREATE && isEmpty(value?.clusterAgentDeploymentCustomization?.schedulingCustomization)) {
|
|
323
|
+
set(value, 'clusterAgentDeploymentCustomization.schedulingCustomization', { priorityClass: clusterAgentDefaultPC, podDisruptionBudget: clusterAgentDefaultPDB });
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (mode === _EDIT && !!value?.clusterAgentDeploymentCustomization?.schedulingCustomization) {
|
|
327
|
+
schedulingCustomizationOriginallyEnabled = true;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return {
|
|
331
|
+
clusterAgentDefaultPC, clusterAgentDefaultPDB, schedulingCustomizationFeatureEnabled, schedulingCustomizationOriginallyEnabled, errors
|
|
332
|
+
};
|
|
333
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const FIELDS = {
|
|
2
|
+
NAME: 'pool.name',
|
|
3
|
+
QUANTITY: 'pool.quantity'
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
const RULESETS = [
|
|
7
|
+
{
|
|
8
|
+
path: FIELDS.QUANTITY,
|
|
9
|
+
rules: ['requiredInt', 'isPositive'],
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
path: FIELDS.NAME,
|
|
13
|
+
rules: ['required'],
|
|
14
|
+
}
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
export const MACHINE_POOL_VALIDATION = {
|
|
18
|
+
FIELDS,
|
|
19
|
+
RULESETS
|
|
20
|
+
};
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
import { BadgeState } from '@components/BadgeState';
|
|
3
|
-
import { stateDisplay } from '@shell/plugins/dashboard-store/resource-class';
|
|
4
|
-
|
|
5
|
-
export default {
|
|
6
|
-
props: {
|
|
7
|
-
value: {
|
|
8
|
-
type: String,
|
|
9
|
-
default: ''
|
|
10
|
-
}
|
|
11
|
-
},
|
|
12
|
-
|
|
13
|
-
components: { BadgeState },
|
|
14
|
-
|
|
15
|
-
data() {
|
|
16
|
-
const STATES = {
|
|
17
|
-
cached: {
|
|
18
|
-
color: 'info', icon: 'dot-open', label: 'Cached', compoundIcon: 'checkmark'
|
|
19
|
-
},
|
|
20
|
-
pending: {
|
|
21
|
-
color: 'warning', icon: 'tag', label: 'In Progress', compoundIcon: 'info'
|
|
22
|
-
},
|
|
23
|
-
disabled: {
|
|
24
|
-
color: 'error', icon: 'dot-half', label: 'Cache Disabled', compoundIcon: 'info'
|
|
25
|
-
},
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
return {
|
|
29
|
-
STATES,
|
|
30
|
-
stateDisplay: '',
|
|
31
|
-
stateBackground: ''
|
|
32
|
-
};
|
|
33
|
-
},
|
|
34
|
-
|
|
35
|
-
watch: {
|
|
36
|
-
value: {
|
|
37
|
-
handler() {
|
|
38
|
-
const out = this.value || 'pending';
|
|
39
|
-
const color = this.colorForState(out);
|
|
40
|
-
|
|
41
|
-
this.stateDisplay = stateDisplay(out);
|
|
42
|
-
this.stateBackground = color.replace('text-', 'bg-');
|
|
43
|
-
},
|
|
44
|
-
immediate: true
|
|
45
|
-
}
|
|
46
|
-
},
|
|
47
|
-
|
|
48
|
-
methods: {
|
|
49
|
-
colorForState(state) {
|
|
50
|
-
const key = (state).toLowerCase();
|
|
51
|
-
let color;
|
|
52
|
-
|
|
53
|
-
if ( this.STATES[key] && this.STATES[key].color ) {
|
|
54
|
-
color = this.STATES[key].color;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if ( !color ) {
|
|
58
|
-
color = 'info';
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return `text-${ color }`;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
</script>
|
|
66
|
-
|
|
67
|
-
<template>
|
|
68
|
-
<div>
|
|
69
|
-
<BadgeState
|
|
70
|
-
:color="stateBackground"
|
|
71
|
-
:label="stateDisplay"
|
|
72
|
-
/>
|
|
73
|
-
</div>
|
|
74
|
-
</template>
|