mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
refactoring & fixes
Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
parent
2054f38d08
commit
3a115ae485
@ -153,10 +153,8 @@ export class Cluster implements ClusterModel {
|
||||
|
||||
@action
|
||||
async refresh() {
|
||||
logger.info(`[CLUSTER]: refreshing status`, this.getMeta());
|
||||
const connectionStatus = await this.getConnectionStatus();
|
||||
this.online = connectionStatus > ClusterStatus.Offline;
|
||||
this.accessible = connectionStatus == ClusterStatus.AccessGranted;
|
||||
logger.info(`[CLUSTER]: refresh`, this.getMeta());
|
||||
await this.refreshConnectionStatus();
|
||||
if (this.accessible) {
|
||||
this.kubeCtl = new Kubectl(this.version)
|
||||
this.distribution = this.detectKubernetesDistribution(this.version)
|
||||
@ -169,11 +167,18 @@ export class Cluster implements ClusterModel {
|
||||
this.features = features;
|
||||
this.isAdmin = isAdmin;
|
||||
this.nodes = nodesCount;
|
||||
await Promise.all([
|
||||
this.refreshEvents(),
|
||||
this.refreshAllowedResources(),
|
||||
]);
|
||||
}
|
||||
await Promise.all([
|
||||
this.refreshEvents(),
|
||||
this.refreshAllowedResources(),
|
||||
]);
|
||||
}
|
||||
|
||||
@action
|
||||
async refreshConnectionStatus() {
|
||||
const connectionStatus = await this.getConnectionStatus();
|
||||
this.online = connectionStatus > ClusterStatus.Offline;
|
||||
this.accessible = connectionStatus == ClusterStatus.AccessGranted;
|
||||
}
|
||||
|
||||
@action
|
||||
@ -219,7 +224,7 @@ export class Cluster implements ClusterModel {
|
||||
const apiUrl = this.kubeProxyUrl + path;
|
||||
return request(apiUrl, {
|
||||
json: true,
|
||||
timeout: 10000,
|
||||
timeout: 5000,
|
||||
headers: {
|
||||
...(options.headers || {}),
|
||||
Host: new URL(this.webContentUrl).host,
|
||||
@ -442,6 +447,9 @@ export class Cluster implements ClusterModel {
|
||||
{ resource: "storageclasses", group: "storage.k8s.io" },
|
||||
]
|
||||
try {
|
||||
if (!this.allowedNamespaces.length) {
|
||||
return [];
|
||||
}
|
||||
const resourceAccessStatuses = await Promise.all(
|
||||
apiResources.map(apiResource => this.canI({
|
||||
resource: apiResource.resource,
|
||||
|
||||
@ -5,7 +5,7 @@ import type { Cluster } from "./cluster"
|
||||
import { bundledKubectl, Kubectl } from "./kubectl"
|
||||
import logger from "./logger"
|
||||
|
||||
export interface KubeAuthProxyResponse {
|
||||
export interface KubeAuthProxyLog {
|
||||
data: string;
|
||||
error?: boolean; // stream=stderr
|
||||
}
|
||||
@ -80,7 +80,7 @@ export class KubeAuthProxy {
|
||||
return errorMsg
|
||||
}
|
||||
|
||||
protected async sendIpcLogMessage(res: KubeAuthProxyResponse) {
|
||||
protected async sendIpcLogMessage(res: KubeAuthProxyLog) {
|
||||
const channel = `kube-auth:${this.cluster.id}`
|
||||
logger.info(`[KUBE-AUTH]: out-channel "${channel}"`, { ...res, meta: this.cluster.getMeta() });
|
||||
broadcastIpc({
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import "./nodes.scss";
|
||||
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { RouteComponentProps } from "react-router";
|
||||
@ -15,7 +14,7 @@ import { NodeMenu } from "./node-menu";
|
||||
import { LineProgress } from "../line-progress";
|
||||
import { _i18n } from "../../i18n";
|
||||
import { bytesToUnits } from "../../utils/convertMemory";
|
||||
import { Tooltip } from "../tooltip";
|
||||
import { Tooltip, TooltipPosition } from "../tooltip";
|
||||
import kebabCase from "lodash/kebabCase";
|
||||
import upperFirst from "lodash/upperFirst";
|
||||
import { apiManager } from "../../api/api-manager";
|
||||
@ -57,7 +56,10 @@ export class Nodes extends React.Component<Props> {
|
||||
<LineProgress
|
||||
max={cores}
|
||||
value={usage}
|
||||
tooltip={_i18n._(t`CPU:`) + ` ${Math.ceil(usage * 100) / cores}\%, ` + _i18n._(t`cores:`) + ` ${cores}`}
|
||||
tooltip={{
|
||||
position: TooltipPosition.BOTTOM,
|
||||
children: _i18n._(t`CPU:`) + ` ${Math.ceil(usage * 100) / cores}\%, ` + _i18n._(t`cores:`) + ` ${cores}`
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@ -71,7 +73,10 @@ export class Nodes extends React.Component<Props> {
|
||||
<LineProgress
|
||||
max={capacity}
|
||||
value={usage}
|
||||
tooltip={_i18n._(t`Memory:`) + ` ${Math.ceil(usage * 100 / capacity)}%, ${bytesToUnits(usage, 3)}`}
|
||||
tooltip={{
|
||||
position: TooltipPosition.BOTTOM,
|
||||
children: _i18n._(t`Memory:`) + ` ${Math.ceil(usage * 100 / capacity)}%, ${bytesToUnits(usage, 3)}`
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@ -85,7 +90,10 @@ export class Nodes extends React.Component<Props> {
|
||||
<LineProgress
|
||||
max={capacity}
|
||||
value={usage}
|
||||
tooltip={_i18n._(t`Disk:`) + ` ${Math.ceil(usage * 100 / capacity)}%, ${bytesToUnits(usage, 3)}`}
|
||||
tooltip={{
|
||||
position: TooltipPosition.BOTTOM,
|
||||
children: _i18n._(t`Disk:`) + ` ${Math.ceil(usage * 100 / capacity)}%, ${bytesToUnits(usage, 3)}`
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@ -51,20 +51,19 @@ export class App extends React.Component {
|
||||
async componentDidMount() {
|
||||
if (this.cluster) {
|
||||
await clusterIpc.activate.invokeFromRenderer(); // refresh state, reconnect, etc.
|
||||
disposeOnUnmount(this, [
|
||||
reaction(() => this.cluster.accessible, this.onClusterAccessChange, {
|
||||
fireImmediately: true
|
||||
})
|
||||
])
|
||||
}
|
||||
disposeOnUnmount(this, [
|
||||
reaction(() => this.startURL, this.onStartUrlChange, {
|
||||
fireImmediately: true
|
||||
})
|
||||
])
|
||||
this.isReady = true;
|
||||
}
|
||||
|
||||
protected onStartUrlChange = (startURL: string) => {
|
||||
protected onClusterAccessChange = (accessible: boolean) => {
|
||||
const path = navigation.getPath();
|
||||
const redirectRequired = ["/", clusterStatusURL()].includes(path);
|
||||
if (redirectRequired || !this.cluster?.accessible) {
|
||||
navigate(startURL);
|
||||
if (!accessible || path === "/") {
|
||||
navigate(this.startURL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,32 +1,40 @@
|
||||
import type { KubeAuthProxyResponse } from "../../../main/kube-auth-proxy";
|
||||
import type { KubeAuthProxyLog } from "../../../main/kube-auth-proxy";
|
||||
|
||||
import "./cluster-status.scss"
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { disposeOnUnmount, observer } from "mobx-react";
|
||||
import { ipcRenderer } from "electron";
|
||||
import { computed, observable } from "mobx";
|
||||
import { autorun, computed, observable } from "mobx";
|
||||
import { clusterIpc } from "../../../common/cluster-ipc";
|
||||
import { getHostedCluster } from "../../../common/cluster-store";
|
||||
import { Icon } from "../icon";
|
||||
import { Button } from "../button";
|
||||
import { cssNames } from "../../utils";
|
||||
import { navigate } from "../../navigation";
|
||||
|
||||
@observer
|
||||
export class ClusterStatus extends React.Component {
|
||||
@observable authOutput: KubeAuthProxyResponse[] = [];
|
||||
@observable authOutput: KubeAuthProxyLog[] = [];
|
||||
@observable isReconnecting = false;
|
||||
|
||||
@computed get hasErrors() {
|
||||
return this.authOutput.some(({ error }) => error)
|
||||
}
|
||||
|
||||
@computed get cluster() {
|
||||
return getHostedCluster();
|
||||
}
|
||||
|
||||
@computed get hasErrors(): boolean {
|
||||
return this.authOutput.some(({ error }) => error) || !!this.cluster.failureReason;
|
||||
}
|
||||
|
||||
@disposeOnUnmount
|
||||
autoRedirectToMain = autorun(() => {
|
||||
if (this.cluster.accessible && !this.hasErrors) {
|
||||
navigate("/");
|
||||
}
|
||||
})
|
||||
|
||||
async componentDidMount() {
|
||||
this.authOutput = [{ data: "Connecting..." }];
|
||||
ipcRenderer.on(`kube-auth:${this.cluster.id}`, (evt, res: KubeAuthProxyResponse) => {
|
||||
ipcRenderer.on(`kube-auth:${this.cluster.id}`, (evt, res: KubeAuthProxyLog) => {
|
||||
this.authOutput.push({
|
||||
data: res.data.trimRight(),
|
||||
error: res.error,
|
||||
@ -48,10 +56,11 @@ export class ClusterStatus extends React.Component {
|
||||
render() {
|
||||
const { authOutput, cluster, hasErrors } = this;
|
||||
const isDisconnected = !!cluster.disconnected;
|
||||
const isInactive = hasErrors || isDisconnected;
|
||||
const failureReason = cluster.failureReason;
|
||||
const isError = hasErrors || isDisconnected;
|
||||
return (
|
||||
<div className="ClusterStatus flex column gaps">
|
||||
{isInactive && (
|
||||
{isError && (
|
||||
<Icon
|
||||
material="cloud_off"
|
||||
className={cssNames({ error: hasErrors })}
|
||||
@ -67,7 +76,10 @@ export class ClusterStatus extends React.Component {
|
||||
})}
|
||||
</pre>
|
||||
)}
|
||||
{isInactive && (
|
||||
{failureReason && (
|
||||
<div className="failure-reason error">{failureReason}</div>
|
||||
)}
|
||||
{isError && (
|
||||
<Button
|
||||
primary
|
||||
label="Reconnect"
|
||||
|
||||
@ -6,13 +6,18 @@ import { observer } from "mobx-react";
|
||||
import { autobind, cssNames, IClassName } from "../../utils";
|
||||
import { observable } from "mobx";
|
||||
|
||||
export type TooltipPosition = "top" | "left" | "right" | "bottom";
|
||||
export enum TooltipPosition {
|
||||
TOP = "top",
|
||||
BOTTOM = "bottom",
|
||||
LEFT = "left",
|
||||
RIGHT = "right",
|
||||
}
|
||||
|
||||
export interface TooltipProps {
|
||||
targetId: string; // "id" of target html-element to bind
|
||||
visible?: boolean;
|
||||
offset?: number; // px
|
||||
usePortal?: boolean;
|
||||
targetId: string; // html-id of target element to bind for
|
||||
visible?: boolean; // initial visibility
|
||||
offset?: number; // offset from target element in pixels (all sides)
|
||||
usePortal?: boolean; // renders element outside of parent (in body), disable for "easy-styling", default: true
|
||||
position?: TooltipPosition;
|
||||
className?: IClassName;
|
||||
formatters?: TooltipContentFormatters;
|
||||
@ -71,7 +76,12 @@ export class Tooltip extends React.Component<TooltipProps> {
|
||||
const { position } = this.props;
|
||||
const { elem, targetElem } = this;
|
||||
|
||||
let allPositions: TooltipPosition[] = ["right", "bottom", "top", "left"];
|
||||
let allPositions: TooltipPosition[] = [
|
||||
TooltipPosition.RIGHT,
|
||||
TooltipPosition.BOTTOM,
|
||||
TooltipPosition.LEFT,
|
||||
TooltipPosition.RIGHT,
|
||||
];
|
||||
if (allPositions.includes(position)) {
|
||||
allPositions = [
|
||||
position, // put first as priority side for positioning
|
||||
|
||||
Loading…
Reference in New Issue
Block a user