PageRegistration & BaseRegistry refactoring (#1334)

Signed-off-by: Roman <ixrock@gmail.com>
Co-authored-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
RomanandJari Kolehmainen authored and GitHub committed 2020-11-12 16:29:02 +02:00
1 parent 6432b3bb9e
commit faa1cef307
43 files changed
+432 -369

No files matched your search

@@ -1,12 +1,12 @@
import type React from "react"
import { BaseRegistry } from "./base-registry";
import { BaseRegistry, BaseRegistryItem } from "./base-registry";
export interface AppPreferenceComponents {
Hint: React.ComponentType<any>;
Input: React.ComponentType<any>;
}
export interface AppPreferenceRegistration {
export interface AppPreferenceRegistration extends BaseRegistryItem {
title: string;
components: AppPreferenceComponents;
}
+53 -11
View File
@@ -1,23 +1,65 @@
// Base class for extensions-api registries
import { action, observable } from "mobx";
import { LensExtension } from "../lens-extension";
import { getRandId } from "../../common/utils";
export class BaseRegistry<T = any> {
protected items = observable<T>([], { deep: false });
export type BaseRegistryKey = LensExtension | null;
export type BaseRegistryItemId = string | symbol;
getItems(): T[] {
return this.items.toJS();
export interface BaseRegistryItem {
id?: BaseRegistryItemId; // uniq id, generated automatically when not provided
}
export interface BaseRegistryAddMeta {
key?: BaseRegistryKey;
merge?: boolean
}
export class BaseRegistry<T extends BaseRegistryItem = any> {
private items = observable.map<BaseRegistryKey, T[]>([], { deep: false });
getItems(): (T & { extension?: LensExtension | null })[] {
return Array.from(this.items).map(([ext, items]) => {
return items.map(item => ({
...item,
extension: ext,
}))
}).flat()
}
getById(itemId: BaseRegistryItemId, key?: BaseRegistryKey): T {
const byId = (item: BaseRegistryItem) => item.id === itemId;
if (key) {
return this.items.get(key)?.find(byId)
}
return this.getItems().find(byId);
}
@action
add(...items: T[]) {
this.items.push(...items);
return () => this.remove(...items);
add(items: T | T[], { key = null, merge = true }: BaseRegistryAddMeta = {}) {
const normalizedItems = (Array.isArray(items) ? items : [items]).map((item: T) => {
item.id = item.id || getRandId();
return item;
});
if (merge && this.items.has(key)) {
const newItems = new Set(this.items.get(key));
normalizedItems.forEach(item => newItems.add(item))
this.items.set(key, [...newItems]);
} else {
this.items.set(key, normalizedItems);
}
return () => this.remove(normalizedItems, key)
}
@action
remove(...items: T[]) {
items.forEach(item => {
this.items.remove(item); // works because of {deep: false};
})
remove(items: T[], key: BaseRegistryKey = null) {
const storedItems = this.items.get(key);
if (!storedItems) return;
const newItems = storedItems.filter(item => !items.includes(item)); // works because of {deep: false};
if (newItems.length > 0) {
this.items.set(key, newItems)
} else {
this.items.delete(key);
}
}
}
@@ -1,16 +1,18 @@
import { BaseRegistry } from "./base-registry";
import type React from "react"
import { BaseRegistry, BaseRegistryItem } from "./base-registry";
import { ClusterFeature } from "../cluster-feature";
export interface ClusterFeatureComponents {
Description: React.ComponentType<any>;
}
export interface ClusterFeatureRegistration {
export interface ClusterFeatureRegistration extends BaseRegistryItem {
title: string;
components: ClusterFeatureComponents
feature: ClusterFeature
}
export class ClusterFeatureRegistry extends BaseRegistry<ClusterFeatureRegistration> {}
export class ClusterFeatureRegistry extends BaseRegistry<ClusterFeatureRegistration> {
}
export const clusterFeatureRegistry = new ClusterFeatureRegistry()
+1
View File
@@ -1,6 +1,7 @@
// All registries managed by extensions api
export * from "./page-registry"
export * from "./page-menu-registry"
export * from "./menu-registry"
export * from "./app-preference-registry"
export * from "./status-bar-registry"
@@ -1,11 +1,11 @@
import React from "react"
import { BaseRegistry } from "./base-registry";
import { BaseRegistry, BaseRegistryItem } from "./base-registry";
export interface KubeObjectDetailComponents {
Details: React.ComponentType<any>;
}
export interface KubeObjectDetailRegistration {
export interface KubeObjectDetailRegistration extends BaseRegistryItem {
kind: string;
apiVersions: string[];
components: KubeObjectDetailComponents;
@@ -14,7 +14,7 @@ export interface KubeObjectDetailRegistration {
export class KubeObjectDetailRegistry extends BaseRegistry<KubeObjectDetailRegistration> {
getItemsForKind(kind: string, apiVersion: string) {
const items = this.items.filter((item) => {
const items = this.getItems().filter((item) => {
return item.kind === kind && item.apiVersions.includes(apiVersion)
}).map((item) => {
if (item.priority === null) {
@@ -1,11 +1,11 @@
import React from "react"
import { BaseRegistry } from "./base-registry";
import { BaseRegistry, BaseRegistryItem } from "./base-registry";
export interface KubeObjectMenuComponents {
MenuItem: React.ComponentType<any>;
}
export interface KubeObjectMenuRegistration {
export interface KubeObjectMenuRegistration extends BaseRegistryItem {
kind: string;
apiVersions: string[];
components: KubeObjectMenuComponents;
@@ -13,7 +13,7 @@ export interface KubeObjectMenuRegistration {
export class KubeObjectMenuRegistry extends BaseRegistry<KubeObjectMenuRegistration> {
getItemsForKind(kind: string, apiVersion: string) {
return this.items.filter((item) => {
return this.getItems().filter((item) => {
return item.kind === kind && item.apiVersions.includes(apiVersion)
})
}
@@ -1,7 +1,7 @@
import { KubeObject, KubeObjectStatus } from "../renderer-api/k8s-api";
import { BaseRegistry } from "./base-registry";
import { BaseRegistry, BaseRegistryItem } from "./base-registry";
export interface KubeObjectStatusRegistration {
export interface KubeObjectStatusRegistration extends BaseRegistryItem {
kind: string;
apiVersions: string[];
resolve: (object: KubeObject) => KubeObjectStatus;
@@ -9,7 +9,7 @@ export interface KubeObjectStatusRegistration {
export class KubeObjectStatusRegistry extends BaseRegistry<KubeObjectStatusRegistration> {
getItemsForKind(kind: string, apiVersion: string) {
return this.items.filter((item) => {
return this.getItems().filter((item) => {
return item.kind === kind && item.apiVersions.includes(apiVersion)
})
}
@@ -0,0 +1,34 @@
// Extensions-api -> Register page menu items
import type React from "react";
import type { IconProps } from "../../renderer/components/icon";
import { BaseRegistry, BaseRegistryItem, BaseRegistryItemId } from "./base-registry";
export interface PageMenuRegistration extends BaseRegistryItem {
id: BaseRegistryItemId; // required id from page-registry item to match with
url?: string; // when not provided initial extension's path used, e.g. "/extension/lens-extension-name"
title: React.ReactNode;
components: PageMenuComponents;
subMenus?: PageSubMenuRegistration[];
}
export interface PageSubMenuRegistration {
url: string;
title: React.ReactNode;
}
export interface PageMenuComponents {
Icon: React.ComponentType<IconProps>;
}
export class PageMenuRegistry<T extends PageMenuRegistration> extends BaseRegistry<T> {
getItems() {
return super.getItems().map(item => {
item.url = item.extension.getPageUrl(item.url)
return item
});
}
}
export const globalPageMenuRegistry = new PageMenuRegistry<Omit<PageMenuRegistration, "subMenus">>();
export const clusterPageMenuRegistry = new PageMenuRegistry();
+21 -19
View File
@@ -1,31 +1,33 @@
// Extensions-api -> Custom page registration
import type React from "react";
import type { RouteProps } from "react-router";
import type { IconProps } from "../../renderer/components/icon";
import type { IClassName } from "../../renderer/utils";
import type { TabRoute } from "../../renderer/components/layout/tab-layout";
import { BaseRegistry } from "./base-registry";
import React from "react";
import { BaseRegistry, BaseRegistryItem } from "./base-registry";
export interface PageRegistration extends RouteProps {
className?: IClassName;
url?: string; // initial url to be used for building menus and tabs, otherwise "path" applied by default
title?: React.ReactNode; // used in sidebar's & tabs-layout if provided
hideInMenu?: boolean; // hide element within app's navigation menu
subPages?: (PageRegistration & TabRoute)[];
export interface PageRegistration extends BaseRegistryItem {
routePath?: string; // additional (suffix) route path to base extension's route: "/extension/:name"
exact?: boolean; // route matching flag, see: https://reactrouter.com/web/api/NavLink/exact-bool
components: PageComponents;
subPages?: SubPageRegistration[];
}
export interface SubPageRegistration {
routePath: string; // required for sub-pages
exact?: boolean;
components: PageComponents;
}
export interface PageComponents {
Page: React.ComponentType<any>;
MenuIcon?: React.ComponentType<IconProps>;
}
export class GlobalPageRegistry extends BaseRegistry<PageRegistration> {
export class PageRegistry<T extends PageRegistration> extends BaseRegistry<T> {
getItems() {
return super.getItems().map(item => {
item.routePath = item.extension.getPageRoute(item.routePath)
return item
});
}
}
export class ClusterPageRegistry extends BaseRegistry<PageRegistration> {
}
export const globalPageRegistry = new GlobalPageRegistry();
export const clusterPageRegistry = new ClusterPageRegistry();
export const globalPageRegistry = new PageRegistry<Omit<PageRegistration, "subPages">>();
export const clusterPageRegistry = new PageRegistry();
@@ -1,9 +1,9 @@
// Extensions API -> Status bar customizations
import React from "react";
import { BaseRegistry } from "./base-registry";
import { BaseRegistry, BaseRegistryItem } from "./base-registry";
export interface StatusBarRegistration {
export interface StatusBarRegistration extends BaseRegistryItem {
item?: React.ReactNode;
}