# Side menu

## Defining a page as a side-menu entry (basicType)

With the `virtualType` and `configureType` we have learned how to configure a page for your Extension product, but that won't make it appear on the side-menu. For that you need to use the function `basicType` coming from `$plugin.DSL`. As an example usage of that method, one could do the following:

```ts
import { IPlugin } from '@shell/core/types';

// this is the definition of a "blank cluster" for Rancher Dashboard
// definition of a "blank cluster" in Rancher Dashboard
const BLANK_CLUSTER = '_';


export function init($plugin: IPlugin, store: any) {
  const YOUR_PRODUCT_NAME = 'myProductName';
  const YOUR_K8S_RESOURCE_NAME = 'provisioning.cattle.io.cluster';
  const CUSTOM_PAGE_NAME = 'page1';
  
  const { 
    product,
    configureType,
    virtualType,
    basicType
  } = $plugin.DSL(store, YOUR_PRODUCT_NAME);

  // registering a top-level product
  product({
    icon: 'gear',
    inStore: 'management',
    weight: 100,
    to: {
      name: `${ YOUR_PRODUCT_NAME }-c-cluster-${ CUSTOM_PAGE_NAME }`,
      params: {
        product: YOUR_PRODUCT_NAME,
        cluster: BLANK_CLUSTER
      }
    }
  });
  
  // defining a k8s resource as page
  configureType(YOUR_K8S_RESOURCE_NAME, {
    displayName: 'some-custom-name-you-wish-to-assign-to-this-resource',
    isCreatable: true,
    isEditable:  true,
    isRemovable: true,
    showAge:     true,
    showState:   true,
    canYaml:     true,
    customRoute: {
      name: `${ YOUR_PRODUCT_NAME }-c-cluster-resource`,
      params: {
        product: YOUR_PRODUCT_NAME,
        cluster: BLANK_CLUSTER,
        resource: YOUR_K8S_RESOURCE_NAME
      }
    }
  });

  

  // creating a custom page
  virtualType({
    labelKey: 'some.translation.key',
    name:     CUSTOM_PAGE_NAME,
    route:    {
      name:   `${ YOUR_PRODUCT_NAME }-c-cluster-${ CUSTOM_PAGE_NAME }`,
      params: {
        product: YOUR_PRODUCT_NAME,
        cluster: BLANK_CLUSTER
      }
    }
  });

  // => => => registering the defined pages as side-menu entries
  basicType([YOUR_K8S_RESOURCE_NAME, CUSTOM_PAGE_NAME]);
}
```

On the above example we are creating two side menu entries on a "root" level for your `YOUR_K8S_RESOURCE_NAME` and `CUSTOM_PAGE_NAME` pages. 

Menu entries can also be grouped under a common "folder/group" in the side menu. For that the `basicType` takes an additional parameter which will be the name for the folder/group" in the side-menu. An example of the grouping as a follow-up on the example above would be: 

```ts
// update of the function usage based on the example above

// => => => registering the defined pages as side-menu entries as a group 
  basicType([YOUR_K8S_RESOURCE_NAME, CUSTOM_PAGE_NAME], 'my-custom-group-name');
```

> NOTE: On the example above the label of the group on the side-menu will be `my-custom-group-name`.

## Side menu ordering (weightType and weightGroup)

How about if you wanted to change the side-menu ordering for your Extension product? That can be achieved by using the functions `weightType` and `weightGroup` coming from `$plugin.DSL`. Let's then look at the following example:

