@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,232 @@
|
|
|
1
|
+
import Queue from '@shell/utils/queue';
|
|
2
|
+
|
|
3
|
+
describe('queue', () => {
|
|
4
|
+
describe('new queue', () => {
|
|
5
|
+
it('starts with length 0', () => {
|
|
6
|
+
const q = new Queue();
|
|
7
|
+
|
|
8
|
+
expect(q.getLength()).toStrictEqual(0);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('starts empty', () => {
|
|
12
|
+
const q = new Queue();
|
|
13
|
+
|
|
14
|
+
expect(q.isEmpty()).toStrictEqual(true);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('peek returns undefined on empty queue', () => {
|
|
18
|
+
const q = new Queue();
|
|
19
|
+
|
|
20
|
+
expect(q.peek()).toBeUndefined();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('dequeue returns undefined on empty queue', () => {
|
|
24
|
+
const q = new Queue();
|
|
25
|
+
|
|
26
|
+
expect(q.dequeue()).toBeUndefined();
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe('enqueue', () => {
|
|
31
|
+
it('increases length by 1', () => {
|
|
32
|
+
const q = new Queue();
|
|
33
|
+
|
|
34
|
+
q.enqueue('a');
|
|
35
|
+
expect(q.getLength()).toStrictEqual(1);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('marks queue as non-empty after first item', () => {
|
|
39
|
+
const q = new Queue();
|
|
40
|
+
|
|
41
|
+
q.enqueue('x');
|
|
42
|
+
expect(q.isEmpty()).toStrictEqual(false);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('accepts arbitrary values', () => {
|
|
46
|
+
const q = new Queue();
|
|
47
|
+
|
|
48
|
+
q.enqueue(42);
|
|
49
|
+
q.enqueue(null);
|
|
50
|
+
q.enqueue({ key: 'val' });
|
|
51
|
+
expect(q.getLength()).toStrictEqual(3);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('dequeue', () => {
|
|
56
|
+
it('returns the enqueued item', () => {
|
|
57
|
+
const q = new Queue();
|
|
58
|
+
|
|
59
|
+
q.enqueue('hello');
|
|
60
|
+
expect(q.dequeue()).toStrictEqual('hello');
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('decreases length by 1', () => {
|
|
64
|
+
const q = new Queue();
|
|
65
|
+
|
|
66
|
+
q.enqueue('a');
|
|
67
|
+
q.enqueue('b');
|
|
68
|
+
q.dequeue();
|
|
69
|
+
expect(q.getLength()).toStrictEqual(1);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('empties the queue when last item is removed', () => {
|
|
73
|
+
const q = new Queue();
|
|
74
|
+
|
|
75
|
+
q.enqueue('only');
|
|
76
|
+
q.dequeue();
|
|
77
|
+
expect(q.isEmpty()).toStrictEqual(true);
|
|
78
|
+
expect(q.getLength()).toStrictEqual(0);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('maintains FIFO order', () => {
|
|
82
|
+
const q = new Queue();
|
|
83
|
+
|
|
84
|
+
q.enqueue('first');
|
|
85
|
+
q.enqueue('second');
|
|
86
|
+
q.enqueue('third');
|
|
87
|
+
|
|
88
|
+
expect(q.dequeue()).toStrictEqual('first');
|
|
89
|
+
expect(q.dequeue()).toStrictEqual('second');
|
|
90
|
+
expect(q.dequeue()).toStrictEqual('third');
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('returns undefined after queue is drained', () => {
|
|
94
|
+
const q = new Queue();
|
|
95
|
+
|
|
96
|
+
q.enqueue('item');
|
|
97
|
+
q.dequeue();
|
|
98
|
+
expect(q.dequeue()).toBeUndefined();
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe('peek', () => {
|
|
103
|
+
it('returns the front item without removing it', () => {
|
|
104
|
+
const q = new Queue();
|
|
105
|
+
|
|
106
|
+
q.enqueue('front');
|
|
107
|
+
q.enqueue('back');
|
|
108
|
+
expect(q.peek()).toStrictEqual('front');
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('does not change the queue length', () => {
|
|
112
|
+
const q = new Queue();
|
|
113
|
+
|
|
114
|
+
q.enqueue('a');
|
|
115
|
+
q.peek();
|
|
116
|
+
expect(q.getLength()).toStrictEqual(1);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('reflects the new front after a dequeue', () => {
|
|
120
|
+
const q = new Queue();
|
|
121
|
+
|
|
122
|
+
q.enqueue('first');
|
|
123
|
+
q.enqueue('second');
|
|
124
|
+
q.dequeue();
|
|
125
|
+
expect(q.peek()).toStrictEqual('second');
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
describe('clear', () => {
|
|
130
|
+
it('empties a populated queue', () => {
|
|
131
|
+
const q = new Queue();
|
|
132
|
+
|
|
133
|
+
q.enqueue('a');
|
|
134
|
+
q.enqueue('b');
|
|
135
|
+
q.clear();
|
|
136
|
+
expect(q.isEmpty()).toStrictEqual(true);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('resets length to 0', () => {
|
|
140
|
+
const q = new Queue();
|
|
141
|
+
|
|
142
|
+
q.enqueue(1);
|
|
143
|
+
q.enqueue(2);
|
|
144
|
+
q.enqueue(3);
|
|
145
|
+
q.clear();
|
|
146
|
+
expect(q.getLength()).toStrictEqual(0);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('allows enqueue after clear', () => {
|
|
150
|
+
const q = new Queue();
|
|
151
|
+
|
|
152
|
+
q.enqueue('before');
|
|
153
|
+
q.clear();
|
|
154
|
+
q.enqueue('after');
|
|
155
|
+
expect(q.dequeue()).toStrictEqual('after');
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('is safe to call on an already-empty queue', () => {
|
|
159
|
+
const q = new Queue();
|
|
160
|
+
|
|
161
|
+
q.clear();
|
|
162
|
+
expect(q.isEmpty()).toStrictEqual(true);
|
|
163
|
+
expect(q.getLength()).toStrictEqual(0);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
describe('mixed operations', () => {
|
|
168
|
+
it('handles interleaved enqueue and dequeue correctly', () => {
|
|
169
|
+
const q = new Queue();
|
|
170
|
+
|
|
171
|
+
q.enqueue('a');
|
|
172
|
+
q.enqueue('b');
|
|
173
|
+
expect(q.dequeue()).toStrictEqual('a');
|
|
174
|
+
q.enqueue('c');
|
|
175
|
+
expect(q.dequeue()).toStrictEqual('b');
|
|
176
|
+
expect(q.dequeue()).toStrictEqual('c');
|
|
177
|
+
expect(q.isEmpty()).toStrictEqual(true);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('tracks length correctly through mixed operations', () => {
|
|
181
|
+
const q = new Queue();
|
|
182
|
+
|
|
183
|
+
q.enqueue(1);
|
|
184
|
+
q.enqueue(2);
|
|
185
|
+
q.enqueue(3);
|
|
186
|
+
expect(q.getLength()).toStrictEqual(3);
|
|
187
|
+
|
|
188
|
+
q.dequeue();
|
|
189
|
+
expect(q.getLength()).toStrictEqual(2);
|
|
190
|
+
|
|
191
|
+
q.enqueue(4);
|
|
192
|
+
expect(q.getLength()).toStrictEqual(3);
|
|
193
|
+
|
|
194
|
+
q.dequeue();
|
|
195
|
+
q.dequeue();
|
|
196
|
+
expect(q.getLength()).toStrictEqual(1);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('compacts the backing array when threshold is reached', () => {
|
|
200
|
+
// The implementation slices when ++offset * 2 >= queue.length.
|
|
201
|
+
// With 4 items: after the 2nd dequeue offset*2 (4) reaches length (4),
|
|
202
|
+
// triggering a compaction so the backing array is reset.
|
|
203
|
+
const q = new Queue();
|
|
204
|
+
|
|
205
|
+
q.enqueue('w');
|
|
206
|
+
q.enqueue('x');
|
|
207
|
+
q.enqueue('y');
|
|
208
|
+
q.enqueue('z');
|
|
209
|
+
|
|
210
|
+
expect(q.dequeue()).toStrictEqual('w'); // offset=1, 1*2=2 < 4 — no compaction yet
|
|
211
|
+
expect(q.dequeue()).toStrictEqual('x'); // offset=2, 2*2=4 >= 4 — compaction!
|
|
212
|
+
// After compaction: backing array = ['y','z'], offset=0
|
|
213
|
+
expect(q.getLength()).toStrictEqual(2);
|
|
214
|
+
expect(q.peek()).toStrictEqual('y');
|
|
215
|
+
expect(q.dequeue()).toStrictEqual('y');
|
|
216
|
+
expect(q.dequeue()).toStrictEqual('z');
|
|
217
|
+
expect(q.isEmpty()).toStrictEqual(true);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it('enqueues object values and preserves them through FIFO', () => {
|
|
221
|
+
const q = new Queue();
|
|
222
|
+
const obj1 = { id: 1, name: 'first' };
|
|
223
|
+
const obj2 = { id: 2, name: 'second' };
|
|
224
|
+
|
|
225
|
+
q.enqueue(obj1);
|
|
226
|
+
q.enqueue(obj2);
|
|
227
|
+
|
|
228
|
+
expect(q.dequeue()).toStrictEqual({ id: 1, name: 'first' });
|
|
229
|
+
expect(q.dequeue()).toStrictEqual({ id: 2, name: 'second' });
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
});
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { NotificationLevel } from '@shell/types/notifications';
|
|
2
|
+
|
|
3
|
+
const MOCK_VERSION = '2.9.0';
|
|
4
|
+
const MOCK_VERSION_WITH_SUFFIX = `${ MOCK_VERSION }-rc1`;
|
|
5
|
+
const READ_WHATS_NEW_KEY = 'read-whatsnew';
|
|
6
|
+
const PREFIX = 'release-notes-';
|
|
7
|
+
const CURRENT_ID = `${ PREFIX }${ MOCK_VERSION }`;
|
|
8
|
+
const RELEASE_NOTES_URL = 'https://example.com/release-notes';
|
|
9
|
+
|
|
10
|
+
function makeGetters(overrides: {
|
|
11
|
+
all?: any[];
|
|
12
|
+
lastReadVersion?: string;
|
|
13
|
+
t?: (key: string, args?: any) => string;
|
|
14
|
+
releaseNotesUrl?: string;
|
|
15
|
+
} = {}) {
|
|
16
|
+
const {
|
|
17
|
+
all = [],
|
|
18
|
+
lastReadVersion = '',
|
|
19
|
+
t = (key: string) => key,
|
|
20
|
+
releaseNotesUrl = RELEASE_NOTES_URL,
|
|
21
|
+
} = overrides;
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
'notifications/all': all,
|
|
25
|
+
'prefs/get': (key: string) => (key === READ_WHATS_NEW_KEY ? lastReadVersion : ''),
|
|
26
|
+
'i18n/t': t,
|
|
27
|
+
releaseNotesUrl,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
describe('addReleaseNotesNotification', () => {
|
|
32
|
+
let addReleaseNotesNotification: any;
|
|
33
|
+
let mockGetVersionData: jest.Mock;
|
|
34
|
+
|
|
35
|
+
beforeEach(() => {
|
|
36
|
+
jest.resetModules();
|
|
37
|
+
mockGetVersionData = jest.fn(() => ({ Version: MOCK_VERSION_WITH_SUFFIX }));
|
|
38
|
+
jest.mock('@shell/config/version', () => ({ getVersionData: mockGetVersionData }));
|
|
39
|
+
addReleaseNotesNotification = require('@shell/utils/release-notes').addReleaseNotesNotification;
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe('version parsing', () => {
|
|
43
|
+
it('strips the pre-release suffix from the version', async() => {
|
|
44
|
+
const dispatch = jest.fn(() => Promise.resolve());
|
|
45
|
+
const getters = makeGetters();
|
|
46
|
+
|
|
47
|
+
await addReleaseNotesNotification(dispatch, getters);
|
|
48
|
+
|
|
49
|
+
expect(dispatch).toHaveBeenCalledWith('notifications/add', expect.objectContaining({ id: CURRENT_ID }));
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('uses the version as-is when there is no suffix', async() => {
|
|
53
|
+
mockGetVersionData.mockReturnValue({ Version: MOCK_VERSION });
|
|
54
|
+
const dispatch = jest.fn(() => Promise.resolve());
|
|
55
|
+
const getters = makeGetters();
|
|
56
|
+
|
|
57
|
+
await addReleaseNotesNotification(dispatch, getters);
|
|
58
|
+
|
|
59
|
+
expect(dispatch).toHaveBeenCalledWith('notifications/add', expect.objectContaining({ id: CURRENT_ID }));
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe('existing notification for the current version', () => {
|
|
64
|
+
it('does not add a notification when the current version notification already exists', async() => {
|
|
65
|
+
const dispatch = jest.fn(() => Promise.resolve());
|
|
66
|
+
const getters = makeGetters({ all: [{ id: CURRENT_ID }] });
|
|
67
|
+
|
|
68
|
+
await addReleaseNotesNotification(dispatch, getters);
|
|
69
|
+
|
|
70
|
+
expect(dispatch).not.toHaveBeenCalledWith('notifications/add', expect.anything());
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('does not remove the current version notification when it already exists', async() => {
|
|
74
|
+
const dispatch = jest.fn(() => Promise.resolve());
|
|
75
|
+
const getters = makeGetters({ all: [{ id: CURRENT_ID }] });
|
|
76
|
+
|
|
77
|
+
await addReleaseNotesNotification(dispatch, getters);
|
|
78
|
+
|
|
79
|
+
expect(dispatch).not.toHaveBeenCalledWith('notifications/remove', CURRENT_ID);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe('old release-notes notifications', () => {
|
|
84
|
+
it('removes a notification for an older version', async() => {
|
|
85
|
+
const oldId = `${ PREFIX }2.8.0`;
|
|
86
|
+
const dispatch = jest.fn(() => Promise.resolve());
|
|
87
|
+
const getters = makeGetters({ all: [{ id: oldId }] });
|
|
88
|
+
|
|
89
|
+
await addReleaseNotesNotification(dispatch, getters);
|
|
90
|
+
|
|
91
|
+
expect(dispatch).toHaveBeenCalledWith('notifications/remove', oldId);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('removes multiple notifications for older versions', async() => {
|
|
95
|
+
const oldId1 = `${ PREFIX }2.7.0`;
|
|
96
|
+
const oldId2 = `${ PREFIX }2.8.0`;
|
|
97
|
+
const dispatch = jest.fn(() => Promise.resolve());
|
|
98
|
+
const getters = makeGetters({ all: [{ id: oldId1 }, { id: oldId2 }] });
|
|
99
|
+
|
|
100
|
+
await addReleaseNotesNotification(dispatch, getters);
|
|
101
|
+
|
|
102
|
+
expect(dispatch).toHaveBeenCalledWith('notifications/remove', oldId1);
|
|
103
|
+
expect(dispatch).toHaveBeenCalledWith('notifications/remove', oldId2);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('still adds a new notification after removing old ones', async() => {
|
|
107
|
+
const dispatch = jest.fn(() => Promise.resolve());
|
|
108
|
+
const getters = makeGetters({ all: [{ id: `${ PREFIX }2.8.0` }] });
|
|
109
|
+
|
|
110
|
+
await addReleaseNotesNotification(dispatch, getters);
|
|
111
|
+
|
|
112
|
+
expect(dispatch).toHaveBeenCalledWith('notifications/add', expect.objectContaining({ id: CURRENT_ID }));
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
describe('non-release-notes notifications', () => {
|
|
117
|
+
it('ignores notifications with a different id prefix', async() => {
|
|
118
|
+
const dispatch = jest.fn(() => Promise.resolve());
|
|
119
|
+
const getters = makeGetters({ all: [{ id: 'cluster-upgrade-1.0.0' }, { id: 'some-other-notification' }] });
|
|
120
|
+
|
|
121
|
+
await addReleaseNotesNotification(dispatch, getters);
|
|
122
|
+
|
|
123
|
+
expect(dispatch).not.toHaveBeenCalledWith('notifications/remove', expect.anything());
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
describe('version preference guard', () => {
|
|
128
|
+
it('does not add notification when the version has already been read', async() => {
|
|
129
|
+
const dispatch = jest.fn(() => Promise.resolve());
|
|
130
|
+
const getters = makeGetters({ lastReadVersion: MOCK_VERSION });
|
|
131
|
+
|
|
132
|
+
await addReleaseNotesNotification(dispatch, getters);
|
|
133
|
+
|
|
134
|
+
expect(dispatch).not.toHaveBeenCalledWith('notifications/add', expect.anything());
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('adds notification when the read version pref is for an older version', async() => {
|
|
138
|
+
const dispatch = jest.fn(() => Promise.resolve());
|
|
139
|
+
const getters = makeGetters({ lastReadVersion: '2.8.0' });
|
|
140
|
+
|
|
141
|
+
await addReleaseNotesNotification(dispatch, getters);
|
|
142
|
+
|
|
143
|
+
expect(dispatch).toHaveBeenCalledWith('notifications/add', expect.objectContaining({ id: CURRENT_ID }));
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('adds notification when the read version pref is empty', async() => {
|
|
147
|
+
const dispatch = jest.fn(() => Promise.resolve());
|
|
148
|
+
const getters = makeGetters({ lastReadVersion: '' });
|
|
149
|
+
|
|
150
|
+
await addReleaseNotesNotification(dispatch, getters);
|
|
151
|
+
|
|
152
|
+
expect(dispatch).toHaveBeenCalledWith('notifications/add', expect.objectContaining({ id: CURRENT_ID }));
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
describe('notification shape', () => {
|
|
157
|
+
it('adds a notification with the correct id, level and preference', async() => {
|
|
158
|
+
const dispatch = jest.fn(() => Promise.resolve());
|
|
159
|
+
const t = jest.fn((key: string) => key);
|
|
160
|
+
const getters = makeGetters({ t });
|
|
161
|
+
|
|
162
|
+
await addReleaseNotesNotification(dispatch, getters);
|
|
163
|
+
|
|
164
|
+
expect(dispatch).toHaveBeenCalledWith('notifications/add', {
|
|
165
|
+
id: CURRENT_ID,
|
|
166
|
+
level: NotificationLevel.Info,
|
|
167
|
+
title: 'landing.whatsNew.title',
|
|
168
|
+
message: 'landing.whatsNew.message',
|
|
169
|
+
preference: {
|
|
170
|
+
key: READ_WHATS_NEW_KEY,
|
|
171
|
+
value: MOCK_VERSION,
|
|
172
|
+
},
|
|
173
|
+
primaryAction: {
|
|
174
|
+
label: 'landing.whatsNew.link',
|
|
175
|
+
target: RELEASE_NOTES_URL,
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('passes version to the title translation function', async() => {
|
|
181
|
+
const dispatch = jest.fn(() => Promise.resolve());
|
|
182
|
+
const t = jest.fn((key: string) => key);
|
|
183
|
+
const getters = makeGetters({ t });
|
|
184
|
+
|
|
185
|
+
await addReleaseNotesNotification(dispatch, getters);
|
|
186
|
+
|
|
187
|
+
expect(t).toHaveBeenCalledWith('landing.whatsNew.title', { version: MOCK_VERSION });
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('uses the releaseNotesUrl getter for the primaryAction target', async() => {
|
|
191
|
+
const customUrl = 'https://custom.example.com/notes';
|
|
192
|
+
const dispatch = jest.fn(() => Promise.resolve());
|
|
193
|
+
const getters = makeGetters({ releaseNotesUrl: customUrl });
|
|
194
|
+
|
|
195
|
+
await addReleaseNotesNotification(dispatch, getters);
|
|
196
|
+
|
|
197
|
+
expect(dispatch).toHaveBeenCalledWith('notifications/add', expect.objectContaining({ primaryAction: expect.objectContaining({ target: customUrl }) }));
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
describe('empty state', () => {
|
|
202
|
+
it('adds a notification when there are no existing notifications', async() => {
|
|
203
|
+
const dispatch = jest.fn(() => Promise.resolve());
|
|
204
|
+
const getters = makeGetters({ all: [] });
|
|
205
|
+
|
|
206
|
+
await addReleaseNotesNotification(dispatch, getters);
|
|
207
|
+
|
|
208
|
+
expect(dispatch).toHaveBeenCalledWith('notifications/add', expect.objectContaining({ id: CURRENT_ID }));
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it('dispatches nothing beyond add when there are no existing notifications', async() => {
|
|
212
|
+
const dispatch = jest.fn(() => Promise.resolve());
|
|
213
|
+
const getters = makeGetters({ all: [] });
|
|
214
|
+
|
|
215
|
+
await addReleaseNotesNotification(dispatch, getters);
|
|
216
|
+
|
|
217
|
+
expect(dispatch).toHaveBeenCalledTimes(1);
|
|
218
|
+
expect(dispatch).toHaveBeenCalledWith('notifications/add', expect.anything());
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
});
|
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
findRouteDefinitionByName,
|
|
3
|
+
filterLocationValidParams,
|
|
4
|
+
queryParamsFor,
|
|
5
|
+
findMeta,
|
|
6
|
+
getClusterFromRoute,
|
|
7
|
+
getProductFromRoute,
|
|
8
|
+
getPackageFromRoute,
|
|
9
|
+
routeMatched,
|
|
10
|
+
routeRequiresAuthentication,
|
|
11
|
+
routeRequiresInstallRedirect,
|
|
12
|
+
} from '@shell/utils/router';
|
|
2
13
|
|
|
3
14
|
describe('findRouteDefinitionByName', () => {
|
|
4
15
|
const createMockRouter = (routes) => ({ getRoutes: () => routes });
|
|
@@ -236,3 +247,245 @@ describe('filterLocationValidParams', () => {
|
|
|
236
247
|
expect(result.params.extra).toBeUndefined();
|
|
237
248
|
});
|
|
238
249
|
});
|
|
250
|
+
|
|
251
|
+
describe('queryParamsFor', () => {
|
|
252
|
+
it.each([
|
|
253
|
+
{
|
|
254
|
+
desc: 'includes key when no default is defined',
|
|
255
|
+
current: {},
|
|
256
|
+
qp: { page: 2 },
|
|
257
|
+
defaults: {},
|
|
258
|
+
expected: { page: 2 },
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
desc: 'sets key to null when default is false and val is truthy',
|
|
262
|
+
current: {},
|
|
263
|
+
qp: { verbose: true },
|
|
264
|
+
defaults: { verbose: false },
|
|
265
|
+
expected: { verbose: null },
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
desc: 'deletes key when default is false and val is falsy',
|
|
269
|
+
current: { verbose: null },
|
|
270
|
+
qp: { verbose: false },
|
|
271
|
+
defaults: { verbose: false },
|
|
272
|
+
expected: {},
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
desc: 'deletes key when value matches non-false default',
|
|
276
|
+
current: {},
|
|
277
|
+
qp: { sort: 'name' },
|
|
278
|
+
defaults: { sort: 'name' },
|
|
279
|
+
expected: {},
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
desc: 'sets key when value differs from non-false default',
|
|
283
|
+
current: {},
|
|
284
|
+
qp: { sort: 'age' },
|
|
285
|
+
defaults: { sort: 'name' },
|
|
286
|
+
expected: { sort: 'age' },
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
desc: 'preserves unrelated keys from current',
|
|
290
|
+
current: { filter: 'active' },
|
|
291
|
+
qp: { page: 2 },
|
|
292
|
+
defaults: {},
|
|
293
|
+
expected: { filter: 'active', page: 2 },
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
desc: 'treats null current as empty object',
|
|
297
|
+
current: null,
|
|
298
|
+
qp: { page: 1 },
|
|
299
|
+
defaults: {},
|
|
300
|
+
expected: { page: 1 },
|
|
301
|
+
},
|
|
302
|
+
])('$desc', ({
|
|
303
|
+
current, qp, defaults, expected
|
|
304
|
+
}) => {
|
|
305
|
+
expect(queryParamsFor(current, qp, defaults)).toStrictEqual(expected);
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
describe('findMeta', () => {
|
|
310
|
+
it.each([
|
|
311
|
+
{
|
|
312
|
+
desc: 'returns undefined when route has no meta',
|
|
313
|
+
route: { params: {} },
|
|
314
|
+
key: 'product',
|
|
315
|
+
expected: undefined,
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
desc: 'returns undefined when route is null',
|
|
319
|
+
route: null,
|
|
320
|
+
key: 'product',
|
|
321
|
+
expected: undefined,
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
desc: 'returns value from a plain meta object',
|
|
325
|
+
route: { meta: { product: 'explorer' } },
|
|
326
|
+
key: 'product',
|
|
327
|
+
expected: 'explorer',
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
desc: 'returns value from a matching item in array meta',
|
|
331
|
+
route: { meta: [{ cluster: 'local' }, { product: 'explorer' }] },
|
|
332
|
+
key: 'product',
|
|
333
|
+
expected: 'explorer',
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
desc: 'returns undefined when key is absent from all meta items',
|
|
337
|
+
route: { meta: [{ cluster: 'local' }] },
|
|
338
|
+
key: 'product',
|
|
339
|
+
expected: undefined,
|
|
340
|
+
},
|
|
341
|
+
])('$desc', ({ route, key, expected }) => {
|
|
342
|
+
expect(findMeta(route, key)).toStrictEqual(expected);
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
describe('getClusterFromRoute', () => {
|
|
347
|
+
it.each([
|
|
348
|
+
{
|
|
349
|
+
desc: 'returns cluster from route params',
|
|
350
|
+
to: { params: { cluster: 'local' } },
|
|
351
|
+
expected: 'local',
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
desc: 'returns cluster from route meta when not in params',
|
|
355
|
+
to: { params: {}, meta: { cluster: 'remote' } },
|
|
356
|
+
expected: 'remote',
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
desc: 'returns undefined when cluster is not in params or meta',
|
|
360
|
+
to: { params: {} },
|
|
361
|
+
expected: undefined,
|
|
362
|
+
},
|
|
363
|
+
])('$desc', ({ to, expected }) => {
|
|
364
|
+
expect(getClusterFromRoute(to)).toStrictEqual(expected);
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
describe('getProductFromRoute', () => {
|
|
369
|
+
it.each([
|
|
370
|
+
{
|
|
371
|
+
desc: 'returns product from route params',
|
|
372
|
+
to: { params: { product: 'explorer' } },
|
|
373
|
+
expected: 'explorer',
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
desc: 'infers product segment from c-cluster-<product>-* route name',
|
|
377
|
+
to: { name: 'c-cluster-explorer-workloads', params: {} },
|
|
378
|
+
expected: 'explorer',
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
desc: 'returns product from route meta when params and name do not have it',
|
|
382
|
+
to: {
|
|
383
|
+
name: 'some-route', params: {}, meta: { product: 'manager' }
|
|
384
|
+
},
|
|
385
|
+
expected: 'manager',
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
desc: 'returns undefined when product is not found anywhere',
|
|
389
|
+
to: { params: {} },
|
|
390
|
+
expected: undefined,
|
|
391
|
+
},
|
|
392
|
+
])('$desc', ({ to, expected }) => {
|
|
393
|
+
expect(getProductFromRoute(to)).toStrictEqual(expected);
|
|
394
|
+
});
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
describe('getPackageFromRoute', () => {
|
|
398
|
+
it.each([
|
|
399
|
+
{
|
|
400
|
+
desc: 'returns undefined when route has no meta',
|
|
401
|
+
route: {},
|
|
402
|
+
expected: undefined,
|
|
403
|
+
},
|
|
404
|
+
{
|
|
405
|
+
desc: 'returns pkg from array meta',
|
|
406
|
+
route: { meta: [{ pkg: 'my-package' }] },
|
|
407
|
+
expected: 'my-package',
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
desc: 'returns pkg from plain object meta',
|
|
411
|
+
route: { meta: { pkg: 'my-package' } },
|
|
412
|
+
expected: 'my-package',
|
|
413
|
+
},
|
|
414
|
+
{
|
|
415
|
+
desc: 'returns undefined when no meta item defines pkg',
|
|
416
|
+
route: { meta: [{ product: 'explorer' }] },
|
|
417
|
+
expected: undefined,
|
|
418
|
+
},
|
|
419
|
+
])('$desc', ({ route, expected }) => {
|
|
420
|
+
expect(getPackageFromRoute(route)).toStrictEqual(expected);
|
|
421
|
+
});
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
describe('routeMatched', () => {
|
|
425
|
+
it.each([
|
|
426
|
+
{
|
|
427
|
+
desc: 'returns false when route has no matched array',
|
|
428
|
+
to: {},
|
|
429
|
+
fn: (m) => !!m.meta?.test,
|
|
430
|
+
expected: false,
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
desc: 'returns true when predicate matches a route entry',
|
|
434
|
+
to: { matched: [{ meta: { test: true } }] },
|
|
435
|
+
fn: (m) => !!m.meta?.test,
|
|
436
|
+
expected: true,
|
|
437
|
+
},
|
|
438
|
+
{
|
|
439
|
+
desc: 'returns false when predicate matches no route entry',
|
|
440
|
+
to: { matched: [{ meta: { other: true } }] },
|
|
441
|
+
fn: (m) => !!m.meta?.test,
|
|
442
|
+
expected: false,
|
|
443
|
+
},
|
|
444
|
+
])('$desc', ({ to, fn, expected }) => {
|
|
445
|
+
expect(routeMatched(to, fn)).toStrictEqual(expected);
|
|
446
|
+
});
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
describe('routeRequiresAuthentication', () => {
|
|
450
|
+
it.each([
|
|
451
|
+
{
|
|
452
|
+
desc: 'returns true when a matched route requires authentication',
|
|
453
|
+
to: { matched: [{ meta: { requiresAuthentication: true } }] },
|
|
454
|
+
expected: true,
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
desc: 'returns false when no matched route requires authentication',
|
|
458
|
+
to: { matched: [{ meta: {} }] },
|
|
459
|
+
expected: false,
|
|
460
|
+
},
|
|
461
|
+
{
|
|
462
|
+
desc: 'returns false when route has no matched array',
|
|
463
|
+
to: {},
|
|
464
|
+
expected: false,
|
|
465
|
+
},
|
|
466
|
+
])('$desc', ({ to, expected }) => {
|
|
467
|
+
expect(routeRequiresAuthentication(to)).toStrictEqual(expected);
|
|
468
|
+
});
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
describe('routeRequiresInstallRedirect', () => {
|
|
472
|
+
it.each([
|
|
473
|
+
{
|
|
474
|
+
desc: 'returns true when a matched route meta contains installRedirect',
|
|
475
|
+
to: { matched: [{ meta: { installRedirect: 'some-product' } }] },
|
|
476
|
+
expected: true,
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
desc: 'returns false when no matched route has installRedirect',
|
|
480
|
+
to: { matched: [{ meta: {} }] },
|
|
481
|
+
expected: false,
|
|
482
|
+
},
|
|
483
|
+
{
|
|
484
|
+
desc: 'returns false when route has no matched array',
|
|
485
|
+
to: {},
|
|
486
|
+
expected: false,
|
|
487
|
+
},
|
|
488
|
+
])('$desc', ({ to, expected }) => {
|
|
489
|
+
expect(routeRequiresInstallRedirect(to)).toStrictEqual(expected);
|
|
490
|
+
});
|
|
491
|
+
});
|