diff --git a/src/common/vars.ts b/src/common/vars.ts index 327b3be436..065d3d969b 100644 --- a/src/common/vars.ts +++ b/src/common/vars.ts @@ -7,7 +7,6 @@ export const isWindows = process.platform === "win32" export const isDebugging = process.env.DEBUG === "true"; export const isProduction = process.env.NODE_ENV === "production" export const isDevelopment = isDebugging || !isProduction; -export const buildVersion = process.env.BUILD_VERSION; export const isTestEnv = !!process.env.JEST_WORKER_ID; export const appName = `${packageInfo.productName}${isDevelopment ? "Dev" : ""}` diff --git a/src/main/cluster.ts b/src/main/cluster.ts index ce08019d90..875760c1f7 100644 --- a/src/main/cluster.ts +++ b/src/main/cluster.ts @@ -78,8 +78,7 @@ export class Cluster implements ClusterModel { this.contextHandler = new ContextHandler(this); const proxyPort = await this.contextHandler.resolveProxyPort(); this.kubeconfigManager = new KubeconfigManager(this, proxyPort); - this.url = this.contextHandler.url - // todo: verify api url + this.url = this.contextHandler.url; // this.apiUrl = kubeConfig.getCurrentCluster().server; this.initialized = true; logger.debug(`[CLUSTER]: init done (id="${this.id}", context="${this.contextName}")`); diff --git a/src/main/context-handler.ts b/src/main/context-handler.ts index d34b314060..a8ce88000b 100644 --- a/src/main/context-handler.ts +++ b/src/main/context-handler.ts @@ -111,12 +111,7 @@ export class ContextHandler { async resolveProxyPort(): Promise { if (!this.proxyPort) { - try { - this.proxyPort = await getFreePort() - } catch (error) { - logger.error(error) - throw(error) - } + this.proxyPort = await getFreePort() } return this.proxyPort } @@ -133,7 +128,7 @@ export class ContextHandler { if (!this.proxyServer) { const proxyPort = await this.resolveProxyPort() const proxyEnv = Object.assign({}, process.env) - if (this.cluster?.preferences.httpsProxy) { + if (this.cluster.preferences.httpsProxy) { proxyEnv.HTTPS_PROXY = this.cluster.preferences.httpsProxy } this.proxyServer = new KubeAuthProxy(this.cluster, proxyPort, proxyEnv) diff --git a/src/main/index.ts b/src/main/index.ts index 2b2d5db33a..2fa21da8aa 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -6,7 +6,7 @@ import { app, dialog } from "electron" import { appName, appProto, isMac, staticDir, staticProto } from "../common/vars"; import path from "path" import initMenu from "./menu" -import { LensProxy, listen } from "./proxy" +import { LensProxy, listen } from "./lens-proxy" import { WindowManager } from "./window-manager"; import { ClusterManager } from "./cluster-manager"; import AppUpdater from "./app-updater" diff --git a/src/main/proxy.ts b/src/main/lens-proxy.ts similarity index 86% rename from src/main/proxy.ts rename to src/main/lens-proxy.ts index 2fc28a0adc..6cc9c14bcd 100644 --- a/src/main/proxy.ts +++ b/src/main/lens-proxy.ts @@ -4,27 +4,20 @@ import { Socket } from "net"; import * as url from "url"; import * as WebSocket from "ws" import { ContextHandler } from "./context-handler"; -import logger from "./logger" import * as shell from "./node-shell-session" import { ClusterManager } from "./cluster-manager" import { Router } from "./router" import { apiPrefix } from "../common/vars"; +import logger from "./logger" export class LensProxy { - public static readonly localShellSessions = true - - public port: number; - protected clusterUrl: url.UrlWithStringQuery - protected clusterManager: ClusterManager - protected retryCounters: Map = new Map() - protected router: Router protected proxyServer: http.Server + protected router: Router protected closed = false + protected retryCounters = new Map() - constructor(port: number, clusterManager: ClusterManager) { - this.port = port - this.clusterManager = clusterManager - this.router = new Router() + constructor(public port: number, protected clusterManager: ClusterManager) { + this.router = new Router(); } public run() { @@ -34,7 +27,7 @@ export class LensProxy { } public close() { - logger.info("Closing proxy server") + logger.info(`Closing proxy server at port ${this.port}`); this.proxyServer.close() this.closed = true } @@ -77,9 +70,7 @@ export class LensProxy { } }) proxy.on("error", (error, req, res, target) => { - if(this.closed) { - return - } + if (this.closed) return; if (target) { logger.debug("Failed proxy to target: " + JSON.stringify(target)) if (req.method === "GET" && (!res.statusCode || res.statusCode >= 500)) { @@ -142,14 +133,13 @@ export class LensProxy { return } const contextHandler = cluster.contextHandler - contextHandler.ensureServer().then(async () => { - const proxyTarget = await this.getProxyTarget(req, contextHandler) - if (proxyTarget) { - proxy.web(req, res, proxyTarget) - } else { - this.router.route(cluster, req, res) - } - }) + await contextHandler.ensureServer(); + const proxyTarget = await this.getProxyTarget(req, contextHandler) + if (proxyTarget) { + proxy.web(req, res, proxyTarget) + } else { + this.router.route(cluster, req, res) + } } protected async handleWsUpgrade(req: http.IncomingMessage, socket: Socket, head: Buffer) { diff --git a/src/renderer/api/terminal-api.ts b/src/renderer/api/terminal-api.ts index d12cd56c7c..da86989eae 100644 --- a/src/renderer/api/terminal-api.ts +++ b/src/renderer/api/terminal-api.ts @@ -3,7 +3,7 @@ import { autobind, base64, EventEmitter, interval } from "../utils"; import { WebSocketApi } from "./websocket-api"; import { configStore } from "../config.store"; import isEqual from "lodash/isEqual" -import { apiPrefix, isDevelopment } from "../../common/vars"; +import { isDevelopment } from "../../common/vars"; export enum TerminalChannels { STDIN = 0, diff --git a/src/renderer/components/+workspaces/add-workspace.tsx b/src/renderer/components/+workspaces/add-workspace.tsx deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/renderer/components/+workspaces/edit-workspace.tsx b/src/renderer/components/+workspaces/edit-workspace.tsx deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/renderer/components/+workspaces/index.ts b/src/renderer/components/+workspaces/index.ts new file mode 100644 index 0000000000..b25d55a129 --- /dev/null +++ b/src/renderer/components/+workspaces/index.ts @@ -0,0 +1 @@ +export * from "./workspaces" diff --git a/src/renderer/components/+workspaces/index.tsx b/src/renderer/components/+workspaces/index.tsx deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/renderer/components/+workspaces/workspaces.scss b/src/renderer/components/+workspaces/workspaces.scss index fbfc355443..7b636036db 100644 --- a/src/renderer/components/+workspaces/workspaces.scss +++ b/src/renderer/components/+workspaces/workspaces.scss @@ -1,33 +1,3 @@ .Workspaces { - display: grid; - grid-template-areas: "draggable draggable" "menu lens-view" "bottom-bar bottom-bar"; - grid-template-rows: auto 1fr min-content; - grid-template-columns: min-content 1fr; - height: 100%; - .draggable-top { - @include set-draggable; - grid-area: draggable; - height: 25px; - } - - #lens-view { - grid-area: lens-view; - } - - .ClusterMenu { - grid-area: menu; - } - - .WorkspacesBottomBar { - grid-area: bottom-bar; - } -} - -.WorkspacesMenu { - border-radius: $radius; - - .workspaces-title { - padding: $padding; - } -} +} \ No newline at end of file diff --git a/src/renderer/components/+workspaces/workspaces.tsx b/src/renderer/components/+workspaces/workspaces.tsx index ed4f105f2d..c3bb76cf5a 100644 --- a/src/renderer/components/+workspaces/workspaces.tsx +++ b/src/renderer/components/+workspaces/workspaces.tsx @@ -1,19 +1,12 @@ import "./workspaces.scss" import React from "react"; -import { ClustersMenu } from "./clusters-menu"; -import { WorkspacesBottomBar } from "./bottom-bar"; - -// todo: support `workspaceId` in URL export class Workspaces extends React.Component { render() { return (
-
-
- - + Workspaces
- ) + ); } } diff --git a/src/renderer/components/app.tsx b/src/renderer/components/app.tsx index 1387ef1b5c..e4ce14e086 100755 --- a/src/renderer/components/app.tsx +++ b/src/renderer/components/app.tsx @@ -1,15 +1,13 @@ import "./app.scss"; -import React from "react"; -import { render } from "react-dom"; -import { Redirect, Route, Router, Switch } from "react-router"; +import React, { Fragment } from "react"; import { observer } from "mobx-react"; -import { I18nProvider } from '@lingui/react' -import { _i18n, i18nStore } from "../i18n"; -import { browserHistory } from "../navigation"; +import { i18nStore } from "../i18n"; +import { configStore } from "../config.store"; +import { Terminal } from "./dock/terminal"; +import { Redirect, Route, Switch } from "react-router"; import { Notifications } from "./notifications"; import { NotFound } from "./+404"; -import { configStore } from "../config.store"; import { UserManagement } from "./+user-management/user-management"; import { ConfirmDialog } from "./confirm-dialog"; import { usersManagementRoute } from "./+user-management/user-management.routes"; @@ -24,7 +22,6 @@ import { Cluster } from "./+cluster/cluster"; import { Config, configRoute } from "./+config"; import { Events } from "./+events/events"; import { eventRoute } from "./+events"; -import { ErrorBoundary } from "./error-boundary"; import { Apps, appsRoute } from "./+apps"; import { KubeObjectDetails } from "./kube-object/kube-object-details"; import { AddRoleBindingDialog } from "./+user-management-roles-bindings"; @@ -33,7 +30,6 @@ import { DeploymentScaleDialog } from "./+workloads-deployments/deployment-scale import { CustomResources } from "./+custom-resources/custom-resources"; import { crdRoute } from "./+custom-resources"; import { isAllowedResource } from "../api/rbac"; -import { Terminal } from "./dock/terminal"; @observer export class App extends React.Component { @@ -43,42 +39,40 @@ export class App extends React.Component { await i18nStore.init(); await configStore.init(); await Terminal.preloadFonts(); - render(, App.rootElem); } render() { const homeUrl = isAllowedResource(["events", "nodes", "pods"]) ? clusterURL() : workloadsURL(); return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + {/* todo: remove */} +

