@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,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
|
+
});
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import perfSettingUtils from '@shell/utils/perf-setting.utils';
|
|
2
|
+
import { PerfSettings } from '@shell/config/settings';
|
|
3
|
+
|
|
4
|
+
const makePerfSettings = (incrementalLoading: boolean, manualRefresh: boolean): PerfSettings => ({
|
|
5
|
+
inactivity: { enabled: false, threshold: 0 },
|
|
6
|
+
incrementalLoading: { enabled: incrementalLoading, threshold: 0 },
|
|
7
|
+
manualRefresh: { enabled: manualRefresh, threshold: 0 },
|
|
8
|
+
disableWebsocketNotification: false,
|
|
9
|
+
garbageCollection: {} as any,
|
|
10
|
+
forceNsFilterV2: null,
|
|
11
|
+
advancedWorker: {},
|
|
12
|
+
kubeAPI: { warningHeader: { separator: '', notificationBlockList: [] } },
|
|
13
|
+
serverPagination: {} as any,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe('perf-setting.utils', () => {
|
|
17
|
+
describe('incrementalLoadingUtils.isEnabled', () => {
|
|
18
|
+
it.each([
|
|
19
|
+
{
|
|
20
|
+
desc: 'SSP disabled, performance setting enabled → enabled',
|
|
21
|
+
paginationEnabled: false,
|
|
22
|
+
perfEnabled: true,
|
|
23
|
+
expected: true,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
desc: 'SSP disabled, performance setting disabled → disabled',
|
|
27
|
+
paginationEnabled: false,
|
|
28
|
+
perfEnabled: false,
|
|
29
|
+
expected: false,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
desc: 'SSP enabled takes precedence even if performance setting enabled → disabled',
|
|
33
|
+
paginationEnabled: true,
|
|
34
|
+
perfEnabled: true,
|
|
35
|
+
expected: false,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
desc: 'SSP enabled, performance setting disabled → disabled',
|
|
39
|
+
paginationEnabled: true,
|
|
40
|
+
perfEnabled: false,
|
|
41
|
+
expected: false,
|
|
42
|
+
},
|
|
43
|
+
])('$desc', ({ paginationEnabled, perfEnabled, expected }) => {
|
|
44
|
+
const settings = makePerfSettings(perfEnabled, false);
|
|
45
|
+
|
|
46
|
+
expect(perfSettingUtils.incrementalLoadingUtils.isEnabled(paginationEnabled, settings)).toStrictEqual(expected);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe('manualRefreshUtils.isEnabled', () => {
|
|
51
|
+
it.each([
|
|
52
|
+
{
|
|
53
|
+
desc: 'SSP disabled, performance setting enabled → enabled',
|
|
54
|
+
paginationEnabled: false,
|
|
55
|
+
perfEnabled: true,
|
|
56
|
+
expected: true,
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
desc: 'SSP disabled, performance setting disabled → disabled',
|
|
60
|
+
paginationEnabled: false,
|
|
61
|
+
perfEnabled: false,
|
|
62
|
+
expected: false,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
desc: 'SSP enabled takes precedence even if performance setting enabled → disabled',
|
|
66
|
+
paginationEnabled: true,
|
|
67
|
+
perfEnabled: true,
|
|
68
|
+
expected: false,
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
desc: 'SSP enabled, performance setting disabled → disabled',
|
|
72
|
+
paginationEnabled: true,
|
|
73
|
+
perfEnabled: false,
|
|
74
|
+
expected: false,
|
|
75
|
+
},
|
|
76
|
+
])('$desc', ({ paginationEnabled, perfEnabled, expected }) => {
|
|
77
|
+
const settings = makePerfSettings(false, perfEnabled);
|
|
78
|
+
|
|
79
|
+
expect(perfSettingUtils.manualRefreshUtils.isEnabled(paginationEnabled, settings)).toStrictEqual(expected);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe('incrementalLoadingUtils and manualRefreshUtils are independent instances', () => {
|
|
84
|
+
it('incrementalLoading setting does not affect manualRefreshUtils', () => {
|
|
85
|
+
const settings = makePerfSettings(true, false);
|
|
86
|
+
|
|
87
|
+
expect(perfSettingUtils.incrementalLoadingUtils.isEnabled(false, settings)).toStrictEqual(true);
|
|
88
|
+
expect(perfSettingUtils.manualRefreshUtils.isEnabled(false, settings)).toStrictEqual(false);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('manualRefresh setting does not affect incrementalLoadingUtils', () => {
|
|
92
|
+
const settings = makePerfSettings(false, true);
|
|
93
|
+
|
|
94
|
+
expect(perfSettingUtils.incrementalLoadingUtils.isEnabled(false, settings)).toStrictEqual(false);
|
|
95
|
+
expect(perfSettingUtils.manualRefreshUtils.isEnabled(false, settings)).toStrictEqual(true);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
});
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import {
|
|
2
|
+
alternateKey,
|
|
3
|
+
isAlternate,
|
|
4
|
+
isMore,
|
|
5
|
+
isRange,
|
|
6
|
+
moreKey,
|
|
7
|
+
rangeKey,
|
|
8
|
+
suppressContextMenu,
|
|
9
|
+
version,
|
|
10
|
+
} from '@shell/utils/platform';
|
|
11
|
+
|
|
12
|
+
describe('platform utils', () => {
|
|
13
|
+
describe('isAlternate', () => {
|
|
14
|
+
it.each([
|
|
15
|
+
{
|
|
16
|
+
desc: 'returns true when the alternate key is pressed',
|
|
17
|
+
event: { [alternateKey]: true },
|
|
18
|
+
expected: true,
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
desc: 'returns false when the alternate key is not pressed',
|
|
22
|
+
event: { [alternateKey]: false },
|
|
23
|
+
expected: false,
|
|
24
|
+
},
|
|
25
|
+
])('$desc', ({ event, expected }) => {
|
|
26
|
+
expect(isAlternate(event)).toStrictEqual(expected);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe('isMore', () => {
|
|
31
|
+
it.each([
|
|
32
|
+
{
|
|
33
|
+
desc: 'returns true when the more key is pressed',
|
|
34
|
+
event: { [moreKey]: true },
|
|
35
|
+
expected: true,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
desc: 'returns false when the more key is not pressed',
|
|
39
|
+
event: { [moreKey]: false },
|
|
40
|
+
expected: false,
|
|
41
|
+
},
|
|
42
|
+
])('$desc', ({ event, expected }) => {
|
|
43
|
+
expect(isMore(event)).toStrictEqual(expected);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe('isRange', () => {
|
|
48
|
+
it.each([
|
|
49
|
+
{
|
|
50
|
+
desc: 'returns true when the range key (shift) is pressed',
|
|
51
|
+
event: { [rangeKey]: true },
|
|
52
|
+
expected: true,
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
desc: 'returns false when the range key is not pressed',
|
|
56
|
+
event: { [rangeKey]: false },
|
|
57
|
+
expected: false,
|
|
58
|
+
},
|
|
59
|
+
])('$desc', ({ event, expected }) => {
|
|
60
|
+
expect(isRange(event)).toStrictEqual(expected);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe('suppressContextMenu', () => {
|
|
65
|
+
it.each([
|
|
66
|
+
{
|
|
67
|
+
desc: 'returns true when ctrlKey is pressed and mouse button is 2',
|
|
68
|
+
event: { ctrlKey: true, button: 2 },
|
|
69
|
+
expected: true,
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
desc: 'returns false when ctrlKey is not pressed',
|
|
73
|
+
event: { ctrlKey: false, button: 2 },
|
|
74
|
+
expected: false,
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
desc: 'returns false when mouse button is not 2',
|
|
78
|
+
event: { ctrlKey: true, button: 0 },
|
|
79
|
+
expected: false,
|
|
80
|
+
},
|
|
81
|
+
])('$desc', ({ event, expected }) => {
|
|
82
|
+
expect(suppressContextMenu(event)).toStrictEqual(expected);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
describe('version', () => {
|
|
87
|
+
it('returns null when userAgent does not contain a Version/ segment', () => {
|
|
88
|
+
expect(version()).toBeNull();
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
});
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import PollerSequential from '@shell/utils/poller-sequential';
|
|
2
|
+
|
|
3
|
+
describe('pollerSequential', () => {
|
|
4
|
+
let fn: jest.Mock;
|
|
5
|
+
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
jest.useFakeTimers();
|
|
8
|
+
fn = jest.fn().mockResolvedValue(undefined);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
jest.useRealTimers();
|
|
13
|
+
jest.restoreAllMocks();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe('constructor', () => {
|
|
17
|
+
it('should store fn, pollRateMs and maxRetries', () => {
|
|
18
|
+
const poller = new PollerSequential(fn, 1000, 5);
|
|
19
|
+
|
|
20
|
+
expect(poller.fn).toBe(fn);
|
|
21
|
+
expect(poller.pollRateMs).toBe(1000);
|
|
22
|
+
expect(poller.maxRetries).toBe(5);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should default maxRetries to POSITIVE_INFINITY', () => {
|
|
26
|
+
const poller = new PollerSequential(fn, 500);
|
|
27
|
+
|
|
28
|
+
expect(poller.maxRetries).toBe(Number.POSITIVE_INFINITY);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should substitute a no-op when fn is falsy', () => {
|
|
32
|
+
const poller = new PollerSequential(null as any, 500);
|
|
33
|
+
|
|
34
|
+
expect(typeof poller.fn).toBe('function');
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should initialise tryCount to 0', () => {
|
|
38
|
+
const poller = new PollerSequential(fn, 1000);
|
|
39
|
+
|
|
40
|
+
expect(poller.tryCount).toBe(0);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should initialise timeoutId to undefined', () => {
|
|
44
|
+
const poller = new PollerSequential(fn, 1000);
|
|
45
|
+
|
|
46
|
+
expect(poller.timeoutId).toBeUndefined();
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe('start', () => {
|
|
51
|
+
it('should set timeoutId after start', () => {
|
|
52
|
+
const poller = new PollerSequential(fn, 1000);
|
|
53
|
+
|
|
54
|
+
poller.start();
|
|
55
|
+
|
|
56
|
+
expect(poller.timeoutId).toBeDefined();
|
|
57
|
+
|
|
58
|
+
poller.stop();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should not call fn immediately (delayed unlike Poller)', () => {
|
|
62
|
+
const poller = new PollerSequential(fn, 1000);
|
|
63
|
+
|
|
64
|
+
poller.start();
|
|
65
|
+
|
|
66
|
+
expect(fn).not.toHaveBeenCalled();
|
|
67
|
+
|
|
68
|
+
poller.stop();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('should stop and restart when start is called while already running', () => {
|
|
72
|
+
const poller = new PollerSequential(fn, 1000);
|
|
73
|
+
const stopSpy = jest.spyOn(poller, 'stop');
|
|
74
|
+
|
|
75
|
+
poller.start();
|
|
76
|
+
poller.start();
|
|
77
|
+
|
|
78
|
+
expect(stopSpy).toHaveBeenCalledWith();
|
|
79
|
+
|
|
80
|
+
poller.stop();
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
describe('stop', () => {
|
|
85
|
+
it('should clear timeoutId after stop', () => {
|
|
86
|
+
const poller = new PollerSequential(fn, 1000);
|
|
87
|
+
|
|
88
|
+
poller.start();
|
|
89
|
+
poller.stop();
|
|
90
|
+
|
|
91
|
+
expect(poller.timeoutId).toBeUndefined();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('should not call fn after stop', async() => {
|
|
95
|
+
const poller = new PollerSequential(fn, 1000);
|
|
96
|
+
|
|
97
|
+
poller.start();
|
|
98
|
+
poller.stop();
|
|
99
|
+
jest.advanceTimersByTime(10000);
|
|
100
|
+
|
|
101
|
+
expect(fn).not.toHaveBeenCalled();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('should be safe to call stop when not running', () => {
|
|
105
|
+
const poller = new PollerSequential(fn, 1000);
|
|
106
|
+
|
|
107
|
+
expect(() => poller.stop()).not.toThrow();
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe('_poll', () => {
|
|
112
|
+
it('should not continue polling if timeoutId has been cleared', async() => {
|
|
113
|
+
const poller = new PollerSequential(fn, 1000);
|
|
114
|
+
|
|
115
|
+
poller.timeoutId = undefined;
|
|
116
|
+
poller._poll();
|
|
117
|
+
|
|
118
|
+
jest.advanceTimersByTime(5000);
|
|
119
|
+
|
|
120
|
+
expect(fn).not.toHaveBeenCalled();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('should clear timeoutId and schedule next poll', () => {
|
|
124
|
+
const poller = new PollerSequential(fn, 1000);
|
|
125
|
+
|
|
126
|
+
poller.start();
|
|
127
|
+
expect(poller.timeoutId).toBeDefined();
|
|
128
|
+
|
|
129
|
+
const firstId = poller.timeoutId;
|
|
130
|
+
|
|
131
|
+
// Advance past the initial delay to trigger _poll
|
|
132
|
+
jest.advanceTimersByTime(1000);
|
|
133
|
+
|
|
134
|
+
// _poll should have set a new timeout (different from the first)
|
|
135
|
+
expect(poller.timeoutId).toBeDefined();
|
|
136
|
+
// timeoutId should have changed since _poll calls stop then sets a new one
|
|
137
|
+
expect(poller.timeoutId).not.toBe(firstId);
|
|
138
|
+
|
|
139
|
+
poller.stop();
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
describe('_intervalMethod', () => {
|
|
144
|
+
it('should reset tryCount to 0 after a successful call', async() => {
|
|
145
|
+
const poller = new PollerSequential(fn, 1000);
|
|
146
|
+
|
|
147
|
+
poller.tryCount = 3;
|
|
148
|
+
await poller._intervalMethod();
|
|
149
|
+
|
|
150
|
+
expect(poller.tryCount).toBe(0);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('should increment tryCount on each error', async() => {
|
|
154
|
+
fn.mockRejectedValue(new Error('fail'));
|
|
155
|
+
const poller = new PollerSequential(fn, 1000, 5);
|
|
156
|
+
|
|
157
|
+
await poller._intervalMethod();
|
|
158
|
+
expect(poller.tryCount).toBe(1);
|
|
159
|
+
|
|
160
|
+
await poller._intervalMethod();
|
|
161
|
+
expect(poller.tryCount).toBe(2);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('should stop when tryCount reaches maxRetries', async() => {
|
|
165
|
+
fn.mockRejectedValue(new Error('fail'));
|
|
166
|
+
const poller = new PollerSequential(fn, 1000, 3);
|
|
167
|
+
const stopSpy = jest.spyOn(poller, 'stop');
|
|
168
|
+
|
|
169
|
+
await poller._intervalMethod();
|
|
170
|
+
await poller._intervalMethod();
|
|
171
|
+
expect(stopSpy).not.toHaveBeenCalled();
|
|
172
|
+
|
|
173
|
+
await poller._intervalMethod();
|
|
174
|
+
expect(stopSpy).toHaveBeenCalledTimes(1);
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
});
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import Poller from '@shell/utils/poller';
|
|
2
|
+
|
|
3
|
+
describe('poller', () => {
|
|
4
|
+
let fn: jest.Mock;
|
|
5
|
+
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
jest.useFakeTimers();
|
|
8
|
+
fn = jest.fn().mockResolvedValue(undefined);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
jest.useRealTimers();
|
|
13
|
+
jest.restoreAllMocks();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe('constructor', () => {
|
|
17
|
+
it('should store fn, pollRateMs and maxRetries', () => {
|
|
18
|
+
const poller = new Poller(fn, 1000, 5);
|
|
19
|
+
|
|
20
|
+
expect(poller.fn).toBe(fn);
|
|
21
|
+
expect(poller.pollRateMs).toBe(1000);
|
|
22
|
+
expect(poller.maxRetries).toBe(5);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should default maxRetries to POSITIVE_INFINITY', () => {
|
|
26
|
+
const poller = new Poller(fn, 500);
|
|
27
|
+
|
|
28
|
+
expect(poller.maxRetries).toBe(Number.POSITIVE_INFINITY);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should substitute a no-op when fn is falsy', () => {
|
|
32
|
+
const poller = new Poller(null as any, 500);
|
|
33
|
+
|
|
34
|
+
expect(typeof poller.fn).toBe('function');
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should initialise tryCount to 0', () => {
|
|
38
|
+
const poller = new Poller(fn, 1000);
|
|
39
|
+
|
|
40
|
+
expect(poller.tryCount).toBe(0);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should initialise intervalId to undefined', () => {
|
|
44
|
+
const poller = new Poller(fn, 1000);
|
|
45
|
+
|
|
46
|
+
expect(poller.intervalId).toBeUndefined();
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe('start', () => {
|
|
51
|
+
it('should call fn immediately when started', () => {
|
|
52
|
+
const poller = new Poller(fn, 1000);
|
|
53
|
+
|
|
54
|
+
poller.start();
|
|
55
|
+
|
|
56
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should set intervalId after start', () => {
|
|
60
|
+
const poller = new Poller(fn, 1000);
|
|
61
|
+
|
|
62
|
+
poller.start();
|
|
63
|
+
|
|
64
|
+
expect(poller.intervalId).toBeDefined();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should call fn again after each poll interval', async() => {
|
|
68
|
+
const poller = new Poller(fn, 1000);
|
|
69
|
+
|
|
70
|
+
poller.start();
|
|
71
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
72
|
+
|
|
73
|
+
jest.advanceTimersByTime(1000);
|
|
74
|
+
expect(fn).toHaveBeenCalledTimes(2);
|
|
75
|
+
|
|
76
|
+
jest.advanceTimersByTime(1000);
|
|
77
|
+
expect(fn).toHaveBeenCalledTimes(3);
|
|
78
|
+
|
|
79
|
+
poller.stop();
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('should stop and restart when start is called while already running', () => {
|
|
83
|
+
const poller = new Poller(fn, 1000);
|
|
84
|
+
const stopSpy = jest.spyOn(poller, 'stop');
|
|
85
|
+
|
|
86
|
+
poller.start();
|
|
87
|
+
poller.start();
|
|
88
|
+
|
|
89
|
+
expect(stopSpy).toHaveBeenCalledWith();
|
|
90
|
+
|
|
91
|
+
poller.stop();
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
describe('stop', () => {
|
|
96
|
+
it('should clear intervalId after stop', () => {
|
|
97
|
+
const poller = new Poller(fn, 1000);
|
|
98
|
+
|
|
99
|
+
poller.start();
|
|
100
|
+
poller.stop();
|
|
101
|
+
|
|
102
|
+
expect(poller.intervalId).toBeUndefined();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should not call fn after stop', () => {
|
|
106
|
+
const poller = new Poller(fn, 1000);
|
|
107
|
+
|
|
108
|
+
poller.start();
|
|
109
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
110
|
+
|
|
111
|
+
poller.stop();
|
|
112
|
+
jest.advanceTimersByTime(5000);
|
|
113
|
+
|
|
114
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('should be safe to call stop when not running', () => {
|
|
118
|
+
const poller = new Poller(fn, 1000);
|
|
119
|
+
|
|
120
|
+
expect(() => poller.stop()).not.toThrow();
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
describe('_intervalMethod', () => {
|
|
125
|
+
it('should reset tryCount to 0 after a successful call', async() => {
|
|
126
|
+
const poller = new Poller(fn, 1000);
|
|
127
|
+
|
|
128
|
+
poller.tryCount = 3;
|
|
129
|
+
await poller._intervalMethod();
|
|
130
|
+
|
|
131
|
+
expect(poller.tryCount).toBe(0);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('should increment tryCount on each error', async() => {
|
|
135
|
+
fn.mockRejectedValue(new Error('fail'));
|
|
136
|
+
const poller = new Poller(fn, 1000, 5);
|
|
137
|
+
|
|
138
|
+
await poller._intervalMethod();
|
|
139
|
+
expect(poller.tryCount).toBe(1);
|
|
140
|
+
|
|
141
|
+
await poller._intervalMethod();
|
|
142
|
+
expect(poller.tryCount).toBe(2);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('should stop when tryCount reaches maxRetries', async() => {
|
|
146
|
+
fn.mockRejectedValue(new Error('fail'));
|
|
147
|
+
const poller = new Poller(fn, 1000, 3);
|
|
148
|
+
const stopSpy = jest.spyOn(poller, 'stop');
|
|
149
|
+
|
|
150
|
+
await poller._intervalMethod();
|
|
151
|
+
await poller._intervalMethod();
|
|
152
|
+
expect(stopSpy).not.toHaveBeenCalled();
|
|
153
|
+
|
|
154
|
+
await poller._intervalMethod();
|
|
155
|
+
expect(stopSpy).toHaveBeenCalledTimes(1);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('should not stop before maxRetries is reached', async() => {
|
|
159
|
+
fn.mockRejectedValue(new Error('fail'));
|
|
160
|
+
const poller = new Poller(fn, 1000, 5);
|
|
161
|
+
const stopSpy = jest.spyOn(poller, 'stop');
|
|
162
|
+
|
|
163
|
+
for (let i = 0; i < 4; i++) {
|
|
164
|
+
await poller._intervalMethod();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
expect(stopSpy).not.toHaveBeenCalled();
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
});
|