Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
b7a6dda
reproduce Neil PR + fix some small issues
aalves08 Sep 26, 2025
86f91d2
fix type for growl message
aalves08 Sep 26, 2025
02db570
working on integrating typedoc with docusaurus
aalves08 Sep 30, 2025
dd32388
fix shim + continue integration of typedoc with docusaurus
aalves08 Oct 3, 2025
53956b9
check if it fixes build
aalves08 Oct 6, 2025
fa8a749
update docusaurus config so that builds are successful + update comme…
aalves08 Oct 6, 2025
6b7e08f
fixing some problems with the shell apis
aalves08 Oct 6, 2025
e1e5533
fix problems with focus trap on slideInManager and ModalManager + upd…
aalves08 Oct 7, 2025
45e8a19
remove auto generated sidebar content from previous docs gen
aalves08 Oct 7, 2025
ff2af5f
fix lint issues
aalves08 Oct 7, 2025
489eb40
fix docusaurus build
aalves08 Oct 7, 2025
d0ccfd1
comment out script to fix pats on auto-generated docs
aalves08 Oct 8, 2025
729fd6b
fix var type
aalves08 Oct 8, 2025
5b723a3
enable auto docs generation + fix curr shell api methods signatures a…
aalves08 Oct 9, 2025
523b64b
working on integrating notification center with shell API
aalves08 Oct 10, 2025
99dee18
working on integrating notification center with shell API
aalves08 Oct 10, 2025
bc9dd6c
adjust shell api methods args signature + add notification center to …
aalves08 Oct 13, 2025
ce31001
fix broken docs build + fix broken unit test
aalves08 Oct 13, 2025
4312631
fix broken docs build
aalves08 Oct 13, 2025
cdfc114
fix broken links with absolute paths
aalves08 Oct 14, 2025
bc2d631
fix type error from vue-router that prevents correct build
aalves08 Oct 14, 2025
5af897e
add system api to shell api
aalves08 Oct 15, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docusaurus/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
.docusaurus
.cache-loader

# Typedoc integration
docs/extensions/shell-api

# Misc
.DS_Store
.env.local
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
53 changes: 53 additions & 0 deletions docusaurus/docs/extensions/shell-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
id: shell-api
---

# Shell API

> Available from Rancher `2.13` and onwards

## What is the Shell API?

The Shell API is a functional API that helps extension developers to interact with UI elements that are included in Rancher UI that are important for extension development. We have paid special attention on the implementation side of the architecture behind this API so that developers can use features such as Intellisense and auto-completion in your favourite IDE.

![Intellisense](./screenshots/intellisense.png)

## How to use the Shell API

### Using Options API in Vue

To use the Shell API in the context of the **Options API** of a Vue component, we globally expose the `$shell` property, which is available under the `this` object, such as:

```ts
import { NotificationLevel } from '@shell/types/notifications';

this.$shell.notification.send(NotificationLevel.Success, 'Some notification title', 'Hello world! Success!', {})
```

### Using Composition API in Vue

To use the Shell API in the context of the **Composition API** of a Vue component, we'll need to import the correct method to make the API available in the component:

```ts
import { useShell } from '@shell/apis';
```

then just assign to a constant in the context for your component and use it, such as:

```ts
import { NotificationLevel } from '@shell/types/notifications';

const shellApi = useShell();

// Example method to display a Growl message
const sendNotification = () => shellApi.notification.send(NotificationLevel.Success, 'Some notification title', 'Hello world! Success!', {})
```

## Available API's

| API | Description | Example |
| :--- | :--- | :--- |
| [Slide-In API](./shell-api/interfaces/SlideInApi) | Responsible for interacting with slide-in panels | <img src={require('/img/slidein.png').default} alt="slidein example" width="500" /> |
| [Modal API](./shell-api/interfaces/ModalApi) | Responsible for interacting with modals | <img src={require('/img/modal.png').default} alt="modal example" width="500" /> |
| [Notification API](./shell-api/interfaces/NotificationApi) | Responsible for interacting with the Rancher UI Notification Center | <img src={require('/img/notification.png').default} alt="notification example" width="500" /> |
| [System API](./shell-api/interfaces/SystemApi) | API for system related information | <img src={require('/img/system.png').default} alt="system example" width="500" /> |
47 changes: 47 additions & 0 deletions docusaurus/docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,53 @@ const config = {
],

