@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
|
@@ -5,6 +5,12 @@ import CopyCode from '@shell/components/CopyCode';
|
|
|
5
5
|
import Tab from '@shell/components/Tabbed/Tab';
|
|
6
6
|
import { allHash } from '@shell/utils/promise';
|
|
7
7
|
|
|
8
|
+
// Couple of things wrong here
|
|
9
|
+
// 1. It should be in pkg/harvester-manager extension
|
|
10
|
+
// 2. It's not used when the harvester-ui extension is loaded
|
|
11
|
+
// - extension has it's own detail/harvesterhci.io.management.cluster.vue which supersedes this
|
|
12
|
+
// - unless harvester standalone uses it, it should not exist in the harvester-ui extension
|
|
13
|
+
|
|
8
14
|
export default {
|
|
9
15
|
emits: ['input'],
|
|
10
16
|
|
|
@@ -31,8 +37,6 @@ export default {
|
|
|
31
37
|
|
|
32
38
|
const res = await allHash(hash);
|
|
33
39
|
|
|
34
|
-
this.allNodes = res.allNodes || [];
|
|
35
|
-
this.allNodePools = res.allNodePools || [];
|
|
36
40
|
this.clusterToken = res.clusterToken;
|
|
37
41
|
},
|
|
38
42
|
|
package/detail/pod.vue
CHANGED
|
@@ -106,7 +106,7 @@ export default {
|
|
|
106
106
|
availableActions: this.value.containerActions,
|
|
107
107
|
stateObj: status, // Required if there's a description
|
|
108
108
|
stateDescription: descriptions.join(' | '), // Required to display the description
|
|
109
|
-
initIcon: this.value.containerIsInit(container) ? 'icon-checkmark
|
|
109
|
+
initIcon: this.value.containerIsInit(container) ? 'icon-checkmark text-success ml-5' : 'icon-minus text-muted ml-5',
|
|
110
110
|
|
|
111
111
|
// Call openShell here so that opening the shell
|
|
112
112
|
// at the container level still has 'this' in scope.
|
|
@@ -147,10 +147,6 @@ export default {
|
|
|
147
147
|
fetchOne.normanClusters = this.$store.dispatch('rancher/findAll', { type: NORMAN.CLUSTER });
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
-
if ( this.value.isRke1 && this.$store.getters['isRancher'] ) {
|
|
151
|
-
fetchOne.normanNodePools = this.$store.dispatch('rancher/findAll', { type: NORMAN.NODE_POOL });
|
|
152
|
-
}
|
|
153
|
-
|
|
154
150
|
const fetchOneRes = await allHash(fetchOne);
|
|
155
151
|
|
|
156
152
|
this.allMachines = fetchOneRes.machines || [];
|
|
@@ -203,10 +199,6 @@ export default {
|
|
|
203
199
|
if ( this.$store.getters['management/canList'](MANAGEMENT.RKE_TEMPLATE) ) {
|
|
204
200
|
this.$store.dispatch('management/findAll', { type: MANAGEMENT.RKE_TEMPLATE });
|
|
205
201
|
}
|
|
206
|
-
|
|
207
|
-
if ( this.$store.getters['management/canList'](MANAGEMENT.RKE_TEMPLATE_REVISION) ) {
|
|
208
|
-
this.$store.dispatch('management/findAll', { type: MANAGEMENT.RKE_TEMPLATE_REVISION });
|
|
209
|
-
}
|
|
210
202
|
},
|
|
211
203
|
|
|
212
204
|
created() {
|
|
@@ -284,9 +276,11 @@ export default {
|
|
|
284
276
|
extCustomParams: null,
|
|
285
277
|
extDetailTabs: {
|
|
286
278
|
machines: true, // in this component
|
|
279
|
+
nodes: true, // in this component
|
|
287
280
|
logs: true, // in this component
|
|
288
281
|
registration: true, // in this component
|
|
289
282
|
snapshots: true, // in this component
|
|
283
|
+
autoscaler: true, // in this component
|
|
290
284
|
related: true, // in ResourceTabs
|
|
291
285
|
events: true, // in ResourceTabs
|
|
292
286
|
conditions: true, // in ResourceTabs
|
|
@@ -451,7 +445,7 @@ export default {
|
|
|
451
445
|
},
|
|
452
446
|
|
|
453
447
|
showNodes() {
|
|
454
|
-
return !this.showMachines && this.haveNodes && !!this.nodes.length && this.extDetailTabs.
|
|
448
|
+
return !this.showMachines && this.haveNodes && !!this.nodes.length && this.extDetailTabs.nodes;
|
|
455
449
|
},
|
|
456
450
|
|
|
457
451
|
showSnapshots() {
|
|
@@ -628,7 +622,7 @@ export default {
|
|
|
628
622
|
},
|
|
629
623
|
|
|
630
624
|
showAutoScalerTab() {
|
|
631
|
-
return isAutoscalerFeatureFlagEnabled(this.$store) && this.value.hasAccessToAutoscalerConfigMap;
|
|
625
|
+
return isAutoscalerFeatureFlagEnabled(this.$store) && this.value.hasAccessToAutoscalerConfigMap && this.extDetailTabs.autoscaler;
|
|
632
626
|
}
|
|
633
627
|
},
|
|
634
628
|
|
|
@@ -3,6 +3,7 @@ import { nextTick } from 'vue';
|
|
|
3
3
|
import { mount } from '@vue/test-utils';
|
|
4
4
|
import AzureAD from '@shell/edit/auth/azuread.vue';
|
|
5
5
|
import { _EDIT } from '@shell/config/query-params';
|
|
6
|
+
import { SLO_OPTION_VALUES } from '@shell/mixins/auth-config';
|
|
6
7
|
|
|
7
8
|
jest.mock('@shell/utils/clipboard', () => {
|
|
8
9
|
return { copyTextToClipboard: jest.fn(() => Promise.resolve({})) };
|
|
@@ -28,43 +29,44 @@ const mockModel = {
|
|
|
28
29
|
type: 'azureADConfig',
|
|
29
30
|
};
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
'i18n/t': (val: string) => val,
|
|
55
|
-
'i18n/exists': jest.fn(),
|
|
56
|
-
},
|
|
57
|
-
dispatch: jest.fn()
|
|
32
|
+
const requiredSetup = (modelOverrides = {}) => ({
|
|
33
|
+
data() {
|
|
34
|
+
return {
|
|
35
|
+
isEnabling: true,
|
|
36
|
+
editConfig: false,
|
|
37
|
+
model: { ...mockModel, ...modelOverrides },
|
|
38
|
+
serverSetting: null,
|
|
39
|
+
errors: [],
|
|
40
|
+
originalModel: null,
|
|
41
|
+
principals: [],
|
|
42
|
+
authConfigName: 'azuread',
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
global: {
|
|
46
|
+
mocks: {
|
|
47
|
+
$fetchState: { pending: false },
|
|
48
|
+
$store: {
|
|
49
|
+
getters: {
|
|
50
|
+
currentStore: () => 'current_store',
|
|
51
|
+
'current_store/schemaFor': jest.fn(),
|
|
52
|
+
'current_store/all': jest.fn(),
|
|
53
|
+
'i18n/t': (val: string) => val,
|
|
54
|
+
'i18n/exists': jest.fn(),
|
|
58
55
|
},
|
|
59
|
-
|
|
60
|
-
$router: { applyQuery: jest.fn() },
|
|
56
|
+
dispatch: jest.fn()
|
|
61
57
|
},
|
|
58
|
+
$route: { query: { AS: '' }, params: { id: 'azure' } },
|
|
59
|
+
$router: { applyQuery: jest.fn() },
|
|
62
60
|
},
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
61
|
+
},
|
|
62
|
+
propsData: {
|
|
63
|
+
value: { applicationSecret: '' },
|
|
64
|
+
mode: _EDIT,
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe('edit: azureAD should', () => {
|
|
69
|
+
let wrapper: any;
|
|
68
70
|
|
|
69
71
|
beforeEach(() => {
|
|
70
72
|
wrapper = mount(AzureAD, { ...requiredSetup() });
|
|
@@ -236,3 +238,184 @@ describe('edit: azureAD should', () => {
|
|
|
236
238
|
expect(saveButton.disabled).toBe(testCase.result);
|
|
237
239
|
});
|
|
238
240
|
});
|
|
241
|
+
|
|
242
|
+
describe('edit: azureAD SSO logout should', () => {
|
|
243
|
+
let wrapper: any;
|
|
244
|
+
|
|
245
|
+
afterEach(() => {
|
|
246
|
+
wrapper.unmount();
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it('not render SLO section when logoutAllSupported is false', () => {
|
|
250
|
+
wrapper = mount(AzureAD, { ...requiredSetup({ logoutAllSupported: false }) });
|
|
251
|
+
const sloSection = wrapper.find('[data-testid="azuread-sloType"]');
|
|
252
|
+
|
|
253
|
+
expect(sloSection.exists()).toBe(false);
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it('render SLO section when logoutAllSupported is true', async() => {
|
|
257
|
+
wrapper = mount(AzureAD, { ...requiredSetup({ logoutAllSupported: true }) });
|
|
258
|
+
await nextTick();
|
|
259
|
+
const sloSection = wrapper.find('[data-testid="azuread-sloType"]');
|
|
260
|
+
|
|
261
|
+
expect(sloSection.exists()).toBe(true);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
it('not render endSessionEndpoint field when sloType is rancher', async() => {
|
|
265
|
+
wrapper = mount(AzureAD, {
|
|
266
|
+
...requiredSetup({ logoutAllSupported: true }),
|
|
267
|
+
data() {
|
|
268
|
+
return {
|
|
269
|
+
...requiredSetup({ logoutAllSupported: true }).data(),
|
|
270
|
+
sloType: SLO_OPTION_VALUES.rancher,
|
|
271
|
+
};
|
|
272
|
+
},
|
|
273
|
+
});
|
|
274
|
+
await nextTick();
|
|
275
|
+
const endSessionEndpointField = wrapper.find('[data-testid="azuread-endSessionEndpoint"]');
|
|
276
|
+
|
|
277
|
+
expect(endSessionEndpointField.exists()).toBe(false);
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
it('render endSessionEndpoint field when sloType is all', async() => {
|
|
281
|
+
wrapper = mount(AzureAD, {
|
|
282
|
+
...requiredSetup({ logoutAllSupported: true }),
|
|
283
|
+
data() {
|
|
284
|
+
return {
|
|
285
|
+
...requiredSetup({ logoutAllSupported: true }).data(),
|
|
286
|
+
sloType: SLO_OPTION_VALUES.all,
|
|
287
|
+
};
|
|
288
|
+
},
|
|
289
|
+
});
|
|
290
|
+
await nextTick();
|
|
291
|
+
const endSessionEndpointField = wrapper.find('[data-testid="azuread-endSessionEndpoint"]');
|
|
292
|
+
|
|
293
|
+
expect(endSessionEndpointField.exists()).toBe(true);
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it('render endSessionEndpoint field when sloType is both', async() => {
|
|
297
|
+
wrapper = mount(AzureAD, {
|
|
298
|
+
...requiredSetup({ logoutAllSupported: true }),
|
|
299
|
+
data() {
|
|
300
|
+
return {
|
|
301
|
+
...requiredSetup({ logoutAllSupported: true }).data(),
|
|
302
|
+
sloType: SLO_OPTION_VALUES.both,
|
|
303
|
+
};
|
|
304
|
+
},
|
|
305
|
+
});
|
|
306
|
+
await nextTick();
|
|
307
|
+
const endSessionEndpointField = wrapper.find('[data-testid="azuread-endSessionEndpoint"]');
|
|
308
|
+
|
|
309
|
+
expect(endSessionEndpointField.exists()).toBe(true);
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
it.each([
|
|
313
|
+
{
|
|
314
|
+
sloType: SLO_OPTION_VALUES.all, endSessionEndpoint: '', disabled: true
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
sloType: SLO_OPTION_VALUES.all, endSessionEndpoint: 'not-a-url', disabled: true
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
sloType: SLO_OPTION_VALUES.all, endSessionEndpoint: 'https://login.microsoftonline.com/tenant/oauth2/v2.0/logout', disabled: false
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
sloType: SLO_OPTION_VALUES.both, endSessionEndpoint: '', disabled: true
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
sloType: SLO_OPTION_VALUES.both, endSessionEndpoint: 'https://login.microsoftonline.com/tenant/oauth2/v2.0/logout', disabled: false
|
|
327
|
+
},
|
|
328
|
+
])('has save button disabled=$disabled when sloType=$sloType and endSessionEndpoint=$endSessionEndpoint', async(testCase) => {
|
|
329
|
+
wrapper = mount(AzureAD, {
|
|
330
|
+
...requiredSetup({
|
|
331
|
+
logoutAllSupported: true,
|
|
332
|
+
tenantId: validTenantId,
|
|
333
|
+
applicationId: validApplicationId,
|
|
334
|
+
applicationSecret: validAppSecret,
|
|
335
|
+
endSessionEndpoint: testCase.endSessionEndpoint,
|
|
336
|
+
}),
|
|
337
|
+
data() {
|
|
338
|
+
return {
|
|
339
|
+
isEnabling: true,
|
|
340
|
+
editConfig: false,
|
|
341
|
+
model: {
|
|
342
|
+
...mockModel,
|
|
343
|
+
logoutAllSupported: true,
|
|
344
|
+
tenantId: validTenantId,
|
|
345
|
+
applicationId: validApplicationId,
|
|
346
|
+
applicationSecret: validAppSecret,
|
|
347
|
+
graphEndpoint: validGraphEndpoint,
|
|
348
|
+
tokenEndpoint: validTokenEndpoint,
|
|
349
|
+
authEndpoint: validAuthEndpoint,
|
|
350
|
+
endSessionEndpoint: testCase.endSessionEndpoint,
|
|
351
|
+
},
|
|
352
|
+
sloType: testCase.sloType,
|
|
353
|
+
serverSetting: null,
|
|
354
|
+
errors: [],
|
|
355
|
+
originalModel: null,
|
|
356
|
+
principals: [],
|
|
357
|
+
authConfigName: 'azuread',
|
|
358
|
+
};
|
|
359
|
+
},
|
|
360
|
+
});
|
|
361
|
+
await nextTick();
|
|
362
|
+
const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
|
|
363
|
+
|
|
364
|
+
expect(saveButton.disabled).toBe(testCase.disabled);
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
it('sets logoutAllEnabled=false and logoutAllForced=false when sloType changes to rancher', async() => {
|
|
368
|
+
wrapper = mount(AzureAD, {
|
|
369
|
+
...requiredSetup({ logoutAllSupported: true }),
|
|
370
|
+
data() {
|
|
371
|
+
return {
|
|
372
|
+
...requiredSetup({ logoutAllSupported: true }).data(),
|
|
373
|
+
sloType: SLO_OPTION_VALUES.all,
|
|
374
|
+
};
|
|
375
|
+
},
|
|
376
|
+
});
|
|
377
|
+
await nextTick();
|
|
378
|
+
wrapper.vm.sloType = SLO_OPTION_VALUES.rancher;
|
|
379
|
+
await nextTick();
|
|
380
|
+
|
|
381
|
+
expect(wrapper.vm.model.logoutAllEnabled).toBe(false);
|
|
382
|
+
expect(wrapper.vm.model.logoutAllForced).toBe(false);
|
|
383
|
+
expect(wrapper.vm.model.endSessionEndpoint).toBe('');
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
it('sets logoutAllEnabled=true and logoutAllForced=true when sloType changes to all', async() => {
|
|
387
|
+
wrapper = mount(AzureAD, {
|
|
388
|
+
...requiredSetup({ logoutAllSupported: true }),
|
|
389
|
+
data() {
|
|
390
|
+
return {
|
|
391
|
+
...requiredSetup({ logoutAllSupported: true }).data(),
|
|
392
|
+
sloType: SLO_OPTION_VALUES.rancher,
|
|
393
|
+
};
|
|
394
|
+
},
|
|
395
|
+
});
|
|
396
|
+
await nextTick();
|
|
397
|
+
wrapper.vm.sloType = SLO_OPTION_VALUES.all;
|
|
398
|
+
await nextTick();
|
|
399
|
+
|
|
400
|
+
expect(wrapper.vm.model.logoutAllEnabled).toBe(true);
|
|
401
|
+
expect(wrapper.vm.model.logoutAllForced).toBe(true);
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
it('sets logoutAllEnabled=true and logoutAllForced=false when sloType changes to both', async() => {
|
|
405
|
+
wrapper = mount(AzureAD, {
|
|
406
|
+
...requiredSetup({ logoutAllSupported: true }),
|
|
407
|
+
data() {
|
|
408
|
+
return {
|
|
409
|
+
...requiredSetup({ logoutAllSupported: true }).data(),
|
|
410
|
+
sloType: SLO_OPTION_VALUES.rancher,
|
|
411
|
+
};
|
|
412
|
+
},
|
|
413
|
+
});
|
|
414
|
+
await nextTick();
|
|
415
|
+
wrapper.vm.sloType = SLO_OPTION_VALUES.both;
|
|
416
|
+
await nextTick();
|
|
417
|
+
|
|
418
|
+
expect(wrapper.vm.model.logoutAllEnabled).toBe(true);
|
|
419
|
+
expect(wrapper.vm.model.logoutAllForced).toBe(false);
|
|
420
|
+
});
|
|
421
|
+
});
|
package/edit/auth/azuread.vue
CHANGED
|
@@ -11,7 +11,7 @@ import { Checkbox } from '@components/Form/Checkbox';
|
|
|
11
11
|
import AuthBanner from '@shell/components/auth/AuthBanner';
|
|
12
12
|
import CopyToClipboardText from '@shell/components/CopyToClipboardText.vue';
|
|
13
13
|
import AllowedPrincipals from '@shell/components/auth/AllowedPrincipals';
|
|
14
|
-
import AuthConfig from '@shell/mixins/auth-config';
|
|
14
|
+
import AuthConfig, { SLO_OPTION_VALUES } from '@shell/mixins/auth-config';
|
|
15
15
|
import { AZURE_MIGRATED } from '@shell/config/labels-annotations';
|
|
16
16
|
import { get } from '@shell/utils/object';
|
|
17
17
|
import AuthProviderWarningBanners from '@shell/edit/auth/AuthProviderWarningBanners';
|
|
@@ -76,6 +76,8 @@ export default {
|
|
|
76
76
|
if ( this.value?.graphEndpoint ) {
|
|
77
77
|
this.setInitialEndpoint(this.value.graphEndpoint);
|
|
78
78
|
}
|
|
79
|
+
|
|
80
|
+
await this.mixinFetch();
|
|
79
81
|
},
|
|
80
82
|
|
|
81
83
|
data() {
|
|
@@ -83,6 +85,7 @@ export default {
|
|
|
83
85
|
isGroupMembershipFilterEnabled: !!this.value.groupMembershipFilter,
|
|
84
86
|
endpoint: 'standard',
|
|
85
87
|
oldEndpoint: false,
|
|
88
|
+
SLO_OPTION_VALUES,
|
|
86
89
|
|
|
87
90
|
// Storing the applicationSecret is necessary because norman doesn't support returning secrets and when we
|
|
88
91
|
// override the steve authconfig with a norman config the applicationSecret is lost
|
|
@@ -95,6 +98,7 @@ export default {
|
|
|
95
98
|
{ path: 'graphEndpoint', rules: ['graphEndpointRequired', 'graphEndpointMustBeURL'] },
|
|
96
99
|
{ path: 'tokenEndpoint', rules: ['tokenEndpointRequired', 'tokenEndpointMustBeURL'] },
|
|
97
100
|
{ path: 'authEndpoint', rules: ['authEndpointRequired', 'authEndpointMustBeURL'] },
|
|
101
|
+
{ path: 'endSessionEndpoint', rules: ['endSessionEndpointRequiredAndValid'] },
|
|
98
102
|
]
|
|
99
103
|
};
|
|
100
104
|
},
|
|
@@ -103,17 +107,18 @@ export default {
|
|
|
103
107
|
// Cannot pass this.model as a rootObject because it is undefined at that point, so had to use a workaround
|
|
104
108
|
fvExtraRules() {
|
|
105
109
|
return {
|
|
106
|
-
tenantIdRequired:
|
|
107
|
-
applicationIdRequired:
|
|
108
|
-
applicationSecretRequired:
|
|
109
|
-
endpointRequired:
|
|
110
|
-
endpointMustBeURL:
|
|
111
|
-
graphEndpointRequired:
|
|
112
|
-
graphEndpointMustBeURL:
|
|
113
|
-
tokenEndpointRequired:
|
|
114
|
-
tokenEndpointMustBeURL:
|
|
115
|
-
authEndpointRequired:
|
|
116
|
-
authEndpointMustBeURL:
|
|
110
|
+
tenantIdRequired: this.modelFieldRequired('tenantId', 'authConfig.azuread.tenantId.label'),
|
|
111
|
+
applicationIdRequired: this.modelFieldRequired('applicationId', 'authConfig.azuread.applicationId.label'),
|
|
112
|
+
applicationSecretRequired: this.applicationSecretRequired(),
|
|
113
|
+
endpointRequired: this.modelFieldRequired('endpoint', 'authConfig.azuread.endpoint.label'),
|
|
114
|
+
endpointMustBeURL: this.modelFieldURL('endpoint'),
|
|
115
|
+
graphEndpointRequired: this.modelFieldRequired('graphEndpoint', 'authConfig.azuread.graphEndpoint.label'),
|
|
116
|
+
graphEndpointMustBeURL: this.modelFieldURL('graphEndpoint'),
|
|
117
|
+
tokenEndpointRequired: this.modelFieldRequired('tokenEndpoint', 'authConfig.azuread.tokenEndpoint.label'),
|
|
118
|
+
tokenEndpointMustBeURL: this.modelFieldURL('tokenEndpoint'),
|
|
119
|
+
authEndpointRequired: this.modelFieldRequired('authEndpoint', 'authConfig.azuread.authEndpoint.label'),
|
|
120
|
+
authEndpointMustBeURL: this.modelFieldURL('authEndpoint'),
|
|
121
|
+
endSessionEndpointRequiredAndValid: this.endSessionEndpointRule(),
|
|
117
122
|
};
|
|
118
123
|
},
|
|
119
124
|
|
|
@@ -165,7 +170,29 @@ export default {
|
|
|
165
170
|
},
|
|
166
171
|
editMemberConfig() {
|
|
167
172
|
return this.model.enabled && !this.isEnabling && !this.editConfig;
|
|
168
|
-
}
|
|
173
|
+
},
|
|
174
|
+
|
|
175
|
+
isLogoutAllSupported() {
|
|
176
|
+
return this.model?.logoutAllSupported;
|
|
177
|
+
},
|
|
178
|
+
|
|
179
|
+
sloOptions() {
|
|
180
|
+
return [
|
|
181
|
+
{ value: SLO_OPTION_VALUES.rancher, label: this.t('authConfig.slo.sloOptions.onlyRancher', { name: this.model?.nameDisplay }) },
|
|
182
|
+
{ value: SLO_OPTION_VALUES.all, label: this.t('authConfig.slo.sloOptions.logoutAll', { name: this.model?.nameDisplay }) },
|
|
183
|
+
{ value: SLO_OPTION_VALUES.both, label: this.t('authConfig.slo.sloOptions.choose') },
|
|
184
|
+
];
|
|
185
|
+
},
|
|
186
|
+
|
|
187
|
+
sloTypeText() {
|
|
188
|
+
const sloOptionSelected = this.sloOptions.find((item) => item.value === this.sloType);
|
|
189
|
+
|
|
190
|
+
return sloOptionSelected?.label || '';
|
|
191
|
+
},
|
|
192
|
+
|
|
193
|
+
sloEndSessionEndpointUiEnabled() {
|
|
194
|
+
return this.sloType === SLO_OPTION_VALUES.all || this.sloType === SLO_OPTION_VALUES.both;
|
|
195
|
+
},
|
|
169
196
|
},
|
|
170
197
|
|
|
171
198
|
watch: {
|
|
@@ -179,6 +206,25 @@ export default {
|
|
|
179
206
|
}
|
|
180
207
|
},
|
|
181
208
|
|
|
209
|
+
// sloType is defined on shell/mixins/auth-config.js
|
|
210
|
+
sloType(neu) {
|
|
211
|
+
switch (neu) {
|
|
212
|
+
case SLO_OPTION_VALUES.rancher:
|
|
213
|
+
this.model.logoutAllEnabled = false;
|
|
214
|
+
this.model.logoutAllForced = false;
|
|
215
|
+
this.model.endSessionEndpoint = '';
|
|
216
|
+
break;
|
|
217
|
+
case SLO_OPTION_VALUES.all:
|
|
218
|
+
this.model.logoutAllEnabled = true;
|
|
219
|
+
this.model.logoutAllForced = true;
|
|
220
|
+
break;
|
|
221
|
+
case SLO_OPTION_VALUES.both:
|
|
222
|
+
this.model.logoutAllEnabled = true;
|
|
223
|
+
this.model.logoutAllForced = false;
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
|
|
182
228
|
model: {
|
|
183
229
|
deep: true,
|
|
184
230
|
handler() {
|
|
@@ -294,7 +340,21 @@ export default {
|
|
|
294
340
|
|
|
295
341
|
return rule(this.model[path]);
|
|
296
342
|
};
|
|
297
|
-
}
|
|
343
|
+
},
|
|
344
|
+
|
|
345
|
+
endSessionEndpointRule() {
|
|
346
|
+
return () => {
|
|
347
|
+
if (!this.isLogoutAllSupported || !this.sloEndSessionEndpointUiEnabled) {
|
|
348
|
+
return undefined;
|
|
349
|
+
}
|
|
350
|
+
if (!this.model.endSessionEndpoint) {
|
|
351
|
+
return this.t('validation.required', { key: this.t('authConfig.azuread.endSessionEndpoint.title') });
|
|
352
|
+
}
|
|
353
|
+
const rule = formRulesGenerator(this.$store.getters['i18n/t'], {}).url;
|
|
354
|
+
|
|
355
|
+
return rule(this.model.endSessionEndpoint);
|
|
356
|
+
};
|
|
357
|
+
},
|
|
298
358
|
}
|
|
299
359
|
};
|
|
300
360
|
</script>
|
|
@@ -348,6 +408,14 @@ export default {
|
|
|
348
408
|
<td>{{ t(`authConfig.azuread.authEndpoint.label`) }}:</td>
|
|
349
409
|
<td>{{ model.authEndpoint }}</td>
|
|
350
410
|
</tr>
|
|
411
|
+
<tr v-if="isLogoutAllSupported">
|
|
412
|
+
<td>{{ t('authConfig.slo.sloTitle') }}:</td>
|
|
413
|
+
<td>{{ sloTypeText }}</td>
|
|
414
|
+
</tr>
|
|
415
|
+
<tr v-if="isLogoutAllSupported && sloEndSessionEndpointUiEnabled">
|
|
416
|
+
<td>{{ t('authConfig.azuread.endSessionEndpoint.title') }}:</td>
|
|
417
|
+
<td>{{ model.endSessionEndpoint }}</td>
|
|
418
|
+
</tr>
|
|
351
419
|
</template>
|
|
352
420
|
<template
|
|
353
421
|
v-if="needsUpdate"
|
|
@@ -521,6 +589,46 @@ export default {
|
|
|
521
589
|
</div>
|
|
522
590
|
</div>
|
|
523
591
|
</div>
|
|
592
|
+
|
|
593
|
+
<!-- SLO logout -->
|
|
594
|
+
<div
|
|
595
|
+
v-if="isLogoutAllSupported"
|
|
596
|
+
class="mb-20"
|
|
597
|
+
>
|
|
598
|
+
<div class="row">
|
|
599
|
+
<div class="col span-12">
|
|
600
|
+
<h3>{{ t('authConfig.slo.sloTitle') }}</h3>
|
|
601
|
+
</div>
|
|
602
|
+
</div>
|
|
603
|
+
<div class="row">
|
|
604
|
+
<div class="col span-4">
|
|
605
|
+
<RadioGroup
|
|
606
|
+
v-model:value="sloType"
|
|
607
|
+
:mode="mode"
|
|
608
|
+
:options="sloOptions"
|
|
609
|
+
:disabled="!model.logoutAllSupported"
|
|
610
|
+
name="sloTypeRadio"
|
|
611
|
+
data-testid="azuread-sloType"
|
|
612
|
+
/>
|
|
613
|
+
</div>
|
|
614
|
+
</div>
|
|
615
|
+
<div
|
|
616
|
+
v-if="sloEndSessionEndpointUiEnabled"
|
|
617
|
+
class="row mt-20"
|
|
618
|
+
>
|
|
619
|
+
<div class="col span-6">
|
|
620
|
+
<LabeledInput
|
|
621
|
+
v-model:value="model.endSessionEndpoint"
|
|
622
|
+
:tooltip="t('authConfig.azuread.endSessionEndpoint.tooltip', { tenantId: `${ tenantId || 'tenant-id' }` }, true)"
|
|
623
|
+
:label="t('authConfig.azuread.endSessionEndpoint.title')"
|
|
624
|
+
:mode="mode"
|
|
625
|
+
:rules="fvGetAndReportPathRules('endSessionEndpoint')"
|
|
626
|
+
:required="true"
|
|
627
|
+
data-testid="azuread-endSessionEndpoint"
|
|
628
|
+
/>
|
|
629
|
+
</div>
|
|
630
|
+
</div>
|
|
631
|
+
</div>
|
|
524
632
|
</template>
|
|
525
633
|
</CruResource>
|
|
526
634
|
</div>
|
package/edit/auth/oidc.vue
CHANGED
|
@@ -15,7 +15,7 @@ import { RadioGroup } from '@components/Form/Radio';
|
|
|
15
15
|
import { Checkbox } from '@components/Form/Checkbox';
|
|
16
16
|
import { BASE_SCOPES } from '@shell/store/auth';
|
|
17
17
|
import CopyToClipboardText from '@shell/components/CopyToClipboardText.vue';
|
|
18
|
-
import
|
|
18
|
+
import { isValidUrl } from '@shell/utils/validators/setting';
|
|
19
19
|
|
|
20
20
|
const PKCE_S256 = 'S256';
|
|
21
21
|
|
|
@@ -105,7 +105,7 @@ export default {
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
// make sure that if SLO options are enabled on radio group, field "endSessionEndpoint" is required
|
|
108
|
-
if (this.isLogoutAllSupported && this.sloEndSessionEndpointUiEnabled && (!this.model.endSessionEndpoint || !
|
|
108
|
+
if (this.isLogoutAllSupported && this.sloEndSessionEndpointUiEnabled && (!this.model.endSessionEndpoint || !isValidUrl(this.model.endSessionEndpoint))) {
|
|
109
109
|
return false;
|
|
110
110
|
}
|
|
111
111
|
|
|
@@ -43,7 +43,9 @@ export default {
|
|
|
43
43
|
const backend = get(this.value.spec, this.value.defaultBackendPath);
|
|
44
44
|
|
|
45
45
|
this.serviceName = get(backend, this.value.serviceNamePath) || '';
|
|
46
|
-
this.servicePort = get(backend, this.value.servicePortPath) ||
|
|
46
|
+
this.servicePort = get(backend, this.value.servicePortPath) ||
|
|
47
|
+
get(backend, this.value.servicePortNamePath) ||
|
|
48
|
+
'';
|
|
47
49
|
},
|
|
48
50
|
computed: {
|
|
49
51
|
isView() {
|
|
@@ -75,10 +77,14 @@ export default {
|
|
|
75
77
|
},
|
|
76
78
|
methods: {
|
|
77
79
|
update() {
|
|
78
|
-
|
|
80
|
+
// Fresh object so the old port path (name vs number) doesn't linger.
|
|
81
|
+
const backend = {};
|
|
82
|
+
const parsed = Number.parseInt(this.servicePort);
|
|
83
|
+
const servicePort = Number.isNaN(parsed) ? this.servicePort : parsed;
|
|
84
|
+
const portPath = typeof servicePort === 'number' ? this.value.servicePortPath : this.value.servicePortNamePath;
|
|
79
85
|
|
|
80
86
|
set(backend, this.value.serviceNamePath, this.serviceName);
|
|
81
|
-
set(backend,
|
|
87
|
+
set(backend, portPath, servicePort);
|
|
82
88
|
set(this.value.spec, this.value.defaultBackendPath, backend);
|
|
83
89
|
|
|
84
90
|
this.$emit('update:value', this.value);
|
|
@@ -119,10 +125,12 @@ export default {
|
|
|
119
125
|
class="col span-3"
|
|
120
126
|
:style="{'margin-right': '0px'}"
|
|
121
127
|
>
|
|
128
|
+
<!-- :required drives the asterisk; portRequired doesn't have .name === 'required' -->
|
|
122
129
|
<LabeledInput
|
|
123
130
|
v-if="portOptions.length === 0 || isView"
|
|
124
|
-
v-model:value
|
|
131
|
+
v-model:value="servicePort"
|
|
125
132
|
:mode="mode"
|
|
133
|
+
:required="true"
|
|
126
134
|
:label="t('ingress.defaultBackend.port.label')"
|
|
127
135
|
:placeholder="t('ingress.defaultBackend.port.placeholder')"
|
|
128
136
|
:rules="rules.port"
|
|
@@ -132,6 +140,7 @@ export default {
|
|
|
132
140
|
v-else
|
|
133
141
|
v-model:value="servicePort"
|
|
134
142
|
:mode="mode"
|
|
143
|
+
:required="true"
|
|
135
144
|
:options="portOptions"
|
|
136
145
|
:label="t('ingress.defaultBackend.port.label')"
|
|
137
146
|
:placeholder="t('ingress.defaultBackend.port.placeholder')"
|
|
@@ -79,20 +79,24 @@ export default {
|
|
|
79
79
|
set(this.value, 'path', this.value.path || '');
|
|
80
80
|
set(this.value, 'pathType', this.value.pathType || this.pathTypes[0]);
|
|
81
81
|
set(this.value.backend, this.ingress.serviceNamePath, get(this.value.backend, this.ingress.serviceNamePath) || '');
|
|
82
|
-
set(this.value.backend, this.ingress.servicePortPath, get(this.value.backend, this.ingress.servicePortPath) || '');
|
|
83
82
|
|
|
84
83
|
this.serviceName = get(this.value.backend, this.ingress.serviceNamePath);
|
|
85
|
-
this.servicePort = get(this.value.backend, this.ingress.servicePortPath)
|
|
84
|
+
this.servicePort = get(this.value.backend, this.ingress.servicePortPath) ||
|
|
85
|
+
get(this.value.backend, this.ingress.servicePortNamePath) ||
|
|
86
|
+
'';
|
|
86
87
|
},
|
|
87
88
|
methods: {
|
|
88
89
|
update() {
|
|
89
|
-
const
|
|
90
|
+
const parsed = Number.parseInt(this.servicePort);
|
|
91
|
+
const servicePort = Number.isNaN(parsed) ? this.servicePort : parsed;
|
|
90
92
|
const serviceName = this.serviceName.label || this.serviceName;
|
|
91
93
|
const out = {
|
|
92
94
|
id: this.value.id, backend: {}, path: this.path, pathType: this.pathType
|
|
93
95
|
};
|
|
94
96
|
|
|
95
|
-
|
|
97
|
+
const portPath = typeof servicePort === 'number' ? this.ingress.servicePortPath : this.ingress.servicePortNamePath;
|
|
98
|
+
|
|
99
|
+
set(out.backend, portPath, servicePort);
|
|
96
100
|
set(out.backend, this.ingress.serviceNamePath, serviceName);
|
|
97
101
|
|
|
98
102
|
this.$emit('update:value', out);
|