@rancher/shell 3.0.12-rc.2 → 3.0.12-rc.4
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/styles/base/_variables.scss +2 -0
- package/assets/styles/fonts/_fontstack.scss +132 -8
- package/assets/styles/global/_layout.scss +4 -0
- package/assets/translations/en-us.yaml +165 -45
- package/assets/translations/zh-hans.yaml +1 -7
- package/chart/monitoring/ClusterSelector.vue +0 -21
- package/chart/monitoring/index.vue +10 -1
- package/chart/monitoring/prometheus/index.vue +6 -3
- package/components/ActionDropdownShell.vue +2 -1
- package/components/CruResource.vue +161 -14
- package/components/CruResourceFooter.vue +9 -5
- package/components/ExplorerMembers.vue +8 -4
- package/components/ExplorerProjectsNamespaces.vue +11 -7
- package/components/GrowlManager.vue +4 -0
- package/components/InstallHelmCharts.vue +2 -2
- package/components/LandingPagePreference.vue +14 -5
- package/components/MgmtNodeList.vue +184 -0
- package/components/Resource/Detail/Card/StateCard/__tests__/composables.test.ts +90 -1
- package/components/Resource/Detail/Card/StateCard/composables.ts +57 -87
- package/components/Resource/Detail/Card/StatusCard/__tests__/StatusCard.test.ts +61 -0
- package/components/Resource/Detail/Card/StatusCard/index.vue +61 -15
- package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +17 -1
- package/components/Resource/Detail/Metadata/KeyValue.vue +5 -2
- package/components/Resource/Detail/Metadata/KeyValueRow.vue +2 -6
- 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/ResourceDetail/index.vue +1 -1
- package/components/ResourceList/Masthead.vue +19 -9
- package/components/ResourceList/index.vue +82 -1
- package/components/RichTranslation.vue +5 -2
- package/components/SelectIconGrid.vue +0 -10
- package/components/Setting.vue +1 -0
- 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/SubtleLink.vue +31 -6
- package/components/Tabbed/Tab.vue +29 -3
- package/components/Tabbed/index.vue +25 -3
- package/components/TableOfContents/TableOfContents.vue +109 -0
- package/components/TableOfContents/composables.ts +258 -0
- package/components/Window/ContainerShell.vue +21 -11
- package/components/Window/__tests__/ContainerShell.test.ts +107 -37
- package/components/Wizard.vue +23 -17
- package/components/fleet/AppCoChartGrid.vue +401 -0
- package/components/fleet/AppCoEmptyState.vue +127 -0
- package/components/fleet/AppCoPageHeader.vue +119 -0
- package/components/fleet/AppCoVersionSelect.vue +70 -0
- package/components/fleet/FleetBundles.vue +100 -12
- package/components/fleet/FleetClusterTargets/ClusterSelectionFields.vue +217 -0
- package/components/fleet/FleetClusterTargets/TargetsList.vue +123 -35
- package/components/fleet/FleetClusterTargets/index.vue +226 -161
- package/components/fleet/FleetIntro.vue +7 -3
- package/components/fleet/FleetNoWorkspaces.vue +7 -3
- package/components/fleet/FleetSecretSelector.vue +5 -3
- package/components/fleet/FleetValuesFrom.vue +8 -2
- package/components/fleet/GitRepoTargetTab.vue +0 -2
- package/components/fleet/HelmOpAdvancedTab.vue +19 -53
- package/components/fleet/HelmOpAppCoConfigTab.vue +593 -0
- package/components/fleet/HelmOpAppCoResourcesSection.vue +162 -0
- package/components/fleet/HelmOpResourcesSection.vue +82 -0
- package/components/fleet/HelmOpTargetOptionsSection.vue +89 -0
- package/components/fleet/HelmOpTargetTab.vue +64 -60
- package/components/fleet/HelmOpValuesTab.vue +129 -105
- package/components/fleet/__tests__/AppCoEmptyState.test.ts +71 -0
- package/components/fleet/__tests__/AppCoVersionSelect.test.ts +36 -0
- package/components/fleet/__tests__/ClusterSelectionFields.test.ts +62 -0
- package/components/fleet/__tests__/FleetClusterTargets.test.ts +402 -115
- package/components/fleet/__tests__/FleetClusters.test.ts +12 -12
- package/components/fleet/__tests__/FleetSecretSelector.test.ts +16 -0
- package/components/fleet/__tests__/FleetValuesFrom.test.ts +44 -0
- package/components/fleet/__tests__/HelmOpAppCoConfigTab.test.ts +59 -0
- package/components/fleet/__tests__/HelmOpAppCoResourcesSection.test.ts +62 -0
- package/components/fleet/__tests__/HelmOpResourcesSection.test.ts +43 -0
- package/components/fleet/__tests__/HelmOpTargetOptionsSection.test.ts +34 -0
- package/components/fleet/__tests__/HelmOpValuesTab.test.ts +39 -0
- package/components/fleet/__tests__/__snapshots__/AppCoEmptyState.test.ts.snap +97 -0
- package/components/fleet/__tests__/__snapshots__/AppCoVersionSelect.test.ts.snap +30 -0
- package/components/fleet/__tests__/__snapshots__/ClusterSelectionFields.test.ts.snap +209 -0
- package/components/fleet/__tests__/__snapshots__/HelmOpTargetOptionsSection.test.ts.snap +140 -0
- package/components/fleet/dashboard/Empty.vue +8 -4
- package/components/fleet/dashboard/ResourceCard.vue +28 -0
- package/components/fleet/dashboard/ResourceDetails.vue +28 -0
- package/components/fleet/dashboard/__tests__/ResourceCard.test.ts +87 -0
- package/components/form/ArrayList.vue +61 -4
- package/components/form/KeyValue.vue +23 -2
- package/components/form/LabeledSelect.vue +59 -4
- package/components/form/Labels.vue +22 -3
- package/components/form/NameNsDescription.vue +24 -5
- package/components/form/ResourceTabs/index.vue +1 -0
- package/components/form/Security.vue +6 -2
- package/components/form/WorkloadPorts.vue +2 -7
- package/components/form/__tests__/NameNsDescription.test.ts +75 -0
- package/components/form/__tests__/Security.test.ts +76 -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/InternalExternalIP.vue +10 -4
- package/components/formatter/MachineSummaryGraph.vue +1 -1
- package/components/formatter/PodsUsage.vue +2 -2
- package/components/formatter/ServiceTargets.vue +26 -7
- package/components/formatter/__tests__/Autoscaler.test.ts +19 -22
- package/components/formatter/__tests__/FleetSummaryGraph.test.ts +216 -0
- package/components/formatter/__tests__/InternalExternalIP.test.ts +132 -0
- package/components/formatter/__tests__/PodsUsage.test.ts +6 -10
- package/components/formatter/__tests__/ServiceTargets.test.ts +412 -0
- package/components/nav/Header.vue +4 -0
- package/components/nav/NamespaceFilter.vue +2 -2
- package/components/nav/TopLevelMenu.helper.ts +15 -3
- package/components/nav/TopLevelMenu.vue +22 -6
- package/components/nav/__tests__/Header.test.ts +15 -0
- package/components/nav/__tests__/TopLevelMenu.test.ts +263 -21
- package/components/templates/default.vue +9 -4
- package/components/templates/home.vue +23 -0
- package/components/templates/plain.vue +23 -0
- package/components/templates/standalone.vue +17 -0
- package/composables/useFormValidation.ts +93 -0
- package/composables/useHelmOpResources.test.ts +56 -0
- package/composables/useHelmOpResources.ts +32 -0
- package/composables/useStateColor.test.ts +325 -0
- package/composables/useStateColor.ts +128 -0
- package/composables/useVeeValidateField.test.ts +159 -0
- package/composables/useVeeValidateField.ts +67 -0
- package/config/home-links.js +1 -1
- package/config/labels-annotations.js +1 -0
- package/config/pagination-table-headers.js +18 -1
- package/config/product/explorer.js +17 -4
- package/config/product/manager.js +84 -21
- package/config/router/index.js +16 -0
- package/config/router/navigation-guards/__tests__/authentication.test.ts +130 -0
- package/config/router/navigation-guards/authentication.js +10 -4
- package/config/router/routes.js +26 -6
- package/config/settings.ts +0 -2
- package/config/table-headers.js +23 -5
- package/config/types.js +11 -1
- package/core/__tests__/plugin-products.test.ts +904 -20
- package/core/plugin-products-base.ts +110 -10
- package/core/plugin-products.ts +4 -0
- package/core/plugin-types.ts +194 -31
- package/core/plugin.ts +18 -7
- package/core/productDebugger.js +9 -4
- package/core/types-provisioning.ts +77 -31
- package/core/types.ts +72 -22
- package/detail/__tests__/pod.test.ts +41 -0
- package/detail/__tests__/provisioning.cattle.io.cluster.test.ts +114 -0
- package/detail/__tests__/workload.test.ts +3 -152
- package/detail/catalog.cattle.io.clusterrepo.vue +1 -1
- package/detail/harvesterhci.io.management.cluster.vue +6 -2
- package/detail/pod.vue +1 -1
- package/detail/provisioning.cattle.io.cluster.vue +34 -14
- package/detail/workload/index.vue +12 -55
- package/edit/__tests__/catalog.cattle.io.clusterrepo.test.ts +248 -0
- package/edit/__tests__/fleet.cattle.io.helmop.test.ts +105 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/General.test.ts.snap +6 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/index.test.ts.snap +1 -0
- package/edit/auth/__tests__/azuread.test.ts +247 -39
- package/edit/auth/__tests__/github.test.ts +234 -0
- package/edit/auth/__tests__/oidc.test.ts +26 -6
- package/edit/auth/__tests__/saml.test.ts +196 -0
- package/edit/auth/azuread.vue +197 -56
- package/edit/auth/github.vue +72 -13
- package/edit/auth/ldap/__tests__/index.test.ts +206 -0
- package/edit/auth/ldap/config.vue +8 -0
- package/edit/auth/ldap/index.vue +75 -1
- package/edit/auth/oidc.vue +119 -73
- package/edit/auth/saml.vue +76 -12
- package/edit/catalog.cattle.io.clusterrepo.vue +140 -32
- package/edit/fleet.cattle.io.helmop.vue +491 -136
- package/edit/management.cattle.io.user.vue +5 -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/provisioning.cattle.io.cluster/__tests__/MachinePool.test.ts +104 -0
- package/edit/provisioning.cattle.io.cluster/index.vue +11 -7
- package/edit/provisioning.cattle.io.cluster/rke2.vue +92 -14
- package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +22 -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/list/fleet.cattle.io.bundle.vue +7 -104
- package/list/fleet.cattle.io.clusterregistrationtoken.vue +20 -0
- package/list/group.principal.vue +5 -4
- package/list/harvesterhci.io.management.cluster.vue +8 -9
- package/list/management.cattle.io.user.vue +12 -9
- package/list/provisioning.cattle.io.cluster.vue +268 -180
- package/list/utils/management.cattle.io.cluster.utils.ts +128 -0
- package/mixins/__tests__/auth-config.test.ts +90 -0
- package/mixins/__tests__/chart.test.ts +206 -0
- package/mixins/__tests__/resource-fetch-api-pagination.test.ts +48 -0
- package/mixins/auth-config.js +7 -0
- package/mixins/brand.js +2 -1
- package/mixins/chart.js +22 -9
- package/mixins/child-hook.js +12 -6
- package/mixins/create-edit-view/impl.js +5 -3
- package/mixins/resource-fetch-api-pagination.js +62 -6
- package/models/__tests__/catalog.cattle.io.clusterrepo.test.ts +57 -0
- package/models/__tests__/compliance.cattle.io.clusterscan.test.ts +144 -0
- package/models/__tests__/ext.cattle.io.kubeconfig.test.ts +67 -67
- package/models/__tests__/fleet-application.test.ts +175 -0
- package/models/__tests__/fleet.cattle.io.bundle.test.ts +169 -0
- package/models/__tests__/fleet.cattle.io.helmop.test.ts +84 -0
- package/models/__tests__/management.cattle.io.cluster.test.ts +1 -1
- package/models/__tests__/management.cattle.io.node.ts +28 -5
- package/models/__tests__/management.cattle.io.nodepool.ts +5 -4
- package/models/__tests__/namespace.test.ts +36 -0
- package/models/__tests__/provisioning.cattle.io.cluster.test.ts +81 -11
- package/models/__tests__/workload.test.ts +401 -26
- package/models/base-cluster.x-k8s.io.js +26 -0
- package/models/catalog.cattle.io.clusterrepo.js +28 -4
- 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 +165 -2
- package/models/ext.cattle.io.kubeconfig.ts +4 -7
- package/models/fleet-application.js +7 -1
- package/models/fleet.cattle.io.helmop.js +20 -1
- package/models/management.cattle.io.cluster.js +434 -41
- package/models/management.cattle.io.node.js +50 -7
- package/models/management.cattle.io.nodepool.js +1 -1
- package/models/namespace.js +1 -1
- package/models/networking.k8s.io.ingress.js +12 -4
- package/models/pod.js +33 -1
- package/models/provisioning.cattle.io.cluster.js +51 -334
- package/models/rke.cattle.io.etcdsnapshot.js +1 -2
- package/models/workload.js +108 -13
- package/models/workload.service.js +5 -0
- package/package.json +22 -39
- package/pages/__tests__/readme.test.ts +49 -0
- package/pages/about.vue +5 -6
- package/pages/auth/login.vue +0 -35
- package/pages/auth/setup.vue +13 -3
- package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +2 -2
- package/pages/c/_cluster/apps/charts/AppChartCardSubHeader.vue +10 -1
- package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +76 -0
- package/pages/c/_cluster/apps/charts/__tests__/index.test.ts +93 -0
- package/pages/c/_cluster/apps/charts/chart.vue +62 -9
- package/pages/c/_cluster/apps/charts/index.vue +48 -10
- package/pages/c/_cluster/apps/charts/install.vue +122 -113
- package/pages/c/_cluster/auth/roles/index.vue +5 -4
- package/pages/c/_cluster/explorer/__tests__/index.test.ts +23 -25
- package/pages/c/_cluster/explorer/index.vue +5 -49
- package/pages/c/_cluster/explorer/workload-dashboard/ByNamespaceSection.vue +31 -0
- package/pages/c/_cluster/explorer/workload-dashboard/ByStateSection.vue +138 -0
- package/pages/c/_cluster/explorer/workload-dashboard/ByTypeSection.vue +30 -0
- package/pages/c/_cluster/explorer/workload-dashboard/WorkloadCard.vue +155 -0
- package/pages/c/_cluster/explorer/workload-dashboard/WorkloadNamespaceCard.vue +142 -0
- package/pages/c/_cluster/explorer/workload-dashboard/WorkloadTypeCard.vue +159 -0
- package/pages/c/_cluster/explorer/workload-dashboard/__tests__/composable.test.ts +561 -0
- package/pages/c/_cluster/explorer/workload-dashboard/composable.ts +440 -0
- package/pages/c/_cluster/explorer/workload-dashboard/index.vue +187 -0
- package/pages/c/_cluster/explorer/workload-dashboard/types.ts +80 -0
- package/pages/c/_cluster/fleet/application/create.vue +187 -136
- package/pages/c/_cluster/fleet/application/index.vue +5 -3
- package/pages/c/_cluster/fleet/application/suse-app-collection/ChartDetailBody.vue +338 -0
- package/pages/c/_cluster/fleet/application/suse-app-collection/ChartDetailHeader.vue +121 -0
- package/pages/c/_cluster/fleet/application/suse-app-collection/chart.vue +369 -0
- package/pages/c/_cluster/fleet/application/suse-app-collection/charts.vue +248 -0
- package/pages/c/_cluster/fleet/application/suse-app-collection/credentials.vue +310 -0
- package/pages/c/_cluster/fleet/index.vue +2 -2
- 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/uiplugins/PluginInfoPanel.vue +1 -0
- package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +815 -2
- package/pages/c/_cluster/uiplugins/index.vue +218 -197
- package/pages/diagnostic.vue +13 -17
- package/pages/fail-whale.vue +30 -7
- package/pages/home.vue +93 -306
- package/pages/readme.vue +88 -0
- package/plugins/clean-html.d.ts +9 -0
- package/plugins/dashboard-store/__tests__/resource-class.test.ts +181 -0
- package/plugins/dashboard-store/actions.js +40 -18
- package/plugins/dashboard-store/resource-class.js +67 -9
- package/plugins/steve/__tests__/actions.test.ts +212 -0
- package/plugins/steve/__tests__/subscribe.spec.ts +6 -3
- package/plugins/steve/actions.js +96 -0
- package/plugins/steve/steve-pagination-utils.ts +12 -4
- package/plugins/steve/subscribe.js +35 -5
- package/rancher-components/Accordion/Accordion.vue +53 -9
- package/rancher-components/Form/Checkbox/Checkbox.vue +14 -0
- package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +10 -4
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +7 -52
- package/rancher-components/Form/Radio/RadioButton.vue +17 -1
- package/rancher-components/Form/Radio/RadioGroup.vue +10 -0
- package/rancher-components/Pill/RcTag/RcTag.vue +3 -2
- package/rancher-components/RcButton/RcButton.test.ts +140 -1
- package/rancher-components/RcButton/RcButton.vue +126 -17
- package/rancher-components/RcButton/types.ts +3 -0
- package/rancher-components/RcDropdown/RcDropdownTrigger.vue +10 -8
- package/rancher-components/RcItemCard/RcItemCard.test.ts +18 -0
- package/rancher-components/RcItemCard/RcItemCard.vue +2 -2
- package/rancher-components/RcSection/RcSection.vue +28 -3
- package/scripts/extension/helm/package/Dockerfile +1 -1
- package/scripts/test-plugins-build.sh +2 -1
- package/store/__tests__/catalog.test.ts +115 -1
- package/store/__tests__/notifications.test.ts +434 -0
- package/store/__tests__/type-map.test.ts +556 -1
- package/store/action-menu.js +8 -3
- package/store/auth.js +1 -1
- package/store/aws.js +27 -16
- package/store/catalog.js +84 -3
- package/store/digitalocean.js +20 -38
- package/store/index.js +2 -0
- package/store/linode.js +25 -40
- package/store/plugins.js +7 -4
- package/store/pnap.js +1 -0
- package/store/type-map.js +111 -29
- package/tsconfig.paths.json +8 -8
- package/types/components/buttonGroup.ts +5 -0
- 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 +206 -72
- 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__/auth.test.ts +273 -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__/computed.test.ts +193 -0
- package/utils/__tests__/cspAdaptor.test.ts +163 -0
- package/utils/__tests__/dom.test.ts +81 -0
- package/utils/__tests__/duration.test.ts +176 -0
- package/utils/__tests__/dynamic-importer.test.ts +102 -0
- package/utils/__tests__/fleet-appco.test.ts +312 -0
- package/utils/__tests__/fleet.test.ts +340 -0
- package/utils/__tests__/ingress.test.ts +553 -0
- package/utils/__tests__/kube.test.ts +68 -0
- package/utils/__tests__/monitoring.test.ts +130 -0
- package/utils/__tests__/namespace-filter.test.ts +109 -0
- package/utils/__tests__/object.test.ts +22 -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__/platform.test.ts +91 -0
- package/utils/__tests__/poller-sequential.test.ts +177 -0
- package/utils/__tests__/poller.test.ts +170 -0
- package/utils/__tests__/position.test.ts +237 -0
- package/utils/__tests__/promise.test.ts +346 -0
- package/utils/__tests__/provider.test.ts +51 -1
- package/utils/__tests__/queue.test.ts +232 -0
- package/utils/__tests__/release-notes.test.ts +221 -0
- package/utils/__tests__/router.test.js +254 -1
- package/utils/__tests__/select.test.ts +208 -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 +265 -1
- package/utils/__tests__/title.test.ts +47 -0
- package/utils/__tests__/units.test.ts +417 -0
- package/utils/__tests__/versions.test.ts +128 -0
- package/utils/__tests__/width.test.ts +53 -0
- package/utils/__tests__/window.test.ts +158 -0
- package/utils/__tests__/xccdf.test.ts +511 -0
- package/utils/chart.js +36 -0
- package/utils/crypto/__tests__/browserHashUtils.test.ts +98 -0
- package/utils/crypto/__tests__/index.test.ts +144 -0
- package/utils/duration.ts +104 -0
- package/utils/dynamic-content/__tests__/notification-handler.test.ts +196 -0
- package/utils/dynamic-content/info.ts +2 -1
- package/utils/error.js +13 -0
- package/utils/fleet-appco.ts +323 -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 +22 -2
- package/utils/pagination-utils.ts +2 -1
- package/utils/provider.ts +12 -0
- package/utils/string.js +25 -2
- package/utils/uiplugins.ts +5 -5
- package/utils/validators/__tests__/cluster-name.test.ts +110 -0
- package/utils/validators/__tests__/container-images.test.ts +104 -0
- package/utils/validators/__tests__/cron-schedule.test.ts +79 -0
- package/utils/validators/__tests__/flow-output.test.ts +91 -0
- package/utils/validators/__tests__/index.test.ts +481 -0
- package/utils/validators/__tests__/kubernetes-name.test.ts +163 -0
- package/utils/validators/__tests__/logging-outputs.test.ts +58 -0
- package/utils/validators/__tests__/misc-validators.test.ts +246 -0
- package/utils/validators/__tests__/monitoring-route.test.ts +119 -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 +415 -0
- package/vue.config.js +1 -1
- 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/pages/support/index.vue +0 -264
- package/utils/duration.js +0 -43
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
import type defaultGc from '@shell/utils/gc/gc';
|
|
2
|
+
import { MANAGEMENT } from '@shell/config/types';
|
|
3
|
+
|
|
4
|
+
type GcInstance = typeof defaultGc;
|
|
5
|
+
|
|
6
|
+
const DEFAULT_PREFS = {
|
|
7
|
+
enabled: true,
|
|
8
|
+
enabledInterval: true,
|
|
9
|
+
interval: 300,
|
|
10
|
+
enabledOnNavigate: true,
|
|
11
|
+
ageThreshold: 120, // seconds → maxAge = 120_000 ms
|
|
12
|
+
countThreshold: 500,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
let stampCounter = 1000;
|
|
16
|
+
|
|
17
|
+
function makeRootState(prefs = DEFAULT_PREFS, clusterReady = true): any {
|
|
18
|
+
stampCounter++;
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
clusterReady,
|
|
22
|
+
management: {
|
|
23
|
+
types: {
|
|
24
|
+
[MANAGEMENT.SETTING]: {
|
|
25
|
+
list: [
|
|
26
|
+
{
|
|
27
|
+
id: 'ui-performance',
|
|
28
|
+
value: JSON.stringify({ garbageCollection: prefs }),
|
|
29
|
+
metadata: { generation: stampCounter, resourceVersion: '1' },
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function makeEmptyRootState(): any {
|
|
39
|
+
return {
|
|
40
|
+
clusterReady: true,
|
|
41
|
+
management: { types: { [MANAGEMENT.SETTING]: { list: [] } } },
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function makeCtx(options: {
|
|
46
|
+
namespace?: string;
|
|
47
|
+
supportsGc?: boolean;
|
|
48
|
+
gcIgnoreTypes?: Record<string, boolean>;
|
|
49
|
+
prefs?: Partial<typeof DEFAULT_PREFS>;
|
|
50
|
+
dispatch?: jest.Mock;
|
|
51
|
+
countsByType?: Record<string, number>;
|
|
52
|
+
clusterReady?: boolean;
|
|
53
|
+
} = {}): any {
|
|
54
|
+
const {
|
|
55
|
+
namespace = 'teststore',
|
|
56
|
+
supportsGc = true,
|
|
57
|
+
gcIgnoreTypes = {},
|
|
58
|
+
prefs,
|
|
59
|
+
dispatch = jest.fn(),
|
|
60
|
+
countsByType = {},
|
|
61
|
+
clusterReady = true,
|
|
62
|
+
} = options;
|
|
63
|
+
|
|
64
|
+
const rootState = makeRootState(
|
|
65
|
+
prefs ? { ...DEFAULT_PREFS, ...prefs } : DEFAULT_PREFS,
|
|
66
|
+
clusterReady
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
state: { config: { supportsGc, namespace } },
|
|
71
|
+
rootState,
|
|
72
|
+
getters: {
|
|
73
|
+
gcIgnoreTypes,
|
|
74
|
+
all: () => [{
|
|
75
|
+
counts: Object.fromEntries(
|
|
76
|
+
Object.entries(countsByType).map(([t, c]) => [t, { summary: { count: c } }])
|
|
77
|
+
),
|
|
78
|
+
}],
|
|
79
|
+
},
|
|
80
|
+
dispatch,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Each test in the outer describe gets a fresh gc instance (gcLastRun = 0,
|
|
86
|
+
* empty caches) so tests do not interfere with each other via shared singleton state.
|
|
87
|
+
*/
|
|
88
|
+
describe('gc', () => {
|
|
89
|
+
let gc: GcInstance;
|
|
90
|
+
|
|
91
|
+
beforeEach(() => {
|
|
92
|
+
jest.resetModules();
|
|
93
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
|
|
94
|
+
gc = require('@shell/utils/gc/gc').default as GcInstance;
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
afterEach(() => {
|
|
98
|
+
jest.useRealTimers();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// ─── gcEnabledForStore ─────────────────────────────────────────────────────
|
|
102
|
+
|
|
103
|
+
describe('gcEnabledForStore', () => {
|
|
104
|
+
it.each([
|
|
105
|
+
{
|
|
106
|
+
desc: 'true when supportsGc is true', state: { config: { supportsGc: true } }, expected: true
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
desc: 'false when supportsGc is false', state: { config: { supportsGc: false } }, expected: false
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
desc: 'undefined when state is undefined', state: undefined, expected: undefined
|
|
113
|
+
},
|
|
114
|
+
])('returns $desc', ({ state, expected }) => {
|
|
115
|
+
expect(gc.gcEnabledForStore(state)).toBe(expected);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// ─── gcEnabledForType ──────────────────────────────────────────────────────
|
|
120
|
+
|
|
121
|
+
describe('gcEnabledForType', () => {
|
|
122
|
+
it.each([
|
|
123
|
+
{
|
|
124
|
+
desc: 'false when type is empty string', gcIgnoreTypes: {}, type: '', expected: false
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
desc: 'false when type is in gcIgnoreTypes', gcIgnoreTypes: { pods: true }, type: 'pods', expected: false
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
desc: 'true when type is non-empty and not ignored', gcIgnoreTypes: {}, type: 'deployments', expected: true
|
|
131
|
+
},
|
|
132
|
+
])('returns $desc', ({ gcIgnoreTypes, type, expected }) => {
|
|
133
|
+
expect(gc.gcEnabledForType({ getters: { gcIgnoreTypes } }, type)).toBe(expected);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// ─── gcEnabledSetting ──────────────────────────────────────────────────────
|
|
138
|
+
|
|
139
|
+
describe('gcEnabledSetting', () => {
|
|
140
|
+
it('returns true when GC is enabled in ui-performance setting', () => {
|
|
141
|
+
const ctx = { rootState: makeRootState({ ...DEFAULT_PREFS, enabled: true }) };
|
|
142
|
+
|
|
143
|
+
expect(gc.gcEnabledSetting(ctx)).toBe(true);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('returns false when GC is disabled in ui-performance setting', () => {
|
|
147
|
+
const ctx = { rootState: makeRootState({ ...DEFAULT_PREFS, enabled: false }) };
|
|
148
|
+
|
|
149
|
+
expect(gc.gcEnabledSetting(ctx)).toBe(false);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('returns undefined when ui-performance setting is absent', () => {
|
|
153
|
+
const ctx = { rootState: makeEmptyRootState() };
|
|
154
|
+
|
|
155
|
+
expect(gc.gcEnabledSetting(ctx)).toBeUndefined();
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// ─── gcEnabledAll ──────────────────────────────────────────────────────────
|
|
160
|
+
|
|
161
|
+
describe('gcEnabledAll', () => {
|
|
162
|
+
it.each([
|
|
163
|
+
{
|
|
164
|
+
desc: 'true when all checks pass', options: {}, type: 'deployments', expected: true
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
desc: 'false when store does not support GC', options: { supportsGc: false }, type: 'deployments', expected: false
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
desc: 'false when GC is disabled in settings', options: { prefs: { enabled: false } }, type: 'deployments', expected: false
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
desc: 'false when type is in gcIgnoreTypes', options: { gcIgnoreTypes: { schema: true } }, type: 'schema', expected: false
|
|
174
|
+
},
|
|
175
|
+
])('returns $desc', ({ options, type, expected }) => {
|
|
176
|
+
expect(gc.gcEnabledAll(makeCtx(options), type)).toBe(expected);
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// ─── gcEnabledInterval ─────────────────────────────────────────────────────
|
|
181
|
+
|
|
182
|
+
describe('gcEnabledInterval', () => {
|
|
183
|
+
it('returns enabledInterval and interval from settings', () => {
|
|
184
|
+
const ctx = {
|
|
185
|
+
rootState: makeRootState({
|
|
186
|
+
...DEFAULT_PREFS, enabledInterval: true, interval: 600
|
|
187
|
+
})
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
expect(gc.gcEnabledInterval(ctx)).toStrictEqual({ enabled: true, interval: 600 });
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('returns enabled: undefined and interval: 0 when setting is absent', () => {
|
|
194
|
+
const ctx = { rootState: makeEmptyRootState() };
|
|
195
|
+
|
|
196
|
+
expect(gc.gcEnabledInterval(ctx)).toStrictEqual({ enabled: undefined, interval: 0 });
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('returns interval: 0 when the interval value is falsy', () => {
|
|
200
|
+
const ctx = { rootState: makeRootState({ ...DEFAULT_PREFS, interval: 0 }) };
|
|
201
|
+
|
|
202
|
+
expect(gc.gcEnabledInterval(ctx)).toStrictEqual({ enabled: true, interval: 0 });
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// ─── gcEnabledRoute ────────────────────────────────────────────────────────
|
|
207
|
+
|
|
208
|
+
describe('gcEnabledRoute', () => {
|
|
209
|
+
it('returns enabledOnNavigate from settings', () => {
|
|
210
|
+
const ctx = { rootState: makeRootState({ ...DEFAULT_PREFS, enabledOnNavigate: false }) };
|
|
211
|
+
|
|
212
|
+
expect(gc.gcEnabledRoute(ctx)).toBe(false);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('returns undefined when setting is absent', () => {
|
|
216
|
+
const ctx = { rootState: makeEmptyRootState() };
|
|
217
|
+
|
|
218
|
+
expect(gc.gcEnabledRoute(ctx)).toBeUndefined();
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// ─── gcUpdateRouteChanged ──────────────────────────────────────────────────
|
|
223
|
+
|
|
224
|
+
describe('gcUpdateRouteChanged', () => {
|
|
225
|
+
/**
|
|
226
|
+
* Condition in garbageCollect:
|
|
227
|
+
* if (lastRouteChange < lastAccessed) → skip (resource is in current route)
|
|
228
|
+
*
|
|
229
|
+
* So: route changed at T1, resource accessed at T2 > T1
|
|
230
|
+
* → lastRouteChange (T1) < lastAccessed (T2) → GC skips this type.
|
|
231
|
+
*/
|
|
232
|
+
it('prevents a resource from being GC\'d when route changed before last access', () => {
|
|
233
|
+
const dispatch = jest.fn();
|
|
234
|
+
const type = 'pods';
|
|
235
|
+
const namespace = 'routetest';
|
|
236
|
+
|
|
237
|
+
jest.useFakeTimers();
|
|
238
|
+
|
|
239
|
+
// Route change at t=200_000 ms
|
|
240
|
+
jest.setSystemTime(200_000);
|
|
241
|
+
gc.gcUpdateRouteChanged();
|
|
242
|
+
|
|
243
|
+
// Resource accessed at t=300_000 ms (AFTER route change → in current route)
|
|
244
|
+
jest.setSystemTime(300_000);
|
|
245
|
+
gc.gcUpdateLastAccessed(makeCtx({ namespace }), type);
|
|
246
|
+
|
|
247
|
+
// GC runs at t=600_000 ms
|
|
248
|
+
// now - lastAccessed = 300_000 > maxAge(120_000) ✓ age check passes
|
|
249
|
+
// lastRouteChange(200_000) < lastAccessed(300_000) → skip (in current route)
|
|
250
|
+
jest.setSystemTime(600_000);
|
|
251
|
+
gc.garbageCollect(makeCtx({
|
|
252
|
+
namespace,
|
|
253
|
+
countsByType: { [type]: 1000 },
|
|
254
|
+
dispatch,
|
|
255
|
+
}));
|
|
256
|
+
|
|
257
|
+
expect(dispatch).not.toHaveBeenCalledWith('forgetType', type);
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// ─── garbageCollect ────────────────────────────────────────────────────────
|
|
262
|
+
|
|
263
|
+
describe('garbageCollect', () => {
|
|
264
|
+
it('skips when recently run (within GC_RE_RUN_GAP of 5 s)', () => {
|
|
265
|
+
const dispatch = jest.fn();
|
|
266
|
+
|
|
267
|
+
jest.useFakeTimers();
|
|
268
|
+
jest.setSystemTime(10_000);
|
|
269
|
+
|
|
270
|
+
// First call: cluster not ready → gcLastRun = 10_000
|
|
271
|
+
gc.garbageCollect(makeCtx({ clusterReady: false, dispatch }));
|
|
272
|
+
// Second call at same time: 10_000 - 10_000 = 0 < 5000 → skips
|
|
273
|
+
gc.garbageCollect(makeCtx({ dispatch }));
|
|
274
|
+
|
|
275
|
+
expect(dispatch).not.toHaveBeenCalledWith('forgetType', expect.any(String));
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it('skips when cluster is not ready', () => {
|
|
279
|
+
const dispatch = jest.fn();
|
|
280
|
+
|
|
281
|
+
jest.useFakeTimers();
|
|
282
|
+
jest.setSystemTime(10_000);
|
|
283
|
+
|
|
284
|
+
gc.garbageCollect(makeCtx({ clusterReady: false, dispatch }));
|
|
285
|
+
|
|
286
|
+
expect(dispatch).not.toHaveBeenCalledWith('forgetType', expect.any(String));
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it('skips when ui-performance setting is absent', () => {
|
|
290
|
+
const dispatch = jest.fn();
|
|
291
|
+
|
|
292
|
+
jest.useFakeTimers();
|
|
293
|
+
jest.setSystemTime(10_000);
|
|
294
|
+
|
|
295
|
+
const ctx = {
|
|
296
|
+
state: { config: { supportsGc: true, namespace: 'teststore' } },
|
|
297
|
+
rootState: makeEmptyRootState(),
|
|
298
|
+
getters: { gcIgnoreTypes: {} },
|
|
299
|
+
dispatch,
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
gc.garbageCollect(ctx);
|
|
303
|
+
|
|
304
|
+
expect(dispatch).not.toHaveBeenCalledWith('forgetType', expect.any(String));
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
it('skips a type listed in the explicit ignoreTypes parameter', () => {
|
|
308
|
+
const dispatch = jest.fn();
|
|
309
|
+
const type = 'configmaps';
|
|
310
|
+
const namespace = 'ignoretypetest';
|
|
311
|
+
|
|
312
|
+
jest.useFakeTimers();
|
|
313
|
+
|
|
314
|
+
jest.setSystemTime(200_000);
|
|
315
|
+
gc.gcUpdateLastAccessed(makeCtx({ namespace }), type);
|
|
316
|
+
|
|
317
|
+
jest.setSystemTime(300_000);
|
|
318
|
+
gc.gcUpdateRouteChanged();
|
|
319
|
+
|
|
320
|
+
jest.setSystemTime(400_000);
|
|
321
|
+
gc.garbageCollect(
|
|
322
|
+
makeCtx({
|
|
323
|
+
namespace, countsByType: { [type]: 1000 }, dispatch
|
|
324
|
+
}),
|
|
325
|
+
{ [type]: true }
|
|
326
|
+
);
|
|
327
|
+
|
|
328
|
+
expect(dispatch).not.toHaveBeenCalledWith('forgetType', type);
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
it('skips a type that was accessed within the ageThreshold', () => {
|
|
332
|
+
const dispatch = jest.fn();
|
|
333
|
+
const type = 'secrets';
|
|
334
|
+
const namespace = 'recenttest';
|
|
335
|
+
|
|
336
|
+
jest.useFakeTimers();
|
|
337
|
+
|
|
338
|
+
// Access 30 s ago (less than 120 s ageThreshold)
|
|
339
|
+
jest.setSystemTime(10_000);
|
|
340
|
+
gc.gcUpdateLastAccessed(makeCtx({ namespace }), type);
|
|
341
|
+
|
|
342
|
+
jest.setSystemTime(40_000); // 30 s later
|
|
343
|
+
gc.garbageCollect(makeCtx({
|
|
344
|
+
namespace, countsByType: { [type]: 1000 }, dispatch
|
|
345
|
+
}));
|
|
346
|
+
|
|
347
|
+
expect(dispatch).not.toHaveBeenCalledWith('forgetType', type);
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
it('skips a type whose count is below countThreshold', () => {
|
|
351
|
+
const dispatch = jest.fn();
|
|
352
|
+
const type = 'namespaces';
|
|
353
|
+
const namespace = 'lowcounttest';
|
|
354
|
+
|
|
355
|
+
jest.useFakeTimers();
|
|
356
|
+
|
|
357
|
+
jest.setSystemTime(200_000);
|
|
358
|
+
gc.gcUpdateLastAccessed(makeCtx({ namespace }), type);
|
|
359
|
+
|
|
360
|
+
jest.setSystemTime(300_000);
|
|
361
|
+
gc.gcUpdateRouteChanged();
|
|
362
|
+
|
|
363
|
+
jest.setSystemTime(400_000);
|
|
364
|
+
// count(100) < countThreshold(500) → skip
|
|
365
|
+
gc.garbageCollect(makeCtx({
|
|
366
|
+
namespace, countsByType: { [type]: 100 }, dispatch
|
|
367
|
+
}));
|
|
368
|
+
|
|
369
|
+
expect(dispatch).not.toHaveBeenCalledWith('forgetType', type);
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
it('dispatches forgetType for a resource that meets all GC criteria', () => {
|
|
373
|
+
const dispatch = jest.fn();
|
|
374
|
+
const type = 'events';
|
|
375
|
+
const namespace = 'gcqualifytest';
|
|
376
|
+
|
|
377
|
+
jest.useFakeTimers();
|
|
378
|
+
|
|
379
|
+
// Resource accessed at t=200_000
|
|
380
|
+
jest.setSystemTime(200_000);
|
|
381
|
+
gc.gcUpdateLastAccessed(makeCtx({ namespace }), type);
|
|
382
|
+
|
|
383
|
+
// Route changed at t=300_000 (AFTER access → lastRouteChange > lastAccessed → no skip)
|
|
384
|
+
jest.setSystemTime(300_000);
|
|
385
|
+
gc.gcUpdateRouteChanged();
|
|
386
|
+
|
|
387
|
+
// GC at t=400_000: now - lastAccessed = 200_000 > maxAge(120_000) ✓
|
|
388
|
+
jest.setSystemTime(400_000);
|
|
389
|
+
gc.garbageCollect(makeCtx({
|
|
390
|
+
namespace, countsByType: { [type]: 1000 }, dispatch
|
|
391
|
+
}));
|
|
392
|
+
|
|
393
|
+
expect(dispatch).toHaveBeenCalledWith('forgetType', type);
|
|
394
|
+
});
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
// ─── gcResetStore ──────────────────────────────────────────────────────────
|
|
398
|
+
|
|
399
|
+
describe('gcResetStore', () => {
|
|
400
|
+
it('removes all cached entries for the store, preventing forgetType dispatch', () => {
|
|
401
|
+
const dispatch = jest.fn();
|
|
402
|
+
const type = 'ingresses';
|
|
403
|
+
const namespace = 'resetstoretest';
|
|
404
|
+
|
|
405
|
+
jest.useFakeTimers();
|
|
406
|
+
|
|
407
|
+
jest.setSystemTime(200_000);
|
|
408
|
+
gc.gcUpdateLastAccessed(makeCtx({ namespace }), type);
|
|
409
|
+
|
|
410
|
+
jest.setSystemTime(300_000);
|
|
411
|
+
gc.gcUpdateRouteChanged();
|
|
412
|
+
|
|
413
|
+
gc.gcResetStore({ config: { namespace } });
|
|
414
|
+
|
|
415
|
+
jest.setSystemTime(400_000);
|
|
416
|
+
gc.garbageCollect(makeCtx({
|
|
417
|
+
namespace, countsByType: { [type]: 1000 }, dispatch
|
|
418
|
+
}));
|
|
419
|
+
|
|
420
|
+
expect(dispatch).not.toHaveBeenCalledWith('forgetType', type);
|
|
421
|
+
});
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
// ─── gcResetType ───────────────────────────────────────────────────────────
|
|
425
|
+
|
|
426
|
+
describe('gcResetType', () => {
|
|
427
|
+
it('removes a specific type so it is not GC\'d while leaving other types intact', () => {
|
|
428
|
+
const dispatch = jest.fn();
|
|
429
|
+
const typeA = 'storageclasses';
|
|
430
|
+
const typeB = 'persistentvolumes';
|
|
431
|
+
const namespace = 'resettypetest';
|
|
432
|
+
|
|
433
|
+
jest.useFakeTimers();
|
|
434
|
+
|
|
435
|
+
jest.setSystemTime(200_000);
|
|
436
|
+
gc.gcUpdateLastAccessed(makeCtx({ namespace }), typeA);
|
|
437
|
+
gc.gcUpdateLastAccessed(makeCtx({ namespace }), typeB);
|
|
438
|
+
|
|
439
|
+
jest.setSystemTime(300_000);
|
|
440
|
+
gc.gcUpdateRouteChanged();
|
|
441
|
+
|
|
442
|
+
gc.gcResetType({ config: { namespace } }, typeA);
|
|
443
|
+
|
|
444
|
+
jest.setSystemTime(400_000);
|
|
445
|
+
gc.garbageCollect(makeCtx({
|
|
446
|
+
namespace,
|
|
447
|
+
countsByType: { [typeA]: 1000, [typeB]: 1000 },
|
|
448
|
+
dispatch,
|
|
449
|
+
}));
|
|
450
|
+
|
|
451
|
+
expect(dispatch).not.toHaveBeenCalledWith('forgetType', typeA);
|
|
452
|
+
expect(dispatch).toHaveBeenCalledWith('forgetType', typeB);
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
it('is a no-op when the store has no cached entries', () => {
|
|
456
|
+
expect(() => {
|
|
457
|
+
gc.gcResetType({ config: { namespace: 'nonexistent-store' } }, 'pods');
|
|
458
|
+
}).not.toThrow();
|
|
459
|
+
});
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
// ─── gcUpdateLastAccessed ──────────────────────────────────────────────────
|
|
463
|
+
|
|
464
|
+
describe('gcUpdateLastAccessed', () => {
|
|
465
|
+
it('does not populate cache when GC is disabled for the store', () => {
|
|
466
|
+
const dispatch = jest.fn();
|
|
467
|
+
const type = 'replicasets';
|
|
468
|
+
const namespace = 'disabledgctest';
|
|
469
|
+
|
|
470
|
+
jest.useFakeTimers();
|
|
471
|
+
|
|
472
|
+
// supportsGc: false → gcEnabledAll = false → cache not updated
|
|
473
|
+
jest.setSystemTime(200_000);
|
|
474
|
+
gc.gcUpdateLastAccessed(makeCtx({ namespace, supportsGc: false }), type);
|
|
475
|
+
|
|
476
|
+
jest.setSystemTime(300_000);
|
|
477
|
+
gc.gcUpdateRouteChanged();
|
|
478
|
+
|
|
479
|
+
jest.setSystemTime(400_000);
|
|
480
|
+
gc.garbageCollect(makeCtx({
|
|
481
|
+
namespace, countsByType: { [type]: 1000 }, dispatch
|
|
482
|
+
}));
|
|
483
|
+
|
|
484
|
+
expect(dispatch).not.toHaveBeenCalledWith('forgetType', type);
|
|
485
|
+
});
|
|
486
|
+
});
|
|
487
|
+
});
|
package/utils/ingress.ts
CHANGED
|
@@ -56,7 +56,15 @@ class IngressDetailEditHelper {
|
|
|
56
56
|
return services.map((service) => ({
|
|
57
57
|
label: service.metadata.name,
|
|
58
58
|
value: service.metadata.name,
|
|
59
|
-
ports: service.spec.ports?.
|
|
59
|
+
ports: service.spec.ports?.flatMap((p: any) => {
|
|
60
|
+
const options = [p.port];
|
|
61
|
+
|
|
62
|
+
if (p.name) {
|
|
63
|
+
options.push(p.name);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return options;
|
|
67
|
+
})
|
|
60
68
|
}));
|
|
61
69
|
}
|
|
62
70
|
}
|
package/utils/object.js
CHANGED
|
@@ -163,6 +163,9 @@ returns an object with no key/value pairs (including nested) where the value is:
|
|
|
163
163
|
undefined
|
|
164
164
|
*/
|
|
165
165
|
export function cleanUp(obj) {
|
|
166
|
+
if ( !obj || typeof obj !== 'object') {
|
|
167
|
+
return obj;
|
|
168
|
+
}
|
|
166
169
|
Object.keys(obj).map((key) => {
|
|
167
170
|
const val = obj[key];
|
|
168
171
|
|
|
@@ -267,7 +270,7 @@ export function diff(from, to, preventNull = false) {
|
|
|
267
270
|
}
|
|
268
271
|
|
|
269
272
|
if (preventNull) {
|
|
270
|
-
|
|
273
|
+
// keys that come from "definedKeys" method are strings with "" chars inside... We need to clean them up
|
|
271
274
|
// so that we can access the value of the obj property
|
|
272
275
|
let key = k;
|
|
273
276
|
|
|
@@ -282,7 +285,24 @@ export function diff(from, to, preventNull = false) {
|
|
|
282
285
|
set(out, key, null);
|
|
283
286
|
}
|
|
284
287
|
} else {
|
|
285
|
-
|
|
288
|
+
const parts = splitObjectPath(k);
|
|
289
|
+
|
|
290
|
+
// Skip any missing nested key whose parent path in out is already a
|
|
291
|
+
// non-object. We don't want to attempt to null out the key that appeared
|
|
292
|
+
// in the diff when a pre-defined key
|
|
293
|
+
// (githubConfigSecret.github_token: '') gets updated to
|
|
294
|
+
// (githubConfigSecret: 'preexisting-secret')
|
|
295
|
+
const skip = parts.some((part) => {
|
|
296
|
+
const existingVal = out?.[part];
|
|
297
|
+
|
|
298
|
+
if (existingVal !== undefined && !isObject(existingVal)) {
|
|
299
|
+
return true;
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
if (!skip) {
|
|
304
|
+
set(out, k, null);
|
|
305
|
+
}
|
|
286
306
|
}
|
|
287
307
|
}
|
|
288
308
|
|
|
@@ -24,9 +24,10 @@ import { EXT_IDS } from '@shell/core/plugin';
|
|
|
24
24
|
import { ExtensionManager } from '@shell/types/extension-manager';
|
|
25
25
|
import { DEFAULT_PERF_SETTING } from '@shell/config/settings';
|
|
26
26
|
|
|
27
|
+
// This feature will be removed soon - https://github.com/rancher/dashboard/issues/17323
|
|
27
28
|
const homePageClusterFeature: PaginationFeature<PaginationFeatureHomePageClusterConfig> = {
|
|
28
29
|
version: 1,
|
|
29
|
-
enabled:
|
|
30
|
+
enabled: false,
|
|
30
31
|
configuration: {
|
|
31
32
|
threshold: 500, results: 250, pagesPerRow: 25
|
|
32
33
|
}
|
package/utils/provider.ts
CHANGED
|
@@ -4,6 +4,10 @@ export function getHostedProviders(context: ClusterProvisionerContext) {
|
|
|
4
4
|
return context?.$extension?.getProviders(context)?.filter((p: IClusterProvisioner) => p.group === 'hosted') || [];
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
+
export function getCAPIProviders(context: ClusterProvisionerContext) {
|
|
8
|
+
return context?.$extension?.getProviders(context)?.filter((p: IClusterProvisioner) => p.group === 'capi') || [];
|
|
9
|
+
}
|
|
10
|
+
|
|
7
11
|
export function isHostedProvider(context: ClusterProvisionerContext, provisioner: string) {
|
|
8
12
|
if (!provisioner) {
|
|
9
13
|
return false;
|
|
@@ -12,3 +16,11 @@ export function isHostedProvider(context: ClusterProvisionerContext, provisioner
|
|
|
12
16
|
|
|
13
17
|
return provisioners.has(provisioner.toLowerCase());
|
|
14
18
|
}
|
|
19
|
+
export function isCAPIProvider(context: ClusterProvisionerContext, provisioner: string) {
|
|
20
|
+
if (!provisioner) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
const provisioners = new Set(getCAPIProviders(context).map((p: IClusterProvisioner) => p.id.toLowerCase()));
|
|
24
|
+
|
|
25
|
+
return provisioners.has(provisioner.toLowerCase());
|
|
26
|
+
}
|
package/utils/string.js
CHANGED
|
@@ -349,10 +349,33 @@ export function xOfy(x, y) {
|
|
|
349
349
|
return `${ typeof x === 'number' ? x : '?' }/${ typeof y === 'number' ? y : '?' }`;
|
|
350
350
|
}
|
|
351
351
|
|
|
352
|
+
const BASE64_REGEX = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/;
|
|
353
|
+
|
|
352
354
|
export function isBase64(value) {
|
|
353
|
-
|
|
355
|
+
return BASE64_REGEX.test(value);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Checks if a value is a valid base64-encoded CA bundle.
|
|
360
|
+
* Unlike isBase64, this handles multiline base64 (e.g. openssl wraps at 76 chars)
|
|
361
|
+
* and rejects short strings that could be false positives.
|
|
362
|
+
* @param {string} value
|
|
363
|
+
* @returns {boolean}
|
|
364
|
+
*/
|
|
365
|
+
export function isBase64EncodedCert(value) {
|
|
366
|
+
if (!value || typeof value !== 'string') {
|
|
367
|
+
return false;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Strip whitespace to handle line-wrapped base64 output
|
|
371
|
+
const stripped = value.replace(/\s/g, '');
|
|
372
|
+
|
|
373
|
+
// CA certs are long enough that legitimate base64 will always exceed this
|
|
374
|
+
if (stripped.length < 16) {
|
|
375
|
+
return false;
|
|
376
|
+
}
|
|
354
377
|
|
|
355
|
-
return
|
|
378
|
+
return BASE64_REGEX.test(stripped);
|
|
356
379
|
}
|
|
357
380
|
|
|
358
381
|
export function generateRandomAlphaString(length) {
|
package/utils/uiplugins.ts
CHANGED
|
@@ -180,18 +180,19 @@ export async function getHelmRepositoryExact(store: any, url: string): Promise<H
|
|
|
180
180
|
/**
|
|
181
181
|
*
|
|
182
182
|
* @param store Vue store
|
|
183
|
-
* @param urlRegexes Regex to match
|
|
183
|
+
* @param urlRegexes Regex to match against the repository's urls
|
|
184
184
|
* @param catalogImages Catalog images to match against the repository's labels
|
|
185
185
|
* @returns HelmRepository
|
|
186
186
|
*/
|
|
187
187
|
export async function getHelmRepositoryMatch(store: any, urlRegexes: string[], catalogImages: string[]): Promise<HelmRepository> {
|
|
188
188
|
return await getHelmRepository(store, (repository: any) => {
|
|
189
|
-
// if installed from rancher/ui-plugin-catalog or rancher/ui-extension-harvester-ui-extension
|
|
190
189
|
const catalog = repository?.metadata?.labels?.[UI_PLUGIN_LABELS.CATALOG_IMAGE] || '';
|
|
191
190
|
|
|
192
|
-
if
|
|
191
|
+
// if installed from rancher/ui-plugin-catalog or rancher/ui-extension-harvester-ui-extension
|
|
192
|
+
if (catalog && catalogImages.includes(catalog)) {
|
|
193
193
|
return true;
|
|
194
194
|
}
|
|
195
|
+
|
|
195
196
|
const target = repository.spec?.gitBranch ? repository.spec?.gitRepo : repository.spec?.url;
|
|
196
197
|
|
|
197
198
|
return matchesSomeRegex(target, urlRegexes);
|
|
@@ -272,8 +273,7 @@ export async function createHelmRepository(store: any, name: string, url: string
|
|
|
272
273
|
});
|
|
273
274
|
|
|
274
275
|
tries++;
|
|
275
|
-
|
|
276
|
-
const downloaded = repo.status.conditions.find((s: any) => s.type === 'Downloaded');
|
|
276
|
+
const downloaded = repo.status?.conditions.find((s: any) => s.type === 'Downloaded');
|
|
277
277
|
|
|
278
278
|
console.log(`Waiting for helm repository to be downloaded... try ${ tries } time(s).`); // eslint-disable-line no-console
|
|
279
279
|
|