App is running!

}/> + + + + + + + + + + + + + + +
+
+ + + + + + + +
) } } diff --git a/src/renderer/components/+workspaces/bottom-bar.scss b/src/renderer/components/cluster-manager/bottom-bar.scss similarity index 58% rename from src/renderer/components/+workspaces/bottom-bar.scss rename to src/renderer/components/cluster-manager/bottom-bar.scss index 1dc5d8fb17..74a33494a8 100644 --- a/src/renderer/components/+workspaces/bottom-bar.scss +++ b/src/renderer/components/cluster-manager/bottom-bar.scss @@ -1,4 +1,4 @@ -.WorkspacesBottomBar { +.BottomBar { font-size: $font-size-small; background-color: #3d90ce; padding: $padding / 2 $padding; @@ -8,3 +8,11 @@ cursor: pointer; } } + +#workspace-menu { + border-radius: $radius; + + .workspaces-title { + padding: $padding; + } +} \ No newline at end of file diff --git a/src/renderer/components/+workspaces/bottom-bar.tsx b/src/renderer/components/cluster-manager/bottom-bar.tsx similarity index 89% rename from src/renderer/components/+workspaces/bottom-bar.tsx rename to src/renderer/components/cluster-manager/bottom-bar.tsx index a142335fdb..b09b16d8c5 100644 --- a/src/renderer/components/+workspaces/bottom-bar.tsx +++ b/src/renderer/components/cluster-manager/bottom-bar.tsx @@ -13,26 +13,26 @@ import { workspaceStore } from "../../../common/workspace-store"; // todo: remove dummy actions + console.log @observer -export class WorkspacesBottomBar extends React.Component { +export class BottomBar extends React.Component { @observable menuVisible = false; render() { const { currentWorkspace, workspacesList } = workspaceStore; return ( -
+
{currentWorkspace}
this.menuVisible = true} close={() => this.menuVisible = false} > console.log('/navigate: workspaces page'))}> Workspaces diff --git a/src/renderer/components/cluster-manager/cluster-context.tsx b/src/renderer/components/cluster-manager/cluster-context.tsx new file mode 100644 index 0000000000..c1feaf091c --- /dev/null +++ b/src/renderer/components/cluster-manager/cluster-context.tsx @@ -0,0 +1,30 @@ +import React from "react"; +import { observer } from "mobx-react"; +import { ClusterId, clusterStore } from "../../../common/cluster-store"; +import { WorkspaceId, workspaceStore } from "../../../common/workspace-store"; + +export const clusterContext = React.createContext(getClusterContext()); + +export interface ClusterContextValue { + workspaceId: WorkspaceId; + clusterId?: ClusterId; +} + +export function getClusterContext(): ClusterContextValue { + return { + clusterId: clusterStore.activeCluster, + workspaceId: workspaceStore.currentWorkspace, + } +} + +@observer +export class ClusterContext extends React.Component { + render() { + const { Provider } = clusterContext; + return ( + + {this.props.children} + + ) + } +} diff --git a/src/renderer/components/cluster-manager/cluster-manager.scss b/src/renderer/components/cluster-manager/cluster-manager.scss new file mode 100644 index 0000000000..3b61531563 --- /dev/null +++ b/src/renderer/components/cluster-manager/cluster-manager.scss @@ -0,0 +1,26 @@ +.ClusterManager { + display: grid; + grid-template-areas: "draggable draggable" "menu lens-view" "bottom-bar bottom-bar"; + grid-template-rows: auto 1fr min-content; + grid-template-columns: min-content 1fr; + height: 100%; + + .draggable-top { + @include set-draggable; + grid-area: draggable; + height: 25px; + } + + #lens-view { + position: relative; + grid-area: lens-view; + } + + .ClustersMenu { + grid-area: menu; + } + + .BottomBar { + grid-area: bottom-bar; + } +} \ No newline at end of file diff --git a/src/renderer/components/cluster-manager/cluster-manager.tsx b/src/renderer/components/cluster-manager/cluster-manager.tsx new file mode 100644 index 0000000000..7d272f823d --- /dev/null +++ b/src/renderer/components/cluster-manager/cluster-manager.tsx @@ -0,0 +1,18 @@ +import "./cluster-manager.scss" +import React from "react"; +import { ClustersMenu } from "./clusters-menu"; +import { BottomBar } from "./bottom-bar"; + +export class ClusterManager extends React.Component { + render() { + const { children: lensView } = this.props; + return ( +
+
+
{lensView}
+ + +
+ ) + } +} diff --git a/src/renderer/components/+workspaces/clusters-menu.scss b/src/renderer/components/cluster-manager/clusters-menu.scss similarity index 96% rename from src/renderer/components/+workspaces/clusters-menu.scss rename to src/renderer/components/cluster-manager/clusters-menu.scss index 4c3a6dcd65..2a2bd6212c 100644 --- a/src/renderer/components/+workspaces/clusters-menu.scss +++ b/src/renderer/components/cluster-manager/clusters-menu.scss @@ -43,7 +43,7 @@ color: white; background: $colorSuccess; font-weight: normal; - border-radius: 50%; + border-radius: $radius; padding: 0; } } diff --git a/src/renderer/components/+workspaces/clusters-menu.tsx b/src/renderer/components/cluster-manager/clusters-menu.tsx similarity index 92% rename from src/renderer/components/+workspaces/clusters-menu.tsx rename to src/renderer/components/cluster-manager/clusters-menu.tsx index 8eef7e438d..55761f303f 100644 --- a/src/renderer/components/+workspaces/clusters-menu.tsx +++ b/src/renderer/components/cluster-manager/clusters-menu.tsx @@ -1,14 +1,13 @@ -import type { Cluster } from "../../../main/cluster"; - import "./clusters-menu.scss" import { remote } from "electron" import React from "react"; import { observer } from "mobx-react"; import { _i18n } from "../../i18n"; import { t, Trans } from "@lingui/macro"; +import type { Cluster } from "../../../main/cluster"; import { userStore } from "../../../common/user-store"; import { clusterStore } from "../../../common/cluster-store"; -import { WorkspaceId } from "../../../common/workspace-store"; +import { workspaceStore } from "../../../common/workspace-store"; import { ClusterIcon } from "../+cluster-settings/cluster-icon"; import { Icon } from "../icon"; import { cssNames, IClassName } from "../../utils"; @@ -19,7 +18,6 @@ import { Badge } from "../badge"; interface Props { className?: IClassName; - workspaceId?: WorkspaceId; } @observer @@ -54,9 +52,10 @@ export class ClustersMenu extends React.Component { } render() { - const { workspaceId, className } = this.props; - const clusters = clusterStore.getByWorkspaceId(workspaceId); + const { className } = this.props; const { newContexts } = userStore; + const { currentWorkspace } = workspaceStore; + const clusters = clusterStore.getByWorkspaceId(currentWorkspace); return (
{clusters.map(cluster => { diff --git a/src/renderer/components/cluster-manager/index.tsx b/src/renderer/components/cluster-manager/index.tsx new file mode 100644 index 0000000000..92f878ad67 --- /dev/null +++ b/src/renderer/components/cluster-manager/index.tsx @@ -0,0 +1 @@ +export * from "./cluster-manager" diff --git a/src/renderer/components/error-boundary/error-boundary.tsx b/src/renderer/components/error-boundary/error-boundary.tsx index 5e43f53f26..bccbbd6ec6 100644 --- a/src/renderer/components/error-boundary/error-boundary.tsx +++ b/src/renderer/components/error-boundary/error-boundary.tsx @@ -7,7 +7,7 @@ import { t, Trans } from "@lingui/macro"; import { Button } from "../button"; import { navigation } from "../../navigation"; import { _i18n } from "../../i18n"; -import { issuesTrackerUrl, slackUrl, buildVersion } from "../../../common/vars"; +import { issuesTrackerUrl, slackUrl } from "../../../common/vars"; interface Props { } @@ -45,7 +45,6 @@ export class ErrorBoundary extends React.Component {
App crash at {pageUrl} - {buildVersion &&

Build version: {buildVersion}

}

diff --git a/src/renderer/components/menu/menu.tsx b/src/renderer/components/menu/menu.tsx index 9d3cc66d16..b6453b2e89 100644 --- a/src/renderer/components/menu/menu.tsx +++ b/src/renderer/components/menu/menu.tsx @@ -21,6 +21,7 @@ export interface MenuProps { isOpen?: boolean; open(): void; close(): void; + id?: string; className?: string; htmlFor?: string; autoFocus?: boolean; diff --git a/src/renderer/index.tsx b/src/renderer/index.tsx index 2dc1ca87a1..fa9a118a47 100644 --- a/src/renderer/index.tsx +++ b/src/renderer/index.tsx @@ -1,38 +1,41 @@ -// todo: remove when app.tsx re-used -import "./components/app.scss" -import "./theme.store"; - import "../common/system-ca" import React from "react"; -import ReactDOM from "react-dom"; +import { render } from "react-dom"; import { Router } from "react-router"; import { userStore } from "../common/user-store"; import { workspaceStore } from "../common/workspace-store"; import { clusterStore } from "../common/cluster-store"; -import { Workspaces } from "./components/+workspaces/workspaces"; import { I18nProvider } from "@lingui/react"; -import { _i18n } from "./i18n"; import { browserHistory } from "./navigation"; +import { _i18n } from "./i18n"; +import { App } from "./components/app"; +import { ClusterManager } from "./components/cluster-manager"; +import { ErrorBoundary } from "./components/error-boundary"; -class App extends React.Component { +class LensApp extends React.Component { static async init() { await Promise.all([ userStore.load(), workspaceStore.load(), clusterStore.load(), ]); - ReactDOM.render(, document.getElementById("app"),) + await App.init(); + render(, App.rootElem); } render() { return ( - + + + + + ) } } -window.addEventListener("load", App.init); +window.addEventListener("load", LensApp.init);