Skip to main content
Version: v3

Product Registration Examples (Experimental)

Note: These examples use the experimental product registration API, which may change in future releases. For the current stable approach, see Extension as a top-level product and Extension as a cluster-level product.

This page provides a set of copy-paste-ready examples for common product registration use cases. Each example is self-contained and shows the complete index.ts for an Extension.

For a detailed explanation of each API method and its types, see the Product Registration API reference.

Quick start: empty product

Register a product with a single call. Useful for bootstrapping a new Extension before adding real pages:

// ./index.ts
import { importTypes } from '@rancher/auto-import';
import { IPlugin } from '@shell/core/types';

export default function(extension: IPlugin) {
importTypes(extension);
extension.metadata = require('./package.json');

extension.addProduct('my-first-product');
}

Result: A product named "my-first-product" appears in the top-level slide-in menu with a default empty page.


Single page product

A product that shows one full-page component with no side-menu. Good for dashboards or settings screens:

// ./index.ts
import { importTypes } from '@rancher/auto-import';
import { IPlugin } from '@shell/core/types';
import { ProductSinglePage } from '@shell/core/plugin-types';

export default function(extension: IPlugin) {
importTypes(extension);
extension.metadata = require('./package.json');

const product: ProductSinglePage = {
name: 'status-board',
label: 'Status Board',
icon: 'globe',
component: () => import('./pages/StatusBoard.vue'),
};

extension.addProduct(product);
}

Result: A product with a single full-page view and no side-menu.


Multiple custom pages

A product with several custom pages listed as side-menu entries:

// ./index.ts
import { importTypes } from '@rancher/auto-import';
import { IPlugin } from '@shell/core/types';
import {
ProductMetadata,
ProductChildCustomPage
} from '@shell/core/plugin-types';

export default function(extension: IPlugin) {
importTypes(extension);
extension.metadata = require('./package.json');

const overviewPage: ProductChildCustomPage = {
name: 'overview',
label: 'Overview',
component: () => import('./pages/Overview.vue'),
weight: 3,
};

const usersPage: ProductChildCustomPage = {
name: 'users',
label: 'Users',
component: () => import('./pages/Users.vue'),
weight: 2,
};

const logsPage: ProductChildCustomPage = {
name: 'logs',
label: 'Logs',
component: () => import('./pages/Logs.vue'),
weight: 1,
};

const product: ProductMetadata = {
name: 'my-app',
label: 'My App',
icon: 'gear',
};

extension.addProduct(product, [overviewPage, usersPage, logsPage]);
}

Result: A product with three pages in the side-menu, ordered by weight (bigger number on top).


Resource pages (Kubernetes resources)

A product that uses Rancher Dashboard's built-in list/detail/edit views for Kubernetes resource types:

// ./index.ts
import { importTypes } from '@rancher/auto-import';
import { IPlugin } from '@shell/core/types';
import {
ProductMetadata,
ProductChildResourcePage
} from '@shell/core/plugin-types';

export default function(extension: IPlugin) {
importTypes(extension);
extension.metadata = require('./package.json');

const clusterPage: ProductChildResourcePage = {
type: 'provisioning.cattle.io.cluster',
weight: 2,
config: {
displayName: 'Clusters',
isCreatable: true,
isEditable: true,
isRemovable: true,
canYaml: true,
showState: true,
showAge: true,
},
};

const secretsPage: ProductChildResourcePage = {
type: 'secret',
weight: 1,
};

const product: ProductMetadata = {
name: 'cluster-tools',
label: 'Cluster Tools',
};

extension.addProduct(product, [clusterPage, secretsPage]);
}

Result: A product with two resource pages. Clicking a resource in the side-menu shows Rancher's standard list view; clicking a row opens the detail view.


Mixed pages: custom + resource

Combine custom pages and resource pages in the same product:

// ./index.ts
import { importTypes } from '@rancher/auto-import';
import { IPlugin } from '@shell/core/types';
import {
ProductMetadata,
ProductChildCustomPage,
ProductChildResourcePage
} from '@shell/core/plugin-types';

export default function(extension: IPlugin) {
importTypes(extension);
extension.metadata = require('./package.json');

const dashboardPage: ProductChildCustomPage = {
name: 'dashboard',
label: 'Dashboard',
component: () => import('./pages/Dashboard.vue'),
weight: 3,
};

const clusterPage: ProductChildResourcePage = {
type: 'provisioning.cattle.io.cluster',
weight: 2,
};

const settingsPage: ProductChildCustomPage = {
name: 'settings',
label: 'Settings',
component: () => import('./pages/Settings.vue'),
weight: 1,
};

const product: ProductMetadata = {
name: 'my-platform',
label: 'My Platform',
};

extension.addProduct(product, [dashboardPage, clusterPage, settingsPage]);
}

