1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Add some documentation

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2022-01-19 09:44:28 -05:00
parent b134cdca97
commit 4aae3f3fcd
10 changed files with 159 additions and 63 deletions

View File

@ -103,8 +103,12 @@ publish-npm: node_modules build-npm
cd src/extensions/npm/extensions && npm publish --access=public --tag=$(NPM_RELEASE_TAG) cd src/extensions/npm/extensions && npm publish --access=public --tag=$(NPM_RELEASE_TAG)
git restore src/extensions/npm/extensions/package.json git restore src/extensions/npm/extensions/package.json
.PHONY: build-docs
build-docs:
yarn typedocs-extensions-api
.PHONY: docs .PHONY: docs
docs: docs: build-docs
yarn mkdocs-serve-local yarn mkdocs-serve-local
.PHONY: clean-extensions .PHONY: clean-extensions

View File

@ -15,7 +15,7 @@ Each guide or code sample includes the following:
## Guides ## Guides
| Guide | APIs | | Guide | APIs |
| ----- | ----- | | ------------------------------------------------------------------ | ---------------------- |
| [Generate new extension project](generator.md) | | | [Generate new extension project](generator.md) | |
| [Main process extension](main-extension.md) | Main.LensExtension | | [Main process extension](main-extension.md) | Main.LensExtension |
| [Renderer process extension](renderer-extension.md) | Renderer.LensExtension | | [Renderer process extension](renderer-extension.md) | Renderer.LensExtension |
@ -27,13 +27,15 @@ Each guide or code sample includes the following:
| [Working with mobx](working-with-mobx.md) | | | [Working with mobx](working-with-mobx.md) | |
| [Protocol Handlers](protocol-handlers.md) | | | [Protocol Handlers](protocol-handlers.md) | |
| [Sending Data between main and renderer](ipc.md) | | | [Sending Data between main and renderer](ipc.md) | |
| [Catalog Entities and Categories](catalog.md) | |
| [Adding Custom Columns for Categories](custom-category-columns.md) | |
## Samples ## Samples
| Sample | APIs | | Sample | APIs |
| ----- | ----- | | ---------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
[hello-world](https://github.com/lensapp/lens-extension-samples/tree/master/helloworld-sample) | LensMainExtension <br> LensRendererExtension <br> Renderer.Component.Icon <br> Renderer.Component.IconProps | | [hello-world](https://github.com/lensapp/lens-extension-samples/tree/master/helloworld-sample) | LensMainExtension <br> LensRendererExtension <br> Renderer.Component.Icon <br> Renderer.Component.IconProps |
[styling-css-modules-sample](https://github.com/lensapp/lens-extension-samples/tree/master/styling-css-modules-sample) | LensMainExtension <br> LensRendererExtension <br> Renderer.Component.Icon <br> Renderer.Component.IconProps | | [styling-css-modules-sample](https://github.com/lensapp/lens-extension-samples/tree/master/styling-css-modules-sample) | LensMainExtension <br> LensRendererExtension <br> Renderer.Component.Icon <br> Renderer.Component.IconProps |
[styling-emotion-sample](https://github.com/lensapp/lens-extension-samples/tree/master/styling-emotion-sample) | LensMainExtension <br> LensRendererExtension <br> Renderer.Component.Icon <br> Renderer.Component.IconProps | | [styling-emotion-sample](https://github.com/lensapp/lens-extension-samples/tree/master/styling-emotion-sample) | LensMainExtension <br> LensRendererExtension <br> Renderer.Component.Icon <br> Renderer.Component.IconProps |
[styling-sass-sample](https://github.com/lensapp/lens-extension-samples/tree/master/styling-sass-sample) | LensMainExtension <br> LensRendererExtension <br> Renderer.Component.Icon <br> Renderer.Component.IconProps | | [styling-sass-sample](https://github.com/lensapp/lens-extension-samples/tree/master/styling-sass-sample) | LensMainExtension <br> LensRendererExtension <br> Renderer.Component.Icon <br> Renderer.Component.IconProps |
[custom-resource-page](https://github.com/lensapp/lens-extension-samples/tree/master/custom-resource-page) | LensRendererExtension <br> Renderer.K8sApi.KubeApi <br> Renderer.K8sApi.KubeObjectStore <br> Renderer.Component.KubeObjectListLayout <br> Renderer.Component.KubeObjectDetailsProps <br> Renderer.Component.IconProps | | [custom-resource-page](https://github.com/lensapp/lens-extension-samples/tree/master/custom-resource-page) | LensRendererExtension <br> Renderer.K8sApi.KubeApi <br> Renderer.K8sApi.KubeObjectStore <br> Renderer.Component.KubeObjectListLayout <br> Renderer.Component.KubeObjectDetailsProps <br> Renderer.Component.IconProps |

View File

@ -1,5 +1,27 @@
# Catalog (WIP) # Catalog (WIP)
## CatalogCategoryRegistry This guide is a brief overview about how the catalog works within Lens.
The catalog should be thought of as the single source of truth about data within Lens.
## CatalogEntityRegistry The data flow is unidirectional, it only flows from the main side to the renderer side.
All data is public within the catalog.
## Categories
A cateogry is the declaration to the catalog of a specific kind of entity.
It declares the currently supported versions of that kind of entity but providing the constructors for the entity classes.
To declare a new category class you must create a new class that extends [Common.Catalog.CatalogCategory](../api/classes/Common.Catalog.CatalogCategory.md) and implement all of the abstract fields.
The categories provided by Lens itself have the following names:
- `KubernetesClusters`
- `WebLinks`
- `General`
To register a category, call the `Main.Catalog.catalogCategories.add()` and `Renderer.Catalog.catalogCategories.add()` with instances of your class.
## Entities
An entity is the data within the catalog.
All entities are typed and the class instances will be recreated on the renderer side by the catalog and the category registrations.

View File

@ -16,11 +16,11 @@ import { Main } from "@k8slens/extensions";
export default class ExampleExtensionMain extends Main.LensExtension { export default class ExampleExtensionMain extends Main.LensExtension {
onActivate() { onActivate() {
console.log('custom main process extension code started'); console.log("custom main process extension code started");
} }
onDeactivate() { onDeactivate() {
console.log('custom main process extension de-activated'); console.log("custom main process extension de-activated");
} }
} }
``` ```
@ -40,7 +40,7 @@ The example above logs messages when the extension is enabled and disabled.
To see standard output from the main process there must be a console connected to it. To see standard output from the main process there must be a console connected to it.
Achieve this by starting Lens from the command prompt. Achieve this by starting Lens from the command prompt.
For more details on accessing Lens state data, please see the [Stores](../stores) guide. For more details on accessing Lens state data, please see the [Stores](stores.md) guide.
### `appMenus` ### `appMenus`
@ -57,9 +57,9 @@ export default class SamplePageMainExtension extends Main.LensExtension {
label: "Sample", label: "Sample",
click() { click() {
console.log("Sample clicked"); console.log("Sample clicked");
} },
} },
] ];
} }
``` ```
@ -67,11 +67,11 @@ export default class SamplePageMainExtension extends Main.LensExtension {
`MenuRegistration` extends Electron's `MenuItemConstructorOptions` interface. `MenuRegistration` extends Electron's `MenuItemConstructorOptions` interface.
The properties of the appMenus array objects are defined as follows: The properties of the appMenus array objects are defined as follows:
* `parentId` is the name of the menu where your new menu item will be listed. - `parentId` is the name of the menu where your new menu item will be listed.
Valid values include: `"file"`, `"edit"`, `"view"`, and `"help"`. Valid values include: `"file"`, `"edit"`, `"view"`, and `"help"`.
`"lens"` is valid on Mac only. `"lens"` is valid on Mac only.
* `label` is the name of your menu item. - `label` is the name of your menu item.
* `click()` is called when the menu item is selected. - `click()` is called when the menu item is selected.
In this example, we simply log a message. In this example, we simply log a message.
However, you would typically have this navigate to a specific page or perform another operation. However, you would typically have this navigate to a specific page or perform another operation.
Note that pages are associated with the [`Renderer.LensExtension`](renderer-extension.md) class and can be defined in the process of extending it. Note that pages are associated with the [`Renderer.LensExtension`](renderer-extension.md) class and can be defined in the process of extending it.
@ -86,9 +86,9 @@ export default class SamplePageMainExtension extends Main.LensExtension {
{ {
parentId: "help", parentId: "help",
label: "Sample", label: "Sample",
click: () => this.navigate("myGlobalPage") click: () => this.navigate("myGlobalPage"),
} },
] ];
} }
``` ```
@ -104,10 +104,10 @@ interface TrayMenuRegistration {
label?: string; label?: string;
click?: (menuItem: TrayMenuRegistration) => void; click?: (menuItem: TrayMenuRegistration) => void;
id?: string; id?: string;
type?: "normal" | "separator" | "submenu" type?: "normal" | "separator" | "submenu";
toolTip?: string; toolTip?: string;
enabled?: boolean; enabled?: boolean;
submenu?: TrayMenuRegistration[] submenu?: TrayMenuRegistration[];
} }
``` ```
@ -117,10 +117,14 @@ The following example demonstrates how tray menus can be added from extension:
import { Main } from "@k8slens/extensions"; import { Main } from "@k8slens/extensions";
export default class SampleTrayMenuMainExtension extends Main.LensExtension { export default class SampleTrayMenuMainExtension extends Main.LensExtension {
trayMenus = [{ trayMenus = [
{
label: "menu from the extension", label: "menu from the extension",
click: () => { console.log("tray menu clicked!") } click: () => {
}] console.log("tray menu clicked!");
},
},
];
} }
``` ```

