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

added more routes, refactoring

Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
Roman 2020-07-15 14:09:31 +03:00
parent e5aff1fdc8
commit d20e61b3e2
22 changed files with 119 additions and 58 deletions

View File

@ -25,14 +25,14 @@ export function broadcastMessage({ channel, filter }: IpcBroadcastOpts, ...args:
filter = webContent => webContent.getType() === "window" filter = webContent => webContent.getType() === "window"
} }
webContents.getAllWebContents().filter(filter).forEach(webContent => { webContents.getAllWebContents().filter(filter).forEach(webContent => {
logger.info(`[IPC]: broadcasting ${channel} to ${webContent.getType()}=${webContent.id}`); logger.debug(`[IPC]: broadcasting ${channel} to ${webContent.getType()}=${webContent.id}`);
webContent.send(channel, ...args); webContent.send(channel, ...args);
}) })
} }
// fixme: support timeout // todo: support timeout
export async function invokeMessage<T = any>(channel: IpcChannel, ...args: any[]): Promise<T> { export async function invokeMessage<T = any>(channel: IpcChannel, ...args: any[]): Promise<T> {
logger.info(`[IPC]: invoke channel "${channel}"`, { args }); logger.debug(`[IPC]: invoke channel "${channel}"`, { args });
return ipcRenderer.invoke(channel, ...args); return ipcRenderer.invoke(channel, ...args);
} }

View File

