diff --git a/src/main/cluster.ts b/src/main/cluster.ts index 8e399375e3..f7b0735039 100644 --- a/src/main/cluster.ts +++ b/src/main/cluster.ts @@ -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, diff --git a/src/main/kube-auth-proxy.ts b/src/main/kube-auth-proxy.ts index d756123870..6079c00347 100644 --- a/src/main/kube-auth-proxy.ts +++ b/src/main/kube-auth-proxy.ts @@ -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({ diff --git a/src/renderer/components/+nodes/nodes.tsx b/src/renderer/components/+nodes/nodes.tsx index 2320219d34..e2d67a5870 100644 --- a/src/renderer/components/+nodes/nodes.tsx +++ b/src/renderer/components/+nodes/nodes.tsx @@ -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 { ) } @@ -71,7 +73,10 @@ export class Nodes extends React.Component { ) } @@ -85,7 +90,10 @@ export class Nodes extends React.Component { ) } diff --git a/src/renderer/components/app.tsx b/src/renderer/components/app.tsx index c9a1f2c1ce..ef41b4b7e2 100755 --- a/src/renderer/components/app.tsx +++ b/src/renderer/components/app.tsx @@ -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); } } diff --git a/src/renderer/components/cluster-manager/cluster-status.tsx b/src/renderer/components/cluster-manager/cluster-status.tsx index 7be7bd7836..0cfe81f724 100644 --- a/src/renderer/components/cluster-manager/cluster-status.tsx +++ b/src/renderer/components/cluster-manager/cluster-status.tsx @@ -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 (
- {isInactive && ( + {isError && ( )} - {isInactive && ( + {failureReason && ( +
{failureReason}
+ )} + {isError && (