View File

@ -84,35 +84,91 @@ export interface CatalogCategorySpec {
} }
/** /**
* If the filter returns true, the menu item is displayed * If the filter return a thruthy value, the menu item is displayed
*/ */
export type AddMenuFilter = (menu: CatalogEntityAddMenu) => any; export type AddMenuFilter = (menu: CatalogEntityAddMenu) => any;
export interface CatalogCategoryEvents { export interface CatalogCategoryEvents {
/**
* This event will be emitted when the category is loaded in the catalog
* view.
*/
load: () => void; load: () => void;
/**
* This event will be emitted when the catalog add menu is opened and is the
* way to added entries to that menu.
*/
catalogAddMenu: (context: CatalogEntityAddMenuContext) => void; catalogAddMenu: (context: CatalogEntityAddMenuContext) => void;
/**
* This event will be emitted when the context menu for an entity is declared
* by this category is opened.
*/
contextMenuOpen: (entity: CatalogEntity, context: CatalogEntityContextMenuContext) => void; contextMenuOpen: (entity: CatalogEntity, context: CatalogEntityContextMenuContext) => void;
} }
export abstract class CatalogCategory extends (EventEmitter as new () => TypedEmitter<CatalogCategoryEvents>) { export abstract class CatalogCategory extends (EventEmitter as new () => TypedEmitter<CatalogCategoryEvents>) {
/**
* The version of category that you are wanting to declare.
*
* Currently supported values:
*
* - `"catalog.k8slens.dev/v1alpha1"`
*/
abstract readonly apiVersion: string; abstract readonly apiVersion: string;
/**
* The kind of item you wish to declare.
*
* Currently supported values:
*
* - `"CatalogCategory"`
*/
abstract readonly kind: string; abstract readonly kind: string;
abstract metadata: {
/**
* The data about the category itself
*/
abstract readonly metadata: {
/**
* The name of your category. The category can be searched for by this
* value. This will also be used for the catalog menu.
*/
name: string; name: string;
/**
* Either an `<svg>` or the name of an icon from {@link IconProps}
*/
icon: string; icon: string;
}; };
/**
* The most important part of a category, as it is where entity versions are declared.
*/
abstract spec: CatalogCategorySpec; abstract spec: CatalogCategorySpec;
/**
* @internal
*/
protected filters = observable.set<AddMenuFilter>([], { protected filters = observable.set<AddMenuFilter>([], {
deep: false, deep: false,
}); });
static parseId(id = ""): { group?: string, kind?: string } { /**
* Parse a category ID into parts.
* @param id The id of a category is parse
* @returns The group and kind parts of the ID
*/
public static parseId(id: string): { group?: string, kind?: string } {
const [group, kind] = id.split("/") ?? []; const [group, kind] = id.split("/") ?? [];
return { group, kind }; return { group, kind };
} }
/**
* Get the ID of this category
*/
public getId(): string { public getId(): string {
return `${this.spec.group}/${this.spec.names.kind}`; return `${this.spec.group}/${this.spec.names.kind}`;
} }

View File

@ -4,16 +4,16 @@
*/ */
/** /**
* Get the value behind `key`. If it was not pressent, first insert `value` * Get the value behind `key`. If it was not present, first insert `value`
* @param map The map to interact with * @param map The map to interact with
* @param key The key to insert into the map with * @param key The key to insert into the map with
* @param value The value to optional add to the map * @param value The value to optional add to the map
* @returns The value in the map * @returns The value in the map
*/ */
export function getOrInsert<K, V>(map: Map<K, V>, key: K, value: V): V { export function getOrInsert<K, V>(map: Map<K, V>, key: K, value: V): V {
if (map.has(key)) { if (!map.has(key)) {
return map.get(key); map.set(key, value);
} }
return map.set(key, value).get(key); return map.get(key);
} }

View File

@ -31,6 +31,11 @@ export * from "../../renderer/components/input/input";
// command-overlay // command-overlay
export const CommandOverlay = asLegacyGlobalObjectForExtensionApi(commandOverlayInjectable); export const CommandOverlay = asLegacyGlobalObjectForExtensionApi(commandOverlayInjectable);
export type {
CategoryColumnRegistration,
AdditionalCategoryColumnRegistration,
} from "../../renderer/components/+catalog/custom-category-columns";
// other components // other components
export * from "../../renderer/components/icon"; export * from "../../renderer/components/icon";
export * from "../../renderer/components/tooltip"; export * from "../../renderer/components/tooltip";

View File

@ -14,9 +14,12 @@ import type { AdditionalCategoryColumnRegistration, CategoryColumnRegistration }
import getCategoryColumnsInjectable, { CategoryColumns, GetCategoryColumnsParams } from "../get-category-columns.injectable"; import getCategoryColumnsInjectable, { CategoryColumns, GetCategoryColumnsParams } from "../get-category-columns.injectable";
class TestCategory extends CatalogCategory { class TestCategory extends CatalogCategory {
apiVersion: string; apiVersion = "catalog.k8slens.dev/v1alpha1";
kind: string; kind = "CatalogCategory";
metadata: { name: string; icon: string; }; metadata: {
name: "Test";
icon: "question_mark";
};
spec: CatalogCategorySpec = { spec: CatalogCategorySpec = {
group: "foo.bar.bat", group: "foo.bar.bat",
names: { names: {

View File

@ -8,7 +8,7 @@
import "./markdown-viewer.scss"; import "./markdown-viewer.scss";
import React, { Component } from "react"; import React, { Component } from "react";
import { marked } from "marked"; import marked from "marked";
import DOMPurify from "dompurify"; import DOMPurify from "dompurify";
import { cssNames } from "../../utils"; import { cssNames } from "../../utils";