mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
refactor cluster settings to pluggable entity settings
Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
1 parent
0533455ef0
commit
6df4ef696f
45 files changed
+328
-298
No files matched your search
@@ -49,7 +49,7 @@ export class KubernetesCluster implements CatalogEntity {
|
||||
{
|
||||
icon: "settings",
|
||||
title: "Settings",
|
||||
onClick: async () => context.navigate(`/cluster/${this.metadata.uid}/settings`)
|
||||
onClick: async () => context.navigate(`/entity/${this.metadata.uid}/settings`)
|
||||
},
|
||||
{
|
||||
icon: "delete",
|
||||
|
||||
@@ -16,6 +16,10 @@ export class CatalogEntityRegistry {
|
||||
return Array.from(this.sources.values()).flat();
|
||||
}
|
||||
|
||||
getById(id: string) {
|
||||
return this.items.find((entity) => entity.metadata.uid === id);
|
||||
}
|
||||
|
||||
getItemsForApiKind<T extends CatalogEntity>(apiVersion: string, kind: string): T[] {
|
||||
const items = this.items.filter((item) => item.apiVersion === apiVersion && item.kind === kind);
|
||||
|
||||
|
||||
@@ -51,11 +51,23 @@ export type CatalogEntityContextMenu = {
|
||||
}
|
||||
};
|
||||
|
||||
export type CatalogEntitySettingsMenu = {
|
||||
group?: string;
|
||||
title: string;
|
||||
components: {
|
||||
View: React.ComponentType<any>
|
||||
};
|
||||
};
|
||||
|
||||
export interface CatalogEntityContextMenuContext {
|
||||
navigate: (url: string) => void;
|
||||
menuItems: CatalogEntityContextMenu[];
|
||||
}
|
||||
|
||||
export interface CatalogEntitySettingsContext {
|
||||
menuItems: CatalogEntityContextMenu[];
|
||||
}
|
||||
|
||||
export interface CatalogEntityAddMenuContext {
|
||||
navigate: (url: string) => void;
|
||||
menuItems: CatalogEntityContextMenu[];
|
||||
@@ -77,4 +89,5 @@ export interface CatalogEntity extends CatalogEntityData {
|
||||
onRun: (context: CatalogEntityActionContext) => Promise<void>;
|
||||
onDetailsOpen: (context: CatalogEntityActionContext) => Promise<void>;
|
||||
onContextMenuOpen: (context: CatalogEntityContextMenuContext) => Promise<void>;
|
||||
onSettingsOpen?: (context: CatalogEntitySettingsContext) => Promise<void>;
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import { dumpConfigYaml } from "./kube-helpers";
|
||||
import { saveToAppFiles } from "./utils/saveToAppFiles";
|
||||
import { KubeConfig } from "@kubernetes/client-node";
|
||||
import { handleRequest, requestMain, subscribeToBroadcast, unsubscribeAllFromBroadcast } from "./ipc";
|
||||
import { ResourceType } from "../renderer/components/+cluster-settings/components/cluster-metrics-setting";
|
||||
import { ResourceType } from "../renderer/components/cluster-settings/components/cluster-metrics-setting";
|
||||
|
||||
export interface ClusterIconUpload {
|
||||
clusterId: string;
|
||||
|
||||
@@ -211,8 +211,8 @@ export class ExtensionLoader {
|
||||
this.autoInitExtensions(async (extension: LensRendererExtension) => {
|
||||
const removeItems = [
|
||||
registries.globalPageRegistry.add(extension.globalPages, extension),
|
||||
registries.globalPageMenuRegistry.add(extension.globalPageMenus, extension),
|
||||
registries.appPreferenceRegistry.add(extension.appPreferences),
|
||||
registries.entitySettingRegistry.add(extension.entitySettings),
|
||||
registries.statusBarRegistry.add(extension.statusBarItems),
|
||||
registries.commandRegistry.add(extension.commands),
|
||||
];
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { Cluster } from "../main/cluster";
|
||||
import { LensExtension } from "./lens-extension";
|
||||
import { getExtensionPageUrl } from "./registries/page-registry";
|
||||
import { CommandRegistration } from "./registries/command-registry";
|
||||
import { EntitySettingRegistration } from "./registries/entity-setting-registry";
|
||||
|
||||
export class LensRendererExtension extends LensExtension {
|
||||
globalPages: PageRegistration[] = [];
|
||||
@@ -11,6 +12,7 @@ export class LensRendererExtension extends LensExtension {
|
||||
clusterPageMenus: ClusterPageMenuRegistration[] = [];
|
||||
kubeObjectStatusTexts: KubeObjectStatusRegistration[] = [];
|
||||
appPreferences: AppPreferenceRegistration[] = [];
|
||||
entitySettings: EntitySettingRegistration[] = [];
|
||||
statusBarItems: StatusBarRegistration[] = [];
|
||||
kubeObjectDetailItems: KubeObjectDetailRegistration[] = [];
|
||||
kubeObjectMenuItems: KubeObjectMenuRegistration[] = [];
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import type React from "react";
|
||||
import { CatalogEntity } from "../../common/catalog-entity";
|
||||
import { BaseRegistry } from "./base-registry";
|
||||
|
||||
export interface EntitySettingViewProps {
|
||||
entity: CatalogEntity;
|
||||
}
|
||||
|
||||
export interface EntitySettingComponents {
|
||||
View: React.ComponentType<EntitySettingViewProps>;
|
||||
}
|
||||
|
||||
export interface EntitySettingRegistration {
|
||||
title: string;
|
||||
kind: string;
|
||||
apiVersions: string[];
|
||||
source?: string;
|
||||
id?: string;
|
||||
components: EntitySettingComponents;
|
||||
}
|
||||
|
||||
export interface RegisteredEntitySetting extends EntitySettingRegistration {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export class EntitySettingRegistry extends BaseRegistry<EntitySettingRegistration, RegisteredEntitySetting> {
|
||||
getRegisteredItem(item: EntitySettingRegistration): RegisteredEntitySetting {
|
||||
return {
|
||||
id: item.id || item.title.toLowerCase().replace(/[^0-9a-zA-Z]+/g, "-"),
|
||||
...item,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const entitySettingRegistry = new EntitySettingRegistry();
|
||||
@@ -9,3 +9,4 @@ export * from "./kube-object-detail-registry";
|
||||
export * from "./kube-object-menu-registry";
|
||||
export * from "./kube-object-status-registry";
|
||||
export * from "./command-registry";
|
||||
export * from "./entity-setting-registry";
|
||||
@@ -57,5 +57,4 @@ export class ClusterPageMenuRegistry extends PageMenuRegistry<ClusterPageMenuReg
|
||||
}
|
||||
}
|
||||
|
||||
export const globalPageMenuRegistry = new PageMenuRegistry();
|
||||
export const clusterPageMenuRegistry = new ClusterPageMenuRegistry();
|
||||
@@ -5,7 +5,6 @@ import { appName, isMac, isWindows, isTestEnv, docsUrl, supportUrl } from "../co
|
||||
import { addClusterURL } from "../renderer/components/+add-cluster/add-cluster.route";
|
||||
import { preferencesURL } from "../renderer/components/+preferences/preferences.route";
|
||||
import { whatsNewURL } from "../renderer/components/+whats-new/whats-new.route";
|
||||
import { clusterSettingsURL } from "../renderer/components/+cluster-settings/cluster-settings.route";
|
||||
import { extensionsURL } from "../renderer/components/+extensions/extensions.route";
|
||||
import { catalogURL } from "../renderer/components/+catalog/catalog.route";
|
||||
import { menuRegistry } from "../extensions/registries/menu-registry";
|
||||
@@ -47,16 +46,6 @@ export function buildMenu(windowManager: WindowManager) {
|
||||
return menuItems;
|
||||
}
|
||||
|
||||
function activeClusterOnly(menuItems: MenuItemConstructorOptions[]) {
|
||||
if (!windowManager.activeClusterId) {
|
||||
menuItems.forEach(item => {
|
||||
item.enabled = false;
|
||||
});
|
||||
}
|
||||
|
||||
return menuItems;
|
||||
}
|
||||
|
||||
async function navigate(url: string) {
|
||||
logger.info(`[MENU]: navigating to ${url}`);
|
||||
await windowManager.navigate(url);
|
||||
@@ -112,19 +101,6 @@ export function buildMenu(windowManager: WindowManager) {
|
||||
navigate(addClusterURL());
|
||||
}
|
||||
},
|
||||
...activeClusterOnly([
|
||||
{
|
||||
label: "Cluster Settings",
|
||||
accelerator: "CmdOrCtrl+Shift+S",
|
||||
click() {
|
||||
navigate(clusterSettingsURL({
|
||||
params: {
|
||||
clusterId: windowManager.activeClusterId
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
]),
|
||||
...ignoreOnMac([
|
||||
{ type: "separator" },
|
||||
{
|
||||
|
||||
@@ -44,6 +44,10 @@ export class CatalogEntityRegistry {
|
||||
return this._items;
|
||||
}
|
||||
|
||||
getById(id: string) {
|
||||
return this._items.find((entity) => entity.metadata.uid === id);
|
||||
}
|
||||
|
||||
getItemsForApiKind<T extends CatalogEntity>(apiVersion: string, kind: string): T[] {
|
||||
const items = this._items.filter((item) => item.apiVersion === apiVersion && item.kind === kind);
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
import type { IClusterViewRouteParams } from "../cluster-manager/cluster-view.route";
|
||||
import type { RouteProps } from "react-router";
|
||||
import { buildURL } from "../../../common/utils/buildUrl";
|
||||
|
||||
export interface IClusterSettingsRouteParams extends IClusterViewRouteParams {
|
||||
}
|
||||
|
||||
export const clusterSettingsRoute: RouteProps = {
|
||||
path: `/cluster/:clusterId/settings`,
|
||||
};
|
||||
|
||||
export const clusterSettingsURL = buildURL<IClusterSettingsRouteParams>(clusterSettingsRoute.path);
|
||||
@@ -1,155 +0,0 @@
|
||||
import "./cluster-settings.scss";
|
||||
|
||||
import React from "react";
|
||||
import { observable, reaction } from "mobx";
|
||||
import { RouteComponentProps } from "react-router";
|
||||
import { observer, disposeOnUnmount } from "mobx-react";
|
||||
import { Cluster } from "../../../main/cluster";
|
||||
import { IClusterSettingsRouteParams } from "./cluster-settings.route";
|
||||
import { clusterStore } from "../../../common/cluster-store";
|
||||
import { PageLayout } from "../layout/page-layout";
|
||||
import { requestMain } from "../../../common/ipc";
|
||||
import { clusterActivateHandler, clusterRefreshHandler } from "../../../common/cluster-ipc";
|
||||
import { navigation } from "../../navigation";
|
||||
import { Tabs, Tab } from "../tabs";
|
||||
import { ClusterProxySetting } from "./components/cluster-proxy-setting";
|
||||
import { ClusterNameSetting } from "./components/cluster-name-setting";
|
||||
import { ClusterHomeDirSetting } from "./components/cluster-home-dir-setting";
|
||||
import { ClusterAccessibleNamespaces } from "./components/cluster-accessible-namespaces";
|
||||
import { ClusterMetricsSetting } from "./components/cluster-metrics-setting";
|
||||
import { ShowMetricsSetting } from "./components/show-metrics";
|
||||
import { ClusterPrometheusSetting } from "./components/cluster-prometheus-setting";
|
||||
import { ClusterKubeconfig } from "./components/cluster-kubeconfig";
|
||||
|
||||
interface Props extends RouteComponentProps<IClusterSettingsRouteParams> {
|
||||
}
|
||||
|
||||
|
||||
const clusterPages = ["General", "Proxy", "Terminal", "Namespaces", "Metrics"];
|
||||
|
||||
@observer
|
||||
export class ClusterSettings extends React.Component<Props> {
|
||||
@observable activeTab = "General";
|
||||
|
||||
get clusterId() {
|
||||
return this.props.match.params.clusterId;
|
||||
}
|
||||
|
||||
get cluster(): Cluster {
|
||||
return clusterStore.getById(this.clusterId);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { hash } = navigation.location;
|
||||
|
||||
document.getElementById(hash.slice(1))?.scrollIntoView();
|
||||
|
||||
disposeOnUnmount(this, [
|
||||
reaction(() => this.cluster, this.refreshCluster, {
|
||||
fireImmediately: true,
|
||||
}),
|
||||
reaction(() => this.clusterId, clusterId => clusterStore.setActive(clusterId), {
|
||||
fireImmediately: true,
|
||||
})
|
||||
]);
|
||||
}
|
||||
|
||||
refreshCluster = async () => {
|
||||
if (this.cluster) {
|
||||
await requestMain(clusterActivateHandler, this.cluster.id);
|
||||
await requestMain(clusterRefreshHandler, this.cluster.id);
|
||||
}
|
||||
};
|
||||
|
||||
onTabChange = (tabId: string) => {
|
||||
this.activeTab = tabId;
|
||||
};
|
||||
|
||||
renderNavigation() {
|
||||
return (
|
||||
<>
|
||||
<h2>{this.cluster.name}</h2>
|
||||
<Tabs className="flex column" scrollable={false} onChange={this.onTabChange} value={this.activeTab}>
|
||||
<div className="header">Cluster Settings</div>
|
||||
{ clusterPages.map((page) => {
|
||||
return <Tab key={page} value={page} label={page} data-testid={`${page}-tab`} />;
|
||||
})}
|
||||
</Tabs>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const cluster = this.cluster;
|
||||
|
||||
if (!cluster) return null;
|
||||
|
||||
return (
|
||||
<PageLayout
|
||||
className="ClusterSettings"
|
||||
navigation={this.renderNavigation()}
|
||||
showOnTop={true}
|
||||
contentGaps={false}
|
||||
>
|
||||
{this.activeTab == "General" && (
|
||||
<section>
|
||||
<h2 data-testid="general-header">General</h2>
|
||||
<section>
|
||||
<section>
|
||||
<ClusterNameSetting cluster={cluster} />
|
||||
</section>
|
||||
<section>
|
||||
<ClusterKubeconfig cluster={cluster} />
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{this.activeTab == "Proxy" && (
|
||||
<section>
|
||||
<h2 data-testid="proxy-header">Proxy</h2>
|
||||
<section>
|
||||
<ClusterProxySetting cluster={cluster} />
|
||||
</section>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{this.activeTab == "Terminal" && (
|
||||
<section>
|
||||
<h2 data-testid="terminal-header">Terminal</h2>
|
||||
<section>
|
||||
<ClusterHomeDirSetting cluster={cluster} />
|
||||
</section>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{this.activeTab == "Namespaces" && (
|
||||
<section>
|
||||
<h2 data-testid="namespaces-header">Namespaces</h2>
|
||||
<section>
|
||||
<ClusterAccessibleNamespaces cluster={cluster} />
|
||||
</section>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{this.activeTab == "Metrics" && (
|
||||
<section>
|
||||
<h2 data-testid="metrics-header">Metrics</h2>
|
||||
<section>
|
||||
<section>
|
||||
<ClusterPrometheusSetting cluster={cluster} />
|
||||
</section>
|
||||
<section>
|
||||
<ClusterMetricsSetting cluster={cluster}/>
|
||||
</section>
|
||||
<section>
|
||||
<ShowMetricsSetting cluster={cluster}/>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
)}
|
||||
|
||||
</PageLayout>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import React from "react";
|
||||
import { Cluster } from "../../../main/cluster";
|
||||
import { ClusterNameSetting } from "./components/cluster-name-setting";
|
||||
import { ClusterProxySetting } from "./components/cluster-proxy-setting";
|
||||
import { ClusterPrometheusSetting } from "./components/cluster-prometheus-setting";
|
||||
import { ClusterHomeDirSetting } from "./components/cluster-home-dir-setting";
|
||||
import { ClusterAccessibleNamespaces } from "./components/cluster-accessible-namespaces";
|
||||
import { ClusterMetricsSetting } from "./components/cluster-metrics-setting";
|
||||
import { ShowMetricsSetting } from "./components/show-metrics";
|
||||
|
||||
interface Props {
|
||||
cluster: Cluster;
|
||||
}
|
||||
|
||||
export class General extends React.Component<Props> {
|
||||
render() {
|
||||
return <div>
|
||||
<h2>General</h2>
|
||||
<ClusterNameSetting cluster={this.props.cluster} />
|
||||
<ClusterProxySetting cluster={this.props.cluster} />
|
||||
<ClusterPrometheusSetting cluster={this.props.cluster} />
|
||||
<ClusterHomeDirSetting cluster={this.props.cluster} />
|
||||
<ClusterAccessibleNamespaces cluster={this.props.cluster} />
|
||||
<ClusterMetricsSetting cluster={this.props.cluster}/>
|
||||
<ShowMetricsSetting cluster={this.props.cluster}/>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import { ClusterIssues } from "./cluster-issues";
|
||||
import { ClusterMetrics } from "./cluster-metrics";
|
||||
import { clusterOverviewStore } from "./cluster-overview.store";
|
||||
import { ClusterPieCharts } from "./cluster-pie-charts";
|
||||
import { ResourceType } from "../+cluster-settings/components/cluster-metrics-setting";
|
||||
import { ResourceType } from "../cluster-settings/components/cluster-metrics-setting";
|
||||
|
||||
@observer
|
||||
export class ClusterOverview extends React.Component {
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import type { RouteProps } from "react-router";
|
||||
import { buildURL } from "../../../common/utils/buildUrl";
|
||||
|
||||
export interface EntitySettingsRouteParams {
|
||||
entityId: string;
|
||||
}
|
||||
|
||||
export const entitySettingsRoute: RouteProps = {
|
||||
path: `/entity/:entityId/settings`,
|
||||
};
|
||||
|
||||
export const entitySettingsURL = buildURL<EntitySettingsRouteParams>(entitySettingsRoute.path);
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
.ClusterSettings {
|
||||
.EntitySettings {
|
||||
$spacing: $padding * 3;
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
import "./entity-settings.scss";
|
||||
|
||||
import React from "react";
|
||||
import { observable } from "mobx";
|
||||
import { RouteComponentProps } from "react-router";
|
||||
import { observer } from "mobx-react";
|
||||
import { PageLayout } from "../layout/page-layout";
|
||||
import { navigation } from "../../navigation";
|
||||
import { Tabs, Tab } from "../tabs";
|
||||
import { CatalogEntity } from "../../api/catalog-entity";
|
||||
import { catalogEntityRegistry } from "../../api/catalog-entity-registry";
|
||||
import { entitySettingRegistry } from "../../../extensions/registries";
|
||||
import { EntitySettingsRouteParams } from "./entity-settings.route";
|
||||
|
||||
|
||||
interface Props extends RouteComponentProps<EntitySettingsRouteParams> {
|
||||
}
|
||||
|
||||
@observer
|
||||
export class EntitySettings extends React.Component<Props> {
|
||||
@observable activeTab: string;
|
||||
|
||||
get entityId() {
|
||||
return this.props.match.params.entityId;
|
||||
}
|
||||
|
||||
get entity(): CatalogEntity {
|
||||
return catalogEntityRegistry.getById(this.entityId);
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
const { hash } = navigation.location;
|
||||
|
||||
console.log(this.entityId, this.entity);
|
||||
|
||||
|
||||
this.activeTab = entitySettingRegistry.getItems()[0]?.id;
|
||||
|
||||
document.getElementById(hash.slice(1))?.scrollIntoView();
|
||||
}
|
||||
|
||||
onTabChange = (tabId: string) => {
|
||||
this.activeTab = tabId;
|
||||
};
|
||||
|
||||
renderNavigation() {
|
||||
const settings = entitySettingRegistry.getItems();
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2>{this.entity.metadata.name}</h2>
|
||||
<Tabs className="flex column" scrollable={false} onChange={this.onTabChange} value={this.activeTab}>
|
||||
<div className="header">Settings</div>
|
||||
{ settings.map((setting) => {
|
||||
return <Tab key={setting.id} value={setting.id} label={setting.title} data-testid={`${setting.id}-tab`} />;
|
||||
})}
|
||||
</Tabs>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.entity) return null;
|
||||
|
||||
const activeSetting = entitySettingRegistry.getItems().find((setting) => setting.id === this.activeTab);
|
||||
|
||||
if (!activeSetting) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<PageLayout
|
||||
className="CatalogEntitySettings"
|
||||
navigation={this.renderNavigation()}
|
||||
showOnTop={true}
|
||||
contentGaps={false}
|
||||
>
|
||||
<section>
|
||||
<h2 data-testid={`${activeSetting.id}-header`}>{activeSetting.title}</h2>
|
||||
<section>
|
||||
<activeSetting.components.View entity={this.entity} />
|
||||
</section>
|
||||
</section>
|
||||
</PageLayout>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import "../cluster-settings";
|
||||
|
||||
export * from "./entity-settings.route";
|
||||
export * from "./entity-settings";
|
||||
@@ -14,7 +14,7 @@ import { IngressCharts } from "./ingress-charts";
|
||||
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
|
||||
import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry";
|
||||
import { getBackendServiceNamePort } from "../../api/endpoints/ingress.api";
|
||||
import { ResourceType } from "../+cluster-settings/components/cluster-metrics-setting";
|
||||
import { ResourceType } from "../cluster-settings/components/cluster-metrics-setting";
|
||||
import { clusterStore } from "../../../common/cluster-store";
|
||||
|
||||
interface Props extends KubeObjectDetailsProps<Ingress> {
|
||||
|
||||
@@ -17,7 +17,7 @@ import { PodDetailsList } from "../+workloads-pods/pod-details-list";
|
||||
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
|
||||
import { KubeEventDetails } from "../+events/kube-event-details";
|
||||
import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry";
|
||||
import { ResourceType } from "../+cluster-settings/components/cluster-metrics-setting";
|
||||
import { ResourceType } from "../cluster-settings/components/cluster-metrics-setting";
|
||||
import { clusterStore } from "../../../common/cluster-store";
|
||||
|
||||
interface Props extends KubeObjectDetailsProps<Node> {
|
||||
|
||||
@@ -14,7 +14,7 @@ import { VolumeClaimDiskChart } from "./volume-claim-disk-chart";
|
||||
import { getDetailsUrl, KubeObjectDetailsProps, KubeObjectMeta } from "../kube-object";
|
||||
import { PersistentVolumeClaim } from "../../api/endpoints";
|
||||
import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry";
|
||||
import { ResourceType } from "../+cluster-settings/components/cluster-metrics-setting";
|
||||
import { ResourceType } from "../cluster-settings/components/cluster-metrics-setting";
|
||||
import { clusterStore } from "../../../common/cluster-store";
|
||||
|
||||
interface Props extends KubeObjectDetailsProps<PersistentVolumeClaim> {
|
||||
|
||||
@@ -18,7 +18,7 @@ import { reaction } from "mobx";
|
||||
import { PodDetailsList } from "../+workloads-pods/pod-details-list";
|
||||
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
|
||||
import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry";
|
||||
import { ResourceType } from "../+cluster-settings/components/cluster-metrics-setting";
|
||||
import { ResourceType } from "../cluster-settings/components/cluster-metrics-setting";
|
||||
import { clusterStore } from "../../../common/cluster-store";
|
||||
|
||||
interface Props extends KubeObjectDetailsProps<DaemonSet> {
|
||||
|
||||
@@ -11,7 +11,7 @@ import { PodContainerPort } from "./pod-container-port";
|
||||
import { ResourceMetrics } from "../resource-metrics";
|
||||
import { IMetrics } from "../../api/endpoints/metrics.api";
|
||||
import { ContainerCharts } from "./container-charts";
|
||||
import { ResourceType } from "../+cluster-settings/components/cluster-metrics-setting";
|
||||
import { ResourceType } from "../cluster-settings/components/cluster-metrics-setting";
|
||||
import { clusterStore } from "../../../common/cluster-store";
|
||||
|
||||
interface Props {
|
||||
|
||||
@@ -22,7 +22,7 @@ import { getItemMetrics } from "../../api/endpoints/metrics.api";
|
||||
import { PodCharts, podMetricTabs } from "./pod-charts";
|
||||
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
|
||||
import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry";
|
||||
import { ResourceType } from "../+cluster-settings/components/cluster-metrics-setting";
|
||||
import { ResourceType } from "../cluster-settings/components/cluster-metrics-setting";
|
||||
import { clusterStore } from "../../../common/cluster-store";
|
||||
|
||||
interface Props extends KubeObjectDetailsProps<Pod> {
|
||||
|
||||
@@ -17,7 +17,7 @@ import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts";
|
||||
import { PodDetailsList } from "../+workloads-pods/pod-details-list";
|
||||
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
|
||||
import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry";
|
||||
import { ResourceType } from "../+cluster-settings/components/cluster-metrics-setting";
|
||||
import { ResourceType } from "../cluster-settings/components/cluster-metrics-setting";
|
||||
import { clusterStore } from "../../../common/cluster-store";
|
||||
|
||||
interface Props extends KubeObjectDetailsProps<ReplicaSet> {
|
||||
|
||||
@@ -18,7 +18,7 @@ import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts";
|
||||
import { PodDetailsList } from "../+workloads-pods/pod-details-list";
|
||||
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
|
||||
import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry";
|
||||
import { ResourceType } from "../+cluster-settings/components/cluster-metrics-setting";
|
||||
import { ResourceType } from "../cluster-settings/components/cluster-metrics-setting";
|
||||
import { clusterStore } from "../../../common/cluster-store";
|
||||
|
||||
interface Props extends KubeObjectDetailsProps<StatefulSet> {
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
import React from "react";
|
||||
import uniqueId from "lodash/uniqueId";
|
||||
import { clusterSettingsURL } from "../+cluster-settings";
|
||||
import { catalogURL } from "../+catalog";
|
||||
|
||||
import { clusterStore } from "../../../common/cluster-store";
|
||||
import { broadcastMessage, requestMain } from "../../../common/ipc";
|
||||
import { clusterDisconnectHandler } from "../../../common/cluster-ipc";
|
||||
import { ConfirmDialog } from "../confirm-dialog";
|
||||
import { Cluster } from "../../../main/cluster";
|
||||
import { Tooltip } from "../../components//tooltip";
|
||||
import { IpcRendererNavigationEvents } from "../../navigation/events";
|
||||
|
||||
const navigate = (route: string) =>
|
||||
broadcastMessage(IpcRendererNavigationEvents.NAVIGATE_IN_APP, route);
|
||||
|
||||
/**
|
||||
* Creates handlers for high-level actions
|
||||
* that could be performed on an individual cluster
|
||||
* @param cluster Cluster
|
||||
*/
|
||||
export const ClusterActions = (cluster: Cluster) => ({
|
||||
showSettings: () => navigate(clusterSettingsURL({
|
||||
params: { clusterId: cluster.id }
|
||||
})),
|
||||
disconnect: async () => {
|
||||
clusterStore.deactivate(cluster.id);
|
||||
navigate(catalogURL());
|
||||
await requestMain(clusterDisconnectHandler, cluster.id);
|
||||
},
|
||||
remove: () => {
|
||||
const tooltipId = uniqueId("tooltip_target_");
|
||||
|
||||
return ConfirmDialog.open({
|
||||
okButtonProps: {
|
||||
primary: false,
|
||||
accent: true,
|
||||
label: "Remove"
|
||||
},
|
||||
ok: () => {
|
||||
clusterStore.deactivate(cluster.id);
|
||||
clusterStore.removeById(cluster.id);
|
||||
navigate(catalogURL());
|
||||
},
|
||||
message: <p>
|
||||
Are you sure want to remove cluster <b id={tooltipId}>{cluster.name}</b>?
|
||||
<Tooltip targetId={tooltipId}>{cluster.id}</Tooltip>
|
||||
</p>
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -9,7 +9,6 @@ import { Catalog, catalogRoute, catalogURL } from "../+catalog";
|
||||
import { Preferences, preferencesRoute } from "../+preferences";
|
||||
import { AddCluster, addClusterRoute } from "../+add-cluster";
|
||||
import { ClusterView } from "./cluster-view";
|
||||
import { ClusterSettings, clusterSettingsRoute } from "../+cluster-settings";
|
||||
import { clusterViewRoute } from "./cluster-view.route";
|
||||
import { clusterStore } from "../../../common/cluster-store";
|
||||
import { hasLoadedView, initView, lensViews, refreshViews } from "./lens-views";
|
||||
@@ -17,6 +16,7 @@ import { globalPageRegistry } from "../../../extensions/registries/page-registry
|
||||
import { Extensions, extensionsRoute } from "../+extensions";
|
||||
import { getMatchedClusterId } from "../../navigation";
|
||||
import { HotbarMenu } from "../hotbar/hotbar-menu";
|
||||
import { EntitySettings, entitySettingsRoute } from "../+entity-settings";
|
||||
|
||||
@observer
|
||||
export class ClusterManager extends React.Component {
|
||||
@@ -58,7 +58,7 @@ export class ClusterManager extends React.Component {
|
||||
<Route component={Extensions} {...extensionsRoute} />
|
||||
<Route component={AddCluster} {...addClusterRoute} />
|
||||
<Route component={ClusterView} {...clusterViewRoute} />
|
||||
<Route component={ClusterSettings} {...clusterSettingsRoute} />
|
||||
<Route component={EntitySettings} {...entitySettingsRoute} />
|
||||
{globalPageRegistry.getItems().map(({ url, components: { Page } }) => {
|
||||
return <Route key={url} path={url} component={Page}/>;
|
||||
})}
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
export * from "./cluster-manager";
|
||||
export * from "./cluster-actions";
|
||||
+3
-3
@@ -1,15 +1,15 @@
|
||||
import { navigate } from "../../navigation";
|
||||
import { commandRegistry } from "../../../extensions/registries/command-registry";
|
||||
import { clusterSettingsURL } from "./cluster-settings.route";
|
||||
import { clusterStore } from "../../../common/cluster-store";
|
||||
import { entitySettingsURL } from "../+entity-settings";
|
||||
|
||||
commandRegistry.add({
|
||||
id: "cluster.viewCurrentClusterSettings",
|
||||
title: "Cluster: View Settings",
|
||||
scope: "global",
|
||||
action: () => navigate(clusterSettingsURL({
|
||||
action: () => navigate(entitySettingsURL({
|
||||
params: {
|
||||
clusterId: clusterStore.active.id
|
||||
entityId: clusterStore.active.id
|
||||
}
|
||||
})),
|
||||
isActive: (context) => !!context.entity
|
||||
@@ -0,0 +1,130 @@
|
||||
import React from "react";
|
||||
import { clusterStore } from "../../../common/cluster-store";
|
||||
import { ClusterProxySetting } from "./components/cluster-proxy-setting";
|
||||
import { ClusterNameSetting } from "./components/cluster-name-setting";
|
||||
import { ClusterHomeDirSetting } from "./components/cluster-home-dir-setting";
|
||||
import { ClusterAccessibleNamespaces } from "./components/cluster-accessible-namespaces";
|
||||
import { ClusterMetricsSetting } from "./components/cluster-metrics-setting";
|
||||
import { ShowMetricsSetting } from "./components/show-metrics";
|
||||
import { ClusterPrometheusSetting } from "./components/cluster-prometheus-setting";
|
||||
import { ClusterKubeconfig } from "./components/cluster-kubeconfig";
|
||||
import { entitySettingRegistry } from "../../../extensions/registries";
|
||||
import { CatalogEntity } from "../../api/catalog-entity";
|
||||
|
||||
entitySettingRegistry.add([
|
||||
{
|
||||
apiVersions: ["entity.k8slens.dev/v1alpha1"],
|
||||
kind: "KubernetesCluster",
|
||||
source: "local",
|
||||
title: "General",
|
||||
components: {
|
||||
View: (props: { entity: CatalogEntity }) => {
|
||||
const cluster = clusterStore.enabledClustersList.find((cluster) => cluster.id === props.entity.metadata.uid);
|
||||
|
||||
if (!cluster) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<section>
|
||||
<section>
|
||||
<ClusterNameSetting cluster={cluster} />
|
||||
</section>
|
||||
<section>
|
||||
<ClusterKubeconfig cluster={cluster} />
|
||||
</section>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
apiVersions: ["entity.k8slens.dev/v1alpha1"],
|
||||
kind: "KubernetesCluster",
|
||||
title: "Proxy",
|
||||
components: {
|
||||
View: (props: { entity: CatalogEntity }) => {
|
||||
const cluster = clusterStore.enabledClustersList.find((cluster) => cluster.id === props.entity.metadata.uid);
|
||||
|
||||
if (!cluster) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<section>
|
||||
<ClusterProxySetting cluster={cluster} />
|
||||
</section>
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
apiVersions: ["entity.k8slens.dev/v1alpha1"],
|
||||
kind: "KubernetesCluster",
|
||||
title: "Terminal",
|
||||
components: {
|
||||
View: (props: { entity: CatalogEntity }) => {
|
||||
const cluster = clusterStore.enabledClustersList.find((cluster) => cluster.id === props.entity.metadata.uid);
|
||||
|
||||
if (!cluster) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<section>
|
||||
<ClusterHomeDirSetting cluster={cluster} />
|
||||
</section>
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
apiVersions: ["entity.k8slens.dev/v1alpha1"],
|
||||
kind: "KubernetesCluster",
|
||||
title: "Namespaces",
|
||||
components: {
|
||||
View: (props: { entity: CatalogEntity }) => {
|
||||
const cluster = clusterStore.enabledClustersList.find((cluster) => cluster.id === props.entity.metadata.uid);
|
||||
|
||||
if (!cluster) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<section>
|
||||
<ClusterAccessibleNamespaces cluster={cluster} />
|
||||
</section>
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
apiVersions: ["entity.k8slens.dev/v1alpha1"],
|
||||
kind: "KubernetesCluster",
|
||||
source: "local",
|
||||
title: "Metrics",
|
||||
components: {
|
||||
View: (props: { entity: CatalogEntity }) => {
|
||||
const cluster = clusterStore.enabledClustersList.find((cluster) => cluster.id === props.entity.metadata.uid);
|
||||
|
||||
if (!cluster) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<section>
|
||||
<section>
|
||||
<ClusterPrometheusSetting cluster={cluster} />
|
||||
</section>
|
||||
<section>
|
||||
<ClusterMetricsSetting cluster={cluster}/>
|
||||
</section>
|
||||
<section>
|
||||
<ShowMetricsSetting cluster={cluster}/>
|
||||
</section>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
]);
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
-1
@@ -1,3 +1,2 @@
|
||||
export * from "./cluster-settings.route";
|
||||
export * from "./cluster-settings";
|
||||
export * from "./cluster-settings.command";
|
||||
@@ -7,7 +7,7 @@ import { isMac } from "../../common/vars";
|
||||
import { invalidKubeconfigHandler } from "./invalid-kubeconfig-handler";
|
||||
import { clusterStore } from "../../common/cluster-store";
|
||||
import { navigate } from "../navigation";
|
||||
import { clusterSettingsURL } from "../components/+cluster-settings";
|
||||
import { entitySettingsURL } from "../components/+entity-settings";
|
||||
|
||||
function sendToBackchannel(backchannel: string, notificationId: string, data: BackchannelArg): void {
|
||||
notificationsStore.remove(notificationId);
|
||||
@@ -79,7 +79,7 @@ function ListNamespacesForbiddenHandler(event: IpcRendererEvent, ...[clusterId]:
|
||||
<p>Cluster <b>{clusterStore.active.name}</b> does not have permissions to list namespaces. Please add the namespaces you have access to.</p>
|
||||
<div className="flex gaps row align-left box grow">
|
||||
<Button active outlined label="Go to Accessible Namespaces Settings" onClick={()=> {
|
||||
navigate(clusterSettingsURL({ params: { clusterId }, fragment: "accessible-namespaces" }));
|
||||
navigate(entitySettingsURL({ params: { entityId: clusterId }, fragment: "accessible-namespaces" }));
|
||||
notificationsStore.remove(notificationId);
|
||||
}} />
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { addClusterURL } from "../components/+add-cluster";
|
||||
import { clusterSettingsURL } from "../components/+cluster-settings";
|
||||
import { extensionsURL } from "../components/+extensions";
|
||||
import { catalogURL } from "../components/+catalog";
|
||||
import { preferencesURL } from "../components/+preferences";
|
||||
@@ -7,6 +6,8 @@ import { clusterViewURL } from "../components/cluster-manager/cluster-view.route
|
||||
import { LensProtocolRouterRenderer } from "./router";
|
||||
import { navigate } from "../navigation/helpers";
|
||||
import { clusterStore } from "../../common/cluster-store";
|
||||
import { entitySettingsURL } from "../components/+entity-settings";
|
||||
import { catalogEntityRegistry } from "../api/catalog-entity-registry";
|
||||
|
||||
export function bindProtocolAddRouteHandlers() {
|
||||
LensProtocolRouterRenderer
|
||||
@@ -23,6 +24,19 @@ export function bindProtocolAddRouteHandlers() {
|
||||
.addInternalHandler("/cluster", () => {
|
||||
navigate(addClusterURL());
|
||||
})
|
||||
.addInternalHandler("/entity/:entityId/settings", ({ pathname: { entityId } }) => {
|
||||
const entity = catalogEntityRegistry.getById(entityId);
|
||||
|
||||
if (entity) {
|
||||
navigate(entitySettingsURL({ params: { entityId } }));
|
||||
} else {
|
||||
console.log("[APP-HANDLER]: catalog entity with given ID does not exist", { entityId });
|
||||
}
|
||||
})
|
||||
.addInternalHandler("/extensions", () => {
|
||||
navigate(extensionsURL());
|
||||
})
|
||||
// Handlers below are deprecated and only kept for backward compat purposes
|
||||
.addInternalHandler("/cluster/:clusterId", ({ pathname: { clusterId } }) => {
|
||||
const cluster = clusterStore.getById(clusterId);
|
||||
|
||||
@@ -36,12 +50,9 @@ export function bindProtocolAddRouteHandlers() {
|
||||
const cluster = clusterStore.getById(clusterId);
|
||||
|
||||
if (cluster) {
|
||||
navigate(clusterSettingsURL({ params: { clusterId } }));
|
||||
navigate(entitySettingsURL({ params: { entityId: clusterId } }));
|
||||
} else {
|
||||
console.log("[APP-HANDLER]: cluster with given ID does not exist", { clusterId });
|
||||
}
|
||||
})
|
||||
.addInternalHandler("/extensions", () => {
|
||||
navigate(extensionsURL());
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user