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 { Component, Catalog, K8sApi } from "@k8slens/extensions";
import { observer } from "mobx-react";
import { observable } from "mobx";
import { computed, observable } from "mobx";
import { MetricsFeature, MetricsConfiguration } from "./metrics-feature";
interface Props {
@ -43,6 +43,22 @@ export class MetricsSettings extends React.Component<Props> {
};
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() {
this.feature = new MetricsFeature(this.props.cluster);
@ -148,6 +164,13 @@ export class MetricsSettings extends React.Component<Props> {
</p>
</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 && (
<section>
<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} />
<small className="hint">
An update is available for installed metrics components.
An update is available for enabled metrics components.
</small>
</section>
)}
@ -164,7 +187,7 @@ export class MetricsSettings extends React.Component<Props> {
<Component.FormSwitch
control={
<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}
onChange={v => this.togglePrometheus(v.target.checked)}
name="prometheus"
@ -182,7 +205,7 @@ export class MetricsSettings extends React.Component<Props> {
<Component.FormSwitch
control={
<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}
onChange={v => this.toggleKubeStateMetrics(v.target.checked)}
name="node-exporter"
@ -201,7 +224,7 @@ export class MetricsSettings extends React.Component<Props> {
<Component.FormSwitch
control={
<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}
onChange={v => this.toggleNodeExporter(v.target.checked)}
name="node-exporter"

View File

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

View File

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

View File

@ -8,7 +8,7 @@ import logger from "./logger";
import { apiKubePrefix } from "../common/vars";
import { Singleton } from "../common/utils";
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 {
constructor() {
@ -47,7 +47,7 @@ export class ClusterManager extends Singleton {
const index = catalogEntityRegistry.items.findIndex((entity) => entity.metadata.uid === cluster.id);
if (index !== -1) {
const entity = catalogEntityRegistry.items[index];
const entity = catalogEntityRegistry.items[index] as KubernetesCluster;
entity.status.phase = cluster.disconnected ? "disconnected" : "connected";
entity.status.active = !cluster.disconnected;
@ -55,6 +55,17 @@ export class ClusterManager extends Singleton {
if (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);
}
}

View File

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

View File

@ -22,6 +22,7 @@ entitySettingRegistry.add([
kind: "KubernetesCluster",
source: "local",
title: "General",
group: "Settings",
components: {
View: (props: { entity: CatalogEntity }) => {
const cluster = getClusterForEntity(props.entity);
@ -47,6 +48,7 @@ entitySettingRegistry.add([
apiVersions: ["entity.k8slens.dev/v1alpha1"],
kind: "KubernetesCluster",
title: "Proxy",
group: "Settings",
components: {
View: (props: { entity: CatalogEntity }) => {
const cluster = getClusterForEntity(props.entity);
@ -67,6 +69,7 @@ entitySettingRegistry.add([
apiVersions: ["entity.k8slens.dev/v1alpha1"],
kind: "KubernetesCluster",
title: "Terminal",
group: "Settings",
components: {
View: (props: { entity: CatalogEntity }) => {
const cluster = getClusterForEntity(props.entity);
@ -87,6 +90,7 @@ entitySettingRegistry.add([
apiVersions: ["entity.k8slens.dev/v1alpha1"],
kind: "KubernetesCluster",
title: "Namespaces",
group: "Settings",
components: {
View: (props: { entity: CatalogEntity }) => {
const cluster = getClusterForEntity(props.entity);
@ -107,6 +111,7 @@ entitySettingRegistry.add([
apiVersions: ["entity.k8slens.dev/v1alpha1"],
kind: "KubernetesCluster",
title: "Metrics",
group: "Settings",
components: {
View: (props: { entity: CatalogEntity }) => {
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 { disposeOnUnmount, observer } from "mobx-react";
import { Select, SelectOption } from "../../select/select";

View File

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

View File

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