diff --git a/src/main/cluster.ts b/src/main/cluster.ts index 7ea2012e40..9dd47d031e 100644 --- a/src/main/cluster.ts +++ b/src/main/cluster.ts @@ -1,7 +1,7 @@ import type { ClusterId, ClusterModel, ClusterPreferences } from "../common/cluster-store" import type { FeatureStatusMap } from "./feature" import type { WorkspaceId } from "../common/workspace-store"; -import { action, computed, observable, reaction, toJS, when } from "mobx"; +import { action, computed, observable, reaction, toJS } from "mobx"; import { apiKubePrefix } from "../common/vars"; import { broadcastIpc } from "../common/ipc"; import { ContextHandler } from "./context-handler" @@ -20,17 +20,19 @@ export enum ClusterStatus { } export interface ClusterState extends ClusterModel { - initialized?: boolean; + initialized: boolean; apiUrl: string; - online?: boolean; - accessible?: boolean; - failureReason?: string; - nodes?: number; - eventCount?: number; - version?: string; - distribution?: string; - isAdmin?: boolean; - features?: FeatureStatusMap; + online: boolean; + accessible: boolean; + failureReason: string; + nodes: number; + eventCount: number; + version: string; + distribution: string; + isAdmin: boolean; + allowedNamespaces: string[] + allowedResources: string[] + features: FeatureStatusMap; } export class Cluster implements ClusterModel { @@ -58,6 +60,8 @@ export class Cluster implements ClusterModel { @observable eventCount = 0; @observable preferences: ClusterPreferences = {}; @observable features: FeatureStatusMap = {}; + @observable allowedNamespaces: string[] = []; + @observable allowedResources: string[] = []; constructor(model: ClusterModel) { this.updateModel(model); @@ -120,7 +124,6 @@ export class Cluster implements ClusterModel { } async activate() { - await when(() => this.initialized); if (this.disconnected) await this.reconnect(); await this.refresh(); return this.pushState(); @@ -150,14 +153,28 @@ export class Cluster implements ClusterModel { this.online = connectionStatus > ClusterStatus.Offline; this.accessible = connectionStatus == ClusterStatus.AccessGranted; if (this.accessible) { - this.distribution = this.detectKubernetesDistribution(this.version) - this.features = await getFeatures(this) - this.isAdmin = await this.isClusterAdmin() - this.nodes = await this.getNodeCount() this.kubeCtl = new Kubectl(this.version) - this.kubeCtl.ensureKubectl() + this.distribution = this.detectKubernetesDistribution(this.version) + const [features, isAdmin, nodesCount] = await Promise.all([ + getFeatures(this), + this.isClusterAdmin(), + this.getNodeCount(), + this.kubeCtl.ensureKubectl() + ]); + this.features = features; + this.isAdmin = isAdmin; + this.nodes = nodesCount; } - await this.refreshEvents(); + await Promise.all([ + this.refreshEvents(), + this.refreshAllowedResources(), + ]); + } + + @action + async refreshAllowedResources() { + this.allowedNamespaces = await this.getAllowedNamespaces(); + this.allowedResources = await this.getAllowedResources(); } @action @@ -342,6 +359,8 @@ export class Cluster implements ClusterModel { isAdmin: this.isAdmin, features: this.features, eventCount: this.eventCount, + allowedNamespaces: this.allowedNamespaces, + allowedResources: this.allowedResources, }; return toJS(state, { recurseEverything: true @@ -368,4 +387,67 @@ export class Cluster implements ClusterModel { online: this.online, } } + + protected async getAllowedNamespaces() { + const api = this.getProxyKubeconfig().makeApiClient(CoreV1Api) + try { + const namespaceList = await api.listNamespace() + const nsAccessStatuses = await Promise.all( + namespaceList.body.items.map(ns => this.canI({ + namespace: ns.metadata.name, + resource: "pods", + verb: "list", + })) + ) + return namespaceList.body.items + .filter((ns, i) => nsAccessStatuses[i]) + .map(ns => ns.metadata.name) + } catch (error) { + const ctx = this.getProxyKubeconfig().getContextObject(this.contextName) + if (ctx.namespace) return [ctx.namespace] + return [] + } + } + + protected async getAllowedResources() { + // TODO: auto-populate all resources dynamically + const apiResources = [ + { resource: "configmaps" }, + { resource: "cronjobs", group: "batch" }, + { resource: "customresourcedefinitions", group: "apiextensions.k8s.io" }, + { resource: "daemonsets", group: "apps" }, + { resource: "deployments", group: "apps" }, + { resource: "endpoints" }, + { resource: "events" }, + { resource: "horizontalpodautoscalers" }, + { resource: "ingresses", group: "networking.k8s.io" }, + { resource: "jobs", group: "batch" }, + { resource: "namespaces" }, + { resource: "networkpolicies", group: "networking.k8s.io" }, + { resource: "nodes" }, + { resource: "persistentvolumes" }, + { resource: "pods" }, + { resource: "podsecuritypolicies" }, + { resource: "resourcequotas" }, + { resource: "secrets" }, + { resource: "services" }, + { resource: "statefulsets", group: "apps" }, + { resource: "storageclasses", group: "storage.k8s.io" }, + ] + try { + const resourceAccessStatuses = await Promise.all( + apiResources.map(apiResource => this.canI({ + resource: apiResource.resource, + group: apiResource.group, + verb: "list", + namespace: this.allowedNamespaces[0] + })) + ) + return apiResources + .filter((resource, i) => resourceAccessStatuses[i]) + .map(apiResource => apiResource.resource) + } catch (error) { + return [] + } + } } diff --git a/src/main/router.ts b/src/main/router.ts index 08bbc1dee0..7c5d48e1d6 100644 --- a/src/main/router.ts +++ b/src/main/router.ts @@ -5,7 +5,7 @@ import path from "path" import { readFile } from "fs-extra" import { Cluster } from "./cluster" import { apiPrefix, appName, outDir } from "../common/vars"; -import { configRoute, helmRoute, kubeconfigRoute, metricsRoute, portForwardRoute, resourceApplierRoute, watchRoute } from "./routes"; +import { helmRoute, kubeconfigRoute, metricsRoute, portForwardRoute, resourceApplierRoute, watchRoute } from "./routes"; export interface RouterRequestOpts { req: http.IncomingMessage; @@ -112,7 +112,6 @@ export class Router { this.handleStaticFile(params.path, response); }); - this.router.add({ method: "get", path: `${apiPrefix}/config` }, configRoute.routeConfig.bind(configRoute)) this.router.add({ method: "get", path: `${apiPrefix}/kubeconfig/service-account/{namespace}/{account}` }, kubeconfigRoute.routeServiceAccountRoute.bind(kubeconfigRoute)) // Watch API diff --git a/src/main/routes/config-route.ts b/src/main/routes/config-route.ts deleted file mode 100644 index 8294af3ded..0000000000 --- a/src/main/routes/config-route.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { app } from "electron" -import { CoreV1Api } from "@kubernetes/client-node" -import { LensApiRequest } from "../router" -import { LensApi } from "../lens-api" -import { Cluster } from "../cluster" - -export interface IConfigRoutePayload { - kubeVersion?: string; - clusterName?: string; - lensVersion?: string; - username?: string; - token?: string; - allowedNamespaces?: string[]; - allowedResources?: string[]; - isClusterAdmin?: boolean; - chartsEnabled: boolean; - kubectlAccess?: boolean; // User accessed via kubectl-lens plugin -} - -// TODO: auto-populate all resources dynamically -const apiResources = [ - { resource: "configmaps" }, - { resource: "cronjobs", group: "batch" }, - { resource: "customresourcedefinitions", group: "apiextensions.k8s.io" }, - { resource: "daemonsets", group: "apps" }, - { resource: "deployments", group: "apps" }, - { resource: "endpoints" }, - { resource: "events" }, - { resource: "horizontalpodautoscalers" }, - { resource: "ingresses", group: "networking.k8s.io" }, - { resource: "jobs", group: "batch" }, - { resource: "namespaces" }, - { resource: "networkpolicies", group: "networking.k8s.io" }, - { resource: "nodes" }, - { resource: "persistentvolumes" }, - { resource: "pods" }, - { resource: "podsecuritypolicies" }, - { resource: "resourcequotas" }, - { resource: "secrets" }, - { resource: "services" }, - { resource: "statefulsets", group: "apps" }, - { resource: "storageclasses", group: "storage.k8s.io" }, -] - -async function getAllowedNamespaces(cluster: Cluster) { - const api = cluster.getProxyKubeconfig().makeApiClient(CoreV1Api) - try { - const namespaceList = await api.listNamespace() - const nsAccessStatuses = await Promise.all( - namespaceList.body.items.map(ns => cluster.canI({ - namespace: ns.metadata.name, - resource: "pods", - verb: "list", - })) - ) - return namespaceList.body.items - .filter((ns, i) => nsAccessStatuses[i]) - .map(ns => ns.metadata.name) - } catch (error) { - const ctx = cluster.getProxyKubeconfig().getContextObject(cluster.contextName) - if (ctx.namespace) { - return [ctx.namespace] - } else { - return [] - } - } -} - -async function getAllowedResources(cluster: Cluster, namespaces: string[]) { - try { - const resourceAccessStatuses = await Promise.all( - apiResources.map(apiResource => cluster.canI({ - resource: apiResource.resource, - group: apiResource.group, - verb: "list", - namespace: namespaces[0] - })) - ) - return apiResources - .filter((resource, i) => resourceAccessStatuses[i]).map(apiResource => apiResource.resource) - } catch (error) { - return [] - } -} - -class ConfigRoute extends LensApi { - public async routeConfig(request: LensApiRequest) { - const { params, response, cluster } = request - - const namespaces = await getAllowedNamespaces(cluster) - const data: IConfigRoutePayload = { - clusterName: cluster.contextName, - lensVersion: app.getVersion(), - kubeVersion: cluster.version, - chartsEnabled: true, - isClusterAdmin: cluster.isAdmin, - allowedResources: await getAllowedResources(cluster, namespaces), - allowedNamespaces: namespaces - }; - - this.respondJson(response, data) - } -} - -export const configRoute = new ConfigRoute() diff --git a/src/main/routes/index.ts b/src/main/routes/index.ts index 3398fe11d4..60a0423de4 100644 --- a/src/main/routes/index.ts +++ b/src/main/routes/index.ts @@ -1,4 +1,3 @@ -export * from "./config-route" export * from "./kubeconfig-route" export * from "./metrics-route" export * from "./port-forward-route" diff --git a/src/renderer/api/kube-watch-api.ts b/src/renderer/api/kube-watch-api.ts index 0459d8689a..3a36ef80a2 100644 --- a/src/renderer/api/kube-watch-api.ts +++ b/src/renderer/api/kube-watch-api.ts @@ -6,9 +6,9 @@ import { autobind, EventEmitter } from "../utils"; import { KubeJsonApiData } from "./kube-json-api"; import type { KubeObjectStore } from "../kube-object.store"; import { KubeApi } from "./kube-api"; -import { configStore } from "../config.store"; import { apiManager } from "./api-manager"; import { apiPrefix, isDevelopment } from "../../common/vars"; +import { clusterStore } from "../../common/cluster-store"; export interface IKubeWatchEvent { type: "ADDED" | "MODIFIED" | "DELETED"; @@ -61,10 +61,10 @@ export class KubeWatchApi { } protected getQuery(): Partial { - const { isClusterAdmin, allowedNamespaces } = configStore; + const { isAdmin, allowedNamespaces } = clusterStore.activeCluster; return { api: this.activeApis.map(api => { - if (isClusterAdmin) return api.getWatchUrl(); + if (isAdmin) return api.getWatchUrl(); return allowedNamespaces.map(namespace => api.getWatchUrl(namespace)) }).flat() } diff --git a/src/renderer/api/rbac.ts b/src/renderer/api/rbac.ts index 46d9d066c0..742b0ff17a 100644 --- a/src/renderer/api/rbac.ts +++ b/src/renderer/api/rbac.ts @@ -1,10 +1,12 @@ -import { configStore } from "../config.store"; +import { clusterStore } from "../../common/cluster-store"; + +// todo: refactor / move to cluster-store.ts? export function isAllowedResource(resources: string | string[]) { if (!Array.isArray(resources)) { resources = [resources]; } - const { allowedResources } = configStore; + const allowedResources = clusterStore.activeCluster?.allowedResources || []; for (const resource of resources) { if (!allowedResources.includes(resource)) { return false; diff --git a/src/renderer/api/terminal-api.ts b/src/renderer/api/terminal-api.ts index da86989eae..0e8bba2df6 100644 --- a/src/renderer/api/terminal-api.ts +++ b/src/renderer/api/terminal-api.ts @@ -1,7 +1,6 @@ import { stringify } from "querystring"; -import { autobind, base64, EventEmitter, interval } from "../utils"; +import { autobind, base64, EventEmitter } from "../utils"; import { WebSocketApi } from "./websocket-api"; -import { configStore } from "../config.store"; import isEqual from "lodash/isEqual" import { isDevelopment } from "../../common/vars"; @@ -25,21 +24,19 @@ enum TerminalColor { NO_COLOR = "\u001b[0m", } -export interface ITerminalApiOptions { +export type TerminalApiQuery = Record & { id: string; node?: string; - colorTheme?: "light" | "dark"; + type?: string | "node"; } export class TerminalApi extends WebSocketApi { protected size: { Width: number; Height: number }; - protected currentToken: string; - protected tokenInterval = interval(60, this.sendNewToken); // refresh every minute public onReady = new EventEmitter<[]>(); public isReady = false; - constructor(protected options: ITerminalApiOptions) { + constructor(protected options: TerminalApiQuery) { super({ logging: isDevelopment, flushOnOpen: false, @@ -47,50 +44,33 @@ export class TerminalApi extends WebSocketApi { }); } - async getUrl(token: string) { - const { hostname, protocol } = location; + async getUrl() { let { port } = location; + const { hostname, protocol } = location; const { id, node } = this.options; const wss = `ws${protocol === "https:" ? "s" : ""}://`; - const queryParams = { token, id }; + const query: TerminalApiQuery = { id }; if (port) { port = `:${port}` } if (node) { - Object.assign(queryParams, { - node: node, - type: "node" - }); + query.node = node; + query.type = "node"; } - return `${wss}${hostname}${port}/api?${stringify(queryParams)}`; + return `${wss}${hostname}${port}/api?${stringify(query)}`; } async connect() { - const token = await configStore.getToken(); - const apiUrl = await this.getUrl(token); - const { colorTheme } = this.options; - this.emitStatus("Connecting ...", { - color: colorTheme == "light" ? TerminalColor.GRAY : TerminalColor.LIGHT_GRAY - }); + const apiUrl = await this.getUrl(); + this.emitStatus("Connecting ..."); this.onData.addListener(this._onReady, { prepend: true }); - this.currentToken = token; - this.tokenInterval.start(); return super.connect(apiUrl); } - @autobind() - async sendNewToken() { - const token = await configStore.getToken(); - if (!this.isReady || token == this.currentToken) return; - this.sendCommand(token, TerminalChannels.TOKEN); - this.currentToken = token; - } - destroy() { if (!this.socket) return; const exitCode = String.fromCharCode(4); // ctrl+d this.sendCommand(exitCode); - this.tokenInterval.stop(); setTimeout(() => super.destroy(), 2000); } diff --git a/src/renderer/components/+apps-releases/release.store.ts b/src/renderer/components/+apps-releases/release.store.ts index 6ef02fca6b..b02cbf7e20 100644 --- a/src/renderer/components/+apps-releases/release.store.ts +++ b/src/renderer/components/+apps-releases/release.store.ts @@ -1,11 +1,11 @@ import isEqual from "lodash/isEqual"; -import { action, observable, when, IReactionDisposer, reaction } from "mobx"; +import { action, IReactionDisposer, observable, reaction, when } from "mobx"; import { autobind } from "../../utils"; import { HelmRelease, helmReleasesApi, IReleaseCreatePayload, IReleaseUpdatePayload } from "../../api/endpoints/helm-releases.api"; import { ItemStore } from "../../item.store"; -import { configStore } from "../../config.store"; -import { secretsStore } from "../+config-secrets/secrets.store"; import { Secret } from "../../api/endpoints"; +import { secretsStore } from "../+config-secrets/secrets.store"; +import { clusterStore } from "../../../common/cluster-store"; @autobind() export class ReleaseStore extends ItemStore { @@ -58,8 +58,8 @@ export class ReleaseStore extends ItemStore { this.isLoading = true; let items; try { - const { isClusterAdmin, allowedNamespaces } = configStore; - items = await this.loadItems(!isClusterAdmin ? allowedNamespaces : null); + const { isAdmin, allowedNamespaces } = clusterStore.activeCluster; + items = await this.loadItems(!isAdmin ? allowedNamespaces : null); } finally { if (items) { items = this.sortItems(items); @@ -73,8 +73,7 @@ export class ReleaseStore extends ItemStore { async loadItems(namespaces?: string[]) { if (!namespaces) { return helmReleasesApi.list(); - } - else { + } else { return Promise .all(namespaces.map(namespace => helmReleasesApi.list(namespace))) .then(items => items.flat()); diff --git a/src/renderer/components/+cluster/cluster.tsx b/src/renderer/components/+cluster/cluster.tsx index 940e10e7ad..29a661d68f 100644 --- a/src/renderer/components/+cluster/cluster.tsx +++ b/src/renderer/components/+cluster/cluster.tsx @@ -1,7 +1,7 @@ import "./cluster.scss" import React from "react"; -import { computed, reaction, when } from "mobx"; +import { computed, reaction } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; import { MainLayout } from "../layout/main-layout"; import { ClusterIssues } from "./cluster-issues"; @@ -13,22 +13,23 @@ import { nodesStore } from "../+nodes/nodes.store"; import { podsStore } from "../+workloads-pods/pods.store"; import { clusterStore } from "./cluster.store"; import { eventStore } from "../+events/event.store"; -import { configStore } from "../../config.store"; import { isAllowedResource } from "../../api/rbac"; @observer export class Cluster extends React.Component { + private dependentStores = [nodesStore, podsStore]; + private watchers = [ interval(60, () => clusterStore.getMetrics()), interval(20, () => eventStore.loadAll()) ]; - private dependentStores = [nodesStore, podsStore]; + @computed get isLoaded() { + return nodesStore.isLoaded && podsStore.isLoaded + } // todo: refactor async componentDidMount() { - await when(() => configStore.isLoaded); - const { dependentStores } = this; if (!isAllowedResource("nodes")) { dependentStores.splice(dependentStores.indexOf(nodesStore), 1) @@ -50,13 +51,6 @@ export class Cluster extends React.Component { ]) } - @computed get isLoaded() { - return ( - nodesStore.isLoaded && - podsStore.isLoaded - ) - } - render() { const { isLoaded } = this; return ( diff --git a/src/renderer/components/+preferences/preferences.tsx b/src/renderer/components/+preferences/preferences.tsx index 4500bea05a..ef7ecd372c 100644 --- a/src/renderer/components/+preferences/preferences.tsx +++ b/src/renderer/components/+preferences/preferences.tsx @@ -82,10 +82,6 @@ export class Preferences extends React.Component { } } - onThemeChange = ({ value }: SelectOption) => { - userStore.preferences.colorTheme = value; - } - onRepoSelect = async ({ value: repo }: SelectOption) => { const isAdded = this.helmAddedRepos.has(repo.name); if (isAdded) { diff --git a/src/renderer/components/+storage/storage.tsx b/src/renderer/components/+storage/storage.tsx index 0951811dcb..973c9c35fc 100644 --- a/src/renderer/components/+storage/storage.tsx +++ b/src/renderer/components/+storage/storage.tsx @@ -9,9 +9,9 @@ import { MainLayout, TabRoute } from "../layout/main-layout"; import { PersistentVolumes, volumesRoute, volumesURL } from "../+storage-volumes"; import { StorageClasses, storageClassesRoute, storageClassesURL } from "../+storage-classes"; import { PersistentVolumeClaims, volumeClaimsRoute, volumeClaimsURL } from "../+storage-volume-claims"; -import { configStore } from "../../config.store"; import { namespaceStore } from "../+namespaces/namespace.store"; import { storageURL } from "./storage.route"; +import { isAllowedResource } from "../../api/rbac"; interface Props extends RouteComponentProps<{}> { } @@ -20,7 +20,6 @@ interface Props extends RouteComponentProps<{}> { export class Storage extends React.Component { static get tabRoutes() { const tabRoutes: TabRoute[] = []; - const { allowedResources } = configStore; const query = namespaceStore.getContextParams() tabRoutes.push({ @@ -30,7 +29,7 @@ export class Storage extends React.Component { path: volumeClaimsRoute.path, }) - if (allowedResources.includes('persistentvolumes')) { + if (isAllowedResource('persistentvolumes')) { tabRoutes.push({ title: Persistent Volumes, component: PersistentVolumes, @@ -39,7 +38,7 @@ export class Storage extends React.Component { }); } - if (allowedResources.includes('storageclasses')) { + if (isAllowedResource('storageclasses')) { tabRoutes.push({ title: Storage Classes, component: StorageClasses, diff --git a/src/renderer/components/+user-management/user-management.tsx b/src/renderer/components/+user-management/user-management.tsx index 3806cc37d7..f8caa438eb 100644 --- a/src/renderer/components/+user-management/user-management.tsx +++ b/src/renderer/components/+user-management/user-management.tsx @@ -1,5 +1,4 @@ import "./user-management.scss" - import React from "react"; import { observer } from "mobx-react"; import { Redirect, Route, Switch } from "react-router"; @@ -11,8 +10,8 @@ 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 { namespaceStore } from "../+namespaces/namespace.store"; -import { configStore } from "../../config.store"; import { PodSecurityPolicies, podSecurityPoliciesRoute, podSecurityPoliciesURL } from "../+pod-security-policies"; +import { isAllowedResource } from "../../api/rbac"; interface Props extends RouteComponentProps<{}> { } @@ -21,7 +20,6 @@ interface Props extends RouteComponentProps<{}> { export class UserManagement extends React.Component { static get tabRoutes() { const tabRoutes: TabRoute[] = []; - const { allowedResources } = configStore; const query = namespaceStore.getContextParams() tabRoutes.push( { @@ -43,7 +41,7 @@ export class UserManagement extends React.Component { path: rolesRoute.path, }, ) - if (allowedResources.includes("podsecuritypolicies")) { + if (isAllowedResource("podsecuritypolicies")) { tabRoutes.push({ title: Pod Security Policies, component: PodSecurityPolicies, diff --git a/src/renderer/components/+workloads-overview/overview-statuses.tsx b/src/renderer/components/+workloads-overview/overview-statuses.tsx index 83575fec86..db5c1f53c6 100644 --- a/src/renderer/components/+workloads-overview/overview-statuses.tsx +++ b/src/renderer/components/+workloads-overview/overview-statuses.tsx @@ -15,13 +15,11 @@ import { cronJobStore } from "../+workloads-cronjobs/cronjob.store"; import { namespaceStore } from "../+namespaces/namespace.store"; import { PageFiltersList } from "../item-object-list/page-filters-list"; import { NamespaceSelectFilter } from "../+namespaces/namespace-select"; -import { configStore } from "../../config.store"; import { isAllowedResource } from "../../api/rbac"; @observer export class OverviewStatuses extends React.Component { render() { - const { allowedResources } = configStore; const { contextNs } = namespaceStore; const pods = isAllowedResource("pods") ? podsStore.getAllByNs(contextNs) : []; const deployments = isAllowedResource("deployments") ? deploymentStore.getAllByNs(contextNs) : []; @@ -37,37 +35,37 @@ export class OverviewStatuses extends React.Component {
- { isAllowedResource("pods") && + {isAllowedResource("pods") &&
Pods ({pods.length})
} - { isAllowedResource("deployments") && + {isAllowedResource("deployments") &&
Deployments ({deployments.length})
} - { isAllowedResource("statefulsets") && + {isAllowedResource("statefulsets") &&
StatefulSets ({statefulSets.length})
} - { isAllowedResource("daemonsets") && + {isAllowedResource("daemonsets") &&
DaemonSets ({daemonSets.length})
} - { isAllowedResource("jobs") && + {isAllowedResource("jobs") &&
Jobs ({jobs.length})
} - { isAllowedResource("cronjobs") && + {isAllowedResource("cronjobs") &&
CronJobs ({cronJobs.length})
diff --git a/src/renderer/components/app.tsx b/src/renderer/components/app.tsx index ae3f4a2b6d..02f243e73e 100755 --- a/src/renderer/components/app.tsx +++ b/src/renderer/components/app.tsx @@ -1,6 +1,7 @@ import "./app.scss"; import React from "react"; import { disposeOnUnmount, observer } from "mobx-react"; +import { computed, observable, reaction } from "mobx"; import { Redirect, Route, Switch } from "react-router"; import { Notifications } from "./notifications"; import { NotFound } from "./+404"; @@ -31,14 +32,12 @@ import { LandingPage, landingRoute, landingURL } from "./+landing-page"; import { ClusterSettings, clusterSettingsRoute } from "./+cluster-settings"; import { Workspaces, workspacesRoute } from "./+workspaces"; import { ErrorBoundary } from "./error-boundary"; -import { computed, observable, reaction } from "mobx"; -import { configStore } from "../config.store"; +import { navigation } from "../navigation"; import { clusterIpc } from "../../common/cluster-ipc"; import { clusterStore } from "../../common/cluster-store"; -import { ClusterStatus } from "./cluster-manager/cluster-status"; import { clusterStatusRoute, clusterStatusURL } from "./cluster-manager/cluster-status.route"; import { Preferences, preferencesRoute } from "./+preferences"; -import { navigation } from "../navigation"; +import { ClusterStatus } from "./cluster-manager/cluster-status"; import { CubeSpinner } from "./spinner"; @observer @@ -52,7 +51,6 @@ export class App extends React.Component { async componentDidMount() { await clusterIpc.activate.invokeFromRenderer(); - await configStore.init(); this.appReady = true; disposeOnUnmount(this, [ diff --git a/src/renderer/components/dock/terminal.store.ts b/src/renderer/components/dock/terminal.store.ts index 278a538852..ee5ab694dc 100644 --- a/src/renderer/components/dock/terminal.store.ts +++ b/src/renderer/components/dock/terminal.store.ts @@ -6,7 +6,6 @@ import { TerminalApi } from "../../api/terminal-api"; import { dockStore, IDockTab, TabId, TabKind } from "./dock.store"; import { WebSocketApiState } from "../../api/websocket-api"; import { _i18n } from "../../i18n"; -import { themeStore } from "../../theme.store"; export interface ITerminalTab extends IDockTab { node?: string; // activate node shell mode @@ -16,7 +15,6 @@ export function isTerminalTab(tab: IDockTab) { return tab && tab.kind === TabKind.TERMINAL; } - export function createTerminalTab(tabParams: Partial = {}) { return dockStore.createTab({ kind: TabKind.TERMINAL, @@ -56,7 +54,6 @@ export class TerminalStore { const api = new TerminalApi({ id: tabId, node: tab.node, - colorTheme: themeStore.activeTheme.type }); const terminal = new Terminal(tabId, api); this.connections.set(tabId, api); diff --git a/src/renderer/components/item-object-list/item-list-layout.tsx b/src/renderer/components/item-object-list/item-list-layout.tsx index 4b11e1254d..902d294771 100644 --- a/src/renderer/components/item-object-list/item-list-layout.tsx +++ b/src/renderer/components/item-object-list/item-list-layout.tsx @@ -19,7 +19,6 @@ import { PageFiltersList } from "./page-filters-list"; import { PageFiltersSelect } from "./page-filters-select"; import { NamespaceSelectFilter } from "../+namespaces/namespace-select"; import { themeStore } from "../../theme.store"; -import { configStore } from "../../config.store"; // todo: refactor, split to small re-usable components @@ -116,7 +115,6 @@ export class ItemListLayout extends React.Component { const stores = [store, ...dependentStores]; if (!isClusterScoped) stores.push(namespaceStore); try { - await when(() => configStore.isLoaded); // todo: remove await Promise.all(stores.map(store => store.loadAll())); const subscriptions = stores.map(store => store.subscribe()); await when(() => this.isUnmounting); diff --git a/src/renderer/components/layout/main-layout.tsx b/src/renderer/components/layout/main-layout.tsx index fc91d16dbb..e09049e8ec 100755 --- a/src/renderer/components/layout/main-layout.tsx +++ b/src/renderer/components/layout/main-layout.tsx @@ -7,11 +7,11 @@ import { matchPath, RouteProps } from "react-router-dom"; import { createStorage, cssNames } from "../../utils"; import { Tab, Tabs } from "../tabs"; import { Sidebar } from "./sidebar"; -import { configStore } from "../../config.store"; import { ErrorBoundary } from "../error-boundary"; import { Dock } from "../dock"; import { navigate, navigation } from "../../navigation"; import { themeStore } from "../../theme.store"; +import { clusterStore } from "../../../common/cluster-store"; export interface TabRoute extends RouteProps { title: React.ReactNode; @@ -47,14 +47,12 @@ export class MainLayout extends React.Component { render() { const { className, contentClass, headerClass, tabs, footer, footerClass, children } = this.props; - const { clusterName } = configStore.config; - const { pathname } = navigation.location; + const clusterName = clusterStore.activeCluster?.contextName; + const routePath = navigation.location.pathname; return (
-
- {clusterName && {clusterName}} -
+ {clusterName}