diff --git a/.github/workflows/check-docs.yml b/.github/workflows/check-docs.yml index f94a2fda5c..eeb4e3c685 100644 --- a/.github/workflows/check-docs.yml +++ b/.github/workflows/check-docs.yml @@ -1,12 +1,12 @@ name: Check Documentation on: pull_request: - types: [opened, labeled, unlabeled, synchronize] + branches: + - "**" jobs: build: name: Check Docs runs-on: ubuntu-latest - if: ${{ contains(github.event.pull_request.labels.*.name, 'area/documentation') }} strategy: matrix: node-version: [14.x] diff --git a/package.json b/package.json index e5decdef44..6ec461aa4f 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "lint:fix": "yarn run lint --fix", "mkdocs-serve-local": "docker build -t mkdocs-serve-local:latest mkdocs/ && docker run --rm -it -p 8000:8000 -v ${PWD}:/docs mkdocs-serve-local:latest", "verify-docs": "docker build -t mkdocs-serve-local:latest mkdocs/ && docker run --rm -v ${PWD}:/docs mkdocs-serve-local:latest build --strict", + "preverify-docs": "yarn run typedocs-extensions-api", "typedocs-extensions-api": "yarn run typedoc src/extensions/extension-api.ts", "version-checkout": "cat package.json | jq '.version' -r | xargs printf \"release/v%s\" | xargs git checkout -b", "version-commit": "cat package.json | jq '.version' -r | xargs printf \"release v%s\" | git commit --no-edit -s -F -", diff --git a/src/common/catalog-entities/general.ts b/src/common/catalog-entities/general.ts index 9387528527..39d547fd86 100644 --- a/src/common/catalog-entities/general.ts +++ b/src/common/catalog-entities/general.ts @@ -7,7 +7,7 @@ import { navigate } from "../../renderer/navigation"; import { CatalogCategory, CatalogEntity, CatalogEntityMetadata, CatalogEntitySpec, CatalogEntityStatus } from "../catalog"; import { catalogCategoryRegistry } from "../catalog/catalog-category-registry"; -interface GeneralEntitySpec extends CatalogEntitySpec { +export interface GeneralEntitySpec extends CatalogEntitySpec { path: string; icon?: { material?: string; diff --git a/src/common/catalog-entities/kubernetes-cluster.ts b/src/common/catalog-entities/kubernetes-cluster.ts index a4012491bd..17c2e85f46 100644 --- a/src/common/catalog-entities/kubernetes-cluster.ts +++ b/src/common/catalog-entities/kubernetes-cluster.ts @@ -130,10 +130,14 @@ export class KubernetesCluster< catalogCategoryRegistry .getCategoryForEntity(this) - ?.emit("contextMenuOpen", this, context); + .emit("contextMenuOpen", this, context); } } +/** + * The category for {@link KubernetesCluster}'s. Not constructable, use + * {@link kubernetesClusterCategory} to register event handlers. + */ class KubernetesClusterCategory extends CatalogCategory { public readonly apiVersion = "catalog.k8slens.dev/v1alpha1"; public readonly kind = "CatalogCategory"; @@ -155,6 +159,7 @@ class KubernetesClusterCategory extends CatalogCategory { }; } +export type { KubernetesClusterCategory }; export const kubernetesClusterCategory = new KubernetesClusterCategory(); catalogCategoryRegistry.add(kubernetesClusterCategory); diff --git a/src/common/catalog/catalog-category-registry.ts b/src/common/catalog/catalog-category-registry.ts index 41bcf9c015..bf1e555cbd 100644 --- a/src/common/catalog/catalog-category-registry.ts +++ b/src/common/catalog/catalog-category-registry.ts @@ -4,16 +4,29 @@ */ import { action, computed, observable, makeObservable } from "mobx"; +import { type Disposer, strictSet, iter, getOrInsertMap } from "../utils"; +import { CatalogCategory, CatalogEntity, CatalogEntityData, CatalogEntityKindData } from "./catalog-entity"; import { once } from "lodash"; -import { iter, getOrInsertMap, strictSet } from "../utils"; -import type { Disposer } from "../utils"; -import { CatalogCategory, CatalogEntityData, CatalogEntityKindData } from "./catalog-entity"; export type CategoryFilter = (category: CatalogCategory) => any; +/** + * The registry of declared categories in the renderer + */ export class CatalogCategoryRegistry { + /** + * @internal + */ protected categories = observable.set(); + + /** + * @internal + */ protected groupKinds = new Map>(); + + /** + * @internal + */ protected filters = observable.set([], { deep: false, }); @@ -22,6 +35,12 @@ export class CatalogCategoryRegistry { makeObservable(this); } + /** + * Attempt to add a new category to the registry. + * @param category The category instance to add + * @returns A function to deregister the instance + * @throws If there already exists a previous category that declared as specific group and kind + */ @action add(category: CatalogCategory): Disposer { const byGroup = getOrInsertMap(this.groupKinds, category.spec.group); @@ -34,10 +53,16 @@ export class CatalogCategoryRegistry { }; } + /** + * Get a list of all the categories that are currently registered + */ @computed get items() { return Array.from(this.categories); } + /** + * Get a list of all the categories that match all the registered filters + */ @computed get filteredItems() { return Array.from( iter.reduce( @@ -48,12 +73,22 @@ export class CatalogCategoryRegistry { ); } - + /** + * Attempt to get a category but the api group and kind it declared + * @param group The group string of the desired category + * @param kind The name that a category declares + */ getForGroupKind(group: string, kind: string): T | undefined { return this.groupKinds.get(group)?.get(kind) as T; } - getEntityForData(data: CatalogEntityData & CatalogEntityKindData) { + /** + * Create a new entity instance from `data` or return `null` if cannot find category + * @param data The data to create the instance from + * @param data.apiVersion Used to find the category by group and version + * @param data.kind Used to find the category for a specific kind + */ + getEntityForData(data: CatalogEntityData & CatalogEntityKindData): CatalogEntity | null { const category = this.getCategoryForEntity(data); if (!category) { @@ -72,14 +107,24 @@ export class CatalogCategoryRegistry { return new specVersion.entityClass(data); } - getCategoryForEntity(data: CatalogEntityData & CatalogEntityKindData): T | undefined { + /** + * Try and find a category by its version declarations + * @param data The `apiVersion` and `kind` that was declared by a category + * @returns The category instance if found + */ + getCategoryForEntity(data: CatalogEntityKindData): T | undefined { const splitApiVersion = data.apiVersion.split("/"); const group = splitApiVersion[0]; return this.getForGroupKind(group, data.kind); } - getByName(name: string) { + /** + * Try and find a category by the name is was registered with + * @param name The name of the category + * @returns The category instance if found + */ + getByName(name: string): CatalogCategory | undefined { return this.items.find(category => category.metadata?.name == name); } diff --git a/src/common/catalog/catalog-entity.ts b/src/common/catalog/catalog-entity.ts index daff2e6017..eebbef43eb 100644 --- a/src/common/catalog/catalog-entity.ts +++ b/src/common/catalog/catalog-entity.ts @@ -10,9 +10,9 @@ import { once } from "lodash"; import { iter, Disposer } from "../utils"; import type { CategoryColumnRegistration } from "../../renderer/components/+catalog/custom-category-columns"; -type ExtractEntityMetadataType = Entity extends CatalogEntity ? Metadata : never; -type ExtractEntityStatusType = Entity extends CatalogEntity ? Status : never; -type ExtractEntitySpecType = Entity extends CatalogEntity ? Spec : never; +export type ExtractEntityMetadataType = Entity extends CatalogEntity ? Metadata : never; +export type ExtractEntityStatusType = Entity extends CatalogEntity ? Status : never; +export type ExtractEntitySpecType = Entity extends CatalogEntity ? Spec : never; export type CatalogEntityConstructor = ( (new (data: CatalogEntityData< @@ -88,26 +88,35 @@ export interface CatalogCategorySpec { */ export type AddMenuFilter = (menu: CatalogEntityAddMenu) => any; +/** + * The events that can be emitted onto a catalog category + */ export interface CatalogCategoryEvents { /** - * This event will be emitted when the category is loaded in the catalog + * An event which is emitted when the category becomes active on the catalog * view. */ load: () => void; /** - * This event will be emitted when the catalog add menu is opened and is the - * way to added entries to that menu. + * An event which is emitted when the menu for adding new catalog entities + * is opened. + * @param context The event context */ catalogAddMenu: (context: CatalogEntityAddMenuContext) => void; /** - * This event will be emitted when the context menu for an entity is declared - * by this category is opened. + * An event which is emitted when the context menu on a entity versioned by + * this category is opened. + * @param entity The entity that was opened + * @param context The event context */ contextMenuOpen: (entity: CatalogEntity, context: CatalogEntityContextMenuContext) => void; } +/** + * A declartion of supported versions a specific kind of CatalogEntity + */ export abstract class CatalogCategory extends (EventEmitter as new () => TypedEmitter) { /** * The version of category that you are wanting to declare. @@ -210,6 +219,9 @@ export interface CatalogEntityMetadata { [key: string]: string | object; } +/** + * The minimal information that all entities must use to describe their current status + */ export interface CatalogEntityStatus { phase: string; reason?: string; @@ -222,59 +234,104 @@ export interface CatalogEntityStatus { active?: boolean; } +/** + * The event context for when an entity is activated + */ export interface CatalogEntityActionContext { - navigate: (url: string) => void; - setCommandPaletteContext: (context?: CatalogEntity) => void; + /** + * A function to navigate around the application + * @param pathname The path to navigate to + */ + navigate: (pathname: string) => void; + + /** + * A function to change the active entity for the command palette + */ + setCommandPaletteContext: (entity?: CatalogEntity) => void; } +/** + * The descriptor for entities' context menus and detail panels' topbars + */ export interface CatalogEntityContextMenu { /** - * Menu title + * When in a context menu, the text displayed */ title: string; + /** - * Menu icon + * When in a toolbar the icon's material or svg data + * + * If not present then this item will not be displayed in the toolbar */ icon?: string; + /** - * OnClick handler + * The function that will be called when the menu item is clicked */ onClick: () => void | Promise; + /** - * Confirm click with a message + * If present then a confirmation dialog will be displayed to the user with + * the given message before the `onClick` handler is called. */ confirm?: { message: string; }; } +/** + * The context type for the add menu event in the catalog view + */ export interface CatalogEntityAddMenu extends CatalogEntityContextMenu { + /** + * The icon's material or svg data for the menu item. + */ icon: string; + + /** + * If this menu item should be the default action. If multiple items are + * declared as the default one then none are executed. + */ defaultAction?: boolean; } -export interface CatalogEntitySettingsMenu { - group?: string; - title: string; - components: { - View: React.ComponentType; - }; -} - +/** + * The context type for entity context menus and drawer detail topbar menus + */ export interface CatalogEntityContextMenuContext { /** - * Navigate to the specified pathname + * A function to navigate around the application + * @param pathname The path to navigate to */ navigate: (pathname: string) => void; + + /** + * The output array of items + */ menuItems: CatalogEntityContextMenu[]; } +/** + * @deprecated Not used + */ export interface CatalogEntitySettingsContext { + /** + * The output array of items + */ menuItems: CatalogEntityContextMenu[]; } export interface CatalogEntityAddMenuContext { + /** + * A function to navigate around the application + * @param pathname The path to navigate to + */ navigate: (url: string) => void; + + /** + * The output array of items + */ menuItems: CatalogEntityAddMenu[]; } @@ -336,14 +393,14 @@ export abstract class CatalogEntity< } /** - * Get the UID of this entity + * A convenience function for getting the entity ID */ public getId(): string { return this.metadata.uid; } /** - * Get the name of this entity + * A convenience function for getting the entity name */ public getName(): string { return this.metadata.name; @@ -364,7 +421,18 @@ export abstract class CatalogEntity< return this.status.enabled ?? true; } + /** + * The function that will be called when the entity is activated + */ public abstract onRun?(context: CatalogEntityActionContext): void | Promise; - public abstract onContextMenuOpen(context: CatalogEntityContextMenuContext): void | Promise; - public abstract onSettingsOpen(context: CatalogEntitySettingsContext): void | Promise; + + /** + * The function that is called when the context menu is opened for a specific entity + */ + public abstract onContextMenuOpen?(context: CatalogEntityContextMenuContext): void | Promise; + + /** + * @deprecated This is not used. Use the `RenderExtension.entitySettings` field instead + */ + public abstract onSettingsOpen?(context: CatalogEntitySettingsContext): void | Promise; } diff --git a/src/common/event-emitter.ts b/src/common/event-emitter.ts index 4d7f5ca53c..265b2b8209 100644 --- a/src/common/event-emitter.ts +++ b/src/common/event-emitter.ts @@ -3,32 +3,75 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -// Custom event emitter +/** + * The options for when adding a new listener + */ +export interface AddListenerOptions { + /** + * Should the listener only ever receive one event. + * + * @default false + */ + once?: boolean; -interface Options { - once?: boolean; // call once and remove - prepend?: boolean; // put listener to the beginning + /** + * If `true` then the listener will be put to the front of the event queue + * + * @default false + */ + prepend?: boolean; } -type Callback = (...data: D) => void | boolean; +/** + * A function for handling events. If the function returns `false` then no + * further listeners will be called for that event. + */ +export type EventListener = (...data: D) => void | boolean; -export class EventEmitter { - protected listeners: [Callback, Options][] = []; +/** + * An event emitter for a single event. Generic over the arguments for the + * event handler. + */ +export class EventEmitter { + protected listeners = new Map, Required>>(); - addListener(callback: Callback, options: Options = {}) { - const fn = options.prepend ? "unshift" : "push"; + /** + * Add a new listener for this event emitter + * @param callback The function to call when an event is emitted. + * @param options Options for controlling how the listener is handled. + */ + addListener(callback: EventListener, options?: AddListenerOptions) { + const { prepend, once = false } = options ?? {}; - this.listeners[fn]([callback, options]); + if (prepend) { + this.listeners = new Map([ + [callback, { once }], + ...this.listeners.entries(), + ]); + } else { + this.listeners.set(callback, { once }); + } } - removeListener(callback: Callback) { - this.listeners = this.listeners.filter(([cb]) => cb !== callback); + /** + * Removes `callback` from being called for future events. + * @param callback The listener instance to remove + */ + removeListener(callback: EventListener) { + this.listeners.delete(callback); } + /** + * Removes all current listeners. + */ removeAllListeners() { - this.listeners.length = 0; + this.listeners.clear(); } + /** + * Emits a new event. + * @param data The event data + */ emit = (...data: D) => { for (const [callback, { once }] of this.listeners) { if (once) { diff --git a/src/common/item.store.ts b/src/common/item.store.ts index 68ef6813b9..6a7c077244 100644 --- a/src/common/item.store.ts +++ b/src/common/item.store.ts @@ -7,6 +7,9 @@ import orderBy from "lodash/orderBy"; import { autoBind } from "./utils"; import { action, computed, observable, when, makeObservable } from "mobx"; +/** + * An object whose ID and name can be gotten via methods. + */ export interface ItemObject { getId(): string; getName(): string; diff --git a/src/common/k8s-api/__tests__/crd.test.ts b/src/common/k8s-api/__tests__/crd.test.ts index 50f9760cb1..52d4df7a3c 100644 --- a/src/common/k8s-api/__tests__/crd.test.ts +++ b/src/common/k8s-api/__tests__/crd.test.ts @@ -29,7 +29,7 @@ describe("Crds", () => { storage: false, }, ], - }, + } as CustomResourceDefinitionSpec, }); expect(() => crd.getVersion()).toThrowError("Failed to find a version for CustomResourceDefinition foo"); @@ -57,7 +57,7 @@ describe("Crds", () => { storage: false, }, ], - }, + } as CustomResourceDefinitionSpec, }); expect(crd.getVersion()).toBe("123"); @@ -85,7 +85,7 @@ describe("Crds", () => { storage: false, }, ], - }, + } as CustomResourceDefinitionSpec, }); expect(crd.getVersion()).toBe("123"); @@ -114,7 +114,7 @@ describe("Crds", () => { storage: false, }, ], - }, + } as CustomResourceDefinitionSpec, }); expect(crd.getVersion()).toBe("123"); diff --git a/src/common/k8s-api/api-manager.ts b/src/common/k8s-api/api-manager.ts index d392673364..fc6d72cd09 100644 --- a/src/common/k8s-api/api-manager.ts +++ b/src/common/k8s-api/api-manager.ts @@ -11,82 +11,137 @@ import type { KubeApi } from "./kube-api"; import type { KubeObject } from "./kube-object"; import { IKubeObjectRef, parseKubeApi, createKubeApiURL } from "./kube-api-parse"; +/** + * The manager of registered kube apis and KubeObject stores + */ export class ApiManager { private apis = observable.map>(); - private stores = observable.map>(); + private stores = observable.map, KubeObjectStore>(); + /** + * @internal + */ constructor() { makeObservable(this); autoBind(this); } - getApi(pathOrCallback: string | ((api: KubeApi) => boolean)) { + /** + * Get the KubeApi instance which either has registered under the given + * path or by the apiBase of the given path or the first api which the + * callback returns `true` for. + * @param pathOrCallback Either the api path or a matching function + */ + getApi(pathOrCallback: string | ((api: KubeApi) => boolean)): KubeApi | undefined { if (typeof pathOrCallback === "string") { return this.apis.get(pathOrCallback) || this.apis.get(parseKubeApi(pathOrCallback).apiBase); } - return iter.find(this.apis.values(), pathOrCallback ?? (() => true)); + return iter.find(this.apis.values(), pathOrCallback); } - getApiByKind(kind: string, apiVersion: string) { - return iter.find(this.apis.values(), api => api.kind === kind && api.apiVersionWithGroup === apiVersion); + /** + * Get the `KubeApi` instance which is for the kube resource `kind` under the + * apiVersion and group `apiVersion` + * + * Example: + * ```ts + * this.getApiByKind("Pod", "api/v1"); + * ``` + * @param kind The kube resource kind + * @param apiVersion The kube apiVersion and group + */ + getApiByKind(kind: string, apiVersion: string): KubeApi | undefined { + return this.getApi(api => api.kind === kind && api.apiVersionWithGroup === apiVersion); } - registerApi(apiBase: string, api: KubeApi) { - if (!api.apiBase) return; - - if (!this.apis.has(apiBase)) { - this.stores.forEach((store) => { - if (store.api === api) { - this.stores.set(apiBase, store); - } - }); - - this.apis.set(apiBase, api); + /** + * Attempt to register `api` under `apiBase`. If `apiBase` already has been + * registered then this function does nothing. + * @param apiBase The kube resource api base to register the api against + * @param api The `KubeApi` instance to register + */ + registerApi(apiBase: string, api: KubeApi): void { + if (!api.apiBase || this.apis.has(apiBase)) { + return; } + + this.apis.set(apiBase, api); } - protected resolveApi(api?: string | KubeApi): KubeApi | undefined { - if (!api) { + /** + * Unifies apiBases and instances into instances + * @param apiOrBase Either the `apiBase` string or the `KubeApi` instance + */ + protected resolveApi(apiOrBase: string | KubeApi): KubeApi | undefined { + if (!apiOrBase) { return undefined; } - if (typeof api === "string") { - return this.getApi(api) as KubeApi; + if (typeof apiOrBase === "string") { + return this.getApi(apiOrBase) as KubeApi; } - return api; + return apiOrBase; } - unregisterApi(api: string | KubeApi) { - if (typeof api === "string") this.apis.delete(api); - else { - const apis = Array.from(this.apis.entries()); - const entry = apis.find(entry => entry[1] === api); - - if (entry) this.unregisterApi(entry[0]); + /** + * Removes + * @param apiOrBase Either an apiBase string or the instance to deregister + */ + unregisterApi(apiOrBase: string | KubeApi) { + if (typeof apiOrBase === "string") { + this.apis.delete(apiOrBase); + } else { + for (const [apiBase, api] of this.apis) { + if (api === apiOrBase) { + this.apis.delete(apiBase); + } + } } } + /** + * Register a store under its api's apiBase + * @param store The store instance to register + */ + registerStore(store: KubeObjectStore): void; + /** + * @deprecated Use {@link ApiManager.registerStore} instead as a store should + * only be registered under its own api + */ + registerStore(store: KubeObjectStore, apis: KubeApi[]): void; @action - registerStore(store: KubeObjectStore, apis: KubeApi[] = [store.api]) { - apis.filter(Boolean).forEach(api => { - if (api.apiBase) this.stores.set(api.apiBase, store); - }); + registerStore(store: KubeObjectStore, apis?: KubeApi[]): void { + if (apis) { + for (const api of apis) { + this.stores.set(api, store); + } + } else { + this.stores.set(store.api, store); + } } - getStore>(api: string | KubeApi): S | undefined { - return this.stores.get(this.resolveApi(api)?.apiBase) as S; + /** + * Get the registered store under the provided key + * @param apiOrBase Either the apiBase or a KubeApi instance + */ + getStore>(apiOrBase: string | KubeApi): S | undefined { + return this.stores.get(this.resolveApi(apiOrBase)) as S; } + /** + * Attempt to get the api string for a given kube resource + * @param ref An object describing the kube resource + * @param parentObject Used to get the namespace or the resource if `ref` does not provided it + * @returns The kube API resource string + */ lookupApiLink(ref: IKubeObjectRef, parentObject?: KubeObject): string { const { kind, apiVersion, name, namespace = parentObject?.getNs(), } = ref; - if (!kind) return ""; - // search in registered apis by 'kind' & 'apiVersion' const api = this.getApi(api => api.kind === kind && api.apiVersionWithGroup == apiVersion); @@ -119,4 +174,7 @@ export class ApiManager { } } +/** + * The single instance per frame. + */ export const apiManager = new ApiManager(); diff --git a/src/common/k8s-api/endpoints/cluster-role-binding.api.ts b/src/common/k8s-api/endpoints/cluster-role-binding.api.ts index b6e6a517ae..2046dc6f7f 100644 --- a/src/common/k8s-api/endpoints/cluster-role-binding.api.ts +++ b/src/common/k8s-api/endpoints/cluster-role-binding.api.ts @@ -3,7 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { isClusterPageContext } from "../../utils/cluster-id-url-parsing"; -import { KubeApi } from "../kube-api"; +import { BaseKubeApiOptions, KubeApi } from "../kube-api"; import { KubeObject } from "../kube-object"; export type ClusterRoleBindingSubjectKind = "Group" | "ServiceAccount" | "User"; @@ -39,16 +39,20 @@ export class ClusterRoleBinding extends KubeObject { } /** - * Only available within kubernetes cluster pages + * The api type for {@link ClusterRoleBinding}'s */ -let clusterRoleBindingApi: KubeApi; - -if (isClusterPageContext()) { - clusterRoleBindingApi = new KubeApi({ - objectConstructor: ClusterRoleBinding, - }); +export class ClusterRoleBindingApi extends KubeApi { + constructor(params?: BaseKubeApiOptions) { + super({ + ...(params ?? {}), + objectConstructor: ClusterRoleBinding, + }); + } } -export { - clusterRoleBindingApi, -}; +/** + * Only available within kubernetes cluster pages + */ +export const clusterRoleBindingApi = isClusterPageContext() + ? new ClusterRoleBindingApi() + : undefined; diff --git a/src/common/k8s-api/endpoints/cluster-role.api.ts b/src/common/k8s-api/endpoints/cluster-role.api.ts index 70a5ef05e8..86a6a9b081 100644 --- a/src/common/k8s-api/endpoints/cluster-role.api.ts +++ b/src/common/k8s-api/endpoints/cluster-role.api.ts @@ -4,7 +4,7 @@ */ import { isClusterPageContext } from "../../utils/cluster-id-url-parsing"; -import { KubeApi } from "../kube-api"; +import { BaseKubeApiOptions, KubeApi } from "../kube-api"; import { KubeObject } from "../kube-object"; export interface ClusterRole { @@ -27,16 +27,20 @@ export class ClusterRole extends KubeObject { } /** - * Only available within kubernetes cluster pages + * The api type for {@link ClusterRole}'s */ -let clusterRoleApi: KubeApi; - -if (isClusterPageContext()) { // initialize automatically only when within a cluster iframe/context - clusterRoleApi = new KubeApi({ - objectConstructor: ClusterRole, - }); +export class ClusterRoleApi extends KubeApi { + constructor(params?: BaseKubeApiOptions) { + super({ + ...(params ?? {}), + objectConstructor: ClusterRole, + }); + } } -export { - clusterRoleApi, -}; +/** + * Only available within kubernetes cluster pages + */ +export const clusterRoleApi = isClusterPageContext() + ? new ClusterRoleApi() + : undefined; diff --git a/src/common/k8s-api/endpoints/cluster.api.ts b/src/common/k8s-api/endpoints/cluster.api.ts index 1d32806382..5d46ddd748 100644 --- a/src/common/k8s-api/endpoints/cluster.api.ts +++ b/src/common/k8s-api/endpoints/cluster.api.ts @@ -110,14 +110,8 @@ export class Cluster extends KubeObject { /** * Only available within kubernetes cluster pages */ -let clusterApi: ClusterApi; - -if (isClusterPageContext()) { // initialize automatically only when within a cluster iframe/context - clusterApi = new ClusterApi({ +export const clusterApi = isClusterPageContext() + ? new ClusterApi({ objectConstructor: Cluster, - }); -} - -export { - clusterApi, -}; + }) + : undefined; diff --git a/src/common/k8s-api/endpoints/configmap.api.ts b/src/common/k8s-api/endpoints/configmap.api.ts index 82bbc47bf7..8238f0e512 100644 --- a/src/common/k8s-api/endpoints/configmap.api.ts +++ b/src/common/k8s-api/endpoints/configmap.api.ts @@ -5,7 +5,7 @@ import { KubeObject } from "../kube-object"; import type { KubeJsonApiData } from "../kube-json-api"; -import { KubeApi } from "../kube-api"; +import { BaseKubeApiOptions, KubeApi } from "../kube-api"; import { autoBind } from "../../utils"; import { isClusterPageContext } from "../../utils/cluster-id-url-parsing"; @@ -32,17 +32,18 @@ export class ConfigMap extends KubeObject { } } +export class ConfigMapApi extends KubeApi { + constructor(params?: BaseKubeApiOptions) { + super({ + ...(params ?? {}), + objectConstructor: ConfigMap, + }); + } +} + /** * Only available within kubernetes cluster pages */ -let configMapApi: KubeApi; - -if (isClusterPageContext()) { - configMapApi = new KubeApi({ - objectConstructor: ConfigMap, - }); -} - -export { - configMapApi, -}; +export const configMapApi = isClusterPageContext() + ? new ConfigMapApi() + : undefined; diff --git a/src/common/k8s-api/endpoints/crd.api.ts b/src/common/k8s-api/endpoints/crd.api.ts index 98f78a0716..6307f9ce9a 100644 --- a/src/common/k8s-api/endpoints/crd.api.ts +++ b/src/common/k8s-api/endpoints/crd.api.ts @@ -3,13 +3,12 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { KubeCreationError, KubeObject } from "../kube-object"; -import { KubeApi } from "../kube-api"; +import { KubeObject, KubeObjectMetadata } from "../kube-object"; +import { BaseKubeApiOptions, KubeApi } from "../kube-api"; import { crdResourcesURL } from "../../routes"; import { isClusterPageContext } from "../../utils/cluster-id-url-parsing"; -import type { KubeJsonApiData } from "../kube-json-api"; -interface AdditionalPrinterColumnsCommon { +export interface AdditionalPrinterColumnsCommon { name: string; type: "integer" | "number" | "string" | "boolean" | "date"; priority: number; @@ -20,7 +19,7 @@ export type AdditionalPrinterColumnsV1 = AdditionalPrinterColumnsCommon & { jsonPath: string; }; -type AdditionalPrinterColumnsV1Beta = AdditionalPrinterColumnsCommon & { +export type AdditionalPrinterColumnsV1Beta = AdditionalPrinterColumnsCommon & { JSONPath: string; }; @@ -79,25 +78,35 @@ export interface CustomResourceDefinition { }; storedVersions: string[]; }; + /** + * @deprecated for apiextensions.k8s.io/v1 but used previously + */ + additionalPrinterColumns?: AdditionalPrinterColumnsV1Beta[]; } -export interface CRDApiData extends KubeJsonApiData { - spec: object; // TODO: make better +export interface CustomResourceDefinitionStatus { + conditions: { + lastTransitionTime: string; + message: string; + reason: string; + status: string; + type?: string; + }[]; + acceptedNames: { + plural: string; + singular: string; + kind: string; + shortNames: string[]; + listKind: string; + }; + storedVersions: string[]; } -export class CustomResourceDefinition extends KubeObject { +export class CustomResourceDefinition extends KubeObject { static kind = "CustomResourceDefinition"; static namespaced = false; static apiBase = "/apis/apiextensions.k8s.io/v1/customresourcedefinitions"; - constructor(data: CRDApiData) { - super(data); - - if (!data.spec || typeof data.spec !== "object") { - throw new KubeCreationError("Cannot create a CustomResourceDefinition from an object without spec", data); - } - } - getResourceUrl() { return crdResourcesURL({ params: { @@ -211,17 +220,21 @@ export class CustomResourceDefinition extends KubeObject { } /** - * Only available within kubernetes cluster pages + * The api type for {@link CustomResourceDefinition}'s */ -let crdApi: KubeApi; - -if (isClusterPageContext()) { - crdApi = new KubeApi({ - objectConstructor: CustomResourceDefinition, - checkPreferredVersion: true, - }); +export class CustomResourceDefinitionApi extends KubeApi { + constructor(params?: Pick) { + super({ + ...(params ?? {}), + objectConstructor: CustomResourceDefinition, + checkPreferredVersion: true, + }); + } } -export { - crdApi, -}; +/** + * Only available within kubernetes cluster pages + */ +export const crdApi = isClusterPageContext() + ? new CustomResourceDefinitionApi() + : undefined; diff --git a/src/common/k8s-api/endpoints/cron-job.api.ts b/src/common/k8s-api/endpoints/cron-job.api.ts index cf50780b0f..6a3d9fd506 100644 --- a/src/common/k8s-api/endpoints/cron-job.api.ts +++ b/src/common/k8s-api/endpoints/cron-job.api.ts @@ -128,14 +128,8 @@ export class CronJob extends KubeObject { /** * Only available within kubernetes cluster pages */ -let cronJobApi: CronJobApi; - -if (isClusterPageContext()) { - cronJobApi = new CronJobApi({ +export const cronJobApi = isClusterPageContext() + ? new CronJobApi({ objectConstructor: CronJob, - }); -} - -export { - cronJobApi, -}; + }) + : undefined; diff --git a/src/common/k8s-api/endpoints/daemon-set.api.ts b/src/common/k8s-api/endpoints/daemon-set.api.ts index 74198de4e5..7acc36dae2 100644 --- a/src/common/k8s-api/endpoints/daemon-set.api.ts +++ b/src/common/k8s-api/endpoints/daemon-set.api.ts @@ -103,14 +103,8 @@ export function getMetricsForDaemonSets(daemonsets: DaemonSet[], namespace: stri /** * Only available within kubernetes cluster pages */ -let daemonSetApi: DaemonSetApi; - -if (isClusterPageContext()) { - daemonSetApi = new DaemonSetApi({ +export const daemonSetApi = isClusterPageContext() + ? new DaemonSetApi({ objectConstructor: DaemonSet, - }); -} - -export { - daemonSetApi, -}; + }) + : undefined; diff --git a/src/common/k8s-api/endpoints/deployment.api.ts b/src/common/k8s-api/endpoints/deployment.api.ts index 505b32dd96..940bc1a866 100644 --- a/src/common/k8s-api/endpoints/deployment.api.ts +++ b/src/common/k8s-api/endpoints/deployment.api.ts @@ -77,7 +77,7 @@ export function getMetricsForDeployments(deployments: Deployment[], namespace: s }); } -interface IContainerProbe { +export interface IContainerProbe { httpGet?: { path?: string; port: number; @@ -224,14 +224,11 @@ export class Deployment extends WorkloadKubeObject { } } -let deploymentApi: DeploymentApi; - -if (isClusterPageContext()) { - deploymentApi = new DeploymentApi({ +/** + * Only available within kubernetes cluster pages + */ +export const deploymentApi = isClusterPageContext() + ? new DeploymentApi({ objectConstructor: Deployment, - }); -} - -export { - deploymentApi, -}; + }) + : undefined; diff --git a/src/common/k8s-api/endpoints/endpoint.api.ts b/src/common/k8s-api/endpoints/endpoint.api.ts index 9e025eb158..cc80777cf3 100644 --- a/src/common/k8s-api/endpoints/endpoint.api.ts +++ b/src/common/k8s-api/endpoints/endpoint.api.ts @@ -5,7 +5,7 @@ import { autoBind } from "../../utils"; import { KubeObject } from "../kube-object"; -import { KubeApi } from "../kube-api"; +import { BaseKubeApiOptions, KubeApi } from "../kube-api"; import type { KubeJsonApiData } from "../kube-json-api"; import { get } from "lodash"; import { isClusterPageContext } from "../../utils/cluster-id-url-parsing"; @@ -28,7 +28,7 @@ export interface IEndpointSubset { ports: IEndpointPort[]; } -interface ITargetRef { +export interface ITargetRef { kind: string; namespace: string; name: string; @@ -131,17 +131,23 @@ export class Endpoint extends KubeObject { return ""; } } - } -let endpointApi: KubeApi; - -if (isClusterPageContext()) { - endpointApi = new KubeApi({ - objectConstructor: Endpoint, - }); +/** + * The api type for {@link Endpoint}'s + */ +export class EndpointApi extends KubeApi { + constructor(params?: BaseKubeApiOptions) { + super({ + ...(params ?? {}), + objectConstructor: Endpoint, + }); + } } -export { - endpointApi, -}; +/** + * Only available within kubernetes cluster pages + */ +export const endpointApi = isClusterPageContext() + ? new EndpointApi() + : undefined; diff --git a/src/common/k8s-api/endpoints/events.api.ts b/src/common/k8s-api/endpoints/events.api.ts index f4218ba8c0..6d42d08cbc 100644 --- a/src/common/k8s-api/endpoints/events.api.ts +++ b/src/common/k8s-api/endpoints/events.api.ts @@ -6,7 +6,7 @@ import moment from "moment"; import { KubeObject } from "../kube-object"; import { formatDuration } from "../../utils/formatDuration"; -import { KubeApi } from "../kube-api"; +import { BaseKubeApiOptions, KubeApi } from "../kube-api"; import { isClusterPageContext } from "../../utils/cluster-id-url-parsing"; export interface KubeEvent { @@ -62,14 +62,22 @@ export class KubeEvent extends KubeObject { } } -let eventApi: KubeApi; +/** + * The api type for {@link KubeEvent}'s + */ -if (isClusterPageContext()) { - eventApi = new KubeApi({ - objectConstructor: KubeEvent, - }); +export class KubeEventApi extends KubeApi { + constructor(params?: BaseKubeApiOptions) { + super({ + ...(params ?? {}), + objectConstructor: KubeEvent, + }); + } } -export { - eventApi, -}; +/** + * Only available within kubernetes cluster pages + */ +export const eventApi = isClusterPageContext() + ? new KubeEventApi() + : undefined; diff --git a/src/common/k8s-api/endpoints/hpa.api.ts b/src/common/k8s-api/endpoints/hpa.api.ts index e284f3a3e8..9d9ce6a6e6 100644 --- a/src/common/k8s-api/endpoints/hpa.api.ts +++ b/src/common/k8s-api/endpoints/hpa.api.ts @@ -4,7 +4,7 @@ */ import { KubeObject } from "../kube-object"; -import { KubeApi } from "../kube-api"; +import { BaseKubeApiOptions, KubeApi } from "../kube-api"; import { isClusterPageContext } from "../../utils/cluster-id-url-parsing"; export enum HpaMetricType { @@ -148,14 +148,21 @@ export class HorizontalPodAutoscaler extends KubeObject { } } -let hpaApi: KubeApi; - -if (isClusterPageContext()) { - hpaApi = new KubeApi({ - objectConstructor: HorizontalPodAutoscaler, - }); +/** + * The api type for {@link HorizontalPodAutoscaler}'s + */ +export class HorizontalPodAutoscalerApi extends KubeApi { + constructor(params?: BaseKubeApiOptions) { + super({ + ...(params ?? {}), + objectConstructor: HorizontalPodAutoscaler, + }); + } } -export { - hpaApi, -}; +/** + * Only available within kubernetes cluster pages + */ +export const hpaApi = isClusterPageContext() + ? new HorizontalPodAutoscalerApi() + : undefined; diff --git a/src/common/k8s-api/endpoints/ingress.api.ts b/src/common/k8s-api/endpoints/ingress.api.ts index b5feaef2c0..623b5f8921 100644 --- a/src/common/k8s-api/endpoints/ingress.api.ts +++ b/src/common/k8s-api/endpoints/ingress.api.ts @@ -40,14 +40,18 @@ export interface ILoadBalancerIngress { ip?: string; } -// extensions/v1beta1 -interface IExtensionsBackend { +/** + * For use when Ingresses are under `extensions/v1beta1` + */ +export interface IExtensionsBackend { serviceName: string; servicePort: number | string; } -// networking.k8s.io/v1 -interface INetworkingBackend { +/** + * For use when Ingresses are under `networking.k8s.io/v1` + */ +export interface INetworkingBackend { service: IIngressService; } @@ -194,17 +198,14 @@ export class Ingress extends KubeObject { } } -let ingressApi: IngressApi; - -if (isClusterPageContext()) { - ingressApi = new IngressApi({ +/** + * Only available within kubernetes cluster pages + */ +export const ingressApi = isClusterPageContext() + ? new IngressApi({ objectConstructor: Ingress, // Add fallback for Kubernetes <1.19 checkPreferredVersion: true, fallbackApiBases: ["/apis/extensions/v1beta1/ingresses"], - }); -} - -export { - ingressApi, -}; + }) + : undefined; diff --git a/src/common/k8s-api/endpoints/job.api.ts b/src/common/k8s-api/endpoints/job.api.ts index 9ceee0ce99..e501a25871 100644 --- a/src/common/k8s-api/endpoints/job.api.ts +++ b/src/common/k8s-api/endpoints/job.api.ts @@ -123,14 +123,11 @@ export function getMetricsForJobs(jobs: Job[], namespace: string, selector = "") }); } -let jobApi: JobApi; - -if (isClusterPageContext()) { - jobApi = new JobApi({ +/** + * Only available within kubernetes cluster pages + */ +export const jobApi = isClusterPageContext() + ? new JobApi({ objectConstructor: Job, - }); -} - -export { - jobApi, -}; + }) + : undefined; diff --git a/src/common/k8s-api/endpoints/limit-range.api.ts b/src/common/k8s-api/endpoints/limit-range.api.ts index 07840e7dfc..8dbbafa187 100644 --- a/src/common/k8s-api/endpoints/limit-range.api.ts +++ b/src/common/k8s-api/endpoints/limit-range.api.ts @@ -4,7 +4,7 @@ */ import { KubeObject } from "../kube-object"; -import { KubeApi } from "../kube-api"; +import { BaseKubeApiOptions, KubeApi } from "../kube-api"; import { autoBind } from "../../utils"; import type { KubeJsonApiData } from "../kube-json-api"; import { isClusterPageContext } from "../../utils/cluster-id-url-parsing"; @@ -65,14 +65,21 @@ export class LimitRange extends KubeObject { } } -let limitRangeApi: KubeApi; - -if (isClusterPageContext()) { - limitRangeApi = new KubeApi({ - objectConstructor: LimitRange, - }); +/** + * The api type for {@link LimitRange}'s + */ +export class LimitRangeApi extends KubeApi { + constructor(params?: BaseKubeApiOptions) { + super({ + ...(params ?? {}), + objectConstructor: LimitRange, + }); + } } -export { - limitRangeApi, -}; +/** + * Only available within kubernetes cluster pages + */ +export const limitRangeApi = isClusterPageContext() + ? new LimitRangeApi() + : undefined; diff --git a/src/common/k8s-api/endpoints/namespaces.api.ts b/src/common/k8s-api/endpoints/namespaces.api.ts index 07b51f701d..ae8eb73fbf 100644 --- a/src/common/k8s-api/endpoints/namespaces.api.ts +++ b/src/common/k8s-api/endpoints/namespaces.api.ts @@ -56,14 +56,11 @@ export function getMetricsForNamespace(namespace: string, selector = ""): Promis }); } -let namespacesApi: NamespaceApi; - -if (isClusterPageContext()) { - namespacesApi = new NamespaceApi({ +/** + * Only available within kubernetes cluster pages + */ +export const namespacesApi = isClusterPageContext() + ? new NamespaceApi({ objectConstructor: Namespace, - }); -} - -export { - namespacesApi, -}; + }) + : undefined; diff --git a/src/common/k8s-api/endpoints/network-policy.api.ts b/src/common/k8s-api/endpoints/network-policy.api.ts index f51c11d70f..19ab0a89d5 100644 --- a/src/common/k8s-api/endpoints/network-policy.api.ts +++ b/src/common/k8s-api/endpoints/network-policy.api.ts @@ -5,7 +5,7 @@ import { KubeObject, LabelSelector } from "../kube-object"; import { autoBind } from "../../utils"; -import { KubeApi } from "../kube-api"; +import { BaseKubeApiOptions, KubeApi } from "../kube-api"; import type { KubeJsonApiData } from "../kube-json-api"; import { isClusterPageContext } from "../../utils/cluster-id-url-parsing"; @@ -129,14 +129,22 @@ export class NetworkPolicy extends KubeObject { } } -let networkPolicyApi: KubeApi; +/** + * The api type for {@link NetworkPolicy}'s + */ -if (isClusterPageContext()) { - networkPolicyApi = new KubeApi({ - objectConstructor: NetworkPolicy, - }); +export class NetworkPolicyApi extends KubeApi { + constructor(params?: BaseKubeApiOptions) { + super({ + ...(params ?? {}), + objectConstructor: NetworkPolicy, + }); + } } -export { - networkPolicyApi, -}; +/** + * Only available within kubernetes cluster pages + */ +export const networkPolicyApi = isClusterPageContext() + ? new NetworkPolicyApi() + : undefined; diff --git a/src/common/k8s-api/endpoints/nodes.api.ts b/src/common/k8s-api/endpoints/nodes.api.ts index 4dc615eef6..183ef28357 100644 --- a/src/common/k8s-api/endpoints/nodes.api.ts +++ b/src/common/k8s-api/endpoints/nodes.api.ts @@ -249,14 +249,11 @@ export class Node extends KubeObject { } } -let nodesApi: NodesApi; - -if (isClusterPageContext()) { - nodesApi = new NodesApi({ +/** + * Only available within kubernetes cluster pages + */ +export const nodesApi = isClusterPageContext() + ? new NodesApi({ objectConstructor: Node, - }); -} - -export { - nodesApi, -}; + }) + : undefined; diff --git a/src/common/k8s-api/endpoints/persistent-volume-claims.api.ts b/src/common/k8s-api/endpoints/persistent-volume-claims.api.ts index a7815e774c..c04df86410 100644 --- a/src/common/k8s-api/endpoints/persistent-volume-claims.api.ts +++ b/src/common/k8s-api/endpoints/persistent-volume-claims.api.ts @@ -94,14 +94,11 @@ export class PersistentVolumeClaim extends KubeObject { } } -let pvcApi: PersistentVolumeClaimsApi; - -if (isClusterPageContext()) { - pvcApi = new PersistentVolumeClaimsApi({ +/** + * Only available within kubernetes cluster pages + */ +export const pvcApi = isClusterPageContext() + ? new PersistentVolumeClaimsApi({ objectConstructor: PersistentVolumeClaim, - }); -} - -export { - pvcApi, -}; + }) + : undefined; diff --git a/src/common/k8s-api/endpoints/persistent-volume.api.ts b/src/common/k8s-api/endpoints/persistent-volume.api.ts index cf225dace8..caf525185c 100644 --- a/src/common/k8s-api/endpoints/persistent-volume.api.ts +++ b/src/common/k8s-api/endpoints/persistent-volume.api.ts @@ -5,7 +5,7 @@ import { KubeObject } from "../kube-object"; import { autoBind, unitsToBytes } from "../../utils"; -import { KubeApi } from "../kube-api"; +import { BaseKubeApiOptions, KubeApi } from "../kube-api"; import type { KubeJsonApiData } from "../kube-json-api"; import { isClusterPageContext } from "../../utils/cluster-id-url-parsing"; @@ -86,14 +86,22 @@ export class PersistentVolume extends KubeObject { } } -let persistentVolumeApi: KubeApi; +/** + * The api type for {@link PersistentVolume}'s + */ -if (isClusterPageContext()) { - persistentVolumeApi = new KubeApi({ - objectConstructor: PersistentVolume, - }); +export class PersistentVolumeApi extends KubeApi { + constructor(params?: BaseKubeApiOptions) { + super({ + ...(params ?? {}), + objectConstructor: PersistentVolume, + }); + } } -export { - persistentVolumeApi, -}; +/** + * Only available within kubernetes cluster pages + */ +export const persistentVolumeApi = isClusterPageContext() + ? new PersistentVolumeApi() + : undefined; diff --git a/src/common/k8s-api/endpoints/pod-metrics.api.ts b/src/common/k8s-api/endpoints/pod-metrics.api.ts index f92e6a6403..376f5b8cf9 100644 --- a/src/common/k8s-api/endpoints/pod-metrics.api.ts +++ b/src/common/k8s-api/endpoints/pod-metrics.api.ts @@ -25,14 +25,11 @@ export class PodMetrics extends KubeObject { static apiBase = "/apis/metrics.k8s.io/v1beta1/pods"; } -let podMetricsApi: KubeApi; - -if (isClusterPageContext()) { - podMetricsApi = new KubeApi({ +/** + * Only available within kubernetes cluster pages + */ +export const podMetricsApi = isClusterPageContext() + ? new KubeApi({ objectConstructor: PodMetrics, - }); -} - -export { - podMetricsApi, -}; + }) + : undefined; diff --git a/src/common/k8s-api/endpoints/poddisruptionbudget.api.ts b/src/common/k8s-api/endpoints/poddisruptionbudget.api.ts index d6df3d3167..7a63deee77 100644 --- a/src/common/k8s-api/endpoints/poddisruptionbudget.api.ts +++ b/src/common/k8s-api/endpoints/poddisruptionbudget.api.ts @@ -5,7 +5,7 @@ import { autoBind } from "../../utils"; import { KubeObject, LabelSelector } from "../kube-object"; -import { KubeApi } from "../kube-api"; +import { BaseKubeApiOptions, KubeApi } from "../kube-api"; import type { KubeJsonApiData } from "../kube-json-api"; import { isClusterPageContext } from "../../utils/cluster-id-url-parsing"; @@ -54,17 +54,23 @@ export class PodDisruptionBudget extends KubeObject { getDesiredHealthy() { return this.status.desiredHealthy; } - } -let pdbApi: KubeApi; - -if (isClusterPageContext()) { - pdbApi = new KubeApi({ - objectConstructor: PodDisruptionBudget, - }); +/** + * The api type for {@link PodDisruptionBudget}'s + */ +export class PodDisruptionBudgetApi extends KubeApi { + constructor(params?: BaseKubeApiOptions) { + super({ + ...(params ?? {}), + objectConstructor: PodDisruptionBudget, + }); + } } -export { - pdbApi, -}; +/** + * Only available within kubernetes cluster pages + */ +export const pdbApi = isClusterPageContext() + ? new PodDisruptionBudgetApi() + : undefined; diff --git a/src/common/k8s-api/endpoints/pods.api.ts b/src/common/k8s-api/endpoints/pods.api.ts index facc1fa3c3..e8b3b2e8d5 100644 --- a/src/common/k8s-api/endpoints/pods.api.ts +++ b/src/common/k8s-api/endpoints/pods.api.ts @@ -73,7 +73,7 @@ export enum PodStatus { EVICTED = "Evicted", } -export interface IPodContainer extends Partial> { +export interface IPodContainer extends Partial> { name: string; image: string; command?: string[]; @@ -129,7 +129,7 @@ export interface IPodContainer extends Partial; - -if (isClusterPageContext()) { - pspApi = new KubeApi({ +/** + * Only available within kubernetes cluster pages + */ +export const pspApi = isClusterPageContext() + ? new KubeApi({ objectConstructor: PodSecurityPolicy, - }); -} - -export { - pspApi, -}; + }) + : undefined; diff --git a/src/common/k8s-api/endpoints/replica-set.api.ts b/src/common/k8s-api/endpoints/replica-set.api.ts index 302ad96b17..e230d30118 100644 --- a/src/common/k8s-api/endpoints/replica-set.api.ts +++ b/src/common/k8s-api/endpoints/replica-set.api.ts @@ -111,14 +111,11 @@ export class ReplicaSet extends WorkloadKubeObject { } } -let replicaSetApi: ReplicaSetApi; - -if (isClusterPageContext()) { - replicaSetApi = new ReplicaSetApi({ +/** + * Only available within kubernetes cluster pages + */ +export const replicaSetApi = isClusterPageContext() + ? new ReplicaSetApi({ objectConstructor: ReplicaSet, - }); -} - -export { - replicaSetApi, -}; + }) + : undefined; diff --git a/src/common/k8s-api/endpoints/resource-quota.api.ts b/src/common/k8s-api/endpoints/resource-quota.api.ts index eda54a7249..211f09c68b 100644 --- a/src/common/k8s-api/endpoints/resource-quota.api.ts +++ b/src/common/k8s-api/endpoints/resource-quota.api.ts @@ -4,7 +4,7 @@ */ import { KubeObject } from "../kube-object"; -import { KubeApi } from "../kube-api"; +import { BaseKubeApiOptions, KubeApi } from "../kube-api"; import { isClusterPageContext } from "../../utils/cluster-id-url-parsing"; export interface IResourceQuotaValues { @@ -65,14 +65,23 @@ export class ResourceQuota extends KubeObject { } } -let resourceQuotaApi: KubeApi; +/** + * The api type for {@link ResourceQuota}'s + */ -if (isClusterPageContext()) { - resourceQuotaApi = new KubeApi({ - objectConstructor: ResourceQuota, - }); +export class ResourceQuotaApi extends KubeApi { + constructor(params?: BaseKubeApiOptions) { + super({ + ...(params ?? {}), + objectConstructor: ResourceQuota, + }); + } } -export { - resourceQuotaApi, -}; +/** + * Only available within kubernetes cluster pages + */ +export const resourceQuotaApi = isClusterPageContext() + ? new ResourceQuotaApi() + : undefined; + diff --git a/src/common/k8s-api/endpoints/role-binding.api.ts b/src/common/k8s-api/endpoints/role-binding.api.ts index dca2510dd3..6dd5498f88 100644 --- a/src/common/k8s-api/endpoints/role-binding.api.ts +++ b/src/common/k8s-api/endpoints/role-binding.api.ts @@ -5,7 +5,7 @@ import { autoBind } from "../../utils"; import { KubeObject } from "../kube-object"; -import { KubeApi } from "../kube-api"; +import { BaseKubeApiOptions, KubeApi } from "../kube-api"; import type { KubeJsonApiData } from "../kube-json-api"; import { isClusterPageContext } from "../../utils/cluster-id-url-parsing"; @@ -46,14 +46,22 @@ export class RoleBinding extends KubeObject { } } -let roleBindingApi: KubeApi; +/** + * The api type for {@link RoleBinding}'s + */ -if (isClusterPageContext()) { - roleBindingApi = new KubeApi({ - objectConstructor: RoleBinding, - }); +export class RoleBindingApi extends KubeApi { + constructor(params?: BaseKubeApiOptions) { + super({ + ...(params ?? {}), + objectConstructor: RoleBinding, + }); + } } -export { - roleBindingApi, -}; +/** + * Only available within kubernetes cluster pages + */ +export const roleBindingApi = isClusterPageContext() + ? new RoleBindingApi() + : undefined; diff --git a/src/common/k8s-api/endpoints/role.api.ts b/src/common/k8s-api/endpoints/role.api.ts index ee960bb934..644b4b24e7 100644 --- a/src/common/k8s-api/endpoints/role.api.ts +++ b/src/common/k8s-api/endpoints/role.api.ts @@ -4,7 +4,7 @@ */ import { KubeObject } from "../kube-object"; -import { KubeApi } from "../kube-api"; +import { BaseKubeApiOptions, KubeApi } from "../kube-api"; import { isClusterPageContext } from "../../utils/cluster-id-url-parsing"; export interface Role { @@ -26,14 +26,23 @@ export class Role extends KubeObject { } } -let roleApi: KubeApi; +/** + * The api type for {@link Role}'s + */ -if (isClusterPageContext()) { - roleApi = new KubeApi({ - objectConstructor: Role, - }); +export class RoleApi extends KubeApi { + constructor(params?: BaseKubeApiOptions) { + super({ + ...(params ?? {}), + objectConstructor: Role, + }); + } } -export{ - roleApi, -}; +/** + * Only available within kubernetes cluster pages + */ +export const roleApi = isClusterPageContext() + ? new RoleApi() + : undefined; + diff --git a/src/common/k8s-api/endpoints/secret.api.ts b/src/common/k8s-api/endpoints/secret.api.ts index a3b821fcf8..f562dc31a6 100644 --- a/src/common/k8s-api/endpoints/secret.api.ts +++ b/src/common/k8s-api/endpoints/secret.api.ts @@ -6,7 +6,7 @@ import { KubeObject } from "../kube-object"; import type { KubeJsonApiData } from "../kube-json-api"; import { autoBind } from "../../utils"; -import { KubeApi } from "../kube-api"; +import { BaseKubeApiOptions, KubeApi } from "../kube-api"; import { isClusterPageContext } from "../../utils/cluster-id-url-parsing"; export enum SecretType { @@ -54,14 +54,21 @@ export class Secret extends KubeObject { } } -let secretsApi: KubeApi; - -if (isClusterPageContext()) { - secretsApi = new KubeApi({ - objectConstructor: Secret, - }); +/** + * The api type for {@link Secret}'s + */ +export class SecretApi extends KubeApi { + constructor(params?: BaseKubeApiOptions) { + super({ + ...(params ?? {}), + objectConstructor: Secret, + }); + } } -export { - secretsApi, -}; +/** + * Only available within kubernetes cluster pages + */ +export const secretsApi = isClusterPageContext() + ? new SecretApi() + : undefined; diff --git a/src/common/k8s-api/endpoints/selfsubjectrulesreviews.api.ts b/src/common/k8s-api/endpoints/selfsubjectrulesreviews.api.ts index c83271b47a..5bfc5945c7 100644 --- a/src/common/k8s-api/endpoints/selfsubjectrulesreviews.api.ts +++ b/src/common/k8s-api/endpoints/selfsubjectrulesreviews.api.ts @@ -71,15 +71,12 @@ export class SelfSubjectRulesReview extends KubeObject { } } -let selfSubjectRulesReviewApi: SelfSubjectRulesReviewApi; - -if (isClusterPageContext()) { - selfSubjectRulesReviewApi = new SelfSubjectRulesReviewApi({ +/** + * Only available within kubernetes cluster pages + */ +export const selfSubjectRulesReviewApi = isClusterPageContext() + ? new SelfSubjectRulesReviewApi({ objectConstructor: SelfSubjectRulesReview, - }); -} - -export { - selfSubjectRulesReviewApi, -}; + }) + : undefined; diff --git a/src/common/k8s-api/endpoints/service-accounts.api.ts b/src/common/k8s-api/endpoints/service-accounts.api.ts index 02cdd453d8..4f3aac90d1 100644 --- a/src/common/k8s-api/endpoints/service-accounts.api.ts +++ b/src/common/k8s-api/endpoints/service-accounts.api.ts @@ -5,7 +5,7 @@ import { autoBind } from "../../utils"; import { KubeObject } from "../kube-object"; -import { KubeApi } from "../kube-api"; +import { BaseKubeApiOptions, KubeApi } from "../kube-api"; import type { KubeJsonApiData } from "../kube-json-api"; import { isClusterPageContext } from "../../utils/cluster-id-url-parsing"; @@ -37,14 +37,22 @@ export class ServiceAccount extends KubeObject { } } -let serviceAccountsApi: KubeApi; +/** + * The api type for {@link ServiceAccount}'s + */ -if (isClusterPageContext()) { - serviceAccountsApi = new KubeApi({ - objectConstructor: ServiceAccount, - }); +export class ServiceAccountApi extends KubeApi { + constructor(params?: BaseKubeApiOptions) { + super({ + ...(params ?? {}), + objectConstructor: ServiceAccount, + }); + } } -export { - serviceAccountsApi, -}; +/** + * Only available within kubernetes cluster pages + */ +export const serviceAccountsApi = isClusterPageContext() + ? new ServiceAccountApi() + : undefined; diff --git a/src/common/k8s-api/endpoints/service.api.ts b/src/common/k8s-api/endpoints/service.api.ts index 6a3eb5ba7b..ad99b5a08b 100644 --- a/src/common/k8s-api/endpoints/service.api.ts +++ b/src/common/k8s-api/endpoints/service.api.ts @@ -5,7 +5,7 @@ import { autoBind } from "../../../renderer/utils"; import { KubeObject } from "../kube-object"; -import { KubeApi } from "../kube-api"; +import { BaseKubeApiOptions, KubeApi } from "../kube-api"; import type { KubeJsonApiData } from "../kube-json-api"; import { isClusterPageContext } from "../../utils/cluster-id-url-parsing"; @@ -132,14 +132,21 @@ export class Service extends KubeObject { } } -let serviceApi: KubeApi; - -if (isClusterPageContext()) { - serviceApi = new KubeApi({ - objectConstructor: Service, - }); +/** + * The api type for {@link Service}'s + */ +export class ServiceApi extends KubeApi { + constructor(params?: BaseKubeApiOptions) { + super({ + ...(params ?? {}), + objectConstructor: Service, + }); + } } -export { - serviceApi, -}; +/** + * Only available within kubernetes cluster pages + */ +export const serviceApi = isClusterPageContext() + ? new ServiceApi() + : undefined; diff --git a/src/common/k8s-api/endpoints/stateful-set.api.ts b/src/common/k8s-api/endpoints/stateful-set.api.ts index d32e24f952..7e494cecdf 100644 --- a/src/common/k8s-api/endpoints/stateful-set.api.ts +++ b/src/common/k8s-api/endpoints/stateful-set.api.ts @@ -136,14 +136,11 @@ export class StatefulSet extends WorkloadKubeObject { } } -let statefulSetApi: StatefulSetApi; - -if (isClusterPageContext()) { - statefulSetApi = new StatefulSetApi({ +/** + * Only available within kubernetes cluster pages + */ +export const statefulSetApi = isClusterPageContext() + ? new StatefulSetApi({ objectConstructor: StatefulSet, - }); -} - -export { - statefulSetApi, -}; + }) + : undefined; diff --git a/src/common/k8s-api/endpoints/storage-class.api.ts b/src/common/k8s-api/endpoints/storage-class.api.ts index c01c89f5b7..924b6b7d9f 100644 --- a/src/common/k8s-api/endpoints/storage-class.api.ts +++ b/src/common/k8s-api/endpoints/storage-class.api.ts @@ -5,7 +5,7 @@ import { autoBind } from "../../utils"; import { KubeObject } from "../kube-object"; -import { KubeApi } from "../kube-api"; +import { BaseKubeApiOptions, KubeApi } from "../kube-api"; import type { KubeJsonApiData } from "../kube-json-api"; import { isClusterPageContext } from "../../utils/cluster-id-url-parsing"; @@ -47,14 +47,22 @@ export class StorageClass extends KubeObject { } } -let storageClassApi: KubeApi; +/** + * The api type for {@link StorageClass}'s + */ -if (isClusterPageContext()) { - storageClassApi = new KubeApi({ - objectConstructor: StorageClass, - }); +export class StorageClassApi extends KubeApi { + constructor(params?: BaseKubeApiOptions) { + super({ + ...(params ?? {}), + objectConstructor: StorageClass, + }); + } } -export { - storageClassApi, -}; +/** + * Only available within kubernetes cluster pages + */ +export const storageClassApi = isClusterPageContext() + ? new StorageClassApi() + : undefined; diff --git a/src/common/k8s-api/index.ts b/src/common/k8s-api/index.ts index 441cb98687..b5dc7352d2 100644 --- a/src/common/k8s-api/index.ts +++ b/src/common/k8s-api/index.ts @@ -9,8 +9,7 @@ import { apiKubePrefix, apiPrefix, isDebugging, isDevelopment } from "../../comm import { isClusterPageContext } from "../utils/cluster-id-url-parsing"; import { appEventBus } from "../app-event-bus/event-bus"; -let apiBase: JsonApi; -let apiKube: KubeJsonApi; +export let apiBase: JsonApi; if (typeof window === "undefined") { appEventBus.addListener((event) => { @@ -42,8 +41,11 @@ if (typeof window === "undefined") { }); } -if (isClusterPageContext()) { - apiKube = new KubeJsonApi({ +/** + * Only available within kubernetes cluster pages + */ +export const apiKube = isClusterPageContext() + ? new KubeJsonApi({ serverAddress: `http://127.0.0.1:${window.location.port}`, apiBase: apiKubePrefix, debug: isDevelopment, @@ -51,10 +53,5 @@ if (isClusterPageContext()) { headers: { "Host": window.location.host, }, - }); -} - -export { - apiBase, - apiKube, -}; + }) + : undefined; diff --git a/src/common/k8s-api/json-api.ts b/src/common/k8s-api/json-api.ts index 9ed120d135..4f9d51f801 100644 --- a/src/common/k8s-api/json-api.ts +++ b/src/common/k8s-api/json-api.ts @@ -44,6 +44,9 @@ export interface JsonApiConfig { const httpAgent = new HttpAgent({ keepAlive: true }); const httpsAgent = new HttpsAgent({ keepAlive: true }); +/** + * The base type used for communicating with a JSON returning API server + */ export class JsonApi { static reqInitDefault: RequestInit = { headers: { @@ -199,6 +202,9 @@ export class JsonApi { } } +/** + * The pseudo-error type that is throw when there are errors from a request + */ export class JsonApiErrorParsed { isUsedForNotification = false; diff --git a/src/common/k8s-api/kube-api-parse.ts b/src/common/k8s-api/kube-api-parse.ts index a47f0e5a1b..d5d5880641 100644 --- a/src/common/k8s-api/kube-api-parse.ts +++ b/src/common/k8s-api/kube-api-parse.ts @@ -12,7 +12,7 @@ import { inspect } from "util"; export interface IKubeObjectRef { kind: string; - apiVersion: string; + apiVersion?: string; name: string; namespace?: string; } diff --git a/src/common/k8s-api/kube-api.ts b/src/common/k8s-api/kube-api.ts index 151e89f03d..92fc6d732d 100644 --- a/src/common/k8s-api/kube-api.ts +++ b/src/common/k8s-api/kube-api.ts @@ -23,16 +23,10 @@ import { Agent, AgentOptions } from "https"; import type { Patch } from "rfc6902"; /** - * The options used for creating a `KubeApi` + * The base constructor options for {@link KubeApi} for use with child classes + * of it. */ -export interface IKubeApiOptions { - /** - * base api-path for listing all resources, e.g. "/api/v1/pods" - * - * If not specified then will be the one on the `objectConstructor` - */ - apiBase?: string; - +export interface BaseKubeApiOptions { /** * If the API uses a different API endpoint (e.g. apiBase) depending on the cluster version, * fallback API bases can be listed individually. @@ -47,17 +41,29 @@ export interface IKubeApiOptions { */ checkPreferredVersion?: boolean; - /** - * The constructor for the kube objects returned from the API - */ - objectConstructor: KubeObjectConstructor; - /** * The api instance to use for making requests * * @default apiKube */ request?: KubeJsonApi; +} + +/** + * The options used for creating a `KubeApi` + */ +export interface IKubeApiOptions extends BaseKubeApiOptions { + /** + * The constructor for the kube objects returned from the API + */ + objectConstructor: KubeObjectConstructor; + + /** + * base api-path for listing all resources, e.g. "/api/v1/pods" + * + * @deprecated It should be specified on the `objectConstructor` + */ + apiBase?: string; /** * @deprecated should be specified by `objectConstructor` @@ -290,7 +296,7 @@ export class KubeApi { this.objectConstructor = objectConstructor; this.parseResponse = this.parseResponse.bind(this); - apiManager.registerApi(apiBase, this); + apiManager.registerApi(this.apiBase, this); } get apiVersionWithGroup() { diff --git a/src/common/k8s-api/kube-json-api.ts b/src/common/k8s-api/kube-json-api.ts index bc578641c3..e6a03de7af 100644 --- a/src/common/k8s-api/kube-json-api.ts +++ b/src/common/k8s-api/kube-json-api.ts @@ -3,7 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { JsonApi, JsonApiData, JsonApiError } from "./json-api"; +import { JsonApi, JsonApiError } from "./json-api"; import type { Response } from "node-fetch"; import { LensProxy } from "../../main/lens-proxy"; import { apiKubePrefix, isDebugging } from "../vars"; @@ -38,10 +38,12 @@ export interface KubeJsonApiMetadata { [key: string]: any; } -export interface KubeJsonApiData extends JsonApiData { +export interface KubeJsonApiData { kind: string; apiVersion: string; - metadata: KubeJsonApiMetadata; + metadata: Metadata; + status?: Status; + spec?: Spec; } export interface KubeJsonApiError extends JsonApiError { diff --git a/src/common/k8s-api/kube-object.store.ts b/src/common/k8s-api/kube-object.store.ts index 373ffb8251..9dbf580981 100644 --- a/src/common/k8s-api/kube-object.store.ts +++ b/src/common/k8s-api/kube-object.store.ts @@ -57,7 +57,10 @@ export interface KubeObjectStoreSubscribeParams { } export abstract class KubeObjectStore extends ItemStore { - static defaultContext = observable.box(); // TODO: support multiple cluster contexts + /** + * @internal + */ + static defaultContext: ClusterContext; // TODO: support multiple cluster contexts public api: KubeApi; public readonly limit?: number; @@ -81,8 +84,11 @@ export abstract class KubeObjectStore extends ItemStore this.bindWatchEventsUpdater(); } + /** + * @internal + */ get context(): ClusterContext { - return KubeObjectStore.defaultContext.get(); + return KubeObjectStore.defaultContext; } // TODO: Circular dependency: KubeObjectStore -> ClusterFrameContext -> NamespaceStore -> KubeObjectStore @@ -369,11 +375,10 @@ export abstract class KubeObjectStore extends ItemStore return Promise.all(this.selectedItems.map(this.remove)); } - async removeItems(items: T[]) { - await Promise.all(items.map(this.remove)); - } - - // collect items from watch-api events to avoid UI blowing up with huge streams of data + /** + * collect items from watch-api events to avoid UI blowing up with huge streams of data + * @internal + */ protected eventsBuffer = observable.array>([], { deep: false }); protected bindWatchEventsUpdater(delay = 1000) { diff --git a/src/common/k8s-api/kube-object.ts b/src/common/k8s-api/kube-object.ts index 7098c98847..7a1f163557 100644 --- a/src/common/k8s-api/kube-object.ts +++ b/src/common/k8s-api/kube-object.ts @@ -14,6 +14,7 @@ import type { JsonApiParams } from "./json-api"; import * as resourceApplierApi from "./endpoints/resource-applier.api"; import { hasOptionalProperty, hasTypedProperty, isObject, isString, bindPredicate, isTypedArray, isRecord } from "../../common/utils/type-narrowing"; import type { Patch } from "rfc6902"; +import Joi from "joi"; export type KubeObjectConstructor = (new (data: KubeJsonApiData | any) => K) & { kind?: string; @@ -25,9 +26,9 @@ export interface KubeObjectMetadata { uid: string; name: string; namespace?: string; - creationTimestamp: string; + creationTimestamp?: string; resourceVersion: string; - selfLink: string; + selfLink?: string; deletionTimestamp?: string; finalizers?: string[]; continue?: string; // provided when used "?limit=" query param to fetch objects list @@ -116,6 +117,36 @@ export interface LabelSelector { matchExpressions?: LabelMatchExpression[]; } +const kubeObjectValidator = Joi + .object({ + metadata: Joi + .object() + .unknown(true) + .required(), + spec: Joi. + object() + .unknown(true) + .optional(), + status: Joi. + object() + .unknown(true) + .optional(), + managedFields: Joi. + object() + .unknown(true) + .optional(), + apiVersion: Joi + .string() + .required(), + kind: Joi + .string() + .required(), + }) + .unknown(true); + +/** + * The Lens representation of a kube resource + */ export class KubeObject implements ItemObject { static readonly kind?: string; static readonly namespaced?: boolean; @@ -126,7 +157,7 @@ export class KubeObject) { + const { error } = kubeObjectValidator.validate(data); - if (!data.metadata || typeof data.metadata !== "object") { - throw new KubeCreationError(`Cannot create a KubeObject from an object without metadata`, data); + if (error) { + throw error; } Object.assign(this, data); diff --git a/src/common/k8s-api/workload-kube-object.ts b/src/common/k8s-api/workload-kube-object.ts index f612f14cd5..7935be9931 100644 --- a/src/common/k8s-api/workload-kube-object.ts +++ b/src/common/k8s-api/workload-kube-object.ts @@ -14,13 +14,18 @@ export interface IToleration { tolerationSeconds?: number; } -interface IMatchExpression { +export interface Affinity { + requiredDuringSchedulingIgnoredDuringExecution?: T[]; + preferredDuringSchedulingIgnoredDuringExecution?: T[]; +} + +export interface IMatchExpression { key: string; operator: string; values: string[]; } -interface INodeAffinity { +export interface INodeAffinity { nodeSelectorTerms?: { matchExpressions: IMatchExpression[]; }[]; @@ -30,7 +35,7 @@ interface INodeAffinity { }; } -interface IPodAffinity { +export interface IPodAffinity { labelSelector: { matchExpressions: IMatchExpression[]; }; @@ -38,18 +43,9 @@ interface IPodAffinity { } export interface IAffinity { - nodeAffinity?: { - requiredDuringSchedulingIgnoredDuringExecution?: INodeAffinity[]; - preferredDuringSchedulingIgnoredDuringExecution?: INodeAffinity[]; - }; - podAffinity?: { - requiredDuringSchedulingIgnoredDuringExecution?: IPodAffinity[]; - preferredDuringSchedulingIgnoredDuringExecution?: IPodAffinity[]; - }; - podAntiAffinity?: { - requiredDuringSchedulingIgnoredDuringExecution?: IPodAffinity[]; - preferredDuringSchedulingIgnoredDuringExecution?: IPodAffinity[]; - }; + nodeAffinity?: Affinity; + podAffinity?: Affinity; + podAntiAffinity?: Affinity; } export class WorkloadKubeObject extends KubeObject { diff --git a/src/common/utils/index.ts b/src/common/utils/index.ts index 0ecb4bc71e..3fd8008214 100644 --- a/src/common/utils/index.ts +++ b/src/common/utils/index.ts @@ -10,6 +10,8 @@ export function noop(...args: T): void { return void args; } +export type Defaulted = Required> & Omit; + export * from "./abort-controller"; export * from "./app-version"; export * from "./autobind"; diff --git a/src/extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api-with-modifications.ts b/src/extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api-with-modifications.ts deleted file mode 100644 index 679dffb3b6..0000000000 --- a/src/extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api-with-modifications.ts +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import type { Injectable, TentativeTuple } from "@ogre-tools/injectable"; -import { getLegacyGlobalDiForExtensionApi } from "./legacy-global-di-for-extension-api"; - -type MapInjectables = { - [Key in keyof T]: T[Key] extends () => infer Res ? Res : never; -}; - -export const asLegacyGlobalObjectForExtensionApiWithModifications = < - TInjectable extends Injectable, - TInstantiationParameter, - OtherFields extends Record any>, ->( - injectableKey: TInjectable, - otherFields: OtherFields, - ...instantiationParameter: TentativeTuple - ) => - new Proxy( - {}, - { - get(target, propertyName) { - if (propertyName === "$$typeof") { - return undefined; - } - - const instance: any = getLegacyGlobalDiForExtensionApi().inject( - injectableKey, - ...instantiationParameter, - ); - - const propertyValue = instance[propertyName] ?? otherFields[propertyName as any](); - - if (typeof propertyValue === "function") { - return function (...args: any[]) { - return propertyValue.apply(instance, args); - }; - } - - return propertyValue; - }, - }, - ) as ReturnType & MapInjectables; diff --git a/src/extensions/common-api/catalog.ts b/src/extensions/common-api/catalog.ts index fae083e75a..1c0c544cc8 100644 --- a/src/extensions/common-api/catalog.ts +++ b/src/extensions/common-api/catalog.ts @@ -9,16 +9,22 @@ export { GeneralEntity, WebLink, } from "../../common/catalog-entities"; - export type { KubernetesClusterPrometheusMetrics, KubernetesClusterSpec, + KubernetesClusterCategory, KubernetesClusterMetadata, WebLinkSpec, WebLinkStatus, WebLinkStatusPhase, KubernetesClusterStatusPhase, KubernetesClusterStatus, + GeneralEntitySpec, } from "../../common/catalog-entities"; +export type { + CategoryFilter, +} from "../../common/catalog/catalog-category-registry"; + export * from "../../common/catalog/catalog-entity"; +export { CatalogRunEvent } from "../../common/catalog/catalog-run-event"; diff --git a/src/extensions/common-api/event-bus.ts b/src/extensions/common-api/event-bus.ts index c6d2a1a34b..fee89538e7 100644 --- a/src/extensions/common-api/event-bus.ts +++ b/src/extensions/common-api/event-bus.ts @@ -5,3 +5,4 @@ export { appEventBus } from "../../common/app-event-bus/event-bus"; export type { AppEvent } from "../../common/app-event-bus/event-bus"; +export type { EventEmitter, AddListenerOptions, EventListener } from "../../common/event-emitter"; diff --git a/src/extensions/common-api/registrations.ts b/src/extensions/common-api/registrations.ts index 76d7538e12..1e36d2c358 100644 --- a/src/extensions/common-api/registrations.ts +++ b/src/extensions/common-api/registrations.ts @@ -2,13 +2,23 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -export type { StatusBarRegistration } from "../../renderer/components/status-bar/status-bar-registration"; -export type { KubeObjectMenuRegistration, KubeObjectMenuComponents } from "../../renderer/components/kube-object-menu/dependencies/kube-object-menu-items/kube-object-menu-registration"; +export type { StatusBarRegistration, StatusBarComponents, StatusBarItemProps } from "../../renderer/components/status-bar/status-bar-registration"; +export type { KubeObjectMenuRegistration, KubeObjectMenuComponents, KubeObjectMenuItemProps } from "../../renderer/components/kube-object-menu/dependencies/kube-object-menu-items/kube-object-menu-registration"; export type { AppPreferenceRegistration, AppPreferenceComponents } from "../../renderer/components/+preferences/app-preferences/app-preference-registration"; export type { KubeObjectDetailRegistration, KubeObjectDetailComponents } from "../registries/kube-object-detail-registry"; export type { KubeObjectStatusRegistration } from "../registries/kube-object-status-registry"; export type { PageRegistration, RegisteredPage, PageParams, PageComponentProps, PageComponents, PageTarget } from "../registries/page-registry"; export type { ClusterPageMenuRegistration, ClusterPageMenuComponents } from "../registries/page-menu-registry"; -export type { ProtocolHandlerRegistration, RouteParams as ProtocolRouteParams, RouteHandler as ProtocolRouteHandler } from "../registries/protocol-handler"; +export type { MenuRegistration } from "../../main/menu/menu-registration"; +export type { MenuTopId } from "../../main/menu/menu"; +export type { CatalogEntityDetailRegistration, CatalogEntityDetailsProps, CatalogEntityDetailComponents } from "../registries/catalog-entity-detail-registry"; export type { CustomCategoryViewProps, CustomCategoryViewComponents, CustomCategoryViewRegistration } from "../../renderer/components/+catalog/custom-views"; export type { ShellEnvModifier, ShellEnvContext } from "../../main/shell-session/shell-env-modifier/shell-env-modifier-registration"; +export type { ProtocolHandlerRegistration, RouteParams as ProtocolRouteParams, RouteHandler as ProtocolRouteHandler } from "../registries/protocol-handler"; +export type { CommandRegistration, CommandContext } from "../../renderer/components/command-palette/registered-commands/commands"; +export type { EntitySettingRegistration, EntitySettingViewProps, EntitySettingComponents } from "../registries/entity-setting-registry"; +export type { WorkloadsOverviewDetailRegistration, WorkloadsOverviewDetailComponents } from "../registries/workloads-overview-detail-registry"; +export type { TopBarRegistration, TopBarComponents } from "../../renderer/components/layout/top-bar/top-bar-registration"; +export type { WelcomeBannerRegistration } from "../../renderer/components/+welcome/welcome-banner-items/welcome-banner-registration"; +export type { WelcomeMenuRegistration } from "../../renderer/components/+welcome/welcome-menu-items/welcome-menu-registration"; +export type { TrayMenuRegistration } from "../../main/tray/tray-menu-registration"; diff --git a/src/extensions/common-api/stores.ts b/src/extensions/common-api/stores.ts index b369579d70..890c458784 100644 --- a/src/extensions/common-api/stores.ts +++ b/src/extensions/common-api/stores.ts @@ -4,3 +4,4 @@ */ export { ExtensionStore } from "../extension-store"; +export type { BaseStoreParams } from "../../common/base-store"; diff --git a/src/extensions/common-api/types.ts b/src/extensions/common-api/types.ts index febb2c4e56..ef01cf7c2c 100644 --- a/src/extensions/common-api/types.ts +++ b/src/extensions/common-api/types.ts @@ -6,5 +6,15 @@ export type IpcMainInvokeEvent = Electron.IpcMainInvokeEvent; export type IpcRendererEvent = Electron.IpcRendererEvent; export type IpcMainEvent = Electron.IpcMainEvent; +export type { LensExtension, LensExtensionManifest, LensExtensionId } from "../lens-extension"; +export type { InstalledExtension } from "../extension-discovery/extension-discovery"; +export type { Disposer } from "../../common/utils"; + +export { + ItemStore, +} from "../../common/item.store"; +export type { + ItemObject, +} from "../../common/item.store"; export * from "./registrations"; diff --git a/src/extensions/common-k8s-api.ts b/src/extensions/common-k8s-api.ts new file mode 100644 index 0000000000..0005c8e68c --- /dev/null +++ b/src/extensions/common-k8s-api.ts @@ -0,0 +1,199 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +/** + * This file is for the common exports to both `Renderer.K8sApi` and `Main.K8sApi` + * + * It would be nicer if we exported this from `Common.K8sApi` but there doesn't seem + * to be a good way to deprecate an export so that will have to wait. + */ + +export { + ResourceStack, +} from "../common/k8s/resource-stack"; +export { + KubeObjectStore, +} from "../common/k8s-api/kube-object.store"; +export { + forCluster, + forRemoteCluster, + KubeApi, +} from "../common/k8s-api/kube-api"; +export type { + BaseKubeApiOptions, + DeleteResourceDescriptor, + KubeApiListOptions, + KubeApiPatchType, + KubeApiWatchCallback, + KubeApiWatchOptions, + PartialKubeObject, + PropagationPolicy, + ResourceDescriptor, +} from "../common/k8s-api/kube-api"; +export type { + IKubeWatchEvent, +} from "../common/k8s-api/kube-watch-event"; +export { + KubeObject, + KubeStatus, +} from "../common/k8s-api/kube-object"; +export type { + KubeStatusData, +} from "../common/k8s-api/kube-object"; +export { + ClusterRole, + ClusterRoleApi, + ClusterRoleBinding, + ClusterRoleBindingApi, + ConfigMap, + ConfigMapApi, + CronJob, + CronJobApi, + CustomResourceDefinition, + CustomResourceDefinitionApi, + DaemonSet, + DaemonSetApi, + Deployment, + DeploymentApi, + Endpoint, + EndpointApi, + HorizontalPodAutoscaler, + HorizontalPodAutoscalerApi, + Ingress, + IngressApi, + Job, + JobApi, + KubeEvent, + KubeEventApi, + LimitRange, + LimitRangeApi, + Namespace, + NamespaceApi, + NetworkPolicy, + NetworkPolicyApi, + Node, + NodesApi, + PersistentVolume, + PersistentVolumeApi, + PersistentVolumeClaim, + PersistentVolumeClaimsApi, + Pod, + PodDisruptionBudget, + PodDisruptionBudgetApi, + PodsApi, + ReplicaSet, + ReplicaSetApi, + ResourceQuota, + ResourceQuotaApi, + Role, + RoleApi, + RoleBinding, + RoleBindingApi, + Secret, + SecretApi, + SecretType, + Service, + ServiceAccount, + ServiceAccountApi, + ServiceApi, + StatefulSet, + StatefulSetApi, + StorageClass, + StorageClassApi, +} from "../common/k8s-api/endpoints"; +export { + KubeObjectStatusLevel, +} from "./registries/kube-object-status-registry"; +export type { + IKubeApiCluster, + IKubeApiOptions, + IKubeApiQueryParams, + ILocalKubeApiConfig, + IRemoteKubeApiConfig, +} from "../common/k8s-api/kube-api"; +export type { + KubeObjectConstructor, + KubeObjectMetadata, + LabelMatchExpression, + LabelSelector, +} from "../common/k8s-api/kube-object"; +export type { + AdditionalPrinterColumnsCommon, + AdditionalPrinterColumnsV1, + AdditionalPrinterColumnsV1Beta, + ClusterRoleBindingSubject, + ClusterRoleBindingSubjectKind, + ContainerProbe, + ContainerState, + ContainerStateRunning, + ContainerStateTerminated, + ContainerStateWaiting, + CRDVersion, + CustomResourceDefinitionSpec, + CustomResourceDefinitionStatus, + EndpointAddress, + EndpointSubset, + HpaMetricType, + IContainerProbe, + IEndpointAddress, + IEndpointPort, + IEndpointSubset, + IExtensionsBackend, + IHpaMetric, + IHpaMetricData, + IIngressBackend, + IIngressService, + ILoadBalancerIngress, + INetworkingBackend, + IPodContainer, + IPodContainerStatus, + IPodLogsQuery, + IPolicyEgress, + IPolicyIngress, + IPolicyIpBlock, + IResourceQuotaValues, + ISecretRef, + ITargetRef, + LimitRangeItem, + NetworkPolicyPeer, + NetworkPolicyPort, + NetworkPolicySpec, + NodeCondition, + NodeTaint, + PodMetrics, + PodStatus, + PolicyType, + RoleBindingSubject, + RoleBindingSubjectKind, + SecretData, + ServicePort, +} from "../common/k8s-api/endpoints"; +export type { + Affinity, + IAffinity, + IMatchExpression, + INodeAffinity, + IPodAffinity, + IToleration, +} from "../common/k8s-api/workload-kube-object"; +export type { + KubeObjectStatus, +} from "./registries/kube-object-status-registry"; +export type { + JsonApi, + JsonApiConfig, + JsonApiData, + JsonApiError, + JsonApiErrorParsed, + JsonApiLog, + JsonApiParams, +} from "../common/k8s-api/json-api"; +export type { + KubeJsonApi, + KubeJsonApiData, + KubeJsonApiDataList, + KubeJsonApiListMetadata, + KubeJsonApiMetadata, +} from "../common/k8s-api/kube-json-api"; diff --git a/src/extensions/lens-extension.ts b/src/extensions/lens-extension.ts index bdfb4578e5..680b9aed80 100644 --- a/src/extensions/lens-extension.ts +++ b/src/extensions/lens-extension.ts @@ -14,18 +14,45 @@ import { setLensExtensionDependencies, } from "./lens-extension-set-dependencies"; -export type LensExtensionId = string; // path to manifest (package.json) +/** + * A named type for when functions should expect an extension's ID + */ +export type LensExtensionId = string; export type LensExtensionConstructor = new (...args: ConstructorParameters) => LensExtension; +/** + * The required fields that an extension's `package.json` must include + */ export interface LensExtensionManifest extends PackageJson { + /** + * The name of the extension + */ name: string; + + /** + * The SemVer version string + */ version: string; - main?: string; // path to %ext/dist/main.js - renderer?: string; // path to %ext/dist/renderer.js + + /** + * The path to compiled JS file for the main side of the extension. + */ + main?: string; + + /** + * The path to compiled JS file for the renderer side of the extension. + */ + renderer?: string; } +/** + * @internal + */ export const Disposers = Symbol(); +/** + * The base class for all extensions. + */ export class LensExtension { readonly id: LensExtensionId; readonly manifest: LensExtensionManifest; @@ -40,6 +67,9 @@ export class LensExtension { return this._isEnabled; } + /** + * @internal + */ [Disposers] = disposer(); constructor({ id, manifest, manifestPath, isBundled }: InstalledExtension) { @@ -64,6 +94,9 @@ export class LensExtension { private dependencies: LensExtensionDependencies; + /** + * @internal + */ [setLensExtensionDependencies] = (dependencies: LensExtensionDependencies) => { this.dependencies = dependencies; }; diff --git a/src/extensions/main-api/k8s-api.ts b/src/extensions/main-api/k8s-api.ts index e9ea0650ac..c710654cef 100644 --- a/src/extensions/main-api/k8s-api.ts +++ b/src/extensions/main-api/k8s-api.ts @@ -3,6 +3,8 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ +export * from "../common-k8s-api"; + /** * @deprecated This function never works * @returns false @@ -10,45 +12,3 @@ export function isAllowedResource(...args: any[]) { return Boolean(void args); } - -export { ResourceStack } from "../../common/k8s/resource-stack"; -export { apiManager } from "../../common/k8s-api/api-manager"; -export { KubeApi, forCluster, forRemoteCluster } from "../../common/k8s-api/kube-api"; -export { KubeObject, KubeStatus } from "../../common/k8s-api/kube-object"; -export { KubeObjectStore } from "../../common/k8s-api/kube-object.store"; -export { Pod, podsApi, PodsApi } from "../../common/k8s-api/endpoints/pods.api"; -export { Node, nodesApi, NodesApi } from "../../common/k8s-api/endpoints/nodes.api"; -export { Deployment, deploymentApi, DeploymentApi } from "../../common/k8s-api/endpoints/deployment.api"; -export { DaemonSet, daemonSetApi } from "../../common/k8s-api/endpoints/daemon-set.api"; -export { StatefulSet, statefulSetApi } from "../../common/k8s-api/endpoints/stateful-set.api"; -export { Job, jobApi } from "../../common/k8s-api/endpoints/job.api"; -export { CronJob, cronJobApi } from "../../common/k8s-api/endpoints/cron-job.api"; -export { ConfigMap, configMapApi } from "../../common/k8s-api/endpoints/configmap.api"; -export { Secret, secretsApi } from "../../common/k8s-api/endpoints/secret.api"; -export { ReplicaSet, replicaSetApi } from "../../common/k8s-api/endpoints/replica-set.api"; -export { ResourceQuota, resourceQuotaApi } from "../../common/k8s-api/endpoints/resource-quota.api"; -export { LimitRange, limitRangeApi } from "../../common/k8s-api/endpoints/limit-range.api"; -export { HorizontalPodAutoscaler, hpaApi } from "../../common/k8s-api/endpoints/hpa.api"; -export { PodDisruptionBudget, pdbApi } from "../../common/k8s-api/endpoints/poddisruptionbudget.api"; -export { Service, serviceApi } from "../../common/k8s-api/endpoints/service.api"; -export { Endpoint, endpointApi } from "../../common/k8s-api/endpoints/endpoint.api"; -export { Ingress, ingressApi, IngressApi } from "../../common/k8s-api/endpoints/ingress.api"; -export { NetworkPolicy, networkPolicyApi } from "../../common/k8s-api/endpoints/network-policy.api"; -export { PersistentVolume, persistentVolumeApi } from "../../common/k8s-api/endpoints/persistent-volume.api"; -export { PersistentVolumeClaim, pvcApi, PersistentVolumeClaimsApi } from "../../common/k8s-api/endpoints/persistent-volume-claims.api"; -export { StorageClass, storageClassApi } from "../../common/k8s-api/endpoints/storage-class.api"; -export { Namespace, namespacesApi } from "../../common/k8s-api/endpoints/namespaces.api"; -export { KubeEvent, eventApi } from "../../common/k8s-api/endpoints/events.api"; -export { ServiceAccount, serviceAccountsApi } from "../../common/k8s-api/endpoints/service-accounts.api"; -export { Role, roleApi } from "../../common/k8s-api/endpoints/role.api"; -export { RoleBinding, roleBindingApi } from "../../common/k8s-api/endpoints/role-binding.api"; -export { ClusterRole, clusterRoleApi } from "../../common/k8s-api/endpoints/cluster-role.api"; -export { ClusterRoleBinding, clusterRoleBindingApi } from "../../common/k8s-api/endpoints/cluster-role-binding.api"; -export { CustomResourceDefinition, crdApi } from "../../common/k8s-api/endpoints/crd.api"; - -// types -export type { ILocalKubeApiConfig, IRemoteKubeApiConfig, IKubeApiCluster } from "../../common/k8s-api/kube-api"; -export type { IPodContainer, IPodContainerStatus } from "../../common/k8s-api/endpoints/pods.api"; -export type { ISecretRef } from "../../common/k8s-api/endpoints/secret.api"; -export type { KubeObjectMetadata, KubeStatusData } from "../../common/k8s-api/kube-object"; -export type { KubeObjectStoreLoadAllParams, KubeObjectStoreLoadingParams, KubeObjectStoreSubscribeParams } from "../../common/k8s-api/kube-object.store"; diff --git a/src/extensions/npm/extensions/package.json b/src/extensions/npm/extensions/package.json index 09db697b35..6066ce7bba 100644 --- a/src/extensions/npm/extensions/package.json +++ b/src/extensions/npm/extensions/package.json @@ -2,7 +2,7 @@ "name": "@k8slens/extensions", "productName": "OpenLens extensions", "description": "OpenLens - Open Source Kubernetes IDE: extensions", - "version": "0.0.0", + "version": "5.3.0", "copyright": "© 2021 OpenLens Authors", "license": "MIT", "main": "dist/src/extensions/extension-api.js", diff --git a/src/extensions/registries/kube-object-status-registry.ts b/src/extensions/registries/kube-object-status-registry.ts index 0121e9a39e..7dd2de7379 100644 --- a/src/extensions/registries/kube-object-status-registry.ts +++ b/src/extensions/registries/kube-object-status-registry.ts @@ -3,9 +3,21 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import type { KubeObject, KubeObjectStatus } from "../renderer-api/k8s-api"; +import type { KubeObject } from "../renderer-api/k8s-api"; import { BaseRegistry } from "./base-registry"; +export enum KubeObjectStatusLevel { + INFO = 1, + WARNING = 2, + CRITICAL = 3, +} + +export interface KubeObjectStatus { + level: KubeObjectStatusLevel; + text: string; + timestamp?: string; +} + export interface KubeObjectStatusRegistration { kind: string; apiVersions: string[]; diff --git a/src/extensions/registries/workloads-overview-detail-registry.ts b/src/extensions/registries/workloads-overview-detail-registry.ts index 2688ba72d6..1036153a71 100644 --- a/src/extensions/registries/workloads-overview-detail-registry.ts +++ b/src/extensions/registries/workloads-overview-detail-registry.ts @@ -8,7 +8,7 @@ import type React from "react"; import { BaseRegistry } from "./base-registry"; export interface WorkloadsOverviewDetailComponents { - Details: React.ComponentType<{}>; + Details: React.ComponentType; } export interface WorkloadsOverviewDetailRegistration { diff --git a/src/extensions/renderer-api/catalog.ts b/src/extensions/renderer-api/catalog.ts index 34f6fcd0bb..6db82fb759 100644 --- a/src/extensions/renderer-api/catalog.ts +++ b/src/extensions/renderer-api/catalog.ts @@ -8,9 +8,19 @@ import type { CatalogCategory, CatalogEntity } from "../../common/catalog"; import { catalogEntityRegistry as registry } from "../../renderer/api/catalog-entity-registry"; import type { CatalogEntityOnBeforeRun } from "../../renderer/api/catalog-entity-registry"; import type { Disposer } from "../../common/utils"; + +export type { + EntityFilter, + CatalogEntityOnBeforeRun, +} from "../../renderer/api/catalog-entity-registry"; + +export type { CatalogCategoryRegistry } from "../../common/catalog/catalog-category-registry"; export { catalogCategoryRegistry as catalogCategories } from "../../common/catalog/catalog-category-registry"; -export class CatalogEntityRegistry { +/** + * The registry for entities synced to renderer + */ +class CatalogEntityRegistry { /** * Currently active/visible entity */ @@ -18,18 +28,36 @@ export class CatalogEntityRegistry { return registry.activeEntity; } + /** + * The mapping of all entities from ID to instance + */ get entities(): Map { return registry.entities; } - getById(id: string) { + /** + * Attempt to get a catalog entity by its ID. + * @param id The ID of the desired entity + */ + getById(id: string): CatalogEntity | undefined { return this.entities.get(id); } + /** + * Get all the entities of a specific version and kind + * @param apiVersion The version string of an entity + * @param kind The kind of the entity + * @returns A list of entities matching that `apiVersion` and `kind` + */ getItemsForApiKind(apiVersion: string, kind: string): T[] { return registry.getItemsForApiKind(apiVersion, kind); } + /** + * Get all the entities for the kinds declared by a specific category + * @param category The category that declares different apiVersions for a specific kind + * @returns A list of entities matching the deckared `apiVersion`'s and `kind` + */ getItemsForCategory(category: CatalogCategory): T[] { return registry.getItemsForCategory(category); } @@ -47,4 +75,6 @@ export class CatalogEntityRegistry { } } +export type { CatalogEntityRegistry }; + export const catalogEntities = new CatalogEntityRegistry(); diff --git a/src/extensions/renderer-api/components.ts b/src/extensions/renderer-api/components.ts index 8e6df41fa1..ff2f05145a 100644 --- a/src/extensions/renderer-api/components.ts +++ b/src/extensions/renderer-api/components.ts @@ -5,16 +5,26 @@ import { asLegacyGlobalFunctionForExtensionApi } from "../as-legacy-globals-for-extension-api/as-legacy-global-function-for-extension-api"; import createTerminalTabInjectable from "../../renderer/components/dock/terminal/create-terminal-tab.injectable"; import terminalStoreInjectable from "../../renderer/components/dock/terminal/store.injectable"; +import type { TerminalStore as TerminalStoreType, TerminalTab } from "../../renderer/components/dock/terminal/store"; import { asLegacyGlobalObjectForExtensionApi } from "../as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api"; import logTabStoreInjectable from "../../renderer/components/dock/logs/tab-store.injectable"; import commandOverlayInjectable from "../../renderer/components/command-palette/command-overlay.injectable"; -import { asLegacyGlobalObjectForExtensionApiWithModifications } from "../as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api-with-modifications"; -import createPodLogsTabInjectable from "../../renderer/components/dock/logs/create-pod-logs-tab.injectable"; -import createWorkloadLogsTabInjectable from "../../renderer/components/dock/logs/create-workload-logs-tab.injectable"; -import sendCommandInjectable from "../../renderer/components/dock/terminal/send-command.injectable"; +import type { CommandOverlay as CommandPalletState } from "../../renderer/components/command-palette/command-overlay.injectable"; +import createPodLogsTabInjectable, { PodLogsTabData } from "../../renderer/components/dock/logs/create-pod-logs-tab.injectable"; +import createWorkloadLogsTabInjectable, { WorkloadLogsTabData } from "../../renderer/components/dock/logs/create-workload-logs-tab.injectable"; +import sendCommandInjectable, { SendCommandOptions } from "../../renderer/components/dock/terminal/send-command.injectable"; import { podsStore } from "../../renderer/components/+workloads-pods/pods.store"; import renameTabInjectable from "../../renderer/components/dock/dock/rename-tab.injectable"; +import type { DockTabStorageState } from "../../renderer/components/dock/dock-tab-store/dock-tab.store"; +import type { LogTabData, LogTabOwnerRef, LogTabStore } from "../../renderer/components/dock/logs/tab-store"; +import type { CommandActionContext, CommandActionNavigateOptions } from "../../renderer/components/command-palette/registered-commands/commands"; +import type { TerminalApi, TerminalApiQuery, TerminalChannels, TerminalEvents, TerminalMessage } from "../../renderer/api/terminal-api"; +import type { Terminal } from "../../renderer/components/dock/terminal/terminal"; +import type { WebSocketApiState } from "../../renderer/api/websocket-api"; +import type { HeaderCustomizer, ItemsFilters, ItemsFilter, SearchFilter, SearchFilters, HeaderPlaceholders, ItemListLayout, ItemListLayoutProps } from "../../renderer/components/item-object-list"; +import type { ItemListLayoutHeader, ItemListLayoutHeaderProps } from "../../renderer/components/item-object-list/header"; +import type { Filter, FilterType } from "../../renderer/components/item-object-list/page-filters.store"; // layouts export * from "../../renderer/components/layout/main-layout"; @@ -29,15 +39,37 @@ export * from "../../renderer/components/checkbox"; export * from "../../renderer/components/radio"; export * from "../../renderer/components/select"; export * from "../../renderer/components/slider"; -export * from "../../renderer/components/switch"; -export * from "../../renderer/components/input/input"; +export { FormSwitch, Switcher } from "../../renderer/components/switch"; +export type { SwitcherProps, SwitcherStyles } from "../../renderer/components/switch"; +export { + Input, + InputValidators, + SearchInput, +} from "../../renderer/components/input"; +export type { + IconData, + IconDataFnArg, + InputElement, + InputElementProps, + InputProps, + InputState, + InputValidator, + SearchInputProps, + SearchInputUrlProps, +} from "../../renderer/components/input"; // command-overlay -export const CommandOverlay = asLegacyGlobalObjectForExtensionApi(commandOverlayInjectable); +export type { + CommandPalletState, + CommandActionContext, + CommandActionNavigateOptions, +}; +export const CommandOverlay = asLegacyGlobalObjectForExtensionApi(commandOverlayInjectable) as CommandPalletState; export type { CategoryColumnRegistration, AdditionalCategoryColumnRegistration, + TitleCellProps, } from "../../renderer/components/+catalog/custom-category-columns"; // other components @@ -59,14 +91,32 @@ export * from "../../renderer/components/+workloads-pods/pod-details-list"; export * from "../../renderer/components/+namespaces/namespace-select"; export * from "../../renderer/components/+namespaces/namespace-select-filter"; export * from "../../renderer/components/layout/sub-title"; -export * from "../../renderer/components/input/search-input"; -export * from "../../renderer/components/chart/bar-chart"; -export * from "../../renderer/components/chart/pie-chart"; +export * from "../../renderer/components/chart"; // kube helpers export * from "../../renderer/components/kube-detail-params"; export * from "../../renderer/components/kube-object-details"; export * from "../../renderer/components/kube-object-list-layout"; +export type { AddRemoveButtonsProps } from "../../renderer/components/add-remove-buttons"; +export { + cssNames, + type IClassName, + type IClassNameMap, +} from "../../renderer/utils"; +export type { + HeaderCustomizer, + ItemsFilters, + ItemsFilter, + FilterType, + Filter, + SearchFilter, + SearchFilters, + HeaderPlaceholders, + ItemListLayout, + ItemListLayoutProps, + ItemListLayoutHeader, + ItemListLayoutHeaderProps, +}; export * from "../../renderer/components/kube-object-menu"; export * from "../../renderer/components/kube-object-meta"; export * from "../../renderer/components/+events/kube-event-details"; @@ -74,31 +124,59 @@ export * from "../../renderer/components/+events/kube-event-details"; // specific exports export * from "../../renderer/components/status-brick"; +export type { + SendCommandOptions, + PodLogsTabData, + WorkloadLogsTabData, + DockTabStorageState, +}; + +export type { + TabKind, + TabId, + DockTabCreateOption, + BaseDockTabCreateOptions, +} from "../../renderer/components/dock/dock/store"; + export const createTerminalTab = asLegacyGlobalFunctionForExtensionApi(createTerminalTabInjectable); -export const terminalStore = asLegacyGlobalObjectForExtensionApiWithModifications(terminalStoreInjectable, { - sendCommand: () => asLegacyGlobalFunctionForExtensionApi(sendCommandInjectable), + +export type { + TerminalStoreType, + TerminalApi, + Terminal, + TerminalTab, + TerminalApiQuery, + WebSocketApiState, + TerminalEvents, + TerminalMessage, + TerminalChannels, +}; +export const terminalStore = Object.assign(asLegacyGlobalObjectForExtensionApi(terminalStoreInjectable), { + sendCommand: asLegacyGlobalFunctionForExtensionApi(sendCommandInjectable), }); -export const logTabStore = asLegacyGlobalObjectForExtensionApiWithModifications(logTabStoreInjectable, { - createPodTab: () => asLegacyGlobalFunctionForExtensionApi(createPodLogsTabInjectable), - createWorkloadTab: () => asLegacyGlobalFunctionForExtensionApi(createWorkloadLogsTabInjectable), - renameTab: () => (tabId: string): void => { + +export const TerminalStore = { + getInstance() { + return terminalStore; + }, + createInstance() { + return terminalStore; + }, + resetInstance() { + console.warn("TerminalStore.resetInstance() does nothing"); + }, +}; + +export type { LogTabStore, LogTabData, LogTabOwnerRef }; +export const logTabStore = Object.assign(asLegacyGlobalObjectForExtensionApi(logTabStoreInjectable), { + createPodTab: asLegacyGlobalFunctionForExtensionApi(createPodLogsTabInjectable), + createWorkloadTab: asLegacyGlobalFunctionForExtensionApi(createWorkloadLogsTabInjectable), + renameTab: (tabId: string): void => { const renameTab = asLegacyGlobalFunctionForExtensionApi(renameTabInjectable); const tabData = logTabStore.getData(tabId); const pod = podsStore.getById(tabData.selectedPodId); renameTab(tabId, `Pod ${pod.getName()}`); }, - tabs: () => undefined, + tabs: undefined, }); - -export class TerminalStore { - static getInstance() { - return terminalStore; - } - static createInstance() { - return terminalStore; - } - static resetInstance() { - console.warn("TerminalStore.resetInstance() does nothing"); - } -} diff --git a/src/extensions/renderer-api/k8s-api.ts b/src/extensions/renderer-api/k8s-api.ts index 1f3829f0cc..54b1dc59d7 100644 --- a/src/extensions/renderer-api/k8s-api.ts +++ b/src/extensions/renderer-api/k8s-api.ts @@ -12,80 +12,88 @@ export function isAllowedResource(resource: KubeResource | KubeResource[]) { const resources = castArray(resource); - return resources.every(x => _isAllowedResource(x)); + return resources.every(_isAllowedResource); } -export { ResourceStack } from "../../common/k8s/resource-stack"; -export { apiManager } from "../../common/k8s-api/api-manager"; -export { KubeObjectStore } from "../../common/k8s-api/kube-object.store"; -export { KubeApi, forCluster, forRemoteCluster } from "../../common/k8s-api/kube-api"; -export { KubeObject, KubeStatus } from "../../common/k8s-api/kube-object"; -export { Pod, podsApi, PodsApi } from "../../common/k8s-api/endpoints"; -export { Node, nodesApi, NodesApi } from "../../common/k8s-api/endpoints"; -export { Deployment, deploymentApi, DeploymentApi } from "../../common/k8s-api/endpoints"; -export { DaemonSet, daemonSetApi } from "../../common/k8s-api/endpoints"; -export { StatefulSet, statefulSetApi } from "../../common/k8s-api/endpoints"; -export { Job, jobApi } from "../../common/k8s-api/endpoints"; -export { CronJob, cronJobApi } from "../../common/k8s-api/endpoints"; -export { ConfigMap, configMapApi } from "../../common/k8s-api/endpoints"; -export { Secret, secretsApi } from "../../common/k8s-api/endpoints"; -export { ReplicaSet, replicaSetApi } from "../../common/k8s-api/endpoints"; -export { ResourceQuota, resourceQuotaApi } from "../../common/k8s-api/endpoints"; -export { LimitRange, limitRangeApi } from "../../common/k8s-api/endpoints"; -export { HorizontalPodAutoscaler, hpaApi } from "../../common/k8s-api/endpoints"; -export { PodDisruptionBudget, pdbApi } from "../../common/k8s-api/endpoints"; -export { Service, serviceApi } from "../../common/k8s-api/endpoints"; -export { Endpoint, endpointApi } from "../../common/k8s-api/endpoints"; -export { Ingress, ingressApi, IngressApi } from "../../common/k8s-api/endpoints"; -export { NetworkPolicy, networkPolicyApi } from "../../common/k8s-api/endpoints"; -export { PersistentVolume, persistentVolumeApi } from "../../common/k8s-api/endpoints"; -export { PersistentVolumeClaim, pvcApi, PersistentVolumeClaimsApi } from "../../common/k8s-api/endpoints"; -export { StorageClass, storageClassApi } from "../../common/k8s-api/endpoints"; -export { Namespace, namespacesApi } from "../../common/k8s-api/endpoints"; -export { KubeEvent, eventApi } from "../../common/k8s-api/endpoints"; -export { ServiceAccount, serviceAccountsApi } from "../../common/k8s-api/endpoints"; -export { Role, roleApi } from "../../common/k8s-api/endpoints"; -export { RoleBinding, roleBindingApi } from "../../common/k8s-api/endpoints"; -export { ClusterRole, clusterRoleApi } from "../../common/k8s-api/endpoints"; -export { ClusterRoleBinding, clusterRoleBindingApi } from "../../common/k8s-api/endpoints"; -export { CustomResourceDefinition, crdApi } from "../../common/k8s-api/endpoints"; -export { KubeObjectStatusLevel } from "./kube-object-status"; -export { KubeJsonApi } from "../../common/k8s-api/kube-json-api"; +export * from "../common-k8s-api"; -// types -export type { ILocalKubeApiConfig, IRemoteKubeApiConfig, IKubeApiCluster } from "../../common/k8s-api/kube-api"; -export type { IPodContainer, IPodContainerStatus } from "../../common/k8s-api/endpoints"; -export type { ISecretRef } from "../../common/k8s-api/endpoints"; -export type { KubeObjectStatus } from "./kube-object-status"; -export type { KubeObjectMetadata, KubeStatusData } from "../../common/k8s-api/kube-object"; -export type { KubeObjectStoreLoadAllParams, KubeObjectStoreLoadingParams, KubeObjectStoreSubscribeParams } from "../../common/k8s-api/kube-object.store"; +export type { + KubeResource, +} from "../../common/rbac"; +export type { + IKubeObjectRef, +} from "../../common/k8s-api/kube-api-parse"; +export { + apiManager, +} from "../../common/k8s-api/api-manager"; +export type { + ApiManager, +} from "../../common/k8s-api/api-manager"; +export { + clusterRoleApi, + clusterRoleBindingApi, + configMapApi, + crdApi, + cronJobApi, + daemonSetApi, + deploymentApi, + endpointApi, + eventApi, + hpaApi, + ingressApi, + jobApi, + limitRangeApi, + namespacesApi, + networkPolicyApi, + nodesApi, + pdbApi, + persistentVolumeApi, + podsApi, + pvcApi, + replicaSetApi, + resourceQuotaApi, + roleApi, + roleBindingApi, + secretsApi, + serviceAccountsApi, + serviceApi, + statefulSetApi, + storageClassApi, +} from "../../common/k8s-api/endpoints"; // stores -export type { EventStore } from "../../renderer/components/+events/event.store"; -export type { PodsStore } from "../../renderer/components/+workloads-pods/pods.store"; -export type { NodesStore } from "../../renderer/components/+nodes/nodes.store"; -export type { DeploymentStore } from "../../renderer/components/+workloads-deployments/deployments.store"; -export type { DaemonSetStore } from "../../renderer/components/+workloads-daemonsets/daemonsets.store"; -export type { StatefulSetStore } from "../../renderer/components/+workloads-statefulsets/statefulset.store"; -export type { JobStore } from "../../renderer/components/+workloads-jobs/job.store"; -export type { CronJobStore } from "../../renderer/components/+workloads-cronjobs/cronjob.store"; +export type { ClusterRoleBindingsStore } from "../../renderer/components/+user-management/+cluster-role-bindings/store"; +export type { ClusterRolesStore } from "../../renderer/components/+user-management/+cluster-roles/store"; export type { ConfigMapsStore } from "../../renderer/components/+config-maps/config-maps.store"; -export type { SecretsStore } from "../../renderer/components/+config-secrets/secrets.store"; +export type { CRDResourceStore } from "../../renderer/components/+custom-resources/crd-resource.store"; +export type { CRDStore } from "../../renderer/components/+custom-resources/crd.store"; +export type { CronJobStore } from "../../renderer/components/+workloads-cronjobs/cronjob.store"; +export type { DaemonSetStore } from "../../renderer/components/+workloads-daemonsets/daemonsets.store"; +export type { DeploymentStore } from "../../renderer/components/+workloads-deployments/deployments.store"; +export type { EndpointStore } from "../../renderer/components/+network-endpoints/endpoints.store"; +export type { EventStore } from "../../renderer/components/+events/event.store"; +export type { HPAStore } from "../../renderer/components/+config-autoscalers/hpa.store"; +export type { IngressStore } from "../../renderer/components/+network-ingresses/ingress.store"; +export type { JobStore } from "../../renderer/components/+workloads-jobs/job.store"; +export type { LimitRangesStore } from "../../renderer/components/+config-limit-ranges/limit-ranges.store"; +export type { NamespaceStore } from "../../renderer/components/+namespaces/namespace-store/namespace.store"; +export type { NetworkPolicyStore } from "../../renderer/components/+network-policies/network-policy.store"; +export type { NodesStore } from "../../renderer/components/+nodes/nodes.store"; +export type { PersistentVolumesStore } from "../../renderer/components/+storage-volumes/volumes.store"; +export type { PodDisruptionBudgetsStore } from "../../renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.store"; +export type { PodsStore } from "../../renderer/components/+workloads-pods/pods.store"; export type { ReplicaSetStore } from "../../renderer/components/+workloads-replicasets/replicasets.store"; export type { ResourceQuotasStore } from "../../renderer/components/+config-resource-quotas/resource-quotas.store"; -export type { LimitRangesStore } from "../../renderer/components/+config-limit-ranges/limit-ranges.store"; -export type { HPAStore } from "../../renderer/components/+config-autoscalers/hpa.store"; -export type { PodDisruptionBudgetsStore } from "../../renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.store"; -export type { ServiceStore } from "../../renderer/components/+network-services/services.store"; -export type { EndpointStore } from "../../renderer/components/+network-endpoints/endpoints.store"; -export type { IngressStore } from "../../renderer/components/+network-ingresses/ingress.store"; -export type { NetworkPolicyStore } from "../../renderer/components/+network-policies/network-policy.store"; -export type { PersistentVolumesStore } from "../../renderer/components/+storage-volumes/volumes.store"; -export type { VolumeClaimStore } from "../../renderer/components/+storage-volume-claims/volume-claim.store"; -export type { StorageClassStore } from "../../renderer/components/+storage-classes/storage-class.store"; -export type { NamespaceStore } from "../../renderer/components/+namespaces/namespace-store/namespace.store"; -export type { ServiceAccountsStore } from "../../renderer/components/+user-management/+service-accounts/store"; -export type { RolesStore } from "../../renderer/components/+user-management/+roles/store"; export type { RoleBindingsStore } from "../../renderer/components/+user-management/+role-bindings/store"; -export type { CRDStore } from "../../renderer/components/+custom-resources/crd.store"; -export type { CRDResourceStore } from "../../renderer/components/+custom-resources/crd-resource.store"; +export type { RolesStore } from "../../renderer/components/+user-management/+roles/store"; +export type { SecretsStore } from "../../renderer/components/+config-secrets/secrets.store"; +export type { ServiceAccountsStore } from "../../renderer/components/+user-management/+service-accounts/store"; +export type { ServiceStore } from "../../renderer/components/+network-services/services.store"; +export type { StatefulSetStore } from "../../renderer/components/+workloads-statefulsets/statefulset.store"; +export type { StorageClassStore } from "../../renderer/components/+storage-classes/storage-class.store"; +export type { VolumeClaimStore } from "../../renderer/components/+storage-volume-claims/volume-claim.store"; +export type { + KubeObjectStoreLoadAllParams, + KubeObjectStoreLoadingParams, + KubeObjectStoreSubscribeParams, +} from "../../common/k8s-api/kube-object.store"; diff --git a/src/extensions/renderer-api/kube-object-status.ts b/src/extensions/renderer-api/kube-object-status.ts deleted file mode 100644 index 200bf35b5d..0000000000 --- a/src/extensions/renderer-api/kube-object-status.ts +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -export interface KubeObjectStatus { - level: KubeObjectStatusLevel; - text: string; - timestamp?: string; -} - -export enum KubeObjectStatusLevel { - INFO = 1, - WARNING = 2, - CRITICAL = 3, -} diff --git a/src/extensions/renderer-api/theming.ts b/src/extensions/renderer-api/theming.ts index 76796ab7bd..36321a6d0c 100644 --- a/src/extensions/renderer-api/theming.ts +++ b/src/extensions/renderer-api/theming.ts @@ -5,6 +5,9 @@ import { ThemeStore } from "../../renderer/theme.store"; +export type { Theme } from "../../renderer/theme.store"; +export type { MonacoTheme, MonacoCustomTheme } from "../../renderer/components/monaco-editor"; + export function getActiveTheme() { return ThemeStore.getInstance().activeTheme; } diff --git a/src/main/menu/menu.ts b/src/main/menu/menu.ts index 18309cb71b..98034d32d8 100644 --- a/src/main/menu/menu.ts +++ b/src/main/menu/menu.ts @@ -15,6 +15,11 @@ import { preferencesURL, extensionsURL, addClusterURL, catalogURL, welcomeURL } import { checkForUpdates, isAutoUpdateEnabled } from "../app-updater"; import type { MenuRegistration } from "./menu-registration"; +/** + * The IDs of the menus that Lens uses. + * + * Note: `"mac"` is only valid on macOS + */ export type MenuTopId = "mac" | "file" | "edit" | "view" | "help"; interface MenuItemsOpts extends MenuItemConstructorOptions { diff --git a/src/renderer/api/terminal-api.ts b/src/renderer/api/terminal-api.ts index d1c842dbef..518513b27f 100644 --- a/src/renderer/api/terminal-api.ts +++ b/src/renderer/api/terminal-api.ts @@ -60,6 +60,9 @@ export interface TerminalEvents extends WebSocketEvents { } export class TerminalApi extends WebSocketApi { + /** + * @internal + */ protected size: { width: number; height: number }; @observable public isReady = false; @@ -144,6 +147,9 @@ export class TerminalApi extends WebSocketApi { } } + /** + * @internal + */ protected _onMessage({ data, ...evt }: MessageEvent): void { try { const message: TerminalMessage = deserialize(new Uint8Array(data)); @@ -169,6 +175,9 @@ export class TerminalApi extends WebSocketApi { } } + /** + * @internal + */ protected _onOpen(evt: Event) { // Client should send terminal size in special channel 4, // But this size will be changed by terminal.fit() @@ -176,11 +185,17 @@ export class TerminalApi extends WebSocketApi { super._onOpen(evt); } + /** + * @internal + */ protected _onClose(evt: CloseEvent) { super._onClose(evt); this.isReady = false; } + /** + * @internal + */ protected emitStatus(data: string, options: { color?: TerminalColor; showTime?: boolean } = {}) { const { color, showTime } = options; const time = showTime ? `${(new Date()).toLocaleString()} ` : ""; @@ -192,6 +207,9 @@ export class TerminalApi extends WebSocketApi { this.emit("data", `${time}${data}\r\n`); } + /** + * @internal + */ protected emitError(error: string) { this.emitStatus(error, { color: TerminalColor.RED, diff --git a/src/renderer/api/websocket-api.ts b/src/renderer/api/websocket-api.ts index 72ebc2d059..86ee75c4ba 100644 --- a/src/renderer/api/websocket-api.ts +++ b/src/renderer/api/websocket-api.ts @@ -8,6 +8,7 @@ import EventEmitter from "events"; import type TypedEventEmitter from "typed-emitter"; import type { Arguments } from "typed-emitter"; import { isDevelopment } from "../../common/vars"; +import type { Defaulted } from "../utils"; interface WebsocketApiParams { /** @@ -62,28 +63,29 @@ export interface WebSocketEvents { close: () => void; } -type Defaulted = Required> & Omit; +const defaultWebsocketApiParams = { + logging: isDevelopment, + reconnectDelay: 10, + flushOnOpen: true, + pingMessage: "PING", +}; export class WebSocketApi extends (EventEmitter as { new(): TypedEventEmitter }) { protected socket?: WebSocket | null; protected pendingCommands: (string | ArrayBufferLike | Blob | ArrayBufferView)[] = []; protected reconnectTimer?: any; protected pingTimer?: any; - protected params: Defaulted; + private params: Defaulted; @observable readyState = WebSocketApiState.PENDING; - private static defaultParams = { - logging: isDevelopment, - reconnectDelay: 10, - flushOnOpen: true, - pingMessage: "PING", - }; - constructor(params: WebsocketApiParams) { super(); makeObservable(this); - this.params = Object.assign({}, WebSocketApi.defaultParams, params); + this.params = { + ...defaultWebsocketApiParams, + ...params, + }; const { pingInterval } = this.params; if (pingInterval) { diff --git a/src/renderer/components/+catalog/catalog-add-button.tsx b/src/renderer/components/+catalog/catalog-add-button.tsx index 8d5daa6025..cb2f2f46f2 100644 --- a/src/renderer/components/+catalog/catalog-add-button.tsx +++ b/src/renderer/components/+catalog/catalog-add-button.tsx @@ -10,7 +10,7 @@ import { Icon } from "../icon"; import { observer } from "mobx-react"; import { observable, makeObservable, action } from "mobx"; import { boundMethod } from "../../../common/utils"; -import type { CatalogCategory, CatalogEntityAddMenuContext, CatalogEntityAddMenu } from "../../api/catalog-entity"; +import type { CatalogCategory, CatalogEntityAddMenu } from "../../api/catalog-entity"; import { EventEmitter } from "events"; import { navigate } from "../../navigation"; import { catalogCategoryRegistry } from "../../api/catalog-category-registry"; @@ -60,12 +60,11 @@ export class CatalogAddButton extends React.Component { updateCategoryItems = action((category: CatalogCategory) => { if (category instanceof EventEmitter) { const menuItems: CatalogEntityAddMenu[] = []; - const context: CatalogEntityAddMenuContext = { + + category.emit("catalogAddMenu", { navigate: (url: string) => navigate(url), menuItems, - }; - - category.emit("catalogAddMenu", context); + }); this.menuItems.set(category.getId(), menuItems); } }); @@ -86,10 +85,13 @@ export class CatalogAddButton extends React.Component { @boundMethod onButtonClick() { - const defaultAction = this.items.find(item => item.defaultAction)?.onClick; - const clickAction = defaultAction || (this.items.length === 1 ? this.items[0].onClick : null); + const defaultActions = this.items.filter(item => item.defaultAction); - clickAction?.(); + if (defaultActions.length === 1) { + defaultActions[0].onClick(); + } else if (defaultActions.length === 0 && this.items.length === 1) { + this.items[0].onClick(); + } } get items() { diff --git a/src/renderer/components/+catalog/custom-category-columns.ts b/src/renderer/components/+catalog/custom-category-columns.ts index 007ca75223..0abf6a3d9a 100644 --- a/src/renderer/components/+catalog/custom-category-columns.ts +++ b/src/renderer/components/+catalog/custom-category-columns.ts @@ -11,7 +11,14 @@ import type { TableCellProps } from "../table"; * These are the supported props for the title cell */ export interface TitleCellProps { + /** + * An optional className entry + */ className?: string; + + /** + * The actual title for the column + */ title: string; } diff --git a/src/renderer/components/+extensions/extensions.tsx b/src/renderer/components/+extensions/extensions.tsx index eb61cd2265..6d344d3693 100644 --- a/src/renderer/components/+extensions/extensions.tsx +++ b/src/renderer/components/+extensions/extensions.tsx @@ -45,6 +45,16 @@ interface Dependencies { extensionInstallationStateStore: ExtensionInstallationStateStore; } +interface Dependencies { + userExtensions: IComputedValue; + enableExtension: (id: LensExtensionId) => void; + disableExtension: (id: LensExtensionId) => void; + confirmUninstallExtension: (extension: InstalledExtension) => Promise; + installFromInput: (input: string) => Promise; + installFromSelectFileDialog: () => Promise; + installOnDrop: (files: File[]) => Promise; +} + @observer class NonInjectedExtensions extends React.Component { @observable installPath = ""; diff --git a/src/renderer/components/+namespaces/namespace-select.tsx b/src/renderer/components/+namespaces/namespace-select.tsx index dc51cbf0b9..6ac747d6b4 100644 --- a/src/renderer/components/+namespaces/namespace-select.tsx +++ b/src/renderer/components/+namespaces/namespace-select.tsx @@ -88,13 +88,9 @@ class NonInjectedNamespaceSelect extends React.Component( - NonInjectedNamespaceSelect, - - { - getProps: (di, props) => ({ - namespaceStore: di.inject(namespaceStoreInjectable), - ...props, - }), - }, -); +export const NamespaceSelect = withInjectables(NonInjectedNamespaceSelect, { + getProps: (di, props) => ({ + namespaceStore: di.inject(namespaceStoreInjectable), + ...props, + }), +}); diff --git a/src/renderer/components/+namespaces/namespace-store/namespace.store.ts b/src/renderer/components/+namespaces/namespace-store/namespace.store.ts index 1a01d9dddc..e32ea597d6 100644 --- a/src/renderer/components/+namespaces/namespace-store/namespace.store.ts +++ b/src/renderer/components/+namespaces/namespace-store/namespace.store.ts @@ -15,6 +15,9 @@ interface Dependencies { export class NamespaceStore extends KubeObjectStore { api = namespacesApi; + /** + * @internal + */ constructor(private dependencies: Dependencies) { super(); makeObservable(this); diff --git a/src/renderer/components/+network-policies/__tests__/network-policy-details.test.tsx b/src/renderer/components/+network-policies/__tests__/network-policy-details.test.tsx index 2724dfa68c..4b0c613d22 100644 --- a/src/renderer/components/+network-policies/__tests__/network-policy-details.test.tsx +++ b/src/renderer/components/+network-policies/__tests__/network-policy-details.test.tsx @@ -12,7 +12,12 @@ jest.mock("../../kube-object-meta"); describe("NetworkPolicyDetails", () => { it("should render w/o errors", () => { - const policy = new NetworkPolicy({ metadata: {} as any, spec: {}} as any); + const policy = new NetworkPolicy({ + metadata: {} as any, + kind: "NetworkPolicy", + apiVersion:"networking.k8s.io/v1", + spec: {}, + }); const { container } = render(); expect(container).toBeInstanceOf(HTMLElement); @@ -31,7 +36,12 @@ describe("NetworkPolicyDetails", () => { }], podSelector: {}, }; - const policy = new NetworkPolicy({ metadata: {} as any, spec } as any); + const policy = new NetworkPolicy({ + metadata: {} as any, + kind: "NetworkPolicy", + apiVersion: "networking.k8s.io/v1", + spec, + }); const { container } = render(); expect(await findByTestId(container, "egress-0")).toBeInstanceOf(HTMLElement); @@ -47,7 +57,12 @@ describe("NetworkPolicyDetails", () => { }], podSelector: {}, }; - const policy = new NetworkPolicy({ metadata: {} as any, spec } as any); + const policy = new NetworkPolicy({ + metadata: {} as any, + kind: "NetworkPolicy", + apiVersion: "networking.k8s.io/v1", + spec, + }); const { container } = render(); expect(container).toBeInstanceOf(HTMLElement); diff --git a/src/renderer/components/+user-management/+service-accounts/secret.tsx b/src/renderer/components/+user-management/+service-accounts/secret.tsx index 04f4f86899..5328686eab 100644 --- a/src/renderer/components/+user-management/+service-accounts/secret.tsx +++ b/src/renderer/components/+user-management/+service-accounts/secret.tsx @@ -21,6 +21,9 @@ interface State { } export class ServiceAccountsSecret extends React.Component { + /** + * @internal + */ public state: State = { showToken: false, }; diff --git a/src/renderer/components/+workloads-pods/pods.store.ts b/src/renderer/components/+workloads-pods/pods.store.ts index 04e5a1942c..7099bb7dce 100644 --- a/src/renderer/components/+workloads-pods/pods.store.ts +++ b/src/renderer/components/+workloads-pods/pods.store.ts @@ -9,7 +9,7 @@ import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; import { autoBind, cpuUnitsToNumber, unitsToBytes } from "../../utils"; import { Pod, PodMetrics, podMetricsApi, podsApi } from "../../../common/k8s-api/endpoints"; import { apiManager } from "../../../common/k8s-api/api-manager"; -import type { WorkloadKubeObject } from "../../../common/k8s-api/workload-kube-object"; +import type { KubeObject } from "../../../common/k8s-api/kube-object"; export class PodsStore extends KubeObjectStore { api = podsApi; @@ -31,7 +31,7 @@ export class PodsStore extends KubeObjectStore { } } - getPodsByOwner(workload: WorkloadKubeObject): Pod[] { + getPodsByOwner(workload: KubeObject): Pod[] { if (!workload) return []; return this.items.filter(pod => { diff --git a/src/renderer/components/chart/bar-chart.tsx b/src/renderer/components/chart/bar-chart.tsx index f53bed6e51..b7ffddb4e4 100644 --- a/src/renderer/components/chart/bar-chart.tsx +++ b/src/renderer/components/chart/bar-chart.tsx @@ -16,8 +16,16 @@ import { ThemeStore } from "../../theme.store"; import { NoMetrics } from "../resource-metrics/no-metrics"; export interface BarChartProps extends ChartProps { + /** + * The name of the chart + */ name?: string; - timeLabelStep?: number; // Minute labels appearance step + + /** + * The step between the minute labels + * @default 10 + */ + timeLabelStep?: number; } const defaultProps: Partial = { diff --git a/src/renderer/components/command-palette/registered-commands/commands.ts b/src/renderer/components/command-palette/registered-commands/commands.ts index d2f48257e3..59b3e4aed3 100644 --- a/src/renderer/components/command-palette/registered-commands/commands.ts +++ b/src/renderer/components/command-palette/registered-commands/commands.ts @@ -15,7 +15,9 @@ export interface CommandContext { export interface CommandActionNavigateOptions { /** * If `true` then the navigate will only navigate on the root frame and not - * within a cluster + * within a cluster's frame. + * + * If `false` then the navigation will only occur in the current frame * @default false */ forceRootFrame?: boolean; diff --git a/src/renderer/components/command-palette/registered-commands/internal-commands.injectable.tsx b/src/renderer/components/command-palette/registered-commands/internal-commands.injectable.tsx index e951c7a713..aab0861afe 100644 --- a/src/renderer/components/command-palette/registered-commands/internal-commands.injectable.tsx +++ b/src/renderer/components/command-palette/registered-commands/internal-commands.injectable.tsx @@ -15,7 +15,7 @@ import type { CommandContext, CommandRegistration } from "./commands"; import { getInjectable } from "@ogre-tools/injectable"; import commandOverlayInjectable from "../command-overlay.injectable"; import createTerminalTabInjectable from "../../dock/terminal/create-terminal-tab.injectable"; -import type { DockTabCreate } from "../../dock/dock/store"; +import type { BaseDockTabCreateOptions } from "../../dock/dock/store"; export function isKubernetesClusterActive(context: CommandContext): boolean { return context.entity?.kind === "KubernetesCluster"; @@ -24,7 +24,7 @@ export function isKubernetesClusterActive(context: CommandContext): boolean { interface Dependencies { openCommandDialog: (component: React.ReactElement) => void; getEntitySettingItems: (kind: string, apiVersion: string, source?: string) => RegisteredEntitySetting[]; - createTerminalTab: () => DockTabCreate; + createTerminalTab: () => BaseDockTabCreateOptions; } function getInternalCommands({ openCommandDialog, getEntitySettingItems, createTerminalTab }: Dependencies): CommandRegistration[] { diff --git a/src/renderer/components/dialog/dialog.tsx b/src/renderer/components/dialog/dialog.tsx index f40f1ee91d..3ed1f3945d 100644 --- a/src/renderer/components/dialog/dialog.tsx +++ b/src/renderer/components/dialog/dialog.tsx @@ -27,13 +27,12 @@ export interface DialogProps { animated?: boolean; "data-testid"?: string; } - -interface DialogState { +export interface DialogState { isOpen: boolean; } @observer -export class Dialog extends React.PureComponent { +export class Dialog extends React.Component { private contentElem: HTMLElement; ref = React.createRef(); @@ -48,6 +47,9 @@ export class Dialog extends React.PureComponent { pinned: false, }; + /** + * @internal + */ public state: DialogState = { isOpen: this.props.isOpen, }; diff --git a/src/renderer/components/dock/create-resource/create-resource-tab.injectable.ts b/src/renderer/components/dock/create-resource/create-resource-tab.injectable.ts index ab7d9b1de5..e946854ebb 100644 --- a/src/renderer/components/dock/create-resource/create-resource-tab.injectable.ts +++ b/src/renderer/components/dock/create-resource/create-resource-tab.injectable.ts @@ -4,7 +4,7 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import dockStoreInjectable from "../dock/store.injectable"; -import { DockTabCreateSpecific, TabKind } from "../dock/store"; +import { DockTabCreateOption, TabKind } from "../dock/store"; const createResourceTabInjectable = getInjectable({ id: "create-resource-tab", @@ -12,7 +12,7 @@ const createResourceTabInjectable = getInjectable({ instantiate: (di) => { const dockStore = di.inject(dockStoreInjectable); - return (tabParams: DockTabCreateSpecific = {}) => + return (tabParams: DockTabCreateOption = {}) => dockStore.createTab({ title: "Create resource", ...tabParams, diff --git a/src/renderer/components/dock/dock-tab-store/dock-tab.store.ts b/src/renderer/components/dock/dock-tab-store/dock-tab.store.ts index f3f74a4ec6..b45a1979d9 100644 --- a/src/renderer/components/dock/dock-tab-store/dock-tab.store.ts +++ b/src/renderer/components/dock/dock-tab-store/dock-tab.store.ts @@ -4,7 +4,7 @@ */ import { action, observable, reaction } from "mobx"; -import { autoBind, StorageHelper, toJS } from "../../../utils"; +import { autoBind, noop, StorageHelper, toJS } from "../../../utils"; import type { TabId } from "../dock/store"; export interface DockTabStoreOptions { @@ -19,35 +19,39 @@ interface DockTabStoreDependencies { } export class DockTabStore { + /** + * @internal + */ protected storage?: StorageHelper>; private data = observable.map(); - constructor(protected dependencies: DockTabStoreDependencies, protected options: DockTabStoreOptions) { + /** + * @internal + */ + protected dependencies: DockTabStoreDependencies; + + constructor(dependencies: DockTabStoreDependencies, { autoInit = true, storageKey }: DockTabStoreOptions) { autoBind(this); - this.options = { - autoInit: true, - ...this.options, - }; + this.dependencies = dependencies; - if (this.options.autoInit) { + this.init = storageKey + ? (() => { + this.storage = this.dependencies.createStorage(storageKey, {}); + + this.storage.whenReady.then(() => { + this.data.replace(this.storage.value); + reaction(() => this.toJSON(), data => this.storage.set(data)); + }); + }) + : noop; + + if (autoInit) { this.init(); } } - protected init() { - const { storageKey } = this.options; - - // auto-save to local-storage - if (storageKey) { - this.storage = this.dependencies.createStorage(storageKey, {}); - - this.storage.whenReady.then(() => { - this.data.replace(this.storage.value); - reaction(() => this.toJSON(), data => this.storage.set(data)); - }); - } - } + protected init: () => void; protected finalizeDataForSave(data: T): T { return data; diff --git a/src/renderer/components/dock/dock/create-dock-tab.injectable.ts b/src/renderer/components/dock/dock/create-dock-tab.injectable.ts index 84ee7c868e..7f40b948f9 100644 --- a/src/renderer/components/dock/dock/create-dock-tab.injectable.ts +++ b/src/renderer/components/dock/dock/create-dock-tab.injectable.ts @@ -4,7 +4,7 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import dockStoreInjectable from "./store.injectable"; -import type { DockTab, DockTabCreate } from "./store"; +import type { DockTab, BaseDockTabCreateOptions } from "./store"; const createDockTabInjectable = getInjectable({ id: "create-dock-tab", @@ -12,7 +12,7 @@ const createDockTabInjectable = getInjectable({ instantiate: (di) => { const dockStore = di.inject(dockStoreInjectable); - return (rawTabDesc: DockTabCreate, addNumber?: boolean): DockTab => + return (rawTabDesc: BaseDockTabCreateOptions, addNumber?: boolean): DockTab => dockStore.createTab(rawTabDesc, addNumber); }, }); diff --git a/src/renderer/components/dock/dock/store.ts b/src/renderer/components/dock/dock/store.ts index ed117e79c8..01b6fcbc17 100644 --- a/src/renderer/components/dock/dock/store.ts +++ b/src/renderer/components/dock/dock/store.ts @@ -24,12 +24,12 @@ export enum TabKind { * * All fields are required. */ -export type DockTab = Required; +export type DockTab = Required; /** * These are the arguments for creating a new Tab on the dock */ -export interface DockTabCreate { +export interface BaseDockTabCreateOptions { /** * The ID of the tab for reference purposes. */ @@ -63,7 +63,7 @@ export interface DockTabCreate { * That way users should get a type error if they try and specify a `kind` * themselves. */ -export type DockTabCreateSpecific = Omit; +export type DockTabCreateOption = Omit; export interface DockStorageState { height: number; @@ -288,7 +288,7 @@ export class DockStore implements DockStorageState { } } - createTab = action((rawTabDesc: DockTabCreate, addNumber = true): DockTab => { + createTab = action((rawTabDesc: BaseDockTabCreateOptions, addNumber = true): DockTab => { const { id = uuid.v4(), kind, diff --git a/src/renderer/components/dock/edit-resource/edit-resource-tab.injectable.ts b/src/renderer/components/dock/edit-resource/edit-resource-tab.injectable.ts index eeba197acc..17c6263ae5 100644 --- a/src/renderer/components/dock/edit-resource/edit-resource-tab.injectable.ts +++ b/src/renderer/components/dock/edit-resource/edit-resource-tab.injectable.ts @@ -6,7 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable"; import editResourceTabStoreInjectable from "./store.injectable"; import dockStoreInjectable from "../dock/store.injectable"; import type { KubeObject } from "../../../../common/k8s-api/kube-object"; -import { DockStore, DockTabCreateSpecific, TabId, TabKind } from "../dock/store"; +import { DockStore, DockTabCreateOption, TabId, TabKind } from "../dock/store"; import type { EditResourceTabStore } from "./store"; import { runInAction } from "mobx"; @@ -15,7 +15,7 @@ interface Dependencies { editResourceStore: EditResourceTabStore; } -const createEditResourceTab = ({ dockStore, editResourceStore }: Dependencies) => (object: KubeObject, tabParams: DockTabCreateSpecific = {}): TabId => { +const createEditResourceTab = ({ dockStore, editResourceStore }: Dependencies) => (object: KubeObject, tabParams: DockTabCreateOption = {}): TabId => { // use existing tab if already opened const tabId = editResourceStore.getTabIdByResource(object); diff --git a/src/renderer/components/dock/info-panel.tsx b/src/renderer/components/dock/info-panel.tsx index 28d68e1f39..dfce613ff5 100644 --- a/src/renderer/components/dock/info-panel.tsx +++ b/src/renderer/components/dock/info-panel.tsx @@ -17,12 +17,12 @@ import { Notifications } from "../notifications"; import { withInjectables } from "@ogre-tools/injectable-react"; import dockStoreInjectable from "./dock/store.injectable"; -export interface InfoPanelProps extends OptionalProps { +export interface InfoPanelProps extends InfoPanelOptionalProps { tabId: TabId; submit?: () => Promise; } -export interface OptionalProps { +export interface InfoPanelOptionalProps { className?: string; error?: string; controls?: ReactNode; @@ -42,7 +42,7 @@ interface Dependencies { @observer class NonInjectedInfoPanel extends Component { - static defaultProps: OptionalProps = { + static defaultProps: InfoPanelOptionalProps = { submitLabel: "Submit", submittingMessage: "Submitting..", showButtons: true, diff --git a/src/renderer/components/dock/install-chart/create-install-chart-tab.injectable.ts b/src/renderer/components/dock/install-chart/create-install-chart-tab.injectable.ts index 4be192504e..25611ef613 100644 --- a/src/renderer/components/dock/install-chart/create-install-chart-tab.injectable.ts +++ b/src/renderer/components/dock/install-chart/create-install-chart-tab.injectable.ts @@ -7,19 +7,19 @@ import installChartTabStoreInjectable from "./store.injectable"; import type { HelmChart } from "../../../../common/k8s-api/endpoints/helm-charts.api"; import { DockTab, - DockTabCreate, - DockTabCreateSpecific, + BaseDockTabCreateOptions, + DockTabCreateOption, TabKind, } from "../dock/store"; import type { InstallChartTabStore } from "./store"; import createDockTabInjectable from "../dock/create-dock-tab.injectable"; interface Dependencies { - createDockTab: (rawTab: DockTabCreate, addNumber: boolean) => DockTab; + createDockTab: (rawTab: BaseDockTabCreateOptions, addNumber: boolean) => DockTab; installChartStore: InstallChartTabStore; } -const createInstallChartTab = ({ createDockTab, installChartStore }: Dependencies) => (chart: HelmChart, tabParams: DockTabCreateSpecific = {}) => { +const createInstallChartTab = ({ createDockTab, installChartStore }: Dependencies) => (chart: HelmChart, tabParams: DockTabCreateOption = {}) => { const { name, repo, version } = chart; const tab = createDockTab( diff --git a/src/renderer/components/dock/logs/create-logs-tab.injectable.ts b/src/renderer/components/dock/logs/create-logs-tab.injectable.ts index e7c03bc271..c0d42cec45 100644 --- a/src/renderer/components/dock/logs/create-logs-tab.injectable.ts +++ b/src/renderer/components/dock/logs/create-logs-tab.injectable.ts @@ -3,7 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import { DockTabCreate, DockTab, TabKind, TabId } from "../dock/store"; +import { BaseDockTabCreateOptions, DockTab, TabKind, TabId } from "../dock/store"; import type { LogTabData } from "./tab-store"; import * as uuid from "uuid"; import { runInAction } from "mobx"; @@ -13,7 +13,7 @@ import setLogTabDataInjectable from "./set-log-tab-data.injectable"; export type CreateLogsTabData = Pick & Omit, "owner" | "selectedPodId" | "selectedContainer" | "namespace">; interface Dependencies { - createDockTab: (rawTabDesc: DockTabCreate, addNumber?: boolean) => DockTab; + createDockTab: (rawTabDesc: BaseDockTabCreateOptions, addNumber?: boolean) => DockTab; setLogTabData: (tabId: string, data: LogTabData) => void; } diff --git a/src/renderer/components/dock/logs/create-workload-logs-tab.injectable.ts b/src/renderer/components/dock/logs/create-workload-logs-tab.injectable.ts index 6b96ff5af7..2667e9d7e0 100644 --- a/src/renderer/components/dock/logs/create-workload-logs-tab.injectable.ts +++ b/src/renderer/components/dock/logs/create-workload-logs-tab.injectable.ts @@ -4,12 +4,12 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { podsStore } from "../../+workloads-pods/pods.store"; -import type { WorkloadKubeObject } from "../../../../common/k8s-api/workload-kube-object"; +import type { DaemonSet, Deployment, Job, Pod, ReplicaSet, StatefulSet } from "../../../../common/k8s-api/endpoints"; import type { TabId } from "../dock/store"; import createLogsTabInjectable, { CreateLogsTabData } from "./create-logs-tab.injectable"; export interface WorkloadLogsTabData { - workload: WorkloadKubeObject; + workload: DaemonSet | Deployment | Job | Pod | ReplicaSet | StatefulSet; } interface Dependencies { diff --git a/src/renderer/components/dock/logs/tab-store.ts b/src/renderer/components/dock/logs/tab-store.ts index 4c910e0733..255ff08884 100644 --- a/src/renderer/components/dock/logs/tab-store.ts +++ b/src/renderer/components/dock/logs/tab-store.ts @@ -61,7 +61,10 @@ interface Dependencies { } export class LogTabStore extends DockTabStore { - constructor(protected dependencies: Dependencies) { + /** + * @internal + */ + constructor(dependencies: Dependencies) { super(dependencies, { storageKey: "pod_logs", }); diff --git a/src/renderer/components/dock/terminal/create-terminal-tab.injectable.ts b/src/renderer/components/dock/terminal/create-terminal-tab.injectable.ts index 8ee4ab45b0..9a8ca3130b 100644 --- a/src/renderer/components/dock/terminal/create-terminal-tab.injectable.ts +++ b/src/renderer/components/dock/terminal/create-terminal-tab.injectable.ts @@ -4,7 +4,7 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import dockStoreInjectable from "../dock/store.injectable"; -import { DockTabCreateSpecific, TabKind } from "../dock/store"; +import { DockTabCreateOption, TabKind } from "../dock/store"; const createTerminalTabInjectable = getInjectable({ id: "create-terminal-tab", @@ -12,7 +12,7 @@ const createTerminalTabInjectable = getInjectable({ instantiate: (di) => { const dockStore = di.inject(dockStoreInjectable); - return (tabParams: DockTabCreateSpecific = {}) => + return (tabParams: DockTabCreateOption = {}) => dockStore.createTab({ title: `Terminal`, ...tabParams, diff --git a/src/renderer/components/dock/terminal/store.ts b/src/renderer/components/dock/terminal/store.ts index a54dccb820..fabf6c2ee8 100644 --- a/src/renderer/components/dock/terminal/store.ts +++ b/src/renderer/components/dock/terminal/store.ts @@ -9,7 +9,7 @@ import { TerminalApi } from "../../../api/terminal-api"; import type { DockTab, TabId } from "../dock/store"; import { WebSocketApiState } from "../../../api/websocket-api"; -export interface ITerminalTab extends DockTab { +export interface TerminalTab extends DockTab { node?: string; // activate node shell mode } @@ -21,11 +21,14 @@ export class TerminalStore { protected terminals = new Map(); protected connections = observable.map(); + /** + * @internal + */ constructor(private dependencies: Dependencies) { } @action - connect(tab: ITerminalTab) { + connect(tab: TerminalTab) { if (this.isConnected(tab.id)) { return; } diff --git a/src/renderer/components/dock/upgrade-chart/create-upgrade-chart-tab.injectable.ts b/src/renderer/components/dock/upgrade-chart/create-upgrade-chart-tab.injectable.ts index 0a50681a93..60b0b19b15 100644 --- a/src/renderer/components/dock/upgrade-chart/create-upgrade-chart-tab.injectable.ts +++ b/src/renderer/components/dock/upgrade-chart/create-upgrade-chart-tab.injectable.ts @@ -6,7 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable"; import upgradeChartTabStoreInjectable from "./store.injectable"; import dockStoreInjectable from "../dock/store.injectable"; import type { HelmRelease } from "../../../../common/k8s-api/endpoints/helm-releases.api"; -import { DockStore, DockTabCreateSpecific, TabId, TabKind } from "../dock/store"; +import { DockStore, DockTabCreateOption, TabId, TabKind } from "../dock/store"; import type { UpgradeChartTabStore } from "./store"; import { runInAction } from "mobx"; @@ -15,7 +15,7 @@ interface Dependencies { dockStore: DockStore; } -const createUpgradeChartTab = ({ upgradeChartStore, dockStore }: Dependencies) => (release: HelmRelease, tabParams: DockTabCreateSpecific = {}): TabId => { +const createUpgradeChartTab = ({ upgradeChartStore, dockStore }: Dependencies) => (release: HelmRelease, tabParams: DockTabCreateOption = {}): TabId => { const tabId = upgradeChartStore.getTabIdByRelease(release.getName()); if (tabId) { diff --git a/src/renderer/components/drawer/drawer-param-toggler.tsx b/src/renderer/components/drawer/drawer-param-toggler.tsx index be7d4984f0..708e98d9ec 100644 --- a/src/renderer/components/drawer/drawer-param-toggler.tsx +++ b/src/renderer/components/drawer/drawer-param-toggler.tsx @@ -12,11 +12,11 @@ export interface DrawerParamTogglerProps { label: string | number; } -interface State { +export interface DrawerParamTogglerState { open?: boolean; } -export class DrawerParamToggler extends React.Component { - public state: State = {}; +export class DrawerParamToggler extends React.Component { + public state: DrawerParamTogglerState = {}; toggle = () => { this.setState({ open: !this.state.open }); diff --git a/src/renderer/components/drawer/drawer.tsx b/src/renderer/components/drawer/drawer.tsx index 404667feb2..bc67451cfb 100644 --- a/src/renderer/components/drawer/drawer.tsx +++ b/src/renderer/components/drawer/drawer.tsx @@ -12,9 +12,7 @@ import { cssNames, noop, StorageHelper } from "../../utils"; import { Icon } from "../icon"; import { Animate, AnimateName } from "../animate"; import { ResizeDirection, ResizeGrowthDirection, ResizeSide, ResizingAnchor } from "../resizing-anchor"; -import drawerStorageInjectable, { - defaultDrawerWidth, -} from "./drawer-storage/drawer-storage.injectable"; +import drawerStorageInjectable, { defaultDrawerWidth } from "./drawer-storage/drawer-storage.injectable"; import { withInjectables } from "@ogre-tools/injectable-react"; import historyInjectable from "../../navigation/history.injectable"; import type { History } from "history"; @@ -47,7 +45,7 @@ const defaultProps: Partial = { onClose: noop, }; -interface State { +export interface DrawerState { isCopied: boolean; width: number; } @@ -64,7 +62,7 @@ interface Dependencies { drawerStorage: StorageHelper<{ width: number }>; } -class NonInjectedDrawer extends React.Component { +class NonInjectedDrawer extends React.Component { static defaultProps = defaultProps as object; private mouseDownTarget: HTMLElement; diff --git a/src/renderer/components/error-boundary/error-boundary.tsx b/src/renderer/components/error-boundary/error-boundary.tsx index e4bf9aa63b..277d519e05 100644 --- a/src/renderer/components/error-boundary/error-boundary.tsx +++ b/src/renderer/components/error-boundary/error-boundary.tsx @@ -21,6 +21,9 @@ interface State { @observer export class ErrorBoundary extends React.Component { + /** + * @internal + */ public state: State = {}; componentDidCatch(error: Error, errorInfo: ErrorInfo) { diff --git a/src/renderer/components/input/input.tsx b/src/renderer/components/input/input.tsx index 788bc142f0..59b6fade4b 100644 --- a/src/renderer/components/input/input.tsx +++ b/src/renderer/components/input/input.tsx @@ -21,10 +21,23 @@ const { conditionalValidators, ...InputValidators } = Validators; export { InputValidators }; export type { InputValidator }; -type InputElement = HTMLInputElement | HTMLTextAreaElement; -type InputElementProps = InputHTMLAttributes & TextareaHTMLAttributes & DOMAttributes; +/** + * Either an {@link HTMLInputElement} or an {@link HTMLTextAreaElement} + */ +export type InputElement = HTMLInputElement | HTMLTextAreaElement; +/** + * The builtin props for {@link InputElement} + */ +export type InputElementProps = InputHTMLAttributes & TextareaHTMLAttributes & DOMAttributes; + +/** + * The information provided for rendering a custom icon + */ export interface IconDataFnArg { + /** + * is `true` if the input is not the same as the original value + */ isDirty: boolean; } @@ -36,28 +49,135 @@ export interface IconDataFnArg { */ export type IconData = string | React.ReactNode | ((opt: IconDataFnArg) => React.ReactNode); +/** + * The props for {@link Input} + */ export type InputProps = Omit & { - theme?: "round-black" | "round"; + /** + * Determins which style of input to use + * + * @default "line" + */ + theme?: "round-black" | "round" | "line"; + + /** + * Any additional class names for this instance + */ className?: string; + + /** + * The current value. Must always be defined, or never. If not provided then + * this component will act as if it is not managed + */ value?: string; + + /** + * Should the input be trimmed of leading and trailing whitespace before + * being passed to the `onChange` or `onSubmit` handlers + * + * @default false + */ trim?: boolean; + + /** + * Should the input be selected when the input becomes focused. + * + * @default false + */ autoSelectOnFocus?: boolean; + + /** + * If specified and the component is not in managed mode then this will be + * used when not valid has been typed + */ defaultValue?: string; - multiLine?: boolean; // use text-area as input field - maxRows?: number; // when multiLine={true} define max rows size - dirty?: boolean; // show validation errors even if the field wasn't touched yet - showValidationLine?: boolean; // show animated validation line for async validators - showErrorsAsTooltip?: boolean | Omit; // show validation errors as a tooltip :hover (instead of block below) + + /** + * If `true` then the input field will be a `