mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
various configs refactoring/fixes, building project optimizations
This commit is contained in:
1 parent
9fd004b214
commit
bfd1a4e0b8
20 files changed
+181
-118
No files matched your search
+7
-2
@@ -1,10 +1,12 @@
|
||||
// App's common configuration for any process (main, renderer, build pipeline, etc.)
|
||||
import path from "path";
|
||||
|
||||
// Flags
|
||||
export const isMac = process.platform === "darwin"
|
||||
export const isWindows = process.platform === "win32"
|
||||
export const isDebugging = process.env.DEBUG === "true";
|
||||
export const isProduction = process.env.NODE_ENV === "production"
|
||||
export const isDevelopment = !isProduction;
|
||||
export const isDevelopment = isDebugging || !isProduction;
|
||||
export const buildVersion = process.env.BUILD_VERSION;
|
||||
|
||||
// Paths
|
||||
@@ -24,7 +26,10 @@ export const apiPrefix = {
|
||||
BASE: '/api',
|
||||
TERMINAL: '/api-terminal', // terminal api
|
||||
KUBE_BASE: '/api-kube', // kubernetes cluster api
|
||||
KUBE_USERS: '/api-users', // users & groups api
|
||||
KUBE_HELM: '/api-helm', // helm charts api
|
||||
KUBE_RESOURCE_APPLIER: "/api-resource",
|
||||
};
|
||||
|
||||
// Links
|
||||
export const issuesTrackerUrl = "https://github.com/lensapp/lens/issues"
|
||||
export const slackUrl = "https://join.slack.com/t/k8slens/shared_invite/enQtOTc5NjAyNjYyOTk4LWU1NDQ0ZGFkOWJkNTRhYTc2YjVmZDdkM2FkNGM5MjhiYTRhMDU2NDQ1MzIyMDA4ZGZlNmExOTc0N2JmY2M3ZGI"
|
||||
+10
-15
@@ -11,7 +11,7 @@ import path from "path"
|
||||
import { promises } from "fs"
|
||||
import { ensureDir } from "fs-extra"
|
||||
import filenamify from "filenamify"
|
||||
import { v4 as uuid } from "uuid"
|
||||
import uuid from "uuid"
|
||||
|
||||
export type FeatureInstallRequest = {
|
||||
name: string;
|
||||
@@ -92,7 +92,7 @@ export class ClusterManager {
|
||||
configs.forEach(c => {
|
||||
k8s.validateConfig(c)
|
||||
const cluster = new Cluster({
|
||||
id: uuid(),
|
||||
id: uuid.v4(),
|
||||
port: this.port,
|
||||
kubeConfig: k8s.dumpConfigYaml(c),
|
||||
preferences: clusterData.preferences,
|
||||
@@ -115,15 +115,15 @@ export class ClusterManager {
|
||||
logger.debug(`IPC: addCluster`)
|
||||
const cluster = await this.addNewCluster(clusterData)
|
||||
return {
|
||||
addedCluster: this.clusterResponse(cluster),
|
||||
allClusters: Array.from(this.getClusters()).map((cluster: Cluster) => this.clusterResponse(cluster))
|
||||
addedCluster: cluster.toClusterInfo(),
|
||||
allClusters: Array.from(this.getClusters()).map((cluster: Cluster) => cluster.toClusterInfo())
|
||||
}
|
||||
});
|
||||
|
||||
this.promiseIpc.on("getClusters", async (workspaceId: string) => {
|
||||
logger.debug(`IPC: getClusters, workspace ${workspaceId}`)
|
||||
const workspaceClusters = Array.from(this.getClusters()).filter((cluster) => cluster.workspace === workspaceId)
|
||||
return workspaceClusters.map((cluster: Cluster) => this.clusterResponse(cluster))
|
||||
return workspaceClusters.map((cluster: Cluster) => cluster.toClusterInfo())
|
||||
});
|
||||
|
||||
this.promiseIpc.on("getCluster", async (id: string) => {
|
||||
@@ -131,7 +131,7 @@ export class ClusterManager {
|
||||
const cluster = this.getCluster(id)
|
||||
if (cluster) {
|
||||
await cluster.refreshCluster()
|
||||
return this.clusterResponse(cluster)
|
||||
return cluster.toClusterInfo()
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
@@ -179,7 +179,7 @@ export class ClusterManager {
|
||||
if(!cluster.preferences) cluster.preferences = {};
|
||||
cluster.preferences.icon = clusterIcon
|
||||
clusterStore.storeCluster(cluster);
|
||||
return {success: true, cluster: this.clusterResponse(cluster), message: ""}
|
||||
return {success: true, cluster: cluster.toClusterInfo(), message: ""}
|
||||
} catch(error) {
|
||||
return {success: false, message: error}
|
||||
}
|
||||
@@ -191,7 +191,7 @@ export class ClusterManager {
|
||||
if (cluster && cluster.preferences) {
|
||||
cluster.preferences.icon = null;
|
||||
clusterStore.storeCluster(cluster)
|
||||
return {success: true, cluster: this.clusterResponse(cluster), message: ""}
|
||||
return {success: true, cluster: cluster.toClusterInfo(), message: ""}
|
||||
} else {
|
||||
return {success: false, message: "Cluster not found"}
|
||||
}
|
||||
@@ -200,7 +200,7 @@ export class ClusterManager {
|
||||
this.promiseIpc.on("refreshCluster", async (clusterId: string) => {
|
||||
const cluster = this.clusters.get(clusterId)
|
||||
await cluster.refreshCluster()
|
||||
return this.clusterResponse(cluster)
|
||||
return cluster.toClusterInfo()
|
||||
});
|
||||
|
||||
this.promiseIpc.on("stopCluster", (clusterId: string) => {
|
||||
@@ -215,7 +215,7 @@ export class ClusterManager {
|
||||
|
||||
this.promiseIpc.on("removeCluster", (ctx: string) => {
|
||||
logger.debug(`IPC: removeCluster: ${ctx}`)
|
||||
return this.removeCluster(ctx).map((cluster: Cluster) => this.clusterResponse(cluster))
|
||||
return this.removeCluster(ctx).map((cluster: Cluster) => cluster.toClusterInfo())
|
||||
});
|
||||
|
||||
this.promiseIpc.on("clusterStored", (clusterId: string) => {
|
||||
@@ -272,11 +272,6 @@ export class ClusterManager {
|
||||
return cluster;
|
||||
}
|
||||
|
||||
// TODO: remove this
|
||||
protected clusterResponse(cluster: Cluster) {
|
||||
return cluster.toClusterInfo()
|
||||
}
|
||||
|
||||
protected async uploadClusterIcon(cluster: Cluster, fileName: string, src: string): Promise<string> {
|
||||
await ensureDir(ClusterManager.clusterIconDir)
|
||||
fileName = filenamify(cluster.contextName + "-" + fileName)
|
||||
|
||||
+9
-13
@@ -179,16 +179,14 @@ export class Cluster implements ClusterInfo {
|
||||
}
|
||||
}
|
||||
|
||||
protected async k8sRequest(path: string, opts?: request.RequestPromiseOptions) {
|
||||
const options = Object.assign({
|
||||
json: true, timeout: 10000
|
||||
}, (opts || {}))
|
||||
if (!options.headers) {
|
||||
options.headers = {}
|
||||
}
|
||||
options.headers.host = `${this.id}.localhost:${this.port}`
|
||||
|
||||
return request(`http://127.0.0.1:${this.port}/api-kube${path}`, options)
|
||||
protected async k8sRequest(path: string, opts: request.RequestPromiseOptions = {}) {
|
||||
const url = `http://127.0.0.1:${this.port}/api-kube${path}`; // fixme: remove hardcoded api prefix
|
||||
opts.json = true;
|
||||
opts.timeout = 10000;
|
||||
opts.headers = Object.assign({}, opts.headers, {
|
||||
host: `${this.id}.localhost:${this.port}`,
|
||||
});
|
||||
return request(url, opts);
|
||||
}
|
||||
|
||||
protected async getConnectionStatus() {
|
||||
@@ -300,9 +298,7 @@ export class Cluster implements ClusterInfo {
|
||||
if (k8s.podHasIssues(pod)) {
|
||||
uniqEventSources.add(w.involvedObject.uid);
|
||||
}
|
||||
continue; // TODO: refactor
|
||||
} catch (error) {
|
||||
continue;
|
||||
} catch (err) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -132,3 +132,8 @@ app.on("will-quit", async (event) => {
|
||||
if (clusterManager) clusterManager.stop()
|
||||
app.exit(0);
|
||||
})
|
||||
|
||||
// auto-restart app in dev-mode
|
||||
if (isDevelopment) {
|
||||
require('electron-reloader')(module);
|
||||
}
|
||||
+3
-2
@@ -1,10 +1,11 @@
|
||||
import * as winston from "winston"
|
||||
import winston from "winston"
|
||||
import { isDebugging } from "../common/vars";
|
||||
|
||||
const options = {
|
||||
colorize: true,
|
||||
handleExceptions: false,
|
||||
json: false,
|
||||
level: process.env.DEBUG === "true" ? "debug" : "info",
|
||||
level: isDebugging ? "debug" : "info",
|
||||
}
|
||||
|
||||
const logger = winston.createLogger({
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
import { app, BrowserWindow, dialog, Menu, MenuItem, MenuItemConstructorOptions, shell, webContents } from "electron"
|
||||
import { isDevelopment, isMac, isWindows } from "../common/vars";
|
||||
import { isDevelopment, isMac, issuesTrackerUrl, isWindows, slackUrl } from "../common/vars";
|
||||
|
||||
// todo: refactor + split menu sections to separated files, e.g. menus/file.menu.ts
|
||||
|
||||
@@ -183,13 +183,13 @@ export default function initMenu(opts: MenuOptions, promiseIpc: any) {
|
||||
{
|
||||
label: 'Community Slack',
|
||||
click: async () => {
|
||||
shell.openExternal('https://join.slack.com/t/k8slens/shared_invite/enQtOTc5NjAyNjYyOTk4LWU1NDQ0ZGFkOWJkNTRhYTc2YjVmZDdkM2FkNGM5MjhiYTRhMDU2NDQ1MzIyMDA4ZGZlNmExOTc0N2JmY2M3ZGI');
|
||||
shell.openExternal(slackUrl);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Report an Issue',
|
||||
click: async () => {
|
||||
shell.openExternal('https://github.com/lensapp/lens/issues');
|
||||
shell.openExternal(issuesTrackerUrl);
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { compile } from "path-to-regexp";
|
||||
import { apiKubeHelm } from "../index";
|
||||
import { apiHelm } from "../index";
|
||||
import { stringify } from "querystring";
|
||||
import { autobind } from "../../utils";
|
||||
|
||||
@@ -21,7 +21,7 @@ const endpoint = compile(`/v2/charts/:repo?/:name?`) as (params?: {
|
||||
|
||||
export const helmChartsApi = {
|
||||
list() {
|
||||
return apiKubeHelm
|
||||
return apiHelm
|
||||
.get<IHelmChartList>(endpoint())
|
||||
.then(data => {
|
||||
return Object
|
||||
@@ -33,7 +33,7 @@ export const helmChartsApi = {
|
||||
|
||||
get(repo: string, name: string, readmeVersion?: string) {
|
||||
const path = endpoint({ repo, name });
|
||||
return apiKubeHelm
|
||||
return apiHelm
|
||||
.get<IHelmChartDetails>(path + "?" + stringify({ version: readmeVersion }))
|
||||
.then(data => {
|
||||
const versions = data.versions.map(HelmChart.create);
|
||||
@@ -46,7 +46,7 @@ export const helmChartsApi = {
|
||||
},
|
||||
|
||||
getValues(repo: string, name: string, version: string) {
|
||||
return apiKubeHelm
|
||||
return apiHelm
|
||||
.get<string>(`/v2/charts/${repo}/${name}/values?` + stringify({ version }));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import jsYaml from "js-yaml";
|
||||
import { compile } from "path-to-regexp";
|
||||
import { autobind, formatDuration } from "../../utils";
|
||||
import capitalize from "lodash/capitalize";
|
||||
import { apiKubeHelm } from "../index";
|
||||
import { apiHelm } from "../index";
|
||||
import { helmChartStore } from "../../components/+apps-helm-charts/helm-chart.store";
|
||||
import { ItemObject } from "../../item.store";
|
||||
import { KubeObject } from "../kube-object";
|
||||
@@ -69,14 +69,14 @@ const endpoint = compile(`/v2/releases/:namespace?/:name?`) as (
|
||||
|
||||
export const helmReleasesApi = {
|
||||
list(namespace?: string) {
|
||||
return apiKubeHelm
|
||||
return apiHelm
|
||||
.get<HelmRelease[]>(endpoint({ namespace }))
|
||||
.then(releases => releases.map(HelmRelease.create));
|
||||
},
|
||||
|
||||
get(name: string, namespace: string) {
|
||||
const path = endpoint({ name, namespace });
|
||||
return apiKubeHelm.get<IReleaseRawDetails>(path).then(details => {
|
||||
return apiHelm.get<IReleaseRawDetails>(path).then(details => {
|
||||
const items: KubeObject[] = JSON.parse(details.resources).items;
|
||||
const resources = items.map(item => KubeObject.create(item));
|
||||
return {
|
||||
@@ -90,34 +90,34 @@ export const helmReleasesApi = {
|
||||
const { repo, ...data } = payload;
|
||||
data.chart = `${repo}/${data.chart}`;
|
||||
data.values = jsYaml.safeLoad(data.values);
|
||||
return apiKubeHelm.post(endpoint(), { data });
|
||||
return apiHelm.post(endpoint(), { data });
|
||||
},
|
||||
|
||||
update(name: string, namespace: string, payload: IReleaseUpdatePayload): Promise<IReleaseUpdateDetails> {
|
||||
const { repo, ...data } = payload;
|
||||
data.chart = `${repo}/${data.chart}`;
|
||||
data.values = jsYaml.safeLoad(data.values);
|
||||
return apiKubeHelm.put(endpoint({ name, namespace }), { data });
|
||||
return apiHelm.put(endpoint({ name, namespace }), { data });
|
||||
},
|
||||
|
||||
async delete(name: string, namespace: string) {
|
||||
const path = endpoint({ name, namespace });
|
||||
return apiKubeHelm.del(path);
|
||||
return apiHelm.del(path);
|
||||
},
|
||||
|
||||
getValues(name: string, namespace: string) {
|
||||
const path = endpoint({ name, namespace }) + "/values";
|
||||
return apiKubeHelm.get<string>(path);
|
||||
return apiHelm.get<string>(path);
|
||||
},
|
||||
|
||||
getHistory(name: string, namespace: string): Promise<IReleaseRevision[]> {
|
||||
const path = endpoint({ name, namespace }) + "/history";
|
||||
return apiKubeHelm.get(path);
|
||||
return apiHelm.get(path);
|
||||
},
|
||||
|
||||
rollback(name: string, namespace: string, revision: number) {
|
||||
const path = endpoint({ name, namespace }) + "/rollback";
|
||||
return apiKubeHelm.put(path, {
|
||||
return apiHelm.put(path, {
|
||||
data: {
|
||||
revision: revision
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import jsYaml from "js-yaml"
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { KubeJsonApiData } from "../kube-json-api";
|
||||
import { apiKubeResourceApplier } from "../index";
|
||||
import { apiResourceApplier } from "../index";
|
||||
import { apiManager } from "../api-manager";
|
||||
|
||||
export const resourceApplierApi = {
|
||||
@@ -13,7 +13,7 @@ export const resourceApplierApi = {
|
||||
if (typeof resource === "string") {
|
||||
resource = jsYaml.safeLoad(resource);
|
||||
}
|
||||
return apiKubeResourceApplier
|
||||
return apiResourceApplier
|
||||
.post<KubeJsonApiData[]>("/stack", { data: resource })
|
||||
.then(data => {
|
||||
const items = data.map(obj => {
|
||||
|
||||
@@ -13,15 +13,11 @@ export const apiKube = new KubeJsonApi({
|
||||
debug: isDevelopment,
|
||||
apiPrefix: apiPrefix.KUBE_BASE,
|
||||
});
|
||||
export const apiKubeUsers = new KubeJsonApi({
|
||||
debug: isDevelopment,
|
||||
apiPrefix: apiPrefix.KUBE_USERS,
|
||||
});
|
||||
export const apiKubeHelm = new KubeJsonApi({
|
||||
export const apiHelm = new KubeJsonApi({
|
||||
debug: isDevelopment,
|
||||
apiPrefix: apiPrefix.KUBE_HELM,
|
||||
});
|
||||
export const apiKubeResourceApplier = new KubeJsonApi({
|
||||
export const apiResourceApplier = new KubeJsonApi({
|
||||
debug: isDevelopment,
|
||||
apiPrefix: apiPrefix.KUBE_RESOURCE_APPLIER,
|
||||
});
|
||||
@@ -38,6 +34,5 @@ function onApiError(error: JsonApiErrorParsed, res: Response) {
|
||||
|
||||
apiBase.onError.addListener(onApiError);
|
||||
apiKube.onError.addListener(onApiError);
|
||||
apiKubeUsers.onError.addListener(onApiError);
|
||||
apiKubeHelm.onError.addListener(onApiError);
|
||||
apiKubeResourceApplier.onError.addListener(onApiError);
|
||||
apiHelm.onError.addListener(onApiError);
|
||||
apiResourceApplier.onError.addListener(onApiError);
|
||||
@@ -8,6 +8,7 @@ import { 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";
|
||||
|
||||
export interface IKubeWatchEvent<T = any> {
|
||||
type: "ADDED" | "MODIFIED" | "DELETED";
|
||||
@@ -28,9 +29,8 @@ export interface IKubeWatchRouteQuery {
|
||||
export class KubeWatchApi {
|
||||
protected evtSource: EventSource;
|
||||
protected onData = new EventEmitter<[IKubeWatchEvent]>();
|
||||
protected apiUrl = configStore.apiPrefix.BASE + "/watch";
|
||||
protected apiUrl = apiPrefix.BASE + "/watch";
|
||||
protected subscribers = observable.map<KubeApi, number>();
|
||||
protected reconnectInterval = interval(60 * 5, this.reconnect); // background reconnect every 5min
|
||||
protected reconnectTimeoutMs = 5000;
|
||||
protected maxReconnectsOnError = 10;
|
||||
protected reconnectAttempts = this.maxReconnectsOnError;
|
||||
@@ -138,7 +138,7 @@ export class KubeWatchApi {
|
||||
}
|
||||
|
||||
protected writeLog(...data: any[]) {
|
||||
if (configStore.isDevelopment) {
|
||||
if (isDevelopment) {
|
||||
console.log('%cKUBE-WATCH-API:', `font-weight: bold`, ...data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +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";
|
||||
|
||||
export enum TerminalChannels {
|
||||
STDIN = 0,
|
||||
@@ -40,26 +41,28 @@ export class TerminalApi extends WebSocketApi {
|
||||
|
||||
constructor(protected options: ITerminalApiOptions) {
|
||||
super({
|
||||
logging: configStore.isDevelopment,
|
||||
logging: isDevelopment,
|
||||
flushOnOpen: false,
|
||||
pingIntervalSeconds: 30,
|
||||
});
|
||||
}
|
||||
|
||||
async getUrl(token: string) {
|
||||
const { hostname, protocol } = location;
|
||||
var { hostname, protocol, port } = location;
|
||||
const prefix = apiPrefix.TERMINAL;
|
||||
const { id, node } = this.options;
|
||||
const apiPrefix = configStore.apiPrefix.TERMINAL;
|
||||
const wss = `ws${protocol === "https:" ? "s" : ""}://`;
|
||||
const queryParams = { token, id };
|
||||
if (port) {
|
||||
port = `:${port}`
|
||||
}
|
||||
if (node) {
|
||||
Object.assign(queryParams, {
|
||||
node: node,
|
||||
type: "node"
|
||||
});
|
||||
}
|
||||
|
||||
return `${wss}${hostname}${configStore.serverPort}${apiPrefix}/api?${stringify(queryParams)}`;
|
||||
return `${wss}${hostname}${port}${prefix}/api?${stringify(queryParams)}`;
|
||||
}
|
||||
|
||||
async connect() {
|
||||
|
||||
@@ -5,9 +5,9 @@ import { reaction } from "mobx";
|
||||
import { disposeOnUnmount, observer } from "mobx-react";
|
||||
import { t, Trans } from "@lingui/macro";
|
||||
import { Button } from "../button";
|
||||
import { configStore } from "../../config.store";
|
||||
import { navigation } from "../../navigation";
|
||||
import { _i18n } from "../../i18n";
|
||||
import { issuesTrackerUrl, slackUrl, buildVersion } from "../../../common/vars";
|
||||
|
||||
interface Props {
|
||||
}
|
||||
@@ -38,14 +38,14 @@ export class ErrorBoundary extends React.Component<Props, State> {
|
||||
render() {
|
||||
const { error, errorInfo } = this.state;
|
||||
if (error) {
|
||||
const slackLink = <a href="https://join.slack.com/t/k8slens/shared_invite/enQtOTc5NjAyNjYyOTk4LWU1NDQ0ZGFkOWJkNTRhYTc2YjVmZDdkM2FkNGM5MjhiYTRhMDU2NDQ1MzIyMDA4ZGZlNmExOTc0N2JmY2M3ZGI" target="_blank">Slack</a>
|
||||
const githubLink = <a href="https://github.com/lensapp/lens/issues" target="_blank">Github</a>
|
||||
const slackLink = <a href={slackUrl} target="_blank">Slack</a>
|
||||
const githubLink = <a href={issuesTrackerUrl} target="_blank">Github</a>
|
||||
const pageUrl = location.href;
|
||||
return (
|
||||
<div className="ErrorBoundary flex column gaps">
|
||||
<h5>
|
||||
<Trans>App crash at <span className="contrast">{pageUrl}</span></Trans>
|
||||
{configStore.buildVersion && <p><Trans>Build version</Trans>: {configStore.buildVersion}</p>}
|
||||
{buildVersion && <p><Trans>Build version</Trans>: {buildVersion}</p>}
|
||||
</h5>
|
||||
<p>
|
||||
<Trans>
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
import { observable, when } from "mobx";
|
||||
import type { IConfigRoutePayload } from "../main/routes/config";
|
||||
import { apiPrefix, buildVersion, isDevelopment } from "../common/vars";
|
||||
import { autobind, interval } from "./utils";
|
||||
import { configApi } from "./api/endpoints";
|
||||
|
||||
@autobind()
|
||||
export class ConfigStore {
|
||||
readonly isDevelopment = isDevelopment;
|
||||
readonly buildVersion = buildVersion;
|
||||
readonly apiPrefix = apiPrefix;
|
||||
|
||||
protected updater = interval(60, this.load);
|
||||
|
||||
@observable config: Partial<IConfigRoutePayload> = {};
|
||||
@@ -32,11 +27,6 @@ export class ConfigStore {
|
||||
return this.config.token;
|
||||
}
|
||||
|
||||
get serverPort() {
|
||||
const port = location.port;
|
||||
return port ? `:${port}` : "";
|
||||
}
|
||||
|
||||
get allowedNamespaces() {
|
||||
return this.config.allowedNamespaces || [];
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user