fix reconnect, better handling no-clusters state

Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
Roman committed 2020-07-24 14:17:14 +03:00
1 parent 0490dc1d12
commit 408f64c184
12 files changed
+145 -138

No files matched your search

+16 -16
View File
@@ -1,7 +1,7 @@
import "./app.scss";
import React from "react";
import { disposeOnUnmount, observer } from "mobx-react";
import { computed, observable, reaction } from "mobx";
import { autorun, computed, observable } from "mobx";
import { Redirect, Route, Switch } from "react-router";
import { Notifications } from "./notifications";
import { NotFound } from "./+404";
@@ -28,45 +28,45 @@ import { CustomResources } from "./+custom-resources/custom-resources";
import { crdRoute } from "./+custom-resources";
import { isAllowedResource } from "../api/rbac";
import { AddCluster, addClusterRoute } from "./+add-cluster";
import { LandingPage, landingRoute, landingURL } from "./+landing-page";
import { LandingPage, landingRoute } from "./+landing-page";
import { ClusterSettings, clusterSettingsRoute } from "./+cluster-settings";
import { Workspaces, workspacesRoute } from "./+workspaces";
import { ErrorBoundary } from "./error-boundary";
import { navigation } from "../navigation";
import { clusterIpc } from "../../common/cluster-ipc";
import { clusterStore } from "../../common/cluster-store";
import { getHostedCluster } from "../../common/cluster-store";
import { clusterStatusRoute, clusterStatusURL } from "./cluster-manager/cluster-status.route";
import { Preferences, preferencesRoute } from "./+preferences";
import { ClusterStatus } from "./cluster-manager/cluster-status";
import { CubeSpinner } from "./spinner";
import { navigate, navigation } from "../navigation";
@observer
export class App extends React.Component {
@observable isReady = false;
@computed get clusterReady() {
const clusterId = location.hostname.split(".")[0];
return !!clusterStore.getById(clusterId)?.isReady;
@computed get clusterReady(): boolean {
const cluster = getHostedCluster();
if (cluster) {
return cluster.initialized && cluster.accessible;
}
}
async componentDidMount() {
await clusterIpc.activate.invokeFromRenderer();
await clusterIpc.activate.invokeFromRenderer(); // refresh state, reconnect, etc.
this.isReady = true;
disposeOnUnmount(this, [
reaction(() => this.startURL, url => {
const redirect = !this.clusterReady || !clusterStore.hasClusters();
if (redirect) navigation.replace(url);
}, {
fireImmediately: true
autorun(() => {
if (!this.clusterReady) {
navigate(clusterStatusURL());
} else if (clusterStatusURL() == navigation.getPath()) {
navigate("/"); // redirect when cluster accessible
}
})
])
}
get startURL() {
if (!clusterStore.hasClusters()) {
return landingURL();
}
if (!this.clusterReady) {
return clusterStatusURL();
}
@@ -1,65 +1,76 @@
import type { KubeAuthProxyResponse } from "../../../main/kube-auth-proxy";
import "./cluster-status.scss"
import React from "react";
import type { KubeAuthProxyResponse } from "../../../main/kube-auth-proxy";
import { clusterStore } from "../../../common/cluster-store";
import { ipcRenderer } from "electron";
import { observable } from "mobx";
import { observer } from "mobx-react";
import { ipcRenderer } from "electron";
import { 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 { clusterIpc } from "../../../common/cluster-ipc";
@observer
export class ClusterStatus extends React.Component {
@observable authOutput: string[] = [];
@observable hasErrors = false;
@observable authOutput: KubeAuthProxyResponse[] = [];
@observable isReconnecting = false;
get cluster() {
return clusterStore.activeCluster;
@computed get hasErrors() {
return this.authOutput.some(({ error }) => error)
}
get clusterId() {
return clusterStore.activeClusterId;
@computed get cluster() {
return getHostedCluster()
}
componentDidMount() {
this.authOutput = ["Connecting ...\n"];
ipcRenderer.on(`kube-auth:${this.clusterId}`, (evt, { data, stream }: KubeAuthProxyResponse) => {
this.authOutput.push(`[${stream}]: ${data}`);
if (stream === "stderr") {
this.hasErrors = true;
}
async componentDidMount() {
this.authOutput = [{ data: "Connecting ...\n" }];
ipcRenderer.on(`kube-auth:${this.cluster.id}`, (evt, res) => {
this.authOutput.push(res);
})
}
componentWillUnmount() {
ipcRenderer.removeAllListeners(`kube-auth:${this.clusterId}`);
ipcRenderer.removeAllListeners(`kube-auth:${this.cluster.id}`);
}
reconnect = () => {
this.authOutput = ["Reconnecting ...\n"];
clusterIpc.reconnect.invokeFromRenderer(this.clusterId);
reconnect = async () => {
this.authOutput = [{ data: "Reconnecting ...\n" }];
this.isReconnecting = true;
await clusterIpc.activate.invokeFromRenderer();
this.isReconnecting = false;
}
render() {
const { authOutput, cluster, hasErrors } = this;
const isDisconnected = !!cluster.disconnected;
const isInactive = hasErrors || isDisconnected;
return (
<div className="ClusterStatus flex column gaps">
{!hasErrors && <Icon material="cloud_queue"/>}
{hasErrors && <Icon material="cloud_off" className="error"/>}
{cluster && <h2>{cluster.contextName}</h2>}
<pre className="kube-auth-out">
{authOutput.map((data, index) => {
const error = data.startsWith("[stderr]");
return <p key={index} className={cssNames({ error })}>{data}</p>
})}
</pre>
{hasErrors && (
{isInactive && (
<Icon
material="cloud_off"
className={cssNames({ error: hasErrors })}
/>
)}
<h2>
{cluster.contextName}
</h2>
{!isDisconnected && (
<pre className="kube-auth-out">
{authOutput.map(({ data, error }, index) => {
return <p key={index} className={cssNames({ error })}>{data}</p>
})}
</pre>
)}
{isInactive && (
<Button
primary className="box center"
primary
label="Reconnect"
className="box center"
onClick={this.reconnect}
waiting={this.isReconnecting}
/>
)}
</div>
@@ -20,6 +20,7 @@ import { landingURL } from "../+landing-page";
import { Tooltip, TooltipContent } from "../tooltip";
import { ConfirmDialog } from "../confirm-dialog";
import { clusterIpc } from "../../../common/cluster-ipc";
import { clusterStatusURL } from "./cluster-status.route";
// fixme: allow to rearrange clusters with drag&drop
@@ -54,9 +55,9 @@ export class ClustersMenu extends React.Component<Props> {
if (cluster.online) {
menu.append(new MenuItem({
label: _i18n._(t`Disconnect`),
click: () => {
navigate(landingURL());
clusterIpc.disconnect.invokeFromRenderer();
click: async () => {
await clusterIpc.disconnect.invokeFromRenderer();
navigate(clusterStatusURL());
}
}))
}