@rancher/shell 3.0.12-rc.1 → 3.0.12-rc.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apis/impl/apis.ts +6 -0
- package/apis/index.ts +26 -0
- package/apis/intf/resources-api/cluster-api.ts +18 -0
- package/apis/intf/resources-api/mgmt-api.ts +15 -0
- package/apis/intf/resources-api/resource-base.ts +107 -0
- package/apis/intf/resources-api/resource-constants.ts +147 -0
- package/apis/intf/resources-api/resources-api.ts +143 -0
- package/apis/intf/resources.ts +49 -0
- package/apis/intf/{modal.ts → shell-api/modal.ts} +21 -26
- package/apis/intf/shell-api/proxy.ts +216 -0
- package/apis/intf/{slide-in.ts → shell-api/slide-in.ts} +4 -3
- package/apis/intf/{system.ts → shell-api/system.ts} +4 -1
- package/apis/intf/shell.ts +12 -6
- package/apis/resources/__tests__/resources-api-class.test.ts +550 -0
- package/apis/resources/index.ts +22 -0
- package/apis/resources/resources-api-class.ts +187 -0
- package/apis/shell/__tests__/proxy.test.ts +369 -0
- package/apis/shell/index.ts +8 -1
- package/apis/shell/modal.ts +4 -1
- package/apis/shell/notifications.ts +9 -6
- package/apis/shell/proxy.ts +256 -0
- package/apis/shell/slide-in.ts +4 -1
- package/apis/vue-shim.d.ts +2 -1
- package/assets/data/aws-regions.json +4 -0
- package/assets/fonts/lato/LatoLatin-Black.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Black.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-BlackItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-BlackItalic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Bold.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Bold.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-BoldItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-BoldItalic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Heavy.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Heavy.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-HeavyItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-HeavyItalic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Italic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Italic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Light.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Light.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-LightItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-LightItalic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Medium.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Medium.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-MediumItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-MediumItalic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Regular.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Regular.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Semibold.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Semibold.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-SemiboldItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-SemiboldItalic.woff2 +0 -0
- package/assets/images/providers/entraid-black.svg +4 -0
- package/assets/images/providers/entraid.svg +9 -0
- package/assets/images/vendor/entraid.svg +9 -0
- package/assets/styles/app.scss +0 -1
- package/assets/styles/base/_variables.scss +2 -0
- package/assets/styles/fonts/_fontstack.scss +132 -8
- package/assets/translations/en-us.yaml +41 -22
- package/assets/translations/zh-hans.yaml +4 -8
- package/chart/__tests__/S3.test.ts +10 -3
- package/chart/monitoring/index.vue +10 -1
- package/components/ActionDropdownShell.vue +2 -1
- package/components/CountBox.vue +20 -0
- package/components/CreateDriver.vue +0 -12
- package/components/CruResourceFooter.vue +9 -5
- package/components/DetailText.vue +12 -3
- package/components/ExplorerProjectsNamespaces.vue +1 -1
- package/components/InstallHelmCharts.vue +2 -2
- package/components/LandingPagePreference.vue +14 -5
- package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +15 -1
- package/components/Resource/Detail/Metadata/index.vue +6 -0
- package/components/Resource/Detail/ResourcePopover/index.vue +12 -1
- package/components/Resource/Detail/SpacedRow.vue +3 -1
- package/components/Resource/Detail/TitleBar/index.vue +10 -11
- package/components/ResourceList/Masthead.vue +12 -8
- package/components/SelectIconGrid.vue +5 -10
- package/components/SingleClusterInfo.vue +1 -0
- package/components/SortableTable/__tests__/sorting.test.ts +126 -0
- package/components/SortableTable/index.vue +6 -9
- package/components/SortableTable/selection.js +23 -5
- package/components/SortableTable/sorting.js +6 -3
- package/components/Wizard.vue +14 -13
- package/components/__tests__/CountBox.test.ts +72 -0
- package/components/__tests__/DetailText.test.ts +113 -0
- package/components/fleet/FleetBundles.vue +100 -12
- package/components/fleet/FleetClusterTargets/index.vue +54 -15
- package/components/fleet/__tests__/FleetClusterTargets.test.ts +149 -115
- package/components/fleet/__tests__/FleetClusters.test.ts +12 -12
- package/components/form/InputWithSelect.vue +18 -10
- package/components/form/KeyValue.vue +17 -1
- package/components/form/LabeledSelect.vue +101 -26
- package/components/form/NameNsDescription.vue +11 -0
- package/components/form/Security.vue +6 -2
- package/components/form/Select.vue +73 -56
- package/components/form/ServiceNameSelect.vue +13 -11
- package/components/form/WorkloadPorts.vue +2 -7
- package/components/form/__tests__/KeyValue.test.ts +66 -0
- package/components/form/__tests__/NodeScheduling.test.ts +9 -0
- package/components/form/__tests__/Security.test.ts +76 -0
- package/components/form/labeled-select-utils/useLabeledSelectPagination.ts +138 -0
- package/components/formatter/Autoscaler.vue +4 -4
- package/components/formatter/ClusterKubeVersion.vue +27 -0
- package/components/formatter/ClusterLink.vue +1 -7
- package/components/formatter/ClusterProvider.vue +6 -10
- package/components/formatter/FleetSummaryGraph.vue +0 -3
- package/components/formatter/MachineSummaryGraph.vue +1 -1
- package/components/formatter/PodsUsage.vue +2 -2
- package/components/formatter/__tests__/Autoscaler.test.ts +19 -22
- package/components/formatter/__tests__/FleetSummaryGraph.test.ts +216 -0
- package/components/formatter/__tests__/PodsUsage.test.ts +6 -10
- package/components/nav/Group.vue +7 -6
- package/components/nav/Header.vue +24 -3
- package/components/nav/NamespaceFilter.vue +2 -2
- package/components/nav/NotificationCenter/Notification.vue +4 -1
- package/components/nav/NotificationCenter/NotificationHeader.vue +20 -8
- package/components/nav/NotificationCenter/__tests__/NotificationHeader.test.ts +80 -0
- package/components/nav/TopLevelMenu.helper.ts +15 -3
- package/components/nav/TopLevelMenu.vue +16 -5
- package/components/nav/Type.vue +8 -7
- package/components/nav/WindowManager/index.vue +2 -1
- package/components/nav/WorkspaceSwitcher.vue +13 -0
- package/components/nav/__tests__/Group.test.ts +67 -0
- package/components/nav/__tests__/Header.test.ts +235 -0
- package/components/nav/__tests__/TopLevelMenu.test.ts +145 -21
- package/components/nav/__tests__/Type.test.ts +20 -3
- package/components/templates/default.vue +34 -4
- package/components/templates/home.vue +30 -25
- package/components/templates/plain.vue +31 -26
- package/components/templates/standalone.vue +17 -0
- package/composables/useFormValidation.ts +93 -0
- package/composables/useLabeledFormElement.ts +10 -2
- package/composables/useLabeledSelect.ts +60 -0
- package/composables/useUserRetentionValidation.ts +1 -49
- package/composables/useVeeValidateField.test.ts +159 -0
- package/composables/useVeeValidateField.ts +67 -0
- package/config/cookies.js +0 -1
- package/config/labels-annotations.js +1 -0
- package/config/pagination-table-headers.js +18 -1
- package/config/product/manager.js +82 -21
- package/config/query-params.js +1 -0
- package/config/router/routes.js +6 -8
- package/config/table-headers.js +20 -1
- package/config/types.js +2 -1
- package/core/__tests__/plugin-products.test.ts +1505 -30
- package/core/plugin-products-base.ts +137 -20
- package/core/plugin-products-helpers.ts +5 -4
- package/core/plugin-products.ts +4 -0
- package/core/plugin-types.ts +129 -4
- package/core/plugin.ts +15 -7
- package/core/productDebugger.js +9 -4
- package/core/types-provisioning.ts +43 -30
- package/core/types.ts +58 -19
- package/detail/__tests__/management.cattle.io.fleetworkspace.test.ts +128 -0
- package/detail/__tests__/pod.test.ts +41 -0
- package/detail/harvesterhci.io.management.cluster.vue +6 -2
- package/detail/management.cattle.io.fleetworkspace.vue +49 -0
- package/detail/pod.vue +1 -1
- package/detail/provisioning.cattle.io.cluster.vue +4 -10
- package/edit/__tests__/fleet.cattle.io.helmop.test.ts +9 -0
- package/edit/__tests__/kontainerDriver.test.ts +0 -13
- package/edit/__tests__/nodeDriver.test.ts +5 -11
- package/edit/__tests__/resources.cattle.io.restore.test.ts +9 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/General.test.ts.snap +6 -0
- package/edit/auth/__tests__/azuread.test.ts +217 -34
- package/edit/auth/__tests__/oidc.test.ts +54 -0
- package/edit/auth/azuread.vue +123 -15
- package/edit/auth/oidc.vue +10 -2
- package/edit/kontainerDriver.vue +1 -2
- package/edit/networking.k8s.io.ingress/DefaultBackend.vue +13 -4
- package/edit/networking.k8s.io.ingress/RulePath.vue +8 -4
- package/edit/networking.k8s.io.ingress/index.vue +75 -20
- package/edit/nodeDriver.vue +0 -2
- package/edit/provisioning.cattle.io.cluster/AgentEnv.vue +1 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/AgentEnv.test.ts +25 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/MachinePool.test.ts +104 -0
- package/edit/provisioning.cattle.io.cluster/index.vue +81 -106
- package/edit/provisioning.cattle.io.cluster/rke2.vue +8 -4
- package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +11 -0
- package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs.vue +37 -4
- package/edit/provisioning.cattle.io.cluster/tabs/registries/__tests__/RegistryConfigs.test.ts +132 -7
- package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +2 -1
- package/edit/secret/__tests__/ssh.test.ts +5 -6
- package/edit/secret/basic.vue +31 -0
- package/edit/secret/index.vue +68 -17
- package/edit/secret/registry.vue +38 -0
- package/edit/secret/ssh.vue +29 -0
- package/edit/secret/tls.vue +30 -0
- package/edit/service.vue +4 -4
- package/edit/workload/Upgrading.vue +3 -3
- package/edit/workload/__tests__/Upgrading.test.ts +6 -9
- package/edit/workload/mixins/workload.js +2 -1
- package/initialize/App.vue +29 -2
- package/initialize/install-plugins.js +0 -2
- package/list/__tests__/management.cattle.io.feature.test.ts +105 -0
- package/list/catalog.cattle.io.app.vue +25 -5
- package/list/fleet.cattle.io.bundle.vue +7 -104
- package/list/fleet.cattle.io.clusterregistrationtoken.vue +20 -0
- package/list/management.cattle.io.feature.vue +1 -1
- package/list/management.cattle.io.fleetworkspace.vue +8 -0
- package/list/provisioning.cattle.io.cluster.vue +262 -180
- package/list/utils/management.cattle.io.cluster.utils.ts +128 -0
- package/machine-config/amazonec2.vue +1 -0
- package/mixins/__tests__/chart.test.ts +112 -0
- package/mixins/brand.js +2 -1
- package/mixins/chart.js +50 -15
- package/mixins/resource-fetch-api-pagination.js +41 -5
- package/models/__tests__/catalog.cattle.io.app.test.ts +15 -1
- package/models/__tests__/catalog.cattle.io.clusterrepo.test.ts +84 -0
- package/models/__tests__/chart.test.ts +99 -6
- package/models/__tests__/ext.cattle.io.kubeconfig.test.ts +67 -67
- package/models/__tests__/management.cattle.io.cluster.test.ts +1 -1
- package/models/__tests__/management.cattle.io.feature.test.ts +131 -0
- package/models/__tests__/management.cattle.io.node.ts +6 -5
- package/models/__tests__/management.cattle.io.nodepool.ts +5 -4
- package/models/__tests__/monitoring.coreos.com.alertmanagerconfig.test.ts +98 -0
- package/models/__tests__/provisioning.cattle.io.cluster.test.ts +32 -11
- package/models/base-cluster.x-k8s.io.js +26 -0
- package/models/catalog.cattle.io.app.js +21 -17
- package/models/catalog.cattle.io.clusterrepo.js +39 -11
- package/models/chart.js +33 -19
- package/models/cluster.js +1 -1
- package/models/cluster.x-k8s.io.machine.js +4 -22
- package/models/cluster.x-k8s.io.machinedeployment.js +2 -20
- package/models/cluster.x-k8s.io.machineset.js +2 -20
- package/models/compliance.cattle.io.clusterscan.js +130 -2
- package/models/ext.cattle.io.kubeconfig.ts +4 -7
- package/models/fleet-application.js +4 -2
- package/models/fleet.cattle.io.bundle.js +1 -1
- package/models/kontainerdriver.js +11 -0
- package/models/management.cattle.io.authconfig.js +5 -1
- package/models/management.cattle.io.cluster.js +402 -78
- package/models/management.cattle.io.feature.js +3 -3
- package/models/management.cattle.io.kontainerdriver.js +1 -26
- package/models/management.cattle.io.node.js +6 -4
- package/models/management.cattle.io.nodepool.js +1 -1
- package/models/monitoring.coreos.com.alertmanagerconfig.js +31 -17
- package/models/networking.k8s.io.ingress.js +12 -4
- package/models/nodedriver.js +7 -0
- package/models/provisioning.cattle.io.cluster.js +47 -330
- package/models/rke.cattle.io.etcdsnapshot.js +1 -2
- package/package.json +20 -37
- package/pages/__tests__/readme.test.ts +49 -0
- package/pages/auth/setup.vue +2 -3
- package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +265 -0
- package/pages/c/_cluster/apps/charts/__tests__/index.test.ts +55 -0
- package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +53 -0
- package/pages/c/_cluster/apps/charts/chart.vue +275 -39
- package/pages/c/_cluster/apps/charts/index.vue +2 -2
- package/pages/c/_cluster/apps/charts/install.vue +18 -10
- package/pages/c/_cluster/auth/user.retention/index.vue +55 -22
- package/pages/c/_cluster/explorer/__tests__/index.test.ts +23 -25
- package/pages/c/_cluster/explorer/index.vue +5 -49
- package/pages/c/_cluster/istio/__tests__/istio.index.test.ts +194 -0
- package/pages/c/_cluster/istio/index.vue +21 -6
- package/pages/c/_cluster/manager/drivers/kontainerDriver/index.vue +5 -7
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +40 -2
- package/pages/c/_cluster/uiplugins/__tests__/PluginInfoPanel.test.ts +61 -0
- package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +735 -13
- package/pages/c/_cluster/uiplugins/index.vue +226 -222
- package/pages/diagnostic.vue +13 -17
- package/pages/fail-whale.vue +18 -0
- package/pages/home.vue +77 -260
- package/pages/readme.vue +88 -0
- package/plugins/dashboard-store/__tests__/resource-class.test.ts +88 -0
- package/plugins/dashboard-store/actions.js +40 -18
- package/plugins/dashboard-store/resource-class.js +5 -2
- package/plugins/steve/__tests__/subscribe.spec.ts +6 -3
- package/plugins/steve/steve-pagination-utils.ts +11 -3
- package/plugins/steve/subscribe.js +35 -5
- package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +211 -1
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +37 -4
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +1 -1
- package/rancher-components/RcButton/RcButton.test.ts +37 -1
- package/rancher-components/RcButton/RcButton.vue +38 -8
- package/rancher-components/RcDropdown/RcDropdownTrigger.vue +10 -8
- package/scripts/test-plugins-build.sh +5 -2
- package/server/server-middleware.js +2 -2
- package/static/humans.txt +1 -0
- package/static/robots.txt +34 -0
- package/static/welcome-cow.svg +18 -0
- package/store/__tests__/catalog.test.ts +276 -12
- package/store/__tests__/type-map.test.ts +556 -1
- package/store/action-menu.js +8 -3
- package/store/auth.js +1 -4
- package/store/aws.js +27 -16
- package/store/catalog.js +87 -11
- package/store/digitalocean.js +20 -38
- package/store/index.js +2 -0
- package/store/linode.js +25 -40
- package/store/pnap.js +1 -0
- package/store/type-map.js +111 -29
- package/tsconfig.paths.json +8 -8
- package/types/kube/kube-api.ts +14 -1
- package/types/rancher/steve.api.ts +12 -12
- package/types/resources/settings.d.ts +2 -1
- package/types/shell/index.d.ts +128 -24
- package/types/store/dashboard-store.types.ts +108 -11
- package/types/store/pagination.types.ts +6 -3
- package/utils/__tests__/alertmanagerconfig.test.ts +117 -0
- package/utils/__tests__/async.test.ts +87 -0
- package/utils/__tests__/aws.test.ts +140 -0
- package/utils/__tests__/banners.test.ts +176 -0
- package/utils/__tests__/chart.test.ts +64 -1
- package/utils/__tests__/color.test.ts +226 -0
- package/utils/__tests__/duration.test.ts +140 -0
- package/utils/__tests__/fleet.test.ts +340 -0
- package/utils/__tests__/git.test.ts +270 -0
- package/utils/__tests__/inactivity.test.ts +316 -0
- package/utils/__tests__/ingress.test.ts +553 -0
- package/utils/__tests__/kube.test.ts +68 -0
- package/utils/__tests__/namespace-filter.test.ts +109 -0
- package/utils/__tests__/object.test.ts +77 -0
- package/utils/__tests__/pagination-utils.test.ts +361 -0
- package/utils/__tests__/parse-externalid.test.ts +137 -0
- package/utils/__tests__/perf-setting.utils.test.ts +98 -0
- package/utils/__tests__/poller-sequential.test.ts +177 -0
- package/utils/__tests__/poller.test.ts +170 -0
- package/utils/__tests__/promise.test.ts +346 -0
- package/utils/__tests__/settings.test.ts +140 -0
- package/utils/__tests__/sort-utils.test.ts +301 -0
- package/utils/__tests__/string-utils.test.ts +798 -0
- package/utils/__tests__/string.test.ts +23 -1
- package/utils/__tests__/style.test.ts +154 -0
- package/utils/__tests__/svg-filter.test.ts +184 -0
- package/utils/__tests__/time.test.ts +14 -1
- package/utils/__tests__/units.test.ts +417 -0
- package/utils/__tests__/url.test.ts +246 -0
- package/utils/__tests__/versions.test.ts +128 -0
- package/utils/__tests__/xccdf.test.ts +391 -0
- package/utils/chart.js +36 -0
- package/utils/fleet.ts +13 -3
- package/utils/gatekeeper/__tests__/util.test.ts +174 -0
- package/utils/gc/__tests__/gc-interval.test.ts +119 -0
- package/utils/gc/__tests__/gc-root-store.test.ts +225 -0
- package/utils/gc/__tests__/gc-route-changed.test.ts +96 -0
- package/utils/gc/__tests__/gc.test.ts +487 -0
- package/utils/ingress.ts +9 -1
- package/utils/object.js +33 -2
- package/utils/pagination-utils.ts +2 -1
- package/utils/string.js +25 -2
- package/utils/time.ts +5 -0
- package/utils/uiplugins.ts +5 -5
- package/utils/validators/__tests__/cluster-name.test.ts +110 -0
- package/utils/validators/__tests__/cron-schedule.test.ts +79 -0
- package/utils/validators/__tests__/index.test.ts +481 -0
- package/utils/validators/__tests__/kubernetes-name.test.ts +163 -0
- package/utils/validators/__tests__/misc-validators.test.ts +246 -0
- package/utils/validators/__tests__/pod-affinity.test.ts +382 -0
- package/utils/validators/__tests__/prometheusrule.test.ts +211 -0
- package/utils/validators/__tests__/role-template.test.ts +149 -0
- package/utils/validators/__tests__/service.test.ts +283 -0
- package/utils/validators/__tests__/setting.test.js +32 -0
- package/utils/validators/formRules/__tests__/index.test.ts +50 -0
- package/utils/validators/formRules/index.ts +5 -5
- package/utils/validators/machine-pool.ts +1 -1
- package/utils/validators/setting.js +18 -3
- package/utils/xccdf.ts +418 -0
- package/vue.config.js +0 -9
- package/assets/fonts/lato/lato-v17-latin-700.woff +0 -0
- package/assets/fonts/lato/lato-v17-latin-700.woff2 +0 -0
- package/assets/fonts/lato/lato-v17-latin-regular.woff +0 -0
- package/assets/fonts/lato/lato-v17-latin-regular.woff2 +0 -0
- package/assets/images/providers/azuread-black.svg +0 -22
- package/assets/images/providers/azuread.svg +0 -25
- package/assets/images/vendor/azuread.svg +0 -18
- package/assets/styles/fonts/_dots.scss +0 -18
- package/components/EmberPage.vue +0 -622
- package/components/EmberPageView.vue +0 -39
- package/components/form/labeled-select-utils/labeled-select-pagination.ts +0 -116
- package/mixins/labeled-form-element.ts +0 -225
- package/pages/c/_cluster/explorer/tools/pages/_page.vue +0 -28
- package/pages/c/_cluster/manager/pages/_page.vue +0 -22
- package/pages/c/_cluster/mcapps/pages/_page.vue +0 -22
- package/plugins/ember-cookie.js +0 -17
- package/utils/ember-page.js +0 -30
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import {
|
|
2
|
+
NAMESPACE_FILTER_ALL_PREFIX,
|
|
3
|
+
NAMESPACE_FILTER_NS_PREFIX,
|
|
4
|
+
NAMESPACE_FILTER_P_PREFIX,
|
|
5
|
+
NAMESPACE_FILTER_NS_FULL_PREFIX,
|
|
6
|
+
NAMESPACE_FILTER_P_FULL_PREFIX,
|
|
7
|
+
NAMESPACE_FILTER_ALL,
|
|
8
|
+
NAMESPACE_FILTER_ALL_SYSTEM,
|
|
9
|
+
NAMESPACE_FILTER_ALL_USER,
|
|
10
|
+
NAMESPACE_FILTER_ALL_ORPHANS,
|
|
11
|
+
NAMESPACE_FILTER_NAMESPACED_PREFIX,
|
|
12
|
+
NAMESPACE_FILTER_NAMESPACED_YES,
|
|
13
|
+
NAMESPACE_FILTER_NAMESPACED_NO,
|
|
14
|
+
NAMESPACE_FILTER_KINDS,
|
|
15
|
+
createNamespaceFilterKey,
|
|
16
|
+
createNamespaceFilterKeyWithId,
|
|
17
|
+
splitNamespaceFilterKey,
|
|
18
|
+
} from '@shell/utils/namespace-filter';
|
|
19
|
+
|
|
20
|
+
describe('namespace-filter constants', () => {
|
|
21
|
+
it('prefix constants have expected values', () => {
|
|
22
|
+
expect(NAMESPACE_FILTER_ALL_PREFIX).toStrictEqual('all');
|
|
23
|
+
expect(NAMESPACE_FILTER_NS_PREFIX).toStrictEqual('ns');
|
|
24
|
+
expect(NAMESPACE_FILTER_P_PREFIX).toStrictEqual('project');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('full prefix constants are built from base prefixes', () => {
|
|
28
|
+
expect(NAMESPACE_FILTER_NS_FULL_PREFIX).toStrictEqual('ns://');
|
|
29
|
+
expect(NAMESPACE_FILTER_P_FULL_PREFIX).toStrictEqual('project://');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('all-namespace filter constants have expected values', () => {
|
|
33
|
+
expect(NAMESPACE_FILTER_ALL).toStrictEqual('all');
|
|
34
|
+
expect(NAMESPACE_FILTER_ALL_SYSTEM).toStrictEqual('all://system');
|
|
35
|
+
expect(NAMESPACE_FILTER_ALL_USER).toStrictEqual('all://user');
|
|
36
|
+
expect(NAMESPACE_FILTER_ALL_ORPHANS).toStrictEqual('all://orphans');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('namespaced filter constants have expected values', () => {
|
|
40
|
+
expect(NAMESPACE_FILTER_NAMESPACED_PREFIX).toStrictEqual('namespaced://');
|
|
41
|
+
expect(NAMESPACE_FILTER_NAMESPACED_YES).toStrictEqual('namespaced://true');
|
|
42
|
+
expect(NAMESPACE_FILTER_NAMESPACED_NO).toStrictEqual('namespaced://false');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('nAMESPACE_FILTER_KINDS has expected shape', () => {
|
|
46
|
+
expect(NAMESPACE_FILTER_KINDS).toStrictEqual({
|
|
47
|
+
DIVIDER: 'divider',
|
|
48
|
+
PROJECT: 'project',
|
|
49
|
+
NAMESPACE: 'namespace',
|
|
50
|
+
SPECIAL: 'special',
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('createNamespaceFilterKey', () => {
|
|
56
|
+
it('returns clusterId when product is undefined', () => {
|
|
57
|
+
expect(createNamespaceFilterKey('c-abc', undefined)).toStrictEqual('c-abc');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('returns clusterId when product has no customNamespaceFilter', () => {
|
|
61
|
+
expect(createNamespaceFilterKey('c-abc', { name: 'manager' })).toStrictEqual('c-abc');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('returns clusterId when product.customNamespaceFilter is falsy', () => {
|
|
65
|
+
expect(createNamespaceFilterKey('c-abc', { name: 'manager', customNamespaceFilter: false })).toStrictEqual('c-abc');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('returns compound key when product has customNamespaceFilter', () => {
|
|
69
|
+
const result = createNamespaceFilterKey('c-abc', { name: 'myProduct', customNamespaceFilter: true });
|
|
70
|
+
|
|
71
|
+
expect(result).toStrictEqual('c-abc__%%__myProduct');
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe('createNamespaceFilterKeyWithId', () => {
|
|
76
|
+
it('combines clusterId and productId with separator', () => {
|
|
77
|
+
expect(createNamespaceFilterKeyWithId('c-abc', 'myProduct')).toStrictEqual('c-abc__%%__myProduct');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('works with empty strings', () => {
|
|
81
|
+
expect(createNamespaceFilterKeyWithId('', '')).toStrictEqual('__%%__');
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
describe('splitNamespaceFilterKey', () => {
|
|
86
|
+
it('splits a compound key into clusterId and productId', () => {
|
|
87
|
+
expect(splitNamespaceFilterKey('c-abc__%%__myProduct')).toStrictEqual({
|
|
88
|
+
clusterId: 'c-abc',
|
|
89
|
+
productId: 'myProduct',
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('returns undefined productId when key has no separator', () => {
|
|
94
|
+
expect(splitNamespaceFilterKey('c-abc')).toStrictEqual({
|
|
95
|
+
clusterId: 'c-abc',
|
|
96
|
+
productId: undefined,
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('round-trips with createNamespaceFilterKeyWithId', () => {
|
|
101
|
+
const key = createNamespaceFilterKeyWithId('cluster-1', 'product-a');
|
|
102
|
+
const result = splitNamespaceFilterKey(key);
|
|
103
|
+
|
|
104
|
+
expect(result).toStrictEqual({
|
|
105
|
+
clusterId: 'cluster-1',
|
|
106
|
+
productId: 'product-a',
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
});
|
|
@@ -210,6 +210,83 @@ describe('fx: diff', () => {
|
|
|
210
210
|
|
|
211
211
|
expect(result).toStrictEqual(expected);
|
|
212
212
|
});
|
|
213
|
+
it('should preserve nested object values when transitioning from empty object to populated object', () => {
|
|
214
|
+
const from = { parent: { child: { config: {} } } };
|
|
215
|
+
const to = {
|
|
216
|
+
parent: {
|
|
217
|
+
child: {
|
|
218
|
+
config: {
|
|
219
|
+
annotations: { hello: 'world' },
|
|
220
|
+
labels: { key: 'value' }
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
const result = diff(from, to);
|
|
227
|
+
const expected = {
|
|
228
|
+
parent: {
|
|
229
|
+
child: {
|
|
230
|
+
config: {
|
|
231
|
+
annotations: { hello: 'world' },
|
|
232
|
+
labels: { key: 'value' }
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
expect(result).toStrictEqual(expected);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('should preserve explicit empty object when clearing nested object values', () => {
|
|
242
|
+
const from = { parent: { child: { config: { annotations: { hello: 'world' } } } } };
|
|
243
|
+
const to = { parent: { child: { config: {} } } };
|
|
244
|
+
|
|
245
|
+
const result = diff(from, to);
|
|
246
|
+
const expected = { parent: { child: { config: {} } } };
|
|
247
|
+
|
|
248
|
+
expect(result).toStrictEqual(expected);
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it('should not emit nested empty objects when there are no differences', () => {
|
|
252
|
+
const from = { parent: { child: { config: { annotations: { hello: 'world' } } } } };
|
|
253
|
+
const to = { parent: { child: { config: { annotations: { hello: 'world' } } } } };
|
|
254
|
+
|
|
255
|
+
const result = diff(from, to);
|
|
256
|
+
const expected = {};
|
|
257
|
+
|
|
258
|
+
expect(result).toStrictEqual(expected);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it('should correctly nullify nested keys when removed', () => {
|
|
262
|
+
const from = {
|
|
263
|
+
parent: {
|
|
264
|
+
child: {
|
|
265
|
+
config: {
|
|
266
|
+
annotations: { hello: 'world' },
|
|
267
|
+
labels: { key: 'value' }
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
const to = { parent: { child: { config: { annotations: { hello: 'world' } } } } };
|
|
273
|
+
|
|
274
|
+
const result = diff(from, to);
|
|
275
|
+
const expected = { parent: { child: { config: { labels: { key: null } } } } };
|
|
276
|
+
|
|
277
|
+
expect(result).toStrictEqual(expected);
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
it('should not nullify child keys when parent object is updated', () => {
|
|
281
|
+
const from = { parent: { child: { config: {} } } };
|
|
282
|
+
const to = { parent: { child: { config: { annotations: { hello: 'world' } } } } };
|
|
283
|
+
|
|
284
|
+
const result = diff(from, to);
|
|
285
|
+
const expected = { parent: { child: { config: { annotations: { hello: 'world' } } } } };
|
|
286
|
+
|
|
287
|
+
expect(result).toStrictEqual(expected);
|
|
288
|
+
expect(result.parent.child.config).not.toHaveProperty('annotations', null);
|
|
289
|
+
});
|
|
213
290
|
});
|
|
214
291
|
|
|
215
292
|
describe('fx: definedKeys', () => {
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
import paginationUtils from '@shell/utils/pagination-utils';
|
|
2
|
+
import {
|
|
3
|
+
NAMESPACE_FILTER_ALL_USER,
|
|
4
|
+
NAMESPACE_FILTER_ALL,
|
|
5
|
+
NAMESPACE_FILTER_ALL_SYSTEM,
|
|
6
|
+
NAMESPACE_FILTER_NAMESPACED_YES,
|
|
7
|
+
NAMESPACE_FILTER_NAMESPACED_NO,
|
|
8
|
+
NAMESPACE_FILTER_KINDS,
|
|
9
|
+
NAMESPACE_FILTER_NS_FULL_PREFIX,
|
|
10
|
+
NAMESPACE_FILTER_P_FULL_PREFIX,
|
|
11
|
+
} from '@shell/utils/namespace-filter';
|
|
12
|
+
import { PAGINATION_SETTINGS_STORE_DEFAULTS } from '@shell/plugins/steve/steve-pagination-utils';
|
|
13
|
+
import { PaginationSettings } from '@shell/types/resources/settings';
|
|
14
|
+
import { PaginationArgs, PaginationFilterField, PaginationParam } from '@shell/types/store/pagination.types';
|
|
15
|
+
|
|
16
|
+
/** Helper to build a plain PaginationParam-shaped object for testing */
|
|
17
|
+
const makeParam = (param: string, equals: boolean, fields: any[]): PaginationParam => ({
|
|
18
|
+
param,
|
|
19
|
+
equals,
|
|
20
|
+
fields,
|
|
21
|
+
} as unknown as PaginationParam);
|
|
22
|
+
|
|
23
|
+
/** Helper to build a PaginationArgs object with sensible defaults */
|
|
24
|
+
const makeArgs = (overrides: Partial<PaginationArgs> = {}): PaginationArgs => ({
|
|
25
|
+
page: 1,
|
|
26
|
+
pageSize: 10,
|
|
27
|
+
sort: [],
|
|
28
|
+
filters: [],
|
|
29
|
+
projectsOrNamespaces: [],
|
|
30
|
+
...overrides,
|
|
31
|
+
} as unknown as PaginationArgs);
|
|
32
|
+
|
|
33
|
+
describe('paginationUtils', () => {
|
|
34
|
+
describe('validateNsProjectFilter', () => {
|
|
35
|
+
it.each([
|
|
36
|
+
[`${ NAMESPACE_FILTER_NS_FULL_PREFIX }my-namespace`, true],
|
|
37
|
+
[`${ NAMESPACE_FILTER_P_FULL_PREFIX }my-project`, true],
|
|
38
|
+
[NAMESPACE_FILTER_ALL, true],
|
|
39
|
+
[NAMESPACE_FILTER_ALL_SYSTEM, true],
|
|
40
|
+
[NAMESPACE_FILTER_ALL_USER, true],
|
|
41
|
+
[NAMESPACE_FILTER_NAMESPACED_YES, true],
|
|
42
|
+
[NAMESPACE_FILTER_NAMESPACED_NO, true],
|
|
43
|
+
[NAMESPACE_FILTER_KINDS.NAMESPACE, true],
|
|
44
|
+
[NAMESPACE_FILTER_KINDS.PROJECT, true],
|
|
45
|
+
['unknown-filter', false],
|
|
46
|
+
['all://orphans', false],
|
|
47
|
+
['', false],
|
|
48
|
+
// Edge cases: prefix without a value
|
|
49
|
+
[NAMESPACE_FILTER_NS_FULL_PREFIX, true],
|
|
50
|
+
[NAMESPACE_FILTER_P_FULL_PREFIX, true],
|
|
51
|
+
])('validates "%s" as %s', (filter, expected) => {
|
|
52
|
+
expect(paginationUtils.validateNsProjectFilter(filter)).toStrictEqual(expected);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
describe('validateNsProjectFilters', () => {
|
|
57
|
+
it('returns true for an empty array', () => {
|
|
58
|
+
expect(paginationUtils.validateNsProjectFilters([])).toStrictEqual(true);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('returns true when all filters are valid', () => {
|
|
62
|
+
expect(paginationUtils.validateNsProjectFilters([NAMESPACE_FILTER_ALL, `${ NAMESPACE_FILTER_NS_FULL_PREFIX }kube-system`])).toStrictEqual(true);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('returns false when at least one filter is invalid', () => {
|
|
66
|
+
expect(paginationUtils.validateNsProjectFilters([NAMESPACE_FILTER_ALL, 'not-valid'])).toStrictEqual(false);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('returns false when all filters are invalid', () => {
|
|
70
|
+
expect(paginationUtils.validateNsProjectFilters(['bad-a', 'bad-b'])).toStrictEqual(false);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('returns undefined when input is undefined (optional chaining)', () => {
|
|
74
|
+
expect(paginationUtils.validateNsProjectFilters(undefined as any)).toBeUndefined();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('returns true for a single valid filter in the array', () => {
|
|
78
|
+
expect(paginationUtils.validateNsProjectFilters([NAMESPACE_FILTER_ALL])).toStrictEqual(true);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe('paginationFilterEqual', () => {
|
|
83
|
+
it('returns true for identical params with no fields', () => {
|
|
84
|
+
const a = makeParam('filter', true, []);
|
|
85
|
+
const b = makeParam('filter', true, []);
|
|
86
|
+
|
|
87
|
+
expect(paginationUtils.paginationFilterEqual(a, b)).toStrictEqual(true);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('returns false for different param names', () => {
|
|
91
|
+
const a = makeParam('filter', true, []);
|
|
92
|
+
const b = makeParam('projectsornamespaces', true, []);
|
|
93
|
+
|
|
94
|
+
expect(paginationUtils.paginationFilterEqual(a, b)).toStrictEqual(false);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('returns false for different equals values', () => {
|
|
98
|
+
const a = makeParam('filter', true, []);
|
|
99
|
+
const b = makeParam('filter', false, []);
|
|
100
|
+
|
|
101
|
+
expect(paginationUtils.paginationFilterEqual(a, b)).toStrictEqual(false);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('returns true for same fields in same order', () => {
|
|
105
|
+
const fields = [{ field: 'metadata.name', value: 'test' }];
|
|
106
|
+
const a = makeParam('filter', true, fields);
|
|
107
|
+
const b = makeParam('filter', true, fields);
|
|
108
|
+
|
|
109
|
+
expect(paginationUtils.paginationFilterEqual(a, b)).toStrictEqual(true);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('returns true for same fields in different order (position-agnostic)', () => {
|
|
113
|
+
const a = makeParam('filter', true, [
|
|
114
|
+
{ field: 'metadata.name', value: 'foo' },
|
|
115
|
+
{ field: 'metadata.namespace', value: 'bar' },
|
|
116
|
+
]);
|
|
117
|
+
const b = makeParam('filter', true, [
|
|
118
|
+
{ field: 'metadata.namespace', value: 'bar' },
|
|
119
|
+
{ field: 'metadata.name', value: 'foo' },
|
|
120
|
+
]);
|
|
121
|
+
|
|
122
|
+
expect(paginationUtils.paginationFilterEqual(a, b)).toStrictEqual(true);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('returns false for different field values', () => {
|
|
126
|
+
const a = makeParam('filter', true, [{ field: 'metadata.name', value: 'foo' }]);
|
|
127
|
+
const b = makeParam('filter', true, [{ field: 'metadata.name', value: 'bar' }]);
|
|
128
|
+
|
|
129
|
+
expect(paginationUtils.paginationFilterEqual(a, b)).toStrictEqual(false);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('returns false for different field names', () => {
|
|
133
|
+
const a = makeParam('filter', true, [{ field: 'metadata.name', value: 'x' }]);
|
|
134
|
+
const b = makeParam('filter', true, [{ field: 'metadata.namespace', value: 'x' }]);
|
|
135
|
+
|
|
136
|
+
expect(paginationUtils.paginationFilterEqual(a, b)).toStrictEqual(false);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('returns false when field counts differ', () => {
|
|
140
|
+
const a = makeParam('filter', true, [{ field: 'a', value: '1' }, { field: 'b', value: '2' }]);
|
|
141
|
+
const b = makeParam('filter', true, [{ field: 'a', value: '1' }]);
|
|
142
|
+
|
|
143
|
+
expect(paginationUtils.paginationFilterEqual(a, b)).toStrictEqual(false);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('handles duplicate fields correctly (position-agnostic does not double-match)', () => {
|
|
147
|
+
const a = makeParam('filter', true, [
|
|
148
|
+
{ field: 'metadata.name', value: 'foo' },
|
|
149
|
+
{ field: 'metadata.name', value: 'foo' },
|
|
150
|
+
]);
|
|
151
|
+
const b = makeParam('filter', true, [
|
|
152
|
+
{ field: 'metadata.name', value: 'foo' },
|
|
153
|
+
{ field: 'metadata.name', value: 'bar' },
|
|
154
|
+
]);
|
|
155
|
+
|
|
156
|
+
expect(paginationUtils.paginationFilterEqual(a, b)).toStrictEqual(false);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('returns true with real PaginationFilterField instances', () => {
|
|
160
|
+
const fieldA = new PaginationFilterField({
|
|
161
|
+
field: 'metadata.name', value: 'test', equals: true, exact: true
|
|
162
|
+
});
|
|
163
|
+
const fieldB = new PaginationFilterField({
|
|
164
|
+
field: 'metadata.name', value: 'test', equals: true, exact: true
|
|
165
|
+
});
|
|
166
|
+
const a = makeParam('filter', true, [fieldA]);
|
|
167
|
+
const b = makeParam('filter', true, [fieldB]);
|
|
168
|
+
|
|
169
|
+
expect(paginationUtils.paginationFilterEqual(a, b)).toStrictEqual(true);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('returns false with real PaginationFilterField instances differing in equality', () => {
|
|
173
|
+
const fieldA = new PaginationFilterField({
|
|
174
|
+
field: 'metadata.name', value: 'test', equals: true, exact: true
|
|
175
|
+
});
|
|
176
|
+
const fieldB = new PaginationFilterField({
|
|
177
|
+
field: 'metadata.name', value: 'test', equals: false, exact: true
|
|
178
|
+
});
|
|
179
|
+
const a = makeParam('filter', true, [fieldA]);
|
|
180
|
+
const b = makeParam('filter', true, [fieldB]);
|
|
181
|
+
|
|
182
|
+
expect(paginationUtils.paginationFilterEqual(a, b)).toStrictEqual(false);
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
describe('paginationFiltersEqual', () => {
|
|
187
|
+
it('returns true for two empty arrays', () => {
|
|
188
|
+
expect(paginationUtils.paginationFiltersEqual([], [])).toStrictEqual(true);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('returns false when first array is longer', () => {
|
|
192
|
+
const p = makeParam('filter', true, []);
|
|
193
|
+
|
|
194
|
+
expect(paginationUtils.paginationFiltersEqual([p], [])).toStrictEqual(false);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('returns false when second array is longer', () => {
|
|
198
|
+
const p = makeParam('filter', true, []);
|
|
199
|
+
|
|
200
|
+
expect(paginationUtils.paginationFiltersEqual([], [p])).toStrictEqual(false);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it('returns true for arrays with identical params', () => {
|
|
204
|
+
const p = makeParam('filter', true, []);
|
|
205
|
+
|
|
206
|
+
expect(paginationUtils.paginationFiltersEqual([p], [p])).toStrictEqual(true);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it('returns false when params differ in equals', () => {
|
|
210
|
+
const a = [makeParam('filter', true, [])];
|
|
211
|
+
const b = [makeParam('filter', false, [])];
|
|
212
|
+
|
|
213
|
+
expect(paginationUtils.paginationFiltersEqual(a, b)).toStrictEqual(false);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it('returns true for multiple matching params', () => {
|
|
217
|
+
const p1 = makeParam('filter', true, [{ field: 'x', value: '1' }]);
|
|
218
|
+
const p2 = makeParam('projectsornamespaces', false, []);
|
|
219
|
+
|
|
220
|
+
expect(paginationUtils.paginationFiltersEqual([p1, p2], [p1, p2])).toStrictEqual(true);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('is position-sensitive (same params in different order returns false)', () => {
|
|
224
|
+
const p1 = makeParam('filter', true, [{ field: 'x', value: '1' }]);
|
|
225
|
+
const p2 = makeParam('projectsornamespaces', true, [{ field: 'y', value: '2' }]);
|
|
226
|
+
|
|
227
|
+
expect(paginationUtils.paginationFiltersEqual([p1, p2], [p2, p1])).toStrictEqual(false);
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
describe('paginationEqual', () => {
|
|
232
|
+
it('returns true for two undefined args', () => {
|
|
233
|
+
expect(paginationUtils.paginationEqual(undefined, undefined)).toStrictEqual(true);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it('returns false when first arg is undefined and second is defined', () => {
|
|
237
|
+
const args = makeArgs();
|
|
238
|
+
|
|
239
|
+
expect(paginationUtils.paginationEqual(undefined, args)).toStrictEqual(false);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it('returns false when first arg is defined and second is undefined', () => {
|
|
243
|
+
const args = makeArgs();
|
|
244
|
+
|
|
245
|
+
expect(paginationUtils.paginationEqual(args, undefined)).toStrictEqual(false);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('returns true for identical args', () => {
|
|
249
|
+
const args = makeArgs();
|
|
250
|
+
|
|
251
|
+
expect(paginationUtils.paginationEqual(args, { ...args })).toStrictEqual(true);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it.each([
|
|
255
|
+
['page', { page: 2 }],
|
|
256
|
+
['pageSize', { pageSize: 20 }],
|
|
257
|
+
])('returns false when %s differs', (_field, override) => {
|
|
258
|
+
const a = makeArgs();
|
|
259
|
+
const b = makeArgs(override);
|
|
260
|
+
|
|
261
|
+
expect(paginationUtils.paginationEqual(a, b)).toStrictEqual(false);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
it('returns false when sort field differs', () => {
|
|
265
|
+
const a = makeArgs({ sort: [{ field: 'metadata.name', asc: true }] });
|
|
266
|
+
const b = makeArgs({ sort: [{ field: 'metadata.namespace', asc: true }] });
|
|
267
|
+
|
|
268
|
+
expect(paginationUtils.paginationEqual(a, b)).toStrictEqual(false);
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it('returns false when sort direction differs', () => {
|
|
272
|
+
const a = makeArgs({ sort: [{ field: 'metadata.name', asc: true }] });
|
|
273
|
+
const b = makeArgs({ sort: [{ field: 'metadata.name', asc: false }] });
|
|
274
|
+
|
|
275
|
+
expect(paginationUtils.paginationEqual(a, b)).toStrictEqual(false);
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it('sort comparison is position-sensitive (not agnostic)', () => {
|
|
279
|
+
const a = makeArgs({ sort: [{ field: 'a', asc: true }, { field: 'b', asc: false }] });
|
|
280
|
+
const b = makeArgs({ sort: [{ field: 'b', asc: false }, { field: 'a', asc: true }] });
|
|
281
|
+
|
|
282
|
+
expect(paginationUtils.paginationEqual(a, b)).toStrictEqual(false);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it('returns true when sort has same entries in same order', () => {
|
|
286
|
+
const sort = [{ field: 'a', asc: true }, { field: 'b', asc: false }];
|
|
287
|
+
const a = makeArgs({ sort: [...sort] });
|
|
288
|
+
const b = makeArgs({ sort: [...sort] });
|
|
289
|
+
|
|
290
|
+
expect(paginationUtils.paginationEqual(a, b)).toStrictEqual(true);
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
it('returns false when filters differ', () => {
|
|
294
|
+
const a = makeArgs({ filters: [makeParam('filter', true, []) as any] });
|
|
295
|
+
const b = makeArgs({ filters: [makeParam('filter', false, []) as any] });
|
|
296
|
+
|
|
297
|
+
expect(paginationUtils.paginationEqual(a, b)).toStrictEqual(false);
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it('returns false when projectsOrNamespaces differ', () => {
|
|
301
|
+
const a = makeArgs({ projectsOrNamespaces: [makeParam('projectsornamespaces', true, []) as any] });
|
|
302
|
+
const b = makeArgs({ projectsOrNamespaces: [makeParam('projectsornamespaces', false, []) as any] });
|
|
303
|
+
|
|
304
|
+
expect(paginationUtils.paginationEqual(a, b)).toStrictEqual(false);
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
it('returns false when sort count differs', () => {
|
|
308
|
+
const a = makeArgs({ sort: [{ field: 'a', asc: true }] });
|
|
309
|
+
const b = makeArgs({ sort: [{ field: 'a', asc: true }, { field: 'b', asc: false }] });
|
|
310
|
+
|
|
311
|
+
expect(paginationUtils.paginationEqual(a, b)).toStrictEqual(false);
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
it('returns true when both have empty optional arrays', () => {
|
|
315
|
+
const a = makeArgs({
|
|
316
|
+
sort: [], filters: [], projectsOrNamespaces: []
|
|
317
|
+
});
|
|
318
|
+
const b = makeArgs({
|
|
319
|
+
sort: [], filters: [], projectsOrNamespaces: []
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
expect(paginationUtils.paginationEqual(a, b)).toStrictEqual(true);
|
|
323
|
+
});
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
describe('getStoreSettings', () => {
|
|
327
|
+
it('returns store defaults when useDefaultStores is true', () => {
|
|
328
|
+
const settings: PaginationSettings = { useDefaultStores: true };
|
|
329
|
+
|
|
330
|
+
expect(paginationUtils.getStoreSettings(settings)).toStrictEqual(PAGINATION_SETTINGS_STORE_DEFAULTS);
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it('returns store defaults when useDefaultStores is absent', () => {
|
|
334
|
+
const settings = {} as PaginationSettings;
|
|
335
|
+
|
|
336
|
+
expect(paginationUtils.getStoreSettings(settings)).toStrictEqual(PAGINATION_SETTINGS_STORE_DEFAULTS);
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
it('returns store defaults when useDefaultStores is false but no stores provided', () => {
|
|
340
|
+
const settings: PaginationSettings = { useDefaultStores: false };
|
|
341
|
+
|
|
342
|
+
expect(paginationUtils.getStoreSettings(settings)).toStrictEqual(PAGINATION_SETTINGS_STORE_DEFAULTS);
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it('returns custom stores when useDefaultStores is false and stores are provided', () => {
|
|
346
|
+
const customStores = { cluster: { resources: { enableAll: true } } } as any;
|
|
347
|
+
const settings: PaginationSettings = {
|
|
348
|
+
useDefaultStores: false,
|
|
349
|
+
stores: customStores,
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
expect(paginationUtils.getStoreSettings(settings)).toStrictEqual(customStores);
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
it('returns store defaults when settings is undefined (via overload)', () => {
|
|
356
|
+
const settings = undefined as unknown as PaginationSettings;
|
|
357
|
+
|
|
358
|
+
expect(paginationUtils.getStoreSettings(settings)).toStrictEqual(PAGINATION_SETTINGS_STORE_DEFAULTS);
|
|
359
|
+
});
|
|
360
|
+
});
|
|
361
|
+
});
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { parseExternalId, parseHelmExternalId } from '@shell/utils/parse-externalid';
|
|
2
|
+
|
|
3
|
+
describe('parseExternalId', () => {
|
|
4
|
+
describe('falsy / empty input', () => {
|
|
5
|
+
it.each([
|
|
6
|
+
{ desc: 'null', input: null },
|
|
7
|
+
{ desc: 'undefined', input: undefined },
|
|
8
|
+
{ desc: 'empty string', input: '' },
|
|
9
|
+
])('returns all-null output for $desc', ({ input }) => {
|
|
10
|
+
expect(parseExternalId(input as any)).toStrictEqual({
|
|
11
|
+
kind: null,
|
|
12
|
+
group: null,
|
|
13
|
+
base: null,
|
|
14
|
+
id: null,
|
|
15
|
+
name: null,
|
|
16
|
+
version: null,
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('new-style: kind://group:name:version', () => {
|
|
22
|
+
it('extracts kind, group, name and version from a full new-style id', () => {
|
|
23
|
+
const result = parseExternalId('catalog://library:mysql:1.2.3');
|
|
24
|
+
|
|
25
|
+
expect(result.kind).toStrictEqual('catalog');
|
|
26
|
+
expect(result.group).toStrictEqual('library');
|
|
27
|
+
expect(result.name).toStrictEqual('mysql');
|
|
28
|
+
expect(result.version).toStrictEqual('1.2.3');
|
|
29
|
+
expect(result.id).toStrictEqual('library:mysql:1.2.3');
|
|
30
|
+
expect(result.templateId).toStrictEqual('library:mysql');
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('handles name with base separator (*)', () => {
|
|
34
|
+
const result = parseExternalId('catalog://library:base*app:1.0.0');
|
|
35
|
+
|
|
36
|
+
expect(result.base).toStrictEqual('base');
|
|
37
|
+
expect(result.name).toStrictEqual('app');
|
|
38
|
+
expect(result.version).toStrictEqual('1.0.0');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('uses part before colon as group', () => {
|
|
42
|
+
// For 'containers://someimage:latest', group='someimage', name='latest'
|
|
43
|
+
const result = parseExternalId('containers://someimage:latest');
|
|
44
|
+
|
|
45
|
+
expect(result.kind).toStrictEqual('containers');
|
|
46
|
+
expect(result.group).toStrictEqual('someimage');
|
|
47
|
+
expect(result.name).toStrictEqual('latest');
|
|
48
|
+
expect(result.version).toBeNull();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('name with no version (no trailing colon) sets version to null', () => {
|
|
52
|
+
const result = parseExternalId('catalog://library:nameonly');
|
|
53
|
+
|
|
54
|
+
expect(result.name).toStrictEqual('nameonly');
|
|
55
|
+
expect(result.version).toBeNull();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe('new-style: kind://name (no group, no colon in rest)', () => {
|
|
60
|
+
it('leaves group null when rest has no colon', () => {
|
|
61
|
+
// NOTE: EXTERNAL_ID.KIND_CATALOG is undefined, so the "set library group for
|
|
62
|
+
// catalog kind" branch is unreachable (kind === undefined condition never matches).
|
|
63
|
+
// group stays null for all kinds when rest contains no colon.
|
|
64
|
+
const result = parseExternalId('catalog://appname');
|
|
65
|
+
|
|
66
|
+
expect(result.kind).toStrictEqual('catalog');
|
|
67
|
+
expect(result.group).toBeNull();
|
|
68
|
+
expect(result.name).toStrictEqual('appname');
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe('old-style: name-version (no ://)', () => {
|
|
73
|
+
it('extracts group, name and version from a name-version string', () => {
|
|
74
|
+
// NOTE: EXTERNAL_ID.KIND_CATALOG is not defined, so result.kind is undefined (not 'catalog').
|
|
75
|
+
// All other fields (group, name, version, templateId) are populated correctly.
|
|
76
|
+
const result = parseExternalId('mysql-1.2.3');
|
|
77
|
+
|
|
78
|
+
expect(result.kind).toBeUndefined();
|
|
79
|
+
expect(result.group).toStrictEqual('library');
|
|
80
|
+
expect(result.name).toStrictEqual('mysql');
|
|
81
|
+
expect(result.version).toStrictEqual('1.2.3');
|
|
82
|
+
expect(result.templateId).toStrictEqual('library:mysql');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('splits on last hyphen so names with hyphens are preserved', () => {
|
|
86
|
+
const result = parseExternalId('my-app-chart-0.1.0');
|
|
87
|
+
|
|
88
|
+
expect(result.kind).toBeUndefined();
|
|
89
|
+
expect(result.group).toStrictEqual('library');
|
|
90
|
+
expect(result.version).toStrictEqual('0.1.0');
|
|
91
|
+
expect(result.name).toStrictEqual('my-app-chart');
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe('parseHelmExternalId', () => {
|
|
97
|
+
describe('falsy / empty input', () => {
|
|
98
|
+
it.each([
|
|
99
|
+
{ desc: 'null', input: null },
|
|
100
|
+
{ desc: 'undefined', input: undefined },
|
|
101
|
+
{ desc: 'empty string', input: '' },
|
|
102
|
+
])('returns all-null output for $desc', ({ input }) => {
|
|
103
|
+
expect(parseHelmExternalId(input as any)).toStrictEqual({
|
|
104
|
+
kind: null,
|
|
105
|
+
group: null,
|
|
106
|
+
base: null,
|
|
107
|
+
id: null,
|
|
108
|
+
name: null,
|
|
109
|
+
version: null,
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
describe('valid helm external id', () => {
|
|
115
|
+
it('parses a helm id with catalog containing a slash (catalog/chart format)', () => {
|
|
116
|
+
// Format: kind:///key=val&key=val — the key=val pairs are parsed directly
|
|
117
|
+
const id = 'catalog:///catalog=cattle-global-data/mycharts&template=nginx&version=1.0.0';
|
|
118
|
+
const result = parseHelmExternalId(id);
|
|
119
|
+
|
|
120
|
+
expect(result.kind).toStrictEqual('catalog');
|
|
121
|
+
expect(result.id).toStrictEqual(id);
|
|
122
|
+
expect(result.template).toStrictEqual('nginx');
|
|
123
|
+
expect(result.version).toStrictEqual('1.0.0');
|
|
124
|
+
// catalog contains slash → replaced with colon for templateId prefix
|
|
125
|
+
expect(result.templateId).toStrictEqual('cattle-global-data:mycharts-nginx');
|
|
126
|
+
expect(result.templateVersionId).toStrictEqual('cattle-global-data:mycharts-nginx-1.0.0');
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('prepends cattle-global-data: prefix when catalog value has no slash', () => {
|
|
130
|
+
const id = 'catalog:///catalog=mycharts&template=redis&version=2.0.0';
|
|
131
|
+
const result = parseHelmExternalId(id);
|
|
132
|
+
|
|
133
|
+
expect(result.templateId).toStrictEqual('cattle-global-data:mycharts-redis');
|
|
134
|
+
expect(result.templateVersionId).toStrictEqual('cattle-global-data:mycharts-redis-2.0.0');
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
});
|