@rancher/shell 3.0.5-rc.1 → 3.0.5-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/assets/data/aws-regions.json +2 -0
- package/assets/images/providers/sks.svg +1 -0
- package/assets/styles/base/_helpers.scss +4 -0
- package/assets/styles/base/_variables.scss +1 -0
- package/assets/styles/global/_layout.scss +0 -1
- package/assets/translations/en-us.yaml +92 -34
- package/assets/translations/zh-hans.yaml +4 -13
- package/chart/monitoring/index.vue +4 -2
- package/components/ActionDropdownShell.vue +71 -0
- package/components/AppModal.vue +18 -4
- package/components/AsyncButton.vue +2 -0
- package/components/CodeMirror.vue +3 -3
- package/components/CommunityLinks.vue +3 -58
- package/components/CruResource.vue +109 -16
- package/components/ExplorerProjectsNamespaces.vue +19 -6
- package/components/FixedBanner.vue +19 -5
- package/components/GlobalRoleBindings.vue +5 -1
- package/components/GrowlManager.vue +1 -0
- package/components/LandingPagePreference.vue +2 -0
- package/components/LocaleSelector.vue +1 -1
- package/components/ModalManager.vue +55 -0
- package/components/PaginatedResourceTable.vue +7 -0
- package/components/PromptModal.vue +47 -8
- package/components/ResourceDetail/Masthead.vue +38 -13
- package/components/ResourceDetail/__tests__/Masthead.test.ts +5 -1
- package/components/ResourceDetail/index.vue +47 -12
- package/components/ResourceList/index.vue +2 -1
- package/components/ResourceTable.vue +54 -19
- package/components/SideNav.vue +5 -1
- package/components/SlideInPanelManager.vue +125 -0
- package/components/SortableTable/THead.vue +5 -2
- package/components/SortableTable/actions.js +1 -1
- package/components/SortableTable/index.vue +54 -40
- package/components/SortableTable/paging.js +16 -19
- package/components/SortableTable/selection.js +1 -12
- package/components/Tabbed/index.vue +6 -0
- package/components/Wizard.vue +2 -2
- package/components/__tests__/AsyncButton.test.ts +39 -0
- package/components/__tests__/CruResource.test.ts +63 -0
- package/components/__tests__/ModalManager.spec.ts +176 -0
- package/components/__tests__/PromptModal.test.ts +146 -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/login/ldap.vue +1 -1
- package/components/fleet/FleetResources.vue +21 -6
- package/components/form/ArrayList.vue +138 -118
- package/components/form/BannerSettings.vue +149 -85
- package/components/form/ColorInput.vue +35 -6
- package/components/form/EnvVars.vue +1 -0
- package/components/form/KeyValue.vue +10 -7
- package/components/form/LabeledSelect.vue +25 -23
- package/components/form/MatchExpressions.vue +9 -2
- package/components/form/NameNsDescription.vue +6 -2
- package/components/form/NotificationSettings.vue +15 -1
- package/components/form/Password.vue +1 -0
- package/components/form/Probe.vue +1 -0
- package/components/form/ResourceSelector.vue +26 -23
- package/components/form/ResourceTabs/index.vue +2 -1
- package/components/form/SSHKnownHosts/__tests__/KnownHostsEditDialog.test.ts +15 -34
- package/components/form/SSHKnownHosts/index.vue +14 -11
- package/components/form/Select.vue +8 -15
- package/components/form/UnitInput.vue +13 -0
- package/components/form/ValueFromResource.vue +12 -12
- package/components/form/__tests__/ArrayList.test.ts +34 -2
- package/components/form/__tests__/ColorInput.test.ts +35 -0
- package/components/form/__tests__/KeyValue.test.ts +36 -0
- package/components/form/__tests__/LabeledSelect.test.ts +73 -0
- package/components/form/__tests__/SSHKnownHosts.test.ts +11 -2
- package/components/form/__tests__/Select.test.ts +34 -1
- package/components/form/__tests__/UnitInput.test.ts +23 -1
- package/components/formatter/ClusterLink.vue +5 -8
- package/components/formatter/Description.vue +30 -0
- package/components/formatter/__tests__/ClusterLink.test.ts +2 -32
- package/components/nav/Group.vue +12 -4
- package/components/nav/Header.vue +16 -43
- package/components/nav/NamespaceFilter.vue +134 -86
- package/components/nav/TopLevelMenu.vue +4 -5
- package/components/nav/WindowManager/ContainerLogs.vue +87 -61
- package/components/nav/WindowManager/ContainerLogsActions.vue +76 -0
- package/components/nav/WindowManager/index.vue +1 -0
- package/components/templates/default.vue +6 -3
- package/components/templates/home.vue +6 -0
- package/components/templates/plain.vue +6 -3
- package/composables/focusTrap.ts +12 -4
- package/config/product/explorer.js +16 -13
- package/config/product/manager.js +1 -28
- package/config/settings.ts +11 -13
- package/config/store.js +4 -0
- package/config/table-headers.js +7 -5
- package/config/uiplugins.js +5 -1
- package/core/types.ts +7 -6
- package/detail/catalog.cattle.io.app.vue +5 -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 +85 -9
- package/detail/service.vue +0 -1
- package/detail/workload/index.vue +21 -34
- package/dialog/AddCustomBadgeDialog.vue +0 -1
- package/{pages/c/_cluster/uiplugins/AddExtensionRepos.vue → dialog/AddExtensionReposDialog.vue} +72 -42
- package/dialog/AssignToDialog.vue +176 -0
- package/dialog/ChangePasswordDialog.vue +106 -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} +83 -65
- package/dialog/FeatureFlagListDialog.vue +288 -0
- package/dialog/ForceMachineRemoveDialog.vue +1 -1
- 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 -62
- 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__/service.test.ts +2 -1
- package/edit/auth/azuread.vue +1 -1
- package/edit/auth/github.vue +1 -1
- package/edit/auth/googleoauth.vue +1 -1
- package/edit/auth/ldap/index.vue +1 -1
- package/edit/auth/oidc.vue +1 -1
- package/edit/auth/saml.vue +1 -1
- package/edit/cloudcredential.vue +24 -10
- package/edit/management.cattle.io.user.vue +28 -3
- package/edit/namespace.vue +1 -4
- package/edit/networking.k8s.io.networkpolicy/PolicyRule.vue +3 -14
- package/edit/networking.k8s.io.networkpolicy/PolicyRuleTarget.vue +57 -62
- package/edit/networking.k8s.io.networkpolicy/PolicyRules.vue +3 -14
- package/edit/networking.k8s.io.networkpolicy/__tests__/PolicyRuleTarget.test.ts +72 -41
- package/edit/networking.k8s.io.networkpolicy/__tests__/utils/mock.json +17 -1
- package/edit/networking.k8s.io.networkpolicy/index.vue +18 -30
- package/edit/provisioning.cattle.io.cluster/CustomCommand.vue +4 -1
- package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +26 -10
- 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/index.vue +21 -73
- package/edit/provisioning.cattle.io.cluster/rke2.vue +24 -7
- package/edit/provisioning.cattle.io.cluster/tabs/DirectoryConfig.vue +5 -3
- package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +4 -1
- package/edit/service.vue +13 -28
- package/initialize/install-plugins.js +2 -1
- package/list/harvesterhci.io.management.cluster.vue +4 -1
- package/list/management.cattle.io.feature.vue +4 -288
- package/list/workload.vue +6 -1
- package/machine-config/azure.vue +16 -4
- package/mixins/resource-fetch-api-pagination.js +55 -43
- package/mixins/resource-fetch.js +14 -5
- package/mixins/vue-select-overrides.js +0 -4
- package/models/__tests__/workload.test.ts +1 -0
- package/models/cluster/node.js +1 -0
- package/models/cluster.js +32 -2
- package/models/fleet.cattle.io.cluster.js +8 -2
- package/models/fleet.cattle.io.gitrepo.js +8 -34
- package/models/management.cattle.io.cluster.js +0 -20
- package/models/management.cattle.io.feature.js +7 -1
- package/models/management.cattle.io.node.js +7 -22
- package/models/management.cattle.io.nodepool.js +12 -0
- package/models/namespace.js +12 -1
- package/models/provisioning.cattle.io.cluster.js +18 -64
- package/models/service.js +24 -9
- package/models/workload.js +70 -31
- package/package.json +1 -1
- package/pages/about.vue +13 -3
- package/pages/account/index.vue +12 -5
- package/pages/auth/login.vue +7 -4
- package/pages/auth/setup.vue +1 -0
- package/pages/auth/verify.vue +9 -7
- package/pages/c/_cluster/apps/charts/install.vue +25 -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 +28 -15
- package/pages/c/_cluster/istio/index.vue +2 -2
- package/pages/c/_cluster/longhorn/index.vue +3 -3
- 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 +60 -5
- package/pages/c/_cluster/settings/performance.vue +7 -26
- 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 +12 -9
- package/pages/fail-whale.vue +8 -5
- package/pages/home.vue +11 -52
- package/pages/prefs.vue +7 -6
- package/plugins/clean-html.js +2 -0
- package/plugins/dashboard-store/__tests__/actions.test.ts +4 -1
- package/plugins/dashboard-store/actions.js +122 -21
- package/plugins/dashboard-store/getters.js +74 -3
- package/plugins/dashboard-store/mutations.js +10 -5
- package/plugins/dashboard-store/resource-class.js +23 -3
- 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/__tests__/getters.test.ts +18 -11
- package/plugins/steve/__tests__/steve-class.test.ts +1 -0
- package/plugins/steve/actions.js +34 -24
- package/plugins/steve/getters.js +39 -10
- package/plugins/steve/steve-class.js +5 -0
- package/plugins/steve/steve-pagination-utils.ts +199 -37
- package/plugins/steve/worker/web-worker.advanced.js +3 -1
- package/public/index.html +1 -0
- package/rancher-components/Banner/Banner.test.ts +51 -3
- package/rancher-components/Banner/Banner.vue +28 -6
- 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 +51 -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 +75 -35
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.test.ts +17 -0
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +26 -1
- 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 +17 -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/index.ts +2 -0
- 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 -13
- package/scripts/typegen.sh +2 -4
- package/store/action-menu.js +26 -56
- package/store/features.js +0 -1
- package/store/index.js +5 -0
- package/store/modal.ts +71 -0
- package/store/slideInPanel.ts +47 -0
- package/store/type-map.js +8 -1
- package/store/type-map.utils.ts +49 -6
- package/types/fleet.d.ts +1 -1
- 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/kube/kube-api.ts +22 -0
- package/types/resources/fleet.d.ts +0 -14
- package/types/resources/settings.d.ts +0 -4
- package/types/shell/index.d.ts +375 -306
- package/types/store/dashboard-store.types.ts +24 -1
- package/types/store/pagination.types.ts +19 -2
- 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 +24 -20
- package/utils/fleet.ts +15 -73
- package/utils/grafana.js +1 -0
- package/utils/object.js +36 -5
- package/utils/pagination-utils.ts +6 -2
- package/utils/perf-setting.utils.ts +28 -0
- package/utils/selector-typed.ts +205 -0
- package/utils/selector.js +29 -6
- package/utils/uiplugins.ts +10 -6
- package/utils/v-sphere.ts +5 -1
- package/utils/validators/formRules/__tests__/index.test.ts +10 -1
- package/utils/validators/formRules/index.ts +27 -3
- package/components/AssignTo.vue +0 -199
- package/components/DisableAuthProviderModal.vue +0 -115
- package/components/MoveModal.vue +0 -167
- package/components/PromptChangePassword.vue +0 -123
- package/components/fleet/FleetBundleResources.vue +0 -86
- package/components/formatter/RKETemplateName.vue +0 -37
- package/dialog/SaveAsRKETemplateDialog.vue +0 -139
- package/types/vue-shim.d +0 -20
package/edit/auth/ldap/index.vue
CHANGED
package/edit/auth/oidc.vue
CHANGED
package/edit/auth/saml.vue
CHANGED
package/edit/cloudcredential.vue
CHANGED
|
@@ -100,6 +100,30 @@ export default {
|
|
|
100
100
|
computed: {
|
|
101
101
|
rke2Enabled: mapFeature(RKE2_FEATURE),
|
|
102
102
|
|
|
103
|
+
hasCustomCloudCredentialComponent() {
|
|
104
|
+
const driverName = this.driverName;
|
|
105
|
+
|
|
106
|
+
return this.$store.getters['type-map/hasCustomCloudCredentialComponent'](driverName);
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
cloudCredentialComponent() {
|
|
110
|
+
const driverName = this.driverName;
|
|
111
|
+
|
|
112
|
+
return this.$store.getters['type-map/importCloudCredential'](driverName);
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
genericCloudCredentialComponent() {
|
|
116
|
+
return this.$store.getters['type-map/importCloudCredential']('generic');
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
cloudComponent() {
|
|
120
|
+
if (this.hasCustomCloudCredentialComponent) {
|
|
121
|
+
return this.cloudCredentialComponent;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return this.genericCloudCredentialComponent;
|
|
125
|
+
},
|
|
126
|
+
|
|
103
127
|
validationPassed() {
|
|
104
128
|
return this.credCustomComponentValidation && this.nameRequiredValidation;
|
|
105
129
|
},
|
|
@@ -112,14 +136,6 @@ export default {
|
|
|
112
136
|
return this.value?.provider;
|
|
113
137
|
},
|
|
114
138
|
|
|
115
|
-
cloudComponent() {
|
|
116
|
-
if (this.$store.getters['type-map/hasCustomCloudCredentialComponent'](this.driverName)) {
|
|
117
|
-
return this.$store.getters['type-map/importCloudCredential'](this.driverName);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return this.$store.getters['type-map/importCloudCredential']('generic');
|
|
121
|
-
},
|
|
122
|
-
|
|
123
139
|
// array of id, label, description, initials for type selection step
|
|
124
140
|
secretSubTypes() {
|
|
125
141
|
const out = [];
|
|
@@ -194,7 +210,6 @@ export default {
|
|
|
194
210
|
},
|
|
195
211
|
|
|
196
212
|
methods: {
|
|
197
|
-
|
|
198
213
|
createValidationChanged(passed) {
|
|
199
214
|
this.credCustomComponentValidation = passed;
|
|
200
215
|
},
|
|
@@ -276,7 +291,6 @@ export default {
|
|
|
276
291
|
<Loading v-if="$fetchState.pending" />
|
|
277
292
|
<CruResource
|
|
278
293
|
v-else
|
|
279
|
-
:done-params="$attrs['done-params'] /* Without this, changes to the validationPassed prop end up propagating all the way to the root of the app and force a re-render when the input becomes valid. I haven't found a reasonable explanation for why this happens. */"
|
|
280
294
|
:mode="mode"
|
|
281
295
|
:validation-passed="validationPassed"
|
|
282
296
|
:selected-subtype="value._type"
|
|
@@ -15,6 +15,8 @@ export default {
|
|
|
15
15
|
ChangePassword, GlobalRoleBindings, CruResource, LabeledInput, Loading
|
|
16
16
|
},
|
|
17
17
|
|
|
18
|
+
emits: ['update:mode'],
|
|
19
|
+
|
|
18
20
|
mixins: [
|
|
19
21
|
CreateEditView
|
|
20
22
|
],
|
|
@@ -40,6 +42,7 @@ export default {
|
|
|
40
42
|
roles: !showGlobalRoles,
|
|
41
43
|
rolesChanged: false,
|
|
42
44
|
},
|
|
45
|
+
watchOverride: false,
|
|
43
46
|
};
|
|
44
47
|
},
|
|
45
48
|
|
|
@@ -115,7 +118,11 @@ export default {
|
|
|
115
118
|
this.$router.replace({ name: this.doneRoute });
|
|
116
119
|
buttonDone(true);
|
|
117
120
|
} catch (err) {
|
|
118
|
-
|
|
121
|
+
if (err?.message?.includes('errors due to escalation')) {
|
|
122
|
+
this.errors = [this.t('rbac.errors.escalation')];
|
|
123
|
+
} else {
|
|
124
|
+
this.errors = exceptionToErrorsArray(err);
|
|
125
|
+
}
|
|
119
126
|
buttonDone(false);
|
|
120
127
|
}
|
|
121
128
|
},
|
|
@@ -150,7 +157,7 @@ export default {
|
|
|
150
157
|
|
|
151
158
|
const normanUser = await this.$store.dispatch('rancher/find', {
|
|
152
159
|
type: NORMAN.USER,
|
|
153
|
-
id: this.value.id,
|
|
160
|
+
id: this.value.id || this.user?.id,
|
|
154
161
|
});
|
|
155
162
|
|
|
156
163
|
// Save change of password
|
|
@@ -181,8 +188,25 @@ export default {
|
|
|
181
188
|
},
|
|
182
189
|
|
|
183
190
|
async updateRoles(userId) {
|
|
184
|
-
if (this.$refs.grb) {
|
|
191
|
+
if (!this.$refs.grb) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
try {
|
|
185
196
|
await this.$refs.grb.save(userId);
|
|
197
|
+
} catch (err) {
|
|
198
|
+
if (this.isCreate) {
|
|
199
|
+
this.watchOverride = true;
|
|
200
|
+
this.$emit(
|
|
201
|
+
'update:mode',
|
|
202
|
+
{
|
|
203
|
+
userId,
|
|
204
|
+
mode: _EDIT,
|
|
205
|
+
resource: 'management.cattle.io.user',
|
|
206
|
+
}
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
throw err;
|
|
186
210
|
}
|
|
187
211
|
}
|
|
188
212
|
}
|
|
@@ -255,6 +279,7 @@ export default {
|
|
|
255
279
|
:user-id="value.id || liveValue.id"
|
|
256
280
|
:mode="mode"
|
|
257
281
|
:real-mode="realMode"
|
|
282
|
+
:watch-override="watchOverride"
|
|
258
283
|
type="user"
|
|
259
284
|
@hasChanges="validation.rolesChanged = $event"
|
|
260
285
|
@canLogIn="validation.roles = $event"
|
package/edit/namespace.vue
CHANGED
|
@@ -11,7 +11,6 @@ import Tab from '@shell/components/Tabbed/Tab';
|
|
|
11
11
|
import ResourceTabs from '@shell/components/form/ResourceTabs/index.vue';
|
|
12
12
|
import CruResource from '@shell/components/CruResource';
|
|
13
13
|
import { PROJECT_ID, _VIEW, FLAT_VIEW, _CREATE } from '@shell/config/query-params';
|
|
14
|
-
import MoveModal from '@shell/components/MoveModal';
|
|
15
14
|
import ResourceQuota from '@shell/components/form/ResourceQuota/Namespace';
|
|
16
15
|
import Loading from '@shell/components/Loading';
|
|
17
16
|
import { HARVESTER_TYPES, RANCHER_TYPES } from '@shell/components/form/ResourceQuota/shared';
|
|
@@ -31,8 +30,7 @@ export default {
|
|
|
31
30
|
PodSecurityAdmission,
|
|
32
31
|
ResourceQuota,
|
|
33
32
|
Tab,
|
|
34
|
-
ResourceTabs
|
|
35
|
-
MoveModal
|
|
33
|
+
ResourceTabs
|
|
36
34
|
},
|
|
37
35
|
|
|
38
36
|
mixins: [CreateEditView],
|
|
@@ -277,6 +275,5 @@ export default {
|
|
|
277
275
|
/>
|
|
278
276
|
</Tab>
|
|
279
277
|
</ResourceTabs>
|
|
280
|
-
<MoveModal v-if="projects" />
|
|
281
278
|
</CruResource>
|
|
282
279
|
</template>
|
|
@@ -5,6 +5,9 @@ import ArrayListGrouped from '@shell/components/form/ArrayListGrouped';
|
|
|
5
5
|
import { _EDIT } from '@shell/config/query-params';
|
|
6
6
|
import PolicyRuleTarget from '@shell/edit/networking.k8s.io.networkpolicy/PolicyRuleTarget';
|
|
7
7
|
|
|
8
|
+
// Components shown for Network Policy --> Ingress/Egress Rules --> Rule Type are...
|
|
9
|
+
// Edit Network Policy --> `PolicyRules` 1 --> M `PolicyRule` 1 --> M `PolicyRuleTarget`
|
|
10
|
+
|
|
8
11
|
export default {
|
|
9
12
|
components: {
|
|
10
13
|
ArrayListGrouped, PolicyRulePort, PolicyRuleTarget
|
|
@@ -28,18 +31,6 @@ export default {
|
|
|
28
31
|
type: String,
|
|
29
32
|
default: ''
|
|
30
33
|
},
|
|
31
|
-
allPods: {
|
|
32
|
-
type: Array,
|
|
33
|
-
default: () => {
|
|
34
|
-
return [];
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
allNamespaces: {
|
|
38
|
-
type: Array,
|
|
39
|
-
default: () => {
|
|
40
|
-
return [];
|
|
41
|
-
},
|
|
42
|
-
},
|
|
43
34
|
},
|
|
44
35
|
data() {
|
|
45
36
|
return { targetKey: this.type === 'ingress' ? 'from' : 'to' };
|
|
@@ -71,8 +62,6 @@ export default {
|
|
|
71
62
|
:mode="mode"
|
|
72
63
|
:type="type"
|
|
73
64
|
:namespace="namespace"
|
|
74
|
-
:all-namespaces="allNamespaces"
|
|
75
|
-
:all-pods="allPods"
|
|
76
65
|
:data-testid="`policy-rule-target-${props.i}`"
|
|
77
66
|
/>
|
|
78
67
|
</template>
|
|
@@ -4,12 +4,13 @@ import { LabeledInput } from '@components/Form/LabeledInput';
|
|
|
4
4
|
import LabeledSelect from '@shell/components/form/LabeledSelect';
|
|
5
5
|
import { _EDIT } from '@shell/config/query-params';
|
|
6
6
|
import MatchExpressions from '@shell/components/form/MatchExpressions';
|
|
7
|
-
import { convert,
|
|
8
|
-
import { POD } from '@shell/config/types';
|
|
7
|
+
import { convert, simplify } from '@shell/utils/selector';
|
|
8
|
+
import { NAMESPACE, POD } from '@shell/config/types';
|
|
9
9
|
import ArrayList from '@shell/components/form/ArrayList';
|
|
10
10
|
import { Banner } from '@components/Banner';
|
|
11
|
-
import
|
|
11
|
+
import debounce from 'lodash/debounce';
|
|
12
12
|
import { isValidCIDR } from '@shell/utils/validators/cidr';
|
|
13
|
+
import { matching } from '@shell/utils/selector-typed';
|
|
13
14
|
|
|
14
15
|
const TARGET_OPTIONS = {
|
|
15
16
|
IP_BLOCK: 'ipBlock',
|
|
@@ -18,6 +19,9 @@ const TARGET_OPTIONS = {
|
|
|
18
19
|
NAMESPACE_AND_POD_SELECTOR: 'namespaceAndPodSelector',
|
|
19
20
|
};
|
|
20
21
|
|
|
22
|
+
// Components shown for Network Policy --> Ingress/Egress Rules --> Rule Type are...
|
|
23
|
+
// Edit Network Policy --> `PolicyRules` 1 --> M `PolicyRule` 1 --> M `PolicyRuleTarget`
|
|
24
|
+
|
|
21
25
|
export default {
|
|
22
26
|
components: {
|
|
23
27
|
ArrayList, Banner, LabeledInput, LabeledSelect, MatchExpressions
|
|
@@ -41,18 +45,6 @@ export default {
|
|
|
41
45
|
type: String,
|
|
42
46
|
default: ''
|
|
43
47
|
},
|
|
44
|
-
allPods: {
|
|
45
|
-
type: Array,
|
|
46
|
-
default: () => {
|
|
47
|
-
return [];
|
|
48
|
-
},
|
|
49
|
-
},
|
|
50
|
-
allNamespaces: {
|
|
51
|
-
type: Array,
|
|
52
|
-
default: () => {
|
|
53
|
-
return [];
|
|
54
|
-
},
|
|
55
|
-
},
|
|
56
48
|
},
|
|
57
49
|
data() {
|
|
58
50
|
if (!this.value[TARGET_OPTIONS.IP_BLOCK] &&
|
|
@@ -66,18 +58,26 @@ export default {
|
|
|
66
58
|
}
|
|
67
59
|
|
|
68
60
|
return {
|
|
69
|
-
portOptions:
|
|
70
|
-
matchingPods:
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
61
|
+
portOptions: ['TCP', 'UDP'],
|
|
62
|
+
matchingPods: {
|
|
63
|
+
matches: [], matched: 0, total: 0
|
|
64
|
+
},
|
|
65
|
+
matchingNamespaces: {
|
|
66
|
+
matches: [], matched: 0, total: 0
|
|
67
|
+
},
|
|
68
|
+
invalidCidr: null,
|
|
69
|
+
invalidCidrs: [],
|
|
74
70
|
POD,
|
|
75
71
|
TARGET_OPTIONS,
|
|
76
|
-
targetOptions:
|
|
77
|
-
|
|
72
|
+
targetOptions: Object.values(TARGET_OPTIONS),
|
|
73
|
+
inStore: this.$store.getters['currentProduct'].inStore,
|
|
74
|
+
debouncedUpdateMatches: debounce(this.updateMatches, 500)
|
|
78
75
|
};
|
|
79
76
|
},
|
|
80
77
|
computed: {
|
|
78
|
+
/**
|
|
79
|
+
* of type matchExpression aka `KubeLabelSelectorExpression[]`
|
|
80
|
+
*/
|
|
81
81
|
podSelectorExpressions: {
|
|
82
82
|
get() {
|
|
83
83
|
return convert(
|
|
@@ -89,6 +89,9 @@ export default {
|
|
|
89
89
|
this.value[TARGET_OPTIONS.POD_SELECTOR] = simplify(podSelectorExpressions);
|
|
90
90
|
}
|
|
91
91
|
},
|
|
92
|
+
/**
|
|
93
|
+
* of type matchExpression aka `KubeLabelSelectorExpression[]`
|
|
94
|
+
*/
|
|
92
95
|
namespaceSelectorExpressions: {
|
|
93
96
|
get() {
|
|
94
97
|
return convert(
|
|
@@ -145,39 +148,40 @@ export default {
|
|
|
145
148
|
},
|
|
146
149
|
watch: {
|
|
147
150
|
namespace: {
|
|
148
|
-
handler: '
|
|
149
|
-
immediate: true
|
|
150
|
-
},
|
|
151
|
-
allNamespaces: {
|
|
152
|
-
handler: 'updateMatches',
|
|
151
|
+
handler: 'debouncedUpdateMatches',
|
|
153
152
|
immediate: true
|
|
154
153
|
},
|
|
155
154
|
'value.podSelector': {
|
|
156
|
-
handler: '
|
|
155
|
+
handler: 'debouncedUpdateMatches',
|
|
157
156
|
immediate: true
|
|
158
157
|
},
|
|
159
158
|
'value.namespaceSelector': {
|
|
160
|
-
handler: '
|
|
159
|
+
handler: 'debouncedUpdateMatches',
|
|
161
160
|
immediate: true
|
|
162
161
|
},
|
|
163
162
|
'value.ipBlock.cidr': 'validateCIDR',
|
|
164
163
|
'value.ipBlock.except': 'validateCIDR',
|
|
165
164
|
podSelectorExpressions: {
|
|
166
|
-
handler: '
|
|
165
|
+
handler: 'debouncedUpdateMatches',
|
|
167
166
|
immediate: true
|
|
168
167
|
},
|
|
169
168
|
namespaceSelectorExpressions: {
|
|
170
|
-
handler: '
|
|
169
|
+
handler: 'debouncedUpdateMatches',
|
|
171
170
|
immediate: true
|
|
172
171
|
}
|
|
173
172
|
},
|
|
173
|
+
|
|
174
|
+
fetch() {
|
|
175
|
+
this.debouncedUpdateMatches();
|
|
176
|
+
},
|
|
177
|
+
|
|
174
178
|
methods: {
|
|
175
|
-
updateMatches() {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}, this.throttle, { leading: true })();
|
|
179
|
+
async updateMatches() {
|
|
180
|
+
// Note - needs to be sequential as getMatchingPods requires matchingNamespaces to be up-to-date
|
|
181
|
+
this.matchingNamespaces = await this.getMatchingNamespaces();
|
|
182
|
+
this.matchingPods = await this.getMatchingPods();
|
|
180
183
|
},
|
|
184
|
+
|
|
181
185
|
validateCIDR() {
|
|
182
186
|
const exceptCidrs = this.value[TARGET_OPTIONS.IP_BLOCK]?.except || [];
|
|
183
187
|
|
|
@@ -191,34 +195,25 @@ export default {
|
|
|
191
195
|
this.invalidCidr = null;
|
|
192
196
|
}
|
|
193
197
|
},
|
|
194
|
-
getMatchingPods() {
|
|
195
|
-
const namespaces = this.targetType === TARGET_OPTIONS.NAMESPACE_AND_POD_SELECTOR ? this.matchingNamespaces.matches : [{ id: this.namespace }];
|
|
196
|
-
const allInNamespace = this.allPods.filter((pod) => namespaces.some((ns) => ns.id === pod.metadata.namespace));
|
|
197
|
-
const match = matching(allInNamespace, this.podSelectorExpressions);
|
|
198
|
-
const matched = match.length || 0;
|
|
199
|
-
const sample = match[0]?.nameDisplay;
|
|
200
198
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
199
|
+
async getMatchingPods() {
|
|
200
|
+
return await matching({
|
|
201
|
+
labelSelector: { matchExpressions: this.podSelectorExpressions },
|
|
202
|
+
type: POD,
|
|
203
|
+
$store: this.$store,
|
|
204
|
+
inStore: this.inStore,
|
|
205
|
+
namespace: this.targetType === TARGET_OPTIONS.NAMESPACE_AND_POD_SELECTOR ? this.matchingNamespaces.matches.map((ns) => ns.id) : this.namespace,
|
|
206
|
+
transient: true,
|
|
207
|
+
});
|
|
208
208
|
},
|
|
209
|
-
getMatchingNamespaces() {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
matches: match,
|
|
218
|
-
none: matched === 0,
|
|
219
|
-
sample,
|
|
220
|
-
total: allNamespaces.length,
|
|
221
|
-
};
|
|
209
|
+
async getMatchingNamespaces() {
|
|
210
|
+
return await matching({
|
|
211
|
+
labelSelector: { matchExpressions: this.namespaceSelectorExpressions },
|
|
212
|
+
type: NAMESPACE,
|
|
213
|
+
$store: this.$store,
|
|
214
|
+
inStore: this.inStore,
|
|
215
|
+
transient: true,
|
|
216
|
+
});
|
|
222
217
|
},
|
|
223
218
|
}
|
|
224
219
|
};
|
|
@@ -6,6 +6,9 @@ import Tab from '@shell/components/Tabbed/Tab';
|
|
|
6
6
|
import Tabbed from '@shell/components/Tabbed';
|
|
7
7
|
import { removeAt } from '@shell/utils/array';
|
|
8
8
|
|
|
9
|
+
// Components shown for Network Policy --> Ingress/Egress Rules --> Rule Type are...
|
|
10
|
+
// Edit Network Policy --> `PolicyRules` 1 --> M `PolicyRule` 1 --> M `PolicyRuleTarget`
|
|
11
|
+
|
|
9
12
|
export default {
|
|
10
13
|
components: {
|
|
11
14
|
PolicyRule, Tabbed, Tab
|
|
@@ -24,18 +27,6 @@ export default {
|
|
|
24
27
|
type: String,
|
|
25
28
|
default: 'ingress'
|
|
26
29
|
},
|
|
27
|
-
allPods: {
|
|
28
|
-
type: Array,
|
|
29
|
-
default: () => {
|
|
30
|
-
return [];
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
allNamespaces: {
|
|
34
|
-
type: Array,
|
|
35
|
-
default: () => {
|
|
36
|
-
return [];
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
30
|
},
|
|
40
31
|
data() {
|
|
41
32
|
if (!this.value.spec[this.type]) {
|
|
@@ -82,8 +73,6 @@ export default {
|
|
|
82
73
|
:mode="mode"
|
|
83
74
|
:type="type"
|
|
84
75
|
:namespace="value.metadata.namespace"
|
|
85
|
-
:all-namespaces="allNamespaces"
|
|
86
|
-
:all-pods="allPods"
|
|
87
76
|
/>
|
|
88
77
|
</Tab>
|
|
89
78
|
</Tabbed>
|
|
@@ -2,6 +2,8 @@ import { mount } from '@vue/test-utils';
|
|
|
2
2
|
import PolicyRuleTarget from '@shell/edit/networking.k8s.io.networkpolicy/PolicyRuleTarget';
|
|
3
3
|
import mock from '@shell/edit/networking.k8s.io.networkpolicy/__tests__/utils/mock.json';
|
|
4
4
|
import { PolicyRuleTargetSelectors } from '@shell/edit/networking.k8s.io.networkpolicy/__tests__/utils/selectors.test.ts';
|
|
5
|
+
import { nextTick } from 'vue';
|
|
6
|
+
import { COUNT, NAMESPACE, POD } from '@shell/config/types';
|
|
5
7
|
|
|
6
8
|
type MatchData = {
|
|
7
9
|
matched: number;
|
|
@@ -11,29 +13,6 @@ type MatchData = {
|
|
|
11
13
|
sample?: string;
|
|
12
14
|
}
|
|
13
15
|
|
|
14
|
-
const newNamespace = {
|
|
15
|
-
id: 'new-namespace',
|
|
16
|
-
type: 'namespace',
|
|
17
|
-
kind: 'Namespace',
|
|
18
|
-
spec: { finalizers: ['kubernetes'] },
|
|
19
|
-
status: { phase: 'Active' },
|
|
20
|
-
metadata: {
|
|
21
|
-
annotations: { user: 'john' },
|
|
22
|
-
name: 'default',
|
|
23
|
-
creationTimestamp: '2024-01-31T10:24:03Z',
|
|
24
|
-
fields: ['default', 'Active', '1d'],
|
|
25
|
-
labels: { user: 'john' },
|
|
26
|
-
relationships: null,
|
|
27
|
-
resourceVersion: '1',
|
|
28
|
-
state: {
|
|
29
|
-
error: false,
|
|
30
|
-
message: '',
|
|
31
|
-
name: 'active',
|
|
32
|
-
transitioning: false
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
|
|
37
16
|
describe.each([
|
|
38
17
|
'view',
|
|
39
18
|
'edit',
|
|
@@ -45,18 +24,60 @@ describe.each([
|
|
|
45
24
|
return { throttleTime: 0 };
|
|
46
25
|
},
|
|
47
26
|
props: {
|
|
48
|
-
namespace:
|
|
49
|
-
|
|
50
|
-
allPods: mock.allPods,
|
|
51
|
-
type: 'ingress',
|
|
27
|
+
namespace: mock.defaultNamespace,
|
|
28
|
+
type: 'ingress',
|
|
52
29
|
mode
|
|
53
30
|
},
|
|
54
31
|
global: {
|
|
55
32
|
mocks: {
|
|
56
33
|
$store: {
|
|
34
|
+
dispatch: (action: string, { type }: { type: string}) => {
|
|
35
|
+
switch (action) {
|
|
36
|
+
case 'cluster/findAll':
|
|
37
|
+
switch (type) {
|
|
38
|
+
case NAMESPACE:
|
|
39
|
+
return mock.allNamespaces;
|
|
40
|
+
case POD:
|
|
41
|
+
return mock.allPods;
|
|
42
|
+
default:
|
|
43
|
+
throw new Error(`unknown type ${ type }`);
|
|
44
|
+
}
|
|
45
|
+
default:
|
|
46
|
+
throw new Error(`unknown action ${ action }`);
|
|
47
|
+
}
|
|
48
|
+
},
|
|
57
49
|
getters: {
|
|
58
|
-
'i18n/exists':
|
|
59
|
-
'i18n/t':
|
|
50
|
+
'i18n/exists': mockExists,
|
|
51
|
+
'i18n/t': (key: string, matchData: MatchData) => matchData ? `${ key }-${ matchData.total }` : key,
|
|
52
|
+
currentProduct: { inStore: 'cluster' },
|
|
53
|
+
'cluster/all': (type: string) => {
|
|
54
|
+
switch (type) {
|
|
55
|
+
case COUNT:
|
|
56
|
+
return mock.counts;
|
|
57
|
+
default:
|
|
58
|
+
throw new Error(`unknown type ${ type }`);
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
'cluster/findAll': ({ type }: {type: string}) => {
|
|
62
|
+
switch (type) {
|
|
63
|
+
case NAMESPACE:
|
|
64
|
+
return mock.allNamespaces;
|
|
65
|
+
case POD:
|
|
66
|
+
return mock.allPods;
|
|
67
|
+
default:
|
|
68
|
+
throw new Error(`unknown type ${ type }`);
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
'cluster/schemaFor': (type: string) => {
|
|
72
|
+
switch (type) {
|
|
73
|
+
case NAMESPACE:
|
|
74
|
+
return { attributes: { namespaced: false } };
|
|
75
|
+
case POD:
|
|
76
|
+
return { attributes: { namespaced: true } };
|
|
77
|
+
default:
|
|
78
|
+
throw new Error(`unknown type ${ type }`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
60
81
|
}
|
|
61
82
|
}
|
|
62
83
|
},
|
|
@@ -64,6 +85,20 @@ describe.each([
|
|
|
64
85
|
});
|
|
65
86
|
|
|
66
87
|
describe(`${ mode } mode`, () => {
|
|
88
|
+
beforeEach(() => {
|
|
89
|
+
jest.useFakeTimers();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
afterEach(() => {
|
|
93
|
+
jest.runOnlyPendingTimers();
|
|
94
|
+
jest.useRealTimers();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const waitForUpdatedMatched = async() => {
|
|
98
|
+
jest.advanceTimersByTime(1000); // Wait for debounced call to fetch updated cluster list
|
|
99
|
+
await nextTick(); // Wait for changes to cluster list to trigger changes
|
|
100
|
+
};
|
|
101
|
+
|
|
67
102
|
it('should display ip-block selector rule', async() => {
|
|
68
103
|
const ipBlock = mock.selectors.ipBlock;
|
|
69
104
|
|
|
@@ -83,6 +118,7 @@ describe.each([
|
|
|
83
118
|
});
|
|
84
119
|
|
|
85
120
|
it('should display namespace selector rule', async() => {
|
|
121
|
+
// This test needs improving - mock data needs to contain more than applicable to selector
|
|
86
122
|
const namespaceSelector = mock.selectors.namespace;
|
|
87
123
|
|
|
88
124
|
await wrapper.setProps({ value: { namespaceSelector } });
|
|
@@ -92,6 +128,12 @@ describe.each([
|
|
|
92
128
|
// Check rule type selector
|
|
93
129
|
expect(wrapper.vm.targetType).toBe('namespaceSelector');
|
|
94
130
|
|
|
131
|
+
// Check the matching namespaces displayed by the banner
|
|
132
|
+
expect(wrapper.vm.$data.matchingNamespaces.matched).toBe(0);
|
|
133
|
+
|
|
134
|
+
await wrapper.vm.updateMatches();
|
|
135
|
+
await waitForUpdatedMatched();
|
|
136
|
+
|
|
95
137
|
// Check the matching namespaces displayed by the banner
|
|
96
138
|
expect(wrapper.vm.$data.matchingNamespaces.matched).toBe(1);
|
|
97
139
|
|
|
@@ -105,21 +147,10 @@ describe.each([
|
|
|
105
147
|
expect(selectors.namespaceAndPod.podRule.exists()).toBe(false);
|
|
106
148
|
|
|
107
149
|
expect(selectors.namespace.element).toBeDefined();
|
|
108
|
-
|
|
109
|
-
// Updating allNamespace should update the matching namespaces message too
|
|
110
|
-
await wrapper.setProps({
|
|
111
|
-
allNamespaces: [
|
|
112
|
-
...wrapper.vm.$props.allNamespaces,
|
|
113
|
-
newNamespace
|
|
114
|
-
]
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
const expectedTotal = 3;
|
|
118
|
-
|
|
119
|
-
expect(wrapper.vm.$data.matchingNamespaces.total).toBe(expectedTotal);
|
|
120
150
|
});
|
|
121
151
|
|
|
122
152
|
it('should display pod selector rule', async() => {
|
|
153
|
+
// This test needs improving - mock data needs to contain more than applicable to selector
|
|
123
154
|
const podSelector = mock.selectors.pod;
|
|
124
155
|
|
|
125
156
|
await wrapper.setProps({ value: { podSelector } });
|
|
@@ -154,5 +154,21 @@
|
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
|
-
]
|
|
157
|
+
],
|
|
158
|
+
"counts": [{
|
|
159
|
+
"counts": {
|
|
160
|
+
"namespace": {
|
|
161
|
+
"summary": {
|
|
162
|
+
"count": 1
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
"pod": {
|
|
166
|
+
"namespaces": {
|
|
167
|
+
"default": {
|
|
168
|
+
"count": 1
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}]
|
|
158
174
|
}
|