mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Catalog & Hotbar - initial groundwork (#2418)
Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
1 parent
e18a041b13
commit
99a464c61d
109 files changed
+1604
-2612
No files matched your search
@@ -3,11 +3,12 @@ import path from "path";
|
||||
import hb from "handlebars";
|
||||
import { observable } from "mobx";
|
||||
import { ResourceApplier } from "../main/resource-applier";
|
||||
import { Cluster } from "../main/cluster";
|
||||
import { KubernetesCluster } from "./core-api/stores";
|
||||
import logger from "../main/logger";
|
||||
import { app } from "electron";
|
||||
import { requestMain } from "../common/ipc";
|
||||
import { clusterKubectlApplyAllHandler } from "../common/cluster-ipc";
|
||||
import { clusterStore } from "../common/cluster-store";
|
||||
|
||||
export interface ClusterFeatureStatus {
|
||||
/** feature's current version, as set by the implementation */
|
||||
@@ -44,7 +45,7 @@ export abstract class ClusterFeature {
|
||||
*
|
||||
* @param cluster the cluster that the feature is to be installed on
|
||||
*/
|
||||
abstract async install(cluster: Cluster): Promise<void>;
|
||||
abstract install(cluster: KubernetesCluster): Promise<void>;
|
||||
|
||||
/**
|
||||
* to be implemented in the derived class, this method is typically called by Lens when a user has indicated that this feature is to be upgraded. The implementation
|
||||
@@ -52,7 +53,7 @@ export abstract class ClusterFeature {
|
||||
*
|
||||
* @param cluster the cluster that the feature is to be upgraded on
|
||||
*/
|
||||
abstract async upgrade(cluster: Cluster): Promise<void>;
|
||||
abstract upgrade(cluster: KubernetesCluster): Promise<void>;
|
||||
|
||||
/**
|
||||
* to be implemented in the derived class, this method is typically called by Lens when a user has indicated that this feature is to be uninstalled. The implementation
|
||||
@@ -60,7 +61,7 @@ export abstract class ClusterFeature {
|
||||
*
|
||||
* @param cluster the cluster that the feature is to be uninstalled from
|
||||
*/
|
||||
abstract async uninstall(cluster: Cluster): Promise<void>;
|
||||
abstract uninstall(cluster: KubernetesCluster): Promise<void>;
|
||||
|
||||
/**
|
||||
* to be implemented in the derived class, this method is called periodically by Lens to determine details about the feature's current status. The implementation
|
||||
@@ -72,7 +73,7 @@ export abstract class ClusterFeature {
|
||||
*
|
||||
* @return a promise, resolved with the updated ClusterFeatureStatus
|
||||
*/
|
||||
abstract async updateStatus(cluster: Cluster): Promise<ClusterFeatureStatus>;
|
||||
abstract updateStatus(cluster: KubernetesCluster): Promise<ClusterFeatureStatus>;
|
||||
|
||||
/**
|
||||
* this is a helper method that conveniently applies kubernetes resources to the cluster.
|
||||
@@ -82,9 +83,15 @@ export abstract class ClusterFeature {
|
||||
* files are templated, the template parameters are filled using the templateContext field (See renderTemplate() method). Finally the resources are applied to the
|
||||
* cluster. As a string[] type resourceSpec is treated as an array of fully formed (not templated) kubernetes resources that are applied to the cluster
|
||||
*/
|
||||
protected async applyResources(cluster: Cluster, resourceSpec: string | string[]) {
|
||||
protected async applyResources(cluster: KubernetesCluster, resourceSpec: string | string[]) {
|
||||
let resources: string[];
|
||||
|
||||
const clusterModel = clusterStore.getById(cluster.metadata.uid);
|
||||
|
||||
if (!clusterModel) {
|
||||
throw new Error(`cluster not found`);
|
||||
}
|
||||
|
||||
if ( typeof resourceSpec === "string" ) {
|
||||
resources = this.renderTemplates(resourceSpec);
|
||||
} else {
|
||||
@@ -92,9 +99,9 @@ export abstract class ClusterFeature {
|
||||
}
|
||||
|
||||
if (app) {
|
||||
await new ResourceApplier(cluster).kubectlApplyAll(resources);
|
||||
await new ResourceApplier(clusterModel).kubectlApplyAll(resources);
|
||||
} else {
|
||||
await requestMain(clusterKubectlApplyAllHandler, cluster.id, resources);
|
||||
await requestMain(clusterKubectlApplyAllHandler, cluster.metadata.uid, resources);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
import { computed } from "mobx";
|
||||
import { CatalogEntity } from "../../common/catalog-entity";
|
||||
import { catalogEntityRegistry as registry } from "../../common/catalog-entity-registry";
|
||||
|
||||
export class CatalogEntityRegistry {
|
||||
@computed getItemsForApiKind<T extends CatalogEntity>(apiVersion: string, kind: string): T[] {
|
||||
return registry.getItemsForApiKind<T>(apiVersion, kind);
|
||||
}
|
||||
}
|
||||
|
||||
export const catalogEntities = new CatalogEntityRegistry();
|
||||
@@ -1,8 +1,4 @@
|
||||
export { ExtensionStore } from "../extension-store";
|
||||
|
||||
export { clusterStore, Cluster, ClusterStore } from "../stores/cluster-store";
|
||||
export type { ClusterModel, ClusterId } from "../stores/cluster-store";
|
||||
|
||||
export { workspaceStore, Workspace, WorkspaceStore } from "../stores/workspace-store";
|
||||
export type { WorkspaceId, WorkspaceModel } from "../stores/workspace-store";
|
||||
|
||||
export { KubernetesCluster, KubernetesClusterCategory } from "../../common/catalog-entities/kubernetes-cluster";
|
||||
export { catalogCategoryRegistry as catalogCategories } from "../../common/catalog-category-registry";
|
||||
export { catalogEntities } from "./catalog";
|
||||
@@ -213,7 +213,6 @@ export class ExtensionLoader {
|
||||
registries.globalPageRegistry.add(extension.globalPages, extension),
|
||||
registries.globalPageMenuRegistry.add(extension.globalPageMenus, extension),
|
||||
registries.appPreferenceRegistry.add(extension.appPreferences),
|
||||
registries.clusterFeatureRegistry.add(extension.clusterFeatures),
|
||||
registries.statusBarRegistry.add(extension.statusBarItems),
|
||||
registries.commandRegistry.add(extension.commands),
|
||||
];
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * from "../../common/catalog-entity";
|
||||
@@ -1 +1,2 @@
|
||||
export * from "./registrations";
|
||||
export * from "./catalog";
|
||||
@@ -1,5 +1,4 @@
|
||||
export type { AppPreferenceRegistration, AppPreferenceComponents } from "../registries/app-preference-registry";
|
||||
export type { ClusterFeatureRegistration, ClusterFeatureComponents } from "../registries/cluster-feature-registry";
|
||||
export type { KubeObjectDetailRegistration, KubeObjectDetailComponents } from "../registries/kube-object-detail-registry";
|
||||
export type { KubeObjectMenuRegistration, KubeObjectMenuComponents } from "../registries/kube-object-menu-registry";
|
||||
export type { KubeObjectStatusRegistration } from "../registries/kube-object-status-registry";
|
||||
|
||||
@@ -2,6 +2,8 @@ import type { MenuRegistration } from "./registries/menu-registry";
|
||||
import { LensExtension } from "./lens-extension";
|
||||
import { WindowManager } from "../main/window-manager";
|
||||
import { getExtensionPageUrl } from "./registries/page-registry";
|
||||
import { catalogEntityRegistry } from "../common/catalog-entity-registry";
|
||||
import { CatalogEntity } from "../common/catalog-entity";
|
||||
|
||||
export class LensMainExtension extends LensExtension {
|
||||
appMenus: MenuRegistration[] = [];
|
||||
@@ -16,4 +18,12 @@ export class LensMainExtension extends LensExtension {
|
||||
|
||||
await windowManager.navigate(pageUrl, frameId);
|
||||
}
|
||||
|
||||
addCatalogSource(id: string, source: CatalogEntity[]) {
|
||||
catalogEntityRegistry.addSource(`${this.name}:${id}`, source);
|
||||
}
|
||||
|
||||
removeCatalogSource(id: string) {
|
||||
catalogEntityRegistry.removeSource(`${this.name}:${id}`);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { AppPreferenceRegistration, ClusterFeatureRegistration, ClusterPageMenuRegistration, KubeObjectDetailRegistration, KubeObjectMenuRegistration, KubeObjectStatusRegistration, PageMenuRegistration, PageRegistration, StatusBarRegistration, } from "./registries";
|
||||
import type { AppPreferenceRegistration, ClusterPageMenuRegistration, KubeObjectDetailRegistration, KubeObjectMenuRegistration, KubeObjectStatusRegistration, PageMenuRegistration, PageRegistration, StatusBarRegistration, } from "./registries";
|
||||
import type { Cluster } from "../main/cluster";
|
||||
import { LensExtension } from "./lens-extension";
|
||||
import { getExtensionPageUrl } from "./registries/page-registry";
|
||||
@@ -11,7 +11,6 @@ export class LensRendererExtension extends LensExtension {
|
||||
clusterPageMenus: ClusterPageMenuRegistration[] = [];
|
||||
kubeObjectStatusTexts: KubeObjectStatusRegistration[] = [];
|
||||
appPreferences: AppPreferenceRegistration[] = [];
|
||||
clusterFeatures: ClusterFeatureRegistration[] = [];
|
||||
statusBarItems: StatusBarRegistration[] = [];
|
||||
kubeObjectDetailItems: KubeObjectDetailRegistration[] = [];
|
||||
kubeObjectMenuItems: KubeObjectMenuRegistration[] = [];
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import type React from "react";
|
||||
import { BaseRegistry } from "./base-registry";
|
||||
import { ClusterFeature } from "../cluster-feature";
|
||||
|
||||
export interface ClusterFeatureComponents {
|
||||
Description: React.ComponentType<any>;
|
||||
}
|
||||
|
||||
export interface ClusterFeatureRegistration {
|
||||
title: string;
|
||||
components: ClusterFeatureComponents
|
||||
feature: ClusterFeature
|
||||
}
|
||||
|
||||
export class ClusterFeatureRegistry extends BaseRegistry<ClusterFeatureRegistration> {
|
||||
}
|
||||
|
||||
export const clusterFeatureRegistry = new ClusterFeatureRegistry();
|
||||
@@ -1,25 +1,25 @@
|
||||
// Extensions API -> Commands
|
||||
|
||||
import type { Cluster } from "../../main/cluster";
|
||||
import type { Workspace } from "../../common/workspace-store";
|
||||
import { BaseRegistry } from "./base-registry";
|
||||
import { action } from "mobx";
|
||||
import { action, observable } from "mobx";
|
||||
import { LensExtension } from "../lens-extension";
|
||||
import { CatalogEntity } from "../../common/catalog-entity";
|
||||
|
||||
export type CommandContext = {
|
||||
cluster?: Cluster;
|
||||
workspace?: Workspace;
|
||||
entity?: CatalogEntity;
|
||||
};
|
||||
|
||||
export interface CommandRegistration {
|
||||
id: string;
|
||||
title: string;
|
||||
scope: "cluster" | "global";
|
||||
scope: "entity" | "global";
|
||||
action: (context: CommandContext) => void;
|
||||
isActive?: (context: CommandContext) => boolean;
|
||||
}
|
||||
|
||||
export class CommandRegistry extends BaseRegistry<CommandRegistration> {
|
||||
@observable activeEntity: CatalogEntity;
|
||||
|
||||
@action
|
||||
add(items: CommandRegistration | CommandRegistration[], extension?: LensExtension) {
|
||||
const itemArray = [items].flat();
|
||||
|
||||
@@ -7,6 +7,5 @@ export * from "./app-preference-registry";
|
||||
export * from "./status-bar-registry";
|
||||
export * from "./kube-object-detail-registry";
|
||||
export * from "./kube-object-menu-registry";
|
||||
export * from "./cluster-feature-registry";
|
||||
export * from "./kube-object-status-registry";
|
||||
export * from "./command-registry";
|
||||
@@ -1,124 +0,0 @@
|
||||
import { clusterStore as internalClusterStore, ClusterId } from "../../common/cluster-store";
|
||||
import type { ClusterModel } from "../../common/cluster-store";
|
||||
import { Cluster } from "../../main/cluster";
|
||||
import { Singleton } from "../core-api/utils";
|
||||
import { ObservableMap } from "mobx";
|
||||
|
||||
export { Cluster } from "../../main/cluster";
|
||||
export type { ClusterModel, ClusterId } from "../../common/cluster-store";
|
||||
|
||||
/**
|
||||
* Store for all added clusters
|
||||
*
|
||||
* @beta
|
||||
*/
|
||||
export class ClusterStore extends Singleton {
|
||||
|
||||
/**
|
||||
* Active cluster id
|
||||
*/
|
||||
get activeClusterId(): string {
|
||||
return internalClusterStore.activeCluster;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set active cluster id
|
||||
*/
|
||||
set activeClusterId(id : ClusterId) {
|
||||
internalClusterStore.setActive(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map of all clusters
|
||||
*/
|
||||
get clusters(): ObservableMap<string, Cluster> {
|
||||
return internalClusterStore.clusters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get active cluster (a cluster which is currently visible)
|
||||
*/
|
||||
get activeCluster(): Cluster | null {
|
||||
return internalClusterStore.active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Array of all clusters
|
||||
*/
|
||||
get clustersList(): Cluster[] {
|
||||
return internalClusterStore.clustersList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Array of all enabled clusters
|
||||
*/
|
||||
get enabledClustersList(): Cluster[] {
|
||||
return internalClusterStore.enabledClustersList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Array of all clusters that have active connection to a Kubernetes cluster
|
||||
*/
|
||||
get connectedClustersList(): Cluster[] {
|
||||
return internalClusterStore.connectedClustersList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cluster object by cluster id
|
||||
* @param id cluster id
|
||||
*/
|
||||
getById(id: ClusterId): Cluster {
|
||||
return internalClusterStore.getById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all clusters belonging to a workspace
|
||||
* @param workspaceId workspace id
|
||||
*/
|
||||
getByWorkspaceId(workspaceId: string): Cluster[] {
|
||||
return internalClusterStore.getByWorkspaceId(workspaceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add clusters to store
|
||||
* @param models list of cluster models
|
||||
*/
|
||||
addClusters(...models: ClusterModel[]): Cluster[] {
|
||||
return internalClusterStore.addClusters(...models);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a cluster to store
|
||||
* @param model cluster
|
||||
*/
|
||||
addCluster(model: ClusterModel | Cluster): Cluster {
|
||||
return internalClusterStore.addCluster(model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a cluster from store
|
||||
* @param model cluster
|
||||
*/
|
||||
async removeCluster(model: ClusterModel) {
|
||||
return internalClusterStore.removeById(model.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a cluster from store by id
|
||||
* @param clusterId cluster id
|
||||
*/
|
||||
async removeById(clusterId: ClusterId) {
|
||||
return internalClusterStore.removeById(clusterId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all clusters belonging to a workspaces
|
||||
* @param workspaceId workspace id
|
||||
*/
|
||||
removeByWorkspaceId(workspaceId: string) {
|
||||
return internalClusterStore.removeByWorkspaceId(workspaceId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const clusterStore = ClusterStore.getInstance<ClusterStore>();
|
||||
@@ -1,118 +0,0 @@
|
||||
import { Singleton } from "../core-api/utils";
|
||||
import { workspaceStore as internalWorkspaceStore, WorkspaceStore as InternalWorkspaceStore, Workspace, WorkspaceId } from "../../common/workspace-store";
|
||||
import { ObservableMap } from "mobx";
|
||||
|
||||
export { Workspace } from "../../common/workspace-store";
|
||||
export type { WorkspaceId, WorkspaceModel } from "../../common/workspace-store";
|
||||
|
||||
/**
|
||||
* Stores all workspaces
|
||||
*
|
||||
* @beta
|
||||
*/
|
||||
export class WorkspaceStore extends Singleton {
|
||||
/**
|
||||
* Default workspace id, this workspace is always present
|
||||
*/
|
||||
static readonly defaultId: WorkspaceId = InternalWorkspaceStore.defaultId;
|
||||
|
||||
/**
|
||||
* Currently active workspace id
|
||||
*/
|
||||
get currentWorkspaceId(): string {
|
||||
return internalWorkspaceStore.currentWorkspaceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set active workspace id
|
||||
*/
|
||||
set currentWorkspaceId(id: string) {
|
||||
internalWorkspaceStore.currentWorkspaceId = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map of all workspaces
|
||||
*/
|
||||
get workspaces(): ObservableMap<string, Workspace> {
|
||||
return internalWorkspaceStore.workspaces;
|
||||
}
|
||||
|
||||
/**
|
||||
* Currently active workspace
|
||||
*/
|
||||
get currentWorkspace(): Workspace {
|
||||
return internalWorkspaceStore.currentWorkspace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Array of all workspaces
|
||||
*/
|
||||
get workspacesList(): Workspace[] {
|
||||
return internalWorkspaceStore.workspacesList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Array of all enabled (visible) workspaces
|
||||
*/
|
||||
get enabledWorkspacesList(): Workspace[] {
|
||||
return internalWorkspaceStore.enabledWorkspacesList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get workspace by id
|
||||
* @param id workspace id
|
||||
*/
|
||||
getById(id: WorkspaceId): Workspace {
|
||||
return internalWorkspaceStore.getById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get workspace by name
|
||||
* @param name workspace name
|
||||
*/
|
||||
getByName(name: string): Workspace {
|
||||
return internalWorkspaceStore.getByName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set active workspace
|
||||
* @param id workspace id
|
||||
*/
|
||||
setActive(id = WorkspaceStore.defaultId) {
|
||||
return internalWorkspaceStore.setActive(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a workspace to store
|
||||
* @param workspace workspace
|
||||
*/
|
||||
addWorkspace(workspace: Workspace) {
|
||||
return internalWorkspaceStore.addWorkspace(workspace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a workspace in store
|
||||
* @param workspace workspace
|
||||
*/
|
||||
updateWorkspace(workspace: Workspace) {
|
||||
return internalWorkspaceStore.updateWorkspace(workspace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove workspace from store
|
||||
* @param workspace workspace
|
||||
*/
|
||||
removeWorkspace(workspace: Workspace) {
|
||||
return internalWorkspaceStore.removeWorkspace(workspace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove workspace by id
|
||||
* @param id workspace
|
||||
*/
|
||||
removeWorkspaceById(id: WorkspaceId) {
|
||||
return internalWorkspaceStore.removeWorkspaceById(id);
|
||||
}
|
||||
}
|
||||
|
||||
export const workspaceStore = WorkspaceStore.getInstance<WorkspaceStore>();
|
||||
Reference in new issue
Block a user