@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
|
@@ -6,7 +6,7 @@ import ButtonGroup from '@shell/components/ButtonGroup';
|
|
|
6
6
|
import SortableTable from '@shell/components/SortableTable';
|
|
7
7
|
import { NAMESPACE, AGE } from '@shell/config/table-headers';
|
|
8
8
|
import { findBy } from '@shell/utils/array';
|
|
9
|
-
import { ExtensionPoint, TableColumnLocation } from '@shell/core/types';
|
|
9
|
+
import { ExtensionPoint, TableColumnLocation, TableLocation } from '@shell/core/types';
|
|
10
10
|
import { getApplicableExtensionEnhancements } from '@shell/core/plugin-helpers';
|
|
11
11
|
import { ToggleSwitch } from '@components/Form/ToggleSwitch';
|
|
12
12
|
import ResourceTableWatch from '@shell/mixins/resource-table-watch';
|
|
@@ -316,29 +316,10 @@ export default {
|
|
|
316
316
|
|
|
317
317
|
// add custom table columns provided by the extensions ExtensionPoint.TABLE_COL hook
|
|
318
318
|
// gate it so that we prevent errors on older versions of dashboard
|
|
319
|
-
if (this.$store.$
|
|
319
|
+
if (this.$store.$extension?.getUIConfig) {
|
|
320
320
|
// { column: TableColumn, paginationColumn: PaginationTableColumn }[]
|
|
321
321
|
const extensionCols = getApplicableExtensionEnhancements(this, ExtensionPoint.TABLE_COL, TableColumnLocation.RESOURCE, this.$route);
|
|
322
322
|
|
|
323
|
-
// Try and insert the columns before the Age column
|
|
324
|
-
let insertPosition = headers.length;
|
|
325
|
-
|
|
326
|
-
if (headers.length > 0) {
|
|
327
|
-
const ageColIndex = headers.findIndex((h) => h.name === AGE.name);
|
|
328
|
-
|
|
329
|
-
if (ageColIndex >= 0) {
|
|
330
|
-
insertPosition = ageColIndex;
|
|
331
|
-
} else {
|
|
332
|
-
// we've found some labels with ' ', which isn't necessarily empty (explore action/button)
|
|
333
|
-
// if we are to add cols, let's push them before these so that the UI doesn't look weird
|
|
334
|
-
const lastViableColIndex = headers.findIndex((h) => (!h.label || !h.label?.trim()) && (!h.labelKey || !h.labelKey?.trim()));
|
|
335
|
-
|
|
336
|
-
if (lastViableColIndex >= 0) {
|
|
337
|
-
insertPosition = lastViableColIndex;
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
323
|
// adding extension defined cols to the correct header config
|
|
343
324
|
extensionCols.forEach((config) => {
|
|
344
325
|
let { column: col, paginationColumn } = config;
|
|
@@ -377,6 +358,37 @@ export default {
|
|
|
377
358
|
if (!col.value && col.getValue) {
|
|
378
359
|
col.value = col.getValue;
|
|
379
360
|
}
|
|
361
|
+
|
|
362
|
+
// Establish a valid header position for the new table column
|
|
363
|
+
let insertPosition = headers.length;
|
|
364
|
+
|
|
365
|
+
if (headers.length > 0) {
|
|
366
|
+
const ageColIndex = headers.findIndex((h) => h.name === AGE.name);
|
|
367
|
+
|
|
368
|
+
if (ageColIndex >= 0) {
|
|
369
|
+
// we will allow for the table col to be added right after the AGE col
|
|
370
|
+
// but that will be the limit
|
|
371
|
+
insertPosition = ageColIndex + 1;
|
|
372
|
+
} else {
|
|
373
|
+
// we've found some labels with ' ', which isn't necessarily empty (explore action/button)
|
|
374
|
+
// if we are to add cols, let's push them before these so that the UI doesn't look weird
|
|
375
|
+
const lastViableColIndex = headers.findIndex((h) => (!h.label || !h.label?.trim()) && (!h.labelKey || !h.labelKey?.trim()));
|
|
376
|
+
|
|
377
|
+
if (lastViableColIndex >= 0) {
|
|
378
|
+
insertPosition = lastViableColIndex;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// apply table col ordering if it's present on the new table col config
|
|
384
|
+
if (col.weight) {
|
|
385
|
+
if (col.weight < 0) {
|
|
386
|
+
insertPosition = 0;
|
|
387
|
+
} else if (col.weight < insertPosition) {
|
|
388
|
+
insertPosition = col.weight;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
380
392
|
headers.splice(insertPosition, 0, col);
|
|
381
393
|
});
|
|
382
394
|
}
|
|
@@ -414,6 +426,16 @@ export default {
|
|
|
414
426
|
return headers;
|
|
415
427
|
},
|
|
416
428
|
|
|
429
|
+
_applicableExtensionTableHooks() {
|
|
430
|
+
if (this.$store.$plugin?.getUIConfig) {
|
|
431
|
+
const extensionTableHooks = getApplicableExtensionEnhancements(this, ExtensionPoint.TABLE, TableLocation.RESOURCE, this.$route);
|
|
432
|
+
|
|
433
|
+
return extensionTableHooks;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
return [];
|
|
437
|
+
},
|
|
438
|
+
|
|
417
439
|
/**
|
|
418
440
|
* Take rows and filter out entries given the namespace filter
|
|
419
441
|
*/
|
|
@@ -640,6 +662,16 @@ export default {
|
|
|
640
662
|
}
|
|
641
663
|
},
|
|
642
664
|
|
|
665
|
+
// this is where we handle the callbacks to the TABLE extension hooks
|
|
666
|
+
handleSortableTableInteraction(arg) {
|
|
667
|
+
if (this._applicableExtensionTableHooks?.length) {
|
|
668
|
+
this._applicableExtensionTableHooks.forEach((item) => {
|
|
669
|
+
if (item.tableHook) {
|
|
670
|
+
item.tableHook(arg);
|
|
671
|
+
}
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
}
|
|
643
675
|
}
|
|
644
676
|
};
|
|
645
677
|
</script>
|
|
@@ -679,6 +711,7 @@ export default {
|
|
|
679
711
|
@clickedActionButton="handleActionButtonClick"
|
|
680
712
|
@group-value-change="group = $event"
|
|
681
713
|
@enter="handleEnterKeyPress"
|
|
714
|
+
@sortable-table-interaction="handleSortableTableInteraction"
|
|
682
715
|
>
|
|
683
716
|
<template
|
|
684
717
|
v-if="showGrouping && _groupOptions.length > 1"
|
|
@@ -57,17 +57,22 @@ watch(
|
|
|
57
57
|
/**
|
|
58
58
|
* trigger focus trap
|
|
59
59
|
*/
|
|
60
|
-
() =>
|
|
61
|
-
(neu) => {
|
|
62
|
-
if (neu) {
|
|
63
|
-
const opts = {
|
|
60
|
+
() => isOpen?.value,
|
|
61
|
+
(neu, old) => {
|
|
62
|
+
if (neu && neu !== old) {
|
|
63
|
+
const opts:any = {
|
|
64
64
|
...DEFAULT_FOCUS_TRAP_OPTS,
|
|
65
|
+
// putting the initial focus on the first element that is not conditionally displayed
|
|
66
|
+
initialFocus: slideInPanelManagerClose.value
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const returnFocusSelector = currentProps?.value?.returnFocusSelector;
|
|
70
|
+
|
|
71
|
+
if (returnFocusSelector) {
|
|
65
72
|
/**
|
|
66
73
|
* will return focus to the first iterable node of this container select
|
|
67
74
|
*/
|
|
68
|
-
setReturnFocus
|
|
69
|
-
const returnFocusSelector = currentProps?.value?.returnFocusSelector;
|
|
70
|
-
|
|
75
|
+
opts.setReturnFocus = () => {
|
|
71
76
|
if (returnFocusSelector && !document.querySelector(returnFocusSelector)) {
|
|
72
77
|
console.warn('SlideInPanelManager: cannot find elem with "returnFocusSelector", returning focus to main view'); // eslint-disable-line no-console
|
|
73
78
|
|
|
@@ -75,10 +80,8 @@ watch(
|
|
|
75
80
|
}
|
|
76
81
|
|
|
77
82
|
return returnFocusSelector || '.dashboard-root';
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
initialFocus: slideInPanelManagerClose.value
|
|
81
|
-
};
|
|
83
|
+
};
|
|
84
|
+
}
|
|
82
85
|
|
|
83
86
|
useWatcherBasedSetupFocusTrapWithDestroyIncluded(
|
|
84
87
|
() => {
|
|
@@ -166,6 +169,8 @@ function closePanel() {
|
|
|
166
169
|
data-testid="slide-in-close"
|
|
167
170
|
:tabindex="isOpen ? 0 : -1"
|
|
168
171
|
@click="closePanel"
|
|
172
|
+
@keypress.enter="closePanel"
|
|
173
|
+
@keyup.space="closePanel"
|
|
169
174
|
/>
|
|
170
175
|
</div>
|
|
171
176
|
<div class="main-panel">
|
|
@@ -52,7 +52,8 @@ export default {
|
|
|
52
52
|
'group-value-change',
|
|
53
53
|
'selection',
|
|
54
54
|
'rowClick',
|
|
55
|
-
'enter'
|
|
55
|
+
'enter',
|
|
56
|
+
'sortable-table-interaction',
|
|
56
57
|
],
|
|
57
58
|
|
|
58
59
|
components: {
|
|
@@ -765,7 +766,7 @@ export default {
|
|
|
765
766
|
needRef = true;
|
|
766
767
|
} else {
|
|
767
768
|
// Check if we have a formatter from a plugin
|
|
768
|
-
const pluginFormatter = this.$
|
|
769
|
+
const pluginFormatter = this.$extension?.getDynamic('formatters', c.formatter);
|
|
769
770
|
|
|
770
771
|
if (pluginFormatter) {
|
|
771
772
|
component = defineAsyncComponent(pluginFormatter);
|
|
@@ -1058,6 +1059,23 @@ export default {
|
|
|
1058
1059
|
},
|
|
1059
1060
|
|
|
1060
1061
|
paginationChanged() {
|
|
1062
|
+
// event used for extensions TABLE hooks
|
|
1063
|
+
this.$emit('sortable-table-interaction', {
|
|
1064
|
+
pagination: {
|
|
1065
|
+
page: this.page,
|
|
1066
|
+
perPage: this.perPage,
|
|
1067
|
+
},
|
|
1068
|
+
filtering: {
|
|
1069
|
+
searchFields: this.searchFields,
|
|
1070
|
+
searchQuery: this.searchQuery
|
|
1071
|
+
},
|
|
1072
|
+
sorting: {
|
|
1073
|
+
sort: this.sortFields,
|
|
1074
|
+
sortBy: this.sortBy,
|
|
1075
|
+
descending: this.descending
|
|
1076
|
+
}
|
|
1077
|
+
});
|
|
1078
|
+
|
|
1061
1079
|
if (!this.externalPaginationEnabled) {
|
|
1062
1080
|
return;
|
|
1063
1081
|
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { mount, VueWrapper } from '@vue/test-utils';
|
|
2
|
+
import Tabbed from '@shell/components/Tabbed/index.vue';
|
|
3
|
+
import Tab from '@shell/components/Tabbed/Tab.vue';
|
|
4
|
+
|
|
5
|
+
jest.mock('@shell/components/form/ResourceTabs/composable', () => ({ useTabCountWatcher: () => ({}) }));
|
|
6
|
+
|
|
7
|
+
const mockT = (key: string) => key;
|
|
8
|
+
|
|
9
|
+
const defaultGlobalMountOptions = {
|
|
10
|
+
components: { Tab },
|
|
11
|
+
mocks: {
|
|
12
|
+
$router: {
|
|
13
|
+
replace: jest.fn(),
|
|
14
|
+
currentRoute: { _value: { hash: '' } }
|
|
15
|
+
},
|
|
16
|
+
$route: { hash: '' },
|
|
17
|
+
t: mockT,
|
|
18
|
+
store: { getters: { 'i18n/t': mockT } }
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
describe('component: Tabbed', () => {
|
|
23
|
+
const findTabNav = (wrapper: VueWrapper<any>) => wrapper.find('[data-testid="tabbed-block"]');
|
|
24
|
+
|
|
25
|
+
it('should display tab navigation for a single tab when hideSingleTab is false (default)', async() => {
|
|
26
|
+
const wrapper = mount(Tabbed, {
|
|
27
|
+
slots: { default: { components: { Tab }, template: '<Tab name="tab1" label="Tab 1" />' } },
|
|
28
|
+
global: { ...defaultGlobalMountOptions },
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
await wrapper.vm.$nextTick();
|
|
32
|
+
|
|
33
|
+
expect(findTabNav(wrapper).exists()).toBe(true);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should display tab navigation for multiple tabs when hideSingleTab is false (default)', async() => {
|
|
37
|
+
const wrapper = mount(Tabbed, {
|
|
38
|
+
slots: {
|
|
39
|
+
default: {
|
|
40
|
+
components: { Tab },
|
|
41
|
+
template: `
|
|
42
|
+
<Tab name="tab1" label="Tab 1" />
|
|
43
|
+
<Tab name="tab2" label="Tab 2" />
|
|
44
|
+
`,
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
global: { ...defaultGlobalMountOptions },
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
await wrapper.vm.$nextTick();
|
|
51
|
+
|
|
52
|
+
expect(findTabNav(wrapper).exists()).toBe(true);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('should NOT display tab navigation for a single tab when hideSingleTab is true', async() => {
|
|
56
|
+
const wrapper = mount(Tabbed, {
|
|
57
|
+
props: { hideSingleTab: true },
|
|
58
|
+
slots: { default: { components: { Tab }, template: '<Tab name="tab1" label="Tab 1" />' } },
|
|
59
|
+
global: { ...defaultGlobalMountOptions },
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
await wrapper.vm.$nextTick();
|
|
63
|
+
|
|
64
|
+
expect(findTabNav(wrapper).exists()).toBe(false);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should display tab navigation for multiple tabs when hideSingleTab is true', async() => {
|
|
68
|
+
const wrapper = mount(Tabbed, {
|
|
69
|
+
props: { hideSingleTab: true },
|
|
70
|
+
slots: {
|
|
71
|
+
default: {
|
|
72
|
+
components: { Tab },
|
|
73
|
+
template: `
|
|
74
|
+
<Tab name="tab1" label="Tab 1" />
|
|
75
|
+
<Tab name="tab2" label="Tab 2" />
|
|
76
|
+
`,
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
global: { ...defaultGlobalMountOptions },
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
await wrapper.vm.$nextTick();
|
|
83
|
+
|
|
84
|
+
expect(findTabNav(wrapper).exists()).toBe(true);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
@@ -7,6 +7,10 @@ import findIndex from 'lodash/findIndex';
|
|
|
7
7
|
import { ExtensionPoint, TabLocation } from '@shell/core/types';
|
|
8
8
|
import { getApplicableExtensionEnhancements } from '@shell/core/plugin-helpers';
|
|
9
9
|
import Tab from '@shell/components/Tabbed/Tab';
|
|
10
|
+
import { ref } from 'vue';
|
|
11
|
+
import { useIsInResourceDetailDrawer } from '@shell/components/Drawer/ResourceDetailDrawer/composables';
|
|
12
|
+
import { useIsInResourceDetailPage } from '@shell/composables/resourceDetail';
|
|
13
|
+
import { useIsInResourceCreatePage, useIsInResourceEditPage } from '@shell/composables/cruResource';
|
|
10
14
|
|
|
11
15
|
export default {
|
|
12
16
|
name: 'Tabbed',
|
|
@@ -105,7 +109,14 @@ export default {
|
|
|
105
109
|
},
|
|
106
110
|
|
|
107
111
|
data() {
|
|
108
|
-
const
|
|
112
|
+
const location = this.getInitialTabLocation();
|
|
113
|
+
let extensionTabs = this.showExtensionTabs ? getApplicableExtensionEnhancements(this, ExtensionPoint.TAB, location, this.$route, this, this.extensionParams) || [] : [];
|
|
114
|
+
const legacyExtensionTabs = this.showExtensionTabs ? getApplicableExtensionEnhancements(this, ExtensionPoint.TAB, TabLocation.RESOURCE_DETAIL, this.$route, this, this.extensionParams) || [] : [];
|
|
115
|
+
|
|
116
|
+
if (!extensionTabs.length) {
|
|
117
|
+
// Support legacy tabs for RESOURCE_DETAIL location
|
|
118
|
+
extensionTabs = legacyExtensionTabs;
|
|
119
|
+
}
|
|
109
120
|
|
|
110
121
|
const parsedExtTabs = extensionTabs.map((item) => {
|
|
111
122
|
return {
|
|
@@ -130,7 +141,18 @@ export default {
|
|
|
130
141
|
// hide tabs based on tab count IF flag is active
|
|
131
142
|
hideTabs() {
|
|
132
143
|
return this.hideSingleTab && this.sortedTabs.length === 1;
|
|
133
|
-
}
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
setup() {
|
|
148
|
+
const isInResourceDetailDrawer = ref(useIsInResourceDetailDrawer());
|
|
149
|
+
const isInResourceDetailPage = ref(useIsInResourceDetailPage());
|
|
150
|
+
const isInResourceEditPage = ref(useIsInResourceEditPage());
|
|
151
|
+
const isInResourceCreatePage = ref(useIsInResourceCreatePage());
|
|
152
|
+
|
|
153
|
+
return {
|
|
154
|
+
isInResourceDetailDrawer, isInResourceDetailPage, isInResourceEditPage, isInResourceCreatePage
|
|
155
|
+
};
|
|
134
156
|
},
|
|
135
157
|
|
|
136
158
|
watch: {
|
|
@@ -166,6 +188,19 @@ export default {
|
|
|
166
188
|
},
|
|
167
189
|
|
|
168
190
|
methods: {
|
|
191
|
+
getInitialTabLocation() {
|
|
192
|
+
if (this.isInResourceEditPage) {
|
|
193
|
+
return TabLocation.RESOURCE_EDIT_PAGE;
|
|
194
|
+
} else if (this.isInResourceDetailDrawer) {
|
|
195
|
+
return TabLocation.RESOURCE_SHOW_CONFIGURATION;
|
|
196
|
+
} else if (this.isInResourceDetailPage) {
|
|
197
|
+
return TabLocation.RESOURCE_DETAIL_PAGE;
|
|
198
|
+
} else if (this.isInResourceCreatePage) {
|
|
199
|
+
return TabLocation.RESOURCE_CREATE_PAGE;
|
|
200
|
+
} else {
|
|
201
|
+
return TabLocation.OTHER;
|
|
202
|
+
}
|
|
203
|
+
},
|
|
169
204
|
hasIcon(tab) {
|
|
170
205
|
return tab.displayAlertIcon || (tab.error && !tab.active);
|
|
171
206
|
},
|
|
@@ -244,4 +244,53 @@ describe('component: NamespaceFilter', () => {
|
|
|
244
244
|
|
|
245
245
|
it.todo('should generate the options based on the Rancher resources');
|
|
246
246
|
});
|
|
247
|
+
|
|
248
|
+
describe('given filter input text selection', () => {
|
|
249
|
+
it('should allow text selection by stopping mousedown propagation', async() => {
|
|
250
|
+
const wrapper = mount(NamespaceFilter, {
|
|
251
|
+
computed: {
|
|
252
|
+
filtered: () => [],
|
|
253
|
+
options: () => [],
|
|
254
|
+
value: () => [],
|
|
255
|
+
},
|
|
256
|
+
global: {
|
|
257
|
+
mocks: {
|
|
258
|
+
t: (key: string) => key,
|
|
259
|
+
$store: { getters: { 'i18n/t': () => '', namespaceFilterMode: () => undefined } },
|
|
260
|
+
$fetchState: { pending: false }
|
|
261
|
+
},
|
|
262
|
+
directives: {
|
|
263
|
+
'clean-tooltip': () => {},
|
|
264
|
+
shortkey: () => {},
|
|
265
|
+
},
|
|
266
|
+
stubs: { RcButton: { template: '<button><slot /></button>' } },
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// Open the dropdown to reveal the filter input
|
|
271
|
+
const dropdown = wrapper.find('[data-testid="namespaces-dropdown"]');
|
|
272
|
+
|
|
273
|
+
await dropdown.trigger('click');
|
|
274
|
+
|
|
275
|
+
// Find the filter input
|
|
276
|
+
const filterInput = wrapper.find('.ns-filter-input');
|
|
277
|
+
|
|
278
|
+
expect(filterInput.exists()).toBe(true);
|
|
279
|
+
|
|
280
|
+
// Trigger mousedown on the filter input and capture the event
|
|
281
|
+
const mousedownEvent = new MouseEvent('mousedown', {
|
|
282
|
+
bubbles: true,
|
|
283
|
+
cancelable: true
|
|
284
|
+
});
|
|
285
|
+
const stopPropagationSpy = jest.spyOn(mousedownEvent, 'stopPropagation');
|
|
286
|
+
|
|
287
|
+
filterInput.element.dispatchEvent(mousedownEvent);
|
|
288
|
+
|
|
289
|
+
// Verify stopPropagation was called (which allows text selection)
|
|
290
|
+
expect(stopPropagationSpy).toHaveBeenCalledWith();
|
|
291
|
+
|
|
292
|
+
// Verify the default was NOT prevented (text selection should work)
|
|
293
|
+
expect(mousedownEvent.defaultPrevented).toBe(false);
|
|
294
|
+
});
|
|
295
|
+
});
|
|
247
296
|
});
|
|
@@ -56,11 +56,13 @@ export default {
|
|
|
56
56
|
|
|
57
57
|
data() {
|
|
58
58
|
return {
|
|
59
|
-
principals:
|
|
60
|
-
searchStr:
|
|
61
|
-
options:
|
|
62
|
-
newValue:
|
|
63
|
-
tooltipContent:
|
|
59
|
+
principals: null,
|
|
60
|
+
searchStr: '',
|
|
61
|
+
options: [],
|
|
62
|
+
newValue: '',
|
|
63
|
+
tooltipContent: null,
|
|
64
|
+
hasSearchTooShort: false,
|
|
65
|
+
minSearchLength: 2,
|
|
64
66
|
};
|
|
65
67
|
},
|
|
66
68
|
|
|
@@ -133,9 +135,20 @@ export default {
|
|
|
133
135
|
this.searchStr = str;
|
|
134
136
|
|
|
135
137
|
if ( str ) {
|
|
138
|
+
// Backend requires minimum 2 characters for search
|
|
139
|
+
if (str.length < this.minSearchLength) {
|
|
140
|
+
this.hasSearchTooShort = true;
|
|
141
|
+
this.options = [];
|
|
142
|
+
loading(false);
|
|
143
|
+
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
this.hasSearchTooShort = false;
|
|
136
148
|
loading(true);
|
|
137
149
|
this.debouncedSearch(str, loading);
|
|
138
150
|
} else {
|
|
151
|
+
this.hasSearchTooShort = false;
|
|
139
152
|
this.search(null, loading);
|
|
140
153
|
}
|
|
141
154
|
},
|
|
@@ -162,6 +175,10 @@ export default {
|
|
|
162
175
|
if ( this.searchStr === str ) {
|
|
163
176
|
// If not, they've already typed something else
|
|
164
177
|
this.options = res.map((x) => x.id);
|
|
178
|
+
// display the search results if the dropdown has been closed
|
|
179
|
+
if (this.options.length) {
|
|
180
|
+
this.$refs['labeled-select'].isOpen = true;
|
|
181
|
+
}
|
|
165
182
|
}
|
|
166
183
|
} catch (e) {
|
|
167
184
|
this.options = [];
|
|
@@ -196,7 +213,12 @@ export default {
|
|
|
196
213
|
@on-close="setTooltipContent()"
|
|
197
214
|
>
|
|
198
215
|
<template v-slot:no-options="{ searching }">
|
|
199
|
-
<template v-if="
|
|
216
|
+
<template v-if="hasSearchTooShort">
|
|
217
|
+
<span class="search-slot">
|
|
218
|
+
{{ t('cluster.memberRoles.addClusterMember.minCharacters', { count: minSearchLength }) }}
|
|
219
|
+
</span>
|
|
220
|
+
</template>
|
|
221
|
+
<template v-else-if="searching">
|
|
200
222
|
<span class="search-slot">
|
|
201
223
|
{{ t('cluster.memberRoles.addClusterMember.noResults') }}
|
|
202
224
|
</span>
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { shallowMount, type VueWrapper } from '@vue/test-utils';
|
|
2
|
+
import SelectPrincipal from '@shell/components/auth/SelectPrincipal.vue';
|
|
3
|
+
|
|
4
|
+
describe('component: SelectPrincipal', () => {
|
|
5
|
+
const mockStore = { dispatch: jest.fn().mockResolvedValue([]) };
|
|
6
|
+
|
|
7
|
+
const defaultMountOptions = {
|
|
8
|
+
global: {
|
|
9
|
+
mocks: {
|
|
10
|
+
$fetchState: { pending: false },
|
|
11
|
+
$store: mockStore,
|
|
12
|
+
t: (key: string, opts?: any) => opts?.count ? `${ key } ${ opts.count }` : key,
|
|
13
|
+
},
|
|
14
|
+
stubs: {
|
|
15
|
+
LabeledSelect: {
|
|
16
|
+
template: '<div class="labeled-select-stub"><slot name="no-options" :searching="searching" /></div>',
|
|
17
|
+
props: ['options', 'searchable', 'filterable'],
|
|
18
|
+
data() {
|
|
19
|
+
return { searching: false };
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
Principal: true,
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
jest.clearAllMocks();
|
|
29
|
+
mockStore.dispatch.mockResolvedValue([]);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe('onSearch', () => {
|
|
33
|
+
it('should set hasSearchTooShort to true when search string is less than minSearchLength', async() => {
|
|
34
|
+
const wrapper: VueWrapper<any> = shallowMount(SelectPrincipal, defaultMountOptions);
|
|
35
|
+
|
|
36
|
+
// Set principals to an empty array to avoid null errors
|
|
37
|
+
wrapper.vm.principals = [];
|
|
38
|
+
await wrapper.vm.$nextTick();
|
|
39
|
+
|
|
40
|
+
const loadingFn = jest.fn();
|
|
41
|
+
|
|
42
|
+
wrapper.vm.onSearch('a', loadingFn);
|
|
43
|
+
|
|
44
|
+
expect(wrapper.vm.hasSearchTooShort).toBe(true);
|
|
45
|
+
expect(wrapper.vm.options).toStrictEqual([]);
|
|
46
|
+
expect(loadingFn).toHaveBeenCalledWith(false);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should set hasSearchTooShort to false when search string meets minSearchLength', async() => {
|
|
50
|
+
const wrapper: VueWrapper<any> = shallowMount(SelectPrincipal, defaultMountOptions);
|
|
51
|
+
|
|
52
|
+
wrapper.vm.principals = [];
|
|
53
|
+
await wrapper.vm.$nextTick();
|
|
54
|
+
|
|
55
|
+
const loadingFn = jest.fn();
|
|
56
|
+
|
|
57
|
+
wrapper.vm.onSearch('ab', loadingFn);
|
|
58
|
+
|
|
59
|
+
expect(wrapper.vm.hasSearchTooShort).toBe(false);
|
|
60
|
+
expect(loadingFn).toHaveBeenCalledWith(true);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should set hasSearchTooShort to false when search string is empty', async() => {
|
|
64
|
+
const wrapper: VueWrapper<any> = shallowMount(SelectPrincipal, defaultMountOptions);
|
|
65
|
+
|
|
66
|
+
wrapper.vm.principals = [];
|
|
67
|
+
await wrapper.vm.$nextTick();
|
|
68
|
+
|
|
69
|
+
// First set hasSearchTooShort to true
|
|
70
|
+
wrapper.vm.hasSearchTooShort = true;
|
|
71
|
+
|
|
72
|
+
const loadingFn = jest.fn();
|
|
73
|
+
|
|
74
|
+
wrapper.vm.onSearch('', loadingFn);
|
|
75
|
+
|
|
76
|
+
expect(wrapper.vm.hasSearchTooShort).toBe(false);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should not call debouncedSearch when search string is too short', async() => {
|
|
80
|
+
const wrapper: VueWrapper<any> = shallowMount(SelectPrincipal, defaultMountOptions);
|
|
81
|
+
|
|
82
|
+
wrapper.vm.principals = [];
|
|
83
|
+
await wrapper.vm.$nextTick();
|
|
84
|
+
|
|
85
|
+
// Spy on the debounced search
|
|
86
|
+
const debouncedSearchSpy = jest.spyOn(wrapper.vm, 'debouncedSearch');
|
|
87
|
+
const loadingFn = jest.fn();
|
|
88
|
+
|
|
89
|
+
wrapper.vm.onSearch('x', loadingFn);
|
|
90
|
+
|
|
91
|
+
expect(debouncedSearchSpy).not.toHaveBeenCalled();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('should call debouncedSearch when search string meets minimum length', async() => {
|
|
95
|
+
const wrapper: VueWrapper<any> = shallowMount(SelectPrincipal, defaultMountOptions);
|
|
96
|
+
|
|
97
|
+
wrapper.vm.principals = [];
|
|
98
|
+
await wrapper.vm.$nextTick();
|
|
99
|
+
|
|
100
|
+
const debouncedSearchSpy = jest.spyOn(wrapper.vm, 'debouncedSearch');
|
|
101
|
+
const loadingFn = jest.fn();
|
|
102
|
+
|
|
103
|
+
wrapper.vm.onSearch('xy', loadingFn);
|
|
104
|
+
|
|
105
|
+
expect(debouncedSearchSpy).toHaveBeenCalledWith('xy', loadingFn);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
describe('minSearchLength', () => {
|
|
110
|
+
it('should have a default minSearchLength of 2', async() => {
|
|
111
|
+
const wrapper: VueWrapper<any> = shallowMount(SelectPrincipal, defaultMountOptions);
|
|
112
|
+
|
|
113
|
+
wrapper.vm.principals = [];
|
|
114
|
+
await wrapper.vm.$nextTick();
|
|
115
|
+
|
|
116
|
+
expect(wrapper.vm.minSearchLength).toBe(2);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
|
-
import { ref, computed
|
|
2
|
+
import { ref, computed } from 'vue';
|
|
3
3
|
import { _EDIT } from '@shell/config/query-params';
|
|
4
4
|
import { TYPES } from '@shell/models/secret';
|
|
5
5
|
import { SECRET } from '@shell/config/types';
|
|
@@ -305,7 +305,7 @@ export default {
|
|
|
305
305
|
namespace.value = toRef(props.forceNamespace);
|
|
306
306
|
updateNamespace(namespace);
|
|
307
307
|
} else if (props.namespaceKey) {
|
|
308
|
-
namespace.value = get(v, props.namespaceKey);
|
|
308
|
+
namespace.value = get(v.value, props.namespaceKey);
|
|
309
309
|
} else {
|
|
310
310
|
namespace.value = metadata?.namespace;
|
|
311
311
|
}
|
|
@@ -181,7 +181,7 @@ export default {
|
|
|
181
181
|
:options="selectNodeOptions"
|
|
182
182
|
:mode="mode"
|
|
183
183
|
:data-testid="'node-scheduling-selectNode'"
|
|
184
|
-
@
|
|
184
|
+
@update:value="update"
|
|
185
185
|
/>
|
|
186
186
|
</div>
|
|
187
187
|
<template v-if="selectNode === 'nodeSelector'">
|
|
@@ -205,7 +205,7 @@ export default {
|
|
|
205
205
|
v-model:value="nodeAffinity"
|
|
206
206
|
:mode="mode"
|
|
207
207
|
:data-testid="'node-scheduling-nodeAffinity'"
|
|
208
|
-
@
|
|
208
|
+
@update:value="update"
|
|
209
209
|
/>
|
|
210
210
|
</template>
|
|
211
211
|
</div>
|