@rancher/shell 3.0.12-rc.1 → 3.0.12-rc.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apis/impl/apis.ts +6 -0
- package/apis/index.ts +26 -0
- package/apis/intf/resources-api/cluster-api.ts +18 -0
- package/apis/intf/resources-api/mgmt-api.ts +15 -0
- package/apis/intf/resources-api/resource-base.ts +107 -0
- package/apis/intf/resources-api/resource-constants.ts +147 -0
- package/apis/intf/resources-api/resources-api.ts +143 -0
- package/apis/intf/resources.ts +49 -0
- package/apis/intf/{modal.ts → shell-api/modal.ts} +21 -26
- package/apis/intf/shell-api/proxy.ts +216 -0
- package/apis/intf/{slide-in.ts → shell-api/slide-in.ts} +4 -3
- package/apis/intf/{system.ts → shell-api/system.ts} +4 -1
- package/apis/intf/shell.ts +12 -6
- package/apis/resources/__tests__/resources-api-class.test.ts +550 -0
- package/apis/resources/index.ts +22 -0
- package/apis/resources/resources-api-class.ts +187 -0
- package/apis/shell/__tests__/proxy.test.ts +369 -0
- package/apis/shell/index.ts +8 -1
- package/apis/shell/modal.ts +4 -1
- package/apis/shell/notifications.ts +9 -6
- package/apis/shell/proxy.ts +256 -0
- package/apis/shell/slide-in.ts +4 -1
- package/apis/vue-shim.d.ts +2 -1
- package/assets/data/aws-regions.json +4 -0
- package/assets/fonts/lato/LatoLatin-Black.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Black.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-BlackItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-BlackItalic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Bold.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Bold.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-BoldItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-BoldItalic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Heavy.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Heavy.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-HeavyItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-HeavyItalic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Italic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Italic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Light.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Light.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-LightItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-LightItalic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Medium.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Medium.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-MediumItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-MediumItalic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Regular.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Regular.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Semibold.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Semibold.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-SemiboldItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-SemiboldItalic.woff2 +0 -0
- package/assets/images/providers/entraid-black.svg +4 -0
- package/assets/images/providers/entraid.svg +9 -0
- package/assets/images/vendor/entraid.svg +9 -0
- package/assets/styles/app.scss +0 -1
- package/assets/styles/base/_variables.scss +2 -0
- package/assets/styles/fonts/_fontstack.scss +132 -8
- package/assets/translations/en-us.yaml +41 -22
- package/assets/translations/zh-hans.yaml +4 -8
- package/chart/__tests__/S3.test.ts +10 -3
- package/chart/monitoring/index.vue +10 -1
- package/components/ActionDropdownShell.vue +2 -1
- package/components/CountBox.vue +20 -0
- package/components/CreateDriver.vue +0 -12
- package/components/CruResourceFooter.vue +9 -5
- package/components/DetailText.vue +12 -3
- package/components/ExplorerProjectsNamespaces.vue +1 -1
- package/components/InstallHelmCharts.vue +2 -2
- package/components/LandingPagePreference.vue +14 -5
- package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +15 -1
- package/components/Resource/Detail/Metadata/index.vue +6 -0
- package/components/Resource/Detail/ResourcePopover/index.vue +12 -1
- package/components/Resource/Detail/SpacedRow.vue +3 -1
- package/components/Resource/Detail/TitleBar/index.vue +10 -11
- package/components/ResourceList/Masthead.vue +12 -8
- package/components/SelectIconGrid.vue +5 -10
- package/components/SingleClusterInfo.vue +1 -0
- package/components/SortableTable/__tests__/sorting.test.ts +126 -0
- package/components/SortableTable/index.vue +6 -9
- package/components/SortableTable/selection.js +23 -5
- package/components/SortableTable/sorting.js +6 -3
- package/components/Wizard.vue +14 -13
- package/components/__tests__/CountBox.test.ts +72 -0
- package/components/__tests__/DetailText.test.ts +113 -0
- package/components/fleet/FleetBundles.vue +100 -12
- package/components/fleet/FleetClusterTargets/index.vue +54 -15
- package/components/fleet/__tests__/FleetClusterTargets.test.ts +149 -115
- package/components/fleet/__tests__/FleetClusters.test.ts +12 -12
- package/components/form/InputWithSelect.vue +18 -10
- package/components/form/KeyValue.vue +17 -1
- package/components/form/LabeledSelect.vue +101 -26
- package/components/form/NameNsDescription.vue +11 -0
- package/components/form/Security.vue +6 -2
- package/components/form/Select.vue +73 -56
- package/components/form/ServiceNameSelect.vue +13 -11
- package/components/form/WorkloadPorts.vue +2 -7
- package/components/form/__tests__/KeyValue.test.ts +66 -0
- package/components/form/__tests__/NodeScheduling.test.ts +9 -0
- package/components/form/__tests__/Security.test.ts +76 -0
- package/components/form/labeled-select-utils/useLabeledSelectPagination.ts +138 -0
- package/components/formatter/Autoscaler.vue +4 -4
- package/components/formatter/ClusterKubeVersion.vue +27 -0
- package/components/formatter/ClusterLink.vue +1 -7
- package/components/formatter/ClusterProvider.vue +6 -10
- package/components/formatter/FleetSummaryGraph.vue +0 -3
- package/components/formatter/MachineSummaryGraph.vue +1 -1
- package/components/formatter/PodsUsage.vue +2 -2
- package/components/formatter/__tests__/Autoscaler.test.ts +19 -22
- package/components/formatter/__tests__/FleetSummaryGraph.test.ts +216 -0
- package/components/formatter/__tests__/PodsUsage.test.ts +6 -10
- package/components/nav/Group.vue +7 -6
- package/components/nav/Header.vue +24 -3
- package/components/nav/NamespaceFilter.vue +2 -2
- package/components/nav/NotificationCenter/Notification.vue +4 -1
- package/components/nav/NotificationCenter/NotificationHeader.vue +20 -8
- package/components/nav/NotificationCenter/__tests__/NotificationHeader.test.ts +80 -0
- package/components/nav/TopLevelMenu.helper.ts +15 -3
- package/components/nav/TopLevelMenu.vue +16 -5
- package/components/nav/Type.vue +8 -7
- package/components/nav/WindowManager/index.vue +2 -1
- package/components/nav/WorkspaceSwitcher.vue +13 -0
- package/components/nav/__tests__/Group.test.ts +67 -0
- package/components/nav/__tests__/Header.test.ts +235 -0
- package/components/nav/__tests__/TopLevelMenu.test.ts +145 -21
- package/components/nav/__tests__/Type.test.ts +20 -3
- package/components/templates/default.vue +34 -4
- package/components/templates/home.vue +30 -25
- package/components/templates/plain.vue +31 -26
- package/components/templates/standalone.vue +17 -0
- package/composables/useFormValidation.ts +93 -0
- package/composables/useLabeledFormElement.ts +10 -2
- package/composables/useLabeledSelect.ts +60 -0
- package/composables/useUserRetentionValidation.ts +1 -49
- package/composables/useVeeValidateField.test.ts +159 -0
- package/composables/useVeeValidateField.ts +67 -0
- package/config/cookies.js +0 -1
- package/config/labels-annotations.js +1 -0
- package/config/pagination-table-headers.js +18 -1
- package/config/product/manager.js +82 -21
- package/config/query-params.js +1 -0
- package/config/router/routes.js +6 -8
- package/config/table-headers.js +20 -1
- package/config/types.js +2 -1
- package/core/__tests__/plugin-products.test.ts +1505 -30
- package/core/plugin-products-base.ts +137 -20
- package/core/plugin-products-helpers.ts +5 -4
- package/core/plugin-products.ts +4 -0
- package/core/plugin-types.ts +129 -4
- package/core/plugin.ts +15 -7
- package/core/productDebugger.js +9 -4
- package/core/types-provisioning.ts +43 -30
- package/core/types.ts +58 -19
- package/detail/__tests__/management.cattle.io.fleetworkspace.test.ts +128 -0
- package/detail/__tests__/pod.test.ts +41 -0
- package/detail/harvesterhci.io.management.cluster.vue +6 -2
- package/detail/management.cattle.io.fleetworkspace.vue +49 -0
- package/detail/pod.vue +1 -1
- package/detail/provisioning.cattle.io.cluster.vue +4 -10
- package/edit/__tests__/fleet.cattle.io.helmop.test.ts +9 -0
- package/edit/__tests__/kontainerDriver.test.ts +0 -13
- package/edit/__tests__/nodeDriver.test.ts +5 -11
- package/edit/__tests__/resources.cattle.io.restore.test.ts +9 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/General.test.ts.snap +6 -0
- package/edit/auth/__tests__/azuread.test.ts +217 -34
- package/edit/auth/__tests__/oidc.test.ts +54 -0
- package/edit/auth/azuread.vue +123 -15
- package/edit/auth/oidc.vue +10 -2
- package/edit/kontainerDriver.vue +1 -2
- package/edit/networking.k8s.io.ingress/DefaultBackend.vue +13 -4
- package/edit/networking.k8s.io.ingress/RulePath.vue +8 -4
- package/edit/networking.k8s.io.ingress/index.vue +75 -20
- package/edit/nodeDriver.vue +0 -2
- package/edit/provisioning.cattle.io.cluster/AgentEnv.vue +1 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/AgentEnv.test.ts +25 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/MachinePool.test.ts +104 -0
- package/edit/provisioning.cattle.io.cluster/index.vue +81 -106
- package/edit/provisioning.cattle.io.cluster/rke2.vue +8 -4
- package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +11 -0
- package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs.vue +37 -4
- package/edit/provisioning.cattle.io.cluster/tabs/registries/__tests__/RegistryConfigs.test.ts +132 -7
- package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +2 -1
- package/edit/secret/__tests__/ssh.test.ts +5 -6
- package/edit/secret/basic.vue +31 -0
- package/edit/secret/index.vue +68 -17
- package/edit/secret/registry.vue +38 -0
- package/edit/secret/ssh.vue +29 -0
- package/edit/secret/tls.vue +30 -0
- package/edit/service.vue +4 -4
- package/edit/workload/Upgrading.vue +3 -3
- package/edit/workload/__tests__/Upgrading.test.ts +6 -9
- package/edit/workload/mixins/workload.js +2 -1
- package/initialize/App.vue +29 -2
- package/initialize/install-plugins.js +0 -2
- package/list/__tests__/management.cattle.io.feature.test.ts +105 -0
- package/list/catalog.cattle.io.app.vue +25 -5
- package/list/fleet.cattle.io.bundle.vue +7 -104
- package/list/fleet.cattle.io.clusterregistrationtoken.vue +20 -0
- package/list/management.cattle.io.feature.vue +1 -1
- package/list/management.cattle.io.fleetworkspace.vue +8 -0
- package/list/provisioning.cattle.io.cluster.vue +262 -180
- package/list/utils/management.cattle.io.cluster.utils.ts +128 -0
- package/machine-config/amazonec2.vue +1 -0
- package/mixins/__tests__/chart.test.ts +112 -0
- package/mixins/brand.js +2 -1
- package/mixins/chart.js +50 -15
- package/mixins/resource-fetch-api-pagination.js +41 -5
- package/models/__tests__/catalog.cattle.io.app.test.ts +15 -1
- package/models/__tests__/catalog.cattle.io.clusterrepo.test.ts +84 -0
- package/models/__tests__/chart.test.ts +99 -6
- package/models/__tests__/ext.cattle.io.kubeconfig.test.ts +67 -67
- package/models/__tests__/management.cattle.io.cluster.test.ts +1 -1
- package/models/__tests__/management.cattle.io.feature.test.ts +131 -0
- package/models/__tests__/management.cattle.io.node.ts +6 -5
- package/models/__tests__/management.cattle.io.nodepool.ts +5 -4
- package/models/__tests__/monitoring.coreos.com.alertmanagerconfig.test.ts +98 -0
- package/models/__tests__/provisioning.cattle.io.cluster.test.ts +32 -11
- package/models/base-cluster.x-k8s.io.js +26 -0
- package/models/catalog.cattle.io.app.js +21 -17
- package/models/catalog.cattle.io.clusterrepo.js +39 -11
- package/models/chart.js +33 -19
- package/models/cluster.js +1 -1
- package/models/cluster.x-k8s.io.machine.js +4 -22
- package/models/cluster.x-k8s.io.machinedeployment.js +2 -20
- package/models/cluster.x-k8s.io.machineset.js +2 -20
- package/models/compliance.cattle.io.clusterscan.js +130 -2
- package/models/ext.cattle.io.kubeconfig.ts +4 -7
- package/models/fleet-application.js +4 -2
- package/models/fleet.cattle.io.bundle.js +1 -1
- package/models/kontainerdriver.js +11 -0
- package/models/management.cattle.io.authconfig.js +5 -1
- package/models/management.cattle.io.cluster.js +402 -78
- package/models/management.cattle.io.feature.js +3 -3
- package/models/management.cattle.io.kontainerdriver.js +1 -26
- package/models/management.cattle.io.node.js +6 -4
- package/models/management.cattle.io.nodepool.js +1 -1
- package/models/monitoring.coreos.com.alertmanagerconfig.js +31 -17
- package/models/networking.k8s.io.ingress.js +12 -4
- package/models/nodedriver.js +7 -0
- package/models/provisioning.cattle.io.cluster.js +47 -330
- package/models/rke.cattle.io.etcdsnapshot.js +1 -2
- package/package.json +20 -37
- package/pages/__tests__/readme.test.ts +49 -0
- package/pages/auth/setup.vue +2 -3
- package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +265 -0
- package/pages/c/_cluster/apps/charts/__tests__/index.test.ts +55 -0
- package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +53 -0
- package/pages/c/_cluster/apps/charts/chart.vue +275 -39
- package/pages/c/_cluster/apps/charts/index.vue +2 -2
- package/pages/c/_cluster/apps/charts/install.vue +18 -10
- package/pages/c/_cluster/auth/user.retention/index.vue +55 -22
- package/pages/c/_cluster/explorer/__tests__/index.test.ts +23 -25
- package/pages/c/_cluster/explorer/index.vue +5 -49
- package/pages/c/_cluster/istio/__tests__/istio.index.test.ts +194 -0
- package/pages/c/_cluster/istio/index.vue +21 -6
- package/pages/c/_cluster/manager/drivers/kontainerDriver/index.vue +5 -7
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +40 -2
- package/pages/c/_cluster/uiplugins/__tests__/PluginInfoPanel.test.ts +61 -0
- package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +735 -13
- package/pages/c/_cluster/uiplugins/index.vue +226 -222
- package/pages/diagnostic.vue +13 -17
- package/pages/fail-whale.vue +18 -0
- package/pages/home.vue +77 -260
- package/pages/readme.vue +88 -0
- package/plugins/dashboard-store/__tests__/resource-class.test.ts +88 -0
- package/plugins/dashboard-store/actions.js +40 -18
- package/plugins/dashboard-store/resource-class.js +5 -2
- package/plugins/steve/__tests__/subscribe.spec.ts +6 -3
- package/plugins/steve/steve-pagination-utils.ts +11 -3
- package/plugins/steve/subscribe.js +35 -5
- package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +211 -1
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +37 -4
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +1 -1
- package/rancher-components/RcButton/RcButton.test.ts +37 -1
- package/rancher-components/RcButton/RcButton.vue +38 -8
- package/rancher-components/RcDropdown/RcDropdownTrigger.vue +10 -8
- package/scripts/test-plugins-build.sh +5 -2
- package/server/server-middleware.js +2 -2
- package/static/humans.txt +1 -0
- package/static/robots.txt +34 -0
- package/static/welcome-cow.svg +18 -0
- package/store/__tests__/catalog.test.ts +276 -12
- package/store/__tests__/type-map.test.ts +556 -1
- package/store/action-menu.js +8 -3
- package/store/auth.js +1 -4
- package/store/aws.js +27 -16
- package/store/catalog.js +87 -11
- package/store/digitalocean.js +20 -38
- package/store/index.js +2 -0
- package/store/linode.js +25 -40
- package/store/pnap.js +1 -0
- package/store/type-map.js +111 -29
- package/tsconfig.paths.json +8 -8
- package/types/kube/kube-api.ts +14 -1
- package/types/rancher/steve.api.ts +12 -12
- package/types/resources/settings.d.ts +2 -1
- package/types/shell/index.d.ts +128 -24
- package/types/store/dashboard-store.types.ts +108 -11
- package/types/store/pagination.types.ts +6 -3
- package/utils/__tests__/alertmanagerconfig.test.ts +117 -0
- package/utils/__tests__/async.test.ts +87 -0
- package/utils/__tests__/aws.test.ts +140 -0
- package/utils/__tests__/banners.test.ts +176 -0
- package/utils/__tests__/chart.test.ts +64 -1
- package/utils/__tests__/color.test.ts +226 -0
- package/utils/__tests__/duration.test.ts +140 -0
- package/utils/__tests__/fleet.test.ts +340 -0
- package/utils/__tests__/git.test.ts +270 -0
- package/utils/__tests__/inactivity.test.ts +316 -0
- package/utils/__tests__/ingress.test.ts +553 -0
- package/utils/__tests__/kube.test.ts +68 -0
- package/utils/__tests__/namespace-filter.test.ts +109 -0
- package/utils/__tests__/object.test.ts +77 -0
- package/utils/__tests__/pagination-utils.test.ts +361 -0
- package/utils/__tests__/parse-externalid.test.ts +137 -0
- package/utils/__tests__/perf-setting.utils.test.ts +98 -0
- package/utils/__tests__/poller-sequential.test.ts +177 -0
- package/utils/__tests__/poller.test.ts +170 -0
- package/utils/__tests__/promise.test.ts +346 -0
- package/utils/__tests__/settings.test.ts +140 -0
- package/utils/__tests__/sort-utils.test.ts +301 -0
- package/utils/__tests__/string-utils.test.ts +798 -0
- package/utils/__tests__/string.test.ts +23 -1
- package/utils/__tests__/style.test.ts +154 -0
- package/utils/__tests__/svg-filter.test.ts +184 -0
- package/utils/__tests__/time.test.ts +14 -1
- package/utils/__tests__/units.test.ts +417 -0
- package/utils/__tests__/url.test.ts +246 -0
- package/utils/__tests__/versions.test.ts +128 -0
- package/utils/__tests__/xccdf.test.ts +391 -0
- package/utils/chart.js +36 -0
- package/utils/fleet.ts +13 -3
- package/utils/gatekeeper/__tests__/util.test.ts +174 -0
- package/utils/gc/__tests__/gc-interval.test.ts +119 -0
- package/utils/gc/__tests__/gc-root-store.test.ts +225 -0
- package/utils/gc/__tests__/gc-route-changed.test.ts +96 -0
- package/utils/gc/__tests__/gc.test.ts +487 -0
- package/utils/ingress.ts +9 -1
- package/utils/object.js +33 -2
- package/utils/pagination-utils.ts +2 -1
- package/utils/string.js +25 -2
- package/utils/time.ts +5 -0
- package/utils/uiplugins.ts +5 -5
- package/utils/validators/__tests__/cluster-name.test.ts +110 -0
- package/utils/validators/__tests__/cron-schedule.test.ts +79 -0
- package/utils/validators/__tests__/index.test.ts +481 -0
- package/utils/validators/__tests__/kubernetes-name.test.ts +163 -0
- package/utils/validators/__tests__/misc-validators.test.ts +246 -0
- package/utils/validators/__tests__/pod-affinity.test.ts +382 -0
- package/utils/validators/__tests__/prometheusrule.test.ts +211 -0
- package/utils/validators/__tests__/role-template.test.ts +149 -0
- package/utils/validators/__tests__/service.test.ts +283 -0
- package/utils/validators/__tests__/setting.test.js +32 -0
- package/utils/validators/formRules/__tests__/index.test.ts +50 -0
- package/utils/validators/formRules/index.ts +5 -5
- package/utils/validators/machine-pool.ts +1 -1
- package/utils/validators/setting.js +18 -3
- package/utils/xccdf.ts +418 -0
- package/vue.config.js +0 -9
- package/assets/fonts/lato/lato-v17-latin-700.woff +0 -0
- package/assets/fonts/lato/lato-v17-latin-700.woff2 +0 -0
- package/assets/fonts/lato/lato-v17-latin-regular.woff +0 -0
- package/assets/fonts/lato/lato-v17-latin-regular.woff2 +0 -0
- package/assets/images/providers/azuread-black.svg +0 -22
- package/assets/images/providers/azuread.svg +0 -25
- package/assets/images/vendor/azuread.svg +0 -18
- package/assets/styles/fonts/_dots.scss +0 -18
- package/components/EmberPage.vue +0 -622
- package/components/EmberPageView.vue +0 -39
- package/components/form/labeled-select-utils/labeled-select-pagination.ts +0 -116
- package/mixins/labeled-form-element.ts +0 -225
- package/pages/c/_cluster/explorer/tools/pages/_page.vue +0 -28
- package/pages/c/_cluster/manager/pages/_page.vue +0 -22
- package/pages/c/_cluster/mcapps/pages/_page.vue +0 -22
- package/plugins/ember-cookie.js +0 -17
- package/utils/ember-page.js +0 -30
|
@@ -2,7 +2,8 @@ import { IExtension } from '@shell/core/types';
|
|
|
2
2
|
import {
|
|
3
3
|
ProductChild, ProductMetadata,
|
|
4
4
|
ConfigureTypeConfiguration, VirtualTypeConfiguration,
|
|
5
|
-
ProductChildCustomPage
|
|
5
|
+
ProductChildCustomPage, VueRouteComponent,
|
|
6
|
+
OverviewPageRoutingMetadata
|
|
6
7
|
} from '@shell/core/plugin-types';
|
|
7
8
|
import EmptyProductPage from '@shell/components/EmptyProductPage.vue';
|
|
8
9
|
import pluginProductsHelpers from '@shell/core/plugin-products-helpers';
|
|
@@ -11,7 +12,7 @@ import {
|
|
|
11
12
|
isProductChildWithComponent,
|
|
12
13
|
isProductChildWithType,
|
|
13
14
|
hasNameProperty,
|
|
14
|
-
hasTypeProperty
|
|
15
|
+
hasTypeProperty,
|
|
15
16
|
} from '@shell/core/plugin-products-type-guards';
|
|
16
17
|
|
|
17
18
|
/**
|
|
@@ -25,6 +26,18 @@ export abstract class BasePluginProduct {
|
|
|
25
26
|
|
|
26
27
|
protected addedResourceRoutes = false;
|
|
27
28
|
|
|
29
|
+
protected registeredPageNames: Set<string> = new Set();
|
|
30
|
+
|
|
31
|
+
// Maps user-friendly group name → internal resolved name (e.g. 'monitoring' → 'myapp-monitoring')
|
|
32
|
+
// Populated during processGroupRecursively, consumed by moveToGroup resolution in processProductLevelDSLOptions
|
|
33
|
+
protected groupNameMap: Map<string, string> = new Map();
|
|
34
|
+
|
|
35
|
+
// Maps user-facing page identifier → internal basicType key
|
|
36
|
+
// Resource pages: type → type (identity, e.g. 'pod' → 'pod')
|
|
37
|
+
// Custom pages: name → prefixed name (e.g. 'myPage' → 'product1-myPage')
|
|
38
|
+
// Populated during configurePageItem, consumed by moveToGroup resolution in processProductLevelDSLOptions
|
|
39
|
+
protected pageIdMap: Map<string, string> = new Map();
|
|
40
|
+
|
|
28
41
|
protected DSLMethods: any;
|
|
29
42
|
|
|
30
43
|
protected config: ProductChild[];
|
|
@@ -38,11 +51,16 @@ export abstract class BasePluginProduct {
|
|
|
38
51
|
*/
|
|
39
52
|
abstract get isNewProduct(): boolean;
|
|
40
53
|
|
|
54
|
+
get productName(): string {
|
|
55
|
+
return this.name;
|
|
56
|
+
}
|
|
57
|
+
|
|
41
58
|
/**
|
|
42
59
|
* Helper to throw errors during product registration
|
|
43
60
|
*/
|
|
44
|
-
protected surfaceError(message: string):
|
|
45
|
-
|
|
61
|
+
protected surfaceError(message: string, e?: any): never {
|
|
62
|
+
console.error(`Extensions - product "${ this.name }" registration error ::: ${ message }`); // eslint-disable-line no-console
|
|
63
|
+
throw new Error(`Extensions - product "${ this.name }" registration error ::: ${ message }`, { cause: e });
|
|
46
64
|
}
|
|
47
65
|
|
|
48
66
|
/**
|
|
@@ -68,6 +86,13 @@ export abstract class BasePluginProduct {
|
|
|
68
86
|
}
|
|
69
87
|
}
|
|
70
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Generates data for group overview page routing
|
|
91
|
+
*/
|
|
92
|
+
protected generateMetadataForGroupOverviewPageRouting(name: string, component: VueRouteComponent): OverviewPageRoutingMetadata {
|
|
93
|
+
return { name, component };
|
|
94
|
+
}
|
|
95
|
+
|
|
71
96
|
/**
|
|
72
97
|
* This is where we register the product and its children via the DSL
|
|
73
98
|
*/
|
|
@@ -97,6 +122,12 @@ export abstract class BasePluginProduct {
|
|
|
97
122
|
this.processGroupRecursively(item, this.name);
|
|
98
123
|
}
|
|
99
124
|
});
|
|
125
|
+
|
|
126
|
+
// Process product-level DSL options after all groups are registered
|
|
127
|
+
// so that the groupNameMap is fully populated for moveToGroup resolution
|
|
128
|
+
if (this.product) {
|
|
129
|
+
this.processProductLevelDSLOptions();
|
|
130
|
+
}
|
|
100
131
|
}
|
|
101
132
|
|
|
102
133
|
/**
|
|
@@ -115,6 +146,10 @@ export abstract class BasePluginProduct {
|
|
|
115
146
|
const itemGroup = item;
|
|
116
147
|
const groupName = parentGroupName ? `${ productName }-${ parentGroupName }-${ itemGroup.name }` : `${ productName }-${ itemGroup.name }`;
|
|
117
148
|
|
|
149
|
+
// Map the user's friendly group name to the resolved internal name
|
|
150
|
+
// so that moveToGroup can translate friendly names automatically
|
|
151
|
+
this.groupNameMap.set(itemGroup.name, groupName);
|
|
152
|
+
|
|
118
153
|
if (!Array.isArray(itemGroup.children)) {
|
|
119
154
|
this.surfaceError('Children defined for group are not in an array format');
|
|
120
155
|
|
|
@@ -172,7 +207,7 @@ export abstract class BasePluginProduct {
|
|
|
172
207
|
}
|
|
173
208
|
|
|
174
209
|
/**
|
|
175
|
-
* Handles product registration via DSL
|
|
210
|
+
* Handles product registration via DSL (we also define entry route for the product here based on the config of the product - ordering)
|
|
176
211
|
*/
|
|
177
212
|
protected handleProductRegistration(): void {
|
|
178
213
|
const { basicType, product } = this.DSLMethods;
|
|
@@ -187,7 +222,7 @@ export abstract class BasePluginProduct {
|
|
|
187
222
|
|
|
188
223
|
if (isProductChildGroup(firstConfig)) {
|
|
189
224
|
// First config item is a group
|
|
190
|
-
if (firstConfig.children.length) {
|
|
225
|
+
if (firstConfig.children.length > 0) {
|
|
191
226
|
const entryChild = firstConfig.children[0];
|
|
192
227
|
|
|
193
228
|
if (!firstConfig.component) {
|
|
@@ -198,16 +233,12 @@ export abstract class BasePluginProduct {
|
|
|
198
233
|
defaultRoute = pluginProductsHelpers.generateVirtualTypeRoute(this.name, entryChild, { omitPath: true, extendProduct: !this.isNewProduct });
|
|
199
234
|
}
|
|
200
235
|
} else {
|
|
201
|
-
// Group with component - route to the group page
|
|
202
|
-
defaultRoute = pluginProductsHelpers.generateVirtualTypeRoute(this.name,
|
|
203
|
-
omitPath: true, component: firstConfig.component, extendProduct: !this.isNewProduct
|
|
204
|
-
});
|
|
236
|
+
// Group with component - route to the group overview page (which will render the group's component and side-menu)
|
|
237
|
+
defaultRoute = pluginProductsHelpers.generateVirtualTypeRoute(this.name, this.generateMetadataForGroupOverviewPageRouting(firstConfig.name, firstConfig.component), { omitPath: true, extendProduct: !this.isNewProduct });
|
|
205
238
|
}
|
|
206
239
|
} else if (firstConfig.component) {
|
|
207
240
|
// Group with component but no children - route to the group page itself
|
|
208
|
-
defaultRoute = pluginProductsHelpers.generateVirtualTypeRoute(this.name,
|
|
209
|
-
omitPath: true, component: firstConfig.component, extendProduct: !this.isNewProduct
|
|
210
|
-
});
|
|
241
|
+
defaultRoute = pluginProductsHelpers.generateVirtualTypeRoute(this.name, this.generateMetadataForGroupOverviewPageRouting(firstConfig.name, firstConfig.component), { omitPath: true, extendProduct: !this.isNewProduct });
|
|
211
242
|
}
|
|
212
243
|
} else if (isProductChildWithType(firstConfig)) {
|
|
213
244
|
// Simple configureType page (resource page)
|
|
@@ -236,11 +267,67 @@ export abstract class BasePluginProduct {
|
|
|
236
267
|
});
|
|
237
268
|
}
|
|
238
269
|
|
|
270
|
+
/**
|
|
271
|
+
* Process product-level DSL options: renameGroups, ignoreGroups, moveToGroup.
|
|
272
|
+
* Called after all config items and groups are registered so that the groupNameMap is fully populated.
|
|
273
|
+
*/
|
|
274
|
+
protected processProductLevelDSLOptions(): void {
|
|
275
|
+
const {
|
|
276
|
+
mapGroup, ignoreGroup, moveType, basicType
|
|
277
|
+
} = this.DSLMethods;
|
|
278
|
+
|
|
279
|
+
if (this.product?.renameGroups?.length) {
|
|
280
|
+
this.product.renameGroups.forEach((mapping) => {
|
|
281
|
+
mapGroup(mapping.groupSelector, mapping.newName);
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (this.product?.ignoreGroups?.length) {
|
|
286
|
+
this.product.ignoreGroups.forEach((ignore) => {
|
|
287
|
+
if (ignore.condition) {
|
|
288
|
+
ignoreGroup(ignore.groupSelector, ignore.condition);
|
|
289
|
+
} else {
|
|
290
|
+
ignoreGroup(ignore.groupSelector);
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (this.product?.moveToGroup?.length) {
|
|
296
|
+
this.product.moveToGroup.forEach((move) => {
|
|
297
|
+
const resolvedGroup = this.groupNameMap.get(move.groupName);
|
|
298
|
+
|
|
299
|
+
if (!resolvedGroup) {
|
|
300
|
+
this.surfaceError(`moveToGroup target group "${ move.groupName }" not found. Available groups: ${ Array.from(this.groupNameMap.keys()).join(', ') }`);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const resolvedPageId = this.pageIdMap.get(move.entryId);
|
|
304
|
+
|
|
305
|
+
if (!resolvedPageId) {
|
|
306
|
+
this.surfaceError(`moveToGroup entryId "${ move.entryId }" not found. Available pages: ${ Array.from(this.pageIdMap.keys()).join(', ') }`);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Re-register via basicType to move the page in the nav tree (basic view mode)
|
|
310
|
+
basicType([resolvedPageId], resolvedGroup);
|
|
311
|
+
|
|
312
|
+
// Also register via moveType for non-basic view modes (e.g. "in use" mode).
|
|
313
|
+
// moveType uses regex matching against schema IDs, so it only works for resource types.
|
|
314
|
+
const isResourceType = resolvedPageId === move.entryId;
|
|
315
|
+
|
|
316
|
+
if (isResourceType) {
|
|
317
|
+
moveType(move.entryId, resolvedGroup, move.weight);
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
239
323
|
/**
|
|
240
324
|
* Configure virtualType (custom page) or configureType (resource page) for a page item
|
|
241
325
|
*/
|
|
242
326
|
protected configurePageItem(parentName: string, item: ProductChild, groupNaming?: string): void {
|
|
243
|
-
const {
|
|
327
|
+
const {
|
|
328
|
+
configureType, virtualType, weightType,
|
|
329
|
+
mapType, ignoreType, hideBulkActions, headers
|
|
330
|
+
} = this.DSLMethods;
|
|
244
331
|
|
|
245
332
|
// Page with a "component" specified maps to a virtualType
|
|
246
333
|
if (isProductChildWithComponent(item) || (isProductChildGroup(item) && item.component)) {
|
|
@@ -248,6 +335,14 @@ export abstract class BasePluginProduct {
|
|
|
248
335
|
const name = `${ parentName }-${ item.name }`;
|
|
249
336
|
const finalName = groupNaming ? `${ parentName }-${ groupNaming }-${ item.name }` : name;
|
|
250
337
|
|
|
338
|
+
// Check for duplicate page names within the same product
|
|
339
|
+
if (this.registeredPageNames.has(finalName)) {
|
|
340
|
+
this.surfaceError(`Duplicate page name "${ item.name }" - each page must have a unique name within a product`);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
this.registeredPageNames.add(finalName);
|
|
344
|
+
this.pageIdMap.set(item.name, finalName);
|
|
345
|
+
|
|
251
346
|
const virtualTypeConfig: VirtualTypeConfiguration = {
|
|
252
347
|
label: item.label,
|
|
253
348
|
labelKey: item.labelKey,
|
|
@@ -261,7 +356,8 @@ export abstract class BasePluginProduct {
|
|
|
261
356
|
if (isProductChildGroup(item)) {
|
|
262
357
|
virtualTypeConfig.exact = true;
|
|
263
358
|
virtualTypeConfig.overview = true;
|
|
264
|
-
|
|
359
|
+
// Pass group metadata as pageChild so the route gets a unique path segment (e.g. /product/c/:cluster/groupName)
|
|
360
|
+
virtualTypeConfig.route = pluginProductsHelpers.generateVirtualTypeRoute(parentName, this.generateMetadataForGroupOverviewPageRouting(item.name, item.component as ProductChildCustomPage['component']), { extendProduct: !this.isNewProduct });
|
|
265
361
|
} else {
|
|
266
362
|
virtualTypeConfig.route = pluginProductsHelpers.generateVirtualTypeRoute(parentName, item, { extendProduct: !this.isNewProduct });
|
|
267
363
|
}
|
|
@@ -270,6 +366,15 @@ export abstract class BasePluginProduct {
|
|
|
270
366
|
} else if (isProductChildWithType(item)) {
|
|
271
367
|
// Page with a "type" specified maps to a configureType
|
|
272
368
|
const typeValue = item.type;
|
|
369
|
+
|
|
370
|
+
// Check for duplicate resource type within the same product
|
|
371
|
+
if (this.registeredPageNames.has(typeValue)) {
|
|
372
|
+
this.surfaceError(`Duplicate resource type "${ typeValue }" - each resource type must be unique within a product`);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
this.registeredPageNames.add(typeValue);
|
|
376
|
+
this.pageIdMap.set(typeValue, typeValue);
|
|
377
|
+
|
|
273
378
|
const route = pluginProductsHelpers.generateConfigureTypeRoute(parentName, item, { extendProduct: !this.isNewProduct });
|
|
274
379
|
|
|
275
380
|
const configureTypeConfig: ConfigureTypeConfiguration = {
|
|
@@ -280,6 +385,22 @@ export abstract class BasePluginProduct {
|
|
|
280
385
|
customRoute: route
|
|
281
386
|
};
|
|
282
387
|
|
|
388
|
+
if (item.headers || item.sspHeaders) {
|
|
389
|
+
headers(item.type, item.headers, item.sspHeaders);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
if (item.overrideListResourceName) {
|
|
393
|
+
mapType(item.type, item.overrideListResourceName);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
if (item.hideFromNav) {
|
|
397
|
+
ignoreType(item.type);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
if (item.hideBulkActions) {
|
|
401
|
+
hideBulkActions(item.type, true);
|
|
402
|
+
}
|
|
403
|
+
|
|
283
404
|
configureType(typeValue, { ...configureTypeConfig, ...(item.config || {}) });
|
|
284
405
|
|
|
285
406
|
if (item.weight) {
|
|
@@ -300,10 +421,6 @@ export abstract class BasePluginProduct {
|
|
|
300
421
|
this.surfaceError('Group items cannot have a "type" property - only custom pages can have groups.');
|
|
301
422
|
}
|
|
302
423
|
|
|
303
|
-
if (child.component && !this.isNewProduct) {
|
|
304
|
-
this.surfaceError('When extending an existing product, group parent items cannot have a component because of route matching conflicts.');
|
|
305
|
-
}
|
|
306
|
-
|
|
307
424
|
let route;
|
|
308
425
|
|
|
309
426
|
if (!child.component) {
|
|
@@ -316,7 +433,7 @@ export abstract class BasePluginProduct {
|
|
|
316
433
|
|
|
317
434
|
route = pluginProductsHelpers.generateVirtualTypeRoute(parentName, pageForRoute, { extendProduct: !this.isNewProduct });
|
|
318
435
|
} else {
|
|
319
|
-
route = pluginProductsHelpers.generateVirtualTypeRoute(parentName,
|
|
436
|
+
route = pluginProductsHelpers.generateVirtualTypeRoute(parentName, this.generateMetadataForGroupOverviewPageRouting(child.name, child.component), { component: child.component, extendProduct: !this.isNewProduct });
|
|
320
437
|
}
|
|
321
438
|
|
|
322
439
|
// add the route for the group page/parent
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
RouteRecordRawWithParams, ProductChildGroup, ProductChild,
|
|
3
|
-
ProductChildCustomPage, ProductChildResourcePage, ProductRegistrationRouteGenerationOptions
|
|
3
|
+
ProductChildCustomPage, ProductChildResourcePage, ProductRegistrationRouteGenerationOptions,
|
|
4
|
+
OverviewPageRoutingMetadata
|
|
4
5
|
} from '@shell/core/plugin-types';
|
|
5
6
|
import { BLANK_CLUSTER } from '@shell/store/store-types';
|
|
6
7
|
|
|
@@ -62,7 +63,7 @@ class PluginProductsHelpers {
|
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
// VIRTUAL TYPE ROUTES
|
|
65
|
-
generateVirtualTypeRoute(parentName: string, pageChild: ProductChildCustomPage | undefined, options: ProductRegistrationRouteGenerationOptions = {}): RouteRecordRawWithParams {
|
|
66
|
+
generateVirtualTypeRoute(parentName: string, pageChild: ProductChildCustomPage | OverviewPageRoutingMetadata | undefined, options: ProductRegistrationRouteGenerationOptions = {}): RouteRecordRawWithParams {
|
|
66
67
|
if (options.extendProduct) {
|
|
67
68
|
return this.generateVirtualTypeRouteForExistingProduct(parentName, pageChild, options);
|
|
68
69
|
} else {
|
|
@@ -71,7 +72,7 @@ class PluginProductsHelpers {
|
|
|
71
72
|
}
|
|
72
73
|
|
|
73
74
|
// VIRTUAL TYPE ROUTES - CLUSTER LEVEL EXTENSION
|
|
74
|
-
private generateVirtualTypeRouteForExistingProduct(parentName: string, pageChild: ProductChildCustomPage | undefined, options: ProductRegistrationRouteGenerationOptions = {}): RouteRecordRawWithParams {
|
|
75
|
+
private generateVirtualTypeRouteForExistingProduct(parentName: string, pageChild: ProductChildCustomPage | OverviewPageRoutingMetadata | undefined, options: ProductRegistrationRouteGenerationOptions = {}): RouteRecordRawWithParams {
|
|
75
76
|
const { component, omitPath } = options;
|
|
76
77
|
const name = pageChild ? `c-cluster-${ parentName }-${ pageChild.name }` : `c-cluster-${ parentName }`;
|
|
77
78
|
const path = pageChild ? `c/:cluster/${ parentName }/${ pageChild.name }` : `c/:cluster/${ parentName }`;
|
|
@@ -95,7 +96,7 @@ class PluginProductsHelpers {
|
|
|
95
96
|
}
|
|
96
97
|
|
|
97
98
|
// VIRTUAL TYPE ROUTES - TOP LEVEL EXTENSION
|
|
98
|
-
private generateVirtualTypeRouteForNewProduct(parentName: string, pageChild: ProductChildCustomPage | undefined, options: ProductRegistrationRouteGenerationOptions = {}): RouteRecordRawWithParams {
|
|
99
|
+
private generateVirtualTypeRouteForNewProduct(parentName: string, pageChild: ProductChildCustomPage | OverviewPageRoutingMetadata | undefined, options: ProductRegistrationRouteGenerationOptions = {}): RouteRecordRawWithParams {
|
|
99
100
|
const { component, omitPath } = options;
|
|
100
101
|
const name = pageChild ? `${ parentName }-c-cluster-${ pageChild.name }` : `${ parentName }-c-cluster`;
|
|
101
102
|
const path = pageChild ? `${ parentName }/c/:cluster/${ pageChild.name }` : `${ parentName }/c/:cluster`;
|
package/core/plugin-products.ts
CHANGED
package/core/plugin-types.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { NAME as EXPLORER_PROD_NAME } from '@shell/config/product/explorer.js';
|
|
|
4
4
|
import { NAME as CLUSTER_MAN_PROD_NAME } from '@shell/config/product/manager.js';
|
|
5
5
|
import { NAME as SETTINGS_PROD_NAME } from '@shell/config/product/settings.js';
|
|
6
6
|
import { NAME as AUTH_PROD_NAME } from '@shell/config/product/auth.js';
|
|
7
|
-
import { ProductOptions } from '@shell/core/types';
|
|
7
|
+
import { ProductOptions, HeaderOptions, PaginationHeaderOptions } from '@shell/core/types';
|
|
8
8
|
|
|
9
9
|
type Async<T> = () => Promise<T>;
|
|
10
10
|
|
|
@@ -150,12 +150,27 @@ export type ConfigureTypeConfiguration = {
|
|
|
150
150
|
// ]
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
+
/**
|
|
154
|
+
* Represents a Vue component or an async function that resolves to a Vue component, used for route components in product configuration
|
|
155
|
+
*/
|
|
156
|
+
export type VueRouteComponent = RouteComponent | Async<RouteComponent>;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Metadata for route generation to a product overview page
|
|
160
|
+
*/
|
|
161
|
+
export type OverviewPageRoutingMetadata = {
|
|
162
|
+
/** Name of the overview page */
|
|
163
|
+
name: string;
|
|
164
|
+
/** Component to render for the overview page */
|
|
165
|
+
component: VueRouteComponent;
|
|
166
|
+
}
|
|
167
|
+
|
|
153
168
|
/**
|
|
154
169
|
* Represents a custom page with a component
|
|
155
170
|
*/
|
|
156
171
|
export type ProductChildCustomPage = ProductChildMetadata & {
|
|
157
172
|
/** Component to render for this custom page */
|
|
158
|
-
component:
|
|
173
|
+
component: VueRouteComponent;
|
|
159
174
|
/** Optional configuration for the page */
|
|
160
175
|
config?: VirtualTypeConfiguration;
|
|
161
176
|
};
|
|
@@ -170,6 +185,16 @@ export type ProductChildResourcePage = {
|
|
|
170
185
|
config?: ConfigureTypeConfiguration;
|
|
171
186
|
/** Ordering weight for this page among its siblings */
|
|
172
187
|
weight?: number;
|
|
188
|
+
/** Use this to override the resource name used in the list view for this type */
|
|
189
|
+
overrideListResourceName?: string;
|
|
190
|
+
/** Whether to hide this resource from the side-menu entirely */
|
|
191
|
+
hideFromNav?: boolean;
|
|
192
|
+
/** Whether to hide bulk actions for this resource */
|
|
193
|
+
hideBulkActions?: boolean;
|
|
194
|
+
/** Table headers for this resource type (client-side pagination) */
|
|
195
|
+
headers?: HeaderOptions[];
|
|
196
|
+
/** Table headers for this resource type (server-side pagination) */
|
|
197
|
+
sspHeaders?: PaginationHeaderOptions[];
|
|
173
198
|
};
|
|
174
199
|
|
|
175
200
|
/**
|
|
@@ -189,7 +214,7 @@ export type ProductChild = ProductChildGroup | ProductChildPage; // eslint-disab
|
|
|
189
214
|
* Represents a group of child pages in a product configuration
|
|
190
215
|
*/
|
|
191
216
|
export type ProductChildGroup = ProductChildMetadata & {
|
|
192
|
-
component?:
|
|
217
|
+
component?: VueRouteComponent;
|
|
193
218
|
children: ProductChild[];
|
|
194
219
|
/** Default child to navigate to */
|
|
195
220
|
default?: string;
|
|
@@ -203,6 +228,106 @@ export type ProductMetadata = Omit<ProductOptions, 'name' | 'label' | 'labelKey'
|
|
|
203
228
|
* Product name (unique identifier)
|
|
204
229
|
*/
|
|
205
230
|
name: string;
|
|
231
|
+
/**
|
|
232
|
+
* @internal
|
|
233
|
+
* Use `renameGroups` on the product metadata to remap group display names in the side-menu. Each entry matches a group's internal ID (via string or regex) and replaces its display label with a new name. This only changes how the group is labelled in the UI — it does not move resources between groups.
|
|
234
|
+
*
|
|
235
|
+
* The `groupSelector` is evaluated against group internal IDs. It can be an exact string or a `RegExp` pattern. The `newName` value is the new display name.
|
|
236
|
+
*
|
|
237
|
+
* const product: ProductMetadata = {
|
|
238
|
+
* name: 'my-app',
|
|
239
|
+
* label: 'My App',
|
|
240
|
+
* renameGroups: [
|
|
241
|
+
* // Rename a group with an ugly internal ID to a friendlier display name
|
|
242
|
+
* { groupSelector: 'cert-manager.io', newName: 'Certificates' },
|
|
243
|
+
* // Use a regex to rename all groups matching a pattern
|
|
244
|
+
* { groupSelector: /^networking\./, newName: 'Networking' },
|
|
245
|
+
* ],
|
|
246
|
+
* };
|
|
247
|
+
*/
|
|
248
|
+
renameGroups?: {
|
|
249
|
+
/** String or regex to match against group internal IDs */
|
|
250
|
+
groupSelector: RegExp | string;
|
|
251
|
+
/** Display name to use for matching groups */
|
|
252
|
+
newName: string;
|
|
253
|
+
}[];
|
|
254
|
+
/**
|
|
255
|
+
* @internal
|
|
256
|
+
*
|
|
257
|
+
* Use `moveToGroup` on the product metadata to move pages (resource types or custom pages) into specific side-menu groups. This is useful when a page should appear inside a group but isn't defined as a child of that group in the config.
|
|
258
|
+
* Each entry identifies a page by its `entryId` — the resource `type` string or the custom page `name` — and moves it into the specified group. Use the group's `name` as you defined it in your config.
|
|
259
|
+
*
|
|
260
|
+
* const monitoringGroup: ProductChildGroup = {
|
|
261
|
+
* name: 'monitoring',
|
|
262
|
+
* label: 'Monitoring',
|
|
263
|
+
* children: [
|
|
264
|
+
* { name: 'alerts', label: 'Alerts', component: () => import('./pages/Alerts.vue') },
|
|
265
|
+
* ],
|
|
266
|
+
* };
|
|
267
|
+
|
|
268
|
+
* const dashboardPage: ProductChildCustomPage = {
|
|
269
|
+
* name: 'dashboard', label: 'Dashboard', component: () => import('./pages/Dashboard.vue'),
|
|
270
|
+
* };
|
|
271
|
+
|
|
272
|
+
* const product: ProductMetadata = {
|
|
273
|
+
* name: 'my-app',
|
|
274
|
+
* label: 'My App',
|
|
275
|
+
* moveToGroup: [
|
|
276
|
+
* // Move the 'pod' resource type into the 'monitoring' group
|
|
277
|
+
* { entryId: 'pod', groupName: 'monitoring' },
|
|
278
|
+
* // Move a custom page into the 'monitoring' group
|
|
279
|
+
* { entryId: 'dashboard', groupName: 'monitoring' },
|
|
280
|
+
* ],
|
|
281
|
+
* };
|
|
282
|
+
*
|
|
283
|
+
* extension.addProduct(product, [monitoringGroup, { type: 'pod' }, dashboardPage]);
|
|
284
|
+
*
|
|
285
|
+
* Note: The `entryId` must match a page declared in the same product config — either a resource page's `type` or a custom page's `name`. The target `groupName` must be a `ProductChildGroup` defined in the same config. If either is not found, an error is thrown at registration time listing the available options. Only exact string identifiers are supported (no regex).
|
|
286
|
+
*
|
|
287
|
+
* The optional `weight` parameter controls precedence when multiple `moveToGroup` rules target the same page (default: `5`). Higher weight takes precedence.
|
|
288
|
+
*/
|
|
289
|
+
moveToGroup?: {
|
|
290
|
+
/** Page identifier — the resource `type` string or the custom page `name` */
|
|
291
|
+
entryId: string;
|
|
292
|
+
/** Target group name as defined in your group config (`name` property) */
|
|
293
|
+
groupName: string;
|
|
294
|
+
/** Ordering weight for the mapping (default: 5). Higher weight takes precedence when multiple rules match */
|
|
295
|
+
weight?: number;
|
|
296
|
+
}[];
|
|
297
|
+
/**
|
|
298
|
+
* @internal
|
|
299
|
+
*
|
|
300
|
+
* maps to DSL ignoreGroup
|
|
301
|
+
*
|
|
302
|
+
* Use `ignoreGroups` on the product metadata to hide specific side-menu groups. Each entry specifies a `groupSelector` to match group names — either an exact string or a regex pattern.
|
|
303
|
+
*
|
|
304
|
+
* The `condition` callback is optional. When provided, it receives the store getters and returns `true` to hide the group (conditional hide). When omitted, the group is always hidden (unconditional hide).
|
|
305
|
+
*
|
|
306
|
+
* Example usage:
|
|
307
|
+
* const product: ProductMetadata = {
|
|
308
|
+
* name: 'my-app',
|
|
309
|
+
* label: 'My App',
|
|
310
|
+
* ignoreGroups: [
|
|
311
|
+
* // Always hide the "internal" group (unconditional — no condition)
|
|
312
|
+
* { groupSelector: 'internal' },
|
|
313
|
+
* // Hide all groups matching a regex pattern (unconditional)
|
|
314
|
+
* { groupSelector: /^deprecated/ },
|
|
315
|
+
* // Conditionally hide based on a feature flag
|
|
316
|
+
* {
|
|
317
|
+
* groupSelector: 'experimental',
|
|
318
|
+
* condition: (getters) => !getters['features/isEnabled']('experimental-feature'),
|
|
319
|
+
* },
|
|
320
|
+
* ],
|
|
321
|
+
* };
|
|
322
|
+
*
|
|
323
|
+
*
|
|
324
|
+
* In this example, the "internal" group is always hidden, any group with a name starting with "deprecated-" is hidden, and the "experimental" group is hidden unless the "experimental-feature" flag is enabled in the store.
|
|
325
|
+
*/
|
|
326
|
+
ignoreGroups?: {
|
|
327
|
+
/** String or regex to match against group names */
|
|
328
|
+
groupSelector: string | RegExp;
|
|
329
|
+
/** Optional conditional function that accepts the root Dashboard Vuex store getters and returns true if the group should be ignored */
|
|
330
|
+
condition?: (getters: any) => boolean }[];
|
|
206
331
|
} & (
|
|
207
332
|
/** Human-readable label for the product
|
|
208
333
|
* Either label or labelKey are required */
|
|
@@ -218,5 +343,5 @@ export type ProductMetadata = Omit<ProductOptions, 'name' | 'label' | 'labelKey'
|
|
|
218
343
|
*/
|
|
219
344
|
export type ProductSinglePage = ProductMetadata & {
|
|
220
345
|
/** Component to render for this product (single page product) */
|
|
221
|
-
component:
|
|
346
|
+
component: VueRouteComponent;
|
|
222
347
|
};
|
package/core/plugin.ts
CHANGED
|
@@ -135,21 +135,29 @@ export class Plugin implements IPlugin {
|
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
addProduct(product: ProductFunction | ProductMetadata | ProductSinglePage | string, config?: ProductChild[]): void {
|
|
138
|
+
let pluginProduct: PluginProduct;
|
|
139
|
+
|
|
138
140
|
if (typeof product === 'string') {
|
|
139
|
-
|
|
141
|
+
pluginProduct = PluginProduct.fromName(this, product);
|
|
140
142
|
} else if (product?.name) {
|
|
141
143
|
if (!config) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
this.productConfigs.push(new PluginProduct(this, p, []));
|
|
144
|
+
pluginProduct = new PluginProduct(this, product as ProductSinglePage, []);
|
|
145
145
|
} else {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
this.productConfigs.push(new PluginProduct(this, p, config));
|
|
146
|
+
pluginProduct = new PluginProduct(this, product as ProductMetadata, config);
|
|
149
147
|
}
|
|
150
148
|
} else {
|
|
151
149
|
this.products.push(product as ProductFunction);
|
|
150
|
+
|
|
151
|
+
return;
|
|
152
152
|
}
|
|
153
|
+
|
|
154
|
+
const existingProduct = this.productConfigs.find((p) => p.newProduct && p.productName === pluginProduct.productName);
|
|
155
|
+
|
|
156
|
+
if (existingProduct) {
|
|
157
|
+
throw new Error(`Extensions - product "${ pluginProduct.productName }" registration error ::: addProduct can only be called once per product. Use extendProduct to add pages to an existing product.`);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
this.productConfigs.push(pluginProduct);
|
|
153
161
|
}
|
|
154
162
|
|
|
155
163
|
extendProduct(product: StandardProductName | string, config: ProductChild[] | ProductChild): void {
|
package/core/productDebugger.js
CHANGED
|
@@ -21,8 +21,13 @@ export function DSLRegistrationsPerProduct(store, prodName) {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
// prod configureType
|
|
24
|
-
if (dataType === 'typeOptions'
|
|
25
|
-
|
|
24
|
+
if (dataType === 'typeOptions') {
|
|
25
|
+
const allTypeOptions = Object.values(typeMapData[dataType]).flat();
|
|
26
|
+
const filtered = allTypeOptions.filter((item) => item.customRoute && item.customRoute.name.includes(prodName));
|
|
27
|
+
|
|
28
|
+
if (filtered.length > 0) {
|
|
29
|
+
parsedData['configureType'] = filtered;
|
|
30
|
+
}
|
|
26
31
|
}
|
|
27
32
|
|
|
28
33
|
// other types which map with prodName
|
|
@@ -36,7 +41,7 @@ export function DSLRegistrationsPerProduct(store, prodName) {
|
|
|
36
41
|
}
|
|
37
42
|
});
|
|
38
43
|
|
|
39
|
-
console.error(
|
|
44
|
+
console.error(`*** PRODUCT DATA DEBUGGER ${ prodName } **** DSLRegistrationsPerProduct`, parsedData); // eslint-disable-line no-console
|
|
40
45
|
}
|
|
41
46
|
|
|
42
47
|
export function registeredRoutes(store, prodName) {
|
|
@@ -44,5 +49,5 @@ export function registeredRoutes(store, prodName) {
|
|
|
44
49
|
|
|
45
50
|
const parsedData = routes.filter((route) => route.path.includes(prodName));
|
|
46
51
|
|
|
47
|
-
console.error(
|
|
52
|
+
console.error(`*** PRODUCT DATA DEBUGGER ${ prodName } **** registeredRoutes`, parsedData); // eslint-disable-line no-console
|
|
48
53
|
}
|
|
@@ -86,6 +86,48 @@ export interface ClusterProvisionerContext {
|
|
|
86
86
|
isView: boolean
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Existing tabs to show or hide in the cluster's detail view
|
|
91
|
+
*/
|
|
92
|
+
export interface ClusterProvisionerDetailTabs {
|
|
93
|
+
/**
|
|
94
|
+
* CAPI machine pool tab
|
|
95
|
+
*/
|
|
96
|
+
machines: boolean,
|
|
97
|
+
/**
|
|
98
|
+
* Mgmt node pool tab
|
|
99
|
+
*/
|
|
100
|
+
nodes?: boolean,
|
|
101
|
+
/**
|
|
102
|
+
* RKE2 provisioning logs
|
|
103
|
+
*/
|
|
104
|
+
logs: boolean,
|
|
105
|
+
/**
|
|
106
|
+
* RKE2 registration commands
|
|
107
|
+
*/
|
|
108
|
+
registration: boolean,
|
|
109
|
+
/**
|
|
110
|
+
* RKE2 snapshots
|
|
111
|
+
*/
|
|
112
|
+
snapshots: boolean,
|
|
113
|
+
/**
|
|
114
|
+
* Kube resources related to the instance of provisioning.cattle.io.cluster
|
|
115
|
+
*/
|
|
116
|
+
related: boolean,
|
|
117
|
+
/**
|
|
118
|
+
* Kube events associated with the instance of provisioning.cattle.io.cluster
|
|
119
|
+
*/
|
|
120
|
+
events: boolean,
|
|
121
|
+
/**
|
|
122
|
+
* Kube conditions of the provisioning.cattle.io.cluster instance
|
|
123
|
+
*/
|
|
124
|
+
conditions: boolean,
|
|
125
|
+
/**
|
|
126
|
+
* RKE2 autoscaler
|
|
127
|
+
*/
|
|
128
|
+
autoscaler?: boolean,
|
|
129
|
+
}
|
|
130
|
+
|
|
89
131
|
/**
|
|
90
132
|
* Interface that a custom Cluster Provisioner should implement
|
|
91
133
|
*
|
|
@@ -180,36 +222,7 @@ export interface IClusterProvisioner {
|
|
|
180
222
|
*
|
|
181
223
|
* `plugin.addTab(TabLocation.RESOURCE_DETAIL... ` can be used to add additional tabs to the same view
|
|
182
224
|
*/
|
|
183
|
-
detailTabs:
|
|
184
|
-
/**
|
|
185
|
-
* RKE2 machine pool tabs
|
|
186
|
-
*/
|
|
187
|
-
machines: boolean,
|
|
188
|
-
/**
|
|
189
|
-
* RKE2 provisioning logs
|
|
190
|
-
*/
|
|
191
|
-
logs: boolean,
|
|
192
|
-
/**
|
|
193
|
-
* RKE2 registration commands
|
|
194
|
-
*/
|
|
195
|
-
registration: boolean,
|
|
196
|
-
/**
|
|
197
|
-
* RKE2 snapshots
|
|
198
|
-
*/
|
|
199
|
-
snapshots: boolean,
|
|
200
|
-
/**
|
|
201
|
-
* Kube resources related to the instance of provisioning.cattle.io.cluster
|
|
202
|
-
*/
|
|
203
|
-
related: boolean,
|
|
204
|
-
/**
|
|
205
|
-
* Kube events associated with the instance of provisioning.cattle.io.cluster
|
|
206
|
-
*/
|
|
207
|
-
events: boolean,
|
|
208
|
-
/**
|
|
209
|
-
* Kube conditions of the provisioning.cattle.io.cluster instance
|
|
210
|
-
*/
|
|
211
|
-
conditions: boolean
|
|
212
|
-
};
|
|
225
|
+
detailTabs: ClusterProvisionerDetailTabs;
|
|
213
226
|
|
|
214
227
|
/* --------------------------------------------------------------------------------------
|
|
215
228
|
* Getters / Functions for Managing Machine Configs
|