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

Polishing Cluster Settings page

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
This commit is contained in:
Alex Andreev 2021-03-23 11:33:16 +03:00
parent b066fb3527
commit 67b1e37015
21 changed files with 176 additions and 154 deletions

View File

@ -1,51 +0,0 @@
.ClusterSettings {
$spacing: $padding * 3;
> .content-wrapper {
--flex-gap: #{$spacing};
}
// TODO: move sub-component styles to separate files
.admin-note {
font-size: small;
opacity: 0.5;
margin-left: $margin;
}
.button-area {
margin-top: $margin * 2;
}
.file-loader {
margin-top: $margin * 2;
}
.status-table {
margin: $spacing 0;
.Table {
border: 1px solid var(--drawerSubtitleBackground);
border-radius: $radius;
.TableRow {
&:not(:last-of-type) {
border-bottom: 1px solid var(--drawerSubtitleBackground);
}
.value {
flex-grow: 2;
word-break: break-word;
color: var(--textColorSecondary);
}
.link {
@include pseudo-link;
}
}
}
}
.Input, .Select {
margin-top: $padding;
}
}

View File

@ -1,5 +1,3 @@
import "./cluster-settings.scss";
import React from "react";
import { reaction } from "mobx";
import { RouteComponentProps } from "react-router";
@ -15,6 +13,8 @@ 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 { ScrollSpy } from "../scroll-spy/scroll-spy";
import { Metrics } from "./metrics";
interface Props extends RouteComponentProps<IClusterSettingsRouteParams> {
}
@ -59,12 +59,21 @@ export class ClusterSettings extends React.Component<Props> {
);
return (
<PageLayout className="ClusterSettings" header={header} showOnTop={true}>
<Status cluster={cluster}></Status>
<General cluster={cluster}></General>
<Features cluster={cluster}></Features>
<Removal cluster={cluster}></Removal>
</PageLayout>
<ScrollSpy htmlFor="ScrollSpyRoot" render={navigation => (
<PageLayout
className="ClusterSettings"
header={header}
showOnTop={true}
navigation={navigation}
contentGaps={false}
>
<Status cluster={cluster}></Status>
<General cluster={cluster}></General>
<Metrics cluster={cluster}></Metrics>
<Features cluster={cluster}></Features>
<Removal cluster={cluster}></Removal>
</PageLayout>
)}/>
);
}
}

View File

