@rancher/shell 3.0.8-rc.8 → 3.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apis/impl/apis.ts +61 -0
- package/apis/index.ts +40 -0
- package/apis/intf/modal.ts +90 -0
- package/apis/intf/shell.ts +36 -0
- package/apis/intf/slide-in.ts +98 -0
- package/apis/intf/system.ts +41 -0
- package/apis/shell/__tests__/modal.test.ts +80 -0
- package/apis/shell/__tests__/notifications.test.ts +71 -0
- package/apis/shell/__tests__/slide-in.test.ts +54 -0
- package/apis/shell/__tests__/system.test.ts +129 -0
- package/apis/shell/index.ts +38 -0
- package/apis/shell/modal.ts +41 -0
- package/apis/shell/notifications.ts +65 -0
- package/apis/shell/slide-in.ts +33 -0
- package/apis/shell/system.ts +65 -0
- package/apis/vue-shim.d.ts +11 -0
- package/assets/brand/suse/dark/rancher-logo.svg +1 -64
- package/assets/styles/global/_tooltip.scss +6 -1
- package/assets/translations/en-us.yaml +14 -1
- package/components/ActionMenuShell.vue +3 -1
- package/components/BackLink.vue +8 -0
- package/components/BannerGraphic.vue +1 -5
- package/components/BrandImage.vue +17 -6
- package/components/Cron/CronExpressionEditor.vue +1 -1
- package/components/Cron/CronExpressionEditorModal.vue +1 -1
- package/components/CruResource.vue +8 -1
- package/components/Drawer/ResourceDetailDrawer/ConfigTab.vue +1 -0
- package/components/Drawer/ResourceDetailDrawer/__tests__/composables.test.ts +50 -1
- package/components/Drawer/ResourceDetailDrawer/composables.ts +19 -0
- package/components/Drawer/ResourceDetailDrawer/index.vue +4 -1
- package/components/Drawer/ResourceDetailDrawer/types.ts +2 -1
- package/components/LocaleSelector.vue +2 -2
- package/components/ModalManager.vue +11 -1
- package/components/Questions/__tests__/Yaml.test.ts +1 -1
- package/components/Questions/__tests__/index.test.ts +159 -0
- package/components/RelatedResources.vue +5 -0
- package/components/Resource/Detail/Metadata/Annotations/index.vue +2 -2
- package/components/Resource/Detail/Metadata/Labels/index.vue +2 -2
- package/components/Resource/Detail/Metadata/index.vue +3 -3
- package/components/Resource/Detail/ResourcePopover/index.vue +5 -1
- package/components/Resource/Detail/composables.ts +2 -2
- package/components/ResourceDetail/Masthead/latest.vue +23 -21
- package/components/ResourceDetail/index.vue +3 -0
- package/components/ResourceTable.vue +54 -21
- package/components/SlideInPanelManager.vue +16 -11
- package/components/SortableTable/THead.vue +2 -1
- package/components/SortableTable/index.vue +20 -2
- package/components/Tabbed/__tests__/index.test.ts +86 -0
- package/components/Tabbed/index.vue +37 -2
- package/components/__tests__/NamespaceFilter.test.ts +49 -0
- package/components/auth/SelectPrincipal.vue +28 -6
- package/components/auth/__tests__/SelectPrincipal.test.ts +119 -0
- package/components/auth/login/ldap.vue +3 -3
- package/components/fleet/FleetSecretSelector.vue +1 -1
- package/components/form/KeyValue.vue +1 -1
- package/components/form/NameNsDescription.vue +1 -1
- package/components/form/NodeScheduling.vue +2 -2
- package/components/form/ResourceTabs/composable.ts +2 -2
- package/components/form/ResourceTabs/index.vue +0 -2
- package/components/form/__tests__/NameNsDescription.test.ts +42 -0
- package/components/formatter/InternalExternalIP.vue +4 -1
- package/components/formatter/LinkName.vue +5 -0
- package/components/formatter/__tests__/InternalExternalIP.test.ts +1 -1
- package/components/nav/Group.vue +25 -7
- package/components/nav/Header.vue +1 -1
- package/components/nav/NamespaceFilter.vue +1 -0
- package/components/nav/Type.vue +17 -6
- package/components/nav/WindowManager/panels/TabBodyContainer.vue +1 -1
- package/components/nav/__tests__/Type.test.ts +59 -0
- package/components/templates/standalone.vue +1 -1
- package/composables/cruResource.ts +27 -0
- package/composables/focusTrap.ts +3 -1
- package/composables/resourceDetail.ts +15 -0
- package/composables/useI18n.ts +10 -1
- package/composables/useLabeledFormElement.ts +3 -4
- package/config/__test__/uiplugins.test.ts +309 -0
- package/config/labels-annotations.js +1 -0
- package/config/product/explorer.js +3 -1
- package/config/product/fleet.js +1 -1
- package/config/router/navigation-guards/clusters.js +3 -3
- package/config/router/navigation-guards/products.js +1 -1
- package/config/router/routes.js +7 -7
- package/config/types.js +7 -0
- package/config/uiplugins.js +46 -2
- package/core/__tests__/extension-manager-impl.test.js +437 -0
- package/core/extension-manager-impl.js +21 -25
- package/core/plugin-helpers.ts +2 -2
- package/core/plugin.ts +9 -1
- package/core/plugins-loader.js +2 -2
- package/core/types-provisioning.ts +5 -1
- package/core/types.ts +35 -0
- package/detail/provisioning.cattle.io.cluster.vue +9 -6
- package/dialog/DeveloperLoadExtensionDialog.vue +13 -4
- package/dialog/MoveNamespaceDialog.vue +20 -4
- package/dialog/RollbackWorkloadDialog.vue +2 -5
- package/dialog/SearchDialog.vue +1 -0
- package/dialog/__tests__/MoveNamespaceDialog.test.ts +249 -0
- package/directives/__tests__/clean-tooltip.test.ts +298 -0
- package/directives/clean-tooltip.ts +234 -0
- package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +2 -2
- package/edit/__tests__/fleet.cattle.io.helmop.test.ts +100 -3
- package/edit/autoscaling.horizontalpodautoscaler/index.vue +1 -0
- package/edit/configmap.vue +1 -0
- package/edit/constraints.gatekeeper.sh.constraint/index.vue +1 -0
- package/edit/fleet.cattle.io.helmop.vue +11 -6
- package/edit/helm.cattle.io.projecthelmchart.vue +1 -0
- package/edit/k8s.cni.cncf.io.networkattachmentdefinition.vue +1 -0
- package/edit/logging-flow/index.vue +1 -0
- package/edit/logging.banzaicloud.io.output/index.vue +1 -0
- package/edit/management.cattle.io.fleetworkspace.vue +1 -1
- package/edit/management.cattle.io.project.vue +1 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +4 -1
- package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +2 -1
- package/edit/monitoring.coreos.com.prometheusrule/index.vue +1 -0
- package/edit/monitoring.coreos.com.receiver/index.vue +2 -1
- package/edit/monitoring.coreos.com.route.vue +1 -1
- package/edit/namespace.vue +1 -0
- package/edit/networking.istio.io.destinationrule/index.vue +1 -0
- package/edit/networking.k8s.io.ingress/index.vue +1 -0
- package/edit/networking.k8s.io.networkpolicy/PolicyRules.vue +1 -0
- package/edit/networking.k8s.io.networkpolicy/index.vue +1 -0
- package/edit/node.vue +1 -0
- package/edit/persistentvolume/index.vue +27 -22
- package/edit/persistentvolume/plugins/awsElasticBlockStore.vue +13 -14
- package/edit/persistentvolume/plugins/azureDisk.vue +49 -48
- package/edit/persistentvolume/plugins/azureFile.vue +15 -14
- package/edit/persistentvolume/plugins/cephfs.vue +15 -14
- package/edit/persistentvolume/plugins/cinder.vue +15 -14
- package/edit/persistentvolume/plugins/csi.vue +18 -16
- package/edit/persistentvolume/plugins/fc.vue +13 -14
- package/edit/persistentvolume/plugins/flexVolume.vue +15 -14
- package/edit/persistentvolume/plugins/flocker.vue +1 -3
- package/edit/persistentvolume/plugins/gcePersistentDisk.vue +13 -14
- package/edit/persistentvolume/plugins/glusterfs.vue +15 -14
- package/edit/persistentvolume/plugins/hostPath.vue +40 -39
- package/edit/persistentvolume/plugins/iscsi.vue +13 -14
- package/edit/persistentvolume/plugins/local.vue +1 -3
- package/edit/persistentvolume/plugins/longhorn.vue +23 -22
- package/edit/persistentvolume/plugins/nfs.vue +15 -14
- package/edit/persistentvolume/plugins/photonPersistentDisk.vue +1 -14
- package/edit/persistentvolume/plugins/portworxVolume.vue +15 -14
- package/edit/persistentvolume/plugins/quobyte.vue +15 -14
- package/edit/persistentvolume/plugins/rbd.vue +15 -14
- package/edit/persistentvolume/plugins/scaleIO.vue +15 -14
- package/edit/persistentvolume/plugins/storageos.vue +15 -14
- package/edit/persistentvolume/plugins/vsphereVolume.vue +1 -3
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +21 -21
- package/edit/provisioning.cattle.io.cluster/index.vue +5 -5
- package/edit/provisioning.cattle.io.cluster/rke2.vue +9 -8
- package/edit/resources.cattle.io.restore.vue +1 -1
- package/edit/secret/index.vue +1 -1
- package/edit/service.vue +1 -0
- package/edit/serviceaccount.vue +1 -0
- package/edit/storage.k8s.io.storageclass/index.vue +1 -0
- package/edit/workload/Job.vue +2 -2
- package/edit/workload/index.vue +2 -1
- package/edit/workload/mixins/workload.js +1 -1
- package/initialize/App.vue +4 -4
- package/initialize/install-plugins.js +19 -5
- package/machine-config/azure.vue +1 -1
- package/machine-config/components/GCEImage.vue +1 -1
- package/mixins/__tests__/brand.spec.ts +2 -2
- package/mixins/brand.js +1 -7
- package/mixins/create-edit-view/index.js +5 -0
- package/models/__tests__/provisioning.cattle.io.cluster.test.ts +128 -5
- package/models/chart.js +70 -74
- package/models/management.cattle.io.cluster.js +21 -3
- package/models/provisioning.cattle.io.cluster.js +31 -11
- package/package.json +11 -10
- package/pages/auth/login.vue +4 -6
- package/pages/auth/setup.vue +1 -1
- package/pages/auth/verify.vue +3 -3
- package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +135 -0
- package/pages/c/_cluster/apps/charts/chart.vue +33 -15
- package/pages/c/_cluster/apps/charts/index.vue +122 -24
- package/pages/c/_cluster/apps/charts/install.vue +33 -0
- package/pages/c/_cluster/explorer/__tests__/index.test.ts +1 -1
- package/pages/c/_cluster/explorer/index.vue +8 -6
- package/pages/c/_cluster/fleet/index.vue +4 -7
- package/pages/c/_cluster/manager/hostedprovider/index.vue +12 -6
- package/pages/c/_cluster/settings/brand.vue +1 -1
- package/pages/c/_cluster/settings/index.vue +5 -0
- package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +7 -0
- package/pages/c/_cluster/uiplugins/catalogs.vue +147 -0
- package/pages/c/_cluster/uiplugins/index.vue +126 -184
- package/pkg/auto-import.js +3 -3
- package/pkg/dynamic-importer.lib.js +1 -1
- package/pkg/import.js +1 -1
- package/plugins/__tests__/mutations.tests.ts +179 -0
- package/plugins/dashboard-client-init.js +3 -0
- package/plugins/dashboard-store/getters.js +19 -2
- package/plugins/dashboard-store/model-loader.js +1 -1
- package/plugins/dashboard-store/mutations.js +23 -2
- package/plugins/dashboard-store/resource-class.js +11 -5
- package/plugins/i18n.js +8 -0
- package/plugins/plugin.js +2 -2
- package/plugins/steve/__tests__/steve-pagination-utils.test.ts +506 -0
- package/plugins/steve/steve-class.js +1 -1
- package/plugins/steve/steve-pagination-utils.ts +131 -47
- package/rancher-components/Form/Checkbox/Checkbox.vue +1 -1
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +1 -1
- package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.vue +6 -42
- package/rancher-components/Pill/RcStatusBadge/index.ts +0 -1
- package/rancher-components/Pill/RcStatusBadge/types.ts +1 -1
- package/rancher-components/Pill/RcStatusIndicator/RcStatusIndicator.vue +5 -28
- package/rancher-components/Pill/RcStatusIndicator/types.ts +2 -1
- package/rancher-components/Pill/types.ts +0 -1
- package/rancher-components/RcDropdown/useDropdownContext.ts +2 -4
- package/rancher-components/RcIcon/RcIcon.test.ts +51 -0
- package/rancher-components/RcIcon/RcIcon.vue +46 -0
- package/rancher-components/RcIcon/index.ts +1 -0
- package/rancher-components/RcIcon/types.ts +160 -0
- package/rancher-components/RcItemCard/RcItemCard.vue +1 -1
- package/rancher-components/utils/status.test.ts +67 -0
- package/rancher-components/utils/status.ts +77 -0
- package/scripts/publish-shell.sh +25 -0
- package/scripts/typegen.sh +1 -0
- package/store/__tests__/catalog.test.ts +1 -1
- package/store/__tests__/type-map.test.ts +164 -2
- package/store/action-menu.js +8 -0
- package/store/auth.js +25 -13
- package/store/catalog.js +6 -0
- package/store/i18n.js +3 -3
- package/store/index.js +8 -6
- package/store/notifications.ts +2 -0
- package/store/prefs.js +6 -7
- package/store/type-map.js +17 -7
- package/store/wm.ts +4 -4
- package/types/internal-api/shell/modal.d.ts +6 -6
- package/types/notifications/index.ts +126 -15
- package/types/rancher/index.d.ts +9 -0
- package/types/shell/index.d.ts +54 -3
- package/types/store/__tests__/pagination.types.spec.ts +137 -0
- package/types/store/pagination.types.ts +157 -9
- package/types/vue-shim.d.ts +5 -4
- package/utils/__tests__/provider.test.ts +98 -0
- package/utils/__tests__/router.test.js +238 -0
- package/utils/__tests__/selector-typed.test.ts +263 -0
- package/utils/cluster.js +4 -1
- package/utils/color.js +1 -1
- package/utils/dynamic-content/__tests__/info.test.ts +6 -0
- package/utils/dynamic-content/info.ts +43 -0
- package/utils/favicon.js +4 -4
- package/utils/fleet.ts +8 -1
- package/utils/pagination-utils.ts +2 -2
- package/utils/pagination-wrapper.ts +1 -1
- package/utils/provider.ts +14 -0
- package/utils/router.js +50 -0
- package/utils/selector-typed.ts +6 -2
- package/utils/unit-tests/pagination-utils.spec.ts +8 -8
- package/vue.config.js +3 -3
- package/composables/useExtensionManager.ts +0 -17
- package/core/plugins.js +0 -38
- package/directives/clean-tooltip.js +0 -32
- package/plugins/internal-api/index.ts +0 -37
- package/plugins/internal-api/shared/base-api.ts +0 -13
- package/plugins/internal-api/shell/shell.api.ts +0 -108
- package/plugins/nuxt-client-init.js +0 -3
- package/types/internal-api/shell/growl.d.ts +0 -25
- package/types/internal-api/shell/slideIn.d.ts +0 -15
|
@@ -96,15 +96,15 @@ export default {
|
|
|
96
96
|
await this.value.waitForProvisioner();
|
|
97
97
|
|
|
98
98
|
// Support for the 'provisioner' extension
|
|
99
|
-
const extClass = this.$
|
|
99
|
+
const extClass = this.$extension.getDynamic('provisioner', this.value.machineProvider);
|
|
100
100
|
|
|
101
101
|
if (extClass) {
|
|
102
102
|
this.extProvider = new extClass({
|
|
103
|
-
dispatch:
|
|
104
|
-
getters:
|
|
105
|
-
axios:
|
|
106
|
-
$
|
|
107
|
-
$t:
|
|
103
|
+
dispatch: this.$store.dispatch,
|
|
104
|
+
getters: this.$store.getters,
|
|
105
|
+
axios: this.$store.$axios,
|
|
106
|
+
$extension: this.$store.app.$extension,
|
|
107
|
+
$t: this.t
|
|
108
108
|
});
|
|
109
109
|
|
|
110
110
|
this.extDetailTabs = {
|
|
@@ -578,6 +578,7 @@ export default {
|
|
|
578
578
|
// Hosted kubernetes providers with private endpoints need the registration tab
|
|
579
579
|
// https://github.com/rancher/dashboard/issues/6036
|
|
580
580
|
// https://github.com/rancher/dashboard/issues/4545
|
|
581
|
+
|
|
581
582
|
if ( this.value.isHostedKubernetesProvider && this.value.isPrivateHostedProvider && !this.isClusterReady ) {
|
|
582
583
|
return this.extDetailTabs.registration;
|
|
583
584
|
}
|
|
@@ -892,6 +893,7 @@ export default {
|
|
|
892
893
|
:disabled="!group.ref.canScaleDownPool()"
|
|
893
894
|
type="button"
|
|
894
895
|
class="btn btn-sm role-secondary"
|
|
896
|
+
data-testid="scale-down-button"
|
|
895
897
|
@click="toggleScaleDownModal($event, group.ref)"
|
|
896
898
|
>
|
|
897
899
|
<i class="icon icon-sm icon-minus" />
|
|
@@ -901,6 +903,7 @@ export default {
|
|
|
901
903
|
:disabled="!group.ref.canScaleUpPool()"
|
|
902
904
|
type="button"
|
|
903
905
|
class="btn btn-sm role-secondary ml-10"
|
|
906
|
+
data-testid="scale-up-button"
|
|
904
907
|
@click="group.ref.scalePool(1)"
|
|
905
908
|
>
|
|
906
909
|
<i class="icon icon-sm icon-plus" />
|
|
@@ -4,6 +4,7 @@ import { LabeledInput } from '@components/Form/LabeledInput';
|
|
|
4
4
|
import Checkbox from '@components/Form/Checkbox/Checkbox.vue';
|
|
5
5
|
import { UI_PLUGIN } from '@shell/config/types';
|
|
6
6
|
import { UI_PLUGIN_CHART_ANNOTATIONS, UI_PLUGIN_NAMESPACE } from '@shell/config/uiplugins';
|
|
7
|
+
import { DEVELOPER_LOAD_NAME_SUFFIX } from '@shell/core/extension-manager-impl';
|
|
7
8
|
|
|
8
9
|
export default {
|
|
9
10
|
emits: ['close'],
|
|
@@ -101,8 +102,16 @@ export default {
|
|
|
101
102
|
const parts = name.split('-');
|
|
102
103
|
|
|
103
104
|
if (parts.length >= 2) {
|
|
104
|
-
version
|
|
105
|
-
|
|
105
|
+
// fixing the name-version separation, especially in RC versions
|
|
106
|
+
// like: elemental-3.0.1-rc.1
|
|
107
|
+
// on capturing version it must be "digit + dot + digit" + rest of string
|
|
108
|
+
const regex = /^(?<name>.+?)-(?<version>\d+\.\d+.*)$/;
|
|
109
|
+
const match = name.match(regex);
|
|
110
|
+
|
|
111
|
+
if (match && match.groups) {
|
|
112
|
+
version = match.groups.version;
|
|
113
|
+
crdName = match.groups.name;
|
|
114
|
+
}
|
|
106
115
|
}
|
|
107
116
|
|
|
108
117
|
if (this.persist) {
|
|
@@ -114,7 +123,7 @@ export default {
|
|
|
114
123
|
},
|
|
115
124
|
spec: {
|
|
116
125
|
plugin: {
|
|
117
|
-
name: crdName
|
|
126
|
+
name: `${ crdName }${ DEVELOPER_LOAD_NAME_SUFFIX }`,
|
|
118
127
|
version,
|
|
119
128
|
endpoint: url,
|
|
120
129
|
noCache: true,
|
|
@@ -136,7 +145,7 @@ export default {
|
|
|
136
145
|
}
|
|
137
146
|
}
|
|
138
147
|
|
|
139
|
-
this.$
|
|
148
|
+
this.$extension.loadAsync(name, url).then(() => {
|
|
140
149
|
this.closeDialog(true);
|
|
141
150
|
|
|
142
151
|
this.$store.dispatch('growl/success', {
|
|
@@ -6,6 +6,8 @@ import LabeledSelect from '@shell/components/form/LabeledSelect';
|
|
|
6
6
|
import { MANAGEMENT } from '@shell/config/types';
|
|
7
7
|
import { PROJECT } from '@shell/config/labels-annotations';
|
|
8
8
|
|
|
9
|
+
const NONE_VALUE = ' ';
|
|
10
|
+
|
|
9
11
|
export default {
|
|
10
12
|
emits: ['close'],
|
|
11
13
|
|
|
@@ -48,8 +50,12 @@ export default {
|
|
|
48
50
|
return this.toMove.filter((namespace) => !!namespace.project).map((namespace) => namespace.project.shortId);
|
|
49
51
|
},
|
|
50
52
|
|
|
53
|
+
isAllInProject() {
|
|
54
|
+
return this.toMove.every((namespace) => !!namespace.project);
|
|
55
|
+
},
|
|
56
|
+
|
|
51
57
|
projectOptions() {
|
|
52
|
-
|
|
58
|
+
const options = this.projects.reduce((inCluster, project) => {
|
|
53
59
|
if (!this.excludedProjects.includes(project.shortId) && project.spec?.clusterName === this.currentCluster.id) {
|
|
54
60
|
inCluster.push({
|
|
55
61
|
value: project.shortId,
|
|
@@ -59,6 +65,16 @@ export default {
|
|
|
59
65
|
|
|
60
66
|
return inCluster;
|
|
61
67
|
}, []);
|
|
68
|
+
|
|
69
|
+
// To be consistent with listed projects we should only provide the option if it applies too all of the namespaces
|
|
70
|
+
if (this.isAllInProject) {
|
|
71
|
+
options.unshift({
|
|
72
|
+
value: NONE_VALUE,
|
|
73
|
+
label: this.t('moveModal.noProject')
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return options;
|
|
62
78
|
}
|
|
63
79
|
},
|
|
64
80
|
|
|
@@ -69,10 +85,10 @@ export default {
|
|
|
69
85
|
|
|
70
86
|
async move(finish) {
|
|
71
87
|
const cluster = this.$store.getters['currentCluster'];
|
|
72
|
-
const clusterWithProjectId = `${ cluster.id }:${ this.targetProject }
|
|
88
|
+
const clusterWithProjectId = this.targetProject && this.targetProject !== NONE_VALUE ? `${ cluster.id }:${ this.targetProject }` : null;
|
|
73
89
|
|
|
74
90
|
const promises = this.toMove.map((namespace) => {
|
|
75
|
-
namespace.setLabel(PROJECT, this.targetProject);
|
|
91
|
+
namespace.setLabel(PROJECT, this.targetProject && this.targetProject !== NONE_VALUE ? this.targetProject : null);
|
|
76
92
|
namespace.setAnnotation(PROJECT, clusterWithProjectId);
|
|
77
93
|
|
|
78
94
|
return namespace.save();
|
|
@@ -128,7 +144,7 @@ export default {
|
|
|
128
144
|
<AsyncButton
|
|
129
145
|
:action-label="t('moveModal.moveButtonLabel')"
|
|
130
146
|
class="btn bg-primary ml-10"
|
|
131
|
-
:disabled="
|
|
147
|
+
:disabled="targetProject === null"
|
|
132
148
|
@click="move"
|
|
133
149
|
/>
|
|
134
150
|
</template>
|
|
@@ -165,12 +165,9 @@ export default {
|
|
|
165
165
|
return option.label;
|
|
166
166
|
},
|
|
167
167
|
sizeDialog() {
|
|
168
|
-
const
|
|
169
|
-
const width = this.showDiff ? '85%' : '600px';
|
|
168
|
+
const modalWidth = this.showDiff ? '85%' : '600px';
|
|
170
169
|
|
|
171
|
-
|
|
172
|
-
dialogs[0].style.setProperty('width', width);
|
|
173
|
-
}
|
|
170
|
+
this.$store.commit('action-menu/updateModalData', [{ key: 'modalWidth', value: modalWidth }]);
|
|
174
171
|
},
|
|
175
172
|
sanitizeYaml(obj, path = '') {
|
|
176
173
|
const res = {};
|
package/dialog/SearchDialog.vue
CHANGED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { shallowMount, VueWrapper } from '@vue/test-utils';
|
|
2
|
+
import MoveNamespaceDialog from '@shell/dialog/MoveNamespaceDialog.vue';
|
|
3
|
+
|
|
4
|
+
const t = (key: string): string => key;
|
|
5
|
+
const NONE_VALUE = ' ';
|
|
6
|
+
|
|
7
|
+
describe('component: MoveNamespaceDialog', () => {
|
|
8
|
+
let wrapper: VueWrapper<any>;
|
|
9
|
+
|
|
10
|
+
const mockProjects = [
|
|
11
|
+
{
|
|
12
|
+
shortId: 'p-abc123',
|
|
13
|
+
nameDisplay: 'Project A',
|
|
14
|
+
spec: { clusterName: 'local' }
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
shortId: 'p-def456',
|
|
18
|
+
nameDisplay: 'Project B',
|
|
19
|
+
spec: { clusterName: 'local' }
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
shortId: 'p-other',
|
|
23
|
+
nameDisplay: 'Other Cluster Project',
|
|
24
|
+
spec: { clusterName: 'other-cluster' }
|
|
25
|
+
}
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
const createMockNamespace = (projectId: string | null = null) => {
|
|
29
|
+
const namespace: any = {
|
|
30
|
+
nameDisplay: 'test-namespace',
|
|
31
|
+
projectId,
|
|
32
|
+
project: projectId ? { shortId: projectId } : null,
|
|
33
|
+
setLabel: jest.fn(),
|
|
34
|
+
setAnnotation: jest.fn(),
|
|
35
|
+
save: jest.fn().mockResolvedValue({}),
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
return namespace;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const mountComponent = (propsData = {}, options = {}) => {
|
|
42
|
+
const store = {
|
|
43
|
+
dispatch: jest.fn().mockResolvedValue(mockProjects),
|
|
44
|
+
getters: { currentCluster: { id: 'local' } }
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const defaultProps = {
|
|
48
|
+
resources: [createMockNamespace('p-abc123')],
|
|
49
|
+
movingCb: jest.fn(),
|
|
50
|
+
registerBackgroundClosing: jest.fn(),
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
return shallowMount(MoveNamespaceDialog, {
|
|
54
|
+
propsData: {
|
|
55
|
+
...defaultProps,
|
|
56
|
+
...propsData,
|
|
57
|
+
},
|
|
58
|
+
global: {
|
|
59
|
+
mocks: {
|
|
60
|
+
$store: store,
|
|
61
|
+
t,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
...options,
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
afterEach(() => {
|
|
69
|
+
if (wrapper) {
|
|
70
|
+
wrapper.unmount();
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe('projectOptions', () => {
|
|
75
|
+
it('should include "None" option as first item', async() => {
|
|
76
|
+
wrapper = mountComponent();
|
|
77
|
+
await wrapper.vm.$options.fetch.call(wrapper.vm);
|
|
78
|
+
|
|
79
|
+
const options = wrapper.vm.projectOptions;
|
|
80
|
+
|
|
81
|
+
expect(options[0]).toStrictEqual({
|
|
82
|
+
value: NONE_VALUE,
|
|
83
|
+
label: 'moveModal.noProject'
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('should include projects from current cluster', async() => {
|
|
88
|
+
// Use a namespace not in any project so no projects get excluded
|
|
89
|
+
const namespace = createMockNamespace(null);
|
|
90
|
+
|
|
91
|
+
wrapper = mountComponent({ resources: [namespace] });
|
|
92
|
+
await wrapper.vm.$options.fetch.call(wrapper.vm);
|
|
93
|
+
|
|
94
|
+
const options = wrapper.vm.projectOptions;
|
|
95
|
+
const projectLabels = options.map((o: any) => o.label);
|
|
96
|
+
|
|
97
|
+
expect(projectLabels).toContain('Project A');
|
|
98
|
+
expect(projectLabels).toContain('Project B');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should exclude projects from other clusters', async() => {
|
|
102
|
+
wrapper = mountComponent();
|
|
103
|
+
await wrapper.vm.$options.fetch.call(wrapper.vm);
|
|
104
|
+
|
|
105
|
+
const options = wrapper.vm.projectOptions;
|
|
106
|
+
const projectLabels = options.map((o: any) => o.label);
|
|
107
|
+
|
|
108
|
+
expect(projectLabels).not.toContain('Other Cluster Project');
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should exclude current project of namespaces being moved', async() => {
|
|
112
|
+
const namespace = createMockNamespace('p-abc123');
|
|
113
|
+
|
|
114
|
+
wrapper = mountComponent({ resources: [namespace] });
|
|
115
|
+
await wrapper.vm.$options.fetch.call(wrapper.vm);
|
|
116
|
+
|
|
117
|
+
const options = wrapper.vm.projectOptions;
|
|
118
|
+
const projectValues = options.map((o: any) => o.value);
|
|
119
|
+
|
|
120
|
+
expect(projectValues).not.toContain('p-abc123');
|
|
121
|
+
expect(projectValues).toContain('p-def456');
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('should NOT include "None" option when some namespaces are not in a project', async() => {
|
|
125
|
+
const namespaceInProject = createMockNamespace('p-abc123');
|
|
126
|
+
const namespaceNotInProject = createMockNamespace(null);
|
|
127
|
+
|
|
128
|
+
wrapper = mountComponent({ resources: [namespaceInProject, namespaceNotInProject] });
|
|
129
|
+
await wrapper.vm.$options.fetch.call(wrapper.vm);
|
|
130
|
+
|
|
131
|
+
const options = wrapper.vm.projectOptions;
|
|
132
|
+
const optionValues = options.map((o: any) => o.value);
|
|
133
|
+
|
|
134
|
+
expect(optionValues).not.toContain(NONE_VALUE);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('should NOT include "None" option when no namespaces are in a project', async() => {
|
|
138
|
+
const namespace = createMockNamespace(null);
|
|
139
|
+
|
|
140
|
+
wrapper = mountComponent({ resources: [namespace] });
|
|
141
|
+
await wrapper.vm.$options.fetch.call(wrapper.vm);
|
|
142
|
+
|
|
143
|
+
const options = wrapper.vm.projectOptions;
|
|
144
|
+
const optionValues = options.map((o: any) => o.value);
|
|
145
|
+
|
|
146
|
+
expect(optionValues).not.toContain(NONE_VALUE);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
describe('targetProject default value', () => {
|
|
151
|
+
it('should default to empty string (None option)', () => {
|
|
152
|
+
wrapper = mountComponent();
|
|
153
|
+
|
|
154
|
+
expect(wrapper.vm.targetProject).toBeNull();
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
describe('move button disabled state', () => {
|
|
159
|
+
it('should be enabled when targetProject is NONE_VALUE (None)', () => {
|
|
160
|
+
wrapper = mountComponent();
|
|
161
|
+
wrapper.vm.targetProject = NONE_VALUE;
|
|
162
|
+
|
|
163
|
+
// The button should be enabled when targetProject !== null
|
|
164
|
+
expect(wrapper.vm.targetProject === null).toBe(false);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('should be enabled when targetProject is a project id', () => {
|
|
168
|
+
wrapper = mountComponent();
|
|
169
|
+
wrapper.vm.targetProject = 'p-def456';
|
|
170
|
+
|
|
171
|
+
expect(wrapper.vm.targetProject === null).toBe(false);
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
describe('move method', () => {
|
|
176
|
+
it('should clear labels and annotations when targetProject is NONE_VALUE (None)', async() => {
|
|
177
|
+
const namespace = createMockNamespace('p-abc123');
|
|
178
|
+
|
|
179
|
+
wrapper = mountComponent({ resources: [namespace] });
|
|
180
|
+
await wrapper.vm.$options.fetch.call(wrapper.vm);
|
|
181
|
+
|
|
182
|
+
wrapper.vm.targetProject = NONE_VALUE;
|
|
183
|
+
|
|
184
|
+
const finish = jest.fn();
|
|
185
|
+
|
|
186
|
+
await wrapper.vm.move(finish);
|
|
187
|
+
|
|
188
|
+
expect(namespace.setLabel).toHaveBeenCalledWith('field.cattle.io/projectId', null);
|
|
189
|
+
expect(namespace.setAnnotation).toHaveBeenCalledWith('field.cattle.io/projectId', null);
|
|
190
|
+
expect(namespace.save).toHaveBeenCalledWith();
|
|
191
|
+
expect(finish).toHaveBeenCalledWith(true);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('should set labels and annotations when moving to a project', async() => {
|
|
195
|
+
const namespace = createMockNamespace('p-abc123');
|
|
196
|
+
|
|
197
|
+
wrapper = mountComponent({ resources: [namespace] });
|
|
198
|
+
await wrapper.vm.$options.fetch.call(wrapper.vm);
|
|
199
|
+
|
|
200
|
+
wrapper.vm.targetProject = 'p-def456';
|
|
201
|
+
|
|
202
|
+
const finish = jest.fn();
|
|
203
|
+
|
|
204
|
+
await wrapper.vm.move(finish);
|
|
205
|
+
|
|
206
|
+
expect(namespace.setLabel).toHaveBeenCalledWith('field.cattle.io/projectId', 'p-def456');
|
|
207
|
+
expect(namespace.setAnnotation).toHaveBeenCalledWith('field.cattle.io/projectId', 'local:p-def456');
|
|
208
|
+
expect(namespace.save).toHaveBeenCalledWith();
|
|
209
|
+
expect(finish).toHaveBeenCalledWith(true);
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it('should handle multiple namespaces', async() => {
|
|
213
|
+
const namespace1 = createMockNamespace('p-abc123');
|
|
214
|
+
const namespace2 = createMockNamespace('p-abc123');
|
|
215
|
+
|
|
216
|
+
wrapper = mountComponent({ resources: [namespace1, namespace2] });
|
|
217
|
+
await wrapper.vm.$options.fetch.call(wrapper.vm);
|
|
218
|
+
|
|
219
|
+
wrapper.vm.targetProject = NONE_VALUE;
|
|
220
|
+
|
|
221
|
+
const finish = jest.fn();
|
|
222
|
+
|
|
223
|
+
await wrapper.vm.move(finish);
|
|
224
|
+
|
|
225
|
+
expect(namespace1.setLabel).toHaveBeenCalledWith('field.cattle.io/projectId', null);
|
|
226
|
+
expect(namespace1.setAnnotation).toHaveBeenCalledWith('field.cattle.io/projectId', null);
|
|
227
|
+
expect(namespace2.setLabel).toHaveBeenCalledWith('field.cattle.io/projectId', null);
|
|
228
|
+
expect(namespace2.setAnnotation).toHaveBeenCalledWith('field.cattle.io/projectId', null);
|
|
229
|
+
expect(namespace1.save).toHaveBeenCalledWith();
|
|
230
|
+
expect(namespace2.save).toHaveBeenCalledWith();
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it('should call finish with false when save fails', async() => {
|
|
234
|
+
const namespace = createMockNamespace('p-abc123');
|
|
235
|
+
|
|
236
|
+
jest.spyOn(namespace, 'save').mockImplementation().mockRejectedValue(new Error('Save failed'));
|
|
237
|
+
wrapper = mountComponent({ resources: [namespace] });
|
|
238
|
+
await wrapper.vm.$options.fetch.call(wrapper.vm);
|
|
239
|
+
|
|
240
|
+
wrapper.vm.targetProject = NONE_VALUE;
|
|
241
|
+
|
|
242
|
+
const finish = jest.fn();
|
|
243
|
+
|
|
244
|
+
await wrapper.vm.move(finish);
|
|
245
|
+
|
|
246
|
+
expect(finish).toHaveBeenCalledWith(false);
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
});
|