@rancher/shell 3.0.8 → 3.0.9-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apis/intf/modal.ts +38 -0
- package/apis/intf/slide-in.ts +3 -1
- package/apis/shell/__tests__/slide-in.test.ts +36 -0
- package/apis/shell/slide-in.ts +5 -1
- package/assets/styles/base/_color.scss +1 -0
- package/assets/styles/base/_typography.scss +14 -5
- package/assets/styles/themes/_light.scss +1 -1
- package/assets/styles/themes/_modern.scss +1 -1
- package/assets/translations/en-us.yaml +94 -33
- package/assets/translations/zh-hans.yaml +0 -2
- package/components/ActionMenuShell.vue +4 -4
- package/components/CodeMirror.vue +4 -3
- package/components/DetailText.vue +54 -7
- package/components/Drawer/Chrome.vue +11 -4
- package/components/Drawer/DrawerCard.vue +19 -0
- package/components/Drawer/ResourceDetailDrawer/ConfigTab.vue +3 -11
- package/components/Drawer/ResourceDetailDrawer/__tests__/ConfigTab.test.ts +2 -2
- package/components/Drawer/ResourceDetailDrawer/index.vue +3 -20
- package/components/Drawer/types.ts +1 -0
- package/components/DynamicContent/DynamicContentCloseButton.vue +2 -2
- package/components/LocaleSelector.vue +1 -1
- package/components/Markdown.vue +1 -1
- package/components/PopoverCard.vue +3 -3
- package/components/Resource/Detail/Card/ExtrasCard.vue +39 -0
- package/components/Resource/Detail/Card/StateCard/__tests__/composables.test.ts +142 -0
- package/components/Resource/Detail/Card/StateCard/composables.ts +41 -11
- package/components/Resource/Detail/Card/StateCard/index.vue +3 -9
- package/components/Resource/Detail/Card/StateCard/types.ts +6 -0
- package/components/Resource/Detail/Card/{PodsCard → StatusCard}/index.vue +11 -10
- package/components/Resource/Detail/Card/__tests__/PodsCard.test.ts +24 -25
- package/components/Resource/Detail/Cards.vue +27 -0
- package/components/Resource/Detail/Masthead/__tests__/index.test.ts +70 -0
- package/components/Resource/Detail/Masthead/index.vue +5 -0
- package/components/Resource/Detail/Metadata/KeyValueRow.vue +4 -2
- package/components/Resource/Detail/ResourcePopover/ResourcePopoverCard.vue +2 -2
- package/components/Resource/Detail/ResourceRow.types.ts +14 -0
- package/components/Resource/Detail/ResourceRow.vue +23 -35
- package/components/Resource/Detail/StatusRow.vue +5 -2
- package/components/Resource/Detail/TitleBar/__tests__/composables.test.ts +38 -7
- package/components/Resource/Detail/TitleBar/__tests__/index.test.ts +106 -2
- package/components/Resource/Detail/TitleBar/composables.ts +2 -1
- package/components/Resource/Detail/TitleBar/index.vue +41 -6
- package/components/ResourceDetail/Masthead/__tests__/index.test.ts +49 -1
- package/components/ResourceDetail/Masthead/__tests__/latest.test.ts +85 -0
- package/components/ResourceDetail/Masthead/index.vue +1 -0
- package/components/ResourceDetail/Masthead/latest.vue +8 -1
- package/components/ResourceDetail/Masthead/legacy.vue +1 -1
- package/components/Setting.vue +1 -1
- package/components/SortableTable/index.vue +25 -0
- package/components/SortableTable/selection.js +25 -12
- package/components/SortableTable/sorting.js +1 -1
- package/components/Tabbed/Tab.vue +1 -0
- package/components/Tabbed/index.vue +29 -6
- package/components/Window/ContainerShell.vue +10 -13
- package/components/fleet/FleetClusterTargets/TargetsList.vue +47 -29
- package/components/fleet/FleetClusterTargets/index.vue +82 -29
- package/components/fleet/FleetClusters.vue +26 -12
- package/components/fleet/FleetGitRepoPaths.vue +2 -2
- package/components/fleet/FleetResources.vue +14 -0
- package/components/fleet/FleetValuesFrom.vue +2 -2
- package/components/fleet/__tests__/FleetClusterTargets.test.ts +531 -0
- package/components/fleet/__tests__/FleetClusters.test.ts +576 -0
- package/components/fleet/dashboard/ResourceDetails.vue +96 -123
- package/components/form/Conditions.vue +1 -15
- package/components/form/HookOption.vue +5 -0
- package/components/form/LabeledSelect.vue +1 -1
- package/components/form/LifecycleHooks.vue +2 -6
- package/components/form/ResourceLabeledSelect.vue +12 -1
- package/components/form/SeccompProfile.vue +113 -0
- package/components/form/Security.vue +244 -133
- package/components/form/__tests__/LabeledSelect.test.ts +1 -1
- package/components/form/__tests__/SeccompProfile.test.js +124 -0
- package/components/form/__tests__/Security.test.ts +125 -37
- package/components/formatter/Autoscaler.vue +2 -2
- package/components/formatter/FleetSummaryGraph.vue +4 -1
- package/components/nav/Group.vue +5 -0
- package/components/nav/Header.vue +3 -3
- package/components/nav/HeaderPageActionMenu.vue +1 -1
- package/components/nav/NamespaceFilter.vue +6 -6
- package/components/nav/NotificationCenter/index.vue +1 -1
- package/components/nav/TopLevelMenu.helper.ts +41 -16
- package/components/nav/TopLevelMenu.vue +45 -25
- package/components/nav/WorkspaceSwitcher.vue +1 -1
- package/components/nav/__tests__/TopLevelMenu.helper.test.ts +277 -0
- package/components/nav/__tests__/TopLevelMenu.test.ts +160 -4
- package/components/templates/default.vue +0 -3
- package/components/templates/home.vue +0 -3
- package/components/templates/plain.vue +0 -3
- package/composables/useClickOutside.ts +1 -1
- package/config/product/explorer.js +1 -2
- package/config/types.js +41 -8
- package/detail/__tests__/workload.test.ts +8 -16
- package/detail/catalog.cattle.io.app.vue +6 -0
- package/detail/fleet.cattle.io.cluster.vue +6 -0
- package/detail/workload/index.vue +7 -109
- package/edit/__tests__/projectsecret.test.ts +42 -0
- package/edit/auth/__tests__/oidc.test.ts +50 -0
- package/edit/auth/oidc.vue +68 -44
- package/edit/autoscaling.horizontalpodautoscaler/index.vue +140 -59
- package/edit/autoscaling.horizontalpodautoscaler/metrics-row.vue +41 -5
- package/edit/projectsecret.vue +29 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/Basics.test.ts +89 -200
- package/edit/provisioning.cattle.io.cluster/__tests__/Networking.test.ts +58 -17
- package/edit/provisioning.cattle.io.cluster/rke2.vue +11 -0
- package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +3 -63
- package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +82 -14
- package/edit/workload/__tests__/index.test.ts +122 -85
- package/edit/workload/index.vue +48 -29
- package/edit/workload/mixins/workload.js +85 -32
- package/list/catalog.cattle.io.clusterrepo.vue +1 -1
- package/list/projectsecret.vue +2 -2
- package/machine-config/__tests__/vmwarevsphere.test.ts +64 -0
- package/machine-config/amazonec2.vue +2 -2
- package/machine-config/vmwarevsphere.vue +58 -4
- package/mixins/__tests__/brand.spec.ts +18 -13
- package/mixins/__tests__/chart.test.ts +63 -0
- package/mixins/chart.js +56 -51
- package/models/__tests__/catalog.cattle.io.app.test.ts +33 -0
- package/models/__tests__/workload.test.ts +333 -0
- package/models/catalog.cattle.io.app.js +8 -0
- package/models/pod.js +14 -0
- package/models/secret.js +1 -1
- package/models/workload.js +93 -27
- package/package.json +4 -4
- package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +91 -0
- package/pages/c/_cluster/apps/charts/install.vue +4 -4
- package/pages/c/_cluster/explorer/EventsTable.vue +2 -2
- package/pages/c/_cluster/fleet/index.vue +18 -12
- package/pages/c/_cluster/manager/hostedprovider/index.vue +1 -19
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +1 -1
- package/pages/c/_cluster/uiplugins/index.vue +1 -1
- package/plugins/dashboard-store/__tests__/resource-class.test.ts +234 -0
- package/plugins/dashboard-store/actions.js +9 -8
- package/plugins/dashboard-store/resource-class.js +97 -1
- package/plugins/steve/__tests__/revision.test.ts +84 -0
- package/plugins/steve/__tests__/steve-pagination-utils.test.ts +30 -0
- package/plugins/steve/__tests__/subscribe.spec.ts +134 -0
- package/plugins/steve/mutations.js +9 -0
- package/plugins/steve/revision.ts +26 -0
- package/plugins/steve/steve-pagination-utils.ts +6 -5
- package/plugins/steve/subscribe.js +211 -51
- package/plugins/subscribe-events.ts +2 -2
- package/rancher-components/Form/Checkbox/Checkbox.vue +13 -0
- package/rancher-components/LabeledTooltip/LabeledTooltip.vue +1 -1
- package/rancher-components/Pill/RcCounterBadge/RcCounterBadge.vue +1 -1
- package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.vue +3 -1
- package/rancher-components/Pill/RcStatusIndicator/RcStatusIndicator.vue +3 -1
- package/rancher-components/Pill/RcTag/RcTag.vue +1 -1
- package/rancher-components/Pill/index.ts +4 -0
- package/rancher-components/RcButton/RcButton.test.ts +53 -9
- package/rancher-components/RcButton/RcButton.vue +217 -25
- package/rancher-components/RcButton/types.ts +27 -1
- package/rancher-components/RcDropdown/RcDropdownMenu.vue +4 -4
- package/rancher-components/RcDropdown/types.ts +3 -3
- package/rancher-components/RcIcon/RcIcon.test.ts +42 -0
- package/rancher-components/RcIcon/RcIcon.vue +9 -6
- package/rancher-components/RcIcon/types.ts +13 -9
- package/rancher-components/utils/status.test.ts +10 -15
- package/rancher-components/utils/status.ts +5 -6
- package/store/aws.js +18 -12
- package/store/index.js +4 -8
- package/store/type-map.utils.ts +1 -1
- package/types/kube/kube-api.ts +29 -3
- package/types/rancher/steve.api.ts +40 -0
- package/types/shell/index.d.ts +99 -0
- package/types/store/dashboard-store.types.ts +29 -7
- package/types/store/pagination.types.ts +1 -0
- package/types/store/subscribe-events.types.ts +1 -0
- package/utils/__tests__/azure.test.ts +56 -0
- package/utils/__tests__/back-off.test.ts +364 -245
- package/utils/__tests__/error.test.ts +44 -0
- package/utils/__tests__/fleet.test.ts +8 -1
- package/utils/__tests__/pagination-wrapper.test.ts +167 -0
- package/utils/__tests__/version.test.ts +55 -1
- package/utils/azure.js +12 -0
- package/utils/back-off.ts +302 -69
- package/utils/cspAdaptor.ts +32 -14
- package/utils/dynamic-content/__tests__/index.test.ts +1 -1
- package/utils/dynamic-content/__tests__/new-release.test.ts +48 -7
- package/utils/dynamic-content/__tests__/support-notice.test.ts +1 -4
- package/utils/dynamic-content/index.ts +1 -6
- package/utils/dynamic-content/new-release.ts +5 -3
- package/utils/dynamic-content/types.d.ts +0 -1
- package/utils/error.js +9 -0
- package/utils/fleet.ts +2 -2
- package/utils/inactivity.ts +2 -3
- package/utils/pagination-wrapper.ts +101 -17
- package/utils/validators/formRules/index.ts +3 -0
- package/utils/version.js +38 -0
- package/components/auth/AzureWarning.vue +0 -77
- /package/components/Resource/Detail/{Card/PodsCard/Bubble.vue → Bubble.vue} +0 -0
- /package/components/Resource/Detail/Card/{PodsCard → StatusCard}/composable.ts +0 -0
|
@@ -17,9 +17,8 @@ describe('findMatchingIngresses', () => {
|
|
|
17
17
|
const mockThis = {
|
|
18
18
|
ingressSchema: true,
|
|
19
19
|
allIngresses: [],
|
|
20
|
-
matchingServices: [],
|
|
21
20
|
matchingIngresses: [],
|
|
22
|
-
value: { metadata: { namespace: 'test' } }
|
|
21
|
+
value: { metadata: { namespace: 'test' }, relatedServices: [] }
|
|
23
22
|
};
|
|
24
23
|
|
|
25
24
|
findMatchingIngresses.call(mockThis);
|
|
@@ -35,9 +34,8 @@ describe('findMatchingIngresses', () => {
|
|
|
35
34
|
spec: { rules: [{ http: { paths: [{ backend: { service: { name: 'service1' } } }] } }] }
|
|
36
35
|
}
|
|
37
36
|
],
|
|
38
|
-
matchingServices: [{ metadata: { name: 'service1' } }],
|
|
39
37
|
matchingIngresses: [],
|
|
40
|
-
value: { metadata: { namespace: 'test' } }
|
|
38
|
+
value: { metadata: { namespace: 'test' }, relatedServices: [{ metadata: { name: 'service1' } }] }
|
|
41
39
|
};
|
|
42
40
|
|
|
43
41
|
findMatchingIngresses.call(mockThis);
|
|
@@ -54,9 +52,8 @@ describe('findMatchingIngresses', () => {
|
|
|
54
52
|
spec: { rules: [{ http: { paths: [{ backend: { service: { name: 'service1' } } }] } }] }
|
|
55
53
|
}
|
|
56
54
|
],
|
|
57
|
-
matchingServices: [{ metadata: { name: 'service1' } }],
|
|
58
55
|
matchingIngresses: [],
|
|
59
|
-
value: { metadata: { namespace: 'test' } }
|
|
56
|
+
value: { metadata: { namespace: 'test' }, relatedServices: [{ metadata: { name: 'service1' } }] }
|
|
60
57
|
};
|
|
61
58
|
|
|
62
59
|
findMatchingIngresses.call(mockThis);
|
|
@@ -72,9 +69,8 @@ describe('findMatchingIngresses', () => {
|
|
|
72
69
|
spec: { rules: [{ http: { paths: [{ backend: { service: { name: 'service2' } } }] } }] }
|
|
73
70
|
}
|
|
74
71
|
],
|
|
75
|
-
matchingServices: [{ metadata: { name: 'service1' } }],
|
|
76
72
|
matchingIngresses: [],
|
|
77
|
-
value: { metadata: { namespace: 'test' } }
|
|
73
|
+
value: { metadata: { namespace: 'test' }, relatedServices: [{ metadata: { name: 'service1' } }] }
|
|
78
74
|
};
|
|
79
75
|
|
|
80
76
|
findMatchingIngresses.call(mockThis);
|
|
@@ -90,9 +86,8 @@ describe('findMatchingIngresses', () => {
|
|
|
90
86
|
spec: { }
|
|
91
87
|
}
|
|
92
88
|
],
|
|
93
|
-
matchingServices: [{ metadata: { name: 'service1' } }],
|
|
94
89
|
matchingIngresses: [],
|
|
95
|
-
value: { metadata: { namespace: 'test' } }
|
|
90
|
+
value: { metadata: { namespace: 'test' }, relatedServices: [{ metadata: { name: 'service1' } }] }
|
|
96
91
|
};
|
|
97
92
|
|
|
98
93
|
findMatchingIngresses.call(mockThis);
|
|
@@ -108,9 +103,8 @@ describe('findMatchingIngresses', () => {
|
|
|
108
103
|
spec: { rules: [{ http: {} }] }
|
|
109
104
|
}
|
|
110
105
|
],
|
|
111
|
-
matchingServices: [{ metadata: { name: 'service1' } }],
|
|
112
106
|
matchingIngresses: [],
|
|
113
|
-
value: { metadata: { namespace: 'test' } }
|
|
107
|
+
value: { metadata: { namespace: 'test' }, relatedServices: [{ metadata: { name: 'service1' } }] }
|
|
114
108
|
};
|
|
115
109
|
|
|
116
110
|
findMatchingIngresses.call(mockThis);
|
|
@@ -126,9 +120,8 @@ describe('findMatchingIngresses', () => {
|
|
|
126
120
|
spec: { rules: [{ http: { paths: [{ backend: {} }] } }] }
|
|
127
121
|
}
|
|
128
122
|
],
|
|
129
|
-
matchingServices: [{ metadata: { name: 'service1' } }],
|
|
130
123
|
matchingIngresses: [],
|
|
131
|
-
value: { metadata: { namespace: 'test' } }
|
|
124
|
+
value: { metadata: { namespace: 'test' }, relatedServices: [{ metadata: { name: 'service1' } }] }
|
|
132
125
|
};
|
|
133
126
|
|
|
134
127
|
findMatchingIngresses.call(mockThis);
|
|
@@ -152,9 +145,8 @@ describe('findMatchingIngresses', () => {
|
|
|
152
145
|
spec: { rules: [{ http: { paths: [{ backend: { service: { name: 'service2' } } }] } }] }
|
|
153
146
|
}
|
|
154
147
|
],
|
|
155
|
-
matchingServices: [{ metadata: { name: 'service1' } }],
|
|
156
148
|
matchingIngresses: [],
|
|
157
|
-
value: { metadata: { namespace: 'test' } }
|
|
149
|
+
value: { metadata: { namespace: 'test' }, relatedServices: [{ metadata: { name: 'service1' } }] }
|
|
158
150
|
};
|
|
159
151
|
|
|
160
152
|
findMatchingIngresses.call(mockThis);
|
|
@@ -53,6 +53,11 @@ export default {
|
|
|
53
53
|
},
|
|
54
54
|
|
|
55
55
|
valuesYaml() {
|
|
56
|
+
// Prevent crash if data hasn't been fetched yet (e.g. secret during upgrade)
|
|
57
|
+
if (!this.value?.valuesLoaded) {
|
|
58
|
+
return '';
|
|
59
|
+
}
|
|
60
|
+
|
|
56
61
|
const combined = mergeWithReplace(
|
|
57
62
|
merge({}, this.value?.chartValues || {}),
|
|
58
63
|
this.value?.values || {},
|
|
@@ -159,6 +164,7 @@ export default {
|
|
|
159
164
|
:scrolling="false"
|
|
160
165
|
:value="valuesYaml"
|
|
161
166
|
editor-mode="VIEW_CODE"
|
|
167
|
+
mode="view"
|
|
162
168
|
/>
|
|
163
169
|
</Tab>
|
|
164
170
|
<Tab
|
|
@@ -59,6 +59,12 @@ export default {
|
|
|
59
59
|
};
|
|
60
60
|
},
|
|
61
61
|
|
|
62
|
+
created() {
|
|
63
|
+
if (this.workspace !== this.value.namespace) {
|
|
64
|
+
this.$store.commit('updateWorkspace', { value: this.value.namespace, getters: this.$store.getters });
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
|
|
62
68
|
computed: {
|
|
63
69
|
clusterId() {
|
|
64
70
|
return this.value.id;
|
|
@@ -2,22 +2,18 @@
|
|
|
2
2
|
import CreateEditView from '@shell/mixins/create-edit-view';
|
|
3
3
|
import { NAMESPACE as NAMESPACE_COL } from '@shell/config/table-headers';
|
|
4
4
|
import {
|
|
5
|
-
POD, WORKLOAD_TYPES,
|
|
5
|
+
POD, WORKLOAD_TYPES, SERVICE, INGRESS, NODE, NAMESPACE, WORKLOAD_TYPE_TO_KIND_MAPPING, METRICS_SUPPORTED_KINDS
|
|
6
6
|
} from '@shell/config/types';
|
|
7
7
|
import ResourceTable from '@shell/components/ResourceTable';
|
|
8
8
|
import Tab from '@shell/components/Tabbed/Tab';
|
|
9
9
|
import Loading from '@shell/components/Loading';
|
|
10
10
|
import ResourceTabs from '@shell/components/form/ResourceTabs';
|
|
11
|
-
import CountGauge from '@shell/components/CountGauge';
|
|
12
11
|
import { allHash } from '@shell/utils/promise';
|
|
13
12
|
import DashboardMetrics from '@shell/components/DashboardMetrics';
|
|
14
13
|
import { mapGetters } from 'vuex';
|
|
15
14
|
import { allDashboardsExist } from '@shell/utils/grafana';
|
|
16
|
-
import PlusMinus from '@shell/components/form/PlusMinus';
|
|
17
|
-
import { matches } from '@shell/utils/selector';
|
|
18
15
|
import { PROJECT } from '@shell/config/labels-annotations';
|
|
19
16
|
|
|
20
|
-
const SCALABLE_TYPES = Object.values(SCALABLE_WORKLOAD_TYPES);
|
|
21
17
|
const WORKLOAD_METRICS_DETAIL_URL = '/api/v1/namespaces/cattle-monitoring-system/services/http:rancher-monitoring-grafana:80/proxy/d/rancher-workload-pods-1/rancher-workload-pods?orgId=1';
|
|
22
18
|
const WORKLOAD_METRICS_SUMMARY_URL = '/api/v1/namespaces/cattle-monitoring-system/services/http:rancher-monitoring-grafana:80/proxy/d/rancher-workload-1/rancher-workload?orgId=1';
|
|
23
19
|
|
|
@@ -27,9 +23,7 @@ export default {
|
|
|
27
23
|
Tab,
|
|
28
24
|
Loading,
|
|
29
25
|
ResourceTabs,
|
|
30
|
-
CountGauge,
|
|
31
26
|
ResourceTable,
|
|
32
|
-
PlusMinus
|
|
33
27
|
},
|
|
34
28
|
|
|
35
29
|
mixins: [CreateEditView],
|
|
@@ -57,10 +51,6 @@ export default {
|
|
|
57
51
|
hash.pods = this.value.fetchPods();
|
|
58
52
|
}
|
|
59
53
|
|
|
60
|
-
if (this.serviceSchema) {
|
|
61
|
-
hash.servicesInNamespace = this.$store.dispatch('cluster/findAll', { type: SERVICE, opt: { namespaced: this.value.metadata.namespace } });
|
|
62
|
-
}
|
|
63
|
-
|
|
64
54
|
if (this.value.type === WORKLOAD_TYPES.CRON_JOB) {
|
|
65
55
|
hash.jobs = this.value.matchingJobs();
|
|
66
56
|
}
|
|
@@ -85,7 +75,6 @@ export default {
|
|
|
85
75
|
this.showProjectMetrics = await allDashboardsExist(this.$store, this.currentCluster.id, [this.WORKLOAD_PROJECT_METRICS_DETAIL_URL, this.WORKLOAD_PROJECT_METRICS_SUMMARY_URL], 'cluster', projectId);
|
|
86
76
|
}
|
|
87
77
|
}
|
|
88
|
-
this.findMatchingServices();
|
|
89
78
|
this.findMatchingIngresses();
|
|
90
79
|
},
|
|
91
80
|
|
|
@@ -97,9 +86,7 @@ export default {
|
|
|
97
86
|
|
|
98
87
|
data() {
|
|
99
88
|
return {
|
|
100
|
-
servicesInNamespace: [],
|
|
101
89
|
allIngresses: [],
|
|
102
|
-
matchingServices: [],
|
|
103
90
|
matchingIngresses: [],
|
|
104
91
|
allNodes: [],
|
|
105
92
|
WORKLOAD_METRICS_DETAIL_URL,
|
|
@@ -223,55 +210,10 @@ export default {
|
|
|
223
210
|
const total = this.isCronJob ? this.totalRuns : this.value.pods.length;
|
|
224
211
|
|
|
225
212
|
return !jobGauges.find((jg) => jg.count === total);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
canScale() {
|
|
229
|
-
return !!SCALABLE_TYPES.includes(this.value.type) && this.value.canUpdate;
|
|
230
|
-
},
|
|
213
|
+
}
|
|
231
214
|
},
|
|
232
215
|
|
|
233
216
|
methods: {
|
|
234
|
-
async scale(isUp) {
|
|
235
|
-
try {
|
|
236
|
-
if (isUp) {
|
|
237
|
-
await this.value.scaleUp();
|
|
238
|
-
} else {
|
|
239
|
-
await this.value.scaleDown();
|
|
240
|
-
}
|
|
241
|
-
} catch (err) {
|
|
242
|
-
this.$store.dispatch('growl/fromError', {
|
|
243
|
-
title: this.t('workload.list.errorCannotScale', { direction: isUp ? 'up' : 'down', workloadName: this.value.name }),
|
|
244
|
-
err
|
|
245
|
-
},
|
|
246
|
-
{ root: true });
|
|
247
|
-
}
|
|
248
|
-
},
|
|
249
|
-
async scaleDown() {
|
|
250
|
-
await this.scale(false);
|
|
251
|
-
},
|
|
252
|
-
async scaleUp() {
|
|
253
|
-
await this.scale(true);
|
|
254
|
-
},
|
|
255
|
-
findMatchingServices() {
|
|
256
|
-
if (!this.serviceSchema) {
|
|
257
|
-
return [];
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
// Find Services that have selectors that match this workload's Pod(s).
|
|
261
|
-
this.matchingServices = this.servicesInNamespace.filter((service) => {
|
|
262
|
-
const selector = service.spec.selector;
|
|
263
|
-
|
|
264
|
-
for (let i = 0; i < this.value.pods.length; i++) {
|
|
265
|
-
const pod = this.value.pods[i];
|
|
266
|
-
|
|
267
|
-
if (service.metadata?.namespace === this.value.metadata?.namespace && matches(pod, selector)) {
|
|
268
|
-
return true;
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
return false;
|
|
273
|
-
});
|
|
274
|
-
},
|
|
275
217
|
findMatchingIngresses() {
|
|
276
218
|
if (!this.ingressSchema) {
|
|
277
219
|
return [];
|
|
@@ -297,8 +239,8 @@ export default {
|
|
|
297
239
|
|
|
298
240
|
if (!targetServiceName) continue;
|
|
299
241
|
|
|
300
|
-
for (let k = 0; k < this.
|
|
301
|
-
const service = this.
|
|
242
|
+
for (let k = 0; k < this.value.relatedServices.length; k++) {
|
|
243
|
+
const service = this.value.relatedServices[k];
|
|
302
244
|
const matchingServiceName = service?.metadata?.name;
|
|
303
245
|
|
|
304
246
|
if (ingress.metadata?.namespace === this.value.metadata?.namespace && matchingServiceName === targetServiceName) {
|
|
@@ -331,50 +273,6 @@ export default {
|
|
|
331
273
|
<template>
|
|
332
274
|
<Loading v-if="$fetchState.pending" />
|
|
333
275
|
<div v-else>
|
|
334
|
-
<div
|
|
335
|
-
v-if="canScale"
|
|
336
|
-
class="right-align flex"
|
|
337
|
-
>
|
|
338
|
-
<PlusMinus
|
|
339
|
-
class="text-right"
|
|
340
|
-
:label="t('tableHeaders.scale')"
|
|
341
|
-
:value="value.spec.replicas"
|
|
342
|
-
:disabled="!isScalable"
|
|
343
|
-
@minus="scaleDown"
|
|
344
|
-
@plus="scaleUp"
|
|
345
|
-
/>
|
|
346
|
-
</div>
|
|
347
|
-
<h3>
|
|
348
|
-
{{ isJob || isCronJob ? t('workload.detailTop.runs') :t('workload.detailTop.pods') }}
|
|
349
|
-
</h3>
|
|
350
|
-
<div
|
|
351
|
-
v-if="value.pods || value.jobGauges"
|
|
352
|
-
class="gauges mb-20"
|
|
353
|
-
:class="{'gauges__pods': !!value.pods}"
|
|
354
|
-
>
|
|
355
|
-
<template v-if="value.jobGauges">
|
|
356
|
-
<CountGauge
|
|
357
|
-
v-for="(group, key) in value.jobGauges"
|
|
358
|
-
:key="key"
|
|
359
|
-
:total="isCronJob? totalRuns : value.pods.length"
|
|
360
|
-
:useful="group.count || 0"
|
|
361
|
-
:graphical="showJobGaugeCircles"
|
|
362
|
-
:primary-color-var="`--sizzle-${group.color}`"
|
|
363
|
-
:name="t(`workload.gaugeStates.${key}`)"
|
|
364
|
-
/>
|
|
365
|
-
</template>
|
|
366
|
-
<template v-else>
|
|
367
|
-
<CountGauge
|
|
368
|
-
v-for="(group, key) in podGauges"
|
|
369
|
-
:key="key"
|
|
370
|
-
:total="value.pods.length"
|
|
371
|
-
:useful="group.count || 0"
|
|
372
|
-
:graphical="showPodGaugeCircles"
|
|
373
|
-
:primary-color-var="`--sizzle-${group.color}`"
|
|
374
|
-
:name="key"
|
|
375
|
-
/>
|
|
376
|
-
</template>
|
|
377
|
-
</div>
|
|
378
276
|
<ResourceTabs
|
|
379
277
|
:value="value"
|
|
380
278
|
>
|
|
@@ -455,7 +353,7 @@ export default {
|
|
|
455
353
|
{{ t('workload.detail.cannotViewServices') }}
|
|
456
354
|
</p>
|
|
457
355
|
<p
|
|
458
|
-
v-else-if="
|
|
356
|
+
v-else-if="value.relatedServices.length === 0"
|
|
459
357
|
class="caption"
|
|
460
358
|
>
|
|
461
359
|
{{ t('workload.detail.cannotFindServices') }}
|
|
@@ -467,8 +365,8 @@ export default {
|
|
|
467
365
|
{{ t('workload.detail.serviceListCaption') }}
|
|
468
366
|
</p>
|
|
469
367
|
<ResourceTable
|
|
470
|
-
v-if="serviceSchema &&
|
|
471
|
-
:rows="
|
|
368
|
+
v-if="serviceSchema && value.relatedServices.length > 0"
|
|
369
|
+
:rows="value.relatedServices"
|
|
472
370
|
:headers="serviceHeaders"
|
|
473
371
|
key-field="id"
|
|
474
372
|
:schema="serviceSchema"
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { shallowMount } from '@vue/test-utils';
|
|
2
|
+
import ProjectSecretProxy from '@shell/edit/projectsecret.vue';
|
|
3
|
+
import Secret from '@shell/edit/secret/index.vue';
|
|
4
|
+
|
|
5
|
+
describe('component: ProjectSecretProxy', () => {
|
|
6
|
+
it('should render Secret component', () => {
|
|
7
|
+
const wrapper = shallowMount(ProjectSecretProxy, {
|
|
8
|
+
global: { stubs: { Secret: true } },
|
|
9
|
+
attrs: { someAttr: 'someValue' }
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
const secretComponent = wrapper.findComponent(Secret);
|
|
13
|
+
|
|
14
|
+
expect(secretComponent.exists()).toBe(true);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('should pass attributes to Secret component', () => {
|
|
18
|
+
const wrapper = shallowMount(ProjectSecretProxy, {
|
|
19
|
+
global: { stubs: { Secret: true } },
|
|
20
|
+
attrs: {
|
|
21
|
+
mode: 'create',
|
|
22
|
+
value: { metadata: { name: 'test' } }
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const secretComponent = wrapper.findComponent(Secret);
|
|
27
|
+
|
|
28
|
+
expect(secretComponent.attributes('mode')).toBe('create');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should pass event listeners to Secret component', () => {
|
|
32
|
+
const onInput = jest.fn();
|
|
33
|
+
const wrapper = shallowMount(ProjectSecretProxy, {
|
|
34
|
+
global: { stubs: { Secret: true } },
|
|
35
|
+
attrs: { onInput }
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const secretComponent = wrapper.findComponent(Secret);
|
|
39
|
+
|
|
40
|
+
expect(secretComponent.vm.$attrs.onInput).toBe(onInput);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
@@ -247,5 +247,55 @@ describe('oidc.vue', () => {
|
|
|
247
247
|
expect(groupsClaim.exists()).toBe(true);
|
|
248
248
|
expect(emailClaim.exists()).toBe(true);
|
|
249
249
|
});
|
|
250
|
+
|
|
251
|
+
it('should render addCustomClaims and supportsGroupSearch checkbox when provider is keycloak', async() => {
|
|
252
|
+
wrapper.vm.model.id = 'keycloakoidc';
|
|
253
|
+
await nextTick();
|
|
254
|
+
|
|
255
|
+
const addCustomClaimsCheckbox = wrapper.find('[data-testid="input-add-custom-claims"]');
|
|
256
|
+
const groupSearchCheckbox = wrapper.find('[data-testid="input-group-search"]');
|
|
257
|
+
|
|
258
|
+
expect(addCustomClaimsCheckbox.exists()).toBe(true);
|
|
259
|
+
expect(groupSearchCheckbox.exists()).toBe(true);
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
it('should render custom claims section when provider is keycloak and addCustomClaims is true', async() => {
|
|
263
|
+
wrapper.vm.model.id = 'keycloakoidc';
|
|
264
|
+
wrapper.vm.addCustomClaims = true;
|
|
265
|
+
await nextTick();
|
|
266
|
+
|
|
267
|
+
const nameClaim = wrapper.find('[data-testid="input-name-claim"]');
|
|
268
|
+
const groupsClaim = wrapper.find('[data-testid="input-groups-claim"]');
|
|
269
|
+
const emailClaim = wrapper.find('[data-testid="input-email-claim"]');
|
|
270
|
+
|
|
271
|
+
expect(nameClaim.exists()).toBe(true);
|
|
272
|
+
expect(groupsClaim.exists()).toBe(true);
|
|
273
|
+
expect(emailClaim.exists()).toBe(true);
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it('should render both addCustomClaims and groupSearch checkboxes when provider is genericoidc', async() => {
|
|
277
|
+
wrapper.vm.model.id = 'genericoidc';
|
|
278
|
+
await nextTick();
|
|
279
|
+
|
|
280
|
+
const addCustomClaimsCheckbox = wrapper.find('[data-testid="input-add-custom-claims"]');
|
|
281
|
+
const groupSearchCheckbox = wrapper.find('[data-testid="input-group-search"]');
|
|
282
|
+
|
|
283
|
+
expect(addCustomClaimsCheckbox.exists()).toBe(true);
|
|
284
|
+
expect(groupSearchCheckbox.exists()).toBe(true);
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
it('should NOT render custom claims section when provider is keycloak and addCustomClaims is false', async() => {
|
|
288
|
+
wrapper.vm.model.id = 'keycloakoidc';
|
|
289
|
+
wrapper.vm.addCustomClaims = false;
|
|
290
|
+
await nextTick();
|
|
291
|
+
|
|
292
|
+
const nameClaim = wrapper.find('[data-testid="input-name-claim"]');
|
|
293
|
+
const groupsClaim = wrapper.find('[data-testid="input-groups-claim"]');
|
|
294
|
+
const emailClaim = wrapper.find('[data-testid="input-email-claim"]');
|
|
295
|
+
|
|
296
|
+
expect(nameClaim.exists()).toBe(false);
|
|
297
|
+
expect(groupsClaim.exists()).toBe(false);
|
|
298
|
+
expect(emailClaim.exists()).toBe(false);
|
|
299
|
+
});
|
|
250
300
|
});
|
|
251
301
|
});
|
package/edit/auth/oidc.vue
CHANGED
|
@@ -17,6 +17,8 @@ import { BASE_SCOPES } from '@shell/store/auth';
|
|
|
17
17
|
import CopyToClipboardText from '@shell/components/CopyToClipboardText.vue';
|
|
18
18
|
import isUrl from 'is-url';
|
|
19
19
|
|
|
20
|
+
const PKCE_S256 = 'S256';
|
|
21
|
+
|
|
20
22
|
export default {
|
|
21
23
|
components: {
|
|
22
24
|
Banner,
|
|
@@ -38,6 +40,10 @@ export default {
|
|
|
38
40
|
|
|
39
41
|
mixins: [CreateEditView, AuthConfig],
|
|
40
42
|
|
|
43
|
+
setup() {
|
|
44
|
+
return { PKCE_S256 };
|
|
45
|
+
},
|
|
46
|
+
|
|
41
47
|
data() {
|
|
42
48
|
return {
|
|
43
49
|
customEndpoint: {
|
|
@@ -149,6 +155,14 @@ export default {
|
|
|
149
155
|
return this.model?.id === 'genericoidc';
|
|
150
156
|
},
|
|
151
157
|
|
|
158
|
+
isKeycloak() {
|
|
159
|
+
return this.model?.id === 'keycloakoidc';
|
|
160
|
+
},
|
|
161
|
+
|
|
162
|
+
supportsCustomClaims() {
|
|
163
|
+
return this.isGenericOidc || this.isKeycloak;
|
|
164
|
+
},
|
|
165
|
+
|
|
152
166
|
isLogoutAllSupported() {
|
|
153
167
|
return this.model?.logoutAllSupported;
|
|
154
168
|
},
|
|
@@ -169,7 +183,7 @@ export default {
|
|
|
169
183
|
|
|
170
184
|
sloEndSessionEndpointUiEnabled() {
|
|
171
185
|
return this.sloType === SLO_OPTION_VALUES.all || this.sloType === SLO_OPTION_VALUES.both;
|
|
172
|
-
}
|
|
186
|
+
},
|
|
173
187
|
},
|
|
174
188
|
|
|
175
189
|
watch: {
|
|
@@ -269,7 +283,7 @@ export default {
|
|
|
269
283
|
},
|
|
270
284
|
|
|
271
285
|
willSave() {
|
|
272
|
-
if (this.
|
|
286
|
+
if (this.supportsCustomClaims && !this.addCustomClaims) {
|
|
273
287
|
this.model.nameClaim = undefined;
|
|
274
288
|
this.model.groupsClaim = undefined;
|
|
275
289
|
this.model.emailClaim = undefined;
|
|
@@ -310,6 +324,9 @@ export default {
|
|
|
310
324
|
<tr v-if="model.authEndpoint">
|
|
311
325
|
<td>{{ t('authConfig.oidc.authEndpoint') }}: </td><td>{{ model.authEndpoint }}</td>
|
|
312
326
|
</tr>
|
|
327
|
+
<tr v-if="model.pkceMethod">
|
|
328
|
+
<td>{{ t('authConfig.oidc.pkceMethod.label') }}: </td><td>{{ model.pkceMethod }}</td>
|
|
329
|
+
</tr>
|
|
313
330
|
<tr v-if="isLogoutAllSupported">
|
|
314
331
|
<td>{{ t('authConfig.slo.sloTitle') }}: </td><td>{{ sloTypeText }}</td>
|
|
315
332
|
</tr>
|
|
@@ -416,34 +433,38 @@ export default {
|
|
|
416
433
|
</div>
|
|
417
434
|
</div>
|
|
418
435
|
|
|
419
|
-
<
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
>
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
436
|
+
<div
|
|
437
|
+
class="row mb-20"
|
|
438
|
+
>
|
|
439
|
+
<div class="col span-6 checkbox-flex">
|
|
440
|
+
<!-- Allow group search -->
|
|
441
|
+
<Checkbox
|
|
442
|
+
v-model:value="model.pkceMethod"
|
|
443
|
+
:value-when-true="PKCE_S256"
|
|
444
|
+
:label="t('authConfig.oidc.pkce.label')"
|
|
445
|
+
:tooltip="t('authConfig.oidc.pkce.tooltip')"
|
|
446
|
+
/>
|
|
447
|
+
<Checkbox
|
|
448
|
+
v-if="supportsGroupSearch"
|
|
449
|
+
v-model:value="model.groupSearchEnabled"
|
|
450
|
+
data-testid="input-group-search"
|
|
451
|
+
:label="t('authConfig.oidc.groupSearch.label')"
|
|
452
|
+
:tooltip="t('authConfig.oidc.groupSearch.tooltip')"
|
|
453
|
+
:mode="mode"
|
|
454
|
+
/>
|
|
455
|
+
<Checkbox
|
|
456
|
+
v-if="supportsCustomClaims"
|
|
457
|
+
v-model:value="addCustomClaims"
|
|
458
|
+
data-testid="input-add-custom-claims"
|
|
459
|
+
:label="t('authConfig.oidc.customClaims.enable.label')"
|
|
460
|
+
:tooltip="t('authConfig.oidc.customClaims.enable.tooltip')"
|
|
461
|
+
:mode="mode"
|
|
462
|
+
/>
|
|
442
463
|
</div>
|
|
443
|
-
</
|
|
464
|
+
</div>
|
|
444
465
|
|
|
445
466
|
<!-- Custom Claims -->
|
|
446
|
-
<template v-if="addCustomClaims &&
|
|
467
|
+
<template v-if="addCustomClaims && supportsCustomClaims">
|
|
447
468
|
<h4>{{ t('authConfig.oidc.customClaims.label') }}</h4>
|
|
448
469
|
<div class="row mb-20">
|
|
449
470
|
<div class="col span-6">
|
|
@@ -475,20 +496,6 @@ export default {
|
|
|
475
496
|
</div>
|
|
476
497
|
</template>
|
|
477
498
|
|
|
478
|
-
<!-- Scopes -->
|
|
479
|
-
<div class="row mb-20">
|
|
480
|
-
<div class="col span-6">
|
|
481
|
-
<ArrayList
|
|
482
|
-
v-model:value="oidcScope"
|
|
483
|
-
:mode="mode"
|
|
484
|
-
:title="t('authConfig.oidc.scope.label')"
|
|
485
|
-
:value-placeholder="t('authConfig.oidc.scope.placeholder')"
|
|
486
|
-
:protip="t('authConfig.oidc.scope.protip', {}, true)"
|
|
487
|
-
@update:value="updateScope"
|
|
488
|
-
/>
|
|
489
|
-
</div>
|
|
490
|
-
</div>
|
|
491
|
-
|
|
492
499
|
<template v-if="!isAmazonCognito">
|
|
493
500
|
<!-- Generated vs Specific Endpoints -->
|
|
494
501
|
<div class="row mb-20">
|
|
@@ -546,7 +553,7 @@ export default {
|
|
|
546
553
|
</div>
|
|
547
554
|
</div>
|
|
548
555
|
|
|
549
|
-
<div class="row
|
|
556
|
+
<div class="row">
|
|
550
557
|
<div class="col span-6">
|
|
551
558
|
<LabeledInput
|
|
552
559
|
v-model:value="model.issuer"
|
|
@@ -570,7 +577,10 @@ export default {
|
|
|
570
577
|
</div>
|
|
571
578
|
|
|
572
579
|
<!-- Advanced section -->
|
|
573
|
-
<AdvancedSection
|
|
580
|
+
<AdvancedSection
|
|
581
|
+
class="mb-40"
|
|
582
|
+
:mode="mode"
|
|
583
|
+
>
|
|
574
584
|
<div class="row mb-20">
|
|
575
585
|
<div class="col span-6">
|
|
576
586
|
<LabeledInput
|
|
@@ -626,10 +636,24 @@ export default {
|
|
|
626
636
|
</div>
|
|
627
637
|
</template>
|
|
628
638
|
|
|
639
|
+
<!-- Scopes -->
|
|
640
|
+
<div class="row mb-20">
|
|
641
|
+
<div class="col span-6">
|
|
642
|
+
<ArrayList
|
|
643
|
+
v-model:value="oidcScope"
|
|
644
|
+
:mode="mode"
|
|
645
|
+
:title="t('authConfig.oidc.scope.label')"
|
|
646
|
+
:value-placeholder="t('authConfig.oidc.scope.placeholder')"
|
|
647
|
+
:protip="t('authConfig.oidc.scope.protip', {}, true)"
|
|
648
|
+
@update:value="updateScope"
|
|
649
|
+
/>
|
|
650
|
+
</div>
|
|
651
|
+
</div>
|
|
652
|
+
|
|
629
653
|
<!-- SLO logout -->
|
|
630
654
|
<div
|
|
631
655
|
v-if="isLogoutAllSupported"
|
|
632
|
-
class="
|
|
656
|
+
class="mb-20"
|
|
633
657
|
>
|
|
634
658
|
<div class="row">
|
|
635
659
|
<div class="col span-12">
|