@rancher/shell 3.0.4 → 3.0.5-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/assets/images/providers/sks.svg +1 -0
- package/assets/styles/base/_basic.scss +6 -0
- package/assets/styles/base/_helpers.scss +4 -0
- package/assets/styles/base/_variables.scss +1 -0
- package/assets/styles/global/_button.scss +1 -0
- package/assets/translations/en-us.yaml +65 -15
- package/assets/translations/zh-hans.yaml +4 -3
- package/chart/monitoring/index.vue +3 -1
- package/cloud-credential/aws.vue +2 -0
- package/components/ActionDropdownShell.vue +71 -0
- package/components/AppModal.vue +18 -4
- package/components/AsyncButton.vue +24 -7
- package/components/BannerGraphic.vue +1 -0
- package/components/CommunityLinks.vue +4 -59
- package/components/CopyToClipboardText.vue +2 -1
- package/components/CruResource.vue +6 -1
- package/components/DetailText.vue +5 -0
- package/components/ExplorerMembers.vue +1 -1
- package/components/ExplorerProjectsNamespaces.vue +68 -18
- package/components/GlobalRoleBindings.vue +5 -1
- package/components/GrowlManager.vue +1 -0
- package/components/LandingPagePreference.vue +7 -3
- package/components/LocaleSelector.vue +39 -95
- package/components/ModalManager.vue +55 -0
- package/components/ModalWithCard.vue +1 -0
- package/components/PromptModal.vue +47 -8
- package/components/PromptRemove.vue +1 -0
- package/components/PromptRestore.vue +1 -0
- package/components/ResourceCancelModal.vue +1 -0
- package/components/ResourceDetail/Masthead.vue +38 -12
- package/components/ResourceDetail/__tests__/Masthead.test.ts +5 -1
- package/components/ResourceDetail/index.vue +47 -12
- package/components/ResourceTable.vue +54 -19
- package/components/SideNav.vue +5 -1
- package/components/SlideInPanelManager.vue +126 -0
- package/components/SortableTable/THead.vue +5 -2
- package/components/SortableTable/actions.js +1 -1
- package/components/SortableTable/index.vue +64 -51
- package/components/SortableTable/paging.js +16 -19
- package/components/SortableTable/selection.js +0 -11
- package/components/Wizard.vue +2 -2
- package/components/__tests__/AsyncButton.test.ts +2 -2
- package/components/__tests__/ModalManager.spec.ts +176 -0
- package/components/__tests__/PromptModal.test.ts +148 -0
- package/components/__tests__/SlideInPanelManager.spec.ts +166 -0
- package/components/auth/AuthBanner.vue +13 -11
- package/components/auth/Principal.vue +1 -0
- package/components/auth/__tests__/RoleDetailEdit.test.ts +3 -2
- package/components/auth/login/ldap.vue +1 -1
- package/components/fleet/FleetResources.vue +21 -6
- package/components/form/ArrayList.vue +76 -60
- package/components/form/BannerSettings.vue +17 -2
- package/components/form/ColorInput.vue +35 -6
- package/components/form/Command.vue +6 -15
- package/components/form/EnvVars.vue +16 -8
- package/components/form/HealthCheck.vue +3 -3
- package/components/form/HookOption.vue +11 -16
- package/components/form/LabeledSelect.vue +18 -22
- package/components/form/LifecycleHooks.vue +3 -3
- package/components/form/MatchExpressions.vue +14 -8
- package/components/form/NameNsDescription.vue +128 -104
- package/components/form/Networking.vue +20 -12
- package/components/form/NodeAffinity.vue +31 -23
- package/components/form/NodeScheduling.vue +13 -3
- package/components/form/NotificationSettings.vue +15 -1
- package/components/form/Password.vue +1 -0
- package/components/form/PodAffinity.vue +43 -43
- package/components/form/Probe.vue +68 -66
- package/components/form/ResourceQuota/Project.vue +5 -1
- package/components/form/ResourceSelector.vue +7 -9
- package/components/form/SSHKnownHosts/__tests__/KnownHostsEditDialog.test.ts +16 -24
- package/components/form/SSHKnownHosts/index.vue +30 -13
- package/components/form/Security.vue +54 -56
- package/components/form/Select.vue +32 -21
- package/components/form/ShellInput.vue +5 -1
- package/components/form/Tolerations.vue +5 -1
- package/components/form/ValueFromResource.vue +134 -121
- package/components/form/WorkloadPorts.vue +18 -18
- package/components/form/__tests__/ArrayList.test.ts +5 -2
- package/components/form/__tests__/ColorInput.test.ts +35 -0
- package/components/form/__tests__/LabeledSelect.test.ts +40 -0
- package/components/form/__tests__/MatchExpressions.test.ts +12 -12
- package/components/form/__tests__/NameNsDescription.test.ts +115 -14
- package/components/form/__tests__/Probe.test.ts +12 -8
- package/components/form/__tests__/SSHKnownHosts.test.ts +22 -2
- package/components/form/__tests__/Select.test.ts +37 -0
- package/components/formatter/InternalExternalIP.vue +2 -0
- package/components/formatter/SecretData.vue +20 -7
- package/components/nav/Group.vue +27 -5
- package/components/nav/Header.vue +17 -43
- package/components/nav/NamespaceFilter.vue +134 -86
- package/components/nav/TopLevelMenu.vue +4 -5
- package/components/nav/Type.vue +12 -1
- package/components/nav/WindowManager/ContainerLogs.vue +87 -61
- package/components/nav/WindowManager/ContainerLogsActions.vue +76 -0
- package/components/templates/blank.vue +4 -1
- package/components/templates/default.vue +8 -3
- package/components/templates/home.vue +10 -1
- package/components/templates/plain.vue +10 -4
- package/composables/focusTrap.ts +12 -4
- package/composables/useRuntimeFlag.ts +29 -0
- package/config/router/routes.js +20 -13
- package/config/store.js +4 -0
- package/config/uiplugins.js +5 -1
- package/core/types.ts +12 -6
- package/detail/catalog.cattle.io.app.vue +6 -1
- package/detail/fleet.cattle.io.bundle.vue +70 -6
- package/detail/fleet.cattle.io.gitrepo.vue +1 -1
- package/detail/namespace.vue +0 -3
- package/detail/node.vue +17 -13
- package/detail/provisioning.cattle.io.cluster.vue +72 -6
- package/dialog/AddCustomBadgeDialog.vue +1 -1
- package/{pages/c/_cluster/uiplugins/AddExtensionRepos.vue → dialog/AddExtensionReposDialog.vue} +72 -42
- package/{components/AssignTo.vue → dialog/AssignToDialog.vue} +71 -80
- package/dialog/ChangePasswordDialog.vue +106 -0
- package/dialog/DeactivateDriverDialog.vue +1 -0
- package/{pages/c/_cluster/uiplugins/DeveloperInstallDialog.vue → dialog/DeveloperLoadExtensionDialog.vue} +74 -71
- package/dialog/DisableAuthProviderDialog.vue +101 -0
- package/dialog/DrainNode.vue +1 -1
- package/{pages/c/_cluster/uiplugins/CatalogList/CatalogLoadDialog.vue → dialog/ExtensionCatalogInstallDialog.vue} +100 -88
- package/{pages/c/_cluster/uiplugins/CatalogList/CatalogUninstallDialog.vue → dialog/ExtensionCatalogUninstallDialog.vue} +69 -57
- package/dialog/FeatureFlagListDialog.vue +288 -0
- package/dialog/ForceMachineRemoveDialog.vue +5 -2
- package/{components/Import.vue → dialog/ImportDialog.vue} +0 -5
- package/{pages/c/_cluster/uiplugins/InstallDialog.vue → dialog/InstallExtensionDialog.vue} +124 -106
- package/{components/form/SSHKnownHosts → dialog}/KnownHostsEditDialog.vue +52 -59
- package/dialog/MoveNamespaceDialog.vue +157 -0
- package/dialog/ScalePoolDownDialog.vue +1 -1
- package/{components/nav/Jump.vue → dialog/SearchDialog.vue} +34 -14
- package/{pages/c/_cluster/uiplugins/UninstallDialog.vue → dialog/UninstallExtensionDialog.vue} +67 -58
- package/dialog/WechatDialog.vue +57 -0
- package/edit/__tests__/monitoring.coreos.com.prometheusrule.test.ts +16 -3
- package/edit/auth/__tests__/oidc.test.ts +152 -109
- package/edit/auth/azuread.vue +2 -1
- package/edit/auth/github.vue +1 -1
- package/edit/auth/googleoauth.vue +5 -1
- package/edit/auth/ldap/index.vue +1 -1
- package/edit/auth/oidc.vue +38 -5
- package/edit/auth/saml.vue +1 -1
- package/edit/cloudcredential.vue +24 -9
- package/edit/logging.banzaicloud.io.output/__tests__/logging.banzaicloud.io.output.test.ts +40 -9
- package/edit/management.cattle.io.user.vue +28 -3
- package/edit/namespace.vue +1 -4
- package/edit/networking.k8s.io.ingress/IngressClass.vue +7 -3
- package/edit/networking.k8s.io.ingress/__tests__/IngressClass.test.ts +58 -0
- package/edit/persistentvolume/__tests__/persistentvolume.test.ts +14 -2
- package/edit/provisioning.cattle.io.cluster/CustomCommand.vue +4 -1
- package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +26 -9
- package/edit/provisioning.cattle.io.cluster/__tests__/Advanced.test.ts +8 -8
- package/edit/provisioning.cattle.io.cluster/__tests__/DirectoryConfig.test.ts +26 -12
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +66 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/utils/rke2-test-data.ts +58 -0
- package/edit/provisioning.cattle.io.cluster/rke2.vue +49 -41
- package/edit/provisioning.cattle.io.cluster/tabs/AgentConfiguration.vue +6 -1
- package/edit/provisioning.cattle.io.cluster/tabs/DirectoryConfig.vue +5 -3
- package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +33 -2
- package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +2 -2
- package/edit/token.vue +2 -0
- package/edit/workload/index.vue +1 -0
- package/edit/workload/mixins/workload.js +0 -2
- package/initialize/install-plugins.js +2 -1
- package/list/harvesterhci.io.management.cluster.vue +4 -1
- package/list/management.cattle.io.feature.vue +4 -287
- package/list/provisioning.cattle.io.cluster.vue +20 -12
- package/machine-config/azure.vue +16 -4
- package/mixins/vue-select-overrides.js +0 -4
- package/models/__tests__/namespace.test.ts +25 -1
- package/models/cloudcredential.js +5 -0
- package/models/fleet.cattle.io.cluster.js +8 -2
- package/models/fleet.cattle.io.gitrepo.js +8 -34
- package/models/kontainerdriver.js +6 -3
- package/models/management.cattle.io.feature.js +7 -1
- package/models/management.cattle.io.node.js +3 -3
- package/models/namespace.js +11 -6
- package/models/nodedriver.js +6 -3
- package/models/workload.js +4 -1
- package/package.json +3 -3
- package/pages/about.vue +13 -3
- package/pages/account/index.vue +16 -6
- package/pages/auth/login.vue +18 -7
- package/pages/auth/logout.vue +4 -1
- package/pages/auth/setup.vue +2 -0
- package/pages/auth/verify.vue +13 -8
- package/pages/c/_cluster/apps/charts/chart.vue +1 -1
- package/pages/c/_cluster/apps/charts/install.vue +26 -26
- package/pages/c/_cluster/auth/config/index.vue +10 -12
- package/pages/c/_cluster/explorer/EventsTable.vue +38 -33
- package/pages/c/_cluster/explorer/index.vue +17 -15
- package/pages/c/_cluster/istio/index.vue +2 -2
- package/pages/c/_cluster/longhorn/index.vue +1 -1
- package/pages/c/_cluster/monitoring/index.vue +1 -1
- package/pages/c/_cluster/monitoring/monitor/_namespace/_id.vue +4 -2
- package/pages/c/_cluster/monitoring/monitor/create.vue +4 -2
- package/pages/c/_cluster/monitoring/route-receiver/_id.vue +4 -2
- package/pages/c/_cluster/monitoring/route-receiver/create.vue +5 -2
- package/pages/c/_cluster/neuvector/index.vue +1 -1
- package/pages/c/_cluster/settings/banners.vue +4 -3
- package/pages/c/_cluster/uiplugins/CatalogList/index.vue +8 -10
- package/pages/c/_cluster/uiplugins/__tests__/AddExtensionRepos.test.ts +4 -7
- package/pages/c/_cluster/uiplugins/index.vue +98 -55
- package/pages/diagnostic.vue +59 -11
- package/pages/fail-whale.vue +14 -8
- package/pages/home.vue +24 -18
- package/pages/prefs.vue +7 -6
- package/pages/support/index.vue +4 -1
- package/plugins/internal-api/index.ts +37 -0
- package/plugins/internal-api/shared/base-api.ts +13 -0
- package/plugins/internal-api/shell/shell.api.ts +108 -0
- package/plugins/steve/actions.js +0 -12
- package/public/index.html +1 -0
- package/rancher-components/Card/Card.vue +1 -1
- package/rancher-components/Form/Checkbox/Checkbox.test.ts +59 -1
- package/rancher-components/Form/Checkbox/Checkbox.vue +27 -3
- package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +47 -0
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +20 -2
- package/rancher-components/Form/Radio/RadioButton.test.ts +36 -1
- package/rancher-components/Form/Radio/RadioButton.vue +20 -4
- package/rancher-components/Form/Radio/RadioGroup.test.ts +60 -0
- package/rancher-components/Form/Radio/RadioGroup.vue +52 -10
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.test.ts +17 -0
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +5 -0
- package/rancher-components/LabeledTooltip/LabeledTooltip.vue +10 -1
- package/rancher-components/RcButton/RcButton.vue +2 -1
- package/rancher-components/RcButton/types.ts +1 -0
- package/rancher-components/RcDropdown/RcDropdown.vue +18 -6
- package/rancher-components/RcDropdown/RcDropdownItem.vue +3 -56
- package/rancher-components/RcDropdown/RcDropdownItemCheckbox.vue +68 -0
- package/rancher-components/RcDropdown/RcDropdownItemSelect.vue +92 -0
- package/rancher-components/RcDropdown/RcDropdownTrigger.vue +10 -0
- package/rancher-components/RcDropdown/index.ts +2 -0
- package/rancher-components/RcDropdown/useDropdownCollection.ts +8 -0
- package/rancher-components/RcDropdown/useDropdownContext.ts +9 -3
- package/rancher-components/RcDropdown/useDropdownItem.ts +63 -0
- package/scripts/extension/bundle +20 -0
- package/scripts/extension/helm/charts/ui-plugin-server/templates/cr.yaml +2 -1
- package/scripts/extension/helm/charts/ui-plugin-server/values.yaml +2 -0
- package/scripts/extension/helmpatch +44 -31
- package/scripts/extension/publish +12 -12
- package/scripts/typegen.sh +2 -4
- package/server/har-file.js +25 -3
- package/store/action-menu.js +26 -56
- package/store/features.js +2 -1
- package/store/index.js +5 -0
- package/store/modal.ts +71 -0
- package/store/slideInPanel.ts +47 -0
- package/store/type-map.js +12 -1
- package/store/type-map.utils.ts +4 -4
- package/types/global-vue.d.ts +5 -0
- package/types/internal-api/shell/growl.d.ts +25 -0
- package/types/internal-api/shell/modal.d.ts +77 -0
- package/types/internal-api/shell/slideIn.d.ts +15 -0
- package/types/resources/fleet.d.ts +0 -14
- package/types/shell/index.d.ts +43 -24
- package/types/vue-shim.d.ts +4 -1
- package/utils/__mocks__/tabbable.js +13 -0
- package/utils/__tests__/object.test.ts +38 -4
- package/utils/cluster.js +35 -0
- package/utils/fleet.ts +15 -73
- package/utils/object.js +48 -5
- package/utils/validators/formRules/__tests__/index.test.ts +10 -1
- package/utils/validators/formRules/index.ts +27 -3
- package/utils/validators/machine-pool.ts +20 -0
- package/components/DisableAuthProviderModal.vue +0 -114
- package/components/MoveModal.vue +0 -166
- package/components/PromptChangePassword.vue +0 -123
- package/components/fleet/FleetBundleResources.vue +0 -86
- package/components/formatter/ExtensionCache.vue +0 -74
- package/components/formatter/Port.vue +0 -24
- package/components/formatter/SecretType.vue +0 -41
- package/types/vue-shim.d +0 -20
|
@@ -6,7 +6,7 @@ import { BOTH, TYPE_MODES } from '@shell/store/type-map';
|
|
|
6
6
|
import { COUNT } from '@shell/config/types';
|
|
7
7
|
|
|
8
8
|
export default {
|
|
9
|
-
emits: ['
|
|
9
|
+
emits: ['close'],
|
|
10
10
|
|
|
11
11
|
components: { Group },
|
|
12
12
|
|
|
@@ -41,7 +41,7 @@ export default {
|
|
|
41
41
|
const allTypes = allTypesByMode[TYPE_MODES.ALL];
|
|
42
42
|
const out = this.$store.getters['type-map/getTree'](productId, TYPE_MODES.ALL, allTypes, clusterId, BOTH, null, this.value);
|
|
43
43
|
|
|
44
|
-
//
|
|
44
|
+
// Supplement the output with count info. Usually the `Type` component would handle this individually... but scales real bad so give it
|
|
45
45
|
// some help
|
|
46
46
|
const counts = this.$store.getters[`${ product.inStore }/all`](COUNT)?.[0]?.counts || {};
|
|
47
47
|
|
|
@@ -77,16 +77,22 @@ export default {
|
|
|
77
77
|
>
|
|
78
78
|
{{ t('nav.resourceSearch.filteringDescription') }}
|
|
79
79
|
</p>
|
|
80
|
-
<
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
80
|
+
<div class="dialog-title">
|
|
81
|
+
<div>{{ t('nav.resourceSearch.label') }}</div>
|
|
82
|
+
<p>{{ t('nav.resourceSearch.prompt') }}</p>
|
|
83
|
+
</div>
|
|
84
|
+
<div class="search-box">
|
|
85
|
+
<input
|
|
86
|
+
ref="input"
|
|
87
|
+
v-model="value"
|
|
88
|
+
:placeholder="t('nav.resourceSearch.placeholder')"
|
|
89
|
+
class="search"
|
|
90
|
+
role="textbox"
|
|
91
|
+
:aria-label="t('nav.resourceSearch.label')"
|
|
92
|
+
aria-describedby="describe-filter-resource-search"
|
|
93
|
+
@keyup.esc="$emit('close')"
|
|
94
|
+
>
|
|
95
|
+
</div>
|
|
90
96
|
<div class="results">
|
|
91
97
|
<div
|
|
92
98
|
v-for="g in groups"
|
|
@@ -100,7 +106,7 @@ export default {
|
|
|
100
106
|
:group="g"
|
|
101
107
|
:can-collapse="false"
|
|
102
108
|
:fixed-open="true"
|
|
103
|
-
@close="$emit('
|
|
109
|
+
@close="$emit('close')"
|
|
104
110
|
>
|
|
105
111
|
<template #accordion>
|
|
106
112
|
<h6>{{ g.label }}</h6>
|
|
@@ -119,17 +125,31 @@ export default {
|
|
|
119
125
|
box-shadow: none;
|
|
120
126
|
}
|
|
121
127
|
|
|
128
|
+
.search-box {
|
|
129
|
+
margin: 8px;
|
|
130
|
+
}
|
|
131
|
+
|
|
122
132
|
.search:focus-visible {
|
|
123
133
|
outline-offset: -2px;
|
|
124
134
|
}
|
|
125
135
|
|
|
136
|
+
.dialog-title {
|
|
137
|
+
padding: 8px;
|
|
138
|
+
|
|
139
|
+
> div {
|
|
140
|
+
font-size: 16px;
|
|
141
|
+
font-weight: bold;
|
|
142
|
+
margin: 8px 0;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
126
146
|
.results {
|
|
127
147
|
margin-top: -1px;
|
|
128
148
|
overflow-y: auto;
|
|
129
149
|
padding: 10px;
|
|
130
150
|
color: var(--dropdown-text);
|
|
131
151
|
background-color: var(--dropdown-bg);
|
|
132
|
-
border: 1px solid var(--dropdown-border);
|
|
152
|
+
border-top: 1px solid var(--dropdown-border);
|
|
133
153
|
height: 75vh;
|
|
134
154
|
}
|
|
135
155
|
</style>
|
package/{pages/c/_cluster/uiplugins/UninstallDialog.vue → dialog/UninstallExtensionDialog.vue}
RENAMED
|
@@ -2,47 +2,70 @@
|
|
|
2
2
|
import { mapGetters } from 'vuex';
|
|
3
3
|
|
|
4
4
|
import AsyncButton from '@shell/components/AsyncButton';
|
|
5
|
-
import AppModal from '@shell/components/AppModal.vue';
|
|
6
5
|
import { CATALOG } from '@shell/config/types';
|
|
7
6
|
import { UI_PLUGIN_NAMESPACE } from '@shell/config/uiplugins';
|
|
8
7
|
|
|
9
8
|
export default {
|
|
10
|
-
emits: ['
|
|
11
|
-
|
|
12
|
-
components: {
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
emits: ['close'],
|
|
10
|
+
|
|
11
|
+
components: { AsyncButton },
|
|
12
|
+
|
|
13
|
+
props: {
|
|
14
|
+
/**
|
|
15
|
+
* Plugin object
|
|
16
|
+
*/
|
|
17
|
+
plugin: {
|
|
18
|
+
type: Object,
|
|
19
|
+
default: () => {},
|
|
20
|
+
required: true
|
|
21
|
+
},
|
|
22
|
+
/**
|
|
23
|
+
* Callback to update install status on extensions main screen
|
|
24
|
+
*/
|
|
25
|
+
updateStatus: {
|
|
26
|
+
type: Function,
|
|
27
|
+
default: () => {},
|
|
28
|
+
required: true
|
|
29
|
+
},
|
|
30
|
+
/**
|
|
31
|
+
* Callback when modal is closed
|
|
32
|
+
*/
|
|
33
|
+
closed: {
|
|
34
|
+
type: Function,
|
|
35
|
+
default: () => {},
|
|
36
|
+
required: true
|
|
37
|
+
},
|
|
38
|
+
resources: {
|
|
39
|
+
type: Array,
|
|
40
|
+
default: () => []
|
|
41
|
+
},
|
|
42
|
+
registerBackgroundClosing: {
|
|
43
|
+
type: Function,
|
|
44
|
+
default: () => {}
|
|
45
|
+
}
|
|
15
46
|
},
|
|
16
47
|
|
|
17
48
|
data() {
|
|
18
|
-
return {
|
|
19
|
-
plugin: undefined, busy: false, showModal: false
|
|
20
|
-
};
|
|
49
|
+
return { busy: false };
|
|
21
50
|
},
|
|
22
51
|
|
|
23
|
-
computed: {
|
|
24
|
-
...mapGetters({ allCharts: 'catalog/charts' }),
|
|
25
|
-
returnFocusSelector() {
|
|
26
|
-
return `[data-testid="extension-card-uninstall-btn-${ this.plugin?.name }"]`;
|
|
27
|
-
}
|
|
28
|
-
},
|
|
52
|
+
computed: { ...mapGetters({ allCharts: 'catalog/charts' }) },
|
|
29
53
|
|
|
30
54
|
methods: {
|
|
31
55
|
showDialog(plugin) {
|
|
32
56
|
this.plugin = plugin;
|
|
33
57
|
this.busy = false;
|
|
34
|
-
this.showModal = true;
|
|
35
58
|
},
|
|
36
59
|
closeDialog(result) {
|
|
37
|
-
this.
|
|
38
|
-
this.$emit('
|
|
60
|
+
this.closed(result);
|
|
61
|
+
this.$emit('close');
|
|
39
62
|
},
|
|
40
63
|
async uninstall() {
|
|
41
64
|
this.busy = true;
|
|
42
65
|
|
|
43
66
|
const plugin = this.plugin;
|
|
44
67
|
|
|
45
|
-
this
|
|
68
|
+
this.updateStatus(plugin.name, 'uninstall');
|
|
46
69
|
|
|
47
70
|
// Delete the CR if this is a developer plugin (there is no Helm App, so need to remove the CRD ourselves)
|
|
48
71
|
if (plugin.uiplugin?.isDeveloper) {
|
|
@@ -78,47 +101,33 @@ export default {
|
|
|
78
101
|
</script>
|
|
79
102
|
|
|
80
103
|
<template>
|
|
81
|
-
<
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
<button
|
|
106
|
-
:disabled="busy"
|
|
107
|
-
class="btn role-secondary"
|
|
108
|
-
data-testid="uninstall-ext-modal-cancel-btn"
|
|
109
|
-
@click="closeDialog(false)"
|
|
110
|
-
>
|
|
111
|
-
{{ t('generic.cancel') }}
|
|
112
|
-
</button>
|
|
113
|
-
<AsyncButton
|
|
114
|
-
mode="uninstall"
|
|
115
|
-
data-testid="uninstall-ext-modal-uninstall-btn"
|
|
116
|
-
@click="uninstall()"
|
|
117
|
-
/>
|
|
118
|
-
</div>
|
|
104
|
+
<div class="plugin-install-dialog">
|
|
105
|
+
<h4 class="mt-10">
|
|
106
|
+
{{ t('plugins.uninstall.title', { name: plugin?.label }) }}
|
|
107
|
+
</h4>
|
|
108
|
+
<div class="mt-10 dialog-panel">
|
|
109
|
+
<div class="dialog-info">
|
|
110
|
+
<p>
|
|
111
|
+
{{ t('plugins.uninstall.prompt') }}
|
|
112
|
+
</p>
|
|
113
|
+
</div>
|
|
114
|
+
<div class="dialog-buttons">
|
|
115
|
+
<button
|
|
116
|
+
:disabled="busy"
|
|
117
|
+
class="btn role-secondary"
|
|
118
|
+
data-testid="uninstall-ext-modal-cancel-btn"
|
|
119
|
+
@click="closeDialog(false)"
|
|
120
|
+
>
|
|
121
|
+
{{ t('generic.cancel') }}
|
|
122
|
+
</button>
|
|
123
|
+
<AsyncButton
|
|
124
|
+
mode="uninstall"
|
|
125
|
+
data-testid="uninstall-ext-modal-uninstall-btn"
|
|
126
|
+
@click="uninstall()"
|
|
127
|
+
/>
|
|
119
128
|
</div>
|
|
120
129
|
</div>
|
|
121
|
-
</
|
|
130
|
+
</div>
|
|
122
131
|
</template>
|
|
123
132
|
|
|
124
133
|
<style lang="scss" scoped>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
// i18n-ignore footer.wechat.modalText, footer.wechat.modalText2
|
|
3
|
+
export default {
|
|
4
|
+
emits: ['close'],
|
|
5
|
+
|
|
6
|
+
name: 'WechatModal',
|
|
7
|
+
|
|
8
|
+
methods: {
|
|
9
|
+
close() {
|
|
10
|
+
this.$emit('close');
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<div class="wechat-modal">
|
|
18
|
+
<h1>{{ t('footer.wechat.modalText') }}</h1>
|
|
19
|
+
<h1>{{ t('footer.wechat.modalText2') }}</h1>
|
|
20
|
+
<div class="qr-img" />
|
|
21
|
+
<div>
|
|
22
|
+
<button
|
|
23
|
+
class="btn role-primary"
|
|
24
|
+
tabindex="0"
|
|
25
|
+
:aria-label="t('generic.close')"
|
|
26
|
+
role="button"
|
|
27
|
+
@click="close"
|
|
28
|
+
@keydown.enter.stop
|
|
29
|
+
>
|
|
30
|
+
{{ t('generic.close') }}
|
|
31
|
+
</button>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
</template>
|
|
35
|
+
|
|
36
|
+
<style lang='scss' scoped>
|
|
37
|
+
.wechat-modal {
|
|
38
|
+
margin: 60px;
|
|
39
|
+
display: flex;
|
|
40
|
+
flex-direction: column;
|
|
41
|
+
align-items: center;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.btn {
|
|
45
|
+
margin: 20px auto 0;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.qr-img {
|
|
49
|
+
background-image: url('../assets/images/wechat-qr-code.jpg');
|
|
50
|
+
background-repeat: no-repeat;
|
|
51
|
+
background-size: cover;
|
|
52
|
+
background-position: center center;
|
|
53
|
+
height: 128px;
|
|
54
|
+
width: 128px;
|
|
55
|
+
margin: 15px auto 10px;
|
|
56
|
+
}
|
|
57
|
+
</style>
|
|
@@ -2,14 +2,23 @@ import { mount } from '@vue/test-utils';
|
|
|
2
2
|
import FormValidation from '@shell/mixins/form-validation';
|
|
3
3
|
import Monitoring from '@shell/edit/monitoring.coreos.com.prometheusrule/index.vue';
|
|
4
4
|
import { _EDIT } from '@shell/config/query-params';
|
|
5
|
+
import { createStore } from 'vuex';
|
|
5
6
|
|
|
6
7
|
describe('edit: management.cattle.io.setting should', () => {
|
|
7
8
|
const MOCKED_ERRORS = ['error1', 'error2', 'error3', 'error4', 'error5'];
|
|
8
9
|
const ERROR_BANNER_SELECTOR = '[data-testid="banner-close"]';
|
|
10
|
+
const store = createStore({
|
|
11
|
+
getters: {
|
|
12
|
+
namespaces: () => () => ({}),
|
|
13
|
+
currentStore: () => () => 'current_store',
|
|
14
|
+
'current_store/schemaFor': () => jest.fn()
|
|
15
|
+
}
|
|
16
|
+
});
|
|
9
17
|
const requiredSetup = () => ({
|
|
10
18
|
// Remove all these mocks after migration to Vue 2.7/3 due mixin logic
|
|
11
19
|
global: {
|
|
12
|
-
|
|
20
|
+
provide: { store },
|
|
21
|
+
mocks: {
|
|
13
22
|
$store: {
|
|
14
23
|
dispatch: jest.fn(),
|
|
15
24
|
getters: {
|
|
@@ -35,8 +44,12 @@ describe('edit: management.cattle.io.setting should', () => {
|
|
|
35
44
|
canYaml: false,
|
|
36
45
|
mode: _EDIT,
|
|
37
46
|
resource: {},
|
|
38
|
-
value: {
|
|
39
|
-
|
|
47
|
+
value: {
|
|
48
|
+
setAnnotation: jest.fn(),
|
|
49
|
+
value: 'anything',
|
|
50
|
+
metadata: {},
|
|
51
|
+
},
|
|
52
|
+
name: ''
|
|
40
53
|
},
|
|
41
54
|
...requiredSetup()
|
|
42
55
|
});
|
|
@@ -32,151 +32,194 @@ const mockModel = {
|
|
|
32
32
|
};
|
|
33
33
|
|
|
34
34
|
describe('oidc.vue', () => {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
35
|
+
describe('given default valid values', () => {
|
|
36
|
+
let wrapper: VueWrapper<any, any>;
|
|
37
|
+
const requiredSetup = () => ({
|
|
38
|
+
data() {
|
|
39
|
+
return {
|
|
40
|
+
isEnabling: false,
|
|
41
|
+
editConfig: false,
|
|
42
|
+
model: { ...mockModel },
|
|
43
|
+
serverSetting: null,
|
|
44
|
+
errors: [],
|
|
45
|
+
originalModel: null,
|
|
46
|
+
principals: [],
|
|
47
|
+
authConfigName: 'oidc',
|
|
48
|
+
} as any; // any is necessary as in pre-existing tests we are including inherited mixins values
|
|
49
|
+
},
|
|
50
|
+
global: {
|
|
51
|
+
mocks: {
|
|
52
|
+
$fetchState: { pending: false },
|
|
53
|
+
$store: {
|
|
54
|
+
getters: {
|
|
55
|
+
currentStore: () => 'current_store',
|
|
56
|
+
'current_store/schemaFor': jest.fn(),
|
|
57
|
+
'current_store/all': jest.fn(),
|
|
58
|
+
'i18n/t': (val: string) => val,
|
|
59
|
+
'i18n/exists': jest.fn(),
|
|
60
|
+
},
|
|
61
|
+
dispatch: jest.fn()
|
|
59
62
|
},
|
|
60
|
-
|
|
63
|
+
$route: { query: { AS: '' }, params: { id: 'oicd' } },
|
|
64
|
+
$router: { applyQuery: jest.fn() },
|
|
61
65
|
},
|
|
62
|
-
$route: { query: { AS: '' }, params: { id: 'oicd' } },
|
|
63
|
-
$router: { applyQuery: jest.fn() },
|
|
64
66
|
},
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
});
|
|
67
|
+
props: {
|
|
68
|
+
value: { applicationSecret: '' },
|
|
69
|
+
mode: _EDIT,
|
|
70
|
+
},
|
|
71
|
+
});
|
|
71
72
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
afterEach(() => {
|
|
76
|
-
wrapper.unmount();
|
|
77
|
-
});
|
|
73
|
+
beforeEach(() => {
|
|
74
|
+
wrapper = mount(oidc, { ...requiredSetup() });
|
|
75
|
+
});
|
|
78
76
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
77
|
+
afterEach(() => {
|
|
78
|
+
wrapper.unmount();
|
|
79
|
+
});
|
|
82
80
|
|
|
83
|
-
|
|
81
|
+
describe('have "Create" button disabled', () => {
|
|
82
|
+
it('given missing Auth endpoint URL', () => {
|
|
83
|
+
wrapper.vm.model.authEndpoint = '';
|
|
84
|
+
wrapper.vm.model.scopes = 'openid profile email'; // set scope to be sure
|
|
85
|
+
wrapper.vm.oidcScope = ['openid', 'profile', 'email']; // TODO #13457: this is duplicated due wrong format of scopes
|
|
84
86
|
|
|
85
|
-
|
|
86
|
-
});
|
|
87
|
+
const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
|
|
87
88
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
await nextTick();
|
|
89
|
+
expect(saveButton.disabled).toBe(true);
|
|
90
|
+
});
|
|
91
91
|
|
|
92
|
-
|
|
92
|
+
it('given missing required basic scopes', () => {
|
|
93
|
+
wrapper.vm.model.authEndpoint = 'whatever'; // set auth endpoint to be sure
|
|
94
|
+
wrapper.vm.model.scopes = 'something else'; // set wrong scope
|
|
95
|
+
wrapper.vm.oidcScope = ['something', 'else']; // TODO #13457: this is duplicated due wrong format of scopes
|
|
93
96
|
|
|
94
|
-
|
|
95
|
-
});
|
|
97
|
+
const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
|
|
96
98
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
await nextTick();
|
|
99
|
+
expect(saveButton.disabled).toBe(true);
|
|
100
|
+
});
|
|
100
101
|
|
|
101
|
-
|
|
102
|
+
it('when provider is disabled and editing config before fields are filled in', async() => {
|
|
103
|
+
wrapper.setData({ model: {}, editConfig: true });
|
|
104
|
+
await nextTick();
|
|
102
105
|
|
|
103
|
-
|
|
104
|
-
});
|
|
106
|
+
const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
|
|
105
107
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
await nextTick();
|
|
108
|
+
expect(saveButton.disabled).toBe(true);
|
|
109
|
+
});
|
|
109
110
|
|
|
110
|
-
|
|
111
|
+
it('when provider is disabled and editing config after required fields and scope is missing openid', async() => {
|
|
112
|
+
wrapper.setData({ oidcUrls: { url: validUrl, realm: validRealm } });
|
|
113
|
+
await nextTick();
|
|
111
114
|
|
|
112
|
-
|
|
113
|
-
});
|
|
115
|
+
const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
|
|
114
116
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
117
|
+
expect(saveButton.disabled).toBe(true);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
118
120
|
|
|
119
|
-
|
|
121
|
+
describe('have "Create" button enabled', () => {
|
|
122
|
+
it('when customEndpoint is disabled and required fields are filled in', async() => {
|
|
123
|
+
wrapper.setData({ oidcUrls: { url: validUrl, realm: validRealm }, oidcScope: validScope.split(' ') });
|
|
124
|
+
await nextTick();
|
|
120
125
|
|
|
121
|
-
|
|
122
|
-
});
|
|
126
|
+
const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
|
|
123
127
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
await nextTick();
|
|
128
|
+
expect(saveButton.disabled).toBe(false);
|
|
129
|
+
});
|
|
127
130
|
|
|
128
|
-
|
|
131
|
+
it('when customEndpoint is enabled and required fields are filled in', async() => {
|
|
132
|
+
wrapper.setData({ customEndpoint: { value: true }, oidcScope: validScope.split(' ') });
|
|
133
|
+
await nextTick();
|
|
129
134
|
|
|
130
|
-
|
|
131
|
-
await nextTick();
|
|
135
|
+
const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
|
|
132
136
|
|
|
133
|
-
|
|
134
|
-
|
|
137
|
+
expect(saveButton.disabled).toBe(false);
|
|
138
|
+
});
|
|
135
139
|
|
|
136
|
-
|
|
137
|
-
|
|
140
|
+
it('when provider is enabled and not editing config', async() => {
|
|
141
|
+
wrapper.setData({ model: { enabled: true }, editConfig: false });
|
|
142
|
+
await nextTick();
|
|
138
143
|
|
|
139
|
-
|
|
140
|
-
expect(wrapper.vm.model.groupSearchEnabled).toBe(false);
|
|
141
|
-
});
|
|
144
|
+
const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
|
|
142
145
|
|
|
143
|
-
|
|
144
|
-
|
|
146
|
+
expect(saveButton.disabled).toBe(false);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
145
149
|
|
|
146
|
-
|
|
150
|
+
it('updates issuer endpoint when oidcUrls.url and oidcUrls.realm changes', async() => {
|
|
151
|
+
wrapper.setData({ oidcUrls: { url: validUrl } });
|
|
152
|
+
await nextTick();
|
|
147
153
|
|
|
148
|
-
|
|
149
|
-
expect(wrapper.vm.model.groupSearchEnabled).toBe(true);
|
|
150
|
-
});
|
|
154
|
+
expect(wrapper.vm.model.issuer).toBe(`${ validUrl }/realms/`);
|
|
151
155
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const newUrl = 'whatever';
|
|
156
|
+
wrapper.setData({ oidcUrls: { realm: validRealm } });
|
|
157
|
+
await nextTick();
|
|
155
158
|
|
|
156
|
-
|
|
157
|
-
|
|
159
|
+
expect(wrapper.vm.model.issuer).toBe(`${ validUrl }/realms/${ validRealm }`);
|
|
160
|
+
});
|
|
158
161
|
|
|
159
|
-
|
|
160
|
-
|
|
162
|
+
it('`groupSearchEnabled` defaults to false', async() => {
|
|
163
|
+
const groupSearchCheckbox = wrapper.getComponent('[data-testid="input-group-search"]');
|
|
161
164
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
+
expect(groupSearchCheckbox.isVisible()).toBe(true);
|
|
166
|
+
expect(wrapper.vm.model.groupSearchEnabled).toBe(false);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('`groupSearchEnabled` updates when checkbox is clicked', async() => {
|
|
170
|
+
const groupSearchCheckbox = wrapper.getComponent('[data-testid="input-group-search"]');
|
|
171
|
+
|
|
172
|
+
await groupSearchCheckbox.find('[role="checkbox"]').trigger('click');
|
|
173
|
+
|
|
174
|
+
expect(groupSearchCheckbox.isVisible()).toBe(true);
|
|
175
|
+
expect(wrapper.vm.model.groupSearchEnabled).toBe(true);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('changing URL should update issuer and auth-endpoint if Keycloak', async() => {
|
|
179
|
+
wrapper.vm.model.id = 'keycloakoidc';
|
|
180
|
+
const newUrl = 'whatever';
|
|
181
|
+
|
|
182
|
+
await wrapper.find(`[data-testid="oidc-url"]`).setValue(newUrl);
|
|
183
|
+
await wrapper.vm.$nextTick();
|
|
184
|
+
|
|
185
|
+
const issuerValue = (wrapper.find('[data-testid="oidc-issuer"]').element as HTMLInputElement).value;
|
|
186
|
+
const endpointValue = (wrapper.find('[data-testid="oidc-auth-endpoint"]').element as HTMLInputElement).value;
|
|
187
|
+
|
|
188
|
+
expect(issuerValue).toBe(`${ newUrl }/realms/`);
|
|
189
|
+
expect(endpointValue).toBe(`${ newUrl }/realms//protocol/openid-connect/auth`);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it('changing realm should update issuer and auth-endpoint if Keycloak', async() => {
|
|
193
|
+
const newRealm = 'newRealm';
|
|
194
|
+
const oldUrl = 'oldUrl';
|
|
195
|
+
|
|
196
|
+
wrapper.vm.model.id = 'keycloakoidc';
|
|
197
|
+
wrapper.vm.oidcUrls.url = oldUrl;
|
|
198
|
+
|
|
199
|
+
await wrapper.find(`[data-testid="oidc-realm"]`).setValue(newRealm);
|
|
200
|
+
await wrapper.vm.$nextTick();
|
|
165
201
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
const oldUrl = 'oldUrl';
|
|
202
|
+
const issuerValue = (wrapper.find('[data-testid="oidc-issuer"]').element as HTMLInputElement).value;
|
|
203
|
+
const endpointValue = (wrapper.find('[data-testid="oidc-auth-endpoint"]').element as HTMLInputElement).value;
|
|
169
204
|
|
|
170
|
-
|
|
171
|
-
|
|
205
|
+
expect(issuerValue).toBe(`${ oldUrl }/realms/${ newRealm }`);
|
|
206
|
+
expect(endpointValue).toBe(`${ oldUrl }/realms/${ newRealm }/protocol/openid-connect/auth`);
|
|
207
|
+
});
|
|
172
208
|
|
|
173
|
-
|
|
174
|
-
|
|
209
|
+
it('clear URL should clear issuer and auth-endpoint if Keycloak', async() => {
|
|
210
|
+
wrapper.vm.model.id = 'keycloakoidc';
|
|
211
|
+
const newUrl = 'whatever';
|
|
212
|
+
const urlInput = wrapper.find(`[data-testid="oidc-url"]`);
|
|
175
213
|
|
|
176
|
-
|
|
177
|
-
|
|
214
|
+
await urlInput.setValue(newUrl);
|
|
215
|
+
await wrapper.vm.$nextTick();
|
|
216
|
+
await urlInput.setValue('');
|
|
217
|
+
await wrapper.vm.$nextTick();
|
|
218
|
+
const issuer = (wrapper.find('[data-testid="oidc-issuer"]').element as HTMLInputElement).value;
|
|
219
|
+
const endpoint = (wrapper.find('[data-testid="oidc-auth-endpoint"]').element as HTMLInputElement).value;
|
|
178
220
|
|
|
179
|
-
|
|
180
|
-
|
|
221
|
+
expect(issuer).toBe('');
|
|
222
|
+
expect(endpoint).toBe('');
|
|
223
|
+
});
|
|
181
224
|
});
|
|
182
225
|
});
|