mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
part 1
Signed-off-by: Roman <ixrock@gmail.com> Signed-off-by: Lauri Nevala <lauri.nevala@gmail.com>
This commit is contained in:
1 parent
1f5acdb9cd
commit
7d3e87685b
38 files changed
+260
-435
No files matched your search
@@ -4,16 +4,16 @@ import { Notifications } from "../components/notifications";
|
||||
import { apiKubePrefix, apiPrefix, isDevelopment } from "../../common/vars";
|
||||
|
||||
export const apiBase = new JsonApi({
|
||||
apiBase: apiPrefix,
|
||||
debug: isDevelopment,
|
||||
apiPrefix: apiPrefix,
|
||||
});
|
||||
export const apiKube = new KubeJsonApi({
|
||||
apiBase: apiKubePrefix,
|
||||
debug: isDevelopment,
|
||||
apiPrefix: apiKubePrefix,
|
||||
});
|
||||
|
||||
// Common handler for HTTP api errors
|
||||
function onApiError(error: JsonApiErrorParsed, res: Response) {
|
||||
export function onApiError(error: JsonApiErrorParsed, res: Response) {
|
||||
switch (res.status) {
|
||||
case 403:
|
||||
error.isUsedForNotification = true;
|
||||
|
||||
@@ -27,7 +27,7 @@ export interface JsonApiLog {
|
||||
}
|
||||
|
||||
export interface JsonApiConfig {
|
||||
apiPrefix: string;
|
||||
apiBase: string;
|
||||
debug?: boolean;
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ export class JsonApi<D = JsonApiData, P extends JsonApiParams = JsonApiParams> {
|
||||
}
|
||||
|
||||
protected request<D>(path: string, params?: P, init: RequestInit = {}) {
|
||||
let reqUrl = this.config.apiPrefix + path;
|
||||
let reqUrl = this.config.apiBase + path;
|
||||
const reqInit: RequestInit = { ...this.reqInit, ...init };
|
||||
const { data, query } = params || {} as P;
|
||||
if (data && !reqInit.body) {
|
||||
|
||||
@@ -61,7 +61,7 @@ export class KubeWatchApi {
|
||||
}
|
||||
|
||||
protected getQuery(): Partial<IKubeWatchRouteQuery> {
|
||||
const { isAdmin, allowedNamespaces } = getHostedCluster();
|
||||
const { isAdmin, allowedNamespaces } = getHostedCluster()
|
||||
return {
|
||||
api: this.activeApis.map(api => {
|
||||
if (isAdmin) return api.getWatchUrl();
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import "./components/app.scss"
|
||||
import React from "react";
|
||||
import { render } from "react-dom";
|
||||
import { isMac } from "../common/vars";
|
||||
import { userStore } from "../common/user-store";
|
||||
import { workspaceStore } from "../common/workspace-store";
|
||||
import { clusterStore, getHostedClusterId } from "../common/cluster-store";
|
||||
import { i18nStore } from "./i18n";
|
||||
import { themeStore } from "./theme.store";
|
||||
import { App } from "./components/app";
|
||||
import { LensApp } from "./lens-app";
|
||||
|
||||
type AppComponent = React.ComponentType & {
|
||||
init?(): void;
|
||||
}
|
||||
|
||||
export async function bootstrap(App: AppComponent) {
|
||||
const rootElem = document.getElementById("app")
|
||||
rootElem.classList.toggle("is-mac", isMac);
|
||||
|
||||
// preload common stores
|
||||
await Promise.all([
|
||||
userStore.load(),
|
||||
workspaceStore.load(),
|
||||
clusterStore.load(),
|
||||
i18nStore.init(),
|
||||
themeStore.init(),
|
||||
]);
|
||||
|
||||
// init app's dependencies if any
|
||||
if (App.init) {
|
||||
await App.init();
|
||||
}
|
||||
render(<App/>, rootElem);
|
||||
}
|
||||
|
||||
// run
|
||||
bootstrap(getHostedClusterId() ? App : LensApp);
|
||||
@@ -58,7 +58,7 @@ export class ReleaseStore extends ItemStore<HelmRelease> {
|
||||
this.isLoading = true;
|
||||
let items;
|
||||
try {
|
||||
const { isAdmin, allowedNamespaces } = getHostedCluster();
|
||||
const { isAdmin, allowedNamespaces } = getHostedCluster()
|
||||
items = await this.loadItems(!isAdmin ? allowedNamespaces : null);
|
||||
} finally {
|
||||
if (items) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import "./cluster-settings.scss"
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Features } from "./features"
|
||||
import { Features } from "./features"
|
||||
import { Removal } from "./removal"
|
||||
import { Status } from "./status"
|
||||
import { General } from "./general"
|
||||
@@ -12,7 +12,6 @@ import { WizardLayout } from "../layout/wizard-layout";
|
||||
export class ClusterSettings extends React.Component {
|
||||
render() {
|
||||
const cluster = getHostedCluster();
|
||||
|
||||
return (
|
||||
<WizardLayout className="ClusterSettings">
|
||||
<Status cluster={cluster}></Status>
|
||||
|
||||
File renamed without changes.
@@ -1,2 +1,2 @@
|
||||
export * from "./cluster.routes"
|
||||
export * from "./cluster.route"
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
import "./landing-page.scss"
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { clusterStore } from "../../../common/cluster-store";
|
||||
import { Trans } from "@lingui/macro";
|
||||
import { clusterStore } from "../../../common/cluster-store";
|
||||
import { workspaceStore } from "../../../common/workspace-store";
|
||||
|
||||
@observer
|
||||
export class LandingPage extends React.Component {
|
||||
render() {
|
||||
const noClusters = !clusterStore.hasClusters();
|
||||
const clusters = clusterStore.getByWorkspaceId(workspaceStore.currentWorkspaceId);
|
||||
const noClustersInScope = !clusters.length;
|
||||
return (
|
||||
<div className="LandingPage flex">
|
||||
{noClusters && (
|
||||
{noClustersInScope && (
|
||||
<div className="no-clusters flex column gaps box center">
|
||||
<h1>
|
||||
<Trans>Welcome!</Trans>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { observer } from "mobx-react";
|
||||
import { Trans } from "@lingui/macro";
|
||||
import { RouteComponentProps } from "react-router";
|
||||
import { Icon } from "../icon";
|
||||
import { IRoleBindingsRouteParams } from "../+user-management/user-management.routes";
|
||||
import { IRoleBindingsRouteParams } from "../+user-management/user-management.route";
|
||||
import { KubeObjectMenu, KubeObjectMenuProps } from "../kube-object/kube-object-menu";
|
||||
import { clusterRoleBindingApi, RoleBinding, roleBindingApi } from "../../api/endpoints";
|
||||
import { roleBindingsStore } from "./role-bindings.store";
|
||||
|
||||
@@ -4,7 +4,7 @@ import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Trans } from "@lingui/macro";
|
||||
import { RouteComponentProps } from "react-router";
|
||||
import { IRolesRouteParams } from "../+user-management/user-management.routes";
|
||||
import { IRolesRouteParams } from "../+user-management/user-management.route";
|
||||
import { KubeObjectMenu, KubeObjectMenuProps } from "../kube-object/kube-object-menu";
|
||||
import { rolesStore } from "./roles.store";
|
||||
import { clusterRoleApi, Role, roleApi } from "../../api/endpoints";
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
export * from "./user-management"
|
||||
export * from "./user-management.routes"
|
||||
export * from "./user-management.route"
|
||||
File renamed without changes.
@@ -8,7 +8,7 @@ import { MainLayout, TabRoute } from "../layout/main-layout";
|
||||
import { Roles } from "../+user-management-roles";
|
||||
import { RoleBindings } from "../+user-management-roles-bindings";
|
||||
import { ServiceAccounts } from "../+user-management-service-accounts";
|
||||
import { roleBindingsRoute, roleBindingsURL, rolesRoute, rolesURL, serviceAccountsRoute, serviceAccountsURL, usersManagementURL } from "./user-management.routes";
|
||||
import { roleBindingsRoute, roleBindingsURL, rolesRoute, rolesURL, serviceAccountsRoute, serviceAccountsURL, usersManagementURL } from "./user-management.route";
|
||||
import { namespaceStore } from "../+namespaces/namespace.store";
|
||||
import { PodSecurityPolicies, podSecurityPoliciesRoute, podSecurityPoliciesURL } from "../+pod-security-policies";
|
||||
import { isAllowedResource } from "../../../common/rbac";
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import "./app.scss";
|
||||
import React from "react";
|
||||
import { disposeOnUnmount, observer } from "mobx-react";
|
||||
import { observable, reaction } from "mobx";
|
||||
import { Redirect, Route, Switch } from "react-router";
|
||||
import { observer } from "mobx-react";
|
||||
import { Redirect, Route, Router, Switch } from "react-router";
|
||||
import { I18nProvider } from "@lingui/react";
|
||||
import { _i18n } from "../i18n";
|
||||
import { history } from "../navigation";
|
||||
import { Notifications } from "./notifications";
|
||||
import { NotFound } from "./+404";
|
||||
import { UserManagement } from "./+user-management/user-management";
|
||||
import { ConfirmDialog } from "./confirm-dialog";
|
||||
import { usersManagementRoute } from "./+user-management/user-management.routes";
|
||||
import { usersManagementRoute } from "./+user-management/user-management.route";
|
||||
import { clusterRoute, clusterURL } from "./+cluster";
|
||||
import { KubeConfigDialog } from "./kubeconfig-dialog/kubeconfig-dialog";
|
||||
import { Nodes, nodesRoute } from "./+nodes";
|
||||
@@ -27,94 +28,54 @@ import { DeploymentScaleDialog } from "./+workloads-deployments/deployment-scale
|
||||
import { CustomResources } from "./+custom-resources/custom-resources";
|
||||
import { crdRoute } from "./+custom-resources";
|
||||
import { isAllowedResource } from "../../common/rbac";
|
||||
import { AddCluster, addClusterRoute } from "./+add-cluster";
|
||||
import { LandingPage, landingRoute, landingURL } from "./+landing-page";
|
||||
import { ClusterSettings, clusterSettingsRoute } from "./+cluster-settings";
|
||||
import { Workspaces, workspacesRoute } from "./+workspaces";
|
||||
import { ErrorBoundary } from "./error-boundary";
|
||||
import { clusterIpc } from "../../common/cluster-ipc";
|
||||
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";
|
||||
import { Terminal } from "./dock/terminal";
|
||||
|
||||
@observer
|
||||
export class App extends React.Component {
|
||||
@observable isReady = false;
|
||||
|
||||
get cluster() {
|
||||
return getHostedCluster()
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
if (this.cluster) {
|
||||
await clusterIpc.activate.invokeFromRenderer(); // refresh state, reconnect, etc.
|
||||
disposeOnUnmount(this, [
|
||||
reaction(() => this.cluster.accessible, this.onClusterAccessChange, {
|
||||
fireImmediately: true
|
||||
})
|
||||
])
|
||||
}
|
||||
this.isReady = true;
|
||||
}
|
||||
|
||||
protected onClusterAccessChange = (accessible: boolean) => {
|
||||
const path = navigation.getPath();
|
||||
if (!accessible || path === "/") {
|
||||
navigate(this.startURL);
|
||||
}
|
||||
static async init() {
|
||||
await Terminal.preloadFonts()
|
||||
}
|
||||
|
||||
get startURL() {
|
||||
if (this.cluster) {
|
||||
if (!this.cluster.accessible) {
|
||||
return clusterStatusURL();
|
||||
}
|
||||
if (isAllowedResource(["events", "nodes", "pods"])) {
|
||||
return clusterURL();
|
||||
}
|
||||
return workloadsURL();
|
||||
if (isAllowedResource(["events", "nodes", "pods"])) {
|
||||
return clusterURL();
|
||||
}
|
||||
return landingURL();
|
||||
return workloadsURL();
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.isReady) {
|
||||
return <CubeSpinner className="box center"/>
|
||||
}
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<Switch>
|
||||
<Route component={LandingPage} {...landingRoute}/>
|
||||
<Route component={Preferences} {...preferencesRoute}/>
|
||||
<Route component={Workspaces} {...workspacesRoute}/>
|
||||
<Route component={AddCluster} {...addClusterRoute}/>
|
||||
<Route component={Cluster} {...clusterRoute}/>
|
||||
<Route component={ClusterStatus} {...clusterStatusRoute}/>
|
||||
<Route component={ClusterSettings} {...clusterSettingsRoute}/>
|
||||
<Route component={Nodes} {...nodesRoute}/>
|
||||
<Route component={Workloads} {...workloadsRoute}/>
|
||||
<Route component={Config} {...configRoute}/>
|
||||
<Route component={Network} {...networkRoute}/>
|
||||
<Route component={Storage} {...storageRoute}/>
|
||||
<Route component={Namespaces} {...namespacesRoute}/>
|
||||
<Route component={Events} {...eventRoute}/>
|
||||
<Route component={CustomResources} {...crdRoute}/>
|
||||
<Route component={UserManagement} {...usersManagementRoute}/>
|
||||
<Route component={Apps} {...appsRoute}/>
|
||||
<Redirect exact from="/" to={this.startURL}/>
|
||||
<Route component={NotFound}/>
|
||||
</Switch>
|
||||
<KubeObjectDetails/>
|
||||
<Notifications/>
|
||||
<ConfirmDialog/>
|
||||
<KubeConfigDialog/>
|
||||
<AddRoleBindingDialog/>
|
||||
<PodLogsDialog/>
|
||||
<DeploymentScaleDialog/>
|
||||
</ErrorBoundary>
|
||||
<I18nProvider i18n={_i18n}>
|
||||
<Router history={history}>
|
||||
<ErrorBoundary>
|
||||
<Switch>
|
||||
<Route component={Cluster} {...clusterRoute}/>
|
||||
<Route component={ClusterSettings} {...clusterSettingsRoute}/>
|
||||
<Route component={Nodes} {...nodesRoute}/>
|
||||
<Route component={Workloads} {...workloadsRoute}/>
|
||||
<Route component={Config} {...configRoute}/>
|
||||
<Route component={Network} {...networkRoute}/>
|
||||
<Route component={Storage} {...storageRoute}/>
|
||||
<Route component={Namespaces} {...namespacesRoute}/>
|
||||
<Route component={Events} {...eventRoute}/>
|
||||
<Route component={CustomResources} {...crdRoute}/>
|
||||
<Route component={UserManagement} {...usersManagementRoute}/>
|
||||
<Route component={Apps} {...appsRoute}/>
|
||||
<Redirect exact from="/" to={this.startURL}/>
|
||||
<Route component={NotFound}/>
|
||||
</Switch>
|
||||
<KubeObjectDetails/>
|
||||
<Notifications/>
|
||||
<ConfirmDialog/>
|
||||
<KubeConfigDialog/>
|
||||
<AddRoleBindingDialog/>
|
||||
<PodLogsDialog/>
|
||||
<DeploymentScaleDialog/>
|
||||
</ErrorBoundary>
|
||||
</Router>
|
||||
</I18nProvider>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -8,13 +8,6 @@
|
||||
#lens-view {
|
||||
position: relative;
|
||||
grid-area: lens-view;
|
||||
|
||||
&.inactive {
|
||||
opacity: .85;
|
||||
filter: grayscale(1);
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.ClustersMenu {
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import "./cluster-manager.scss"
|
||||
import React from "react";
|
||||
import { computed } from "mobx";
|
||||
import { observer } from "mobx-react";
|
||||
import { App } from "../app";
|
||||
import { ClustersMenu } from "./clusters-menu";
|
||||
import { BottomBar } from "./bottom-bar";
|
||||
import { cssNames, IClassName } from "../../utils";
|
||||
import { Terminal } from "../dock/terminal";
|
||||
import { i18nStore } from "../../i18n";
|
||||
import { themeStore } from "../../theme.store";
|
||||
import { clusterStore, getHostedClusterId, isNoClustersView } from "../../../common/cluster-store";
|
||||
import { CubeSpinner } from "../spinner";
|
||||
import { ClusterId } from "../../../common/cluster-store";
|
||||
import { Route, Switch } from "react-router";
|
||||
import { LandingPage, landingRoute } 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;
|
||||
@@ -19,34 +20,26 @@ interface Props {
|
||||
|
||||
@observer
|
||||
export class ClusterManager extends React.Component<Props> {
|
||||
static async init() {
|
||||
await Promise.all([
|
||||
i18nStore.init(),
|
||||
themeStore.init(),
|
||||
Terminal.preloadFonts(),
|
||||
])
|
||||
}
|
||||
|
||||
@computed get isInactive() {
|
||||
const { activeCluster, activeClusterId, clusters } = clusterStore;
|
||||
const isActivatedBefore = activeCluster?.initialized;
|
||||
return clusters.size > 0 && !isActivatedBefore && activeClusterId !== getHostedClusterId();
|
||||
activateView(clusterId: ClusterId) {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { className, contentClass } = this.props;
|
||||
const lensViewClass = cssNames("flex column", contentClass, {
|
||||
inactive: this.isInactive,
|
||||
});
|
||||
const { className } = this.props;
|
||||
return (
|
||||
<div className={cssNames("ClusterManager", className)}>
|
||||
<div id="draggable-top"/>
|
||||
<div id="lens-view" className={lensViewClass}>
|
||||
<App/>
|
||||
<div id="lens-view">
|
||||
<Switch>
|
||||
<Route component={LandingPage} {...landingRoute}/>
|
||||
<Route component={Preferences} {...preferencesRoute}/>
|
||||
<Route component={Workspaces} {...workspacesRoute}/>
|
||||
<Route component={AddCluster} {...addClusterRoute}/>
|
||||
<Route component={ClusterStatus} {...clusterStatusRoute}/>
|
||||
<Route render={() => <p>Lens</p>}/>
|
||||
</Switch>
|
||||
</div>
|
||||
<ClustersMenu/>
|
||||
<BottomBar/>
|
||||
{this.isInactive && <CubeSpinner center/>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -6,19 +6,20 @@ import { disposeOnUnmount, observer } from "mobx-react";
|
||||
import { ipcRenderer } from "electron";
|
||||
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";
|
||||
import { Cluster } from "../../../main/cluster";
|
||||
|
||||
@observer
|
||||
export class ClusterStatus extends React.Component {
|
||||
@observable authOutput: KubeAuthProxyLog[] = [];
|
||||
@observable isReconnecting = false;
|
||||
|
||||
@computed get cluster() {
|
||||
return getHostedCluster();
|
||||
// fixme
|
||||
@computed get cluster(): Cluster {
|
||||
return null;
|
||||
}
|
||||
|
||||
@computed get hasErrors(): boolean {
|
||||
@@ -33,6 +34,9 @@ export class ClusterStatus extends React.Component {
|
||||
})
|
||||
|
||||
async componentDidMount() {
|
||||
if (this.cluster.disconnected) {
|
||||
return;
|
||||
}
|
||||
this.authOutput = [{ data: "Connecting..." }];
|
||||
ipcRenderer.on(`kube-auth:${this.cluster.id}`, (evt, res: KubeAuthProxyLog) => {
|
||||
this.authOutput.push({
|
||||
@@ -40,16 +44,21 @@ export class ClusterStatus extends React.Component {
|
||||
error: res.error,
|
||||
});
|
||||
})
|
||||
await this.refreshClusterState();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
ipcRenderer.removeAllListeners(`kube-auth:${this.cluster.id}`);
|
||||
}
|
||||
|
||||
async refreshClusterState() {
|
||||
return clusterIpc.activate.invokeFromRenderer();
|
||||
}
|
||||
|
||||
reconnect = async () => {
|
||||
this.authOutput = [{ data: "Reconnecting..." }];
|
||||
this.isReconnecting = true;
|
||||
await clusterIpc.activate.invokeFromRenderer();
|
||||
await this.refreshClusterState();
|
||||
this.isReconnecting = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
> .add-cluster {
|
||||
position: relative;
|
||||
margin-top: $padding;
|
||||
min-width: 43px;
|
||||
|
||||
.Icon {
|
||||
border-radius: $radius;
|
||||
|
||||
@@ -85,11 +85,10 @@ export class ClustersMenu extends React.Component<Props> {
|
||||
render() {
|
||||
const { className } = this.props;
|
||||
const { newContexts } = userStore;
|
||||
const { currentWorkspaceId } = workspaceStore;
|
||||
const clusters = clusterStore.getByWorkspaceId(currentWorkspaceId);
|
||||
const noClusters = !clusterStore.clusters.size;
|
||||
const clusters = clusterStore.getByWorkspaceId(workspaceStore.currentWorkspaceId);
|
||||
const noClustersInScope = clusters.length === 0;
|
||||
const isLanding = navigation.getPath() === landingURL();
|
||||
const showStartupHint = this.showHint && isLanding && noClusters;
|
||||
const showStartupHint = this.showHint && isLanding && noClustersInScope;
|
||||
return (
|
||||
<div
|
||||
className={cssNames("ClustersMenu flex column gaps", className)}
|
||||
|
||||
@@ -10,8 +10,8 @@ import { Sidebar } from "./sidebar";
|
||||
import { ErrorBoundary } from "../error-boundary";
|
||||
import { Dock } from "../dock";
|
||||
import { navigate, navigation } from "../../navigation";
|
||||
import { themeStore } from "../../theme.store";
|
||||
import { getHostedCluster } from "../../../common/cluster-store";
|
||||
import { themeStore } from "../../theme.store";
|
||||
|
||||
export interface TabRoute extends RouteProps {
|
||||
title: React.ReactNode;
|
||||
@@ -47,12 +47,13 @@ export class MainLayout extends React.Component<Props> {
|
||||
|
||||
render() {
|
||||
const { className, contentClass, headerClass, tabs, footer, footerClass, children } = this.props;
|
||||
const { contextName: clusterName } = getHostedCluster();
|
||||
const routePath = navigation.location.pathname;
|
||||
return (
|
||||
<div className={cssNames("MainLayout", className, themeStore.activeTheme.type)}>
|
||||
<header className={cssNames("flex gaps align-center", headerClass)}>
|
||||
<span className="cluster">{clusterName}</span>
|
||||
<span className="cluster">
|
||||
{getHostedCluster().contextName}
|
||||
</span>
|
||||
</header>
|
||||
|
||||
<aside className={cssNames("flex column", { pinned: this.isPinned, accessible: this.isAccessible })}>
|
||||
|
||||
@@ -11,7 +11,7 @@ import { Icon } from "../icon";
|
||||
import { workloadsRoute, workloadsURL } from "../+workloads/workloads.route";
|
||||
import { namespacesURL } from "../+namespaces/namespaces.route";
|
||||
import { nodesURL } from "../+nodes/nodes.route";
|
||||
import { usersManagementRoute, usersManagementURL } from "../+user-management/user-management.routes";
|
||||
import { usersManagementRoute, usersManagementURL } from "../+user-management/user-management.route";
|
||||
import { networkRoute, networkURL } from "../+network/network.route";
|
||||
import { storageRoute, storageURL } from "../+storage/storage.route";
|
||||
import { clusterURL } from "../+cluster";
|
||||
@@ -43,7 +43,9 @@ interface Props {
|
||||
@observer
|
||||
export class Sidebar extends React.Component<Props> {
|
||||
async componentDidMount() {
|
||||
if (!crdStore.isLoaded && isAllowedResource('customresourcedefinitions')) crdStore.loadAll()
|
||||
if (!crdStore.isLoaded && isAllowedResource('customresourcedefinitions')) {
|
||||
crdStore.loadAll()
|
||||
}
|
||||
}
|
||||
|
||||
renderCustomResources() {
|
||||
|
||||
@@ -1,33 +1,17 @@
|
||||
import "../common/system-ca"
|
||||
import React from "react";
|
||||
import { render } from "react-dom";
|
||||
import { Route, Router, Switch } from "react-router";
|
||||
import { observer } from "mobx-react";
|
||||
import { userStore } from "../common/user-store";
|
||||
import { workspaceStore } from "../common/workspace-store";
|
||||
import { clusterStore } from "../common/cluster-store";
|
||||
import { I18nProvider } from "@lingui/react";
|
||||
import { history } from "./navigation";
|
||||
import { isMac } from "../common/vars";
|
||||
import { _i18n } from "./i18n";
|
||||
import { ClusterManager } from "./components/cluster-manager";
|
||||
import { ErrorBoundary } from "./components/error-boundary";
|
||||
import { WhatsNew, whatsNewRoute } from "./components/+whats-new";
|
||||
|
||||
@observer
|
||||
class LensApp extends React.Component {
|
||||
static async init() {
|
||||
const rootElem = document.getElementById("app");
|
||||
rootElem.classList.toggle("is-mac", isMac);
|
||||
await Promise.all([
|
||||
userStore.load(),
|
||||
workspaceStore.load(),
|
||||
clusterStore.load(),
|
||||
]);
|
||||
await ClusterManager.init();
|
||||
render(<LensApp/>, rootElem);
|
||||
}
|
||||
|
||||
export class LensApp extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<I18nProvider i18n={_i18n}>
|
||||
@@ -44,6 +28,3 @@ class LensApp extends React.Component {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// run
|
||||
LensApp.init();
|
||||
@@ -1,6 +1,5 @@
|
||||
// Navigation helpers
|
||||
|
||||
import { ipcRenderer } from "electron";
|
||||
import { compile } from "path-to-regexp"
|
||||
import { createBrowserHistory, createMemoryHistory, Location, LocationDescriptor } from "history";
|
||||
import { createObservableHistory } from "mobx-observable-history";
|
||||
@@ -8,13 +7,6 @@ import { createObservableHistory } from "mobx-observable-history";
|
||||
export const history = typeof window !== "undefined" ? createBrowserHistory() : createMemoryHistory();
|
||||
export const navigation = createObservableHistory(history);
|
||||
|
||||
if (ipcRenderer) {
|
||||
// subscribe for navigation via menu.ts
|
||||
ipcRenderer.on("menu:navigate", (event, path: string) => {
|
||||
navigate(path);
|
||||
});
|
||||
}
|
||||
|
||||
export function navigate(location: LocationDescriptor) {
|
||||
navigation.location = location as Location;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { computed, observable, reaction } from "mobx";
|
||||
import { autobind } from "./utils";
|
||||
import { autobind } from "./utils/autobind";
|
||||
import { userStore } from "../common/user-store";
|
||||
import logger from "../main/logger";
|
||||
|
||||
|
||||
Reference in new issue
Block a user