mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
part 2
Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
parent
e5138e7c5d
commit
d04c8d3045
@ -156,11 +156,6 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
||||
this.activeClusterId = newClusters.has(activeCluster) ? activeCluster : null;
|
||||
this.clusters.replace(newClusters);
|
||||
this.removedClusters.replace(removedClusters);
|
||||
|
||||
// "auto-select" first cluster if available
|
||||
if (!this.activeClusterId && newClusters.size) {
|
||||
this.activeClusterId = Array.from(newClusters.values())[0].id;
|
||||
}
|
||||
}
|
||||
|
||||
toJSON(): ClusterStoreModel {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { action, computed, observable, reaction, toJS } from "mobx";
|
||||
import { action, computed, observable, toJS } from "mobx";
|
||||
import { BaseStore } from "./base-store";
|
||||
import { clusterStore } from "./cluster-store"
|
||||
|
||||
@ -22,15 +22,6 @@ export class WorkspaceStore extends BaseStore<WorkspaceStoreModel> {
|
||||
super({
|
||||
configName: "lens-workspace-store",
|
||||
});
|
||||
|
||||
// switch to first available cluster in current workspace
|
||||
reaction(() => this.currentWorkspaceId, workspaceId => {
|
||||
const clusters = clusterStore.getByWorkspaceId(workspaceId);
|
||||
const activeClusterInWorkspace = clusters.some(cluster => cluster.id === clusterStore.activeClusterId);
|
||||
if (!activeClusterInWorkspace) {
|
||||
clusterStore.activeClusterId = clusters.length ? clusters[0].id : null;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@observable currentWorkspaceId = WorkspaceStore.defaultId;
|
||||
|
||||
@ -67,11 +67,6 @@ export class Cluster implements ClusterModel {
|
||||
@observable allowedNamespaces: string[] = [];
|
||||
@observable allowedResources: string[] = [];
|
||||
|
||||
@computed get host() {
|
||||
const proxyHost = new URL(this.kubeProxyUrl).host;
|
||||
return `${this.id}.${proxyHost}`
|
||||
}
|
||||
|
||||
constructor(model: ClusterModel) {
|
||||
this.updateModel(model);
|
||||
}
|
||||
@ -223,7 +218,7 @@ export class Cluster implements ClusterModel {
|
||||
json: true,
|
||||
timeout: 5000,
|
||||
headers: {
|
||||
Host: this.host, // provide cluster-id for ClusterManager.getClusterForRequest()
|
||||
Host: `${this.id}.${new URL(this.kubeProxyUrl).host}`, // required in ClusterManager.getClusterForRequest()
|
||||
...(options.headers || {}),
|
||||
},
|
||||
})
|
||||
|
||||
@ -27,6 +27,7 @@ export class WindowManager {
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true,
|
||||
webviewTag: true,
|
||||
},
|
||||
});
|
||||
this.windowState.manage(this.mainView);
|
||||
|
||||
@ -1,32 +1,34 @@
|
||||
import "./cluster-manager.scss"
|
||||
import React from "react";
|
||||
import { Redirect, Route, Switch } from "react-router";
|
||||
import { observer } from "mobx-react";
|
||||
import { ClustersMenu } from "./clusters-menu";
|
||||
import { BottomBar } from "./bottom-bar";
|
||||
import { cssNames, IClassName } from "../../utils";
|
||||
import { ClusterId } from "../../../common/cluster-store";
|
||||
import { Route, Switch } from "react-router";
|
||||
import { LandingPage, landingRoute } from "../+landing-page";
|
||||
import { LandingPage, landingRoute, landingURL } from "../+landing-page";
|
||||
import { Preferences, preferencesRoute } from "../+preferences";
|
||||
import { Workspaces, workspacesRoute } from "../+workspaces";
|
||||
import { AddCluster, addClusterRoute } from "../+add-cluster";
|
||||
import { ClusterStatus } from "./cluster-status";
|
||||
import { clusterStatusRoute } from "./cluster-status.route";
|
||||
|
||||
interface Props {
|
||||
className?: IClassName;
|
||||
contentClass?: IClassName;
|
||||
}
|
||||
import { ClusterView } from "./cluster-view";
|
||||
import { clusterViewRoute, clusterViewURL } from "./cluster-view.route";
|
||||
import { clusterStore } from "../../../common/cluster-store";
|
||||
|
||||
@observer
|
||||
export class ClusterManager extends React.Component<Props> {
|
||||
activateView(clusterId: ClusterId) {
|
||||
export class ClusterManager extends React.Component {
|
||||
get startUrl() {
|
||||
const { activeClusterId } = clusterStore;
|
||||
if (activeClusterId) {
|
||||
return clusterViewURL({
|
||||
params: {
|
||||
clusterId: activeClusterId
|
||||
}
|
||||
})
|
||||
}
|
||||
return landingURL()
|
||||
}
|
||||
|
||||
render() {
|
||||
const { className } = this.props;
|
||||
return (
|
||||
<div className={cssNames("ClusterManager", className)}>
|
||||
<div className="ClusterManager">
|
||||
<div id="draggable-top"/>
|
||||
<div id="lens-view">
|
||||
<Switch>
|
||||
@ -34,8 +36,8 @@ export class ClusterManager extends React.Component<Props> {
|
||||
<Route component={Preferences} {...preferencesRoute}/>
|
||||
<Route component={Workspaces} {...workspacesRoute}/>
|
||||
<Route component={AddCluster} {...addClusterRoute}/>
|
||||
<Route component={ClusterStatus} {...clusterStatusRoute}/>
|
||||
<Route render={() => <p>Lens</p>}/>
|
||||
<Route component={ClusterView} {...clusterViewRoute}/>
|
||||
<Redirect exact from="/" to={this.startUrl}/>
|
||||
</Switch>
|
||||
</div>
|
||||
<ClustersMenu/>
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
import { RouteProps } from "react-router";
|
||||
import { buildURL } from "../../navigation";
|
||||
|
||||
export const clusterStatusRoute: RouteProps = {
|
||||
path: "/cluster-status"
|
||||
}
|
||||
|
||||
export const clusterStatusURL = buildURL(clusterStatusRoute.path)
|
||||
@ -2,37 +2,37 @@ import type { KubeAuthProxyLog } from "../../../main/kube-auth-proxy";
|
||||
|
||||
import "./cluster-status.scss"
|
||||
import React from "react";
|
||||
import { disposeOnUnmount, observer } from "mobx-react";
|
||||
import { observer } from "mobx-react";
|
||||
import { ipcRenderer } from "electron";
|
||||
import { autorun, computed, observable } from "mobx";
|
||||
import { computed, observable } from "mobx";
|
||||
import { clusterIpc } from "../../../common/cluster-ipc";
|
||||
import { Icon } from "../icon";
|
||||
import { Button } from "../button";
|
||||
import { cssNames } from "../../utils";
|
||||
import { navigate } from "../../navigation";
|
||||
import { Cluster } from "../../../main/cluster";
|
||||
import { ClusterId, clusterStore } from "../../../common/cluster-store";
|
||||
|
||||
interface Props {
|
||||
clusterId: ClusterId;
|
||||
}
|
||||
|
||||
@observer
|
||||
export class ClusterStatus extends React.Component {
|
||||
export class ClusterStatus extends React.Component<Props> {
|
||||
@observable authOutput: KubeAuthProxyLog[] = [];
|
||||
@observable isReconnecting = false;
|
||||
|
||||
// fixme
|
||||
@computed get clusterId() {
|
||||
return this.props.clusterId;
|
||||
}
|
||||
|
||||
@computed get cluster(): Cluster {
|
||||
return null;
|
||||
return clusterStore.getById(this.clusterId);
|
||||
}
|
||||
|
||||
@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() {
|
||||
if (this.cluster.disconnected) {
|
||||
return;
|
||||
@ -48,11 +48,11 @@ export class ClusterStatus extends React.Component {
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
ipcRenderer.removeAllListeners(`kube-auth:${this.cluster.id}`);
|
||||
ipcRenderer.removeAllListeners(`kube-auth:${this.clusterId}`);
|
||||
}
|
||||
|
||||
async refreshClusterState() {
|
||||
return clusterIpc.activate.invokeFromRenderer();
|
||||
return clusterIpc.activate.invokeFromRenderer(this.clusterId);
|
||||
}
|
||||
|
||||
reconnect = async () => {
|
||||
|
||||
@ -0,0 +1,22 @@
|
||||
import { matchPath, RouteProps } from "react-router";
|
||||
import { buildURL, navigation } from "../../navigation";
|
||||
|
||||
export interface IClusterViewRouteParams {
|
||||
clusterId: string;
|
||||
}
|
||||
|
||||
export const clusterViewRoute: RouteProps = {
|
||||
path: "/cluster/:clusterId"
|
||||
}
|
||||
|
||||
export const clusterViewURL = buildURL<IClusterViewRouteParams>(clusterViewRoute.path)
|
||||
|
||||
export function getMatchedClusterId(): string {
|
||||
const matched = matchPath<IClusterViewRouteParams>(navigation.location.pathname, {
|
||||
...clusterViewRoute,
|
||||
exact: true,
|
||||
})
|
||||
if (matched) {
|
||||
return matched.params.clusterId;
|
||||
}
|
||||
}
|
||||
10
src/renderer/components/cluster-manager/cluster-view.scss
Normal file
10
src/renderer/components/cluster-manager/cluster-view.scss
Normal file
@ -0,0 +1,10 @@
|
||||
.ClusterView {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
//display: none;
|
||||
|
||||
&.loaded {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
46
src/renderer/components/cluster-manager/cluster-view.tsx
Normal file
46
src/renderer/components/cluster-manager/cluster-view.tsx
Normal file
@ -0,0 +1,46 @@
|
||||
import React from "react";
|
||||
import { autorun, computed, observable } from "mobx";
|
||||
import { disposeOnUnmount, observer } from "mobx-react";
|
||||
import { ClusterId, clusterStore } from "../../../common/cluster-store";
|
||||
import { getMatchedClusterId } from "./cluster-view.route";
|
||||
import { Cluster } from "../../../main/cluster";
|
||||
|
||||
@observer
|
||||
export class ClusterView extends React.Component {
|
||||
static views = observable.map<ClusterId, /*HTMLIFrameElement*/ any>()
|
||||
static isLoaded = observable.map<ClusterId, boolean>()
|
||||
|
||||
@computed get cluster() {
|
||||
return clusterStore.getById(getMatchedClusterId())
|
||||
}
|
||||
|
||||
@computed get clusterView() {
|
||||
return ClusterView.views.get(this.cluster?.id)
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
disposeOnUnmount(this, [
|
||||
autorun(() => this.activateView(this.cluster))
|
||||
])
|
||||
}
|
||||
|
||||
activateView = (cluster: Cluster) => {
|
||||
if (!cluster || ClusterView.views.has(cluster.id)) {
|
||||
return;
|
||||
}
|
||||
const view = document.createElement("webview");
|
||||
view.className = "ClusterView"
|
||||
view.src = `${location.protocol}://${cluster.id}.${location.host}`
|
||||
view.onload = () => console.log('CLUSTER VIEW READY!', cluster);
|
||||
document.body.appendChild(view);
|
||||
ClusterView.views.set(cluster.id, view);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { cluster } = this;
|
||||
if (cluster && cluster.accessible) {
|
||||
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@ -20,7 +20,7 @@ import { landingURL } from "../+landing-page";
|
||||
import { Tooltip } from "../tooltip";
|
||||
import { ConfirmDialog } from "../confirm-dialog";
|
||||
import { clusterIpc } from "../../../common/cluster-ipc";
|
||||
import { clusterStatusURL } from "./cluster-status.route";
|
||||
import { clusterViewURL, getMatchedClusterId } from "./cluster-view.route";
|
||||
|
||||
// fixme: allow to rearrange clusters with drag&drop
|
||||
|
||||
@ -32,12 +32,9 @@ interface Props {
|
||||
export class ClustersMenu extends React.Component<Props> {
|
||||
@observable showHint = true;
|
||||
|
||||
showCluster = (clusterId: ClusterId) => {
|
||||
if (clusterStore.activeClusterId === clusterId) {
|
||||
navigate("/"); // redirect to index
|
||||
} else {
|
||||
clusterStore.activeClusterId = clusterId;
|
||||
}
|
||||
activateCluster = (clusterId: ClusterId) => {
|
||||
clusterStore.activeClusterId = clusterId;
|
||||
navigate(clusterViewURL({ params: { clusterId } }))
|
||||
}
|
||||
|
||||
addCluster = () => {
|
||||
@ -57,9 +54,6 @@ export class ClustersMenu extends React.Component<Props> {
|
||||
label: _i18n._(t`Disconnect`),
|
||||
click: async () => {
|
||||
await clusterIpc.disconnect.invokeFromRenderer(cluster.id);
|
||||
if (cluster.id === clusterStore.activeClusterId) {
|
||||
navigate(clusterStatusURL());
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
@ -110,8 +104,8 @@ export class ClustersMenu extends React.Component<Props> {
|
||||
key={cluster.id}
|
||||
showErrors={true}
|
||||
cluster={cluster}
|
||||
isActive={cluster.id === clusterStore.activeClusterId}
|
||||
onClick={() => this.showCluster(cluster.id)}
|
||||
isActive={cluster.id === getMatchedClusterId()}
|
||||
onClick={() => this.activateCluster(cluster.id)}
|
||||
onContextMenu={() => this.showContextMenu(cluster)}
|
||||
/>
|
||||
)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user