mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Merge remote-tracking branch 'origin/master' into eliminate-gst-from-app-paths
This commit is contained in:
56 files changed
+379
-224
No files matched your search
@@ -493,42 +493,9 @@ users:
|
||||
it("moves the icon into preferences", async () => {
|
||||
const storedClusterData = clusterStore.clustersList[0];
|
||||
|
||||
expect(storedClusterData.hasOwnProperty("icon")).toBe(false);
|
||||
expect(storedClusterData.preferences.hasOwnProperty("icon")).toBe(true);
|
||||
expect(
|
||||
storedClusterData.preferences.icon.startsWith("data:;base64,"),
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("for a pre 2.7.0-beta.0 config without a workspace", () => {
|
||||
beforeEach(() => {
|
||||
ClusterStore.resetInstance();
|
||||
const mockOpts = {
|
||||
"some-directory-for-user-data": {
|
||||
"lens-cluster-store.json": JSON.stringify({
|
||||
__internal__: {
|
||||
migrations: {
|
||||
version: "2.6.6",
|
||||
},
|
||||
},
|
||||
cluster1: {
|
||||
kubeConfig: minimalValidKubeConfig,
|
||||
preferences: {
|
||||
terminalCWD: "/some-directory-for-user-data",
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
mockFs(mockOpts);
|
||||
|
||||
clusterStore = mainDi.inject(clusterStoreInjectable);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mockFs.restore();
|
||||
expect(Object.prototype.hasOwnProperty.call(storedClusterData, "icon")).toBe(false);
|
||||
expect(Object.prototype.hasOwnProperty.call(storedClusterData.preferences, "icon")).toBe(true);
|
||||
expect(storedClusterData.preferences.icon.startsWith("data:;base64,")).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -580,6 +547,7 @@ users:
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const minimalValidKubeConfig = JSON.stringify({
|
||||
apiVersion: "v1",
|
||||
clusters: [
|
||||
|
||||
@@ -42,19 +42,19 @@ import { Console } from "console";
|
||||
import { SemVer } from "semver";
|
||||
import electron from "electron";
|
||||
import { stdout, stderr } from "process";
|
||||
import { ThemeStore } from "../../renderer/theme.store";
|
||||
import type { ClusterStoreModel } from "../cluster-store/cluster-store";
|
||||
import { getDisForUnitTesting } from "../../test-utils/get-dis-for-unit-testing";
|
||||
import userStoreInjectable from "../user-store/user-store.injectable";
|
||||
import type { DependencyInjectionContainer } from "@ogre-tools/injectable";
|
||||
import directoryForUserDataInjectable from "../app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||
import type { ClusterStoreModel } from "../cluster-store/cluster-store";
|
||||
import { defaultTheme } from "../vars";
|
||||
|
||||
console = new Console(stdout, stderr);
|
||||
|
||||
describe("user store tests", () => {
|
||||
let userStore: UserStore;
|
||||
let mainDi: DependencyInjectionContainer;
|
||||
|
||||
|
||||
beforeEach(async () => {
|
||||
const dis = getDisForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
@@ -92,7 +92,7 @@ describe("user store tests", () => {
|
||||
userStore.httpsProxy = "abcd://defg";
|
||||
|
||||
expect(userStore.httpsProxy).toBe("abcd://defg");
|
||||
expect(userStore.colorTheme).toBe(ThemeStore.defaultTheme);
|
||||
expect(userStore.colorTheme).toBe(defaultTheme);
|
||||
|
||||
userStore.colorTheme = "light";
|
||||
expect(userStore.colorTheme).toBe("light");
|
||||
@@ -101,7 +101,7 @@ describe("user store tests", () => {
|
||||
it("correctly resets theme to default value", async () => {
|
||||
userStore.colorTheme = "some other theme";
|
||||
userStore.resetTheme();
|
||||
expect(userStore.colorTheme).toBe(ThemeStore.defaultTheme);
|
||||
expect(userStore.colorTheme).toBe(defaultTheme);
|
||||
});
|
||||
|
||||
it("correctly calculates if the last seen version is an old release", () => {
|
||||
|
||||
@@ -20,11 +20,10 @@
|
||||
*/
|
||||
|
||||
import { catalogCategoryRegistry } from "../catalog/catalog-category-registry";
|
||||
import { CatalogEntity, CatalogEntityActionContext, CatalogEntityContextMenuContext, CatalogEntityMetadata, CatalogEntityStatus } from "../catalog";
|
||||
import { CatalogEntity, CatalogEntityActionContext, CatalogEntityContextMenuContext, CatalogEntityMetadata, CatalogEntityStatus, CatalogCategory, CatalogCategorySpec } from "../catalog";
|
||||
import { clusterActivateHandler, clusterDisconnectHandler } from "../cluster-ipc";
|
||||
import { ClusterStore } from "../cluster-store/cluster-store";
|
||||
import { broadcastMessage, requestMain } from "../ipc";
|
||||
import { CatalogCategory, CatalogCategorySpec } from "../catalog";
|
||||
import { app } from "electron";
|
||||
import type { CatalogEntitySpec } from "../catalog/catalog-entity";
|
||||
import { IpcRendererNavigationEvents } from "../../renderer/navigation/events";
|
||||
|
||||
@@ -30,7 +30,15 @@ import { ClusterFrameInfo, clusterFrameMap } from "../cluster-frames";
|
||||
import type { Disposer } from "../utils";
|
||||
import type remote from "@electron/remote";
|
||||
|
||||
const electronRemote = ipcMain ? null : require("@electron/remote");
|
||||
const electronRemote = (() => {
|
||||
if (ipcRenderer) {
|
||||
try {
|
||||
return require("@electron/remote");
|
||||
} catch {}
|
||||
}
|
||||
|
||||
return null;
|
||||
})();
|
||||
|
||||
const subFramesChannel = "ipc:get-sub-frames";
|
||||
|
||||
|
||||
@@ -19,10 +19,10 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { CustomResourceDefinition } from "../endpoints";
|
||||
import { CustomResourceDefinition, CustomResourceDefinitionSpec } from "../endpoints";
|
||||
|
||||
describe("Crds", () => {
|
||||
describe("getVersion", () => {
|
||||
describe("getVersion()", () => {
|
||||
it("should throw if none of the versions are served", () => {
|
||||
const crd = new CustomResourceDefinition({
|
||||
apiVersion: "apiextensions.k8s.io/v1",
|
||||
@@ -136,7 +136,7 @@ describe("Crds", () => {
|
||||
expect(crd.getVersion()).toBe("123");
|
||||
});
|
||||
|
||||
it("should get the version name from the version field", () => {
|
||||
it("should get the version name from the version field, ignoring versions on v1beta", () => {
|
||||
const crd = new CustomResourceDefinition({
|
||||
apiVersion: "apiextensions.k8s.io/v1beta1",
|
||||
kind: "CustomResourceDefinition",
|
||||
@@ -147,7 +147,14 @@ describe("Crds", () => {
|
||||
},
|
||||
spec: {
|
||||
version: "abc",
|
||||
},
|
||||
versions: [
|
||||
{
|
||||
name: "foobar",
|
||||
served: true,
|
||||
storage: true,
|
||||
},
|
||||
],
|
||||
} as CustomResourceDefinitionSpec,
|
||||
});
|
||||
|
||||
expect(crd.getVersion()).toBe("abc");
|
||||
|
||||
@@ -164,14 +164,14 @@ describe("KubeObject", () => {
|
||||
|
||||
describe("isJsonApiDataList", () => {
|
||||
function isAny(val: unknown): val is any {
|
||||
return !Boolean(void val);
|
||||
return true;
|
||||
}
|
||||
|
||||
function isNotAny(val: unknown): val is any {
|
||||
return Boolean(void val);
|
||||
return false;
|
||||
}
|
||||
|
||||
function isBoolean(val: unknown): val is Boolean {
|
||||
function isBoolean(val: unknown): val is boolean {
|
||||
return typeof val === "boolean";
|
||||
}
|
||||
|
||||
|
||||
@@ -48,34 +48,36 @@ export interface CRDVersion {
|
||||
additionalPrinterColumns?: AdditionalPrinterColumnsV1[];
|
||||
}
|
||||
|
||||
export interface CustomResourceDefinition {
|
||||
spec: {
|
||||
group: string;
|
||||
/**
|
||||
* @deprecated for apiextensions.k8s.io/v1 but used previously
|
||||
*/
|
||||
version?: string;
|
||||
names: {
|
||||
plural: string;
|
||||
singular: string;
|
||||
kind: string;
|
||||
listKind: string;
|
||||
};
|
||||
scope: "Namespaced" | "Cluster" | string;
|
||||
/**
|
||||
* @deprecated for apiextensions.k8s.io/v1 but used previously
|
||||
*/
|
||||
validation?: object;
|
||||
versions?: CRDVersion[];
|
||||
conversion: {
|
||||
strategy?: string;
|
||||
webhook?: any;
|
||||
};
|
||||
/**
|
||||
* @deprecated for apiextensions.k8s.io/v1 but used previously
|
||||
*/
|
||||
additionalPrinterColumns?: AdditionalPrinterColumnsV1Beta[];
|
||||
export interface CustomResourceDefinitionSpec {
|
||||
group: string;
|
||||
/**
|
||||
* @deprecated for apiextensions.k8s.io/v1 but used in v1beta1
|
||||
*/
|
||||
version?: string;
|
||||
names: {
|
||||
plural: string;
|
||||
singular: string;
|
||||
kind: string;
|
||||
listKind: string;
|
||||
};
|
||||
scope: "Namespaced" | "Cluster";
|
||||
/**
|
||||
* @deprecated for apiextensions.k8s.io/v1 but used in v1beta1
|
||||
*/
|
||||
validation?: object;
|
||||
versions?: CRDVersion[];
|
||||
conversion: {
|
||||
strategy?: string;
|
||||
webhook?: any;
|
||||
};
|
||||
/**
|
||||
* @deprecated for apiextensions.k8s.io/v1 but used in v1beta1
|
||||
*/
|
||||
additionalPrinterColumns?: AdditionalPrinterColumnsV1Beta[];
|
||||
}
|
||||
|
||||
export interface CustomResourceDefinition {
|
||||
spec: CustomResourceDefinitionSpec;
|
||||
status: {
|
||||
conditions: {
|
||||
lastTransitionTime: string;
|
||||
@@ -150,27 +152,32 @@ export class CustomResourceDefinition extends KubeObject {
|
||||
}
|
||||
|
||||
getPreferedVersion(): CRDVersion {
|
||||
// Prefer the modern `versions` over the legacy `version`
|
||||
if (this.spec.versions) {
|
||||
for (const version of this.spec.versions) {
|
||||
if (version.storage) {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
} else if (this.spec.version) {
|
||||
const { additionalPrinterColumns: apc } = this.spec;
|
||||
const additionalPrinterColumns = apc?.map(({ JSONPath, ...apc }) => ({ ...apc, jsonPath: JSONPath }));
|
||||
const { apiVersion } = this;
|
||||
|
||||
return {
|
||||
name: this.spec.version,
|
||||
served: true,
|
||||
storage: true,
|
||||
schema: this.spec.validation,
|
||||
additionalPrinterColumns,
|
||||
};
|
||||
switch (apiVersion) {
|
||||
case "apiextensions.k8s.io/v1":
|
||||
for (const version of this.spec.versions) {
|
||||
if (version.storage) {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case "apiextensions.k8s.io/v1beta1": {
|
||||
const { additionalPrinterColumns: apc } = this.spec;
|
||||
const additionalPrinterColumns = apc?.map(({ JSONPath, ...apc }) => ({ ...apc, jsonPath: JSONPath }));
|
||||
|
||||
return {
|
||||
name: this.spec.version,
|
||||
served: true,
|
||||
storage: true,
|
||||
schema: this.spec.validation,
|
||||
additionalPrinterColumns,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`Failed to find a version for CustomResourceDefinition ${this.metadata.name}`);
|
||||
throw new Error(`Unknown apiVersion=${apiVersion}: Failed to find a version for CustomResourceDefinition ${this.metadata.name}`);
|
||||
}
|
||||
|
||||
getVersion() {
|
||||
@@ -197,7 +204,7 @@ export class CustomResourceDefinition extends KubeObject {
|
||||
const columns = this.getPreferedVersion().additionalPrinterColumns ?? [];
|
||||
|
||||
return columns
|
||||
.filter(column => column.name != "Age" && (ignorePriority || !column.priority));
|
||||
.filter(column => column.name.toLowerCase() != "age" && (ignorePriority || !column.priority));
|
||||
}
|
||||
|
||||
getValidation() {
|
||||
|
||||
@@ -187,7 +187,7 @@ export class Ingress extends KubeObject {
|
||||
const servicePort = defaultBackend?.service.port.number ?? backend?.servicePort;
|
||||
|
||||
if (rules && rules.length > 0) {
|
||||
if (rules.some(rule => rule.hasOwnProperty("http"))) {
|
||||
if (rules.some(rule => Object.prototype.hasOwnProperty.call(rule, "http"))) {
|
||||
ports.push(httpPort);
|
||||
}
|
||||
} else if (servicePort !== undefined) {
|
||||
|
||||
@@ -184,7 +184,8 @@ export function getMetricLastPoints(metrics: Record<string, IMetrics>) {
|
||||
if (metric.data.result.length) {
|
||||
result[metricName] = +metric.data.result[0].values.slice(-1)[0][1];
|
||||
}
|
||||
} catch (e) {
|
||||
} catch {
|
||||
// ignore error
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -34,6 +34,9 @@ import type { IKubeWatchEvent } from "./kube-watch-event";
|
||||
import { KubeJsonApi, KubeJsonApiData } from "./kube-json-api";
|
||||
import { noop } from "../utils";
|
||||
import type { RequestInit } from "node-fetch";
|
||||
|
||||
// BUG: https://github.com/mysticatea/abort-controller/pull/22
|
||||
// eslint-disable-next-line import/no-named-as-default
|
||||
import AbortController from "abort-controller";
|
||||
import { Agent, AgentOptions } from "https";
|
||||
import type { Patch } from "rfc6902";
|
||||
@@ -698,21 +701,16 @@ export class KubeApi<T extends KubeObject> {
|
||||
}
|
||||
|
||||
protected modifyWatchEvent(event: IKubeWatchEvent<KubeJsonApiData>) {
|
||||
if (event.type === "ERROR") {
|
||||
return;
|
||||
|
||||
switch (event.type) {
|
||||
case "ADDED":
|
||||
case "DELETED":
|
||||
|
||||
case "MODIFIED": {
|
||||
ensureObjectSelfLink(this, event.object);
|
||||
|
||||
const { namespace, resourceVersion } = event.object.metadata;
|
||||
|
||||
this.setResourceVersion(namespace, resourceVersion);
|
||||
this.setResourceVersion("", resourceVersion);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ensureObjectSelfLink(this, event.object);
|
||||
|
||||
const { namespace, resourceVersion } = event.object.metadata;
|
||||
|
||||
this.setResourceVersion(namespace, resourceVersion);
|
||||
this.setResourceVersion("", resourceVersion);
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,9 @@ import { ensureObjectSelfLink, IKubeApiQueryParams, KubeApi } from "./kube-api";
|
||||
import { parseKubeApi } from "./kube-api-parse";
|
||||
import type { KubeJsonApiData } from "./kube-json-api";
|
||||
import type { RequestInit } from "node-fetch";
|
||||
|
||||
// BUG: https://github.com/mysticatea/abort-controller/pull/22
|
||||
// eslint-disable-next-line import/no-named-as-default
|
||||
import AbortController from "abort-controller";
|
||||
import type { Patch } from "rfc6902";
|
||||
|
||||
@@ -469,7 +472,9 @@ export abstract class KubeObjectStore<T extends KubeObject> extends ItemStore<T>
|
||||
|
||||
switch (type) {
|
||||
case "ADDED":
|
||||
case "MODIFIED":
|
||||
|
||||
// falls through
|
||||
case "MODIFIED": {
|
||||
const newItem = new this.api.objectConstructor(object);
|
||||
|
||||
if (!item) {
|
||||
@@ -477,7 +482,9 @@ export abstract class KubeObjectStore<T extends KubeObject> extends ItemStore<T>
|
||||
} else {
|
||||
items[index] = newItem;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case "DELETED":
|
||||
if (item) {
|
||||
items.splice(index, 1);
|
||||
|
||||
@@ -89,7 +89,7 @@ export abstract class LensProtocolRouter {
|
||||
|
||||
public static readonly LoggingPrefix = "[PROTOCOL ROUTER]";
|
||||
|
||||
static readonly ExtensionUrlSchema = `/:${EXTENSION_PUBLISHER_MATCH}(\@[A-Za-z0-9_]+)?/:${EXTENSION_NAME_MATCH}`;
|
||||
static readonly ExtensionUrlSchema = `/:${EXTENSION_PUBLISHER_MATCH}(@[A-Za-z0-9_]+)?/:${EXTENSION_NAME_MATCH}`;
|
||||
|
||||
constructor(protected dependencies: Dependencies) {}
|
||||
|
||||
|
||||
@@ -22,11 +22,11 @@
|
||||
import moment from "moment-timezone";
|
||||
import path from "path";
|
||||
import os from "os";
|
||||
import { ThemeStore } from "../../renderer/theme.store";
|
||||
import { getAppVersion, ObservableToggleSet } from "../utils";
|
||||
import type { editor } from "monaco-editor";
|
||||
import merge from "lodash/merge";
|
||||
import { SemVer } from "semver";
|
||||
import { defaultTheme } from "../vars";
|
||||
|
||||
export interface KubeconfigSyncEntry extends KubeconfigSyncValue {
|
||||
filePath: string;
|
||||
@@ -72,10 +72,10 @@ const shell: PreferenceDescription<string | undefined> = {
|
||||
|
||||
const colorTheme: PreferenceDescription<string> = {
|
||||
fromStore(val) {
|
||||
return val || ThemeStore.defaultTheme;
|
||||
return val || defaultTheme;
|
||||
},
|
||||
toStore(val) {
|
||||
if (!val || val === ThemeStore.defaultTheme) {
|
||||
if (!val || val === defaultTheme) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
export function defineGlobal(propName: string, descriptor: PropertyDescriptor) {
|
||||
const scope = typeof global !== "undefined" ? global : window;
|
||||
|
||||
if (scope.hasOwnProperty(propName)) {
|
||||
if (Object.prototype.hasOwnProperty.call(scope, propName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ export type Falsey = false | 0 | "" | null | undefined;
|
||||
* Create a new type safe empty Iterable
|
||||
* @returns An `Iterable` that yields 0 items
|
||||
*/
|
||||
// eslint-disable-next-line require-yield
|
||||
export function* newEmpty<T>(): IterableIterator<T> {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -31,12 +31,13 @@ export interface ReadFileFromTarOpts {
|
||||
}
|
||||
|
||||
export function readFileFromTar<R = Buffer>({ tarPath, filePath, parseJson }: ReadFileFromTarOpts): Promise<R> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const fileChunks: Buffer[] = [];
|
||||
|
||||
await tar.list({
|
||||
tar.list({
|
||||
file: tarPath,
|
||||
filter: entryPath => path.normalize(entryPath) === filePath,
|
||||
sync: true,
|
||||
onentry(entry: FileStat) {
|
||||
entry.on("data", chunk => {
|
||||
fileChunks.push(chunk);
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { array } from "../utils";
|
||||
import * as array from "../utils/array";
|
||||
|
||||
/**
|
||||
* A strict N-tuple of type T
|
||||
|
||||
@@ -41,6 +41,7 @@ export const isIntegrationTesting = process.argv.includes(integrationTestingArg)
|
||||
export const productName = packageInfo.productName;
|
||||
export const appName = `${packageInfo.productName}${isDevelopment ? "Dev" : ""}`;
|
||||
export const publicPath = "/build/" as string;
|
||||
export const defaultTheme = "lens-dark" as string;
|
||||
|
||||
// Webpack build paths
|
||||
export const contextDir = process.cwd();
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
// Base class for extensions-api registries
|
||||
import { action, observable, makeObservable } from "mobx";
|
||||
import { Singleton } from "../../common/utils";
|
||||
import { LensExtension } from "../lens-extension";
|
||||
import type { LensExtension } from "../lens-extension";
|
||||
|
||||
export class BaseRegistry<T, I = T> extends Singleton {
|
||||
private items = observable.map<T, I>([], { deep: false });
|
||||
|
||||
@@ -25,10 +25,9 @@ import { isLinux, isMac, isPublishConfigured, isTestEnv } from "../common/vars";
|
||||
import { delay } from "../common/utils";
|
||||
import { areArgsUpdateAvailableToBackchannel, AutoUpdateChecking, AutoUpdateLogPrefix, AutoUpdateNoUpdateAvailable, broadcastMessage, onceCorrect, UpdateAvailableChannel, UpdateAvailableToBackchannel } from "../common/ipc";
|
||||
import { once } from "lodash";
|
||||
import { ipcMain } from "electron";
|
||||
import { ipcMain, autoUpdater as electronAutoUpdater } from "electron";
|
||||
import { nextUpdateChannel } from "./utils/update-channel";
|
||||
import { UserStore } from "../common/user-store";
|
||||
import { autoUpdater as electronAutoUpdater } from "electron";
|
||||
|
||||
let installVersion: null | string = null;
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import * as tempy from "tempy";
|
||||
import tempy from "tempy";
|
||||
import fse from "fs-extra";
|
||||
import * as yaml from "js-yaml";
|
||||
import { promiseExecFile } from "../../common/utils/promise-exec";
|
||||
|
||||
@@ -119,7 +119,9 @@ export class HelmRepoManager extends Singleton {
|
||||
if (typeof parsedConfig === "object" && parsedConfig) {
|
||||
return parsedConfig as HelmRepoConfig;
|
||||
}
|
||||
} catch { }
|
||||
} catch {
|
||||
// ignore error
|
||||
}
|
||||
|
||||
return {
|
||||
repositories: [],
|
||||
|
||||
@@ -101,7 +101,9 @@ export const initIpcMainHandlers = ({ electronMenuItems, directoryForLensLocalSt
|
||||
const localStorageFilePath = path.resolve(directoryForLensLocalStorage, `${cluster.id}.json`);
|
||||
|
||||
await remove(localStorageFilePath);
|
||||
} catch {}
|
||||
} catch {
|
||||
// ignore error
|
||||
}
|
||||
});
|
||||
|
||||
ipcMainHandle(clusterSetDeletingHandler, (event, clusterId: string) => {
|
||||
|
||||
+11
-11
@@ -356,10 +356,10 @@ export class Kubectl {
|
||||
bashScript += `export PATH="${helmPath}:${kubectlPath}:$PATH"\n`;
|
||||
bashScript += "export KUBECONFIG=\"$tempkubeconfig\"\n";
|
||||
|
||||
bashScript += `NO_PROXY=\",\${NO_PROXY:-localhost},\"\n`;
|
||||
bashScript += `NO_PROXY=\"\${NO_PROXY//,localhost,/,}\"\n`;
|
||||
bashScript += `NO_PROXY=\"\${NO_PROXY//,127.0.0.1,/,}\"\n`;
|
||||
bashScript += `NO_PROXY=\"localhost,127.0.0.1\${NO_PROXY%,}\"\n`;
|
||||
bashScript += `NO_PROXY=",\${NO_PROXY:-localhost},"\n`;
|
||||
bashScript += `NO_PROXY="\${NO_PROXY//,localhost,/,}"\n`;
|
||||
bashScript += `NO_PROXY="\${NO_PROXY//,127.0.0.1,/,}"\n`;
|
||||
bashScript += `NO_PROXY="localhost,127.0.0.1\${NO_PROXY%,}"\n`;
|
||||
bashScript += "export NO_PROXY\n";
|
||||
bashScript += "unset tempkubeconfig\n";
|
||||
await fsPromises.writeFile(bashScriptPath, bashScript.toString(), { mode: 0o644 });
|
||||
@@ -377,18 +377,18 @@ export class Kubectl {
|
||||
zshScript += "test -f \"$OLD_ZDOTDIR/.zshrc\" && . \"$OLD_ZDOTDIR/.zshrc\"\n";
|
||||
|
||||
// voodoo to replace any previous occurrences of kubectl path in the PATH
|
||||
zshScript += `kubectlpath=\"${kubectlPath}"\n`;
|
||||
zshScript += `helmpath=\"${helmPath}"\n`;
|
||||
zshScript += `kubectlpath="${kubectlPath}"\n`;
|
||||
zshScript += `helmpath="${helmPath}"\n`;
|
||||
zshScript += "p=\":$kubectlpath:\"\n";
|
||||
zshScript += "d=\":$PATH:\"\n";
|
||||
zshScript += `d=\${d//$p/:}\n`;
|
||||
zshScript += `d=\${d/#:/}\n`;
|
||||
zshScript += `export PATH=\"$helmpath:$kubectlpath:\${d/%:/}\"\n`;
|
||||
zshScript += `export PATH="$helmpath:$kubectlpath:\${d/%:/}"\n`;
|
||||
zshScript += "export KUBECONFIG=\"$tempkubeconfig\"\n";
|
||||
zshScript += `NO_PROXY=\",\${NO_PROXY:-localhost},\"\n`;
|
||||
zshScript += `NO_PROXY=\"\${NO_PROXY//,localhost,/,}\"\n`;
|
||||
zshScript += `NO_PROXY=\"\${NO_PROXY//,127.0.0.1,/,}\"\n`;
|
||||
zshScript += `NO_PROXY=\"localhost,127.0.0.1\${NO_PROXY%,}\"\n`;
|
||||
zshScript += `NO_PROXY=",\${NO_PROXY:-localhost},"\n`;
|
||||
zshScript += `NO_PROXY="\${NO_PROXY//,localhost,/,}"\n`;
|
||||
zshScript += `NO_PROXY="\${NO_PROXY//,127.0.0.1,/,}"\n`;
|
||||
zshScript += `NO_PROXY="localhost,127.0.0.1\${NO_PROXY%,}"\n`;
|
||||
zshScript += "export NO_PROXY\n";
|
||||
zshScript += "unset tempkubeconfig\n";
|
||||
zshScript += "unset OLD_ZDOTDIR\n";
|
||||
|
||||
@@ -25,7 +25,7 @@ import { exec } from "child_process";
|
||||
import fs from "fs-extra";
|
||||
import * as yaml from "js-yaml";
|
||||
import path from "path";
|
||||
import * as tempy from "tempy";
|
||||
import tempy from "tempy";
|
||||
import logger from "./logger";
|
||||
import { appEventBus } from "../common/app-event-bus/event-bus";
|
||||
import { cloneJsonObject } from "../common/utils";
|
||||
|
||||
@@ -73,6 +73,7 @@ export class NodeShellSession extends ShellSession {
|
||||
switch (nodeOs) {
|
||||
default:
|
||||
logger.warn(`[NODE-SHELL-SESSION]: could not determine node OS, falling back with assumption of linux`);
|
||||
// fallthrough
|
||||
case "linux":
|
||||
args.push("sh", "-c", "((clear && bash) || (clear && ash) || (clear && sh))");
|
||||
break;
|
||||
|
||||
@@ -134,7 +134,9 @@ export abstract class ShellSession {
|
||||
for (const shellProcess of this.processes.values()) {
|
||||
try {
|
||||
process.kill(shellProcess.pid);
|
||||
} catch {}
|
||||
} catch {
|
||||
// ignore error
|
||||
}
|
||||
}
|
||||
|
||||
this.processes.clear();
|
||||
@@ -212,7 +214,9 @@ export abstract class ShellSession {
|
||||
if (stats.isDirectory()) {
|
||||
return potentialCwd;
|
||||
}
|
||||
} catch {}
|
||||
} catch {
|
||||
// ignore error
|
||||
}
|
||||
}
|
||||
|
||||
return "."; // Always valid
|
||||
|
||||
@@ -33,7 +33,7 @@ export default {
|
||||
const contextName = value[0];
|
||||
|
||||
// Looping all the keys gives out the store internal stuff too...
|
||||
if (contextName === "__internal__" || value[1].hasOwnProperty("kubeConfig")) continue;
|
||||
if (contextName === "__internal__" || Object.prototype.hasOwnProperty.call(value[1], "kubeConfig")) continue;
|
||||
store.set(contextName, { kubeConfig: value[1] });
|
||||
}
|
||||
},
|
||||
|
||||
@@ -34,7 +34,7 @@ export default {
|
||||
if (!cluster.kubeConfig) continue;
|
||||
const config = yaml.load(cluster.kubeConfig);
|
||||
|
||||
if (!config || typeof config !== "object" || !config.hasOwnProperty("users")) {
|
||||
if (!config || typeof config !== "object" || !Object.prototype.hasOwnProperty.call(config, "users")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
|
||||
import { CatalogEntityRegistry } from "../catalog-entity-registry";
|
||||
import "../../../common/catalog-entities";
|
||||
import { catalogCategoryRegistry } from "../../../common/catalog/catalog-category-registry";
|
||||
import { CatalogCategory, CatalogEntityData, CatalogEntityKindData } from "../catalog-entity";
|
||||
import { KubernetesCluster, WebLink } from "../../../common/catalog-entities";
|
||||
|
||||
@@ -28,14 +28,21 @@ import { ClusterStore } from "../../common/cluster-store/cluster-store";
|
||||
import { Disposer, iter } from "../utils";
|
||||
import { once } from "lodash";
|
||||
import logger from "../../common/logger";
|
||||
import { catalogEntityRunContext } from "./catalog-entity";
|
||||
import { CatalogRunEvent } from "../../common/catalog/catalog-run-event";
|
||||
import { ipcRenderer } from "electron";
|
||||
import { CatalogIpcEvents } from "../../common/ipc/catalog";
|
||||
import { navigate } from "../navigation";
|
||||
|
||||
export type EntityFilter = (entity: CatalogEntity) => any;
|
||||
export type CatalogEntityOnBeforeRun = (event: CatalogRunEvent) => void | Promise<void>;
|
||||
|
||||
export const catalogEntityRunContext = {
|
||||
navigate: (url: string) => navigate(url),
|
||||
setCommandPaletteContext: (entity?: CatalogEntity) => {
|
||||
catalogEntityRegistry.activeEntity = entity;
|
||||
},
|
||||
};
|
||||
|
||||
export class CatalogEntityRegistry {
|
||||
@observable protected activeEntityId: string | undefined = undefined;
|
||||
protected _entities = observable.map<string, CatalogEntity>([], { deep: true });
|
||||
|
||||
@@ -19,10 +19,7 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { navigate } from "../navigation";
|
||||
import type { CatalogEntity } from "../../common/catalog";
|
||||
import { catalogEntityRegistry } from "./catalog-entity-registry";
|
||||
|
||||
export { catalogEntityRunContext } from "./catalog-entity-registry";
|
||||
export { CatalogCategory, CatalogEntity } from "../../common/catalog";
|
||||
export type {
|
||||
CatalogEntityData,
|
||||
@@ -33,10 +30,3 @@ export type {
|
||||
CatalogEntityContextMenu,
|
||||
CatalogEntityContextMenuContext,
|
||||
} from "../../common/catalog";
|
||||
|
||||
export const catalogEntityRunContext = {
|
||||
navigate: (url: string) => navigate(url),
|
||||
setCommandPaletteContext: (entity?: CatalogEntity) => {
|
||||
catalogEntityRegistry.activeEntity = entity;
|
||||
},
|
||||
};
|
||||
@@ -45,15 +45,17 @@ export class HpaDetails extends React.Component<HpaDetailsProps> {
|
||||
|
||||
const renderName = (metric: IHpaMetric) => {
|
||||
switch (metric.type) {
|
||||
case HpaMetricType.Resource:
|
||||
const addition = metric.resource.targetAverageUtilization ? <>(as a percentage of request)</> : "";
|
||||
case HpaMetricType.Resource: {
|
||||
const addition = metric.resource.targetAverageUtilization
|
||||
? "(as a percentage of request)"
|
||||
: "";
|
||||
|
||||
return <>Resource {metric.resource.name} on Pods {addition}</>;
|
||||
|
||||
}
|
||||
case HpaMetricType.Pods:
|
||||
return <>{metric.pods.metricName} on Pods</>;
|
||||
|
||||
case HpaMetricType.Object:
|
||||
case HpaMetricType.Object: {
|
||||
const { target } = metric.object;
|
||||
const { kind, name } = target;
|
||||
const objectUrl = getDetailsUrl(apiManager.lookupApiLink(target, hpa));
|
||||
@@ -64,6 +66,7 @@ export class HpaDetails extends React.Component<HpaDetailsProps> {
|
||||
<Link to={objectUrl}>{kind}/{name}</Link>
|
||||
</>
|
||||
);
|
||||
}
|
||||
case HpaMetricType.External:
|
||||
return (
|
||||
<>
|
||||
|
||||
+1
-2
@@ -18,8 +18,7 @@
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { lifecycleEnum } from "@ogre-tools/injectable";
|
||||
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||
import { unpackExtension } from "./unpack-extension";
|
||||
import extensionLoaderInjectable from "../../../../../extensions/extension-loader/extension-loader.injectable";
|
||||
import getExtensionDestFolderInjectable
|
||||
|
||||
@@ -47,8 +47,8 @@ export const getBaseRegistryUrl = ({ getRegistryUrlPreference }: Dependencies) =
|
||||
} catch (error) {
|
||||
Notifications.error(<p>Failed to get configured registry from <code>.npmrc</code>. Falling back to default registry</p>);
|
||||
console.warn("[EXTENSIONS]: failed to get configured registry from .npmrc", error);
|
||||
// fallthrough
|
||||
}
|
||||
// fallthrough
|
||||
}
|
||||
default:
|
||||
case ExtensionRegistryLocation.DEFAULT:
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ import { KubeConfig } from "@kubernetes/client-node";
|
||||
import { fireEvent, render } from "@testing-library/react";
|
||||
import mockFs from "mock-fs";
|
||||
import React from "react";
|
||||
import selectEvent from "react-select-event";
|
||||
import * as selectEvent from "react-select-event";
|
||||
|
||||
import type { Cluster } from "../../../../common/cluster/cluster";
|
||||
import { DeleteClusterDialog } from "../delete-cluster-dialog";
|
||||
|
||||
@@ -21,8 +21,7 @@
|
||||
|
||||
import React from "react";
|
||||
import "@testing-library/jest-dom/extend-expect";
|
||||
import selectEvent from "react-select-event";
|
||||
|
||||
import * as selectEvent from "react-select-event";
|
||||
import { Pod } from "../../../../common/k8s-api/endpoints";
|
||||
import { LogResourceSelector } from "../log-resource-selector";
|
||||
import type { LogTabData } from "../log-tab-store/log-tab.store";
|
||||
@@ -33,8 +32,7 @@ import mockFs from "mock-fs";
|
||||
import { getDiForUnitTesting } from "../../getDiForUnitTesting";
|
||||
import type { DiRender } from "../../test-utils/renderFor";
|
||||
import { renderFor } from "../../test-utils/renderFor";
|
||||
import directoryForUserDataInjectable
|
||||
from "../../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||
import directoryForUserDataInjectable from "../../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||
import callForLogsInjectable from "../log-store/call-for-logs/call-for-logs.injectable";
|
||||
|
||||
jest.mock("electron", () => ({
|
||||
|
||||
@@ -133,7 +133,8 @@ export class FilePicker extends React.Component<Props> {
|
||||
switch (onOverSizeLimit) {
|
||||
case OverSizeLimitStyle.FILTER:
|
||||
return files.filter(file => file.size <= maxSize );
|
||||
case OverSizeLimitStyle.REJECT:
|
||||
|
||||
case OverSizeLimitStyle.REJECT: {
|
||||
const firstFileToLarge = files.find(file => file.size > maxSize);
|
||||
|
||||
if (firstFileToLarge) {
|
||||
@@ -141,6 +142,7 @@ export class FilePicker extends React.Component<Props> {
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +158,9 @@ export class FilePicker extends React.Component<Props> {
|
||||
switch (onOverTotalSizeLimit) {
|
||||
case OverTotalSizeLimitStyle.FILTER_LARGEST:
|
||||
files = _.orderBy(files, ["size"]);
|
||||
case OverTotalSizeLimitStyle.FILTER_LAST:
|
||||
|
||||
// fallthrough
|
||||
case OverTotalSizeLimitStyle.FILTER_LAST: {
|
||||
let newTotalSize = totalSize;
|
||||
|
||||
for (;files.length > 0;) {
|
||||
@@ -168,6 +172,7 @@ export class FilePicker extends React.Component<Props> {
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
case OverTotalSizeLimitStyle.REJECT:
|
||||
throw `Total file size to upload is too large. Expected at most ${maxTotalSize}. Found ${totalSize}.`;
|
||||
}
|
||||
|
||||
@@ -73,6 +73,7 @@ export class Icon extends React.PureComponent<IconProps> {
|
||||
switch (evt.nativeEvent.code) {
|
||||
case "Space":
|
||||
|
||||
// fallthrough
|
||||
case "Enter": {
|
||||
// eslint-disable-next-line react/no-find-dom-node
|
||||
const icon = findDOMNode(this) as HTMLElement;
|
||||
|
||||
@@ -39,7 +39,7 @@ export const isRequired: InputValidator = {
|
||||
export const isEmail: InputValidator = {
|
||||
condition: ({ type }) => type === "email",
|
||||
message: () => `Wrong email format`,
|
||||
validate: value => !!value.match(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/),
|
||||
validate: value => !!value.match(/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/),
|
||||
};
|
||||
|
||||
export const isNumber: InputValidator = {
|
||||
|
||||
@@ -31,7 +31,6 @@ import { apiManager } from "../../../common/k8s-api/api-manager";
|
||||
import { crdStore } from "../+custom-resources/crd.store";
|
||||
import { KubeObjectMenu } from "../kube-object-menu";
|
||||
import { KubeObjectDetailRegistry } from "../../api/kube-object-detail-registry";
|
||||
import logger from "../../../main/logger";
|
||||
import { CrdResourceDetails } from "../+custom-resources";
|
||||
import { KubeObjectMeta } from "../kube-object-meta";
|
||||
import { hideDetails, kubeDetailsUrlParam } from "../kube-detail-params";
|
||||
@@ -62,7 +61,7 @@ export class KubeObjectDetails extends React.Component {
|
||||
.getStore(this.path)
|
||||
?.getByPath(this.path);
|
||||
} catch (error) {
|
||||
logger.error(`[KUBE-OBJECT-DETAILS]: failed to get store or object: ${error}`, { path: this.path });
|
||||
console.error(`[KUBE-OBJECT-DETAILS]: failed to get store or object: ${error}`, { path: this.path });
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
import { hideDetails } from "../../kube-detail-params";
|
||||
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||
|
||||
export const hideDetailsInjectable = getInjectable({
|
||||
const hideDetailsInjectable = getInjectable({
|
||||
instantiate: () => hideDetails,
|
||||
lifecycle: lifecycleEnum.singleton,
|
||||
});
|
||||
|
||||
@@ -27,7 +27,7 @@ import { observer } from "mobx-react";
|
||||
import { boundMethod, cssNames } from "../../utils";
|
||||
import { ConfirmDialog } from "../confirm-dialog";
|
||||
import { Icon, IconProps } from "../icon";
|
||||
import { Menu, MenuItem, MenuProps } from "../menu";
|
||||
import { Menu, MenuItem, MenuProps } from "./menu";
|
||||
import uniqueId from "lodash/uniqueId";
|
||||
import isString from "lodash/isString";
|
||||
|
||||
|
||||
@@ -243,7 +243,9 @@ export class Menu extends React.Component<MenuProps, State> {
|
||||
break;
|
||||
|
||||
case "Space":
|
||||
case "Enter":
|
||||
// fallthrough
|
||||
|
||||
case "Enter": {
|
||||
const focusedItem = this.focusedItem;
|
||||
|
||||
if (focusedItem) {
|
||||
@@ -251,10 +253,12 @@ export class Menu extends React.Component<MenuProps, State> {
|
||||
evt.preventDefault();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "ArrowUp":
|
||||
this.focusNextItem(true);
|
||||
break;
|
||||
|
||||
case "ArrowDown":
|
||||
this.focusNextItem();
|
||||
break;
|
||||
|
||||
@@ -24,7 +24,8 @@ import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { action, computed, makeObservable, observable, reaction } from "mobx";
|
||||
import { editor, Uri } from "monaco-editor";
|
||||
import { MonacoTheme, MonacoValidator, monacoValidators } from "./index";
|
||||
import type { MonacoTheme } from "./monaco-themes";
|
||||
import { MonacoValidator, monacoValidators } from "./monaco-validators";
|
||||
import { debounce, merge } from "lodash";
|
||||
import { cssNames, disposer } from "../../utils";
|
||||
import { UserStore } from "../../../common/user-store";
|
||||
|
||||
@@ -20,8 +20,7 @@
|
||||
*/
|
||||
|
||||
import styles from "./react-table.module.scss";
|
||||
import React from "react";
|
||||
import { useCallback, useMemo } from "react";
|
||||
import React, { useCallback, useMemo } from "react";
|
||||
import { useFlexLayout, useSortBy, useTable, UseTableOptions } from "react-table";
|
||||
import { Icon } from "../icon";
|
||||
import { cssNames } from "../../utils";
|
||||
|
||||
@@ -31,7 +31,8 @@ import { Notifications } from "../components/notifications";
|
||||
import { cssNames } from "../utils";
|
||||
import { getPortForwards } from "./port-forward-store/port-forward-store";
|
||||
import type { ForwardedPort } from "./port-forward-item";
|
||||
import { aboutPortForwarding, openPortForward } from ".";
|
||||
import { openPortForward } from "./port-forward-utils";
|
||||
import { aboutPortForwarding } from "./port-forward-notify";
|
||||
import { Checkbox } from "../components/checkbox";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import modifyPortForwardInjectable from "./port-forward-store/modify-port-forward/modify-port-forward.injectable";
|
||||
|
||||
@@ -33,7 +33,7 @@ export class SearchStore {
|
||||
* @param value Unescaped string
|
||||
*/
|
||||
public static escapeRegex(value?: string): string {
|
||||
return value ? value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&") : "";
|
||||
return value ? value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&") : "";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,6 +27,7 @@ import lensDarkThemeJson from "./themes/lens-dark.json";
|
||||
import lensLightThemeJson from "./themes/lens-light.json";
|
||||
import type { SelectOption } from "./components/select";
|
||||
import type { MonacoEditorProps } from "./components/monaco-editor";
|
||||
import { defaultTheme } from "../common/vars";
|
||||
|
||||
export type ThemeId = string;
|
||||
|
||||
@@ -40,7 +41,6 @@ export interface Theme {
|
||||
}
|
||||
|
||||
export class ThemeStore extends Singleton {
|
||||
static readonly defaultTheme = "lens-dark";
|
||||
protected styles: HTMLStyleElement;
|
||||
|
||||
// bundled themes from `themes/${themeId}.json`
|
||||
@@ -54,7 +54,7 @@ export class ThemeStore extends Singleton {
|
||||
}
|
||||
|
||||
@computed get activeTheme(): Theme {
|
||||
return this.themes.get(this.activeThemeId) ?? this.themes.get(ThemeStore.defaultTheme);
|
||||
return this.themes.get(this.activeThemeId) ?? this.themes.get(defaultTheme);
|
||||
}
|
||||
|
||||
@computed get themeOptions(): SelectOption<string>[] {
|
||||
|
||||
@@ -20,16 +20,8 @@
|
||||
*/
|
||||
|
||||
// Helper for working with storages (e.g. window.localStorage, NodeJS/file-system, etc.)
|
||||
import {
|
||||
action,
|
||||
comparer,
|
||||
computed,
|
||||
makeObservable,
|
||||
observable,
|
||||
toJS,
|
||||
when,
|
||||
} from "mobx";
|
||||
import produce, { Draft, isDraft } from "immer";
|
||||
import { action, comparer, computed, makeObservable, observable, toJS, when } from "mobx";
|
||||
import { produce, Draft, isDraft } from "immer";
|
||||
import { isEqual, isPlainObject } from "lodash";
|
||||
import logger from "../../main/logger";
|
||||
|
||||
@@ -142,7 +134,7 @@ export class StorageHelper<T> {
|
||||
get(): T {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
|
||||
@computed
|
||||
get value(): T {
|
||||
return this.data.get() ?? this.defaultValue;
|
||||
|
||||
Reference in new issue
Block a user