@ -24,7 +24,7 @@ export class WorkspaceStore extends BaseStore<WorkspaceStoreModel> {
}); });
} }
@observable currentWorkspace = WorkspaceStore.defaultId; @observable currentWorkspaceId = WorkspaceStore.defaultId;
@observable workspaces = observable.map<WorkspaceId, Workspace>({ @observable workspaces = observable.map<WorkspaceId, Workspace>({
[WorkspaceStore.defaultId]: { [WorkspaceStore.defaultId]: {
@ -33,6 +33,10 @@ export class WorkspaceStore extends BaseStore<WorkspaceStoreModel> {
} }
}); });
@computed get currentWorkspace(): Workspace {
return this.getById(this.currentWorkspaceId);
}
@computed get workspacesList() { @computed get workspacesList() {
return Array.from(this.workspaces.values()); return Array.from(this.workspaces.values());
} }
@ -41,12 +45,6 @@ export class WorkspaceStore extends BaseStore<WorkspaceStoreModel> {
return this.workspaces.get(id); return this.workspaces.get(id);
} }
@action
setCurrent(id: WorkspaceId) {
if (!this.getById(id)) return;
this.currentWorkspace = id;
}
@action @action
public saveWorkspace(workspace: Workspace) { public saveWorkspace(workspace: Workspace) {
const id = workspace.id; const id = workspace.id;
@ -65,8 +63,8 @@ export class WorkspaceStore extends BaseStore<WorkspaceStoreModel> {
if (id === WorkspaceStore.defaultId) { if (id === WorkspaceStore.defaultId) {
throw new Error("Cannot remove default workspace"); throw new Error("Cannot remove default workspace");
} }
if (id === this.currentWorkspace) { if (id === this.currentWorkspaceId) {
this.currentWorkspace = WorkspaceStore.defaultId; this.currentWorkspaceId = WorkspaceStore.defaultId;
} }
this.workspaces.delete(id); this.workspaces.delete(id);
clusterStore.removeByWorkspaceId(id) clusterStore.removeByWorkspaceId(id)
@ -75,7 +73,7 @@ export class WorkspaceStore extends BaseStore<WorkspaceStoreModel> {
@action @action
protected fromStore({ currentWorkspace, workspaces = [] }: WorkspaceStoreModel) { protected fromStore({ currentWorkspace, workspaces = [] }: WorkspaceStoreModel) {
if (currentWorkspace) { if (currentWorkspace) {
this.currentWorkspace = currentWorkspace this.currentWorkspaceId = currentWorkspace
} }
if (workspaces.length) { if (workspaces.length) {
this.workspaces.clear(); this.workspaces.clear();
@ -87,7 +85,7 @@ export class WorkspaceStore extends BaseStore<WorkspaceStoreModel> {
toJSON(): WorkspaceStoreModel { toJSON(): WorkspaceStoreModel {
return toJS({ return toJS({
currentWorkspace: this.currentWorkspace, currentWorkspace: this.currentWorkspaceId,
workspaces: this.workspacesList, workspaces: this.workspacesList,
}, { }, {
recurseEverything: true recurseEverything: true

View File

@ -1,11 +1,11 @@
import "./add-cluster.scss" import "./add-cluster.scss"
import React from "react"; import React from "react";
import { observable } from "mobx"; import { observer } from "mobx-react";
interface Props { interface Props {
} }
@observable @observer
export class AddCluster extends React.Component<Props> { export class AddCluster extends React.Component<Props> {
render() { render() {
return ( return (

View File

@ -0,0 +1,8 @@
import { RouteProps } from "react-router";
import { buildURL } from "../../navigation";
export const clusterSettingsRoute: RouteProps = {
path: "/cluster-settings"
}
export const clusterSettingsURL = buildURL(clusterSettingsRoute.path)

View File

@ -1,9 +1,8 @@
import "./cluster-settings.scss" import "./cluster-settings.scss"
import React from "react"; import React from "react";
import { observer } from "mobx-react";
interface Props { @observer
}
export class ClusterSettings extends React.Component { export class ClusterSettings extends React.Component {
render() { render() {
return ( return (

View File

@ -1 +1,2 @@
export * from "./cluster-settings.route"
export * from "./cluster-settings" export * from "./cluster-settings"

View File

@ -0,0 +1 @@
export * from "./landing-page"

View File

@ -1,9 +1,8 @@
import "./landing-page.scss" import "./landing-page.scss"
import React from "react"; import React from "react";
import { observer } from "mobx-react";
interface Props { @observer
}
export class LandingPage extends React.Component { export class LandingPage extends React.Component {
render() { render() {
return ( return (

View File

@ -0,0 +1,2 @@
export * from "./preferences.route"
export * from "./preferences"

View File

@ -0,0 +1,8 @@
import { RouteProps } from "react-router";
import { buildURL } from "../../navigation";
export const preferencesRoute: RouteProps = {
path: "/preferences"
}
export const preferencesURL = buildURL(preferencesRoute.path)

View File

@ -1,9 +1,8 @@
import "./preferences.scss" import "./preferences.scss"
import React from "react"; import React from "react";
import { observer } from "mobx-react";
interface Props { @observer
}
export class Preferences extends React.Component { export class Preferences extends React.Component {
render() { render() {
return ( return (

View File

@ -0,0 +1,2 @@
export * from "./whats-new.route"
export * from "./whats-new"

View File

@ -0,0 +1,8 @@
import { RouteProps } from "react-router";
import { buildURL } from "../../navigation";
export const whatsNewRoute: RouteProps = {
path: "/what-s-new"
}
export const whatsNewURL = buildURL(whatsNewRoute.path)

View File

@ -1,9 +1,8 @@
import "./whats-new.scss" import "./whats-new.scss"
import React from "react"; import React from "react";
import { observer } from "mobx-react";
interface Props { @observer
}
export class WhatsNew extends React.Component { export class WhatsNew extends React.Component {
render() { render() {
return ( return (

View File

@ -1 +1,2 @@
export * from "./workspaces.route"
export * from "./workspaces" export * from "./workspaces"

View File

@ -0,0 +1,8 @@
import { RouteProps } from "react-router";
import { buildURL } from "../../navigation";
export const workspacesRoute: RouteProps = {
path: "/workspaces"
}
export const workspacesURL = buildURL(workspacesRoute.path)

View File

@ -1,6 +1,8 @@
import "./workspaces.scss" import "./workspaces.scss"
import React from "react"; import React from "react";
import { observer } from "mobx-react";
@observer
export class Workspaces extends React.Component { export class Workspaces extends React.Component {
render() { render() {
return ( return (

View File

@ -1,6 +1,7 @@
import "./app.scss"; import "./app.scss";
import React, { Fragment } from "react"; import React, { Fragment } from "react";
import { observer } from "mobx-react";
import { i18nStore } from "../i18n"; import { i18nStore } from "../i18n";
import { configStore } from "../config.store"; import { configStore } from "../config.store";
import { Terminal } from "./dock/terminal"; import { Terminal } from "./dock/terminal";
@ -29,7 +30,12 @@ import { DeploymentScaleDialog } from "./+workloads-deployments/deployment-scale
import { CustomResources } from "./+custom-resources/custom-resources"; import { CustomResources } from "./+custom-resources/custom-resources";
import { crdRoute } from "./+custom-resources"; import { crdRoute } from "./+custom-resources";
import { isAllowedResource } from "../api/rbac"; import { isAllowedResource } from "../api/rbac";
import { AddCluster, addClusterRoute } from "./+add-cluster";
import { LandingPage } from "./+landing-page";
import { clusterStore } from "../../common/cluster-store";
import { ClusterSettings, clusterSettingsRoute } from "./+cluster-settings";
@observer
export class App extends React.Component { export class App extends React.Component {
static rootElem = document.getElementById('app'); static rootElem = document.getElementById('app');
@ -40,11 +46,15 @@ export class App extends React.Component {
} }
render() { render() {
const showLanding = clusterStore.clusters.size === 0;
const homeUrl = isAllowedResource(["events", "nodes", "pods"]) ? clusterURL() : workloadsURL(); const homeUrl = isAllowedResource(["events", "nodes", "pods"]) ? clusterURL() : workloadsURL();
return ( return (
<Fragment> <Fragment>
<Switch> <Switch>
<Switch> <Switch>
{showLanding && <Route component={LandingPage}/>}
<Route component={AddCluster} {...addClusterRoute}/>
<Route component={ClusterSettings} {...clusterSettingsRoute}/>
<Route component={Cluster} {...clusterRoute}/> <Route component={Cluster} {...clusterRoute}/>
<Route component={Nodes} {...nodesRoute}/> <Route component={Nodes} {...nodesRoute}/>
<Route component={Workloads} {...workloadsRoute}/> <Route component={Workloads} {...workloadsRoute}/>

View File

@ -1,10 +1,13 @@
.BottomBar { .BottomBar {
$spacing: $padding / 2;
font-size: $font-size-small; font-size: $font-size-small;
background-color: #3d90ce; background-color: #3d90ce;
padding: $padding / 2 $padding; padding: $spacing $padding;
color: white; color: white;
#workspace { #current-workspace {
--flex-gap: #{$spacing};
cursor: pointer; cursor: pointer;
} }
} }

View File

@ -1,5 +1,4 @@
import "./bottom-bar.scss" import "./bottom-bar.scss"
import React from "react"; import React from "react";
import { observable } from "mobx"; import { observable } from "mobx";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
@ -7,41 +6,47 @@ import { Link } from "react-router-dom";
import { Trans } from "@lingui/macro"; import { Trans } from "@lingui/macro";
import { Icon } from "../icon"; import { Icon } from "../icon";
import { Menu, MenuItem } from "../menu"; import { Menu, MenuItem } from "../menu";
import { prevDefault } from "../../utils"; import { WorkspaceId, workspaceStore } from "../../../common/workspace-store";
import { workspaceStore } from "../../../common/workspace-store"; import { workspacesURL } from "../+workspaces";
// todo: remove dummy actions + console.log
@observer @observer
export class BottomBar extends React.Component { export class BottomBar extends React.Component {
@observable menuVisible = false; @observable menuVisible = false;
selectWorkspace = (workspaceId: WorkspaceId) => {
workspaceStore.currentWorkspaceId = workspaceId;
}
render() { render() {
const { currentWorkspace, workspacesList } = workspaceStore; const { currentWorkspace, workspacesList } = workspaceStore;
const menuId = "workspaces-menu"
return ( return (
<div className="BottomBar flex gaps"> <div className="BottomBar flex gaps">
<div id="workspace" className="workspace flex align-center box right"> <div id="current-workspace" className="flex gaps align-center box right">
<Icon small material="layers"/> {currentWorkspace} <Icon small material="layers"/>
<span className="workspace-name">{currentWorkspace.name}</span>
</div> </div>
<Menu <Menu
usePortal usePortal
htmlFor="workspace"
id="workspace-menu" id="workspace-menu"
htmlFor="current-workspace"
isOpen={this.menuVisible} isOpen={this.menuVisible}
open={() => this.menuVisible = true} open={() => this.menuVisible = true}
close={() => this.menuVisible = false} close={() => this.menuVisible = false}
> >
<Link <Link className="workspaces-title" to={workspacesURL()}>
to="#"
className="workspaces-title"
onClick={prevDefault(() => console.log('/navigate: workspaces page'))}>
<Trans>Workspaces</Trans> <Trans>Workspaces</Trans>
</Link> </Link>
{workspacesList.map(workspace => { {workspacesList.map(({ id, name, description }) => {
const { id, name, description } = workspace;
return ( return (
<MenuItem key={id} onClick={() => console.log(`navigate: /workspaces/${id}`)} title={description}> <MenuItem
<Icon small material="layers"/> {name} key={id}
active={id === currentWorkspace.id}
onClick={() => this.selectWorkspace(id)}
title={description}
>
<Icon small material="layers"/>
<span className="workspace">{name}</span>
</MenuItem> </MenuItem>
) )
})} })}

View File

@ -13,7 +13,7 @@ export interface ClusterContextValue {
export function getClusterContext(): ClusterContextValue { export function getClusterContext(): ClusterContextValue {
return { return {
clusterId: clusterStore.activeClusterId, clusterId: clusterStore.activeClusterId,
workspaceId: workspaceStore.currentWorkspace, workspaceId: workspaceStore.currentWorkspaceId,
} }
} }

View File

@ -6,12 +6,15 @@ import { _i18n } from "../../i18n";
import { t, Trans } from "@lingui/macro"; import { t, Trans } from "@lingui/macro";
import type { Cluster } from "../../../main/cluster"; import type { Cluster } from "../../../main/cluster";
import { userStore } from "../../../common/user-store"; import { userStore } from "../../../common/user-store";
import { clusterStore } from "../../../common/cluster-store"; import { ClusterId, clusterStore } from "../../../common/cluster-store";
import { workspaceStore } from "../../../common/workspace-store"; import { workspaceStore } from "../../../common/workspace-store";
import { ClusterIcon } from "../+cluster-settings/cluster-icon"; import { ClusterIcon } from "../+cluster-settings/cluster-icon";
import { Icon } from "../icon"; import { Icon } from "../icon";
import { cssNames, IClassName } from "../../utils"; import { cssNames, IClassName } from "../../utils";
import { Badge } from "../badge"; import { Badge } from "../badge";
import { navigate } from "../../navigation";
import { addClusterURL } from "../+add-cluster";
import { clusterSettingsURL } from "../+cluster-settings";
// fixme: allow to rearrange clusters with drag&drop // fixme: allow to rearrange clusters with drag&drop
// fixme: make add-icon's tooltip visible on init // fixme: make add-icon's tooltip visible on init
@ -22,13 +25,16 @@ interface Props {
@observer @observer
export class ClustersMenu extends React.Component<Props> { export class ClustersMenu extends React.Component<Props> {
showCluster = (cluster: Cluster) => { showCluster = (clusterId: ClusterId) => {
clusterStore.activeClusterId = cluster.id; if (clusterStore.activeClusterId === clusterId) {
console.log('show lens for cluster:', cluster.contextName); navigate("/"); // redirect to index
} else {
clusterStore.activeClusterId = clusterId;
}
} }
addCluster = () => { addCluster = () => {
console.log('navigate: /add-cluster') navigate(addClusterURL());
} }
showContextMenu = (cluster: Cluster) => { showContextMenu = (cluster: Cluster) => {
@ -37,15 +43,17 @@ export class ClustersMenu extends React.Component<Props> {
menu.append(new MenuItem({ menu.append(new MenuItem({
label: _i18n._(t`Settings`), label: _i18n._(t`Settings`),
click: () => console.log(`navigate to cluster settings`, cluster) click: () => navigate(clusterSettingsURL())
})); }));
if (cluster.initialized) { if (cluster.initialized) {
menu.append(new MenuItem({ menu.append(new MenuItem({
label: _i18n._(t`Disconnect`), label: _i18n._(t`Disconnect`),
click: () => console.log(`disconnect cluster and navigate to workspaces`, cluster.contextName) click: () => {
console.log(`//fixme: disconnect cluster`, cluster);
navigate("/");
}
})) }))
} }
menu.popup({ menu.popup({
window: remote.getCurrentWindow() window: remote.getCurrentWindow()
}) })
@ -54,8 +62,8 @@ export class ClustersMenu extends React.Component<Props> {
render() { render() {
const { className } = this.props; const { className } = this.props;
const { newContexts } = userStore; const { newContexts } = userStore;
const { currentWorkspace } = workspaceStore; const { currentWorkspaceId } = workspaceStore;
const clusters = clusterStore.getByWorkspaceId(currentWorkspace); const clusters = clusterStore.getByWorkspaceId(currentWorkspaceId);
return ( return (
<div className={cssNames("ClustersMenu flex gaps column", className)}> <div className={cssNames("ClustersMenu flex gaps column", className)}>
{clusters.map(cluster => { {clusters.map(cluster => {
@ -65,7 +73,7 @@ export class ClustersMenu extends React.Component<Props> {
showErrors={true} showErrors={true}
cluster={cluster} cluster={cluster}
isActive={cluster.id === clusterStore.activeClusterId} isActive={cluster.id === clusterStore.activeClusterId}
onClick={() => this.showCluster(cluster)} onClick={() => this.showCluster(cluster.id)}
onContextMenu={() => this.showContextMenu(cluster)} onContextMenu={() => this.showContextMenu(cluster)}
/> />
) )