Pages organized in groups

Use groups to create collapsible folder/groups in the side-menu:

// ./index.ts
import { importTypes } from '@rancher/auto-import';
import { IPlugin } from '@shell/core/types';
import {
ProductMetadata,
ProductChildCustomPage,
ProductChildGroup
} from '@shell/core/plugin-types';

export default function(extension: IPlugin) {
importTypes(extension);
extension.metadata = require('./package.json');

// Standalone page (outside any group)
const homePage: ProductChildCustomPage = {
name: 'home',
label: 'Home',
component: () => import('./pages/Home.vue'),
weight: 10,
};

// "Monitoring" group with two pages
const alertsPage: ProductChildCustomPage = {
name: 'alerts',
label: 'Alerts',
component: () => import('./pages/Alerts.vue'),
};

const metricsPage: ProductChildCustomPage = {
name: 'metrics',
label: 'Metrics',
component: () => import('./pages/Metrics.vue'),
};

const monitoringGroup: ProductChildGroup = {
name: 'monitoring',
label: 'Monitoring',
weight: 5,
children: [alertsPage, metricsPage],
};

// "Admin" group with two pages
const usersPage: ProductChildCustomPage = {
name: 'users',
label: 'Users',
component: () => import('./pages/Users.vue'),
};

const rolesPage: ProductChildCustomPage = {
name: 'roles',
label: 'Roles',
component: () => import('./pages/Roles.vue'),
};

const adminGroup: ProductChildGroup = {
name: 'admin',
label: 'Administration',
weight: 1,
children: [usersPage, rolesPage],
};

const product: ProductMetadata = {
name: 'my-platform',
label: 'My Platform',
};

extension.addProduct(product, [homePage, monitoringGroup, adminGroup]);
}

Result: The side-menu will look like:

Home
▾ Monitoring
Alerts
Metrics
▾ Administration
Users
Roles

Group with its own page

A group can have its own component that renders when the group header is clicked, instead of navigating to the first child:

const monitoringGroup: ProductChildGroup = {
name: 'monitoring',
label: 'Monitoring',
component: () => import('./pages/MonitoringOverview.vue'), // group's own page
children: [alertsPage, metricsPage],
};

Result: Clicking "Monitoring" in the side-menu shows the MonitoringOverview component. Expanding the group reveals the child pages.


Extending Cluster Explorer

Add a standalone custom page to the Cluster Explorer product:

// ./index.ts
import { importTypes } from '@rancher/auto-import';
import { IPlugin } from '@shell/core/types';
import { ProductChildCustomPage } from '@shell/core/plugin-types';

export default function(extension: IPlugin) {
importTypes(extension);
extension.metadata = require('./package.json');

const customPage: ProductChildCustomPage = {
name: 'cost-analysis',
label: 'Cost Analysis',
component: () => import('./pages/CostAnalysis.vue'),
};

extension.extendProduct('explorer', [customPage]);
}

Or, to add pages inside a group:

// ./index.ts
import { importTypes } from '@rancher/auto-import';
import { IPlugin } from '@shell/core/types';
import {
ProductChildCustomPage,
ProductChildGroup
} from '@shell/core/plugin-types';

export default function(extension: IPlugin) {
importTypes(extension);
extension.metadata = require('./package.json');

const costPage: ProductChildCustomPage = {
name: 'cost-analysis',
label: 'Cost Analysis',
component: () => import('./pages/CostAnalysis.vue'),
};

const usagePage: ProductChildCustomPage = {
name: 'usage-report',
label: 'Usage Report',
component: () => import('./pages/UsageReport.vue'),
};

const insightsGroup: ProductChildGroup = {
name: 'insights',
label: 'Insights',
children: [costPage, usagePage],
};

extension.extendProduct('explorer', [insightsGroup]);
}

The products available for extension are: 'explorer', 'manager', 'settings', and 'auth'.


Using translation keys instead of labels

For i18n support, use labelKey instead of label. The key will be resolved from your Extension's translation files:

const product: ProductMetadata = {
name: 'my-app',
labelKey: 'product.myApp.label',
icon: 'gear',
};

const overviewPage: ProductChildCustomPage = {
name: 'overview',
labelKey: 'product.myApp.overview',
component: () => import('./pages/Overview.vue'),
};

extension.addProduct(product, [overviewPage]);

Note: See the Localization documentation for details on setting up translation files.