mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Merge branch 'master' into feature/catalog
Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
commit
cc684d62c3
19
Makefile
19
Makefile
@ -1,3 +1,8 @@
|
|||||||
|
CMD_ARGS = $(filter-out $@,$(MAKECMDGOALS))
|
||||||
|
|
||||||
|
%:
|
||||||
|
@:
|
||||||
|
|
||||||
EXTENSIONS_DIR = ./extensions
|
EXTENSIONS_DIR = ./extensions
|
||||||
extensions = $(foreach dir, $(wildcard $(EXTENSIONS_DIR)/*), ${dir})
|
extensions = $(foreach dir, $(wildcard $(EXTENSIONS_DIR)/*), ${dir})
|
||||||
extension_node_modules = $(foreach dir, $(wildcard $(EXTENSIONS_DIR)/*), ${dir}/node_modules)
|
extension_node_modules = $(foreach dir, $(wildcard $(EXTENSIONS_DIR)/*), ${dir}/node_modules)
|
||||||
@ -16,16 +21,16 @@ node_modules: yarn.lock
|
|||||||
yarn install --frozen-lockfile
|
yarn install --frozen-lockfile
|
||||||
yarn check --verify-tree --integrity
|
yarn check --verify-tree --integrity
|
||||||
|
|
||||||
static/build/LensDev.html:
|
static/build/LensDev.html: node_modules
|
||||||
yarn compile:renderer
|
yarn compile:renderer
|
||||||
|
|
||||||
.PHONY: compile-dev
|
.PHONY: compile-dev
|
||||||
compile-dev:
|
compile-dev: node_modules
|
||||||
yarn compile:main --cache
|
yarn compile:main --cache
|
||||||
yarn compile:renderer --cache
|
yarn compile:renderer --cache
|
||||||
|
|
||||||
.PHONY: dev
|
.PHONY: dev
|
||||||
dev: node_modules binaries/client build-extensions static/build/LensDev.html
|
dev: binaries/client build-extensions static/build/LensDev.html
|
||||||
yarn dev
|
yarn dev
|
||||||
|
|
||||||
.PHONY: lint
|
.PHONY: lint
|
||||||
@ -34,7 +39,7 @@ lint:
|
|||||||
|
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
test: binaries/client
|
test: binaries/client
|
||||||
yarn test
|
yarn run jest $(or $(CMD_ARGS), "src")
|
||||||
|
|
||||||
.PHONY: integration-linux
|
.PHONY: integration-linux
|
||||||
integration-linux: binaries/client build-extension-types build-extensions
|
integration-linux: binaries/client build-extension-types build-extensions
|
||||||
@ -58,10 +63,6 @@ integration-win: binaries/client build-extension-types build-extensions
|
|||||||
yarn build:win
|
yarn build:win
|
||||||
yarn integration
|
yarn integration
|
||||||
|
|
||||||
.PHONY: test-app
|
|
||||||
test-app:
|
|
||||||
yarn test
|
|
||||||
|
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
build: node_modules binaries/client build-extensions
|
build: node_modules binaries/client build-extensions
|
||||||
ifeq "$(DETECTED_OS)" "Windows"
|
ifeq "$(DETECTED_OS)" "Windows"
|
||||||
@ -77,7 +78,7 @@ $(extension_dists): src/extensions/npm/extensions/dist
|
|||||||
cd $(@:/dist=) && npm run build
|
cd $(@:/dist=) && npm run build
|
||||||
|
|
||||||
.PHONY: build-extensions
|
.PHONY: build-extensions
|
||||||
build-extensions: $(extension_node_modules) $(extension_dists)
|
build-extensions: node_modules $(extension_node_modules) $(extension_dists)
|
||||||
|
|
||||||
.PHONY: test-extensions
|
.PHONY: test-extensions
|
||||||
test-extensions: $(extension_node_modules)
|
test-extensions: $(extension_node_modules)
|
||||||
|
|||||||
@ -1,9 +1,18 @@
|
|||||||
|
/**
|
||||||
|
* @jest-environment node
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Cluster tests are run if there is a pre-existing minikube cluster. Before running cluster tests the TEST_NAMESPACE
|
||||||
|
namespace is removed, if it exists, from the minikube cluster. Resources are created as part of the cluster tests in the
|
||||||
|
TEST_NAMESPACE namespace. This is done to minimize destructive impact of the cluster tests on an existing minikube
|
||||||
|
cluster and vice versa.
|
||||||
|
*/
|
||||||
import { Application } from "spectron";
|
import { Application } from "spectron";
|
||||||
import * as utils from "../helpers/utils";
|
import * as utils from "../helpers/utils";
|
||||||
import { listHelmRepositories } from "../helpers/utils";
|
import { listHelmRepositories } from "../helpers/utils";
|
||||||
import { fail } from "assert";
|
import { fail } from "assert";
|
||||||
|
|
||||||
|
|
||||||
jest.setTimeout(60000);
|
jest.setTimeout(60000);
|
||||||
|
|
||||||
// FIXME (!): improve / simplify all css-selectors + use [data-test-id="some-id"] (already used in some tests below)
|
// FIXME (!): improve / simplify all css-selectors + use [data-test-id="some-id"] (already used in some tests below)
|
||||||
@ -11,9 +20,11 @@ describe("Lens integration tests", () => {
|
|||||||
let app: Application;
|
let app: Application;
|
||||||
|
|
||||||
describe("app start", () => {
|
describe("app start", () => {
|
||||||
beforeAll(async () => app = await utils.appStart(), 20000);
|
utils.beforeAllWrapped(async () => {
|
||||||
|
app = await utils.appStart();
|
||||||
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
utils.afterAllWrapped(async () => {
|
||||||
if (app?.isRunning()) {
|
if (app?.isRunning()) {
|
||||||
await utils.tearDown(app);
|
await utils.tearDown(app);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,10 +33,12 @@ describe("Lens cluster pages", () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
describe("cluster add", () => {
|
describe("cluster add", () => {
|
||||||
beforeAll(async () => app = await utils.appStart(), 20000);
|
utils.beforeAllWrapped(async () => {
|
||||||
|
app = await utils.appStart();
|
||||||
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
utils.afterAllWrapped(async () => {
|
||||||
if (app && app.isRunning()) {
|
if (app?.isRunning()) {
|
||||||
return utils.tearDown(app);
|
return utils.tearDown(app);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -64,11 +66,10 @@ describe("Lens cluster pages", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe("cluster pages", () => {
|
describe("cluster pages", () => {
|
||||||
|
utils.beforeAllWrapped(appStartAddCluster);
|
||||||
|
|
||||||
beforeAll(appStartAddCluster, 40000);
|
utils.afterAllWrapped(async () => {
|
||||||
|
if (app?.isRunning()) {
|
||||||
afterAll(async () => {
|
|
||||||
if (app && app.isRunning()) {
|
|
||||||
return utils.tearDown(app);
|
return utils.tearDown(app);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -355,10 +356,10 @@ describe("Lens cluster pages", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("viewing pod logs", () => {
|
describe("viewing pod logs", () => {
|
||||||
beforeEach(appStartAddCluster, 40000);
|
utils.beforeEachWrapped(appStartAddCluster);
|
||||||
|
|
||||||
afterEach(async () => {
|
utils.afterEachWrapped(async () => {
|
||||||
if (app && app.isRunning()) {
|
if (app?.isRunning()) {
|
||||||
return utils.tearDown(app);
|
return utils.tearDown(app);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -405,10 +406,10 @@ describe("Lens cluster pages", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("cluster operations", () => {
|
describe("cluster operations", () => {
|
||||||
beforeEach(appStartAddCluster, 40000);
|
utils.beforeEachWrapped(appStartAddCluster);
|
||||||
|
|
||||||
afterEach(async () => {
|
utils.afterEachWrapped(async () => {
|
||||||
if (app && app.isRunning()) {
|
if (app?.isRunning()) {
|
||||||
return utils.tearDown(app);
|
return utils.tearDown(app);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -7,9 +7,11 @@ describe("Lens command palette", () => {
|
|||||||
let app: Application;
|
let app: Application;
|
||||||
|
|
||||||
describe("menu", () => {
|
describe("menu", () => {
|
||||||
beforeAll(async () => app = await utils.appStart(), 20000);
|
utils.beforeAllWrapped(async () => {
|
||||||
|
app = await utils.appStart();
|
||||||
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
utils.afterAllWrapped(async () => {
|
||||||
if (app?.isRunning()) {
|
if (app?.isRunning()) {
|
||||||
await utils.tearDown(app);
|
await utils.tearDown(app);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,13 +13,13 @@ describe("Lens integration tests", () => {
|
|||||||
const ready = minikubeReady("workspace-int-tests");
|
const ready = minikubeReady("workspace-int-tests");
|
||||||
|
|
||||||
utils.describeIf(ready)("workspaces", () => {
|
utils.describeIf(ready)("workspaces", () => {
|
||||||
beforeAll(async () => {
|
utils.beforeAllWrapped(async () => {
|
||||||
app = await utils.appStart();
|
app = await utils.appStart();
|
||||||
await utils.clickWhatsNew(app);
|
await utils.clickWhatsNew(app);
|
||||||
}, 20000);
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
utils.afterAllWrapped(async () => {
|
||||||
if (app && app.isRunning()) {
|
if (app?.isRunning()) {
|
||||||
return utils.tearDown(app);
|
return utils.tearDown(app);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -8,6 +8,39 @@ const AppPaths: Partial<Record<NodeJS.Platform, string>> = {
|
|||||||
"darwin": "./dist/mac/Lens.app/Contents/MacOS/Lens",
|
"darwin": "./dist/mac/Lens.app/Contents/MacOS/Lens",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface DoneCallback {
|
||||||
|
(...args: any[]): any;
|
||||||
|
fail(error?: string | { message: string }): any;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is necessary because Jest doesn't do this correctly.
|
||||||
|
* @param fn The function to call
|
||||||
|
*/
|
||||||
|
export function wrapJestLifecycle(fn: () => Promise<void>): (done: DoneCallback) => void {
|
||||||
|
return function (done: DoneCallback) {
|
||||||
|
fn()
|
||||||
|
.then(() => done())
|
||||||
|
.catch(error => done.fail(error));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function beforeAllWrapped(fn: () => Promise<void>): void {
|
||||||
|
beforeAll(wrapJestLifecycle(fn));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function beforeEachWrapped(fn: () => Promise<void>): void {
|
||||||
|
beforeEach(wrapJestLifecycle(fn));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function afterAllWrapped(fn: () => Promise<void>): void {
|
||||||
|
afterAll(wrapJestLifecycle(fn));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function afterEachWrapped(fn: () => Promise<void>): void {
|
||||||
|
afterEach(wrapJestLifecycle(fn));
|
||||||
|
}
|
||||||
|
|
||||||
export function itIf(condition: boolean) {
|
export function itIf(condition: boolean) {
|
||||||
return condition ? it : it.skip;
|
return condition ? it : it.skip;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,7 +26,6 @@
|
|||||||
"build:linux": "yarn run compile && electron-builder --linux --dir -c.productName=Lens",
|
"build:linux": "yarn run compile && electron-builder --linux --dir -c.productName=Lens",
|
||||||
"build:mac": "yarn run compile && electron-builder --mac --dir -c.productName=Lens",
|
"build:mac": "yarn run compile && electron-builder --mac --dir -c.productName=Lens",
|
||||||
"build:win": "yarn run compile && electron-builder --win --dir -c.productName=Lens",
|
"build:win": "yarn run compile && electron-builder --win --dir -c.productName=Lens",
|
||||||
"test": "scripts/test.sh",
|
|
||||||
"integration": "jest --runInBand integration",
|
"integration": "jest --runInBand integration",
|
||||||
"dist": "yarn run compile && electron-builder --publish onTag",
|
"dist": "yarn run compile && electron-builder --publish onTag",
|
||||||
"dist:win": "yarn run compile && electron-builder --publish onTag --x64 --ia32",
|
"dist:win": "yarn run compile && electron-builder --publish onTag --x64 --ia32",
|
||||||
@ -36,7 +35,7 @@
|
|||||||
"download:kubectl": "yarn run ts-node build/download_kubectl.ts",
|
"download:kubectl": "yarn run ts-node build/download_kubectl.ts",
|
||||||
"download:helm": "yarn run ts-node build/download_helm.ts",
|
"download:helm": "yarn run ts-node build/download_helm.ts",
|
||||||
"build:tray-icons": "yarn run ts-node build/build_tray_icon.ts",
|
"build:tray-icons": "yarn run ts-node build/build_tray_icon.ts",
|
||||||
"lint": "yarn run eslint $@ --ext js,ts,tsx --max-warnings=0 .",
|
"lint": "yarn run eslint --ext js,ts,tsx --max-warnings=0 .",
|
||||||
"lint:fix": "yarn run lint --fix",
|
"lint:fix": "yarn run lint --fix",
|
||||||
"mkdocs-serve-local": "docker build -t mkdocs-serve-local:latest mkdocs/ && docker run --rm -it -p 8000:8000 -v ${PWD}:/docs mkdocs-serve-local:latest",
|
"mkdocs-serve-local": "docker build -t mkdocs-serve-local:latest mkdocs/ && docker run --rm -it -p 8000:8000 -v ${PWD}:/docs mkdocs-serve-local:latest",
|
||||||
"verify-docs": "docker build -t mkdocs-serve-local:latest mkdocs/ && docker run --rm -v ${PWD}:/docs mkdocs-serve-local:latest build --strict",
|
"verify-docs": "docker build -t mkdocs-serve-local:latest mkdocs/ && docker run --rm -v ${PWD}:/docs mkdocs-serve-local:latest build --strict",
|
||||||
@ -52,7 +51,6 @@
|
|||||||
"jest": {
|
"jest": {
|
||||||
"collectCoverage": false,
|
"collectCoverage": false,
|
||||||
"verbose": true,
|
"verbose": true,
|
||||||
"testEnvironment": "node",
|
|
||||||
"transform": {
|
"transform": {
|
||||||
"^.+\\.tsx?$": "ts-jest"
|
"^.+\\.tsx?$": "ts-jest"
|
||||||
},
|
},
|
||||||
@ -288,7 +286,7 @@
|
|||||||
"@types/react-beautiful-dnd": "^13.0.0",
|
"@types/react-beautiful-dnd": "^13.0.0",
|
||||||
"@types/react-dom": "^17.0.0",
|
"@types/react-dom": "^17.0.0",
|
||||||
"@types/react-router-dom": "^5.1.6",
|
"@types/react-router-dom": "^5.1.6",
|
||||||
"@types/react-select": "^3.0.13",
|
"@types/react-select": "^4.0.13",
|
||||||
"@types/react-window": "^1.8.2",
|
"@types/react-window": "^1.8.2",
|
||||||
"@types/readable-stream": "^2.3.9",
|
"@types/readable-stream": "^2.3.9",
|
||||||
"@types/request": "^2.48.5",
|
"@types/request": "^2.48.5",
|
||||||
@ -352,7 +350,7 @@
|
|||||||
"react-beautiful-dnd": "^13.0.0",
|
"react-beautiful-dnd": "^13.0.0",
|
||||||
"react-refresh": "^0.9.0",
|
"react-refresh": "^0.9.0",
|
||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.2.0",
|
||||||
"react-select": "^3.1.0",
|
"react-select": "^4.3.0",
|
||||||
"react-select-event": "^5.1.0",
|
"react-select-event": "^5.1.0",
|
||||||
"react-window": "^1.8.5",
|
"react-window": "^1.8.5",
|
||||||
"sass-loader": "^8.0.2",
|
"sass-loader": "^8.0.2",
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
jest --env=jsdom ${1:-src}
|
|
||||||
@ -34,7 +34,8 @@ jest.mock("electron", () => {
|
|||||||
app: {
|
app: {
|
||||||
getVersion: () => "99.99.99",
|
getVersion: () => "99.99.99",
|
||||||
getPath: () => "tmp",
|
getPath: () => "tmp",
|
||||||
getLocale: () => "en"
|
getLocale: () => "en",
|
||||||
|
setLoginItemSettings: jest.fn(),
|
||||||
},
|
},
|
||||||
ipcMain: {
|
ipcMain: {
|
||||||
handle: jest.fn(),
|
handle: jest.fn(),
|
||||||
@ -91,7 +92,7 @@ describe("empty config", () => {
|
|||||||
|
|
||||||
it("removes cluster from store", async () => {
|
it("removes cluster from store", async () => {
|
||||||
await clusterStore.removeById("foo");
|
await clusterStore.removeById("foo");
|
||||||
expect(clusterStore.getById("foo")).toBeUndefined();
|
expect(clusterStore.getById("foo")).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("sets active cluster", () => {
|
it("sets active cluster", () => {
|
||||||
@ -197,7 +198,7 @@ describe("config with existing clusters", () => {
|
|||||||
expect(storedCluster).toBeTruthy();
|
expect(storedCluster).toBeTruthy();
|
||||||
const storedCluster2 = clusterStore.getById("cluster2");
|
const storedCluster2 = clusterStore.getById("cluster2");
|
||||||
|
|
||||||
expect(storedCluster2).toBeUndefined();
|
expect(storedCluster2).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("allows getting all of the clusters", async () => {
|
it("allows getting all of the clusters", async () => {
|
||||||
|
|||||||
@ -1,7 +1,3 @@
|
|||||||
/**
|
|
||||||
* @jest-environment jsdom
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { SearchStore } from "../search-store";
|
import { SearchStore } from "../search-store";
|
||||||
|
|
||||||
let searchStore: SearchStore = null;
|
let searchStore: SearchStore = null;
|
||||||
|
|||||||
@ -1,3 +1,7 @@
|
|||||||
|
import { Console } from "console";
|
||||||
|
|
||||||
|
console = new Console(process.stdout, process.stderr);
|
||||||
|
|
||||||
import mockFs from "mock-fs";
|
import mockFs from "mock-fs";
|
||||||
|
|
||||||
jest.mock("electron", () => {
|
jest.mock("electron", () => {
|
||||||
@ -5,7 +9,8 @@ jest.mock("electron", () => {
|
|||||||
app: {
|
app: {
|
||||||
getVersion: () => "99.99.99",
|
getVersion: () => "99.99.99",
|
||||||
getPath: () => "tmp",
|
getPath: () => "tmp",
|
||||||
getLocale: () => "en"
|
getLocale: () => "en",
|
||||||
|
setLoginItemSettings: jest.fn(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@ -19,7 +19,7 @@ export interface BaseStoreParams<T = any> extends ConfOptions<T> {
|
|||||||
* Note: T should only contain base JSON serializable types.
|
* Note: T should only contain base JSON serializable types.
|
||||||
*/
|
*/
|
||||||
export abstract class BaseStore<T = any> extends Singleton {
|
export abstract class BaseStore<T = any> extends Singleton {
|
||||||
protected storeConfig: Config<T>;
|
protected storeConfig?: Config<T>;
|
||||||
protected syncDisposers: Function[] = [];
|
protected syncDisposers: Function[] = [];
|
||||||
|
|
||||||
whenLoaded = when(() => this.isLoaded);
|
whenLoaded = when(() => this.isLoaded);
|
||||||
@ -36,7 +36,7 @@ export abstract class BaseStore<T = any> extends Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get name() {
|
get name() {
|
||||||
return path.basename(this.storeConfig.path);
|
return path.basename(this.path);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected get syncRendererChannel() {
|
protected get syncRendererChannel() {
|
||||||
@ -48,7 +48,7 @@ export abstract class BaseStore<T = any> extends Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get path() {
|
get path() {
|
||||||
return this.storeConfig.path;
|
return this.storeConfig?.path || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async init() {
|
protected async init() {
|
||||||
@ -82,10 +82,13 @@ export abstract class BaseStore<T = any> extends Singleton {
|
|||||||
|
|
||||||
protected async saveToFile(model: T) {
|
protected async saveToFile(model: T) {
|
||||||
logger.info(`[STORE]: SAVING ${this.path}`);
|
logger.info(`[STORE]: SAVING ${this.path}`);
|
||||||
|
|
||||||
// todo: update when fixed https://github.com/sindresorhus/conf/issues/114
|
// todo: update when fixed https://github.com/sindresorhus/conf/issues/114
|
||||||
Object.entries(model).forEach(([key, value]) => {
|
if (this.storeConfig) {
|
||||||
this.storeConfig.set(key, value);
|
for (const [key, value] of Object.entries(model)) {
|
||||||
});
|
this.storeConfig.set(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enableSync() {
|
enableSync() {
|
||||||
|
|||||||
@ -212,8 +212,12 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
setActive(id: ClusterId) {
|
setActive(clusterId: ClusterId) {
|
||||||
const clusterId = this.clusters.has(id) ? id : null;
|
const cluster = this.clusters.get(clusterId);
|
||||||
|
|
||||||
|
if (!cluster?.enabled) {
|
||||||
|
clusterId = null;
|
||||||
|
}
|
||||||
|
|
||||||
this.activeCluster = clusterId;
|
this.activeCluster = clusterId;
|
||||||
}
|
}
|
||||||
@ -244,8 +248,8 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
|||||||
return this.clusters.size > 0;
|
return this.clusters.size > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
getById(id: ClusterId): Cluster {
|
getById(id: ClusterId): Cluster | null {
|
||||||
return this.clusters.get(id);
|
return this.clusters.get(id) ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
|
|||||||
@ -4,3 +4,7 @@ fetchMock.enableMocks();
|
|||||||
|
|
||||||
// Mock __non_webpack_require__ for tests
|
// Mock __non_webpack_require__ for tests
|
||||||
globalThis.__non_webpack_require__ = jest.fn();
|
globalThis.__non_webpack_require__ = jest.fn();
|
||||||
|
|
||||||
|
process.on("unhandledRejection", (err) => {
|
||||||
|
fail(err);
|
||||||
|
});
|
||||||
|
|||||||
@ -70,7 +70,7 @@ class HelmApiRoute extends LensApi {
|
|||||||
this.respondJson(response, result);
|
this.respondJson(response, result);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.debug(error);
|
logger.debug(error);
|
||||||
this.respondText(response, error);
|
this.respondText(response, error, 422);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ class HelmApiRoute extends LensApi {
|
|||||||
this.respondJson(response, result);
|
this.respondJson(response, result);
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
logger.debug(error);
|
logger.debug(error);
|
||||||
this.respondText(response, error);
|
this.respondText(response, error, 422);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
import packageInfo from "../../package.json";
|
import packageInfo from "../../package.json";
|
||||||
import { Menu, NativeImage, Tray } from "electron";
|
import { Menu, Tray } from "electron";
|
||||||
import { autorun } from "mobx";
|
import { autorun } from "mobx";
|
||||||
import { showAbout } from "./menu";
|
import { showAbout } from "./menu";
|
||||||
import { checkForUpdates } from "./app-updater";
|
import { checkForUpdates } from "./app-updater";
|
||||||
@ -10,6 +10,8 @@ import logger from "./logger";
|
|||||||
import { isDevelopment, isWindows } from "../common/vars";
|
import { isDevelopment, isWindows } from "../common/vars";
|
||||||
import { exitApp } from "./exit-app";
|
import { exitApp } from "./exit-app";
|
||||||
|
|
||||||
|
const TRAY_LOG_PREFIX = "[TRAY]";
|
||||||
|
|
||||||
// note: instance of Tray should be saved somewhere, otherwise it disappears
|
// note: instance of Tray should be saved somewhere, otherwise it disappears
|
||||||
export let tray: Tray;
|
export let tray: Tray;
|
||||||
|
|
||||||
@ -22,69 +24,70 @@ export function getTrayIcon(): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function initTray(windowManager: WindowManager) {
|
export function initTray(windowManager: WindowManager) {
|
||||||
const dispose = autorun(() => {
|
const icon = getTrayIcon();
|
||||||
try {
|
|
||||||
const menu = createTrayMenu(windowManager);
|
|
||||||
|
|
||||||
buildTray(getTrayIcon(), menu, windowManager);
|
tray = new Tray(icon);
|
||||||
} catch (err) {
|
tray.setToolTip(packageInfo.description);
|
||||||
logger.error(`[TRAY]: building failed: ${err}`);
|
tray.setIgnoreDoubleClickEvents(true);
|
||||||
}
|
|
||||||
});
|
if (isWindows) {
|
||||||
|
tray.on("click", () => {
|
||||||
|
windowManager
|
||||||
|
.ensureMainWindow()
|
||||||
|
.catch(error => logger.error(`${TRAY_LOG_PREFIX}: Failed to open lens`, { error }));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const disposers = [
|
||||||
|
autorun(() => {
|
||||||
|
try {
|
||||||
|
const menu = createTrayMenu(windowManager);
|
||||||
|
|
||||||
|
tray.setContextMenu(menu);
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(`${TRAY_LOG_PREFIX}: building failed`, { error });
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
dispose();
|
disposers.forEach(disposer => disposer());
|
||||||
tray?.destroy();
|
tray?.destroy();
|
||||||
tray = null;
|
tray = null;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildTray(icon: string | NativeImage, menu: Menu, windowManager: WindowManager) {
|
|
||||||
if (!tray) {
|
|
||||||
tray = new Tray(icon);
|
|
||||||
tray.setToolTip(packageInfo.description);
|
|
||||||
tray.setIgnoreDoubleClickEvents(true);
|
|
||||||
tray.setImage(icon);
|
|
||||||
tray.setContextMenu(menu);
|
|
||||||
|
|
||||||
if (isWindows) {
|
|
||||||
tray.on("click", () => {
|
|
||||||
windowManager.ensureMainWindow();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return tray;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createTrayMenu(windowManager: WindowManager): Menu {
|
function createTrayMenu(windowManager: WindowManager): Menu {
|
||||||
return Menu.buildFromTemplate([
|
return Menu.buildFromTemplate([
|
||||||
{
|
{
|
||||||
label: "Open Lens",
|
label: "Open Lens",
|
||||||
async click() {
|
click() {
|
||||||
await windowManager.ensureMainWindow();
|
windowManager
|
||||||
|
.ensureMainWindow()
|
||||||
|
.catch(error => logger.error(`${TRAY_LOG_PREFIX}: Failed to open lens`, { error }));
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Preferences",
|
label: "Preferences",
|
||||||
click() {
|
click() {
|
||||||
windowManager.navigate(preferencesURL());
|
windowManager
|
||||||
|
.navigate(preferencesURL())
|
||||||
|
.catch(error => logger.error(`${TRAY_LOG_PREFIX}: Failed to nativate to Preferences`, { error }));
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Check for updates",
|
label: "Check for updates",
|
||||||
async click() {
|
click() {
|
||||||
await checkForUpdates();
|
checkForUpdates()
|
||||||
await windowManager.ensureMainWindow();
|
.then(() => windowManager.ensureMainWindow());
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "About Lens",
|
label: "About Lens",
|
||||||
async click() {
|
click() {
|
||||||
// note: argument[1] (browserWindow) not available when app is not focused / hidden
|
windowManager.ensureMainWindow()
|
||||||
const browserWindow = await windowManager.ensureMainWindow();
|
.then(showAbout)
|
||||||
|
.catch(error => logger.error(`${TRAY_LOG_PREFIX}: Failed to show Lens About view`, { error }));
|
||||||
showAbout(browserWindow);
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ type: "separator" },
|
{ type: "separator" },
|
||||||
|
|||||||
@ -1,134 +1,115 @@
|
|||||||
|
jest.mock("../kube-object");
|
||||||
|
jest.mock("../kube-api");
|
||||||
|
jest.mock("../api-manager", () => ({
|
||||||
|
apiManager() {
|
||||||
|
return {
|
||||||
|
registerStore: jest.fn(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
import { IKubeApiParsed, parseKubeApi } from "../kube-api-parse";
|
import { IKubeApiParsed, parseKubeApi } from "../kube-api-parse";
|
||||||
|
|
||||||
interface KubeApiParseTestData {
|
/**
|
||||||
url: string;
|
* [<input-url>, <expected-result>]
|
||||||
expected: Required<IKubeApiParsed>;
|
*/
|
||||||
}
|
type KubeApiParseTestData = [string, Required<IKubeApiParsed>];
|
||||||
|
|
||||||
const tests: KubeApiParseTestData[] = [
|
const tests: KubeApiParseTestData[] = [
|
||||||
{
|
["/apis/apiextensions.k8s.io/v1beta1/customresourcedefinitions/prometheuses.monitoring.coreos.com", {
|
||||||
url: "/apis/apiextensions.k8s.io/v1beta1/customresourcedefinitions/prometheuses.monitoring.coreos.com",
|
apiBase: "/apis/apiextensions.k8s.io/v1beta1/customresourcedefinitions",
|
||||||
expected: {
|
apiPrefix: "/apis",
|
||||||
apiBase: "/apis/apiextensions.k8s.io/v1beta1/customresourcedefinitions",
|
apiGroup: "apiextensions.k8s.io",
|
||||||
apiPrefix: "/apis",
|
apiVersion: "v1beta1",
|
||||||
apiGroup: "apiextensions.k8s.io",
|
apiVersionWithGroup: "apiextensions.k8s.io/v1beta1",
|
||||||
apiVersion: "v1beta1",
|
namespace: undefined,
|
||||||
apiVersionWithGroup: "apiextensions.k8s.io/v1beta1",
|
resource: "customresourcedefinitions",
|
||||||
namespace: undefined,
|
name: "prometheuses.monitoring.coreos.com"
|
||||||
resource: "customresourcedefinitions",
|
}],
|
||||||
name: "prometheuses.monitoring.coreos.com"
|
["/api/v1/namespaces/kube-system/pods/coredns-6955765f44-v8p27", {
|
||||||
},
|
apiBase: "/api/v1/pods",
|
||||||
},
|
apiPrefix: "/api",
|
||||||
{
|
apiGroup: "",
|
||||||
url: "/api/v1/namespaces/kube-system/pods/coredns-6955765f44-v8p27",
|
apiVersion: "v1",
|
||||||
expected: {
|
apiVersionWithGroup: "v1",
|
||||||
apiBase: "/api/v1/pods",
|
namespace: "kube-system",
|
||||||
apiPrefix: "/api",
|
resource: "pods",
|
||||||
apiGroup: "",
|
name: "coredns-6955765f44-v8p27"
|
||||||
apiVersion: "v1",
|
}],
|
||||||
apiVersionWithGroup: "v1",
|
["/apis/stable.example.com/foo1/crontabs", {
|
||||||
namespace: "kube-system",
|
apiBase: "/apis/stable.example.com/foo1/crontabs",
|
||||||
resource: "pods",
|
apiPrefix: "/apis",
|
||||||
name: "coredns-6955765f44-v8p27"
|
apiGroup: "stable.example.com",
|
||||||
},
|
apiVersion: "foo1",
|
||||||
},
|
apiVersionWithGroup: "stable.example.com/foo1",
|
||||||
{
|
resource: "crontabs",
|
||||||
url: "/apis/stable.example.com/foo1/crontabs",
|
name: undefined,
|
||||||
expected: {
|
namespace: undefined,
|
||||||
apiBase: "/apis/stable.example.com/foo1/crontabs",
|
}],
|
||||||
apiPrefix: "/apis",
|
["/apis/cluster.k8s.io/v1alpha1/clusters", {
|
||||||
apiGroup: "stable.example.com",
|
apiBase: "/apis/cluster.k8s.io/v1alpha1/clusters",
|
||||||
apiVersion: "foo1",
|
apiPrefix: "/apis",
|
||||||
apiVersionWithGroup: "stable.example.com/foo1",
|
apiGroup: "cluster.k8s.io",
|
||||||
resource: "crontabs",
|
apiVersion: "v1alpha1",
|
||||||
name: undefined,
|
apiVersionWithGroup: "cluster.k8s.io/v1alpha1",
|
||||||
namespace: undefined,
|
resource: "clusters",
|
||||||
},
|
name: undefined,
|
||||||
},
|
namespace: undefined,
|
||||||
{
|
}],
|
||||||
url: "/apis/cluster.k8s.io/v1alpha1/clusters",
|
["/api/v1/namespaces", {
|
||||||
expected: {
|
apiBase: "/api/v1/namespaces",
|
||||||
apiBase: "/apis/cluster.k8s.io/v1alpha1/clusters",
|
apiPrefix: "/api",
|
||||||
apiPrefix: "/apis",
|
apiGroup: "",
|
||||||
apiGroup: "cluster.k8s.io",
|
apiVersion: "v1",
|
||||||
apiVersion: "v1alpha1",
|
apiVersionWithGroup: "v1",
|
||||||
apiVersionWithGroup: "cluster.k8s.io/v1alpha1",
|
resource: "namespaces",
|
||||||
resource: "clusters",
|
name: undefined,
|
||||||
name: undefined,
|
namespace: undefined,
|
||||||
namespace: undefined,
|
}],
|
||||||
},
|
["/api/v1/secrets", {
|
||||||
},
|
apiBase: "/api/v1/secrets",
|
||||||
{
|
apiPrefix: "/api",
|
||||||
url: "/api/v1/namespaces",
|
apiGroup: "",
|
||||||
expected: {
|
apiVersion: "v1",
|
||||||
apiBase: "/api/v1/namespaces",
|
apiVersionWithGroup: "v1",
|
||||||
apiPrefix: "/api",
|
resource: "secrets",
|
||||||
apiGroup: "",
|
name: undefined,
|
||||||
apiVersion: "v1",
|
namespace: undefined,
|
||||||
apiVersionWithGroup: "v1",
|
}],
|
||||||
resource: "namespaces",
|
["/api/v1/nodes/minikube", {
|
||||||
name: undefined,
|
apiBase: "/api/v1/nodes",
|
||||||
namespace: undefined,
|
apiPrefix: "/api",
|
||||||
},
|
apiGroup: "",
|
||||||
},
|
apiVersion: "v1",
|
||||||
{
|
apiVersionWithGroup: "v1",
|
||||||
url: "/api/v1/secrets",
|
resource: "nodes",
|
||||||
expected: {
|
name: "minikube",
|
||||||
apiBase: "/api/v1/secrets",
|
namespace: undefined,
|
||||||
apiPrefix: "/api",
|
}],
|
||||||
apiGroup: "",
|
["/api/foo-bar/nodes/minikube", {
|
||||||
apiVersion: "v1",
|
apiBase: "/api/foo-bar/nodes",
|
||||||
apiVersionWithGroup: "v1",
|
apiPrefix: "/api",
|
||||||
resource: "secrets",
|
apiGroup: "",
|
||||||
name: undefined,
|
apiVersion: "foo-bar",
|
||||||
namespace: undefined,
|
apiVersionWithGroup: "foo-bar",
|
||||||
},
|
resource: "nodes",
|
||||||
},
|
name: "minikube",
|
||||||
{
|
namespace: undefined,
|
||||||
url: "/api/v1/nodes/minikube",
|
}],
|
||||||
expected: {
|
["/api/v1/namespaces/kube-public", {
|
||||||
apiBase: "/api/v1/nodes",
|
apiBase: "/api/v1/namespaces",
|
||||||
apiPrefix: "/api",
|
apiPrefix: "/api",
|
||||||
apiGroup: "",
|
apiGroup: "",
|
||||||
apiVersion: "v1",
|
apiVersion: "v1",
|
||||||
apiVersionWithGroup: "v1",
|
apiVersionWithGroup: "v1",
|
||||||
resource: "nodes",
|
resource: "namespaces",
|
||||||
name: "minikube",
|
name: "kube-public",
|
||||||
namespace: undefined,
|
namespace: undefined,
|
||||||
},
|
}],
|
||||||
},
|
|
||||||
{
|
|
||||||
url: "/api/foo-bar/nodes/minikube",
|
|
||||||
expected: {
|
|
||||||
apiBase: "/api/foo-bar/nodes",
|
|
||||||
apiPrefix: "/api",
|
|
||||||
apiGroup: "",
|
|
||||||
apiVersion: "foo-bar",
|
|
||||||
apiVersionWithGroup: "foo-bar",
|
|
||||||
resource: "nodes",
|
|
||||||
name: "minikube",
|
|
||||||
namespace: undefined,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
url: "/api/v1/namespaces/kube-public",
|
|
||||||
expected: {
|
|
||||||
apiBase: "/api/v1/namespaces",
|
|
||||||
apiPrefix: "/api",
|
|
||||||
apiGroup: "",
|
|
||||||
apiVersion: "v1",
|
|
||||||
apiVersionWithGroup: "v1",
|
|
||||||
resource: "namespaces",
|
|
||||||
name: "kube-public",
|
|
||||||
namespace: undefined,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
describe("parseApi unit tests", () => {
|
describe("parseApi unit tests", () => {
|
||||||
for (const { url, expected } of tests) {
|
it.each(tests)("testing %s", (url, expected) => {
|
||||||
test(`testing "${url}"`, () => {
|
expect(parseKubeApi(url)).toStrictEqual(expected);
|
||||||
expect(parseKubeApi(url)).toStrictEqual(expected);
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|||||||
@ -28,7 +28,7 @@ describe("KubeApi", () => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const apiBase = "/apis/networking.k8s.io/v1/ingresses";
|
const apiBase = "/apis/networking.k8s.io/v1/ingresses";
|
||||||
const fallbackApiBase = "/apis/extensions/v1beta1/ingresses";
|
const fallbackApiBase = "/apis/extensions/v1beta1/ingresses";
|
||||||
const kubeApi = new KubeApi({
|
const kubeApi = new KubeApi({
|
||||||
@ -36,7 +36,7 @@ describe("KubeApi", () => {
|
|||||||
fallbackApiBases: [fallbackApiBase],
|
fallbackApiBases: [fallbackApiBase],
|
||||||
checkPreferredVersion: true,
|
checkPreferredVersion: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
await kubeApi.get();
|
await kubeApi.get();
|
||||||
expect(kubeApi.apiPrefix).toEqual("/apis");
|
expect(kubeApi.apiPrefix).toEqual("/apis");
|
||||||
expect(kubeApi.apiGroup).toEqual("networking.k8s.io");
|
expect(kubeApi.apiGroup).toEqual("networking.k8s.io");
|
||||||
|
|||||||
303
src/renderer/api/__tests__/pods.test.ts
Normal file
303
src/renderer/api/__tests__/pods.test.ts
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
import { Pod } from "../endpoints";
|
||||||
|
|
||||||
|
interface GetDummyPodOptions {
|
||||||
|
running?: number;
|
||||||
|
dead?: number;
|
||||||
|
initRunning?: number;
|
||||||
|
initDead?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDummyPodDefaultOptions(): Required<GetDummyPodOptions> {
|
||||||
|
return {
|
||||||
|
running: 0,
|
||||||
|
dead: 0,
|
||||||
|
initDead: 0,
|
||||||
|
initRunning: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDummyPod(opts: GetDummyPodOptions = getDummyPodDefaultOptions()): Pod {
|
||||||
|
const pod = new Pod({
|
||||||
|
apiVersion: "v1",
|
||||||
|
kind: "Pod",
|
||||||
|
metadata: {
|
||||||
|
uid: "1",
|
||||||
|
name: "test",
|
||||||
|
resourceVersion: "v1",
|
||||||
|
selfLink: "http"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
pod.spec = {
|
||||||
|
containers: [],
|
||||||
|
initContainers: [],
|
||||||
|
serviceAccount: "dummy",
|
||||||
|
serviceAccountName: "dummy",
|
||||||
|
};
|
||||||
|
|
||||||
|
pod.status = {
|
||||||
|
phase: "Running",
|
||||||
|
conditions: [],
|
||||||
|
hostIP: "10.0.0.1",
|
||||||
|
podIP: "10.0.0.1",
|
||||||
|
startTime: "now",
|
||||||
|
containerStatuses: [],
|
||||||
|
initContainerStatuses: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
for (let i = 0; i < opts.running; i += 1) {
|
||||||
|
const name = `container_r_${i}`;
|
||||||
|
|
||||||
|
pod.spec.containers.push({
|
||||||
|
image: "dummy",
|
||||||
|
imagePullPolicy: "dummy",
|
||||||
|
name,
|
||||||
|
});
|
||||||
|
pod.status.containerStatuses.push({
|
||||||
|
image: "dummy",
|
||||||
|
imageID: "dummy",
|
||||||
|
name,
|
||||||
|
ready: true,
|
||||||
|
restartCount: i,
|
||||||
|
state: {
|
||||||
|
running: {
|
||||||
|
startedAt: "before"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < opts.dead; i += 1) {
|
||||||
|
const name = `container_d_${i}`;
|
||||||
|
|
||||||
|
pod.spec.containers.push({
|
||||||
|
image: "dummy",
|
||||||
|
imagePullPolicy: "dummy",
|
||||||
|
name,
|
||||||
|
});
|
||||||
|
pod.status.containerStatuses.push({
|
||||||
|
image: "dummy",
|
||||||
|
imageID: "dummy",
|
||||||
|
name,
|
||||||
|
ready: false,
|
||||||
|
restartCount: i,
|
||||||
|
state: {
|
||||||
|
terminated: {
|
||||||
|
startedAt: "before",
|
||||||
|
exitCode: i+1,
|
||||||
|
finishedAt: "later",
|
||||||
|
reason: `reason_${i}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < opts.initRunning; i += 1) {
|
||||||
|
const name = `container_ir_${i}`;
|
||||||
|
|
||||||
|
pod.spec.initContainers.push({
|
||||||
|
image: "dummy",
|
||||||
|
imagePullPolicy: "dummy",
|
||||||
|
name,
|
||||||
|
});
|
||||||
|
pod.status.initContainerStatuses.push({
|
||||||
|
image: "dummy",
|
||||||
|
imageID: "dummy",
|
||||||
|
name,
|
||||||
|
ready: true,
|
||||||
|
restartCount: i,
|
||||||
|
state: {
|
||||||
|
running: {
|
||||||
|
startedAt: "before"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < opts.initDead; i += 1) {
|
||||||
|
const name = `container_id_${i}`;
|
||||||
|
|
||||||
|
pod.spec.initContainers.push({
|
||||||
|
image: "dummy",
|
||||||
|
imagePullPolicy: "dummy",
|
||||||
|
name,
|
||||||
|
});
|
||||||
|
pod.status.initContainerStatuses.push({
|
||||||
|
image: "dummy",
|
||||||
|
imageID: "dummy",
|
||||||
|
name,
|
||||||
|
ready: false,
|
||||||
|
restartCount: i,
|
||||||
|
state: {
|
||||||
|
terminated: {
|
||||||
|
startedAt: "before",
|
||||||
|
exitCode: i+1,
|
||||||
|
finishedAt: "later",
|
||||||
|
reason: `reason_${i}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return pod;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("Pods", () => {
|
||||||
|
const podTests = [];
|
||||||
|
|
||||||
|
for (let r = 0; r < 10; r += 1) {
|
||||||
|
for (let d = 0; d < 10; d += 1) {
|
||||||
|
for (let ir = 0; ir < 10; ir += 1) {
|
||||||
|
for (let id = 0; id < 10; id += 1) {
|
||||||
|
podTests.push([r, d, ir, id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe.each(podTests)("for [%d running, %d dead] & initial [%d running, %d dead]", (running, dead, initRunning, initDead) => {
|
||||||
|
const pod = getDummyPod({ running, dead, initRunning, initDead });
|
||||||
|
|
||||||
|
function getNamedContainer(name: string) {
|
||||||
|
return {
|
||||||
|
image: "dummy",
|
||||||
|
imagePullPolicy: "dummy",
|
||||||
|
name
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
it("getRunningContainers should return only running and init running", () => {
|
||||||
|
const res = [
|
||||||
|
...Array.from(new Array(running), (val, index) => getNamedContainer(`container_r_${index}`)),
|
||||||
|
...Array.from(new Array(initRunning), (val, index) => getNamedContainer(`container_ir_${index}`)),
|
||||||
|
];
|
||||||
|
|
||||||
|
expect(pod.getRunningContainers()).toStrictEqual(res);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("getAllContainers should return all containers", () => {
|
||||||
|
const res = [
|
||||||
|
...Array.from(new Array(running), (val, index) => getNamedContainer(`container_r_${index}`)),
|
||||||
|
...Array.from(new Array(dead), (val, index) => getNamedContainer(`container_d_${index}`)),
|
||||||
|
...Array.from(new Array(initRunning), (val, index) => getNamedContainer(`container_ir_${index}`)),
|
||||||
|
...Array.from(new Array(initDead), (val, index) => getNamedContainer(`container_id_${index}`)),
|
||||||
|
];
|
||||||
|
|
||||||
|
expect(pod.getAllContainers()).toStrictEqual(res);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("getRestartsCount should return total restart counts", () => {
|
||||||
|
function sum(len: number): number {
|
||||||
|
let res = 0;
|
||||||
|
|
||||||
|
for (let i = 0; i < len; i += 1) {
|
||||||
|
res += i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(pod.getRestartsCount()).toStrictEqual(sum(running) + sum(dead));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("hasIssues should return false", () => {
|
||||||
|
expect(pod.hasIssues()).toStrictEqual(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("getSelectedNodeOs", () => {
|
||||||
|
it("should return stable", () => {
|
||||||
|
const pod = getDummyPod();
|
||||||
|
|
||||||
|
pod.spec.nodeSelector = {
|
||||||
|
"kubernetes.io/os": "foobar"
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(pod.getSelectedNodeOs()).toStrictEqual("foobar");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return beta", () => {
|
||||||
|
const pod = getDummyPod();
|
||||||
|
|
||||||
|
pod.spec.nodeSelector = {
|
||||||
|
"beta.kubernetes.io/os": "foobar1"
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(pod.getSelectedNodeOs()).toStrictEqual("foobar1");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return stable over beta", () => {
|
||||||
|
const pod = getDummyPod();
|
||||||
|
|
||||||
|
pod.spec.nodeSelector = {
|
||||||
|
"kubernetes.io/os": "foobar2",
|
||||||
|
"beta.kubernetes.io/os": "foobar3"
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(pod.getSelectedNodeOs()).toStrictEqual("foobar2");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return undefined if none set", () => {
|
||||||
|
const pod = getDummyPod();
|
||||||
|
|
||||||
|
expect(pod.getSelectedNodeOs()).toStrictEqual(undefined);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("hasIssues", () => {
|
||||||
|
it("should return true if a condition isn't ready", () => {
|
||||||
|
const pod = getDummyPod({ running: 1 });
|
||||||
|
|
||||||
|
pod.status.conditions.push({
|
||||||
|
type: "Ready",
|
||||||
|
status: "foobar",
|
||||||
|
lastProbeTime: 1,
|
||||||
|
lastTransitionTime: "longer ago"
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(pod.hasIssues()).toStrictEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return false if a condition is non-ready", () => {
|
||||||
|
const pod = getDummyPod({ running: 1 });
|
||||||
|
|
||||||
|
pod.status.conditions.push({
|
||||||
|
type: "dummy",
|
||||||
|
status: "foobar",
|
||||||
|
lastProbeTime: 1,
|
||||||
|
lastTransitionTime: "longer ago"
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(pod.hasIssues()).toStrictEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return true if a current container is in a crash loop back off", () => {
|
||||||
|
const pod = getDummyPod({ running: 1 });
|
||||||
|
|
||||||
|
pod.status.containerStatuses[0].state = {
|
||||||
|
waiting: {
|
||||||
|
reason: "CrashLookBackOff",
|
||||||
|
message: "too much foobar"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(pod.hasIssues()).toStrictEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return true if a current phase isn't running", () => {
|
||||||
|
const pod = getDummyPod({ running: 1 });
|
||||||
|
|
||||||
|
pod.status.phase = "not running";
|
||||||
|
|
||||||
|
expect(pod.hasIssues()).toStrictEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return false if a current phase is running", () => {
|
||||||
|
const pod = getDummyPod({ running: 1 });
|
||||||
|
|
||||||
|
pod.status.phase = "Running";
|
||||||
|
|
||||||
|
expect(pod.hasIssues()).toStrictEqual(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -270,60 +270,55 @@ export class Pod extends WorkloadKubeObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getAllContainers() {
|
getAllContainers() {
|
||||||
return this.getContainers().concat(this.getInitContainers());
|
return [...this.getContainers(), ...this.getInitContainers()];
|
||||||
}
|
}
|
||||||
|
|
||||||
getRunningContainers() {
|
getRunningContainers() {
|
||||||
const statuses = this.getContainerStatuses();
|
const runningContainerNames = new Set(
|
||||||
|
this.getContainerStatuses()
|
||||||
return this.getAllContainers().filter(container => {
|
.filter(({ state }) => state.running)
|
||||||
return statuses.find(status => status.name === container.name && !!status.state["running"]);
|
.map(({ name }) => name)
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return this.getAllContainers()
|
||||||
|
.filter(({ name }) => runningContainerNames.has(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
getContainerStatuses(includeInitContainers = true) {
|
getContainerStatuses(includeInitContainers = true) {
|
||||||
const statuses: IPodContainerStatus[] = [];
|
const { containerStatuses = [], initContainerStatuses = [] } = this.status ?? {};
|
||||||
const { containerStatuses, initContainerStatuses } = this.status;
|
|
||||||
|
|
||||||
if (containerStatuses) {
|
if (includeInitContainers) {
|
||||||
statuses.push(...containerStatuses);
|
return [...containerStatuses, ...initContainerStatuses];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (includeInitContainers && initContainerStatuses) {
|
return [...containerStatuses];
|
||||||
statuses.push(...initContainerStatuses);
|
|
||||||
}
|
|
||||||
|
|
||||||
return statuses;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getRestartsCount(): number {
|
getRestartsCount(): number {
|
||||||
const { containerStatuses } = this.status;
|
const { containerStatuses = [] } = this.status ?? {};
|
||||||
|
|
||||||
if (!containerStatuses) return 0;
|
return containerStatuses.reduce((totalCount, { restartCount }) => totalCount + restartCount, 0);
|
||||||
|
|
||||||
return containerStatuses.reduce((count, item) => count + item.restartCount, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getQosClass() {
|
getQosClass() {
|
||||||
return this.status.qosClass || "";
|
return this.status?.qosClass || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
getReason() {
|
getReason() {
|
||||||
return this.status.reason || "";
|
return this.status?.reason || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
getPriorityClassName() {
|
getPriorityClassName() {
|
||||||
return this.spec.priorityClassName || "";
|
return this.spec.priorityClassName || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns one of 5 statuses: Running, Succeeded, Pending, Failed, Evicted
|
getStatus(): PodStatus {
|
||||||
getStatus() {
|
|
||||||
const phase = this.getStatusPhase();
|
const phase = this.getStatusPhase();
|
||||||
const reason = this.getReason();
|
const reason = this.getReason();
|
||||||
const goodConditions = ["Initialized", "Ready"].every(condition =>
|
const trueConditionTypes = new Set(this.getConditions()
|
||||||
!!this.getConditions().find(item => item.type === condition && item.status === "True")
|
.filter(({ status }) => status === "True")
|
||||||
);
|
.map(({ type }) => type));
|
||||||
|
const isInGoodCondition = ["Initialized", "Ready"].every(condition => trueConditionTypes.has(condition));
|
||||||
|
|
||||||
if (reason === PodStatus.EVICTED) {
|
if (reason === PodStatus.EVICTED) {
|
||||||
return PodStatus.EVICTED;
|
return PodStatus.EVICTED;
|
||||||
@ -337,7 +332,7 @@ export class Pod extends WorkloadKubeObject {
|
|||||||
return PodStatus.SUCCEEDED;
|
return PodStatus.SUCCEEDED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (phase === PodStatus.RUNNING && goodConditions) {
|
if (phase === PodStatus.RUNNING && isInGoodCondition) {
|
||||||
return PodStatus.RUNNING;
|
return PodStatus.RUNNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -349,37 +344,27 @@ export class Pod extends WorkloadKubeObject {
|
|||||||
if (this.getReason() === PodStatus.EVICTED) return "Evicted";
|
if (this.getReason() === PodStatus.EVICTED) return "Evicted";
|
||||||
if (this.getStatus() === PodStatus.RUNNING && this.metadata.deletionTimestamp) return "Terminating";
|
if (this.getStatus() === PodStatus.RUNNING && this.metadata.deletionTimestamp) return "Terminating";
|
||||||
|
|
||||||
let message = "";
|
|
||||||
const statuses = this.getContainerStatuses(false); // not including initContainers
|
const statuses = this.getContainerStatuses(false); // not including initContainers
|
||||||
|
|
||||||
if (statuses.length) {
|
for (const { state } of statuses.reverse()) {
|
||||||
statuses.forEach(status => {
|
if (state.waiting) {
|
||||||
const { state } = status;
|
return state.waiting.reason || "Waiting";
|
||||||
|
}
|
||||||
|
|
||||||
if (state.waiting) {
|
if (state.terminated) {
|
||||||
const { reason } = state.waiting;
|
return state.terminated.reason || "Terminated";
|
||||||
|
}
|
||||||
message = reason ? reason : "Waiting";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state.terminated) {
|
|
||||||
const { reason } = state.terminated;
|
|
||||||
|
|
||||||
message = reason ? reason : "Terminated";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if (message) return message;
|
|
||||||
|
|
||||||
return this.getStatusPhase();
|
return this.getStatusPhase();
|
||||||
}
|
}
|
||||||
|
|
||||||
getStatusPhase() {
|
getStatusPhase() {
|
||||||
return this.status.phase;
|
return this.status?.phase;
|
||||||
}
|
}
|
||||||
|
|
||||||
getConditions() {
|
getConditions() {
|
||||||
return this.status.conditions || [];
|
return this.status?.conditions || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
getVolumes() {
|
getVolumes() {
|
||||||
@ -393,9 +378,7 @@ export class Pod extends WorkloadKubeObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getNodeSelectors(): string[] {
|
getNodeSelectors(): string[] {
|
||||||
const { nodeSelector } = this.spec;
|
const { nodeSelector = {} } = this.spec;
|
||||||
|
|
||||||
if (!nodeSelector) return [];
|
|
||||||
|
|
||||||
return Object.entries(nodeSelector).map(values => values.join(": "));
|
return Object.entries(nodeSelector).map(values => values.join(": "));
|
||||||
}
|
}
|
||||||
@ -409,20 +392,19 @@ export class Pod extends WorkloadKubeObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hasIssues() {
|
hasIssues() {
|
||||||
const notReady = !!this.getConditions().find(condition => {
|
for (const { type, status } of this.getConditions()) {
|
||||||
return condition.type == "Ready" && condition.status !== "True";
|
if (type === "Ready" && status !== "True") {
|
||||||
});
|
return true;
|
||||||
const crashLoop = !!this.getContainerStatuses().find(condition => {
|
}
|
||||||
const waiting = condition.state.waiting;
|
}
|
||||||
|
|
||||||
return (waiting && waiting.reason == "CrashLoopBackOff");
|
for (const { state } of this.getContainerStatuses()) {
|
||||||
});
|
if (state?.waiting?.reason === "CrashLookBackOff") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return this.getStatusPhase() !== "Running";
|
||||||
notReady ||
|
|
||||||
crashLoop ||
|
|
||||||
this.getStatusPhase() !== "Running"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getLivenessProbe(container: IPodContainer) {
|
getLivenessProbe(container: IPodContainer) {
|
||||||
@ -476,14 +458,11 @@ export class Pod extends WorkloadKubeObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getNodeName() {
|
getNodeName() {
|
||||||
return this.spec?.nodeName;
|
return this.spec.nodeName;
|
||||||
}
|
}
|
||||||
|
|
||||||
getSelectedNodeOs() {
|
getSelectedNodeOs(): string | undefined {
|
||||||
if (!this.spec.nodeSelector) return;
|
return this.spec.nodeSelector?.["kubernetes.io/os"] || this.spec.nodeSelector?.["beta.kubernetes.io/os"];
|
||||||
if (!this.spec.nodeSelector["kubernetes.io/os"] && !this.spec.nodeSelector["beta.kubernetes.io/os"]) return;
|
|
||||||
|
|
||||||
return this.spec.nodeSelector["kubernetes.io/os"] || this.spec.nodeSelector["beta.kubernetes.io/os"];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -19,6 +19,7 @@ import { filesystemProvisionerStore } from "../main/extension-filesystem";
|
|||||||
import { App } from "./components/app";
|
import { App } from "./components/app";
|
||||||
import { LensApp } from "./lens-app";
|
import { LensApp } from "./lens-app";
|
||||||
import { themeStore } from "./theme.store";
|
import { themeStore } from "./theme.store";
|
||||||
|
import { NonceProvider as StyleCache } from "react-select";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If this is a development buid, wait a second to attach
|
* If this is a development buid, wait a second to attach
|
||||||
@ -78,9 +79,14 @@ export async function bootstrap(App: AppComponent) {
|
|||||||
window.location.href = "about:blank";
|
window.location.href = "about:blank";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const cacheProps = { nonce: "lens", cacheKey: "lens" };
|
||||||
|
|
||||||
render(<>
|
render(<>
|
||||||
{isMac && <div id="draggable-top" />}
|
{isMac && <div id="draggable-top" />}
|
||||||
<App />
|
<StyleCache {...cacheProps}>
|
||||||
|
<App />
|
||||||
|
</StyleCache>
|
||||||
</>, rootElem);
|
</>, rootElem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { ItemStore } from "../../item.store";
|
|||||||
import { Secret } from "../../api/endpoints";
|
import { Secret } from "../../api/endpoints";
|
||||||
import { secretsStore } from "../+config-secrets/secrets.store";
|
import { secretsStore } from "../+config-secrets/secrets.store";
|
||||||
import { namespaceStore } from "../+namespaces/namespace.store";
|
import { namespaceStore } from "../+namespaces/namespace.store";
|
||||||
|
import { Notifications } from "../notifications";
|
||||||
|
|
||||||
@autobind()
|
@autobind()
|
||||||
export class ReleaseStore extends ItemStore<HelmRelease> {
|
export class ReleaseStore extends ItemStore<HelmRelease> {
|
||||||
@ -67,7 +68,11 @@ export class ReleaseStore extends ItemStore<HelmRelease> {
|
|||||||
this.items.replace(this.sortItems(items));
|
this.items.replace(this.sortItems(items));
|
||||||
this.isLoaded = true;
|
this.isLoaded = true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Loading Helm Chart releases has failed: ${error}`);
|
console.error("Loading Helm Chart releases has failed", error);
|
||||||
|
|
||||||
|
if (error.error) {
|
||||||
|
Notifications.error(error.error);
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,41 @@
|
|||||||
|
.NamespaceSelectFilter {
|
||||||
|
.Select {
|
||||||
|
&__placeholder {
|
||||||
|
width: 100%;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: scroll!important;
|
||||||
|
text-overflow: unset!important;
|
||||||
|
margin-left: -8px;
|
||||||
|
padding-left: 8px;
|
||||||
|
margin-right: -8px;
|
||||||
|
padding-right: 8px;
|
||||||
|
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__value-container {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&::before, &::after {
|
||||||
|
content: ' ';
|
||||||
|
position: absolute;
|
||||||
|
z-index: 20;
|
||||||
|
display: block;
|
||||||
|
width: 8px;
|
||||||
|
height: var(--font-size);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
left: 0px;
|
||||||
|
background: linear-gradient(to right, var(--contentColor) 0px, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
right: 0px;
|
||||||
|
background: linear-gradient(to left, var(--contentColor) 0px, transparent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,7 +2,7 @@ import "./namespace-select.scss";
|
|||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { components, PlaceholderProps } from "react-select";
|
import { components, OptionTypeBase, PlaceholderProps } from "react-select";
|
||||||
|
|
||||||
import { Icon } from "../icon";
|
import { Icon } from "../icon";
|
||||||
import { FilterIcon } from "../item-object-list/filter-icon";
|
import { FilterIcon } from "../item-object-list/filter-icon";
|
||||||
@ -11,7 +11,7 @@ import { SelectOption } from "../select";
|
|||||||
import { NamespaceSelect } from "./namespace-select";
|
import { NamespaceSelect } from "./namespace-select";
|
||||||
import { namespaceStore } from "./namespace.store";
|
import { namespaceStore } from "./namespace.store";
|
||||||
|
|
||||||
const Placeholder = observer((props: PlaceholderProps<any>) => {
|
const Placeholder = observer((props: PlaceholderProps<OptionTypeBase, boolean>) => {
|
||||||
const getPlaceholder = (): React.ReactNode => {
|
const getPlaceholder = (): React.ReactNode => {
|
||||||
const namespaces = namespaceStore.contextNamespaces;
|
const namespaces = namespaceStore.contextNamespaces;
|
||||||
|
|
||||||
@ -71,6 +71,7 @@ export class NamespaceSelectFilter extends React.Component {
|
|||||||
placeholder={""}
|
placeholder={""}
|
||||||
onChange={this.onChange}
|
onChange={this.onChange}
|
||||||
formatOptionLabel={this.formatOptionLabel}
|
formatOptionLabel={this.formatOptionLabel}
|
||||||
|
className="NamespaceSelectFilter"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,22 +23,6 @@
|
|||||||
|
|
||||||
.NamespaceSelect {
|
.NamespaceSelect {
|
||||||
@include namespaceSelectCommon;
|
@include namespaceSelectCommon;
|
||||||
|
|
||||||
.Select {
|
|
||||||
&__placeholder {
|
|
||||||
width: 100%;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: scroll;
|
|
||||||
margin-left: -8px;
|
|
||||||
padding-left: 8px;
|
|
||||||
margin-right: -8px;
|
|
||||||
padding-right: 8px;
|
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.NamespaceSelectMenu {
|
.NamespaceSelectMenu {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import "./namespace-select.scss";
|
import "./namespace-select-filter.scss";
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { computed } from "mobx";
|
import { computed } from "mobx";
|
||||||
@ -8,7 +8,6 @@ import { cssNames } from "../../utils";
|
|||||||
import { Icon } from "../icon";
|
import { Icon } from "../icon";
|
||||||
import { namespaceStore } from "./namespace.store";
|
import { namespaceStore } from "./namespace.store";
|
||||||
import { kubeWatchApi } from "../../api/kube-watch-api";
|
import { kubeWatchApi } from "../../api/kube-watch-api";
|
||||||
import { components, ValueContainerProps } from "react-select";
|
|
||||||
|
|
||||||
interface Props extends SelectProps {
|
interface Props extends SelectProps {
|
||||||
showIcons?: boolean;
|
showIcons?: boolean;
|
||||||
@ -22,16 +21,6 @@ const defaultProps: Partial<Props> = {
|
|||||||
showClusterOption: false,
|
showClusterOption: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
function GradientValueContainer<T>({children, ...rest}: ValueContainerProps<T>) {
|
|
||||||
return (
|
|
||||||
<components.ValueContainer {...rest}>
|
|
||||||
<div className="GradientValueContainer front" />
|
|
||||||
{children}
|
|
||||||
<div className="GradientValueContainer back" />
|
|
||||||
</components.ValueContainer>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class NamespaceSelect extends React.Component<Props> {
|
export class NamespaceSelect extends React.Component<Props> {
|
||||||
static defaultProps = defaultProps as object;
|
static defaultProps = defaultProps as object;
|
||||||
@ -77,8 +66,6 @@ export class NamespaceSelect extends React.Component<Props> {
|
|||||||
render() {
|
render() {
|
||||||
const { className, showIcons, customizeOptions, components = {}, ...selectProps } = this.props;
|
const { className, showIcons, customizeOptions, components = {}, ...selectProps } = this.props;
|
||||||
|
|
||||||
components.ValueContainer ??= GradientValueContainer;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Select
|
<Select
|
||||||
className={cssNames("NamespaceSelect", className)}
|
className={cssNames("NamespaceSelect", className)}
|
||||||
|
|||||||
@ -1,7 +1,3 @@
|
|||||||
/**
|
|
||||||
* @jest-environment jsdom
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import "@testing-library/jest-dom/extend-expect";
|
import "@testing-library/jest-dom/extend-expect";
|
||||||
import { fireEvent, render } from "@testing-library/react";
|
import { fireEvent, render } from "@testing-library/react";
|
||||||
|
|||||||
@ -1,7 +1,3 @@
|
|||||||
/**
|
|
||||||
* @jest-environment jsdom
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import "@testing-library/jest-dom/extend-expect";
|
import "@testing-library/jest-dom/extend-expect";
|
||||||
import { render } from "@testing-library/react";
|
import { render } from "@testing-library/react";
|
||||||
|
|||||||
@ -1,7 +1,3 @@
|
|||||||
/**
|
|
||||||
* @jest-environment jsdom
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { podsStore } from "../../+workloads-pods/pods.store";
|
import { podsStore } from "../../+workloads-pods/pods.store";
|
||||||
import { Pod } from "../../../api/endpoints";
|
import { Pod } from "../../../api/endpoints";
|
||||||
import { dockStore } from "../dock.store";
|
import { dockStore } from "../dock.store";
|
||||||
|
|||||||
@ -6,23 +6,29 @@ import React, { ReactNode } from "react";
|
|||||||
import { computed } from "mobx";
|
import { computed } from "mobx";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { autobind, cssNames } from "../../utils";
|
import { autobind, cssNames } from "../../utils";
|
||||||
import ReactSelect, { ActionMeta, components, Props as ReactSelectProps, Styles } from "react-select";
|
import ReactSelect, { components } from "react-select";
|
||||||
import Creatable, { CreatableProps } from "react-select/creatable";
|
import Creatable from "react-select/creatable";
|
||||||
import { themeStore } from "../../theme.store";
|
import { themeStore } from "../../theme.store";
|
||||||
|
|
||||||
|
import type { ActionMeta, GroupTypeBase, OptionTypeBase, Props as ReactSelectProps, Styles as ReactSelectStyles } from "react-select";
|
||||||
|
|
||||||
const { Menu } = components;
|
const { Menu } = components;
|
||||||
|
|
||||||
|
type OptionType = { label: string; value: string };
|
||||||
|
type GroupType = GroupTypeBase<OptionType>;
|
||||||
|
|
||||||
export interface GroupSelectOption<T extends SelectOption = SelectOption> {
|
export interface GroupSelectOption<T extends SelectOption = SelectOption> {
|
||||||
label: ReactNode;
|
label: ReactNode;
|
||||||
options: T[];
|
options: T[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SelectOption<T = any> {
|
export interface SelectOption<T = any> {
|
||||||
value: T;
|
value?: T;
|
||||||
label?: React.ReactNode;
|
label?: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SelectProps<T = any> extends ReactSelectProps<T>, CreatableProps<T> {
|
export interface SelectProps<T = any> extends ReactSelectProps<OptionTypeBase, boolean> {
|
||||||
|
options?: ReadonlyArray<OptionType | GroupType | unknown>;
|
||||||
value?: T;
|
value?: T;
|
||||||
themeName?: "dark" | "light" | "outlined";
|
themeName?: "dark" | "light" | "outlined";
|
||||||
menuClass?: string;
|
menuClass?: string;
|
||||||
@ -43,7 +49,7 @@ export class Select extends React.Component<SelectProps> {
|
|||||||
return this.props.themeName || themeStore.activeTheme.type;
|
return this.props.themeName || themeStore.activeTheme.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
private styles: Styles = {
|
private styles: ReactSelectStyles<OptionTypeBase, boolean> = {
|
||||||
menuPortal: styles => ({
|
menuPortal: styles => ({
|
||||||
...styles,
|
...styles,
|
||||||
zIndex: "auto"
|
zIndex: "auto"
|
||||||
@ -68,16 +74,10 @@ export class Select extends React.Component<SelectProps> {
|
|||||||
return this.options.find(opt => opt === value || opt.value === value);
|
return this.options.find(opt => opt === value || opt.value === value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed get options(): SelectOption[] {
|
@computed get options(): readonly SelectOption[] {
|
||||||
const { autoConvertOptions, options } = this.props;
|
return this.props.options.map(opt => {
|
||||||
|
return this.isValidOption(opt) ? opt : { value: opt, label: String(opt) };
|
||||||
if (autoConvertOptions && Array.isArray(options)) {
|
});
|
||||||
return options.map(opt => {
|
|
||||||
return this.isValidOption(opt) ? opt : { value: opt, label: String(opt) };
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return options as SelectOption[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
@autobind()
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Here you can find description of changes we've built into each release. While we try our best to make each upgrade automatic and as smooth as possible, there may be some cases where you might need to do something to ensure the application works smoothly. So please read through the release highlights!
|
Here you can find description of changes we've built into each release. While we try our best to make each upgrade automatic and as smooth as possible, there may be some cases where you might need to do something to ensure the application works smoothly. So please read through the release highlights!
|
||||||
|
|
||||||
## 4.2.0-rc.2 (current version)
|
## 4.2.0-rc.3 (current version)
|
||||||
|
|
||||||
- Add lens:// protocol handling with a routing mechanism
|
- Add lens:// protocol handling with a routing mechanism
|
||||||
- Add common app routes to the protocol renderer router from the documentation
|
- Add common app routes to the protocol renderer router from the documentation
|
||||||
@ -33,6 +33,10 @@ Here you can find description of changes we've built into each release. While we
|
|||||||
- Fix: Closing workspace menu after clicking on iframe
|
- Fix: Closing workspace menu after clicking on iframe
|
||||||
- Fix: extension global pages are never able to be visible
|
- Fix: extension global pages are never able to be visible
|
||||||
- Fix: recreate proxy kubeconfig if it is deleted
|
- Fix: recreate proxy kubeconfig if it is deleted
|
||||||
|
- Fix: Proxy should listen only on loopback device
|
||||||
|
- Fix: Block global path traversal in router
|
||||||
|
- Fix: Set initial cursor position for the editor to beginning
|
||||||
|
- Fix: Highlight sidebar's active section
|
||||||
|
|
||||||
## 4.1.4
|
## 4.1.4
|
||||||
|
|
||||||
|
|||||||
195
yarn.lock
195
yarn.lock
@ -76,7 +76,7 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.10.1"
|
"@babel/types" "^7.10.1"
|
||||||
|
|
||||||
"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.10.1":
|
"@babel/helper-module-imports@^7.10.1":
|
||||||
version "7.10.1"
|
version "7.10.1"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.1.tgz#dd331bd45bccc566ce77004e9d05fe17add13876"
|
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.1.tgz#dd331bd45bccc566ce77004e9d05fe17add13876"
|
||||||
integrity sha512-SFxgwYmZ3HZPyZwJRiVNLRHWuW2OgE5k2nrVs6D9Iv4PPnXVffuEHy83Sfx/l4SqF+5kyJXjAyUmrG7tNm+qVg==
|
integrity sha512-SFxgwYmZ3HZPyZwJRiVNLRHWuW2OgE5k2nrVs6D9Iv4PPnXVffuEHy83Sfx/l4SqF+5kyJXjAyUmrG7tNm+qVg==
|
||||||
@ -267,6 +267,13 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
regenerator-runtime "^0.13.4"
|
regenerator-runtime "^0.13.4"
|
||||||
|
|
||||||
|
"@babel/runtime@^7.12.0":
|
||||||
|
version "7.13.10"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.13.10.tgz#47d42a57b6095f4468da440388fdbad8bebf0d7d"
|
||||||
|
integrity sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw==
|
||||||
|
dependencies:
|
||||||
|
regenerator-runtime "^0.13.4"
|
||||||
|
|
||||||
"@babel/runtime@^7.12.5":
|
"@babel/runtime@^7.12.5":
|
||||||
version "7.12.5"
|
version "7.12.5"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e"
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e"
|
||||||
@ -359,79 +366,67 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
js-sha3 "^0.8.0"
|
js-sha3 "^0.8.0"
|
||||||
|
|
||||||
"@emotion/cache@^10.0.27", "@emotion/cache@^10.0.9":
|
"@emotion/cache@^11.0.0", "@emotion/cache@^11.1.3":
|
||||||
version "10.0.29"
|
version "11.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.29.tgz#87e7e64f412c060102d589fe7c6dc042e6f9d1e0"
|
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.1.3.tgz#c7683a9484bcd38d5562f2b9947873cf66829afd"
|
||||||
integrity sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==
|
integrity sha512-n4OWinUPJVaP6fXxWZD9OUeQ0lY7DvtmtSuqtRWT0Ofo/sBLCVSgb4/Oa0Q5eFxcwablRKjUXqXtNZVyEwCAuA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@emotion/sheet" "0.9.4"
|
"@emotion/memoize" "^0.7.4"
|
||||||
"@emotion/stylis" "0.8.5"
|
"@emotion/sheet" "^1.0.0"
|
||||||
"@emotion/utils" "0.11.3"
|
"@emotion/utils" "^1.0.0"
|
||||||
"@emotion/weak-memoize" "0.2.5"
|
"@emotion/weak-memoize" "^0.2.5"
|
||||||
|
stylis "^4.0.3"
|
||||||
|
|
||||||
"@emotion/core@^10.0.9":
|
"@emotion/hash@^0.8.0":
|
||||||
version "10.0.28"
|
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/core/-/core-10.0.28.tgz#bb65af7262a234593a9e952c041d0f1c9b9bef3d"
|
|
||||||
integrity sha512-pH8UueKYO5jgg0Iq+AmCLxBsvuGtvlmiDCOuv8fGNYn3cowFpLN98L8zO56U0H1PjDIyAlXymgL3Wu7u7v6hbA==
|
|
||||||
dependencies:
|
|
||||||
"@babel/runtime" "^7.5.5"
|
|
||||||
"@emotion/cache" "^10.0.27"
|
|
||||||
"@emotion/css" "^10.0.27"
|
|
||||||
"@emotion/serialize" "^0.11.15"
|
|
||||||
"@emotion/sheet" "0.9.4"
|
|
||||||
"@emotion/utils" "0.11.3"
|
|
||||||
|
|
||||||
"@emotion/css@^10.0.27", "@emotion/css@^10.0.9":
|
|
||||||
version "10.0.27"
|
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/css/-/css-10.0.27.tgz#3a7458198fbbebb53b01b2b87f64e5e21241e14c"
|
|
||||||
integrity sha512-6wZjsvYeBhyZQYNrGoR5yPMYbMBNEnanDrqmsqS1mzDm1cOTu12shvl2j4QHNS36UaTE0USIJawCH9C8oW34Zw==
|
|
||||||
dependencies:
|
|
||||||
"@emotion/serialize" "^0.11.15"
|
|
||||||
"@emotion/utils" "0.11.3"
|
|
||||||
babel-plugin-emotion "^10.0.27"
|
|
||||||
|
|
||||||
"@emotion/hash@0.8.0", "@emotion/hash@^0.8.0":
|
|
||||||
version "0.8.0"
|
version "0.8.0"
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413"
|
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413"
|
||||||
integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==
|
integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==
|
||||||
|
|
||||||
"@emotion/memoize@0.7.4":
|
"@emotion/memoize@^0.7.4":
|
||||||
version "0.7.4"
|
version "0.7.5"
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb"
|
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.5.tgz#2c40f81449a4e554e9fc6396910ed4843ec2be50"
|
||||||
integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==
|
integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==
|
||||||
|
|
||||||
"@emotion/serialize@^0.11.15", "@emotion/serialize@^0.11.16":
|
"@emotion/react@^11.1.1":
|
||||||
version "0.11.16"
|
version "11.1.5"
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.16.tgz#dee05f9e96ad2fb25a5206b6d759b2d1ed3379ad"
|
resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.1.5.tgz#15e78f9822894cdc296e6f4e0688bac8120dfe66"
|
||||||
integrity sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==
|
integrity sha512-xfnZ9NJEv9SU9K2sxXM06lzjK245xSeHRpUh67eARBm3PBHjjKIZlfWZ7UQvD0Obvw6ZKjlC79uHrlzFYpOB/Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@emotion/hash" "0.8.0"
|
"@babel/runtime" "^7.7.2"
|
||||||
"@emotion/memoize" "0.7.4"
|
"@emotion/cache" "^11.1.3"
|
||||||
"@emotion/unitless" "0.7.5"
|
"@emotion/serialize" "^1.0.0"
|
||||||
"@emotion/utils" "0.11.3"
|
"@emotion/sheet" "^1.0.1"
|
||||||
csstype "^2.5.7"
|
"@emotion/utils" "^1.0.0"
|
||||||
|
"@emotion/weak-memoize" "^0.2.5"
|
||||||
|
hoist-non-react-statics "^3.3.1"
|
||||||
|
|
||||||
"@emotion/sheet@0.9.4":
|
"@emotion/serialize@^1.0.0":
|
||||||
version "0.9.4"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-0.9.4.tgz#894374bea39ec30f489bbfc3438192b9774d32e5"
|
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.0.1.tgz#322cdebfdbb5a88946f17006548191859b9b0855"
|
||||||
integrity sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA==
|
integrity sha512-TXlKs5sgUKhFlszp/rg4lIAZd7UUSmJpwaf9/lAEFcUh2vPi32i7x4wk7O8TN8L8v2Ol8k0CxnhRBY0zQalTxA==
|
||||||
|
dependencies:
|
||||||
|
"@emotion/hash" "^0.8.0"
|
||||||
|
"@emotion/memoize" "^0.7.4"
|
||||||
|
"@emotion/unitless" "^0.7.5"
|
||||||
|
"@emotion/utils" "^1.0.0"
|
||||||
|
csstype "^3.0.2"
|
||||||
|
|
||||||
"@emotion/stylis@0.8.5":
|
"@emotion/sheet@^1.0.0", "@emotion/sheet@^1.0.1":
|
||||||
version "0.8.5"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04"
|
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.0.1.tgz#245f54abb02dfd82326e28689f34c27aa9b2a698"
|
||||||
integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==
|
integrity sha512-GbIvVMe4U+Zc+929N1V7nW6YYJtidj31lidSmdYcWozwoBIObXBnaJkKNDjZrLm9Nc0BR+ZyHNaRZxqNZbof5g==
|
||||||
|
|
||||||
"@emotion/unitless@0.7.5":
|
"@emotion/unitless@^0.7.5":
|
||||||
version "0.7.5"
|
version "0.7.5"
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
|
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
|
||||||
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
|
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
|
||||||
|
|
||||||
"@emotion/utils@0.11.3":
|
"@emotion/utils@^1.0.0":
|
||||||
version "0.11.3"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-0.11.3.tgz#a759863867befa7e583400d322652a3f44820924"
|
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.0.0.tgz#abe06a83160b10570816c913990245813a2fd6af"
|
||||||
integrity sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==
|
integrity sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA==
|
||||||
|
|
||||||
"@emotion/weak-memoize@0.2.5":
|
"@emotion/weak-memoize@^0.2.5":
|
||||||
version "0.2.5"
|
version "0.2.5"
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46"
|
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46"
|
||||||
integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==
|
integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==
|
||||||
@ -1596,11 +1591,12 @@
|
|||||||
"@types/history" "*"
|
"@types/history" "*"
|
||||||
"@types/react" "*"
|
"@types/react" "*"
|
||||||
|
|
||||||
"@types/react-select@^3.0.13":
|
"@types/react-select@^4.0.13":
|
||||||
version "3.0.13"
|
version "4.0.13"
|
||||||
resolved "https://registry.yarnpkg.com/@types/react-select/-/react-select-3.0.13.tgz#b1a05eae0f65fb4f899b4db1f89b8420cb9f3656"
|
resolved "https://registry.yarnpkg.com/@types/react-select/-/react-select-4.0.13.tgz#8d2c41a0df7fbf67ab0b995797b0e9b4e6b38cde"
|
||||||
integrity sha512-JxmSArGgzAOtb37+Jz2+3av8rVmp/3s3DGwlcP+g59/a3owkiuuU4/Jajd+qA32beDPHy4gJR2kkxagPY3j9kg==
|
integrity sha512-rXYEc565IzzjgQzs9C0YCFxV/QajMZnCHG5QwRQ5BZMfH0Lj90VI/xohawemRkD46IvpaLRbO6xzSquJlgBGUA==
|
||||||
dependencies:
|
dependencies:
|
||||||
|
"@emotion/serialize" "^1.0.0"
|
||||||
"@types/react" "*"
|
"@types/react" "*"
|
||||||
"@types/react-dom" "*"
|
"@types/react-dom" "*"
|
||||||
"@types/react-transition-group" "*"
|
"@types/react-transition-group" "*"
|
||||||
@ -2692,22 +2688,6 @@ babel-jest@^26.0.1:
|
|||||||
graceful-fs "^4.2.4"
|
graceful-fs "^4.2.4"
|
||||||
slash "^3.0.0"
|
slash "^3.0.0"
|
||||||
|
|
||||||
babel-plugin-emotion@^10.0.27:
|
|
||||||
version "10.0.33"
|
|
||||||
resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-10.0.33.tgz#ce1155dcd1783bbb9286051efee53f4e2be63e03"
|
|
||||||
integrity sha512-bxZbTTGz0AJQDHm8k6Rf3RQJ8tX2scsfsRyKVgAbiUPUNIRtlK+7JxP+TAd1kRLABFxe0CFm2VdK4ePkoA9FxQ==
|
|
||||||
dependencies:
|
|
||||||
"@babel/helper-module-imports" "^7.0.0"
|
|
||||||
"@emotion/hash" "0.8.0"
|
|
||||||
"@emotion/memoize" "0.7.4"
|
|
||||||
"@emotion/serialize" "^0.11.16"
|
|
||||||
babel-plugin-macros "^2.0.0"
|
|
||||||
babel-plugin-syntax-jsx "^6.18.0"
|
|
||||||
convert-source-map "^1.5.0"
|
|
||||||
escape-string-regexp "^1.0.5"
|
|
||||||
find-root "^1.1.0"
|
|
||||||
source-map "^0.5.7"
|
|
||||||
|
|
||||||
babel-plugin-istanbul@^6.0.0:
|
babel-plugin-istanbul@^6.0.0:
|
||||||
version "6.0.0"
|
version "6.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765"
|
resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765"
|
||||||
@ -2728,20 +2708,6 @@ babel-plugin-jest-hoist@^26.0.0:
|
|||||||
"@babel/types" "^7.3.3"
|
"@babel/types" "^7.3.3"
|
||||||
"@types/babel__traverse" "^7.0.6"
|
"@types/babel__traverse" "^7.0.6"
|
||||||
|
|
||||||
babel-plugin-macros@^2.0.0:
|
|
||||||
version "2.8.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138"
|
|
||||||
integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==
|
|
||||||
dependencies:
|
|
||||||
"@babel/runtime" "^7.7.2"
|
|
||||||
cosmiconfig "^6.0.0"
|
|
||||||
resolve "^1.12.0"
|
|
||||||
|
|
||||||
babel-plugin-syntax-jsx@^6.18.0:
|
|
||||||
version "6.18.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946"
|
|
||||||
integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=
|
|
||||||
|
|
||||||
babel-preset-current-node-syntax@^0.1.2:
|
babel-preset-current-node-syntax@^0.1.2:
|
||||||
version "0.1.2"
|
version "0.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-0.1.2.tgz#fb4a4c51fe38ca60fede1dc74ab35eb843cb41d6"
|
resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-0.1.2.tgz#fb4a4c51fe38ca60fede1dc74ab35eb843cb41d6"
|
||||||
@ -3934,7 +3900,7 @@ content-type@~1.0.4:
|
|||||||
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
|
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
|
||||||
integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
|
integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
|
||||||
|
|
||||||
convert-source-map@^1.4.0, convert-source-map@^1.5.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0:
|
convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0:
|
||||||
version "1.7.0"
|
version "1.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442"
|
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442"
|
||||||
integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==
|
integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==
|
||||||
@ -4245,7 +4211,7 @@ cssstyle@^2.2.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
cssom "~0.3.6"
|
cssom "~0.3.6"
|
||||||
|
|
||||||
csstype@^2.2.0, csstype@^2.5.2, csstype@^2.5.7, csstype@^2.6.5, csstype@^2.6.7:
|
csstype@^2.2.0, csstype@^2.5.2, csstype@^2.6.5, csstype@^2.6.7:
|
||||||
version "2.6.10"
|
version "2.6.10"
|
||||||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.10.tgz#e63af50e66d7c266edb6b32909cfd0aabe03928b"
|
resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.10.tgz#e63af50e66d7c266edb6b32909cfd0aabe03928b"
|
||||||
integrity sha512-D34BqZU4cIlMCY93rZHbrq9pjTAQJ3U8S8rfBqjwHxkGPThWFjzZDQpgMJY0QViLxth6ZKYiwFBo14RdN44U/w==
|
integrity sha512-D34BqZU4cIlMCY93rZHbrq9pjTAQJ3U8S8rfBqjwHxkGPThWFjzZDQpgMJY0QViLxth6ZKYiwFBo14RdN44U/w==
|
||||||
@ -5782,11 +5748,6 @@ find-npm-prefix@^1.0.2:
|
|||||||
resolved "https://registry.yarnpkg.com/find-npm-prefix/-/find-npm-prefix-1.0.2.tgz#8d8ce2c78b3b4b9e66c8acc6a37c231eb841cfdf"
|
resolved "https://registry.yarnpkg.com/find-npm-prefix/-/find-npm-prefix-1.0.2.tgz#8d8ce2c78b3b4b9e66c8acc6a37c231eb841cfdf"
|
||||||
integrity sha512-KEftzJ+H90x6pcKtdXZEPsQse8/y/UnvzRKrOSQFprnrGaFuJ62fVkP34Iu2IYuMvyauCyoLTNkJZgrrGA2wkA==
|
integrity sha512-KEftzJ+H90x6pcKtdXZEPsQse8/y/UnvzRKrOSQFprnrGaFuJ62fVkP34Iu2IYuMvyauCyoLTNkJZgrrGA2wkA==
|
||||||
|
|
||||||
find-root@^1.1.0:
|
|
||||||
version "1.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
|
|
||||||
integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==
|
|
||||||
|
|
||||||
find-up@^1.0.0:
|
find-up@^1.0.0:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
|
resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
|
||||||
@ -6570,7 +6531,7 @@ hmac-drbg@^1.0.0:
|
|||||||
minimalistic-assert "^1.0.0"
|
minimalistic-assert "^1.0.0"
|
||||||
minimalistic-crypto-utils "^1.0.1"
|
minimalistic-crypto-utils "^1.0.1"
|
||||||
|
|
||||||
hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2:
|
hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2:
|
||||||
version "3.3.2"
|
version "3.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
|
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
|
||||||
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
|
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
|
||||||
@ -11257,10 +11218,10 @@ react-dom@^17.0.1:
|
|||||||
object-assign "^4.1.1"
|
object-assign "^4.1.1"
|
||||||
scheduler "^0.20.1"
|
scheduler "^0.20.1"
|
||||||
|
|
||||||
react-input-autosize@^2.2.2:
|
react-input-autosize@^3.0.0:
|
||||||
version "2.2.2"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-input-autosize/-/react-input-autosize-2.2.2.tgz#fcaa7020568ec206bc04be36f4eb68e647c4d8c2"
|
resolved "https://registry.yarnpkg.com/react-input-autosize/-/react-input-autosize-3.0.0.tgz#6b5898c790d4478d69420b55441fcc31d5c50a85"
|
||||||
integrity sha512-jQJgYCA3S0j+cuOwzuCd1OjmBmnZLdqQdiLKRYrsMMzbjUrVDS5RvJUDwJqA7sKuksDuzFtm6hZGKFu7Mjk5aw==
|
integrity sha512-nL9uS7jEs/zu8sqwFE5MAPx6pPkNAriACQ2rGLlqmKr2sPGtN7TXTyDdQt4lbNXVx7Uzadb40x8qotIuru6Rhg==
|
||||||
dependencies:
|
dependencies:
|
||||||
prop-types "^15.5.8"
|
prop-types "^15.5.8"
|
||||||
|
|
||||||
@ -11326,18 +11287,17 @@ react-select-event@^5.1.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@testing-library/dom" ">=7"
|
"@testing-library/dom" ">=7"
|
||||||
|
|
||||||
react-select@^3.1.0:
|
react-select@^4.3.0:
|
||||||
version "3.1.0"
|
version "4.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-select/-/react-select-3.1.0.tgz#ab098720b2e9fe275047c993f0d0caf5ded17c27"
|
resolved "https://registry.yarnpkg.com/react-select/-/react-select-4.3.0.tgz#6bde634ae7a378b49f3833c85c126f533483fa2e"
|
||||||
integrity sha512-wBFVblBH1iuCBprtpyGtd1dGMadsG36W5/t2Aj8OE6WbByDg5jIFyT7X5gT+l0qmT5TqWhxX+VsKJvCEl2uL9g==
|
integrity sha512-SBPD1a3TJqE9zoI/jfOLCAoLr/neluaeokjOixr3zZ1vHezkom8K0A9J4QG9IWDqIDE9K/Mv+0y1GjidC2PDtQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.4.4"
|
"@babel/runtime" "^7.12.0"
|
||||||
"@emotion/cache" "^10.0.9"
|
"@emotion/cache" "^11.0.0"
|
||||||
"@emotion/core" "^10.0.9"
|
"@emotion/react" "^11.1.1"
|
||||||
"@emotion/css" "^10.0.9"
|
|
||||||
memoize-one "^5.0.0"
|
memoize-one "^5.0.0"
|
||||||
prop-types "^15.6.0"
|
prop-types "^15.6.0"
|
||||||
react-input-autosize "^2.2.2"
|
react-input-autosize "^3.0.0"
|
||||||
react-transition-group "^4.3.0"
|
react-transition-group "^4.3.0"
|
||||||
|
|
||||||
react-transition-group@^4.3.0, react-transition-group@^4.4.0:
|
react-transition-group@^4.3.0, react-transition-group@^4.4.0:
|
||||||
@ -11808,7 +11768,7 @@ resolve-url@^0.2.1:
|
|||||||
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
|
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
|
||||||
integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
|
integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
|
||||||
|
|
||||||
resolve@^1.1.6, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.17.0, resolve@^1.3.2:
|
resolve@^1.1.6, resolve@^1.10.0, resolve@^1.17.0, resolve@^1.3.2:
|
||||||
version "1.17.0"
|
version "1.17.0"
|
||||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444"
|
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444"
|
||||||
integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==
|
integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==
|
||||||
@ -12507,7 +12467,7 @@ source-map@^0.4.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
amdefine ">=0.0.4"
|
amdefine ">=0.0.4"
|
||||||
|
|
||||||
source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7:
|
source-map@^0.5.0, source-map@^0.5.6:
|
||||||
version "0.5.7"
|
version "0.5.7"
|
||||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
|
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
|
||||||
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
|
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
|
||||||
@ -12979,6 +12939,11 @@ style-loader@^1.2.1:
|
|||||||
loader-utils "^2.0.0"
|
loader-utils "^2.0.0"
|
||||||
schema-utils "^2.6.6"
|
schema-utils "^2.6.6"
|
||||||
|
|
||||||
|
stylis@^4.0.3:
|
||||||
|
version "4.0.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.7.tgz#412a90c28079417f3d27c028035095e4232d2904"
|
||||||
|
integrity sha512-OFFeUXFgwnGOKvEXaSv0D0KQ5ADP0n6g3SVONx6I/85JzNZ3u50FRwB3lVIk1QO2HNdI75tbVzc4Z66Gdp9voA==
|
||||||
|
|
||||||
sumchecker@^3.0.1:
|
sumchecker@^3.0.1:
|
||||||
version "3.0.1"
|
version "3.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-3.0.1.tgz#6377e996795abb0b6d348e9b3e1dfb24345a8e42"
|
resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-3.0.1.tgz#6377e996795abb0b6d348e9b3e1dfb24345a8e42"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user