1
0
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:
Jari Kolehmainen 2021-04-15 10:07:49 +03:00
parent 0533455ef0
commit 6df4ef696f
45 changed files with 328 additions and 298 deletions

View File

@ -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",

View File

@ -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);

View File

@ -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>;
}

View File

@ -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;

View File

@ -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),
];

View File

@ -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[] = [];

View File

@ -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();

View File

@ -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";

View File

@ -57,5 +57,4 @@ export class ClusterPageMenuRegistry extends PageMenuRegistry<ClusterPageMenuReg
}
}
export const globalPageMenuRegistry = new PageMenuRegistry();
export const clusterPageMenuRegistry = new ClusterPageMenuRegistry();

View File

@ -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" },
{

View File

@ -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);

View File

@ -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);

View File

@ -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>
);
}
}

View File

@ -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>;
}
}

View File

@ -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 {

View File

@ -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);

View File

@ -1,4 +1,4 @@
.ClusterSettings {
.EntitySettings {
$spacing: $padding * 3;

View File

@ -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>
);
}
}

View File

@ -0,0 +1,4 @@
import "../cluster-settings";
export * from "./entity-settings.route";
export * from "./entity-settings";

View File

@ -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> {

View File

@ -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> {

View File

@ -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> {

View File

@ -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> {

View File

@ -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 {

View File

@ -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> {

View File

@ -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> {

View File

@ -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> {

View File

@ -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>
});
}
});

View File

@ -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}/>;
})}

View File

@ -1,2 +1 @@
export * from "./cluster-manager";
export * from "./cluster-actions";

View File

@ -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

View File

@ -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>
);
}
}
}
]);

View File

@ -1,3 +1,2 @@
export * from "./cluster-settings.route";
export * from "./cluster-settings";
export * from "./cluster-settings.command";

View File

@ -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>

View File

@ -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());
});
}