```ts
import { IPlugin } from '@shell/core/types';

// this is the definition of a "blank cluster" for Rancher Dashboard
// definition of a "blank cluster" in Rancher Dashboard
const BLANK_CLUSTER = '_';

export function init($plugin: IPlugin, store: any) {
  const YOUR_PRODUCT_NAME = 'myProductName';
  const YOUR_K8S_RESOURCE_NAME = 'provisioning.cattle.io.cluster';
  const CUSTOM_PAGE_NAME_1 = 'page1';
  const CUSTOM_PAGE_NAME_2 = 'page2';
  const CUSTOM_PAGE_NAME_3 = 'page3';
  
  const { 
    product,
    configureType,
    virtualType,
    basicType
  } = $plugin.DSL(store, YOUR_PRODUCT_NAME);
  // registering a top-level product
  product({
    icon: 'gear',
    inStore: 'management',
    weight: 100,
    to: {
      name: `${ YOUR_PRODUCT_NAME }-c-cluster-${ CUSTOM_PAGE_NAME_2 }`,
      params: {
        product: YOUR_PRODUCT_NAME,
        cluster: BLANK_CLUSTER
      }
    }
  });
  // defining a k8s resource as page
  configureType(YOUR_K8S_RESOURCE_NAME, {
    displayName: 'some-custom-name-you-wish-to-assign-to-this-resource',
    isCreatable: true,
    isEditable:  true,
    isRemovable: true,
    showAge:     true,
    showState:   true,
    canYaml:     true,
    customRoute: {
      name: `${ YOUR_PRODUCT_NAME }-c-cluster-resource`,
      params: {
        product: YOUR_PRODUCT_NAME,
        cluster: BLANK_CLUSTER,
        resource: YOUR_K8S_RESOURCE_NAME
      }
    }
  });
  // creating a custom page
  virtualType({
    labelKey: 'some.translation.key',
    name:     CUSTOM_PAGE_NAME_1,
    route:    {
      name:   `${ YOUR_PRODUCT_NAME }-c-cluster-${ CUSTOM_PAGE_NAME_1 }`,
      params: {
        product: YOUR_PRODUCT_NAME,
        cluster: BLANK_CLUSTER
      }
    }
  });
  // creating yet another custom page
  virtualType({
    labelKey: 'some.translation.key',
    name:     CUSTOM_PAGE_NAME_2,
    route:    {
      name:   `${ YOUR_PRODUCT_NAME }-c-cluster-${ CUSTOM_PAGE_NAME_2 }`,
      params: {
        product: YOUR_PRODUCT_NAME,
        cluster: BLANK_CLUSTER
      }
    }
  });
  virtualType({
    labelKey: 'some.translation.key',
    name:     CUSTOM_PAGE_NAME_3,
    route:    {
      name:   `${ YOUR_PRODUCT_NAME }-c-cluster-${ CUSTOM_PAGE_NAME_3 }`,
      params: {
        product: YOUR_PRODUCT_NAME,
        cluster: BLANK_CLUSTER
      }
    }
  });
  // registering some of the defined pages as side-menu entries in the root level
  basicType([CUSTOM_PAGE_NAME_2, CUSTOM_PAGE_NAME_3]);
  // registering some of the defined pages as side-menu entries in a group
  basicType([YOUR_K8S_RESOURCE_NAME, CUSTOM_PAGE_NAME_1], 'myAdvancedGroup');
}
```

> Note: All individual root elements (in the example would be `CUSTOM_PAGE_NAME_2` and `CUSTOM_PAGE_NAME_3`) are placed under a pseudo-group called `root`, which in turn has always a default weight of `1000`.
In the example provided above we are registering 4 pages: 1 is a "resource" page (`YOUR_K8S_RESOURCE_NAME`) and 3 are "custom" pages (`CUSTOM_PAGE_NAME_1`, `CUSTOM_PAGE_NAME_2` and `CUSTOM_PAGE_NAME_3`). 

These pages are set as side-menu entries being `YOUR_K8S_RESOURCE_NAME` and `CUSTOM_PAGE_NAME_1` in a group called `myAdvancedGroup` and 2 other pages(`CUSTOM_PAGE_NAME_2` and `CUSTOM_PAGE_NAME_3`) as a root level side-menu entry. 

The default ordering of these side-menu entries is the order on which you register them using `basicType`, taking also into consideration pseudo-group `root`, which in turn will always be above any other custom groups, provided the fact that the developer hasn't defined any custom group weight yet.

In the above example the side-menu output would be something like:

* CUSTOM_PAGE_NAME_2
* CUSTOM_PAGE_NAME_3
* myAdvancedGroup
  - YOUR_K8S_RESOURCE_NAME
  - CUSTOM_PAGE_NAME_1

If we wanted to define some custom ordering for these menu entries, we would need to use the functions `weightType` and `weightGroup`, like: 

