@rancher/shell 3.0.8-rc.1 → 3.0.8-rc.12
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/brand/suse/banner.svg +1 -0
- package/assets/brand/suse/dark/banner.svg +1 -0
- package/assets/brand/suse/dark/login-landscape.svg +1 -0
- package/assets/brand/suse/dark/rancher-logo.svg +1 -1
- package/assets/brand/suse/favicon.png +0 -0
- package/assets/brand/suse/login-landscape.svg +1 -0
- package/assets/brand/suse/metadata.json +11 -1
- package/assets/brand/suse/rancher-logo.svg +1 -1
- package/assets/fonts/suse/suse-v2-latin-300.woff +0 -0
- package/assets/fonts/suse/suse-v2-latin-300.woff2 +0 -0
- package/assets/fonts/suse/suse-v2-latin-600.woff +0 -0
- package/assets/fonts/suse/suse-v2-latin-600.woff2 +0 -0
- package/assets/fonts/suse/suse-v2-latin-700.woff +0 -0
- package/assets/fonts/suse/suse-v2-latin-700.woff2 +0 -0
- package/assets/fonts/suse/suse-v2-latin-800.woff +0 -0
- package/assets/fonts/suse/suse-v2-latin-800.woff2 +0 -0
- package/assets/fonts/suse/suse-v2-latin-regular.woff +0 -0
- package/assets/fonts/suse/suse-v2-latin-regular.woff2 +0 -0
- package/assets/images/content/README.md +5 -0
- package/assets/images/content/cloud-native.svg +84 -0
- package/assets/images/content/dark/cloud-native.svg +21 -0
- package/assets/images/content/dark/shield.svg +59 -0
- package/assets/images/content/dark/suse.svg +10 -0
- package/assets/images/content/shield.svg +59 -0
- package/assets/images/content/suse.svg +10 -0
- package/assets/styles/base/_typography.scss +1 -0
- package/assets/styles/fonts/_fontstack.scss +53 -1
- package/assets/styles/global/_cards.scss +0 -3
- package/assets/styles/global/_layout.scss +21 -35
- package/assets/styles/themes/_dark.scss +1 -1
- package/assets/styles/themes/_light.scss +1 -1
- package/assets/styles/themes/_modern.scss +11 -3
- package/assets/styles/themes/_suse.scss +116 -24
- package/assets/translations/en-us.yaml +94 -10
- package/components/AutoscalerCard.vue +113 -0
- package/components/AutoscalerTab.vue +94 -0
- package/components/BackLink.vue +8 -0
- package/components/BannerGraphic.vue +36 -21
- package/components/BrandImage.vue +17 -6
- package/components/ClusterIconMenu.vue +1 -1
- package/components/ClusterProviderIcon.vue +1 -1
- package/components/Cron/CronExpressionEditor.vue +1 -1
- package/components/Cron/CronExpressionEditorModal.vue +1 -1
- package/components/Drawer/Chrome.vue +2 -6
- package/components/Drawer/ResourceDetailDrawer/ConfigTab.vue +4 -9
- package/components/Drawer/ResourceDetailDrawer/YamlTab.vue +3 -8
- package/components/Drawer/ResourceDetailDrawer/composables.ts +3 -4
- package/components/Drawer/ResourceDetailDrawer/index.vue +4 -9
- package/components/Drawer/ResourceDetailDrawer/types.ts +17 -0
- package/components/Drawer/types.ts +3 -0
- package/components/DynamicContent/DynamicContentBanner.vue +102 -0
- package/components/DynamicContent/DynamicContentCloseButton.vue +42 -0
- package/components/DynamicContent/DynamicContentIcon.vue +132 -0
- package/components/DynamicContent/DynamicContentPanel.vue +112 -0
- package/components/DynamicContent/content.ts +78 -0
- package/components/EmberPage.vue +1 -1
- package/components/IconOrSvg.vue +2 -2
- package/components/PaginatedResourceTable.vue +2 -6
- package/components/PopoverCard.vue +192 -0
- package/components/Questions/__tests__/index.test.ts +159 -0
- package/components/Resource/Detail/CopyToClipboard.vue +4 -1
- package/components/Resource/Detail/FetchLoader/composables.ts +18 -4
- package/components/Resource/Detail/Metadata/Annotations/index.vue +2 -2
- package/components/Resource/Detail/Metadata/IdentifyingInformation/__tests__/identifying-fields.test.ts +1 -1
- package/components/Resource/Detail/Metadata/IdentifyingInformation/identifying-fields.ts +4 -0
- package/components/Resource/Detail/Metadata/KeyValueRow.vue +1 -1
- package/components/Resource/Detail/Metadata/Labels/index.vue +2 -2
- package/components/Resource/Detail/Metadata/composables.ts +9 -9
- package/components/Resource/Detail/Metadata/index.vue +3 -3
- package/components/Resource/Detail/ResourcePopover/ResourcePopoverCard.vue +2 -19
- package/components/Resource/Detail/ResourcePopover/__tests__/ResourcePopoverCard.test.ts +0 -29
- package/components/Resource/Detail/ResourcePopover/__tests__/index.test.ts +132 -150
- package/components/Resource/Detail/ResourcePopover/index.vue +54 -159
- package/components/Resource/Detail/TitleBar/__tests__/index.test.ts +0 -2
- package/components/Resource/Detail/TitleBar/composables.ts +2 -1
- package/components/Resource/Detail/TitleBar/index.vue +10 -6
- package/components/Resource/Detail/composables.ts +12 -0
- package/components/ResourceDetail/Masthead/latest.vue +29 -0
- package/components/ResourceDetail/index.vue +4 -1
- package/components/ResourceList/Masthead.vue +1 -1
- package/components/ResourceTable.vue +1 -1
- package/components/SortableTable/index.vue +2 -1
- package/components/Tabbed/__tests__/index.test.ts +86 -0
- package/components/{nav/WindowManager → Window}/ContainerLogs.vue +1 -1
- package/components/{nav/WindowManager → Window}/ContainerLogsActions.vue +1 -0
- package/components/{nav/WindowManager → Window}/__tests__/ContainerLogs.test.ts +1 -1
- package/components/{nav/WindowManager → Window}/__tests__/ContainerShell.test.ts +2 -2
- package/components/__tests__/AutoscalerCard.test.ts +154 -0
- package/components/__tests__/AutoscalerTab.test.ts +125 -0
- package/components/__tests__/PopoverCard.test.ts +204 -0
- package/components/auth/SelectPrincipal.vue +24 -6
- package/components/auth/__tests__/SelectPrincipal.test.ts +119 -0
- package/components/auth/login/ldap.vue +3 -3
- package/components/form/NodeScheduling.vue +2 -2
- package/components/formatter/Autoscaler.vue +97 -0
- package/components/formatter/InternalExternalIP.vue +198 -24
- package/components/formatter/__tests__/Autoscaler.test.ts +156 -0
- package/components/formatter/__tests__/InternalExternalIP.test.ts +133 -0
- package/components/google/util/__tests__/formatter.test.ts +47 -0
- package/components/google/util/formatter.ts +5 -2
- package/components/nav/Group.vue +21 -5
- package/components/nav/Header.vue +37 -17
- package/components/nav/NamespaceFilter.vue +13 -1
- package/components/nav/NotificationCenter/index.vue +2 -1
- package/components/nav/TopLevelMenu.helper.ts +16 -6
- package/components/nav/TopLevelMenu.vue +4 -2
- package/components/nav/Type.vue +8 -3
- package/components/{DraggableZone.vue → nav/WindowManager/PinArea.vue} +47 -80
- package/components/nav/WindowManager/composables/useComponentsMount.ts +70 -0
- package/components/nav/WindowManager/composables/useDimensionsHandler.ts +105 -0
- package/components/nav/WindowManager/composables/useDragHandler.ts +99 -0
- package/components/nav/WindowManager/composables/usePanelHandler.ts +72 -0
- package/components/nav/WindowManager/composables/usePanelsHandler.ts +14 -0
- package/components/nav/WindowManager/composables/useResizeHandler.ts +167 -0
- package/components/nav/WindowManager/composables/useTabsHandler.ts +51 -0
- package/components/nav/WindowManager/constants.ts +23 -0
- package/components/nav/WindowManager/index.vue +61 -575
- package/components/nav/WindowManager/panels/HorizontalPanel.vue +265 -0
- package/components/nav/WindowManager/panels/TabBodyContainer.vue +39 -0
- package/components/nav/WindowManager/panels/VerticalPanel.vue +308 -0
- package/components/nav/__tests__/Type.test.ts +59 -0
- package/components/templates/default.vue +4 -40
- package/components/templates/home.vue +31 -5
- package/components/templates/plain.vue +30 -4
- package/components/templates/standalone.vue +1 -1
- package/composables/useI18n.ts +10 -1
- package/composables/useInterval.ts +15 -0
- package/config/__test__/uiplugins.test.ts +309 -0
- package/config/labels-annotations.js +9 -1
- package/config/product/explorer.js +3 -1
- package/config/product/manager.js +20 -9
- package/config/router/navigation-guards/clusters.js +3 -3
- package/config/router/navigation-guards/products.js +1 -1
- package/config/router/routes.js +10 -2
- package/config/settings.ts +2 -1
- package/config/store.js +4 -2
- package/config/table-headers.js +8 -0
- package/config/types.js +9 -0
- package/config/uiplugins.js +46 -2
- package/config/version.js +1 -1
- package/core/__test__/extension-manager-impl.test.js +236 -0
- package/core/extension-manager-impl.js +21 -4
- package/core/plugin-helpers.ts +4 -2
- package/core/plugins-loader.js +2 -2
- package/core/types-provisioning.ts +8 -1
- package/detail/pod.vue +1 -0
- package/detail/provisioning.cattle.io.cluster.vue +19 -7
- package/dialog/DeveloperLoadExtensionDialog.vue +13 -4
- package/dialog/RollbackWorkloadDialog.vue +2 -5
- package/dialog/SearchDialog.vue +1 -0
- package/directives/ui-context.ts +103 -0
- package/edit/__tests__/fleet.cattle.io.helmop.test.ts +2 -2
- package/edit/auth/__tests__/oidc.test.ts +26 -0
- package/edit/auth/github.vue +5 -0
- package/edit/auth/oidc.vue +5 -1
- package/edit/autoscaling.horizontalpodautoscaler/index.vue +1 -0
- package/edit/cloudcredential.vue +1 -1
- package/edit/configmap.vue +1 -0
- package/edit/constraints.gatekeeper.sh.constraint/index.vue +1 -0
- package/edit/fleet.cattle.io.gitrepo.vue +0 -10
- package/edit/fleet.cattle.io.helmop.vue +6 -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/CustomCommand.vue +32 -5
- package/edit/provisioning.cattle.io.cluster/__tests__/CustomCommand.test.ts +35 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/Networking.test.ts +155 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +21 -21
- package/edit/provisioning.cattle.io.cluster/index.vue +28 -18
- package/edit/provisioning.cattle.io.cluster/rke2.vue +50 -16
- package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +107 -5
- package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +92 -4
- package/edit/secret/index.vue +1 -1
- package/edit/service.vue +9 -4
- package/edit/serviceaccount.vue +1 -0
- package/edit/storage.k8s.io.storageclass/index.vue +1 -0
- package/edit/workload/index.vue +2 -1
- package/edit/workload/mixins/workload.js +1 -1
- package/initialize/App.vue +4 -4
- package/initialize/install-directives.js +2 -0
- package/initialize/install-plugins.js +19 -2
- package/list/provisioning.cattle.io.cluster.vue +15 -2
- package/machine-config/amazonec2.vue +42 -135
- package/machine-config/components/EC2Networking.vue +490 -0
- package/machine-config/components/__tests__/EC2Networking.test.ts +148 -0
- package/machine-config/components/__tests__/utils/vpcSubnetMockData.js +294 -0
- package/machine-config/digitalocean.vue +11 -0
- package/machine-config/google.vue +1 -1
- package/mixins/__tests__/brand.spec.ts +2 -2
- package/mixins/__tests__/chart.test.ts +21 -0
- package/mixins/brand.js +1 -7
- package/mixins/chart.js +7 -1
- package/mixins/create-edit-view/index.js +5 -0
- package/models/__tests__/chart.test.ts +33 -4
- package/models/__tests__/provisioning.cattle.io.cluster.test.ts +112 -5
- package/models/chart.js +25 -13
- package/models/cluster/node.js +13 -6
- package/models/cluster.x-k8s.io.machine.js +10 -20
- package/models/cluster.x-k8s.io.machinedeployment.js +5 -1
- package/models/management.cattle.io.cluster.js +21 -3
- package/models/management.cattle.io.kontainerdriver.js +1 -0
- package/models/provisioning.cattle.io.cluster.js +249 -33
- package/package.json +8 -7
- package/pages/auth/login.vue +41 -5
- 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 +11 -13
- package/pages/c/_cluster/apps/charts/install.vue +1 -1
- package/pages/c/_cluster/explorer/index.vue +8 -6
- package/pages/c/_cluster/manager/hostedprovider/index.vue +220 -0
- package/pages/c/_cluster/settings/brand.vue +1 -1
- 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/pages/home.vue +14 -4
- package/pkg/auto-import.js +3 -3
- package/pkg/dynamic-importer.lib.js +5 -1
- package/pkg/import.js +1 -1
- 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/resource-class.js +10 -6
- package/plugins/dynamic-content.js +13 -0
- package/plugins/i18n.js +8 -0
- package/plugins/plugin.js +2 -2
- package/plugins/steve/__tests__/steve-pagination-utils.test.ts +333 -0
- package/plugins/steve/steve-class.js +1 -1
- package/plugins/steve/steve-pagination-utils.ts +39 -20
- package/plugins/steve/subscribe.js +17 -9
- package/plugins/subscribe-events.ts +4 -2
- package/rancher-components/Form/Checkbox/Checkbox.vue +1 -1
- package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.vue +6 -34
- 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/RcDropdownItem.vue +1 -0
- package/rancher-components/RcDropdown/RcDropdownItemSelect.vue +5 -1
- 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/utils/status.test.ts +67 -0
- package/rancher-components/utils/status.ts +77 -0
- package/scripts/typegen.sh +1 -0
- package/store/__tests__/catalog.test.ts +1 -1
- package/store/action-menu.js +8 -0
- package/store/auth.js +4 -4
- package/store/catalog.js +6 -0
- package/store/features.js +1 -0
- package/store/i18n.js +3 -3
- package/store/index.js +40 -19
- package/store/notifications.ts +51 -4
- package/store/plugins.js +7 -3
- package/store/prefs.js +6 -6
- package/store/type-map.js +7 -7
- package/store/ui-context.ts +86 -0
- package/store/wm.ts +244 -0
- package/types/notifications/index.ts +27 -3
- package/types/shell/index.d.ts +80 -4
- package/types/store/__tests__/pagination.types.spec.ts +137 -0
- package/types/store/pagination.types.ts +157 -9
- package/types/store/subscribe-events.types.ts +8 -1
- package/types/store/subscribe.types.ts +1 -0
- package/types/window-manager.ts +24 -0
- package/utils/__tests__/object.test.ts +19 -0
- package/utils/__tests__/provider.test.ts +98 -0
- package/utils/__tests__/selector-typed.test.ts +263 -0
- package/utils/__tests__/version.test.ts +19 -1
- package/utils/autoscaler-utils.ts +7 -0
- package/utils/back-off.ts +3 -3
- package/utils/brand.ts +29 -0
- package/utils/chart.js +18 -0
- package/utils/color.js +1 -1
- package/utils/dynamic-content/__tests__/announcement.test.ts +498 -0
- package/utils/dynamic-content/__tests__/info.test.ts +21 -9
- package/utils/dynamic-content/announcement.ts +142 -0
- package/utils/dynamic-content/example.json +40 -0
- package/utils/dynamic-content/index.ts +6 -2
- package/utils/dynamic-content/info.ts +44 -2
- package/utils/dynamic-content/new-release.ts +1 -1
- package/utils/dynamic-content/notification-handler.ts +48 -0
- package/utils/dynamic-content/types.d.ts +53 -1
- package/utils/dynamic-importer.js +2 -2
- package/utils/favicon.js +4 -4
- package/utils/object.js +20 -2
- package/utils/pagination-utils.ts +2 -2
- package/utils/pagination-wrapper.ts +13 -9
- package/utils/provider.ts +14 -0
- package/utils/scroll.js +7 -0
- package/utils/selector-typed.ts +6 -2
- package/utils/settings.ts +15 -0
- package/utils/unit-tests/pagination-utils.spec.ts +8 -8
- package/utils/validators/machine-pool.ts +13 -3
- package/utils/version.js +15 -0
- package/vue.config.js +3 -3
- package/assets/images/icons/document.svg +0 -3
- package/plugins/nuxt-client-init.js +0 -3
- package/store/wm.js +0 -95
- /package/components/{nav/WindowManager → Window}/ChartReadme.vue +0 -0
- /package/components/{nav/WindowManager → Window}/ContainerShell.vue +0 -0
- /package/components/{nav/WindowManager → Window}/KubectlShell.vue +0 -0
- /package/components/{nav/WindowManager → Window}/MachineSsh.vue +0 -0
- /package/components/{nav/WindowManager → Window}/Window.vue +0 -0
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
SCHEMA, COUNT, POD, MANAGEMENT, BRAND
|
|
4
|
+
} from '@shell/config/types';
|
|
5
|
+
import { SETTING } from '@shell/config/settings';
|
|
3
6
|
|
|
4
7
|
import { matches } from '@shell/utils/selector';
|
|
5
8
|
import { typeMunge, typeRef, SIMPLE_TYPES } from '@shell/utils/create-yaml';
|
|
@@ -204,6 +207,20 @@ export default {
|
|
|
204
207
|
}
|
|
205
208
|
},
|
|
206
209
|
|
|
210
|
+
brand: (state, getters) => {
|
|
211
|
+
const brand = getters['byId'](MANAGEMENT.SETTING, SETTING.BRAND);
|
|
212
|
+
|
|
213
|
+
if (!brand?.value) {
|
|
214
|
+
return undefined;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if ([BRAND.CSP, BRAND.FEDERAL, BRAND.RGS].includes(brand.value)) {
|
|
218
|
+
return BRAND.SUSE;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return brand.value;
|
|
222
|
+
},
|
|
223
|
+
|
|
207
224
|
/**
|
|
208
225
|
* Checks a schema for the given path
|
|
209
226
|
*
|
|
@@ -526,7 +543,7 @@ export default {
|
|
|
526
543
|
const store = state.config.namespace;
|
|
527
544
|
const resource = id || context ? { id, context } : null;
|
|
528
545
|
|
|
529
|
-
return paginationUtils.isEnabled({ rootGetters, $
|
|
546
|
+
return paginationUtils.isEnabled({ rootGetters, $extension: rootState.$extension }, { store, resource });
|
|
530
547
|
},
|
|
531
548
|
|
|
532
549
|
/**
|
|
@@ -39,7 +39,6 @@ import { handleConflict } from '@shell/plugins/dashboard-store/normalize';
|
|
|
39
39
|
import { ExtensionPoint, ActionLocation } from '@shell/core/types';
|
|
40
40
|
import { getApplicableExtensionEnhancements } from '@shell/core/plugin-helpers';
|
|
41
41
|
import { parse } from '@shell/utils/selector';
|
|
42
|
-
import { importDrawer } from '@shell/utils/dynamic-importer';
|
|
43
42
|
|
|
44
43
|
export const DNS_LIKE_TYPES = ['dnsLabel', 'dnsLabelRestricted', 'hostname'];
|
|
45
44
|
|
|
@@ -611,7 +610,11 @@ export default class Resource {
|
|
|
611
610
|
}
|
|
612
611
|
|
|
613
612
|
get '$plugin'() {
|
|
614
|
-
return this.$ctx.rootState?.$
|
|
613
|
+
return this.$ctx.rootState?.$extension;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
get '$extension'() {
|
|
617
|
+
return this.$ctx.rootState?.$extension;
|
|
615
618
|
}
|
|
616
619
|
|
|
617
620
|
get customValidationRules() {
|
|
@@ -906,11 +909,11 @@ export default class Resource {
|
|
|
906
909
|
return out;
|
|
907
910
|
}
|
|
908
911
|
|
|
909
|
-
showConfiguration(returnFocusSelector) {
|
|
912
|
+
showConfiguration(returnFocusSelector, defaultTab) {
|
|
910
913
|
const onClose = () => this.$ctx.commit('slideInPanel/close', undefined, { root: true });
|
|
911
914
|
|
|
912
915
|
this.$ctx.commit('slideInPanel/open', {
|
|
913
|
-
component:
|
|
916
|
+
component: require(`@shell/components/Drawer/ResourceDetailDrawer/index.vue`).default,
|
|
914
917
|
componentProps: {
|
|
915
918
|
resource: this,
|
|
916
919
|
onClose,
|
|
@@ -921,7 +924,8 @@ export default class Resource {
|
|
|
921
924
|
'z-index': 101, // We want this to be above the main side menu
|
|
922
925
|
closeOnRouteChange: ['name', 'params', 'query'], // We want to ignore hash changes, tables in extensions can trigger the drawer to close while opening
|
|
923
926
|
triggerFocusTrap: true,
|
|
924
|
-
returnFocusSelector
|
|
927
|
+
returnFocusSelector,
|
|
928
|
+
defaultTab
|
|
925
929
|
}
|
|
926
930
|
}, { root: true });
|
|
927
931
|
}
|
|
@@ -1777,7 +1781,7 @@ export default class Resource {
|
|
|
1777
1781
|
CustomValidators[validatorName](pathValue, this.$rootGetters, errors, validatorArgs, displayKey, data);
|
|
1778
1782
|
} else if (!isEmpty(validatorName) && !validatorExists) {
|
|
1779
1783
|
// Check if validator is imported from plugin
|
|
1780
|
-
const pluginValidator = this.$rootState.$
|
|
1784
|
+
const pluginValidator = this.$rootState.$extension?.getValidator(validatorName);
|
|
1781
1785
|
|
|
1782
1786
|
if (pluginValidator) {
|
|
1783
1787
|
pluginValidator(pathValue, this.$rootGetters, errors, validatorArgs, displayKey, data);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { createHandler, DynamicContentAnnouncementHandlerName } from '@shell/utils/dynamic-content/notification-handler';
|
|
2
|
+
import { NotificationHandlerExtensionName } from '@shell/types/notifications';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Register the notification handler for dynamic content
|
|
6
|
+
*/
|
|
7
|
+
export default function(context) {
|
|
8
|
+
const { store, $extension } = context;
|
|
9
|
+
|
|
10
|
+
const handler = createHandler(store);
|
|
11
|
+
|
|
12
|
+
$extension.register(NotificationHandlerExtensionName, DynamicContentAnnouncementHandlerName, handler);
|
|
13
|
+
}
|
package/plugins/i18n.js
CHANGED
|
@@ -3,6 +3,14 @@ import { escapeHtml } from '../utils/string';
|
|
|
3
3
|
import { watchEffect, ref, h } from 'vue';
|
|
4
4
|
import { useStore } from 'vuex';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* @param {import('vuex').Store<any>} store
|
|
8
|
+
* @param {string} key
|
|
9
|
+
* @param {Record<string, any>} [args]
|
|
10
|
+
* @param {boolean} [raw]
|
|
11
|
+
* @param {boolean} [escapehtml]
|
|
12
|
+
* @returns {string}
|
|
13
|
+
*/
|
|
6
14
|
export function stringFor(store, key, args, raw = false, escapehtml = true) {
|
|
7
15
|
const translation = store.getters['i18n/t'](key, args);
|
|
8
16
|
|
package/plugins/plugin.js
CHANGED
|
@@ -44,7 +44,7 @@ export default async function(context) {
|
|
|
44
44
|
const res = await allHashSettled(fetches);
|
|
45
45
|
|
|
46
46
|
// Initialize the built-in extensions now - this is now done here so that built-in extensions get the same, correct environment data (version etc)
|
|
47
|
-
context.$
|
|
47
|
+
context.$extension.loadBuiltinExtensions();
|
|
48
48
|
|
|
49
49
|
if (res.plugins?.status === 'rejected') {
|
|
50
50
|
throw new Error(res.reason);
|
|
@@ -60,7 +60,7 @@ export default async function(context) {
|
|
|
60
60
|
const shouldNotLoad = shouldNotLoadPlugin(plugin, { rancherVersion, kubeVersion }, context.store.getters['uiplugins/plugins'] || []); // Error key string or boolean
|
|
61
61
|
|
|
62
62
|
if (!shouldNotLoad) {
|
|
63
|
-
hash[plugin.name] = context.$
|
|
63
|
+
hash[plugin.name] = context.$extension.loadPluginAsync(plugin);
|
|
64
64
|
} else {
|
|
65
65
|
context.store.dispatch('uiplugins/setError', { name: plugin.name, error: shouldNotLoad });
|
|
66
66
|
}
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
|
|
2
|
+
import { PaginationFilterEquality, PaginationFilterField, PaginationParamFilter, PaginationParamProjectOrNamespace } from '@shell/types/store/pagination.types';
|
|
3
|
+
import { NAMESPACE_FILTER_P_FULL_PREFIX } from '@shell/utils/namespace-filter';
|
|
4
|
+
import stevePaginationUtils from '../steve-pagination-utils';
|
|
5
|
+
import Schema from '@shell/models/schema';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The `NamespaceProjectFilters` class is a protected class within `steve-pagination-utils.ts`.
|
|
9
|
+
* To test its protected methods, we extend it with a test class that exposes them.
|
|
10
|
+
*/
|
|
11
|
+
class TestNamespaceProjectFilters {
|
|
12
|
+
public handlePrefAndSettingFilter(args: any) {
|
|
13
|
+
return stevePaginationUtils.handlePrefAndSettingFilter(args);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public handleSystemOrUserFilter(args: any) {
|
|
17
|
+
return stevePaginationUtils.handleSystemOrUserFilter(args);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public handleSelectionFilter(neu: string[], isLocalCluster: boolean) {
|
|
21
|
+
return stevePaginationUtils.handleSelectionFilter(neu, isLocalCluster);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
describe('class: NamespaceProjectFilters', () => {
|
|
26
|
+
const testNamespaceProjectFilters = new TestNamespaceProjectFilters();
|
|
27
|
+
|
|
28
|
+
const normalNs = {
|
|
29
|
+
id: 'normal', name: 'normal', isObscure: false, isSystem: false
|
|
30
|
+
};
|
|
31
|
+
const obscureNs = {
|
|
32
|
+
id: 'obscure', name: 'obscure', isObscure: true, isSystem: false
|
|
33
|
+
};
|
|
34
|
+
const systemNs = {
|
|
35
|
+
id: 'system', name: 'system', isObscure: false, isSystem: true
|
|
36
|
+
};
|
|
37
|
+
const obscureAndSystemNs = {
|
|
38
|
+
id: 'obscure-system', name: 'obscure-system', isObscure: true, isSystem: true
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const allNamespaces = [normalNs, obscureNs, systemNs, obscureAndSystemNs];
|
|
42
|
+
|
|
43
|
+
describe('method: handlePrefAndSettingFilter', () => {
|
|
44
|
+
it('should return no filters if all namespaces are shown', () => {
|
|
45
|
+
const result = testNamespaceProjectFilters.handlePrefAndSettingFilter({
|
|
46
|
+
allNamespaces,
|
|
47
|
+
showReservedRancherNamespaces: true,
|
|
48
|
+
productHidesSystemNamespaces: false,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
expect(result).toStrictEqual([]);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should filter obscure namespaces if showReservedRancherNamespaces is false', () => {
|
|
55
|
+
const result = testNamespaceProjectFilters.handlePrefAndSettingFilter({
|
|
56
|
+
allNamespaces,
|
|
57
|
+
showReservedRancherNamespaces: false,
|
|
58
|
+
productHidesSystemNamespaces: false,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
expect(result).toHaveLength(1);
|
|
62
|
+
expect(result).toContainEqual(expect.objectContaining({
|
|
63
|
+
fields: [expect.objectContaining({
|
|
64
|
+
value: 'obscure,obscure-system', equality: ' NOTIN ', field: `metadata.namespace`
|
|
65
|
+
})]
|
|
66
|
+
}));
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('should filter system namespaces if productHidesSystemNamespaces is true', () => {
|
|
70
|
+
const result = testNamespaceProjectFilters.handlePrefAndSettingFilter({
|
|
71
|
+
allNamespaces,
|
|
72
|
+
showReservedRancherNamespaces: true,
|
|
73
|
+
productHidesSystemNamespaces: true,
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
expect(result).toHaveLength(1);
|
|
77
|
+
expect(result).toContainEqual(expect.objectContaining({
|
|
78
|
+
fields: [expect.objectContaining({
|
|
79
|
+
value: 'system,obscure-system', equality: ' NOTIN ', field: `metadata.namespace`
|
|
80
|
+
})]
|
|
81
|
+
}));
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should filter both obscure and system namespaces when both settings are active', () => {
|
|
85
|
+
const result = testNamespaceProjectFilters.handlePrefAndSettingFilter({
|
|
86
|
+
allNamespaces,
|
|
87
|
+
showReservedRancherNamespaces: false,
|
|
88
|
+
productHidesSystemNamespaces: true,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
expect(result).toHaveLength(1);
|
|
92
|
+
expect(result).toContainEqual(expect.objectContaining({
|
|
93
|
+
fields: [expect.objectContaining({
|
|
94
|
+
value: 'obscure,system,obscure-system', equality: ' NOTIN ', field: `metadata.namespace`
|
|
95
|
+
})]
|
|
96
|
+
}));
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
describe('method: handleSystemOrUserFilter', () => {
|
|
101
|
+
it('should create an OR filter for system namespaces when isAllSystem is true', () => {
|
|
102
|
+
const result = testNamespaceProjectFilters.handleSystemOrUserFilter({
|
|
103
|
+
allNamespaces,
|
|
104
|
+
isAllSystem: true,
|
|
105
|
+
isAllUser: false,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
expect(result).toHaveLength(1);
|
|
109
|
+
const filter = result[0] as PaginationParamFilter;
|
|
110
|
+
|
|
111
|
+
expect(filter.fields).toHaveLength(2);
|
|
112
|
+
expect(filter.fields).toContainEqual(expect.objectContaining({
|
|
113
|
+
value: 'system', equality: '=', field: 'metadata.namespace'
|
|
114
|
+
}));
|
|
115
|
+
expect(filter.fields).toContainEqual(expect.objectContaining({
|
|
116
|
+
value: 'obscure-system', equality: '=', field: 'metadata.namespace'
|
|
117
|
+
}));
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should create AND filters to exclude system namespaces when isAllUser is true', () => {
|
|
121
|
+
const result = testNamespaceProjectFilters.handleSystemOrUserFilter({
|
|
122
|
+
allNamespaces,
|
|
123
|
+
isAllSystem: false,
|
|
124
|
+
isAllUser: true,
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
expect(result).toHaveLength(2);
|
|
128
|
+
expect(result).toContainEqual(expect.objectContaining({
|
|
129
|
+
fields: [expect.objectContaining({
|
|
130
|
+
value: 'system', equality: '!=', field: 'metadata.namespace'
|
|
131
|
+
})]
|
|
132
|
+
}));
|
|
133
|
+
expect(result).toContainEqual(expect.objectContaining({
|
|
134
|
+
fields: [expect.objectContaining({
|
|
135
|
+
value: 'obscure-system', equality: '!=', field: 'metadata.namespace'
|
|
136
|
+
})]
|
|
137
|
+
}));
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
describe('method: handleSelectionFilter', () => {
|
|
142
|
+
const selection = ['ns-1', `${ NAMESPACE_FILTER_P_FULL_PREFIX }p-1`];
|
|
143
|
+
|
|
144
|
+
it('should create projectsOrNamespaces filter for a selection in a non-local cluster', () => {
|
|
145
|
+
const result = testNamespaceProjectFilters.handleSelectionFilter(selection, false);
|
|
146
|
+
|
|
147
|
+
expect(result.projectsOrNamespaces).toHaveLength(1);
|
|
148
|
+
const pnsFilter = result.projectsOrNamespaces[0] as PaginationParamProjectOrNamespace;
|
|
149
|
+
|
|
150
|
+
expect(pnsFilter.param).toBe('projectsornamespaces');
|
|
151
|
+
expect(pnsFilter.fields).toHaveLength(2);
|
|
152
|
+
expect(pnsFilter.fields).toContainEqual(expect.objectContaining({ value: 'ns-1' }));
|
|
153
|
+
expect(pnsFilter.fields).toContainEqual(expect.objectContaining({ value: 'p-1' }));
|
|
154
|
+
expect(result.filters).toStrictEqual([]);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('should create projectsOrNamespaces and an exclusion filter for a selection in a local cluster', () => {
|
|
158
|
+
const result = testNamespaceProjectFilters.handleSelectionFilter(selection, true);
|
|
159
|
+
|
|
160
|
+
// projectsOrNamespaces part
|
|
161
|
+
expect(result.projectsOrNamespaces).toHaveLength(1);
|
|
162
|
+
const pnsFilter = result.projectsOrNamespaces[0] as PaginationParamProjectOrNamespace;
|
|
163
|
+
|
|
164
|
+
expect(pnsFilter.param).toBe('projectsornamespaces');
|
|
165
|
+
expect(pnsFilter.fields).toHaveLength(2);
|
|
166
|
+
expect(pnsFilter.fields).toContainEqual(expect.objectContaining({ value: 'ns-1' }));
|
|
167
|
+
expect(pnsFilter.fields).toContainEqual(expect.objectContaining({ value: 'p-1' }));
|
|
168
|
+
|
|
169
|
+
// filters part
|
|
170
|
+
expect(result.filters).toHaveLength(1);
|
|
171
|
+
const filter = result.filters[0] as PaginationParamFilter;
|
|
172
|
+
|
|
173
|
+
expect(filter.fields).toHaveLength(1);
|
|
174
|
+
expect(filter.fields).toContainEqual(expect.objectContaining({
|
|
175
|
+
field: 'metadata.namespace',
|
|
176
|
+
equality: '!=',
|
|
177
|
+
value: 'p-1',
|
|
178
|
+
}));
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it('should handle selections with only namespaces in a local cluster', () => {
|
|
182
|
+
const nsSelection = ['ns-1', 'ns-2'];
|
|
183
|
+
const result = testNamespaceProjectFilters.handleSelectionFilter(nsSelection, true);
|
|
184
|
+
|
|
185
|
+
expect(result.projectsOrNamespaces).toHaveLength(1);
|
|
186
|
+
const pnsFilter = result.projectsOrNamespaces[0] as PaginationParamProjectOrNamespace;
|
|
187
|
+
|
|
188
|
+
expect(pnsFilter.fields).toHaveLength(2);
|
|
189
|
+
expect(pnsFilter.fields).toContainEqual(expect.objectContaining({ value: 'ns-1' }));
|
|
190
|
+
expect(pnsFilter.fields).toContainEqual(expect.objectContaining({ value: 'ns-2' }));
|
|
191
|
+
expect(result.filters).toStrictEqual([]);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('should handle selections with only projects in a local cluster', () => {
|
|
195
|
+
const projectSelection = [`${ NAMESPACE_FILTER_P_FULL_PREFIX }p-1`, `${ NAMESPACE_FILTER_P_FULL_PREFIX }p-2`];
|
|
196
|
+
const result = testNamespaceProjectFilters.handleSelectionFilter(projectSelection, true);
|
|
197
|
+
|
|
198
|
+
expect(result.projectsOrNamespaces).toHaveLength(1);
|
|
199
|
+
const pnsFilter = result.projectsOrNamespaces[0] as PaginationParamProjectOrNamespace;
|
|
200
|
+
|
|
201
|
+
expect(pnsFilter.fields).toHaveLength(2);
|
|
202
|
+
expect(pnsFilter.fields).toContainEqual(expect.objectContaining({ value: 'p-1' }));
|
|
203
|
+
expect(pnsFilter.fields).toContainEqual(expect.objectContaining({ value: 'p-2' }));
|
|
204
|
+
|
|
205
|
+
expect(result.filters).toHaveLength(2);
|
|
206
|
+
expect(result.filters).toContainEqual(expect.objectContaining({
|
|
207
|
+
fields: [expect.objectContaining({
|
|
208
|
+
field: 'metadata.namespace',
|
|
209
|
+
equality: '!=',
|
|
210
|
+
value: 'p-1'
|
|
211
|
+
})],
|
|
212
|
+
}));
|
|
213
|
+
expect(result.filters).toContainEqual(expect.objectContaining({
|
|
214
|
+
fields: [expect.objectContaining({
|
|
215
|
+
field: 'metadata.namespace',
|
|
216
|
+
equality: '!=',
|
|
217
|
+
value: 'p-2'
|
|
218
|
+
})],
|
|
219
|
+
}));
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
class TestStevePaginationUtils {
|
|
225
|
+
public convertPaginationParams(args: any) {
|
|
226
|
+
return stevePaginationUtils.convertPaginationParams(args);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
describe('class StevePaginationUtils', () => {
|
|
231
|
+
const testStevePaginationUtils = new TestStevePaginationUtils();
|
|
232
|
+
const schema = { id: 'pod' } as unknown as Schema;
|
|
233
|
+
|
|
234
|
+
it('should return an empty string for no filters', () => {
|
|
235
|
+
const result = testStevePaginationUtils.convertPaginationParams({ schema, filters: [] });
|
|
236
|
+
|
|
237
|
+
expect(result).toBe('');
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('should handle a single filter with a single field', () => {
|
|
241
|
+
const filters = [
|
|
242
|
+
new PaginationParamFilter({ fields: [new PaginationFilterField({ field: 'metadata.name', value: 'test' })] }),
|
|
243
|
+
];
|
|
244
|
+
const result = testStevePaginationUtils.convertPaginationParams({ schema, filters });
|
|
245
|
+
|
|
246
|
+
expect(result).toBe('filter=metadata.name=test');
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it('should handle a single filter with a single field with encoded char', () => {
|
|
250
|
+
const filters = [
|
|
251
|
+
new PaginationParamFilter({ fields: [new PaginationFilterField({ field: 'metadata.name', value: 'te/st' })] }),
|
|
252
|
+
];
|
|
253
|
+
const result = testStevePaginationUtils.convertPaginationParams({ schema, filters });
|
|
254
|
+
|
|
255
|
+
expect(result).toBe('filter=metadata.name="te%2Fst"');
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it('should handle a single filter with multiple fields (OR)', () => {
|
|
259
|
+
const filters = [
|
|
260
|
+
new PaginationParamFilter({
|
|
261
|
+
fields: [
|
|
262
|
+
new PaginationFilterField({ field: 'metadata.name', value: 'test1' }),
|
|
263
|
+
new PaginationFilterField({ field: 'metadata.namespace', value: 'ns1' }),
|
|
264
|
+
],
|
|
265
|
+
}),
|
|
266
|
+
];
|
|
267
|
+
const result = testStevePaginationUtils.convertPaginationParams({ schema, filters });
|
|
268
|
+
|
|
269
|
+
expect(result).toBe('filter=metadata.name=test1,metadata.namespace=ns1');
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
it('should handle multiple filters (AND)', () => {
|
|
273
|
+
const filters = [
|
|
274
|
+
new PaginationParamFilter({ fields: [new PaginationFilterField({ field: 'metadata.name', value: 'test1' })] }),
|
|
275
|
+
new PaginationParamFilter({ fields: [new PaginationFilterField({ field: 'metadata.namespace', value: 'ns1' })] }),
|
|
276
|
+
];
|
|
277
|
+
const result = testStevePaginationUtils.convertPaginationParams({ schema, filters });
|
|
278
|
+
|
|
279
|
+
expect(result).toBe('filter=metadata.name=test1&filter=metadata.namespace=ns1');
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
it('should handle different equality operators', () => {
|
|
283
|
+
const filters = [
|
|
284
|
+
new PaginationParamFilter({
|
|
285
|
+
fields: [
|
|
286
|
+
new PaginationFilterField({
|
|
287
|
+
field: 'spec.containers.image',
|
|
288
|
+
value: 'nginx',
|
|
289
|
+
equality: PaginationFilterEquality.CONTAINS,
|
|
290
|
+
}),
|
|
291
|
+
],
|
|
292
|
+
}),
|
|
293
|
+
new PaginationParamFilter({
|
|
294
|
+
fields: [
|
|
295
|
+
new PaginationFilterField({
|
|
296
|
+
field: 'metadata.name',
|
|
297
|
+
value: 'test',
|
|
298
|
+
equality: PaginationFilterEquality.NOT_EQUALS,
|
|
299
|
+
}),
|
|
300
|
+
],
|
|
301
|
+
}),
|
|
302
|
+
];
|
|
303
|
+
const result = testStevePaginationUtils.convertPaginationParams({ schema, filters });
|
|
304
|
+
|
|
305
|
+
expect(result).toBe('filter=spec.containers.image~nginx&filter=metadata.name!=test');
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it('should handle IN and NOT_IN operators', () => {
|
|
309
|
+
const filters = [
|
|
310
|
+
new PaginationParamFilter({
|
|
311
|
+
fields: [
|
|
312
|
+
new PaginationFilterField({
|
|
313
|
+
field: 'metadata.name',
|
|
314
|
+
value: 'test1,test2',
|
|
315
|
+
equality: PaginationFilterEquality.IN,
|
|
316
|
+
}),
|
|
317
|
+
],
|
|
318
|
+
}),
|
|
319
|
+
new PaginationParamFilter({
|
|
320
|
+
fields: [
|
|
321
|
+
new PaginationFilterField({
|
|
322
|
+
field: 'metadata.namespace',
|
|
323
|
+
value: 'ns1,ns2',
|
|
324
|
+
equality: PaginationFilterEquality.NOT_IN,
|
|
325
|
+
}),
|
|
326
|
+
],
|
|
327
|
+
}),
|
|
328
|
+
];
|
|
329
|
+
const result = testStevePaginationUtils.convertPaginationParams({ schema, filters });
|
|
330
|
+
|
|
331
|
+
expect(result).toBe('filter=metadata.name IN (test1,test2)&filter=metadata.namespace NOTIN (ns1,ns2)');
|
|
332
|
+
});
|
|
333
|
+
});
|
|
@@ -47,7 +47,7 @@ export default class SteveModel extends HybridModel {
|
|
|
47
47
|
* Get all model extensions for this model
|
|
48
48
|
*/
|
|
49
49
|
get modelExtensions() {
|
|
50
|
-
return this.$
|
|
50
|
+
return this.$extension.getDynamic(EXT_IDS.MODEL_EXTENSION, this.type) || [];
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
cleanForSave(data, forNew) {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { ActionFindPageArgs } from '@shell/types/store/dashboard-store.types';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
PaginationParam, PaginationFilterField, PaginationParamProjectOrNamespace, PaginationParamFilter, PaginationFilterEquality
|
|
4
|
+
} from '@shell/types/store/pagination.types';
|
|
3
5
|
import { NAMESPACE_FILTER_ALL_SYSTEM, NAMESPACE_FILTER_ALL_USER, NAMESPACE_FILTER_P_FULL_PREFIX } from '@shell/utils/namespace-filter';
|
|
4
6
|
import ModelNamespace from '@shell/models/namespace';
|
|
5
7
|
import { uniq } from '@shell/utils/array';
|
|
@@ -48,7 +50,7 @@ class NamespaceProjectFilters {
|
|
|
48
50
|
|
|
49
51
|
// These are AND'd together
|
|
50
52
|
// Not ns 1 AND ns 2
|
|
51
|
-
|
|
53
|
+
const filterNamespaces = allNamespaces.reduce((res, ns) => {
|
|
52
54
|
// Links to ns.isObscure and covers things like `c-`, `user-`, etc (see OBSCURE_NAMESPACE_PREFIX)
|
|
53
55
|
const hideObscure = showReservedRancherNamespaces ? false : ns.isObscure;
|
|
54
56
|
|
|
@@ -56,13 +58,23 @@ class NamespaceProjectFilters {
|
|
|
56
58
|
const hideSystem = productHidesSystemNamespaces ? ns.isSystem : false;
|
|
57
59
|
|
|
58
60
|
if (hideObscure || hideSystem) {
|
|
59
|
-
res.push(
|
|
60
|
-
field: 'metadata.namespace', value: ns.name, equals: false
|
|
61
|
-
}));
|
|
61
|
+
res.push(ns.name);
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
return res;
|
|
65
|
-
}, [] as
|
|
65
|
+
}, [] as String[]);
|
|
66
|
+
|
|
67
|
+
if (filterNamespaces.length) {
|
|
68
|
+
return [new PaginationParamFilter({
|
|
69
|
+
fields: [{
|
|
70
|
+
value: filterNamespaces.join(','),
|
|
71
|
+
equality: PaginationFilterEquality.NOT_IN,
|
|
72
|
+
field: 'metadata.namespace',
|
|
73
|
+
}],
|
|
74
|
+
})];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return [];
|
|
66
78
|
}
|
|
67
79
|
|
|
68
80
|
/**
|
|
@@ -502,29 +514,36 @@ class StevePaginationUtils extends NamespaceProjectFilters {
|
|
|
502
514
|
// Check if the API supports filtering by this field
|
|
503
515
|
this.validateField(validateFields, schema, field.field);
|
|
504
516
|
|
|
505
|
-
// we're just checking that the field exists, so there's no value
|
|
517
|
+
// we're just checking that the field exists, so there's no equality or value
|
|
506
518
|
if (field.exists) {
|
|
507
519
|
return field.field;
|
|
508
520
|
}
|
|
509
|
-
const encodedValue = encodeURIComponent(field.value || '');
|
|
510
521
|
|
|
511
|
-
//
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
522
|
+
// If field was created by PaginationFilterField ctor equality will be set. If field created by json (legacy) it might not
|
|
523
|
+
const equality = field.equality || PaginationFilterField.safeEquality(field);
|
|
524
|
+
|
|
525
|
+
if (!equality) {
|
|
526
|
+
throw new Error(`A pagination filter must contain an equality. ${ JSON.stringify(field) }`);
|
|
527
|
+
}
|
|
528
|
+
|
|
516
529
|
let safeValue;
|
|
517
530
|
|
|
518
|
-
if (
|
|
519
|
-
|
|
520
|
-
safeValue = encodedValue;
|
|
531
|
+
if ([PaginationFilterEquality.IN, PaginationFilterEquality.NOT_IN].includes(equality)) {
|
|
532
|
+
safeValue = `(${ field.value })`;
|
|
521
533
|
} else {
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
534
|
+
const encodedValue = encodeURIComponent(field.value || '');
|
|
535
|
+
|
|
536
|
+
if (StevePaginationUtils.VALID_FIELD_VALUE_REGEX.test(field.value || '')) {
|
|
537
|
+
// Does not contain any protected characters, send as is
|
|
538
|
+
safeValue = encodedValue;
|
|
539
|
+
} else {
|
|
540
|
+
// Contains protected characters, wrap in quotes to ensure backend doesn't fail
|
|
541
|
+
// - replace reserver `"`/`%22` with empty string - see https://github.com/rancher/dashboard/issues/14549 for improvement
|
|
542
|
+
safeValue = `"${ encodedValue.replaceAll('%22', '') }"`;
|
|
543
|
+
}
|
|
525
544
|
}
|
|
526
545
|
|
|
527
|
-
return `${ this.convertArrayPath(field.field) }${
|
|
546
|
+
return `${ this.convertArrayPath(field.field) }${ equality }${ safeValue }`;
|
|
528
547
|
}
|
|
529
548
|
|
|
530
549
|
return field.value;
|
|
@@ -888,16 +888,20 @@ const defaultActions = {
|
|
|
888
888
|
}
|
|
889
889
|
});
|
|
890
890
|
}
|
|
891
|
-
|
|
892
891
|
// Should any listeners be notified of this request for them to kick off their own event handling?
|
|
893
|
-
getters.listenerManager.triggerEventListener({
|
|
892
|
+
getters.listenerManager.triggerEventListener({
|
|
893
|
+
event: STEVE_WATCH_MODE.RESOURCE_CHANGES,
|
|
894
|
+
params: {
|
|
895
|
+
...params,
|
|
896
|
+
forceWatch: opt.forceWatch
|
|
897
|
+
}
|
|
898
|
+
});
|
|
894
899
|
} else {
|
|
895
900
|
have = getters['all'](resourceType).slice();
|
|
896
901
|
|
|
897
902
|
if ( namespace ) {
|
|
898
903
|
have = have.filter((x) => x.metadata?.namespace === namespace);
|
|
899
904
|
}
|
|
900
|
-
|
|
901
905
|
want = await dispatch('findAll', {
|
|
902
906
|
type: resourceType,
|
|
903
907
|
watchNamespace: namespace,
|
|
@@ -1181,12 +1185,16 @@ const defaultActions = {
|
|
|
1181
1185
|
});
|
|
1182
1186
|
|
|
1183
1187
|
if (hasEventListeners) {
|
|
1184
|
-
//
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1188
|
+
const inError = getters.inError(obj); // We don't want to force listeners to resync if the socket is in error (handled by resource.error mechanism)
|
|
1189
|
+
|
|
1190
|
+
if (!inError) {
|
|
1191
|
+
// If there's event listeners kick them off
|
|
1192
|
+
// - The re-watch associated with normal watches will watch from a revision from it's own cache
|
|
1193
|
+
// - The revision in that cache might be ahead of the state the listeners have, so the watch won't ping something for the listeners to trigger on
|
|
1194
|
+
// - so to work around this whenever we start the watches again trigger off the changes for it
|
|
1195
|
+
// Improvement - we only do one event here (currently the only one supported), could expand to others
|
|
1196
|
+
getters.listenerManager.triggerEventListener({ event: STEVE_WATCH_EVENT_TYPES.CHANGES, params: obj });
|
|
1197
|
+
}
|
|
1190
1198
|
}
|
|
1191
1199
|
}
|
|
1192
1200
|
},
|
|
@@ -167,7 +167,7 @@ export class SteveWatchEventListenerManager {
|
|
|
167
167
|
|
|
168
168
|
if (eventWatcher) {
|
|
169
169
|
Object.values(eventWatcher.callbacks).forEach((cb) => {
|
|
170
|
-
cb();
|
|
170
|
+
cb({ forceWatch: params.forceWatch }); // eslint-disable-line node/no-callback-literal
|
|
171
171
|
});
|
|
172
172
|
}
|
|
173
173
|
}
|
|
@@ -176,7 +176,9 @@ export class SteveWatchEventListenerManager {
|
|
|
176
176
|
const watch = this.getWatch({ params });
|
|
177
177
|
|
|
178
178
|
watch.listeners.forEach((l) => {
|
|
179
|
-
Object.values(l.callbacks || {}).forEach((cb) =>
|
|
179
|
+
Object.values(l.callbacks || {}).forEach((cb) => {
|
|
180
|
+
cb({ forceWatch: params.forceWatch });// eslint-disable-line node/no-callback-literal
|
|
181
|
+
});
|
|
180
182
|
});
|
|
181
183
|
}
|
|
182
184
|
|