@ -17,7 +17,6 @@ export class ClusterAccessibleNamespaces extends React.Component<Props> {
return (
<>
<SubTitle title="Accessible Namespaces" />
<p>This setting is useful for manually specifying which namespaces you have access to. This is useful when you do not have permissions to list namespaces.</p>
<EditableList
placeholder="Add new namespace..."
add={(newNamespace) => {
@ -30,6 +29,10 @@ export class ClusterAccessibleNamespaces extends React.Component<Props> {
this.props.cluster.accessibleNamespaces = Array.from(this.namespaces);
}}
/>
<small className="hint">
Specify which namespaces you have access to.
This is useful when you do not have permissions to list namespaces.
</small>
</>
);
}

View File

@ -33,7 +33,6 @@ export class ClusterHomeDirSetting extends React.Component<Props> {
return (
<>
<SubTitle title="Working Directory"/>
<p>Terminal working directory.</p>
<Input
theme="round-black"
value={this.directory}

View File

@ -1,3 +1,5 @@
import "./cluster-icon.scss";
import React from "react";
import { Cluster } from "../../../../main/cluster";
import { FilePicker, OverSizeLimitStyle } from "../../file-picker";
@ -42,38 +44,28 @@ export class ClusterIconSetting extends React.Component<Props> {
}
}
getClearButton() {
if (this.props.cluster.preferences.icon) {
return <Button tooltip="Revert back to default icon" accent onClick={() => this.onIconPick([])}>Clear</Button>;
}
}
render() {
const label = (
<>
return (
<div className="ClusterIconSetting flex column gaps align-flex-start">
<SubTitle title="Icon"/>
<ClusterIcon
cluster={this.props.cluster}
showErrors={false}
showTooltip={false}
isActive={true}
/>
{"Browse for new icon..."}
</>
);
return (
<>
<SubTitle title="Cluster Icon" />
<p>Define cluster icon. By default automatically generated.</p>
<div className="file-loader">
<div className="flex gaps align-center">
<FilePicker
accept="image/*"
label={label}
label="Upload an Icon&nbsp;"
onOverSizeLimit={OverSizeLimitStyle.FILTER}
handler={this.onIconPick}
/>
{this.getClearButton()}
{this.props.cluster.preferences.icon && (
<Button plain tooltip="Revert back to default icon" onClick={() => this.onIconPick([])}>Clear</Button>
)}
</div>
</>
</div>
);
}
}

View File

@ -0,0 +1,12 @@
.ClusterIconSetting {
.ClusterIcon {
--size: 50px;
}
.FilePicker label {
color: var(--textColorAccent);
padding: 5px 9px;
border-radius: 4px;
background: var(--blue);
}
}

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";
@ -109,7 +107,7 @@ export class ClusterMetricsSetting extends React.Component<Props> {
return (
<div className="MetricsSelect">
<SubTitle title={"Hide metrics from the UI"}/>
<div className="flex gaps">
<div className="flex gaps align-center">
{this.renderMetricsSelect()}
</div>
</div>

View File

@ -33,8 +33,7 @@ export class ClusterNameSetting extends React.Component<Props> {
render() {
return (
<>
<SubTitle title="Cluster Name" />
<p>Define cluster name.</p>
<SubTitle title="Name" />
<Input
theme="round-black"
validators={isRequired}

View File

@ -80,14 +80,14 @@ export class ClusterPrometheusSetting extends React.Component<Props> {
render() {
return (
<>
<SubTitle title="Prometheus"/>
<section id="prometheus">
<h2>Prometheus</h2>
<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>
<p>Prometheus installation method.</p>
<SubTitle title="Prometheus installation method"/>
<Select
value={this.provider}
onChange={({value}) => {
@ -113,7 +113,7 @@ export class ClusterPrometheusSetting extends React.Component<Props> {
</small>
</>
)}
</>
</section>
);
}
}

View File

@ -32,8 +32,7 @@ export class ClusterProxySetting extends React.Component<Props> {
render() {
return (
<>
<SubTitle title="HTTP Proxy" />
<p>HTTP Proxy server. Used for communicating with Kubernetes API.</p>
<SubTitle title="HTTP Proxy Server" />
<Input
theme="round-black"
value={this.proxy}
@ -42,6 +41,9 @@ export class ClusterProxySetting extends React.Component<Props> {
placeholder="http://<address>:<port>"
validators={this.proxy ? InputValidators.isUrl : undefined}
/>
<small className="hint">
Used to communicate with the Kubernetes API.
</small>
</>
);
}

View File

@ -14,10 +14,7 @@ export class ClusterWorkspaceSetting extends React.Component<Props> {
render() {
return (
<>
<SubTitle title="Cluster Workspace"/>
<p>
Define cluster workspace.
</p>
<SubTitle title="Workspace"/>
<Select
value={this.props.cluster.workspace}
onChange={({value}) => this.props.cluster.workspace = value}

View File

@ -0,0 +1,7 @@
.HiddenMetrics {
margin-top: -6px;
.Badge {
margin: 4px 0;
}
}

View File

@ -1,4 +1,4 @@
import "./cluster-metrics-setting.scss";
import "./hidden-metrics.scss";
import React from "react";
import { disposeOnUnmount, observer } from "mobx-react";
@ -12,7 +12,7 @@ interface Props {
}
@observer
export class ShowMetricsSetting extends React.Component<Props> {
export class HiddenMetrics extends React.Component<Props> {
@observable hiddenMetrics = observable.set<string>();
componentDidMount() {
@ -55,7 +55,7 @@ export class ShowMetricsSetting extends React.Component<Props> {
render() {
return (
<div className="MetricsSelect flex wrap gaps">
<div className="HiddenMetrics flex wrap gaps">
{this.renderMetrics()}
</div>
);

View File

@ -30,7 +30,7 @@ export class RemoveClusterButton extends React.Component<Props> {
const { cluster } = this.props;
return (
<Button accent onClick={this.confirmRemoveCluster} className="button-area" disabled={cluster.isManaged}>
<Button accent onClick={this.confirmRemoveCluster} disabled={cluster.isManaged}>
Remove Cluster
</Button>
);

View File

@ -1,7 +1,6 @@
import React from "react";
import { Cluster } from "../../../main/cluster";
import { InstallFeature } from "./components/install-feature";
import { SubTitle } from "../layout/sub-title";
import { clusterFeatureRegistry } from "../../../extensions/registries/cluster-feature-registry";
interface Props {
@ -13,21 +12,21 @@ export class Features extends React.Component<Props> {
const { cluster } = this.props;
return (
<div>
<h2>Features</h2>
<section id="features">
<h1>Features</h1>
{
clusterFeatureRegistry
.getItems()
.map((f) => (
<InstallFeature key={f.title} cluster={cluster} feature={f.feature}>
<>
<SubTitle title={f.title} />
<section id={f.title}>
<h2>{f.title}</h2>
<p><f.components.Description /></p>
</>
</section>
</InstallFeature>
))
}
</div>
</section>
);
}
}

View File

@ -1,14 +1,12 @@
import React from "react";
import { Cluster } from "../../../main/cluster";
import { ClusterNameSetting } from "./components/cluster-name-setting";
import { ClusterWorkspaceSetting } from "./components/cluster-workspace-setting";
import { ClusterIconSetting } from "./components/cluster-icon-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";
import { ClusterHomeDirSetting } from "./components/cluster-home-dir-setting";
import { ClusterIconSetting } from "./components/cluster-icon-setting";
import { ClusterNameSetting } from "./components/cluster-name-setting";
import { ClusterProxySetting } from "./components/cluster-proxy-setting";
import { ClusterWorkspaceSetting } from "./components/cluster-workspace-setting";
interface Props {
cluster: Cluster;
@ -16,17 +14,30 @@ interface Props {
export class General extends React.Component<Props> {
render() {
return <div>
<h2>General</h2>
<ClusterNameSetting cluster={this.props.cluster} />
<ClusterWorkspaceSetting cluster={this.props.cluster} />
<ClusterIconSetting 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>;
return (
<section id="general" title="General">
<section>
<h1>General</h1>
</section>
<section id="cluster">
<h2>Cluster</h2>
<ClusterNameSetting cluster={this.props.cluster} />
<ClusterWorkspaceSetting cluster={this.props.cluster} />
<ClusterIconSetting cluster={this.props.cluster} />
</section>
<section id="proxy">
<h2>Proxy</h2>
<ClusterProxySetting cluster={this.props.cluster} />
</section>
<section id="terminal">
<h2>Terminal</h2>
<ClusterHomeDirSetting cluster={this.props.cluster} />
</section>
<section id="namespaces">
<h2>Namespaces</h2>
<ClusterAccessibleNamespaces cluster={this.props.cluster} />
</section>
</section>
);
}
}

View File

@ -0,0 +1,27 @@
import React from "react";
import { Cluster } from "../../../main/cluster";
import { ClusterMetricsSetting } from "./components/cluster-metrics-setting";
import { ClusterPrometheusSetting } from "./components/cluster-prometheus-setting";
import { HiddenMetrics } from "./components/hidden-metrics";
interface Props {
cluster: Cluster;
}
export function Metrics({ cluster }: Props) {
return (
<section id="metrics" title="Metrics">
<section>
<h1>Metrics</h1>
</section>
<ClusterPrometheusSetting cluster={cluster} />
<section id="hide-metrics">
<h2>Hide Metrics</h2>
<ClusterMetricsSetting cluster={cluster}/>
<HiddenMetrics cluster={cluster}/>
</section>
</section>
);
}

View File

@ -11,10 +11,12 @@ export class Removal extends React.Component<Props> {
const { cluster } = this.props;
return (
<div>
<h2>Removal</h2>
<RemoveClusterButton cluster={cluster} />
</div>
<section id="remove">
<h1>Removal</h1>
<div className="flex justify-flex-start">
<RemoveClusterButton cluster={cluster}/>
</div>
</section>
);
}
}

View File

@ -0,0 +1,26 @@
.Status {
.status-table {
margin-bottom: var(--spacing);
.Table {
border: 1px solid var(--borderFaintColor);
border-radius: $radius;
.TableRow {
&:not(:last-of-type) {
border-bottom: 1px solid var(--borderFaintColor);
}
.value {
flex-grow: 2;
word-break: break-word;
color: var(--textColorSecondary);
}
.link {
@include pseudo-link;
}
}
}
}
}

View File

@ -1,6 +1,7 @@
import "./status.scss";
import React from "react";
import { Cluster } from "../../../main/cluster";
import { SubTitle } from "../layout/sub-title";
import { Table, TableCell, TableRow } from "../table";
import { autobind } from "../../utils";
import { shell } from "electron";
@ -47,15 +48,16 @@ export class Status extends React.Component<Props> {
}
render() {
return <div>
<h2>Status</h2>
<SubTitle title="Cluster Status"/>
<p>
Cluster status information including: detected distribution, kernel version, and online status.
</p>
<div className="status-table">
{this.renderStatusRows()}
</div>
</div>;
return (
<section id="status" className="Status">
<h1>Status</h1>
<p>
Cluster status information including: detected distribution, kernel version, and online status.
</p>
<div className="status-table">
{this.renderStatusRows()}
</div>
</section>
);
}
}