1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

clarify ui

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
Jari Kolehmainen 2021-05-12 07:44:01 +03:00
parent c4e501f329
commit 331a617c5b
10 changed files with 96 additions and 52 deletions

View File

@ -1,7 +1,7 @@
import React from "react"; import React from "react";
import { Component, Catalog, K8sApi } from "@k8slens/extensions"; import { Component, Catalog, K8sApi } from "@k8slens/extensions";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { observable } from "mobx"; import { computed, observable } from "mobx";
import { MetricsFeature, MetricsConfiguration } from "./metrics-feature"; import { MetricsFeature, MetricsConfiguration } from "./metrics-feature";
interface Props { interface Props {
@ -43,6 +43,22 @@ export class MetricsSettings extends React.Component<Props> {
}; };
feature: MetricsFeature; feature: MetricsFeature;
@computed get isTogglable() {
if (!this.props.cluster.status.active) return false;
if (this.canUpgrade) return false;
if (!this.isActiveMetricsProvider) return false;
return true;
}
get metricsProvider() {
return this.props.cluster.spec?.metrics?.prometheus?.type || "";
}
get isActiveMetricsProvider() {
return (!this.metricsProvider || this.metricsProvider === "lens");
}
async componentDidMount() { async componentDidMount() {
this.feature = new MetricsFeature(this.props.cluster); this.feature = new MetricsFeature(this.props.cluster);
@ -148,6 +164,13 @@ export class MetricsSettings extends React.Component<Props> {
</p> </p>
</section> </section>
)} )}
{ !this.isActiveMetricsProvider && (
<section>
<p style={ {color: "var(--colorError)"} }>
Other metrics provider is currently active. See &quot;Metrics&quot; tab for details.
</p>
</section>
)}
{ this.canUpgrade && ( { this.canUpgrade && (
<section> <section>
<Component.SubTitle title="Software Update" /> <Component.SubTitle title="Software Update" />
@ -155,7 +178,7 @@ export class MetricsSettings extends React.Component<Props> {
<Component.Button label={this.upgrading ? "Updating ..." : "Update Now"} primary onClick={() => this.updateStack() } waiting={this.upgrading} /> <Component.Button label={this.upgrading ? "Updating ..." : "Update Now"} primary onClick={() => this.updateStack() } waiting={this.upgrading} />
<small className="hint"> <small className="hint">
An update is available for installed metrics components. An update is available for enabled metrics components.
</small> </small>
</section> </section>
)} )}
@ -164,7 +187,7 @@ export class MetricsSettings extends React.Component<Props> {
<Component.FormSwitch <Component.FormSwitch
control={ control={
<Component.Switcher <Component.Switcher
disabled={this.featureStates.kubeStateMetrics === undefined || !this.props.cluster.status.active} disabled={this.featureStates.kubeStateMetrics === undefined || !this.isTogglable}
checked={!!this.featureStates.prometheus && this.props.cluster.status.active} checked={!!this.featureStates.prometheus && this.props.cluster.status.active}
onChange={v => this.togglePrometheus(v.target.checked)} onChange={v => this.togglePrometheus(v.target.checked)}
name="prometheus" name="prometheus"
@ -182,7 +205,7 @@ export class MetricsSettings extends React.Component<Props> {
<Component.FormSwitch <Component.FormSwitch
control={ control={
<Component.Switcher <Component.Switcher
disabled={this.featureStates.kubeStateMetrics === undefined || !this.props.cluster.status.active} disabled={this.featureStates.kubeStateMetrics === undefined || !this.isTogglable}
checked={!!this.featureStates.kubeStateMetrics && this.props.cluster.status.active} checked={!!this.featureStates.kubeStateMetrics && this.props.cluster.status.active}
onChange={v => this.toggleKubeStateMetrics(v.target.checked)} onChange={v => this.toggleKubeStateMetrics(v.target.checked)}
name="node-exporter" name="node-exporter"
@ -201,7 +224,7 @@ export class MetricsSettings extends React.Component<Props> {
<Component.FormSwitch <Component.FormSwitch
control={ control={
<Component.Switcher <Component.Switcher
disabled={this.featureStates.nodeExporter === undefined || !this.props.cluster.status.active} disabled={this.featureStates.nodeExporter === undefined || !this.isTogglable}
checked={!!this.featureStates.nodeExporter && this.props.cluster.status.active} checked={!!this.featureStates.nodeExporter && this.props.cluster.status.active}
onChange={v => this.toggleNodeExporter(v.target.checked)} onChange={v => this.toggleNodeExporter(v.target.checked)}
name="node-exporter" name="node-exporter"

View File

@ -6,9 +6,24 @@ import { requestMain } from "../ipc";
import { productName } from "../vars"; import { productName } from "../vars";
import { CatalogCategory, CatalogCategorySpec } from "../catalog"; import { CatalogCategory, CatalogCategorySpec } from "../catalog";
export type KubernetesClusterPrometheusMetrics = {
address?: {
namespace: string;
service: string;
port: number;
prefix: string;
};
type?: string;
};
export type KubernetesClusterSpec = { export type KubernetesClusterSpec = {
kubeconfigPath: string; kubeconfigPath: string;
kubeconfigContext: string; kubeconfigContext: string;
metrics?: {
source: string;
prometheus?: KubernetesClusterPrometheusMetrics;
}
}; };
export interface KubernetesClusterStatus extends CatalogEntityStatus { export interface KubernetesClusterStatus extends CatalogEntityStatus {

View File

@ -11,13 +11,14 @@ export interface EntitySettingComponents {
} }
export interface EntitySettingRegistration { export interface EntitySettingRegistration {
title: string;
kind: string;
apiVersions: string[]; apiVersions: string[];
source?: string; kind: string;
title: string;
components: EntitySettingComponents; components: EntitySettingComponents;
source?: string;
id?: string; id?: string;
priority?: number; priority?: number;
group?: string;
} }
export interface RegisteredEntitySetting extends EntitySettingRegistration { export interface RegisteredEntitySetting extends EntitySettingRegistration {

View File

@ -8,7 +8,7 @@ import logger from "./logger";
import { apiKubePrefix } from "../common/vars"; import { apiKubePrefix } from "../common/vars";
import { Singleton } from "../common/utils"; import { Singleton } from "../common/utils";
import { catalogEntityRegistry } from "../common/catalog"; import { catalogEntityRegistry } from "../common/catalog";
import { KubernetesCluster } from "../common/catalog-entities/kubernetes-cluster"; import { KubernetesCluster, KubernetesClusterPrometheusMetrics } from "../common/catalog-entities/kubernetes-cluster";
export class ClusterManager extends Singleton { export class ClusterManager extends Singleton {
constructor() { constructor() {
@ -47,7 +47,7 @@ export class ClusterManager extends Singleton {
const index = catalogEntityRegistry.items.findIndex((entity) => entity.metadata.uid === cluster.id); const index = catalogEntityRegistry.items.findIndex((entity) => entity.metadata.uid === cluster.id);
if (index !== -1) { if (index !== -1) {
const entity = catalogEntityRegistry.items[index]; const entity = catalogEntityRegistry.items[index] as KubernetesCluster;
entity.status.phase = cluster.disconnected ? "disconnected" : "connected"; entity.status.phase = cluster.disconnected ? "disconnected" : "connected";
entity.status.active = !cluster.disconnected; entity.status.active = !cluster.disconnected;
@ -55,6 +55,17 @@ export class ClusterManager extends Singleton {
if (cluster.preferences?.clusterName) { if (cluster.preferences?.clusterName) {
entity.metadata.name = cluster.preferences.clusterName; entity.metadata.name = cluster.preferences.clusterName;
} }
entity.spec.metrics ||= { source: "local" };
if (entity.spec.metrics.source === "local") {
const prometheus: KubernetesClusterPrometheusMetrics = entity.spec?.metrics?.prometheus || {};
prometheus.type = cluster.preferences.prometheusProvider?.type;
prometheus.address = cluster.preferences.prometheus;
entity.spec.metrics.prometheus = prometheus;
}
catalogEntityRegistry.items.splice(index, 1, entity); catalogEntityRegistry.items.splice(index, 1, entity);
} }
} }

View File

@ -11,6 +11,7 @@ import { CatalogEntity } from "../../api/catalog-entity";
import { catalogEntityRegistry } from "../../api/catalog-entity-registry"; import { catalogEntityRegistry } from "../../api/catalog-entity-registry";
import { entitySettingRegistry } from "../../../extensions/registries"; import { entitySettingRegistry } from "../../../extensions/registries";
import { EntitySettingsRouteParams } from "./entity-settings.route"; import { EntitySettingsRouteParams } from "./entity-settings.route";
import { groupBy } from "lodash";
interface Props extends RouteComponentProps<EntitySettingsRouteParams> { interface Props extends RouteComponentProps<EntitySettingsRouteParams> {
} }
@ -52,18 +53,24 @@ export class EntitySettings extends React.Component<Props> {
}; };
renderNavigation() { renderNavigation() {
const groups = Object.entries(groupBy(this.menuItems, (item) => item.group || "Extensions"));
return ( return (
<> <>
<h2>{this.entity.metadata.name}</h2> <h2>{this.entity.metadata.name}</h2>
<Tabs className="flex column" scrollable={false} onChange={this.onTabChange} value={this.activeTab}> <Tabs className="flex column" scrollable={false} onChange={this.onTabChange} value={this.activeTab}>
<div className="header">Settings</div> { groups.map((group) => (
{ this.menuItems.map((setting) => ( <>
<Tab <div className="header">{group[0]}</div>
key={setting.id} { group[1].map((setting) => (
value={setting.id} <Tab
label={setting.title} key={setting.id}
data-testid={`${setting.id}-tab`} value={setting.id}
/> label={setting.title}
data-testid={`${setting.id}-tab`}
/>
))}
</>
))} ))}
</Tabs> </Tabs>
</> </>

View File

@ -22,6 +22,7 @@ entitySettingRegistry.add([
kind: "KubernetesCluster", kind: "KubernetesCluster",
source: "local", source: "local",
title: "General", title: "General",
group: "Settings",
components: { components: {
View: (props: { entity: CatalogEntity }) => { View: (props: { entity: CatalogEntity }) => {
const cluster = getClusterForEntity(props.entity); const cluster = getClusterForEntity(props.entity);
@ -47,6 +48,7 @@ entitySettingRegistry.add([
apiVersions: ["entity.k8slens.dev/v1alpha1"], apiVersions: ["entity.k8slens.dev/v1alpha1"],
kind: "KubernetesCluster", kind: "KubernetesCluster",
title: "Proxy", title: "Proxy",
group: "Settings",
components: { components: {
View: (props: { entity: CatalogEntity }) => { View: (props: { entity: CatalogEntity }) => {
const cluster = getClusterForEntity(props.entity); const cluster = getClusterForEntity(props.entity);
@ -67,6 +69,7 @@ entitySettingRegistry.add([
apiVersions: ["entity.k8slens.dev/v1alpha1"], apiVersions: ["entity.k8slens.dev/v1alpha1"],
kind: "KubernetesCluster", kind: "KubernetesCluster",
title: "Terminal", title: "Terminal",
group: "Settings",
components: { components: {
View: (props: { entity: CatalogEntity }) => { View: (props: { entity: CatalogEntity }) => {
const cluster = getClusterForEntity(props.entity); const cluster = getClusterForEntity(props.entity);
@ -87,6 +90,7 @@ entitySettingRegistry.add([
apiVersions: ["entity.k8slens.dev/v1alpha1"], apiVersions: ["entity.k8slens.dev/v1alpha1"],
kind: "KubernetesCluster", kind: "KubernetesCluster",
title: "Namespaces", title: "Namespaces",
group: "Settings",
components: { components: {
View: (props: { entity: CatalogEntity }) => { View: (props: { entity: CatalogEntity }) => {
const cluster = getClusterForEntity(props.entity); const cluster = getClusterForEntity(props.entity);
@ -107,6 +111,7 @@ entitySettingRegistry.add([
apiVersions: ["entity.k8slens.dev/v1alpha1"], apiVersions: ["entity.k8slens.dev/v1alpha1"],
kind: "KubernetesCluster", kind: "KubernetesCluster",
title: "Metrics", title: "Metrics",
group: "Settings",
components: { components: {
View: (props: { entity: CatalogEntity }) => { View: (props: { entity: CatalogEntity }) => {
const cluster = getClusterForEntity(props.entity); const cluster = getClusterForEntity(props.entity);

View File

@ -1,12 +0,0 @@
.MetricsSelect {
$spacing: $padding;
--flex-gap: #{$spacing};
.Badge {
margin-top: $spacing;
}
.Button {
margin-top: $spacing;
}
}

View File

@ -1,5 +1,3 @@
import "./cluster-metrics-setting.scss";
import React from "react"; import React from "react";
import { disposeOnUnmount, observer } from "mobx-react"; import { disposeOnUnmount, observer } from "mobx-react";
import { Select, SelectOption } from "../../select/select"; import { Select, SelectOption } from "../../select/select";

View File

@ -6,6 +6,7 @@ import { SubTitle } from "../../layout/sub-title";
import { Select, SelectOption } from "../../select"; import { Select, SelectOption } from "../../select";
import { Input } from "../../input"; import { Input } from "../../input";
import { observable, computed, autorun } from "mobx"; import { observable, computed, autorun } from "mobx";
import { productName } from "../../../../common/vars";
const options: SelectOption<string>[] = [ const options: SelectOption<string>[] = [
{ value: "", label: "Auto detect" }, { value: "", label: "Auto detect" },
@ -81,23 +82,20 @@ export class ClusterPrometheusSetting extends React.Component<Props> {
render() { render() {
return ( return (
<> <>
<SubTitle title="Prometheus installation method"/> <section>
<p> <SubTitle title="Prometheus"/>
Use pre-installed Prometheus service for metrics. Please refer to the{" "} <Select
<a href="https://github.com/lensapp/lens/blob/master/troubleshooting/custom-prometheus.md" target="_blank" rel="noreferrer">guide</a>{" "} value={this.provider}
for possible configuration changes. onChange={({value}) => {
</p> this.provider = value;
<Select this.onSaveProvider();
value={this.provider} }}
onChange={({value}) => { options={options}
this.provider = value; />
this.onSaveProvider(); <small className="hint">What query format is used to fetch metrics from Prometheus</small>
}} </section>
options={options}
/>
<small className="hint">What query format is used to fetch metrics from Prometheus</small>
{this.canEditPrometheusPath && ( {this.canEditPrometheusPath && (
<> <section>
<p>Prometheus service address.</p> <p>Prometheus service address.</p>
<Input <Input
theme="round-black" theme="round-black"
@ -108,9 +106,9 @@ export class ClusterPrometheusSetting extends React.Component<Props> {
/> />
<small className="hint"> <small className="hint">
An address to an existing Prometheus installation{" "} An address to an existing Prometheus installation{" "}
({"<namespace>/<service>:<port>"}). Lens tries to auto-detect address if left empty. ({"<namespace>/<service>:<port>"}). {productName} tries to auto-detect address if left empty.
</small> </small>
</> </section>
)} )}
</> </>
); );

View File

@ -1,5 +1,3 @@
import "./cluster-metrics-setting.scss";
import React from "react"; import React from "react";
import { disposeOnUnmount, observer } from "mobx-react"; import { disposeOnUnmount, observer } from "mobx-react";
import { Cluster } from "../../../../main/cluster"; import { Cluster } from "../../../../main/cluster";