@rancher/shell 3.0.12-rc.2 → 3.0.12-rc.3
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/impl/apis.ts +6 -0
- package/apis/index.ts +26 -0
- package/apis/intf/resources-api/cluster-api.ts +18 -0
- package/apis/intf/resources-api/mgmt-api.ts +15 -0
- package/apis/intf/resources-api/resource-base.ts +107 -0
- package/apis/intf/resources-api/resource-constants.ts +147 -0
- package/apis/intf/resources-api/resources-api.ts +143 -0
- package/apis/intf/resources.ts +49 -0
- package/apis/intf/{modal.ts → shell-api/modal.ts} +21 -26
- package/apis/intf/shell-api/proxy.ts +216 -0
- package/apis/intf/{slide-in.ts → shell-api/slide-in.ts} +4 -3
- package/apis/intf/{system.ts → shell-api/system.ts} +4 -1
- package/apis/intf/shell.ts +12 -6
- package/apis/resources/__tests__/resources-api-class.test.ts +550 -0
- package/apis/resources/index.ts +22 -0
- package/apis/resources/resources-api-class.ts +187 -0
- package/apis/shell/__tests__/proxy.test.ts +369 -0
- package/apis/shell/index.ts +8 -1
- package/apis/shell/modal.ts +4 -1
- package/apis/shell/notifications.ts +9 -6
- package/apis/shell/proxy.ts +256 -0
- package/apis/shell/slide-in.ts +4 -1
- package/apis/vue-shim.d.ts +2 -1
- package/assets/data/aws-regions.json +4 -0
- package/assets/fonts/lato/LatoLatin-Black.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Black.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-BlackItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-BlackItalic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Bold.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Bold.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-BoldItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-BoldItalic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Heavy.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Heavy.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-HeavyItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-HeavyItalic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Italic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Italic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Light.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Light.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-LightItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-LightItalic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Medium.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Medium.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-MediumItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-MediumItalic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Regular.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Regular.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Semibold.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Semibold.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-SemiboldItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-SemiboldItalic.woff2 +0 -0
- package/assets/styles/base/_variables.scss +2 -0
- package/assets/styles/fonts/_fontstack.scss +132 -8
- package/assets/translations/en-us.yaml +22 -5
- package/chart/monitoring/index.vue +10 -1
- package/components/ActionDropdownShell.vue +2 -1
- package/components/CruResourceFooter.vue +9 -5
- package/components/ExplorerProjectsNamespaces.vue +1 -1
- package/components/InstallHelmCharts.vue +2 -2
- package/components/LandingPagePreference.vue +14 -5
- package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +15 -1
- package/components/Resource/Detail/Metadata/index.vue +6 -0
- package/components/Resource/Detail/ResourcePopover/index.vue +12 -1
- package/components/Resource/Detail/SpacedRow.vue +3 -1
- package/components/Resource/Detail/TitleBar/index.vue +10 -11
- package/components/ResourceList/Masthead.vue +12 -8
- package/components/SelectIconGrid.vue +0 -10
- package/components/SingleClusterInfo.vue +1 -0
- package/components/SortableTable/__tests__/sorting.test.ts +126 -0
- package/components/SortableTable/index.vue +6 -9
- package/components/SortableTable/selection.js +23 -5
- package/components/SortableTable/sorting.js +6 -3
- package/components/Wizard.vue +14 -13
- package/components/fleet/FleetBundles.vue +100 -12
- package/components/fleet/FleetClusterTargets/index.vue +37 -15
- package/components/fleet/__tests__/FleetClusterTargets.test.ts +149 -115
- package/components/fleet/__tests__/FleetClusters.test.ts +12 -12
- package/components/form/LabeledSelect.vue +20 -3
- package/components/form/NameNsDescription.vue +11 -0
- package/components/form/Security.vue +6 -2
- package/components/form/WorkloadPorts.vue +2 -7
- package/components/form/__tests__/Security.test.ts +76 -0
- package/components/formatter/Autoscaler.vue +4 -4
- package/components/formatter/ClusterKubeVersion.vue +27 -0
- package/components/formatter/ClusterLink.vue +1 -7
- package/components/formatter/ClusterProvider.vue +6 -10
- package/components/formatter/FleetSummaryGraph.vue +0 -3
- package/components/formatter/MachineSummaryGraph.vue +1 -1
- package/components/formatter/PodsUsage.vue +2 -2
- package/components/formatter/__tests__/Autoscaler.test.ts +19 -22
- package/components/formatter/__tests__/FleetSummaryGraph.test.ts +216 -0
- package/components/formatter/__tests__/PodsUsage.test.ts +6 -10
- package/components/nav/NamespaceFilter.vue +2 -2
- package/components/nav/TopLevelMenu.helper.ts +15 -3
- package/components/nav/TopLevelMenu.vue +16 -5
- package/components/nav/__tests__/TopLevelMenu.test.ts +145 -21
- package/components/templates/home.vue +18 -0
- package/components/templates/plain.vue +18 -0
- package/components/templates/standalone.vue +17 -0
- package/composables/useFormValidation.ts +93 -0
- package/composables/useVeeValidateField.test.ts +159 -0
- package/composables/useVeeValidateField.ts +67 -0
- package/config/pagination-table-headers.js +18 -1
- package/config/product/manager.js +82 -21
- package/config/router/routes.js +6 -0
- package/config/table-headers.js +20 -1
- package/config/types.js +2 -1
- package/core/__tests__/plugin-products.test.ts +904 -20
- package/core/plugin-products-base.ts +107 -7
- package/core/plugin-products.ts +4 -0
- package/core/plugin-types.ts +111 -1
- package/core/plugin.ts +15 -7
- package/core/productDebugger.js +9 -4
- package/core/types-provisioning.ts +43 -30
- package/core/types.ts +57 -20
- package/detail/__tests__/pod.test.ts +41 -0
- package/detail/harvesterhci.io.management.cluster.vue +6 -2
- package/detail/pod.vue +1 -1
- package/detail/provisioning.cattle.io.cluster.vue +4 -10
- package/edit/auth/__tests__/azuread.test.ts +217 -34
- package/edit/auth/azuread.vue +122 -14
- package/edit/auth/oidc.vue +2 -2
- package/edit/networking.k8s.io.ingress/DefaultBackend.vue +13 -4
- package/edit/networking.k8s.io.ingress/RulePath.vue +8 -4
- package/edit/networking.k8s.io.ingress/index.vue +75 -20
- package/edit/provisioning.cattle.io.cluster/__tests__/MachinePool.test.ts +104 -0
- package/edit/provisioning.cattle.io.cluster/index.vue +11 -7
- package/edit/provisioning.cattle.io.cluster/rke2.vue +8 -4
- package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +11 -0
- package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs.vue +37 -4
- package/edit/provisioning.cattle.io.cluster/tabs/registries/__tests__/RegistryConfigs.test.ts +132 -7
- package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +2 -1
- package/edit/secret/__tests__/ssh.test.ts +5 -6
- package/edit/secret/basic.vue +31 -0
- package/edit/secret/index.vue +68 -17
- package/edit/secret/registry.vue +38 -0
- package/edit/secret/ssh.vue +29 -0
- package/edit/secret/tls.vue +30 -0
- package/edit/service.vue +4 -4
- package/edit/workload/Upgrading.vue +3 -3
- package/edit/workload/__tests__/Upgrading.test.ts +6 -9
- package/edit/workload/mixins/workload.js +2 -1
- package/list/fleet.cattle.io.bundle.vue +7 -104
- package/list/fleet.cattle.io.clusterregistrationtoken.vue +20 -0
- package/list/provisioning.cattle.io.cluster.vue +262 -180
- package/list/utils/management.cattle.io.cluster.utils.ts +128 -0
- package/mixins/__tests__/chart.test.ts +112 -0
- package/mixins/brand.js +2 -1
- package/mixins/chart.js +12 -8
- package/mixins/resource-fetch-api-pagination.js +41 -5
- package/models/__tests__/ext.cattle.io.kubeconfig.test.ts +67 -67
- package/models/__tests__/management.cattle.io.cluster.test.ts +1 -1
- package/models/__tests__/management.cattle.io.node.ts +6 -5
- package/models/__tests__/management.cattle.io.nodepool.ts +5 -4
- package/models/__tests__/provisioning.cattle.io.cluster.test.ts +32 -11
- package/models/base-cluster.x-k8s.io.js +26 -0
- package/models/cluster.js +1 -1
- package/models/cluster.x-k8s.io.machine.js +4 -22
- package/models/cluster.x-k8s.io.machinedeployment.js +2 -20
- package/models/cluster.x-k8s.io.machineset.js +2 -20
- package/models/compliance.cattle.io.clusterscan.js +130 -2
- package/models/ext.cattle.io.kubeconfig.ts +4 -7
- package/models/fleet-application.js +3 -1
- package/models/management.cattle.io.cluster.js +417 -40
- package/models/management.cattle.io.node.js +6 -4
- package/models/management.cattle.io.nodepool.js +1 -1
- package/models/networking.k8s.io.ingress.js +12 -4
- package/models/provisioning.cattle.io.cluster.js +47 -330
- package/models/rke.cattle.io.etcdsnapshot.js +1 -2
- package/package.json +11 -29
- package/pages/__tests__/readme.test.ts +49 -0
- package/pages/auth/setup.vue +2 -3
- package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +76 -0
- package/pages/c/_cluster/apps/charts/chart.vue +60 -8
- package/pages/c/_cluster/apps/charts/install.vue +10 -7
- package/pages/c/_cluster/explorer/__tests__/index.test.ts +23 -25
- package/pages/c/_cluster/explorer/index.vue +5 -49
- package/pages/c/_cluster/istio/__tests__/istio.index.test.ts +194 -0
- package/pages/c/_cluster/istio/index.vue +21 -6
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +1 -0
- package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +719 -2
- package/pages/c/_cluster/uiplugins/index.vue +203 -197
- package/pages/diagnostic.vue +13 -17
- package/pages/fail-whale.vue +18 -0
- package/pages/home.vue +77 -260
- package/pages/readme.vue +88 -0
- package/plugins/dashboard-store/__tests__/resource-class.test.ts +88 -0
- package/plugins/dashboard-store/actions.js +40 -18
- package/plugins/dashboard-store/resource-class.js +5 -2
- package/plugins/steve/__tests__/subscribe.spec.ts +6 -3
- package/plugins/steve/steve-pagination-utils.ts +11 -3
- package/plugins/steve/subscribe.js +35 -5
- package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +10 -4
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +7 -52
- package/rancher-components/RcButton/RcButton.test.ts +37 -1
- package/rancher-components/RcButton/RcButton.vue +38 -8
- package/rancher-components/RcDropdown/RcDropdownTrigger.vue +10 -8
- package/store/__tests__/catalog.test.ts +115 -1
- package/store/__tests__/type-map.test.ts +556 -1
- package/store/action-menu.js +8 -3
- package/store/auth.js +1 -1
- package/store/aws.js +27 -16
- package/store/catalog.js +27 -3
- package/store/digitalocean.js +20 -38
- package/store/index.js +2 -0
- package/store/linode.js +25 -40
- package/store/pnap.js +1 -0
- package/store/type-map.js +111 -29
- package/tsconfig.paths.json +8 -8
- package/types/kube/kube-api.ts +14 -1
- package/types/rancher/steve.api.ts +12 -12
- package/types/resources/settings.d.ts +2 -1
- package/types/shell/index.d.ts +102 -2
- package/types/store/dashboard-store.types.ts +108 -11
- package/types/store/pagination.types.ts +6 -3
- package/utils/__tests__/alertmanagerconfig.test.ts +117 -0
- package/utils/__tests__/async.test.ts +87 -0
- package/utils/__tests__/aws.test.ts +140 -0
- package/utils/__tests__/banners.test.ts +176 -0
- package/utils/__tests__/chart.test.ts +64 -1
- package/utils/__tests__/color.test.ts +226 -0
- package/utils/__tests__/duration.test.ts +140 -0
- package/utils/__tests__/fleet.test.ts +340 -0
- package/utils/__tests__/ingress.test.ts +553 -0
- package/utils/__tests__/kube.test.ts +68 -0
- package/utils/__tests__/namespace-filter.test.ts +109 -0
- package/utils/__tests__/pagination-utils.test.ts +361 -0
- package/utils/__tests__/parse-externalid.test.ts +137 -0
- package/utils/__tests__/perf-setting.utils.test.ts +98 -0
- package/utils/__tests__/poller-sequential.test.ts +177 -0
- package/utils/__tests__/poller.test.ts +170 -0
- package/utils/__tests__/promise.test.ts +346 -0
- package/utils/__tests__/settings.test.ts +140 -0
- package/utils/__tests__/sort-utils.test.ts +301 -0
- package/utils/__tests__/string-utils.test.ts +798 -0
- package/utils/__tests__/string.test.ts +23 -1
- package/utils/__tests__/style.test.ts +154 -0
- package/utils/__tests__/svg-filter.test.ts +184 -0
- package/utils/__tests__/units.test.ts +417 -0
- package/utils/__tests__/versions.test.ts +128 -0
- package/utils/__tests__/xccdf.test.ts +391 -0
- package/utils/chart.js +36 -0
- package/utils/fleet.ts +13 -3
- package/utils/gatekeeper/__tests__/util.test.ts +174 -0
- package/utils/gc/__tests__/gc-interval.test.ts +119 -0
- package/utils/gc/__tests__/gc-root-store.test.ts +225 -0
- package/utils/gc/__tests__/gc-route-changed.test.ts +96 -0
- package/utils/gc/__tests__/gc.test.ts +487 -0
- package/utils/ingress.ts +9 -1
- package/utils/pagination-utils.ts +2 -1
- package/utils/string.js +25 -2
- package/utils/uiplugins.ts +5 -5
- package/utils/validators/__tests__/cluster-name.test.ts +110 -0
- package/utils/validators/__tests__/cron-schedule.test.ts +79 -0
- package/utils/validators/__tests__/index.test.ts +481 -0
- package/utils/validators/__tests__/kubernetes-name.test.ts +163 -0
- package/utils/validators/__tests__/misc-validators.test.ts +246 -0
- package/utils/validators/__tests__/pod-affinity.test.ts +382 -0
- package/utils/validators/__tests__/prometheusrule.test.ts +211 -0
- package/utils/validators/__tests__/role-template.test.ts +149 -0
- package/utils/validators/__tests__/service.test.ts +283 -0
- package/utils/validators/__tests__/setting.test.js +32 -0
- package/utils/validators/formRules/__tests__/index.test.ts +50 -0
- package/utils/validators/formRules/index.ts +5 -5
- package/utils/validators/machine-pool.ts +1 -1
- package/utils/validators/setting.js +18 -3
- package/utils/xccdf.ts +418 -0
- package/assets/fonts/lato/lato-v17-latin-700.woff +0 -0
- package/assets/fonts/lato/lato-v17-latin-700.woff2 +0 -0
- package/assets/fonts/lato/lato-v17-latin-regular.woff +0 -0
- package/assets/fonts/lato/lato-v17-latin-regular.woff2 +0 -0
|
@@ -90,36 +90,36 @@ describe('component: FleetClusters', () => {
|
|
|
90
90
|
const wrapper = createWrapper();
|
|
91
91
|
const reposReady = wrapper.vm.headers.find((h: any) => h.name === 'reposReady');
|
|
92
92
|
|
|
93
|
-
expect(reposReady
|
|
94
|
-
expect(reposReady
|
|
95
|
-
expect(reposReady
|
|
93
|
+
expect(reposReady?.labelKey).toBe('tableHeaders.reposReady');
|
|
94
|
+
expect(reposReady?.value).toBe('status.readyGitRepos');
|
|
95
|
+
expect(reposReady?.search).toBe(false);
|
|
96
96
|
});
|
|
97
97
|
|
|
98
98
|
it('should configure helmOpsReady column correctly', () => {
|
|
99
99
|
const wrapper = createWrapper();
|
|
100
100
|
const helmOpsReady = wrapper.vm.headers.find((h: any) => h.name === 'helmOpsReady');
|
|
101
101
|
|
|
102
|
-
expect(helmOpsReady
|
|
103
|
-
expect(helmOpsReady
|
|
104
|
-
expect(helmOpsReady
|
|
102
|
+
expect(helmOpsReady?.labelKey).toBe('tableHeaders.helmOpsReady');
|
|
103
|
+
expect(helmOpsReady?.value).toBe('status.readyHelmOps');
|
|
104
|
+
expect(helmOpsReady?.search).toBe(false);
|
|
105
105
|
});
|
|
106
106
|
|
|
107
107
|
it('should configure bundlesReady column correctly', () => {
|
|
108
108
|
const wrapper = createWrapper();
|
|
109
109
|
const bundlesReady = wrapper.vm.headers.find((h: any) => h.name === 'bundlesReady');
|
|
110
110
|
|
|
111
|
-
expect(bundlesReady
|
|
112
|
-
expect(bundlesReady
|
|
113
|
-
expect(bundlesReady
|
|
111
|
+
expect(bundlesReady?.labelKey).toBe('tableHeaders.bundlesReady');
|
|
112
|
+
expect(bundlesReady?.value).toBe('status.display.readyBundles');
|
|
113
|
+
expect(bundlesReady?.search).toBe(false);
|
|
114
114
|
});
|
|
115
115
|
|
|
116
116
|
it('should configure lastSeen column with LiveDate formatter', () => {
|
|
117
117
|
const wrapper = createWrapper();
|
|
118
118
|
const lastSeen = wrapper.vm.headers.find((h: any) => h.name === 'lastSeen');
|
|
119
119
|
|
|
120
|
-
expect(lastSeen
|
|
121
|
-
expect(lastSeen
|
|
122
|
-
expect(lastSeen
|
|
120
|
+
expect(lastSeen?.formatter).toBe('LiveDate');
|
|
121
|
+
expect(lastSeen?.formatterOpts).toStrictEqual({ addSuffix: true });
|
|
122
|
+
expect(lastSeen?.width).toBe(120);
|
|
123
123
|
});
|
|
124
124
|
});
|
|
125
125
|
|
|
@@ -12,7 +12,8 @@ import { _VIEW } from '@shell/config/query-params';
|
|
|
12
12
|
import { useClickOutside } from '@shell/composables/useClickOutside';
|
|
13
13
|
import { useLabeledFormElement, labeledFormElementProps } from '@shell/composables/useLabeledFormElement';
|
|
14
14
|
import { useLabeledSelect } from '@shell/composables/useLabeledSelect';
|
|
15
|
-
import { ref } from 'vue';
|
|
15
|
+
import { ref, toRef } from 'vue';
|
|
16
|
+
import { useVeeValidateField } from '@shell/composables/useVeeValidateField';
|
|
16
17
|
|
|
17
18
|
export default {
|
|
18
19
|
name: 'LabeledSelect',
|
|
@@ -115,6 +116,11 @@ export default {
|
|
|
115
116
|
noOptionsLabelKey: {
|
|
116
117
|
type: String,
|
|
117
118
|
default: 'labelSelect.noOptions.empty'
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
name: {
|
|
122
|
+
type: String,
|
|
123
|
+
default: null
|
|
118
124
|
}
|
|
119
125
|
},
|
|
120
126
|
|
|
@@ -161,6 +167,13 @@ export default {
|
|
|
161
167
|
resizeHandlerFn(select);
|
|
162
168
|
};
|
|
163
169
|
|
|
170
|
+
const { effectiveValidationMessage, veeHandleBlur, veeValidate } = useVeeValidateField({
|
|
171
|
+
name: toRef(props, 'name'),
|
|
172
|
+
rules: toRef(props, 'rules'),
|
|
173
|
+
value: toRef(props, 'value'),
|
|
174
|
+
validationMessage,
|
|
175
|
+
});
|
|
176
|
+
|
|
164
177
|
return {
|
|
165
178
|
isOpen,
|
|
166
179
|
select,
|
|
@@ -172,7 +185,7 @@ export default {
|
|
|
172
185
|
onFocusLabeled,
|
|
173
186
|
onBlurLabeled,
|
|
174
187
|
isDisabled,
|
|
175
|
-
validationMessage,
|
|
188
|
+
validationMessage: effectiveValidationMessage,
|
|
176
189
|
requiredField,
|
|
177
190
|
isSearchable,
|
|
178
191
|
isFilterable,
|
|
@@ -186,6 +199,8 @@ export default {
|
|
|
186
199
|
paginating,
|
|
187
200
|
loadMore,
|
|
188
201
|
setPaginationFilter,
|
|
202
|
+
veeHandleBlur,
|
|
203
|
+
veeValidate,
|
|
189
204
|
};
|
|
190
205
|
},
|
|
191
206
|
|
|
@@ -221,7 +236,7 @@ export default {
|
|
|
221
236
|
// update placeholder text to inform user they can add their own opts when none are found
|
|
222
237
|
showTagPrompts() {
|
|
223
238
|
return !this.options.length && this.$attrs.taggable && this.isSearchable;
|
|
224
|
-
}
|
|
239
|
+
},
|
|
225
240
|
},
|
|
226
241
|
|
|
227
242
|
methods: {
|
|
@@ -272,6 +287,8 @@ export default {
|
|
|
272
287
|
this.$emit('on-blur');
|
|
273
288
|
this.selectedVisibility = 'visible';
|
|
274
289
|
this.onBlurLabeled();
|
|
290
|
+
this.veeHandleBlur(undefined, false);
|
|
291
|
+
this.veeValidate();
|
|
275
292
|
},
|
|
276
293
|
|
|
277
294
|
onOpen() {
|
|
@@ -164,6 +164,14 @@ export default {
|
|
|
164
164
|
}),
|
|
165
165
|
type: Object,
|
|
166
166
|
},
|
|
167
|
+
nameFieldName: {
|
|
168
|
+
type: String,
|
|
169
|
+
default: null,
|
|
170
|
+
},
|
|
171
|
+
namespaceFieldName: {
|
|
172
|
+
type: String,
|
|
173
|
+
default: null,
|
|
174
|
+
},
|
|
167
175
|
|
|
168
176
|
/**
|
|
169
177
|
* Inherited global identifier prefix for tests
|
|
@@ -438,6 +446,7 @@ export default {
|
|
|
438
446
|
<LabeledInput
|
|
439
447
|
ref="namespaceInput"
|
|
440
448
|
v-model:value="namespace"
|
|
449
|
+
:name="namespaceFieldName"
|
|
441
450
|
:label="t('namespace.label')"
|
|
442
451
|
:placeholder="t('namespace.createNamespace')"
|
|
443
452
|
:disabled="namespaceReallyDisabled"
|
|
@@ -464,6 +473,7 @@ export default {
|
|
|
464
473
|
<LabeledSelect
|
|
465
474
|
v-show="!createNamespace"
|
|
466
475
|
v-model:value="namespace"
|
|
476
|
+
:name="namespaceFieldName"
|
|
467
477
|
:clearable="true"
|
|
468
478
|
:options="options"
|
|
469
479
|
:disabled="namespaceReallyDisabled"
|
|
@@ -487,6 +497,7 @@ export default {
|
|
|
487
497
|
ref="nameInput"
|
|
488
498
|
key="name"
|
|
489
499
|
v-model:value="name"
|
|
500
|
+
:name="nameFieldName"
|
|
490
501
|
data-testid="NameNsDescriptionNameInput"
|
|
491
502
|
:label="t(nameLabel)"
|
|
492
503
|
:placeholder="t(namePlaceholder)"
|
|
@@ -140,11 +140,12 @@ export default {
|
|
|
140
140
|
this.afterPrivilegedTickedMessage = this.t('workload.container.security.privileged.afterTick.false');
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
-
|
|
143
|
+
// Drop empty values so we don't send a string for int64 fields.
|
|
144
|
+
if (securityContext.fsGroup === '' || securityContext.fsGroup === null || securityContext.fsGroup === undefined) {
|
|
144
145
|
delete securityContext.fsGroup;
|
|
145
146
|
}
|
|
146
147
|
|
|
147
|
-
if (securityContext.runAsUser === '') {
|
|
148
|
+
if (securityContext.runAsUser === '' || securityContext.runAsUser === null || securityContext.runAsUser === undefined) {
|
|
148
149
|
delete securityContext.runAsUser;
|
|
149
150
|
}
|
|
150
151
|
|
|
@@ -175,6 +176,7 @@ export default {
|
|
|
175
176
|
ref="firstFocusable"
|
|
176
177
|
v-model:value.number="securityContext.fsGroup"
|
|
177
178
|
type="number"
|
|
179
|
+
min="0"
|
|
178
180
|
:mode="mode"
|
|
179
181
|
:label="t('workload.container.security.fsGroup')"
|
|
180
182
|
@update:value="update"
|
|
@@ -283,6 +285,8 @@ export default {
|
|
|
283
285
|
</legend>
|
|
284
286
|
<LabeledInput
|
|
285
287
|
v-model:value.number="securityContext.runAsUser"
|
|
288
|
+
type="number"
|
|
289
|
+
min="0"
|
|
286
290
|
:label="t('workload.container.security.runAsUser.label')"
|
|
287
291
|
:mode="mode"
|
|
288
292
|
@update:value="update"
|
|
@@ -130,14 +130,11 @@ export default {
|
|
|
130
130
|
const version = this.provisioningCluster?.kubernetesVersion;
|
|
131
131
|
|
|
132
132
|
if (this.provisioningCluster?.isRke2) {
|
|
133
|
+
// This is a candidate for using the prov cluster provisioner (or now the mgmt cluster provisioner directly)
|
|
133
134
|
const machineSelectorConfig = this.provisioningCluster?.spec?.rkeConfig?.machineSelectorConfig || {};
|
|
134
135
|
const agentConfig = (machineSelectorConfig[0] || {}).config;
|
|
135
136
|
|
|
136
137
|
cloudProvider = agentConfig?.['cloud-provider-name'];
|
|
137
|
-
} else if (this.provisioningCluster?.isRke1) {
|
|
138
|
-
const currentCluster = this.$store.getters['currentCluster'];
|
|
139
|
-
|
|
140
|
-
cloudProvider = currentCluster?.spec?.rancherKubernetesEngineConfig?.cloudProvider?.name;
|
|
141
138
|
}
|
|
142
139
|
|
|
143
140
|
return cloudProvider === HARVESTER &&
|
|
@@ -145,9 +142,7 @@ export default {
|
|
|
145
142
|
},
|
|
146
143
|
|
|
147
144
|
provisioningCluster() {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
return out;
|
|
145
|
+
return this.$store.getters['management/byId'](CAPI.RANCHER_CLUSTER, this.currentCluster.provClusterId);
|
|
151
146
|
},
|
|
152
147
|
},
|
|
153
148
|
|
|
@@ -79,6 +79,42 @@ describe('component: Security', () => {
|
|
|
79
79
|
expect(wrapper.emitted('update:value')).toHaveLength(1);
|
|
80
80
|
});
|
|
81
81
|
|
|
82
|
+
// Regression: clearing runAsUser must drop the key from the emitted object.
|
|
83
|
+
// Otherwise the spec is sent with `runAsUser: ""` and the API rejects with
|
|
84
|
+
// "cannot unmarshal string ... of type int64". See issue #9601.
|
|
85
|
+
it('should omit runAsUser from the emitted value when the input is cleared', async() => {
|
|
86
|
+
const wrapper = mount(Security, {
|
|
87
|
+
props: {
|
|
88
|
+
mode: _EDIT, formType: FORM_TYPES.CONTAINER, value: { runAsUser: 33 }
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
const input = wrapper.find('[data-testid="input-security-runAsUser"]').find('input');
|
|
92
|
+
|
|
93
|
+
await input.setValue('');
|
|
94
|
+
|
|
95
|
+
const events = wrapper.emitted('update:value') ?? [];
|
|
96
|
+
const last = events[events.length - 1][0] as Record<string, unknown>;
|
|
97
|
+
|
|
98
|
+
expect(Object.prototype.hasOwnProperty.call(last, 'runAsUser')).toBe(false);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should omit runAsUser from the emitted value when it is undefined', async() => {
|
|
102
|
+
const wrapper = mount(Security, {
|
|
103
|
+
props: {
|
|
104
|
+
mode: _EDIT, formType: FORM_TYPES.CONTAINER, value: {}
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const checkbox = wrapper.find('[data-testid="input-security-runasNonRoot"]').find('label');
|
|
109
|
+
|
|
110
|
+
await checkbox.trigger('click');
|
|
111
|
+
|
|
112
|
+
const events = wrapper.emitted('update:value') ?? [];
|
|
113
|
+
const last = events[events.length - 1][0] as Record<string, unknown>;
|
|
114
|
+
|
|
115
|
+
expect(Object.prototype.hasOwnProperty.call(last, 'runAsUser')).toBe(false);
|
|
116
|
+
});
|
|
117
|
+
|
|
82
118
|
it.each([
|
|
83
119
|
'privileged',
|
|
84
120
|
'allowPrivilegeEscalation',
|
|
@@ -139,5 +175,45 @@ describe('component: Security', () => {
|
|
|
139
175
|
|
|
140
176
|
expect(wrapper.emitted('update:value')).toHaveLength(1);
|
|
141
177
|
});
|
|
178
|
+
|
|
179
|
+
it.each([
|
|
180
|
+
'runAsUser',
|
|
181
|
+
'fsGroup',
|
|
182
|
+
])('should omit %p from the emitted value when it is undefined', async(field) => {
|
|
183
|
+
const wrapper = mount(Security, {
|
|
184
|
+
props: {
|
|
185
|
+
mode: _EDIT, formType: FORM_TYPES.POD, value: {}
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
const checkbox = wrapper.find('[data-testid="input-security-runasNonRoot"]').find('label');
|
|
190
|
+
|
|
191
|
+
await checkbox.trigger('click');
|
|
192
|
+
|
|
193
|
+
const events = wrapper.emitted('update:value') ?? [];
|
|
194
|
+
const last = events[events.length - 1][0] as Record<string, unknown>;
|
|
195
|
+
|
|
196
|
+
expect(Object.prototype.hasOwnProperty.call(last, field)).toBe(false);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// Regression for #9601 — see equivalent container-level test above.
|
|
200
|
+
it.each([
|
|
201
|
+
['runAsUser', { runAsUser: 33 }],
|
|
202
|
+
['fsGroup', { fsGroup: 100 }],
|
|
203
|
+
])('should omit %p from the emitted value when the input is cleared', async(field, initial) => {
|
|
204
|
+
const wrapper = mount(Security, {
|
|
205
|
+
props: {
|
|
206
|
+
mode: _EDIT, formType: FORM_TYPES.POD, value: initial
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
const input = wrapper.find(`[data-testid="input-security-${ field }"]`).find('input');
|
|
210
|
+
|
|
211
|
+
await input.setValue('');
|
|
212
|
+
|
|
213
|
+
const events = wrapper.emitted('update:value') ?? [];
|
|
214
|
+
const last = events[events.length - 1][0] as Record<string, unknown>;
|
|
215
|
+
|
|
216
|
+
expect(Object.prototype.hasOwnProperty.call(last, field)).toBe(false);
|
|
217
|
+
});
|
|
142
218
|
});
|
|
143
219
|
});
|
|
@@ -21,8 +21,8 @@ const store = useStore();
|
|
|
21
21
|
const i18n = useI18n(store);
|
|
22
22
|
|
|
23
23
|
const checked = computed(() => props.value === true || props.value === 'true');
|
|
24
|
-
const actionIcon = computed(() => props.row.isAutoscalerPaused ? 'icon-play' : 'icon-pause');
|
|
25
|
-
const actionText = computed(() => props.row.isAutoscalerPaused ? i18n.t('autoscaler.card.resume') : i18n.t('autoscaler.card.pause'));
|
|
24
|
+
const actionIcon = computed(() => props.row.provCluster.isAutoscalerPaused ? 'icon-play' : 'icon-pause');
|
|
25
|
+
const actionText = computed(() => props.row.provCluster.isAutoscalerPaused ? i18n.t('autoscaler.card.resume') : i18n.t('autoscaler.card.pause'));
|
|
26
26
|
const stopPropagation = (event: Event) => {
|
|
27
27
|
// This is to prevent click events from getting to the table row which ends up selecting the row
|
|
28
28
|
event.stopPropagation();
|
|
@@ -45,7 +45,7 @@ const stopPropagation = (event: Event) => {
|
|
|
45
45
|
#heading-action="{close}"
|
|
46
46
|
>
|
|
47
47
|
<RcButton
|
|
48
|
-
v-if="row.canPauseResumeAutoscaler"
|
|
48
|
+
v-if="row.provCluster.canPauseResumeAutoscaler"
|
|
49
49
|
variant="secondary"
|
|
50
50
|
size="small"
|
|
51
51
|
class="action"
|
|
@@ -56,7 +56,7 @@ const stopPropagation = (event: Event) => {
|
|
|
56
56
|
</RcButton>
|
|
57
57
|
</template>
|
|
58
58
|
<template #card-body>
|
|
59
|
-
<AutoscalerCard :value="props.row" />
|
|
59
|
+
<AutoscalerCard :value="props.row.provCluster" />
|
|
60
60
|
</template>
|
|
61
61
|
</PopoverCard>
|
|
62
62
|
</span>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
name: 'ClusterKubeVersion',
|
|
5
|
+
|
|
6
|
+
props: {
|
|
7
|
+
row: {
|
|
8
|
+
type: Object,
|
|
9
|
+
default: null,
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<div>
|
|
17
|
+
<span>
|
|
18
|
+
{{ row.kubernetesVersion }}
|
|
19
|
+
</span>
|
|
20
|
+
<div
|
|
21
|
+
v-clean-tooltip="{content: row.architecture.tooltip, placement: 'left'}"
|
|
22
|
+
class="text-muted"
|
|
23
|
+
>
|
|
24
|
+
{{ row.architecture.label }}
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
</template>
|
|
@@ -31,7 +31,7 @@ export default {
|
|
|
31
31
|
return this.getCustomDetailLink(this.row);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
return this.row?.detailLocation;
|
|
34
|
+
return this.row?.provCluster?.detailLocation;
|
|
35
35
|
},
|
|
36
36
|
|
|
37
37
|
statusErrorConditions() {
|
|
@@ -77,12 +77,6 @@ export default {
|
|
|
77
77
|
class="conditions-alert-icon icon-alert icon"
|
|
78
78
|
data-testid="unavailable-machines-alert-icon"
|
|
79
79
|
/>
|
|
80
|
-
<i
|
|
81
|
-
v-if="row.isRke1"
|
|
82
|
-
v-clean-tooltip="t('cluster.rke1Unsupported')"
|
|
83
|
-
class="rke1-unsupported-icon icon-warning icon"
|
|
84
|
-
data-testid="rke1-unsupported-icon"
|
|
85
|
-
/>
|
|
86
80
|
<i
|
|
87
81
|
v-if="row.hasError && statusErrorConditions.length > 0"
|
|
88
82
|
v-clean-tooltip="{ content: `<div>${formattedConditions}</div>`, html: true }"
|
|
@@ -12,26 +12,22 @@ export default {
|
|
|
12
12
|
<template>
|
|
13
13
|
<div>
|
|
14
14
|
<template v-if="row.machineProvider">
|
|
15
|
-
<span v-if="row.isHarvester && row.
|
|
15
|
+
<span v-if="row.isHarvester && row.isReady && !row.hasError">
|
|
16
16
|
<a
|
|
17
|
-
v-if="row.mgmt.isReady && !row.hasError"
|
|
18
17
|
role="button"
|
|
19
18
|
@click="row.goToHarvesterCluster()"
|
|
20
19
|
>
|
|
21
20
|
{{ row.machineProviderDisplay }}
|
|
22
21
|
</a>
|
|
23
22
|
</span>
|
|
24
|
-
<span v-else>
|
|
23
|
+
<span v-else-if="row.machineProviderDisplay">
|
|
25
24
|
{{ row.machineProviderDisplay }}
|
|
26
25
|
</span>
|
|
27
26
|
</template>
|
|
28
|
-
<
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
{{ t('cluster.provider.custom') }}
|
|
33
|
-
</template>
|
|
34
|
-
<div class="text-muted">
|
|
27
|
+
<div
|
|
28
|
+
v-if="row.machineProviderDisplay !== row.provisionerDisplay"
|
|
29
|
+
class="text-muted"
|
|
30
|
+
>
|
|
35
31
|
{{ row.provisionerDisplay }}
|
|
36
32
|
</div>
|
|
37
33
|
</div>
|
|
@@ -26,9 +26,6 @@ export default {
|
|
|
26
26
|
if (this.clusterId) {
|
|
27
27
|
return this.row.statusResourceCountsForCluster(this.clusterId);
|
|
28
28
|
}
|
|
29
|
-
if (this.row.statusResourceCountsForCluster) {
|
|
30
|
-
return this.row.statusResourceCountsForCluster;
|
|
31
|
-
}
|
|
32
29
|
|
|
33
30
|
return this.row.status?.resourceCounts || {};
|
|
34
31
|
},
|
|
@@ -18,7 +18,7 @@ export default {
|
|
|
18
18
|
computed: {
|
|
19
19
|
ready() {
|
|
20
20
|
// Ensure we never show more ready machines than desired
|
|
21
|
-
// If
|
|
21
|
+
// If we can address in backend, we could revert this in the future
|
|
22
22
|
const ready = this.row?.ready || 0;
|
|
23
23
|
const desired = this.row?.desired || 0;
|
|
24
24
|
|
|
@@ -9,8 +9,8 @@ export default {
|
|
|
9
9
|
},
|
|
10
10
|
computed: {
|
|
11
11
|
podsUsage() {
|
|
12
|
-
const usedPods = this.row?.
|
|
13
|
-
const totalPods = this.row?.
|
|
12
|
+
const usedPods = this.row?.status?.requested?.pods;
|
|
13
|
+
const totalPods = this.row?.status?.allocatable?.pods;
|
|
14
14
|
|
|
15
15
|
if (!this.row?.isReady || !totalPods) {
|
|
16
16
|
return '—';
|
|
@@ -30,6 +30,10 @@ describe('component: formatter/Autoscaler.vue', () => {
|
|
|
30
30
|
stubs: {
|
|
31
31
|
PopoverCard: PopoverCardStub,
|
|
32
32
|
RcButton: { template: '<button><slot /></button>' },
|
|
33
|
+
// RcButton: {
|
|
34
|
+
// template: '<button><i v-if="icon" :class="icon" /><i v-if="leftIcon" :class="leftIcon" /><slot /></button>',
|
|
35
|
+
// props: ['icon', 'leftIcon']
|
|
36
|
+
// },
|
|
33
37
|
AutoscalerCard: {
|
|
34
38
|
name: 'AutoscalerCard',
|
|
35
39
|
props: ['value'],
|
|
@@ -88,30 +92,26 @@ describe('component: formatter/Autoscaler.vue', () => {
|
|
|
88
92
|
});
|
|
89
93
|
|
|
90
94
|
it('should render AutoscalerCard with correct row data', () => {
|
|
91
|
-
const
|
|
92
|
-
const wrapper = createWrapper({ value: true, row:
|
|
95
|
+
const provCluster = { id: 'test-row' };
|
|
96
|
+
const wrapper = createWrapper({ value: true, row: { provCluster } });
|
|
93
97
|
const card = wrapper.findComponent({ name: 'AutoscalerCard' });
|
|
94
98
|
|
|
95
99
|
expect(card.exists()).toBe(true);
|
|
96
|
-
expect(card.props('value')).toStrictEqual(
|
|
100
|
+
expect(card.props('value')).toStrictEqual(provCluster);
|
|
97
101
|
});
|
|
98
102
|
});
|
|
99
103
|
|
|
100
104
|
describe('heading action button', () => {
|
|
101
105
|
it('should NOT render if canExplore is false', () => {
|
|
102
|
-
const
|
|
103
|
-
const wrapper = createWrapper({ value: true, row:
|
|
106
|
+
const provCluster = { canExplore: false };
|
|
107
|
+
const wrapper = createWrapper({ value: true, row: { provCluster } });
|
|
104
108
|
|
|
105
109
|
expect(wrapper.find('button').exists()).toBe(false);
|
|
106
110
|
});
|
|
107
111
|
|
|
108
112
|
it('should render "Pause" button if autoscaler is running', () => {
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
};
|
|
112
|
-
const wrapper = createWrapper({
|
|
113
|
-
value: true, row: rowData, canPauseResumeAutoscaler: true
|
|
114
|
-
});
|
|
113
|
+
const provCluster = { isAutoscalerPaused: false, canPauseResumeAutoscaler: true };
|
|
114
|
+
const wrapper = createWrapper({ value: true, row: { canExplore: true, provCluster } });
|
|
115
115
|
const button = wrapper.find('button');
|
|
116
116
|
|
|
117
117
|
expect(button.exists()).toBe(true);
|
|
@@ -120,10 +120,8 @@ describe('component: formatter/Autoscaler.vue', () => {
|
|
|
120
120
|
});
|
|
121
121
|
|
|
122
122
|
it('should render "Resume" button if autoscaler is paused', () => {
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
};
|
|
126
|
-
const wrapper = createWrapper({ value: true, row: rowData });
|
|
123
|
+
const provCluster = { isAutoscalerPaused: true, canPauseResumeAutoscaler: true };
|
|
124
|
+
const wrapper = createWrapper({ value: true, row: { canExplore: true, provCluster } });
|
|
127
125
|
const button = wrapper.find('button');
|
|
128
126
|
|
|
129
127
|
expect(button.exists()).toBe(true);
|
|
@@ -132,20 +130,19 @@ describe('component: formatter/Autoscaler.vue', () => {
|
|
|
132
130
|
});
|
|
133
131
|
|
|
134
132
|
it('should hide "Resume" button if canPauseResumeAutoscaler is false', () => {
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
};
|
|
138
|
-
const wrapper = createWrapper({ value: true, row: rowData });
|
|
133
|
+
const provCluster = { isAutoscalerPaused: true, canPauseResumeAutoscaler: false };
|
|
134
|
+
const wrapper = createWrapper({ value: true, row: { canExplore: true, provCluster } });
|
|
139
135
|
const button = wrapper.find('button');
|
|
140
136
|
|
|
141
137
|
expect(button.exists()).toBe(false);
|
|
142
138
|
});
|
|
143
139
|
|
|
144
140
|
it('should call toggleAutoscalerRunner and close on click', async() => {
|
|
145
|
-
const
|
|
146
|
-
|
|
141
|
+
const provCluster = { canPauseResumeAutoscaler: true };
|
|
142
|
+
const mgmtCluster = {
|
|
143
|
+
toggleAutoscalerRunner: mockToggleRunner, canExplore: true, provCluster
|
|
147
144
|
};
|
|
148
|
-
const wrapper = createWrapper({ value: true, row:
|
|
145
|
+
const wrapper = createWrapper({ value: true, row: mgmtCluster });
|
|
149
146
|
|
|
150
147
|
wrapper.find('button').trigger('click');
|
|
151
148
|
|