plugins: [
[
'docusaurus-plugin-typedoc',
{
// Set to true to hide the source path information entirely.
disableSources: true,

// This removes the prefix from the title of a generated page
// Ex: "Interface: ModalApi" vs "ModalApi"
textContentMappings: { 'title.memberPage': '{name}' },

// show params as code blocks
useCodeBlocks: true,

// The entry point for TypeDoc to start scanning for files.
// The path is relative to the `docusaurus` directory.
// entryPoints: ['../shell/apis/shell/*'],
entryPoints: ['../shell/apis/intf/shell.ts'],

// The tsconfig file for TypeDoc to use.
// This is CRITICAL to point to our special, isolated config
// to avoid the thousands of compilation errors from the main project.
tsconfig: 'tsconfig-typedoc-integration.json',

// The output directory for the generated markdown files.
// We are targeting the specific versioned folder for the "next" version
// and placing it directly into the "advanced" subfolder.
out: 'docs/extensions/shell-api',

// disables REAME as default entry point
readme: 'none',

// prevents deletion of files that are in "out" directory
cleanOutputDir: false,

// allows auto-generation of the sidebar for the auto-generated items
sidebar: { autoConfiguration: true },

// since we can't prevent the generation of a "bad" index file, we rename it to something harmless
entryFileName: '_api-index.md',

// A unique ID for this plugin instance. Needed so that it generates all the files successfully (including sidebar entries)
id: 'api-docs',

// exclude all code comments marked as @internal
excludeInternal: true
},
],
[require.resolve('docusaurus-lunr-search'), { excludeRoutes: ['internal/*', 'internal/**/*', '/internal/*', '/internal/**/*', 'blog/*', 'blog/**/*', '/blog/*', '/blog/**/*'] }
],
[
Expand Down
75 changes: 74 additions & 1 deletion docusaurus/extensionSidebar.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,67 @@
const fs = require('fs');
const path = require('path');

// Define the absolute path to the sidebar file that `docusaurus-plugin-typedoc` generates.
const typedocSidebarPath = path.resolve(__dirname, './docs/extensions/shell-api/typedoc-sidebar.cjs');

/**
* Recursively processes an array of Docusaurus sidebar items.
* It finds any 'doc' items and removes the incorrect 'extensions/' prefix
* from their ID, which is a known issue with the plugin in multi-instance setups.
*
* @param {Array<object>} items The array of sidebar items from the generated file.
* @returns {Array<object>} The corrected array of sidebar items.
*/
function fixTypedocIds(items) {
return items.map((item) => {
// 1. Start with a shallow copy of the item.
const newItem = { ...item };

// Remove 'extensions/' prefix from 'doc' IDs
if (newItem.type === 'doc' && newItem.id && newItem.id.startsWith('extensions/')) {
newItem.id = newItem.id.replace('extensions/', '');
}

// RECURSION: Process sub-items if it's a 'category'
if (newItem.type === 'category' && newItem.items) {
newItem.items = fixTypedocIds(newItem.items);
}

// Remove 'link' property if it points to an '_api-index' document (auto-generated by the plugin... we discard them)
const link = newItem.link;

if (
link &&
typeof link === 'object' && link !== null &&
link.id &&
typeof link.id === 'string' &&
link.id.endsWith('_api-index')
) {
// Use object destructuring to create a new object without the 'link' property
// and return it immediately.
const { link: removedLink, ...rest } = newItem;

return rest;
}

// Return the (potentially) modified item.
return newItem;
});
}

// Initialize an empty array for the TypeDoc sidebar items.
let typedocSidebarItems = [];

// Safely check if the generated `typedoc-sidebar.cjs` file exists.
// This prevents build errors if the file hasn't been generated yet.
if (fs.existsSync(typedocSidebarPath)) {
// If the file exists, import its contents.
const originalTypedocSidebar = require(typedocSidebarPath);

// Run the imported items through our correction function.
typedocSidebarItems = fixTypedocIds(originalTypedocSidebar);
}

/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */
const sidebars = {
extensionsSidebar: [
Expand Down Expand Up @@ -51,6 +115,15 @@ const sidebars = {
],
}],
},
{
type: 'category',
label: 'Shell API',
link: {
type: 'doc',
id: 'shell-api',
},
items: typedocSidebarItems
},
{
type: 'category',
label: 'Extensions API',
Expand Down Expand Up @@ -123,7 +196,7 @@ const sidebars = {
'advanced/stores',
'advanced/version-compatibility',
'advanced/safe-mode',
'advanced/yarn-link',
'advanced/yarn-link'
]
},
'publishing',
Expand Down
10 changes: 8 additions & 2 deletions docusaurus/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,17 @@
"prism-react-renderer": "^2.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"yaml": "2.5.1"
"yaml": "2.5.1",
"docusaurus-plugin-typedoc": "^1.4.2",
"typedoc": "^0.28.13",
"typedoc-plugin-markdown": "^4.9.0",
"typescript": "^5.9.2"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "^3.6.3",
"@docusaurus/types": "3.0.0"
"@docusaurus/types": "3.0.0",
"vue": "3.5.18",
"vue-router": "4.5.1"
},
"browserslist": {
"production": [
Expand Down
13 changes: 13 additions & 0 deletions docusaurus/src/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,19 @@ a.gettingStartedLink .resourcesSvg svg {
hr {
margin: 2rem 0;
}

/* Fixes for CSS issues with auto generated docs */
/* Fixes anchor styling methods subtitle */
h4.anchor {
font-size: 26px;
}

/* Fixes anchor styling for method params */
h5.anchor {
font-size: 20px;
text-decoration: underline;
}

@media screen and (max-width: 996px) {
.homepage-banner {
padding: 30px 30px;
Expand Down
Binary file added docusaurus/static/img/growl.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docusaurus/static/img/modal.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docusaurus/static/img/notification.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docusaurus/static/img/notifications/error.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docusaurus/static/img/notifications/success.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docusaurus/static/img/notifications/warning.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docusaurus/static/img/slidein.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docusaurus/static/img/system.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions docusaurus/tsconfig-typedoc-integration.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"extends": "./tsconfig.paths.json",
"compilerOptions": {
"baseUrl": ".",
"module": "commonjs",
"target": "es6",
"esModuleInterop": true,
"skipLibCheck": true,
},
"include": [
"../shell/apis/intf/shell.ts"
],
"exclude": [
"node_modules"
]
}
28 changes: 28 additions & 0 deletions docusaurus/tsconfig.paths.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"compilerOptions": {
"paths": {
// we need to explicitly tell docusaurus where to look for vue types...
"vue": [
"node_modules/vue"
],
"vue-router": [
"node_modules/vue-router"
],
"~/*": [
"../*"
],
"@/*": [
"../*"
],
"@shell/*": [
"../shell/*"
],
"@pkg/*": [
"../shell/pkg/*"
],
"@components/*": [
"../pkg/rancher-components/src/components/*"
]
}
}
}
3 changes: 2 additions & 1 deletion pkg/rancher-prime/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@
"**/*.ts",
"**/*.d.ts",
"**/*.tsx",
"**/*.vue"
"**/*.vue",
"../../shell/types/vue-shim.d.ts"
],
"exclude": [
"../../node_modules"
Expand Down
61 changes: 61 additions & 0 deletions shell/apis/impl/apis.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { throttle } from 'lodash';
import { createExtensionManager } from '@shell/core/extension-manager-impl';
import { ShellApiImpl } from '@shell/apis/shell';

/**
* Initialise the APIs that are available in the shell
*
* This is loaded during app startiup in `initialize/index.js`
*/
export function initUiApis(context: any, inject: any, vueApp: any) {
// ======================================================================================================================
// Extension Manager
// ======================================================================================================================
const extensionManager = createExtensionManager(context);
const deprecationMessage = '[DEPRECATED] `this.$plugin` is deprecated and will be removed in a future version. Use `this.$extension` instead.';

registerApi('plugin', deprecationProxy(extensionManager, deprecationMessage), inject, vueApp);
registerApi('extension', extensionManager, inject, vueApp);

// ======================================================================================================================
// Shell API
// ======================================================================================================================
registerApi('shell', new ShellApiImpl(context.store), inject, vueApp);
}

// ======================================================================================================================
// Helpers
// ======================================================================================================================

function registerApi(name: string, api: any, inject: any, vueApp: any) {
inject(name, api);
vueApp.provide(`$${ name }`, api);
}

/**
* Proxy to log a deprecation warning when target is accessed. Only prints
* deprecation warnings in dev builds.
* @param {*} target the object to proxy
* @param {*} message the deprecation warning to print to the console
* @returns The proxied target that prints a deprecation warning when target is
* accessed
*/
const deprecationProxy = (target: any, message: string) => {
const logWarning = throttle(() => {
// eslint-disable-next-line no-console
console.warn(message);
}, 150);

const deprecationHandler = {
get(target: any, prop: any) {
logWarning();

return Reflect.get(target, prop);
}
};

// an empty handler allows the proxy to behave just like the original target
const proxyHandler = !!process.env.dev ? deprecationHandler : {};

return new Proxy(target, proxyHandler);
};
Loading
Loading