```ts
import { IPlugin } from '@shell/core/types';

// this is the definition of a "blank cluster" for Rancher Dashboard
// definition of a "blank cluster" in Rancher Dashboard
const BLANK_CLUSTER = '_';

export function init($plugin: IPlugin, store: any) {
  const YOUR_PRODUCT_NAME = 'myProductName';
  const YOUR_K8S_RESOURCE_NAME = 'provisioning.cattle.io.cluster';
  const CUSTOM_PAGE_NAME_1 = 'page1';
  const CUSTOM_PAGE_NAME_2 = 'page2';
  const CUSTOM_PAGE_NAME_3 = 'page3';
  
  const { 
    product,
    configureType,
    virtualType,
    basicType
  } = $plugin.DSL(store, YOUR_PRODUCT_NAME);
  // registering a top-level product
  product({
    icon: 'gear',
    inStore: 'management',
    weight: 100,
    to: {
      name: `${ YOUR_PRODUCT_NAME }-c-cluster-${ CUSTOM_PAGE_NAME_2 }`,
      params: {
        product: YOUR_PRODUCT_NAME,
        cluster: BLANK_CLUSTER
      }
    }
  });
  // defining a k8s resource as page
  configureType(YOUR_K8S_RESOURCE_NAME, {
    displayName: 'some-custom-name-you-wish-to-assign-to-this-resource',
    isCreatable: true,
    isEditable:  true,
    isRemovable: true,
    showAge:     true,
    showState:   true,
    canYaml:     true,
    customRoute: {
      name: `${ YOUR_PRODUCT_NAME }-c-cluster-resource`,
      params: {
        product: YOUR_PRODUCT_NAME,
        cluster: BLANK_CLUSTER,
        resource: YOUR_K8S_RESOURCE_NAME
      }
    }
  });
  // creating a custom page
  virtualType({
    labelKey: 'some.translation.key',
    name:     CUSTOM_PAGE_NAME_1,
    route:    {
      name:   `${ YOUR_PRODUCT_NAME }-c-cluster-${ CUSTOM_PAGE_NAME_1 }`,
      params: {
        product: YOUR_PRODUCT_NAME,
        cluster: BLANK_CLUSTER
      }
    }
  });
  // creating yet another custom page
  virtualType({
    labelKey: 'some.translation.key',
    name:     CUSTOM_PAGE_NAME_2,
    route:    {
      name:   `${ YOUR_PRODUCT_NAME }-c-cluster-${ CUSTOM_PAGE_NAME_2 }`,
      params: {
        product: YOUR_PRODUCT_NAME,
        cluster: BLANK_CLUSTER
      }
    }
  });
  virtualType({
    labelKey: 'some.translation.key',
    name:     CUSTOM_PAGE_NAME_3,
    route:    {
      name:   `${ YOUR_PRODUCT_NAME }-c-cluster-${ CUSTOM_PAGE_NAME_3 }`,
      params: {
        product: YOUR_PRODUCT_NAME,
        cluster: BLANK_CLUSTER
      }
    }
  });
  // registering some of the defined pages as side-menu entries in the root level
  basicType([CUSTOM_PAGE_NAME_2, CUSTOM_PAGE_NAME_3]);
  // registering some of the defined pages as side-menu entries in a group
  basicType([YOUR_K8S_RESOURCE_NAME, CUSTOM_PAGE_NAME_1], 'myAdvancedGroup');
  // => => => individual ordering of each menu entry
  weightType(CUSTOM_PAGE_NAME_1, 2, true);
  weightType(YOUR_K8S_RESOURCE_NAME, 1, true);
  weightType(CUSTOM_PAGE_NAME_3, 2, true);
  weightType(CUSTOM_PAGE_NAME_2, 1, true);
  // => => => ordering of the grouped entry
  weightGroup('myAdvancedGroup', 1001, true);
}
```

Given the example provided above, what would be the output in terms of ordering of this side-menu?
* myAdvancedGroup
  - CUSTOM_PAGE_NAME_1
  - YOUR_K8S_RESOURCE_NAME
* CUSTOM_PAGE_NAME_3
* CUSTOM_PAGE_NAME_2

Interpreting the code on the example, it's easy to follow the ordering defined:
- We are setting 3 root level side-menu items: `CUSTOM_PAGE_NAME_2`, `CUSTOM_PAGE_NAME_3` and `myAdvancedGroup`
- Technically, as mentioned on the note above, `CUSTOM_PAGE_NAME_2` and `CUSTOM_PAGE_NAME_3` are placed under a group called `root` which has no label associated, hence why it's not perceived as "group" like `myAdvancedGroup`
- Since we are giving a weight of `1001` to `myAdvancedGroup` (the bigger, the higher it will sit on the menu ordering - higher than the default `1000` of `root`), the `myAdvancedGroup` menu will be above the `CUSTOM_PAGE_NAME_2` and `CUSTOM_PAGE_NAME_3` side-menu entries
- Inside the `myAdvancedGroup` group we are setting a specific order as well: weight of `2` to `CUSTOM_PAGE_NAME_1` and a weight of `1` to `YOUR_K8S_RESOURCE_NAME`.This will make the side-menu entry for `CUSTOM_PAGE_NAME_1` appear higher than `YOUR_K8S_RESOURCE_NAME` inside the group `myAdvancedGroup`
- As for the `CUSTOM_PAGE_NAME_2` and `CUSTOM_PAGE_NAME_3` they are done inside that virtual group called `root`. Since `CUSTOM_PAGE_NAME_3` is set a weight of `2` and `CUSTOM_PAGE_NAME_3` is set a weight of `1`, `CUSTOM_PAGE_NAME_3` will appear above `CUSTOM_PAGE_NAME_2`

> NOTE: The last parameter for the `weightType` and `weightGroup` functions is a boolean that should be set to `true` at all times so that it works properly.

## Customizing the Product Side-Menu Entry

When you register your Extension product, a top-level side-menu entry is automatically created for it.

**How It Works:**

- **Label Computation:**
The label is generated by searching for the translation key `product.<productId>`. If not found, it defaults to the product ID with its first letter capitalized.
- **Customization Example:**
To change the side‑menu entry for a product with the ID `myProduct`, add the following to your translation file at the root level:
   ```yaml
   product:
     myProduct: My Product
   ```
   This translation file should reside in your package’s localization directory (e.g., `./pkg/<extension-name>/l10n`). For more details, see the [Localization documentation](../../advanced/localization.md).
