diff --git a/.eslintrc.js b/.eslintrc.js index 913d959a97..a9b4fa21f9 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,62 +1,92 @@ +const packageJson = require("./package.json"); + module.exports = { ignorePatterns: [ "**/node_modules/**/*", "**/dist/**/*", ], + settings: { + react: { + version: packageJson.devDependencies.react || "detect", + } + }, overrides: [ { files: [ - "src/renderer/**/*.js", - "build/**/*.js", - "extensions/**/*.js" + "**/*.js" ], extends: [ - 'eslint:recommended', + "eslint:recommended", ], env: { node: true }, parserOptions: { ecmaVersion: 2018, - sourceType: 'module', + sourceType: "module", }, + plugins: [ + "unused-imports" + ], rules: { "indent": ["error", 2, { "SwitchCase": 1, }], "no-unused-vars": "off", + "unused-imports/no-unused-imports": "error", + "unused-imports/no-unused-vars": [ + "warn", { + "vars": "all", + "args": "after-used", + "ignoreRestSiblings": true, + } + ], + "quotes": ["error", "double", { + "avoidEscape": true, + "allowTemplateLiterals": true, + }], "semi": ["error", "always"], "object-shorthand": "error", } }, { files: [ - "build/*.ts", - "src/**/*.ts", - "integration/**/*.ts", - "src/extensions/**/*.ts*", - "extensions/**/*.ts*", - "__mocks__/*.ts", + "**/*.ts", ], parser: "@typescript-eslint/parser", extends: [ - 'plugin:@typescript-eslint/recommended', + "plugin:@typescript-eslint/recommended", + ], + plugins: [ + "unused-imports" ], parserOptions: { ecmaVersion: 2018, - sourceType: 'module', + sourceType: "module", }, rules: { "@typescript-eslint/explicit-function-return-type": "off", "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/no-unused-vars": "off", "@typescript-eslint/explicit-module-boundary-types": "off", "@typescript-eslint/ban-types": "off", "@typescript-eslint/ban-ts-comment": "off", "@typescript-eslint/no-empty-interface": "off", + "@typescript-eslint/no-unused-vars": "off", + "unused-imports/no-unused-imports-ts": "error", + "unused-imports/no-unused-vars-ts": [ + "warn", { + "vars": "all", + "args": "after-used", + "ignoreRestSiblings": true, + } + ], "indent": ["error", 2, { "SwitchCase": 1, }], + "quotes": ["error", "double", { + "avoidEscape": true, + "allowTemplateLiterals": true, + }], "semi": "off", "@typescript-eslint/semi": ["error"], "object-shorthand": "error", @@ -64,21 +94,24 @@ module.exports = { }, { files: [ - "src/renderer/**/*.tsx", + "**/*.tsx", ], parser: "@typescript-eslint/parser", + plugins: [ + "unused-imports" + ], extends: [ - 'plugin:@typescript-eslint/recommended', + "plugin:@typescript-eslint/recommended", + "plugin:react/recommended", ], parserOptions: { ecmaVersion: 2018, - sourceType: 'module', + sourceType: "module", jsx: true, }, rules: { "@typescript-eslint/explicit-function-return-type": "off", "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/no-unused-vars": "off", "@typescript-eslint/interface-name-prefix": "off", "@typescript-eslint/no-use-before-define": "off", "@typescript-eslint/no-empty-interface": "off", @@ -87,9 +120,23 @@ module.exports = { "@typescript-eslint/explicit-module-boundary-types": "off", "@typescript-eslint/ban-types": "off", "@typescript-eslint/no-empty-function": "off", + "react/display-name": "off", + "@typescript-eslint/no-unused-vars": "off", + "unused-imports/no-unused-imports-ts": "error", + "unused-imports/no-unused-vars-ts": [ + "warn", { + "vars": "all", + "args": "after-used", + "ignoreRestSiblings": true, + } + ], "indent": ["error", 2, { "SwitchCase": 1, }], + "quotes": ["error", "double", { + "avoidEscape": true, + "allowTemplateLiterals": true, + }], "semi": "off", "@typescript-eslint/semi": ["error"], "object-shorthand": "error", diff --git a/__mocks__/electron.ts b/__mocks__/electron.ts index 86f35c956d..1b531fb8d7 100644 --- a/__mocks__/electron.ts +++ b/__mocks__/electron.ts @@ -4,9 +4,7 @@ module.exports = { app: { getVersion: jest.fn().mockReturnValue("3.0.0"), getLocale: jest.fn().mockRejectedValue("en"), - getPath: jest.fn((name: string) => { - return "tmp"; - }), + getPath: jest.fn(() => "tmp"), }, remote: { app: { diff --git a/build/download_kubectl.ts b/build/download_kubectl.ts index 137588ff58..bab01d7f02 100644 --- a/build/download_kubectl.ts +++ b/build/download_kubectl.ts @@ -92,12 +92,12 @@ class KubectlDownloader { } const downloadVersion = packageInfo.config.bundledKubectlVersion; -const baseDir = path.join(process.env.INIT_CWD, 'binaries', 'client'); +const baseDir = path.join(process.env.INIT_CWD, "binaries", "client"); const downloads = [ - { platform: 'linux', arch: 'amd64', target: path.join(baseDir, 'linux', 'x64', 'kubectl') }, - { platform: 'darwin', arch: 'amd64', target: path.join(baseDir, 'darwin', 'x64', 'kubectl') }, - { platform: 'windows', arch: 'amd64', target: path.join(baseDir, 'windows', 'x64', 'kubectl.exe') }, - { platform: 'windows', arch: '386', target: path.join(baseDir, 'windows', 'ia32', 'kubectl.exe') } + { platform: "linux", arch: "amd64", target: path.join(baseDir, "linux", "x64", "kubectl") }, + { platform: "darwin", arch: "amd64", target: path.join(baseDir, "darwin", "x64", "kubectl") }, + { platform: "windows", arch: "amd64", target: path.join(baseDir, "windows", "x64", "kubectl.exe") }, + { platform: "windows", arch: "386", target: path.join(baseDir, "windows", "ia32", "kubectl.exe") } ]; downloads.forEach((dlOpts) => { diff --git a/build/notarize.js b/build/notarize.js index 9904dccc3b..5b3bcba4b7 100644 --- a/build/notarize.js +++ b/build/notarize.js @@ -1,8 +1,8 @@ -const { notarize } = require('electron-notarize'); +const { notarize } = require("electron-notarize"); exports.default = async function notarizing(context) { const { electronPlatformName, appOutDir } = context; - if (electronPlatformName !== 'darwin') { + if (electronPlatformName !== "darwin") { return; } if (!process.env.APPLEID || !process.env.APPLEIDPASS) { @@ -12,7 +12,7 @@ exports.default = async function notarizing(context) { const appName = context.packager.appInfo.productFilename; return await notarize({ - appBundleId: 'io.kontena.lens-app', + appBundleId: "io.kontena.lens-app", appPath: `${appOutDir}/${appName}.app`, appleId: process.env.APPLEID, appleIdPassword: process.env.APPLEIDPASS, diff --git a/extensions/example-extension/main.ts b/extensions/example-extension/main.ts index 3648b563a6..494c3e0d29 100644 --- a/extensions/example-extension/main.ts +++ b/extensions/example-extension/main.ts @@ -2,10 +2,10 @@ import { LensMainExtension } from "@k8slens/extensions"; export default class ExampleExtensionMain extends LensMainExtension { onActivate() { - console.log('EXAMPLE EXTENSION MAIN: ACTIVATED', this.name, this.id); + console.log("EXAMPLE EXTENSION MAIN: ACTIVATED", this.name, this.id); } onDeactivate() { - console.log('EXAMPLE EXTENSION MAIN: DEACTIVATED', this.name, this.id); + console.log("EXAMPLE EXTENSION MAIN: DEACTIVATED", this.name, this.id); } } diff --git a/extensions/example-extension/webpack.config.js b/extensions/example-extension/webpack.config.js index 89e84e3125..94a27a8e08 100644 --- a/extensions/example-extension/webpack.config.js +++ b/extensions/example-extension/webpack.config.js @@ -1,8 +1,8 @@ -const path = require('path'); +const path = require("path"); module.exports = [ { - entry: './main.ts', + entry: "./main.ts", context: __dirname, target: "electron-main", mode: "production", @@ -10,7 +10,7 @@ module.exports = [ rules: [ { test: /\.tsx?$/, - use: 'ts-loader', + use: "ts-loader", exclude: /node_modules/, }, ], @@ -23,16 +23,16 @@ module.exports = [ } ], resolve: { - extensions: [ '.tsx', '.ts', '.js' ], + extensions: [ ".tsx", ".ts", ".js" ], }, output: { libraryTarget: "commonjs2", - filename: 'main.js', - path: path.resolve(__dirname, 'dist'), + filename: "main.js", + path: path.resolve(__dirname, "dist"), }, }, { - entry: './renderer.tsx', + entry: "./renderer.tsx", context: __dirname, target: "electron-renderer", mode: "production", @@ -40,7 +40,7 @@ module.exports = [ rules: [ { test: /\.tsx?$/, - use: 'ts-loader', + use: "ts-loader", exclude: /node_modules/, }, ], @@ -53,13 +53,13 @@ module.exports = [ } ], resolve: { - extensions: [ '.tsx', '.ts', '.js' ], + extensions: [ ".tsx", ".ts", ".js" ], }, output: { libraryTarget: "commonjs2", globalObject: "this", - filename: 'renderer.js', - path: path.resolve(__dirname, 'dist'), + filename: "renderer.js", + path: path.resolve(__dirname, "dist"), }, }, ]; diff --git a/extensions/kube-object-event-status/webpack.config.js b/extensions/kube-object-event-status/webpack.config.js index bc68a5c9f8..a35cf40850 100644 --- a/extensions/kube-object-event-status/webpack.config.js +++ b/extensions/kube-object-event-status/webpack.config.js @@ -1,8 +1,8 @@ -const path = require('path'); +const path = require("path"); module.exports = [ { - entry: './renderer.tsx', + entry: "./renderer.tsx", context: __dirname, target: "electron-renderer", mode: "production", @@ -10,7 +10,7 @@ module.exports = [ rules: [ { test: /\.tsx?$/, - use: 'ts-loader', + use: "ts-loader", exclude: /node_modules/, }, ], @@ -23,13 +23,13 @@ module.exports = [ } ], resolve: { - extensions: [ '.tsx', '.ts', '.js' ], + extensions: [ ".tsx", ".ts", ".js" ], }, output: { libraryTarget: "commonjs2", globalObject: "this", - filename: 'renderer.js', - path: path.resolve(__dirname, 'dist'), + filename: "renderer.js", + path: path.resolve(__dirname, "dist"), }, }, ]; diff --git a/extensions/license-menu-item/webpack.config.ts b/extensions/license-menu-item/webpack.config.ts index 7edcb8355e..7b69571cd7 100644 --- a/extensions/license-menu-item/webpack.config.ts +++ b/extensions/license-menu-item/webpack.config.ts @@ -1,10 +1,10 @@ import path from "path"; -const outputPath = path.resolve(__dirname, 'dist'); +const outputPath = path.resolve(__dirname, "dist"); export default [ { - entry: './main.ts', + entry: "./main.ts", context: __dirname, target: "electron-main", mode: "production", @@ -12,7 +12,7 @@ export default [ rules: [ { test: /\.tsx?$/, - use: 'ts-loader', + use: "ts-loader", exclude: /node_modules/, }, ], @@ -22,12 +22,12 @@ export default [ "mobx": "var global.Mobx", }, resolve: { - extensions: ['.tsx', '.ts', '.js'], + extensions: [".tsx", ".ts", ".js"], }, output: { libraryTarget: "commonjs2", globalObject: "this", - filename: 'main.js', + filename: "main.js", path: outputPath, }, }, diff --git a/extensions/metrics-cluster-feature/renderer.tsx b/extensions/metrics-cluster-feature/renderer.tsx index b1afd1e570..9da5c391e2 100644 --- a/extensions/metrics-cluster-feature/renderer.tsx +++ b/extensions/metrics-cluster-feature/renderer.tsx @@ -7,15 +7,13 @@ export default class ClusterMetricsFeatureExtension extends LensRendererExtensio { title: "Metrics Stack", components: { - Description: () => { - return ( - - Enable timeseries data visualization (Prometheus stack) for your cluster. - Install this only if you don't have existing Prometheus stack installed. - You can see preview of manifests here. - - ); - } + Description: () => ( + + Enable timeseries data visualization (Prometheus stack) for your cluster. + Install this only if you don't have existing Prometheus stack installed. + You can see preview of manifests here. + + ) }, feature: new MetricsFeature() } diff --git a/extensions/metrics-cluster-feature/src/metrics-feature.ts b/extensions/metrics-cluster-feature/src/metrics-feature.ts index f843fe1506..904591d2a3 100644 --- a/extensions/metrics-cluster-feature/src/metrics-feature.ts +++ b/extensions/metrics-cluster-feature/src/metrics-feature.ts @@ -54,8 +54,8 @@ export class MetricsFeature extends ClusterFeature.Feature { const storageClassApi = K8sApi.forCluster(cluster, K8sApi.StorageClass); const scs = await storageClassApi.list(); this.templateContext.persistence.enabled = scs.some(sc => ( - sc.metadata?.annotations?.['storageclass.kubernetes.io/is-default-class'] === 'true' || - sc.metadata?.annotations?.['storageclass.beta.kubernetes.io/is-default-class'] === 'true' + sc.metadata?.annotations?.["storageclass.kubernetes.io/is-default-class"] === "true" || + sc.metadata?.annotations?.["storageclass.beta.kubernetes.io/is-default-class"] === "true" )); super.applyResources(cluster, path.join(__dirname, "../resources/")); diff --git a/extensions/metrics-cluster-feature/webpack.config.js b/extensions/metrics-cluster-feature/webpack.config.js index ab3ef3fec4..8d3ea196ba 100644 --- a/extensions/metrics-cluster-feature/webpack.config.js +++ b/extensions/metrics-cluster-feature/webpack.config.js @@ -1,8 +1,8 @@ -const path = require('path'); +const path = require("path"); module.exports = [ { - entry: './renderer.tsx', + entry: "./renderer.tsx", context: __dirname, target: "electron-renderer", mode: "production", @@ -10,7 +10,7 @@ module.exports = [ rules: [ { test: /\.tsx?$/, - use: 'ts-loader', + use: "ts-loader", exclude: /node_modules/, }, ], @@ -23,13 +23,13 @@ module.exports = [ } ], resolve: { - extensions: [ '.tsx', '.ts', '.js' ], + extensions: [ ".tsx", ".ts", ".js" ], }, output: { libraryTarget: "commonjs2", globalObject: "this", - filename: 'renderer.js', - path: path.resolve(__dirname, 'dist'), + filename: "renderer.js", + path: path.resolve(__dirname, "dist"), }, node: { __dirname: false diff --git a/extensions/node-menu/webpack.config.js b/extensions/node-menu/webpack.config.js index bc68a5c9f8..a35cf40850 100644 --- a/extensions/node-menu/webpack.config.js +++ b/extensions/node-menu/webpack.config.js @@ -1,8 +1,8 @@ -const path = require('path'); +const path = require("path"); module.exports = [ { - entry: './renderer.tsx', + entry: "./renderer.tsx", context: __dirname, target: "electron-renderer", mode: "production", @@ -10,7 +10,7 @@ module.exports = [ rules: [ { test: /\.tsx?$/, - use: 'ts-loader', + use: "ts-loader", exclude: /node_modules/, }, ], @@ -23,13 +23,13 @@ module.exports = [ } ], resolve: { - extensions: [ '.tsx', '.ts', '.js' ], + extensions: [ ".tsx", ".ts", ".js" ], }, output: { libraryTarget: "commonjs2", globalObject: "this", - filename: 'renderer.js', - path: path.resolve(__dirname, 'dist'), + filename: "renderer.js", + path: path.resolve(__dirname, "dist"), }, }, ]; diff --git a/extensions/pod-menu/webpack.config.js b/extensions/pod-menu/webpack.config.js index bc68a5c9f8..a35cf40850 100644 --- a/extensions/pod-menu/webpack.config.js +++ b/extensions/pod-menu/webpack.config.js @@ -1,8 +1,8 @@ -const path = require('path'); +const path = require("path"); module.exports = [ { - entry: './renderer.tsx', + entry: "./renderer.tsx", context: __dirname, target: "electron-renderer", mode: "production", @@ -10,7 +10,7 @@ module.exports = [ rules: [ { test: /\.tsx?$/, - use: 'ts-loader', + use: "ts-loader", exclude: /node_modules/, }, ], @@ -23,13 +23,13 @@ module.exports = [ } ], resolve: { - extensions: [ '.tsx', '.ts', '.js' ], + extensions: [ ".tsx", ".ts", ".js" ], }, output: { libraryTarget: "commonjs2", globalObject: "this", - filename: 'renderer.js', - path: path.resolve(__dirname, 'dist'), + filename: "renderer.js", + path: path.resolve(__dirname, "dist"), }, }, ]; diff --git a/extensions/telemetry/webpack.config.js b/extensions/telemetry/webpack.config.js index f13f54f9fd..c7862dc2c9 100644 --- a/extensions/telemetry/webpack.config.js +++ b/extensions/telemetry/webpack.config.js @@ -1,8 +1,8 @@ -const path = require('path'); +const path = require("path"); module.exports = [ { - entry: './main.ts', + entry: "./main.ts", context: __dirname, target: "electron-main", mode: "production", @@ -10,7 +10,7 @@ module.exports = [ rules: [ { test: /\.tsx?$/, - use: 'ts-loader', + use: "ts-loader", exclude: /node_modules/, }, ], @@ -23,17 +23,17 @@ module.exports = [ } ], resolve: { - extensions: [ '.tsx', '.ts', '.js' ], + extensions: [ ".tsx", ".ts", ".js" ], }, output: { libraryTarget: "commonjs2", globalObject: "this", - filename: 'main.js', - path: path.resolve(__dirname, 'dist'), + filename: "main.js", + path: path.resolve(__dirname, "dist"), }, }, { - entry: './renderer.tsx', + entry: "./renderer.tsx", context: __dirname, target: "electron-renderer", mode: "production", @@ -41,7 +41,7 @@ module.exports = [ rules: [ { test: /\.tsx?$/, - use: 'ts-loader', + use: "ts-loader", exclude: /node_modules/, }, ], @@ -55,13 +55,13 @@ module.exports = [ } ], resolve: { - extensions: [ '.tsx', '.ts', '.js' ], + extensions: [ ".tsx", ".ts", ".js" ], }, output: { libraryTarget: "commonjs2", globalObject: "this", - filename: 'renderer.js', - path: path.resolve(__dirname, 'dist'), + filename: "renderer.js", + path: path.resolve(__dirname, "dist"), }, }, ]; diff --git a/integration/__tests__/app.tests.ts b/integration/__tests__/app.tests.ts index eb67fc9ee8..e65dbcd445 100644 --- a/integration/__tests__/app.tests.ts +++ b/integration/__tests__/app.tests.ts @@ -8,9 +8,6 @@ import { Application } from "spectron"; import * as util from "../helpers/utils"; import { spawnSync } from "child_process"; -const describeif = (condition: boolean) => condition ? describe : describe.skip; -const itif = (condition: boolean) => condition ? it : it.skip; - jest.setTimeout(60000); // FIXME (!): improve / simplify all css-selectors + use [data-test-id="some-id"] (already used in some tests below) @@ -82,18 +79,18 @@ describe("Lens integration tests", () => { }); it('shows "add cluster"', async () => { - await app.electron.ipcRenderer.send('test-menu-item-click', "File", "Add Cluster"); + await app.electron.ipcRenderer.send("test-menu-item-click", "File", "Add Cluster"); await app.client.waitUntilTextExists("h2", "Add Cluster"); }); describe("preferences page", () => { it('shows "preferences"', async () => { const appName: string = process.platform === "darwin" ? "Lens" : "File"; - await app.electron.ipcRenderer.send('test-menu-item-click', appName, "Preferences"); + await app.electron.ipcRenderer.send("test-menu-item-click", appName, "Preferences"); await app.client.waitUntilTextExists("h2", "Preferences"); }); - it('ensures helm repos', async () => { + it("ensures helm repos", async () => { await app.client.waitUntilTextExists("div.repos #message-bitnami", "bitnami"); // wait for the helm-cli to fetch the bitnami repo await app.client.click("#HelmRepoSelect"); // click the repo select to activate the drop-down await app.client.waitUntilTextExists("div.Select__option", ""); // wait for at least one option to appear (any text) @@ -101,12 +98,12 @@ describe("Lens integration tests", () => { }); it.skip('quits Lens"', async () => { - await app.client.keys(['Meta', 'Q']); - await app.client.keys('Meta'); + await app.client.keys(["Meta", "Q"]); + await app.client.keys("Meta"); }); }); - describeif(ready)("workspaces", () => { + util.describeIf(ready)("workspaces", () => { beforeAll(appStart, 20000); afterAll(async () => { @@ -115,27 +112,27 @@ describe("Lens integration tests", () => { } }); - it('creates new workspace', async () => { + it("creates new workspace", async () => { await clickWhatsNew(app); - await app.client.click('#current-workspace .Icon'); + await app.client.click("#current-workspace .Icon"); await app.client.click('a[href="/workspaces"]'); - await app.client.click('.Workspaces button.Button'); + await app.client.click(".Workspaces button.Button"); await app.client.keys("test-workspace"); - await app.client.click('.Workspaces .Input.description input'); + await app.client.click(".Workspaces .Input.description input"); await app.client.keys("test description"); - await app.client.click('.Workspaces .workspace.editing .Icon'); + await app.client.click(".Workspaces .workspace.editing .Icon"); await app.client.waitUntilTextExists(".workspace .name a", "test-workspace"); }); - it('adds cluster in default workspace', async () => { + it("adds cluster in default workspace", async () => { await addMinikubeCluster(app); await app.client.waitUntilTextExists("pre.kube-auth-out", "Authentication proxy started"); await app.client.waitForExist(`iframe[name="minikube"]`); await app.client.waitForVisible(".ClustersMenu .ClusterIcon.active"); }); - it('adds cluster in test-workspace', async () => { - await app.client.click('#current-workspace .Icon'); + it("adds cluster in test-workspace", async () => { + await app.client.click("#current-workspace .Icon"); await app.client.waitForVisible('.WorkspaceMenu li[title="test description"]'); await app.client.click('.WorkspaceMenu li[title="test description"]'); await addMinikubeCluster(app); @@ -143,10 +140,10 @@ describe("Lens integration tests", () => { await app.client.waitForExist(`iframe[name="minikube"]`); }); - it('checks if default workspace has active cluster', async () => { - await app.client.click('#current-workspace .Icon'); - await app.client.waitForVisible('.WorkspaceMenu > li:first-of-type'); - await app.client.click('.WorkspaceMenu > li:first-of-type'); + it("checks if default workspace has active cluster", async () => { + await app.client.click("#current-workspace .Icon"); + await app.client.waitForVisible(".WorkspaceMenu > li:first-of-type"); + await app.client.click(".WorkspaceMenu > li:first-of-type"); await app.client.waitForVisible(".ClustersMenu .ClusterIcon.active"); }); }); @@ -170,7 +167,7 @@ describe("Lens integration tests", () => { await app.client.waitUntilTextExists("span.link-text", "Cluster"); }; - describeif(ready)("cluster tests", () => { + util.describeIf(ready)("cluster tests", () => { let clusterAdded = false; const addCluster = async () => { @@ -190,7 +187,7 @@ describe("Lens integration tests", () => { } }); - it('allows to add a cluster', async () => { + it("allows to add a cluster", async () => { await addCluster(); clusterAdded = true; }); @@ -515,7 +512,7 @@ describe("Lens integration tests", () => { } }); - it('shows default namespace', async () => { + it("shows default namespace", async () => { expect(clusterAdded).toBe(true); await app.client.click('a[href="/namespaces"]'); await app.client.waitUntilTextExists("div.TableCell", "default"); @@ -539,7 +536,7 @@ describe("Lens integration tests", () => { await app.client.waitUntilTextExists('a[href^="/pods"]', "Pods"); await app.client.click('a[href^="/pods"]'); await app.client.waitUntilTextExists("div.TableCell", "kube-apiserver"); - await app.client.click('.Icon.new-dock-tab'); + await app.client.click(".Icon.new-dock-tab"); await app.client.waitUntilTextExists("li.MenuItem.create-resource-tab", "Create resource"); await app.client.click("li.MenuItem.create-resource-tab"); await app.client.waitForVisible(".CreateResource div.ace_content"); diff --git a/integration/helpers/utils.ts b/integration/helpers/utils.ts index 9df2d9ed66..263caa50a7 100644 --- a/integration/helpers/utils.ts +++ b/integration/helpers/utils.ts @@ -6,6 +6,14 @@ const AppPaths: Partial> = { "darwin": "./dist/mac/Lens.app/Contents/MacOS/Lens", }; +export function itIf(condition: boolean) { + return condition ? it : it.skip; +} + +export function describeIf(condition: boolean) { + return condition ? describe : describe.skip; +} + export function setup(): Application { return new Application({ path: AppPaths[process.platform], // path to electron app diff --git a/package.json b/package.json index 889ca2cc9c..d0245d52d2 100644 --- a/package.json +++ b/package.json @@ -338,6 +338,8 @@ "electron-builder": "^22.7.0", "electron-notarize": "^0.3.0", "eslint": "^7.7.0", + "eslint-plugin-react": "^7.21.5", + "eslint-plugin-unused-imports": "^1.0.0", "file-loader": "^6.0.0", "flex.box": "^3.4.4", "fork-ts-checker-webpack-plugin": "^5.0.0", diff --git a/src/common/__tests__/cluster-store.test.ts b/src/common/__tests__/cluster-store.test.ts index 8c319d3f97..603a7c1b9e 100644 --- a/src/common/__tests__/cluster-store.test.ts +++ b/src/common/__tests__/cluster-store.test.ts @@ -13,8 +13,8 @@ describe("empty config", () => { beforeEach(() => { ClusterStore.resetInstance(); const mockOpts = { - 'tmp': { - 'lens-cluster-store.json': JSON.stringify({}) + "tmp": { + "lens-cluster-store.json": JSON.stringify({}) } }; mockFs(mockOpts); @@ -144,8 +144,8 @@ describe("config with existing clusters", () => { beforeEach(() => { ClusterStore.resetInstance(); const mockOpts = { - 'tmp': { - 'lens-cluster-store.json': JSON.stringify({ + "tmp": { + "lens-cluster-store.json": JSON.stringify({ __internal__: { migrations: { version: "99.99.99" @@ -153,24 +153,24 @@ describe("config with existing clusters", () => { }, clusters: [ { - id: 'cluster1', - kubeConfig: 'foo', - contextName: 'foo', - preferences: { terminalCWD: '/foo' }, - workspace: 'default' + id: "cluster1", + kubeConfig: "foo", + contextName: "foo", + preferences: { terminalCWD: "/foo" }, + workspace: "default" }, { - id: 'cluster2', - kubeConfig: 'foo2', - contextName: 'foo2', - preferences: { terminalCWD: '/foo2' } + id: "cluster2", + kubeConfig: "foo2", + contextName: "foo2", + preferences: { terminalCWD: "/foo2" } }, { - id: 'cluster3', - kubeConfig: 'foo', - contextName: 'foo', - preferences: { terminalCWD: '/foo' }, - workspace: 'foo' + id: "cluster3", + kubeConfig: "foo", + contextName: "foo", + preferences: { terminalCWD: "/foo" }, + workspace: "foo" }, ] }) @@ -186,27 +186,27 @@ describe("config with existing clusters", () => { }); it("allows to retrieve a cluster", () => { - const storedCluster = clusterStore.getById('cluster1'); - expect(storedCluster.id).toBe('cluster1'); - expect(storedCluster.preferences.terminalCWD).toBe('/foo'); + const storedCluster = clusterStore.getById("cluster1"); + expect(storedCluster.id).toBe("cluster1"); + expect(storedCluster.preferences.terminalCWD).toBe("/foo"); }); it("allows to delete a cluster", () => { - clusterStore.removeById('cluster2'); - const storedCluster = clusterStore.getById('cluster1'); + clusterStore.removeById("cluster2"); + const storedCluster = clusterStore.getById("cluster1"); expect(storedCluster).toBeTruthy(); - const storedCluster2 = clusterStore.getById('cluster2'); + const storedCluster2 = clusterStore.getById("cluster2"); expect(storedCluster2).toBeUndefined(); }); it("allows getting all of the clusters", async () => { const storedClusters = clusterStore.clustersList; expect(storedClusters.length).toBe(3); - expect(storedClusters[0].id).toBe('cluster1'); - expect(storedClusters[0].preferences.terminalCWD).toBe('/foo'); - expect(storedClusters[1].id).toBe('cluster2'); - expect(storedClusters[1].preferences.terminalCWD).toBe('/foo2'); - expect(storedClusters[2].id).toBe('cluster3'); + expect(storedClusters[0].id).toBe("cluster1"); + expect(storedClusters[0].preferences.terminalCWD).toBe("/foo"); + expect(storedClusters[1].id).toBe("cluster2"); + expect(storedClusters[1].preferences.terminalCWD).toBe("/foo2"); + expect(storedClusters[2].id).toBe("cluster3"); }); }); @@ -214,14 +214,14 @@ describe("pre 2.0 config with an existing cluster", () => { beforeEach(() => { ClusterStore.resetInstance(); const mockOpts = { - 'tmp': { - 'lens-cluster-store.json': JSON.stringify({ + "tmp": { + "lens-cluster-store.json": JSON.stringify({ __internal__: { migrations: { version: "1.0.0" } }, - cluster1: 'kubeconfig content' + cluster1: "kubeconfig content" }) } }; @@ -244,8 +244,8 @@ describe("pre 2.6.0 config with a cluster that has arrays in auth config", () => beforeEach(() => { ClusterStore.resetInstance(); const mockOpts = { - 'tmp': { - 'lens-cluster-store.json': JSON.stringify({ + "tmp": { + "lens-cluster-store.json": JSON.stringify({ __internal__: { migrations: { version: "2.4.1" @@ -270,8 +270,8 @@ describe("pre 2.6.0 config with a cluster that has arrays in auth config", () => const file = clusterStore.clustersList[0].kubeConfigPath; const config = fs.readFileSync(file, "utf8"); const kc = yaml.safeLoad(config); - expect(kc.users[0].user['auth-provider'].config['access-token']).toBe("should be string"); - expect(kc.users[0].user['auth-provider'].config['expiry']).toBe("should be string"); + expect(kc.users[0].user["auth-provider"].config["access-token"]).toBe("should be string"); + expect(kc.users[0].user["auth-provider"].config["expiry"]).toBe("should be string"); }); }); @@ -279,8 +279,8 @@ describe("pre 2.6.0 config with a cluster icon", () => { beforeEach(() => { ClusterStore.resetInstance(); const mockOpts = { - 'tmp': { - 'lens-cluster-store.json': JSON.stringify({ + "tmp": { + "lens-cluster-store.json": JSON.stringify({ __internal__: { migrations: { version: "2.4.1" @@ -308,8 +308,8 @@ describe("pre 2.6.0 config with a cluster icon", () => { 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.hasOwnProperty("icon")).toBe(false); + expect(storedClusterData.preferences.hasOwnProperty("icon")).toBe(true); expect(storedClusterData.preferences.icon.startsWith("data:;base64,")).toBe(true); }); }); @@ -318,8 +318,8 @@ describe("for a pre 2.7.0-beta.0 config without a workspace", () => { beforeEach(() => { ClusterStore.resetInstance(); const mockOpts = { - 'tmp': { - 'lens-cluster-store.json': JSON.stringify({ + "tmp": { + "lens-cluster-store.json": JSON.stringify({ __internal__: { migrations: { version: "2.6.6" @@ -345,7 +345,7 @@ describe("for a pre 2.7.0-beta.0 config without a workspace", () => { it("adds cluster to default workspace", async () => { const storedClusterData = clusterStore.clustersList[0]; - expect(storedClusterData.workspace).toBe('default'); + expect(storedClusterData.workspace).toBe("default"); }); }); @@ -353,8 +353,8 @@ describe("pre 3.6.0-beta.1 config with an existing cluster", () => { beforeEach(() => { ClusterStore.resetInstance(); const mockOpts = { - 'tmp': { - 'lens-cluster-store.json': JSON.stringify({ + "tmp": { + "lens-cluster-store.json": JSON.stringify({ __internal__: { migrations: { version: "3.5.0" @@ -362,9 +362,9 @@ describe("pre 3.6.0-beta.1 config with an existing cluster", () => { }, clusters: [ { - id: 'cluster1', - kubeConfig: 'kubeconfig content', - contextName: 'cluster', + id: "cluster1", + kubeConfig: "kubeconfig content", + contextName: "cluster", preferences: { icon: "store://icon_path", } diff --git a/src/common/__tests__/user-store.test.ts b/src/common/__tests__/user-store.test.ts index 05b668873a..2a05cd9adb 100644 --- a/src/common/__tests__/user-store.test.ts +++ b/src/common/__tests__/user-store.test.ts @@ -3,9 +3,9 @@ import mockFs from "mock-fs"; jest.mock("electron", () => { return { app: { - getVersion: () => '99.99.99', - getPath: () => 'tmp', - getLocale: () => 'en' + getVersion: () => "99.99.99", + getPath: () => "tmp", + getLocale: () => "en" } }; }); @@ -18,7 +18,7 @@ describe("user store tests", () => { describe("for an empty config", () => { beforeEach(() => { UserStore.resetInstance(); - mockFs({ tmp: { 'config.json': "{}" } }); + mockFs({ tmp: { "config.json": "{}" } }); }); afterEach(() => { @@ -35,26 +35,26 @@ describe("user store tests", () => { it("allows adding and listing seen contexts", () => { const us = UserStore.getInstance(); - us.seenContexts.add('foo'); + us.seenContexts.add("foo"); expect(us.seenContexts.size).toBe(1); - us.seenContexts.add('foo'); - us.seenContexts.add('bar'); + us.seenContexts.add("foo"); + us.seenContexts.add("bar"); expect(us.seenContexts.size).toBe(2); // check 'foo' isn't added twice - expect(us.seenContexts.has('foo')).toBe(true); - expect(us.seenContexts.has('bar')).toBe(true); + expect(us.seenContexts.has("foo")).toBe(true); + expect(us.seenContexts.has("bar")).toBe(true); }); it("allows setting and getting preferences", () => { const us = UserStore.getInstance(); - us.preferences.httpsProxy = 'abcd://defg'; + us.preferences.httpsProxy = "abcd://defg"; - expect(us.preferences.httpsProxy).toBe('abcd://defg'); + expect(us.preferences.httpsProxy).toBe("abcd://defg"); expect(us.preferences.colorTheme).toBe(UserStore.defaultTheme); us.preferences.colorTheme = "light"; - expect(us.preferences.colorTheme).toBe('light'); + expect(us.preferences.colorTheme).toBe("light"); }); it("correctly resets theme to default value", async () => { @@ -80,11 +80,11 @@ describe("user store tests", () => { beforeEach(() => { UserStore.resetInstance(); mockFs({ - 'tmp': { - 'config.json': JSON.stringify({ - user: { username: 'foobar' }, - preferences: { colorTheme: 'light' }, - lastSeenAppVersion: '1.2.3' + "tmp": { + "config.json": JSON.stringify({ + user: { username: "foobar" }, + preferences: { colorTheme: "light" }, + lastSeenAppVersion: "1.2.3" }) } }); @@ -97,7 +97,7 @@ describe("user store tests", () => { it("sets last seen app version to 0.0.0", () => { const us = UserStore.getInstance(); - expect(us.lastSeenAppVersion).toBe('0.0.0'); + expect(us.lastSeenAppVersion).toBe("0.0.0"); }); }); }); \ No newline at end of file diff --git a/src/common/__tests__/workspace-store.test.ts b/src/common/__tests__/workspace-store.test.ts index 86c76db6ca..e50bb23c99 100644 --- a/src/common/__tests__/workspace-store.test.ts +++ b/src/common/__tests__/workspace-store.test.ts @@ -3,9 +3,9 @@ import mockFs from "mock-fs"; jest.mock("electron", () => { return { app: { - getVersion: () => '99.99.99', - getPath: () => 'tmp', - getLocale: () => 'en' + getVersion: () => "99.99.99", + getPath: () => "tmp", + getLocale: () => "en" } }; }); @@ -16,7 +16,7 @@ describe("workspace store tests", () => { describe("for an empty config", () => { beforeEach(async () => { WorkspaceStore.resetInstance(); - mockFs({ tmp: { 'lens-workspace-store.json': "{}" } }); + mockFs({ tmp: { "lens-workspace-store.json": "{}" } }); await WorkspaceStore.getInstance().load(); }); @@ -146,7 +146,7 @@ describe("workspace store tests", () => { WorkspaceStore.resetInstance(); mockFs({ tmp: { - 'lens-workspace-store.json': JSON.stringify({ + "lens-workspace-store.json": JSON.stringify({ currentWorkspace: "abc", workspaces: [{ id: "abc", diff --git a/src/common/base-store.ts b/src/common/base-store.ts index 8b5fc98c32..7060f61f44 100644 --- a/src/common/base-store.ts +++ b/src/common/base-store.ts @@ -2,7 +2,7 @@ import path from "path"; import Config from "conf"; import { Options as ConfOptions } from "conf/dist/source/types"; import { app, ipcMain, IpcMainEvent, ipcRenderer, IpcRendererEvent, remote } from "electron"; -import { action, IReactionOptions, observable, reaction, runInAction, toJS, when } from "mobx"; +import { IReactionOptions, observable, reaction, runInAction, when } from "mobx"; import Singleton from "./utils/singleton"; import { getAppVersion } from "./utils/app-version"; import logger from "../main/logger"; diff --git a/src/common/ipc.ts b/src/common/ipc.ts index 2ff513c357..2d7852681d 100644 --- a/src/common/ipc.ts +++ b/src/common/ipc.ts @@ -16,7 +16,7 @@ export async function requestMain(channel: string, ...args: any[]) { async function getSubFrames(): Promise { const subFrames: number[] = []; - clusterFrameMap.forEach((frameId, _) => { + clusterFrameMap.forEach(frameId => { subFrames.push(frameId); }); return subFrames; diff --git a/src/common/kube-helpers.ts b/src/common/kube-helpers.ts index ecb85f78b9..b8d88c2227 100644 --- a/src/common/kube-helpers.ts +++ b/src/common/kube-helpers.ts @@ -7,7 +7,7 @@ import logger from "../main/logger"; import commandExists from "command-exists"; import { ExecValidationNotFoundError } from "./custom-errors"; -export const kubeConfigDefaultPath = path.join(os.homedir(), '.kube', 'config'); +export const kubeConfigDefaultPath = path.join(os.homedir(), ".kube", "config"); function resolveTilde(filePath: string) { if (filePath[0] === "~" && (filePath[1] === "/" || filePath.length === 1)) { @@ -78,15 +78,15 @@ export function dumpConfigYaml(kubeConfig: Partial): string { apiVersion: "v1", kind: "Config", preferences: {}, - 'current-context': kubeConfig.currentContext, + "current-context": kubeConfig.currentContext, clusters: kubeConfig.clusters.map(cluster => { return { name: cluster.name, cluster: { - 'certificate-authority-data': cluster.caData, - 'certificate-authority': cluster.caFile, + "certificate-authority-data": cluster.caData, + "certificate-authority": cluster.caFile, server: cluster.server, - 'insecure-skip-tls-verify': cluster.skipTLSVerify + "insecure-skip-tls-verify": cluster.skipTLSVerify } }; }), @@ -104,11 +104,11 @@ export function dumpConfigYaml(kubeConfig: Partial): string { return { name: user.name, user: { - 'client-certificate-data': user.certData, - 'client-certificate': user.certFile, - 'client-key-data': user.keyData, - 'client-key': user.keyFile, - 'auth-provider': user.authProvider, + "client-certificate-data": user.certData, + "client-certificate": user.certFile, + "client-key-data": user.keyData, + "client-key": user.keyFile, + "auth-provider": user.authProvider, exec: user.exec, token: user.token, username: user.username, diff --git a/src/common/user-store.ts b/src/common/user-store.ts index 2de6bcba6d..8b694c4f04 100644 --- a/src/common/user-store.ts +++ b/src/common/user-store.ts @@ -1,5 +1,5 @@ import type { ThemeId } from "../renderer/theme.store"; -import { app, remote } from 'electron'; +import { app, remote } from "electron"; import semver from "semver"; import { readFile } from "fs-extra"; import { action, observable, reaction, toJS } from "mobx"; @@ -9,7 +9,7 @@ import { getAppVersion } from "./utils/app-version"; import { kubeConfigDefaultPath, loadConfig } from "./kube-helpers"; import { appEventBus } from "./event-bus"; import logger from "../main/logger"; -import path from 'path'; +import path from "path"; export interface UserStoreModel { kubeConfigPath: string; diff --git a/src/common/utils/debouncePromise.ts b/src/common/utils/debouncePromise.ts index c9dcfafc89..e03c0e76bd 100755 --- a/src/common/utils/debouncePromise.ts +++ b/src/common/utils/debouncePromise.ts @@ -2,7 +2,7 @@ export function debouncePromise(func: (...args: F) => T | Promise, timeout = 0): (...args: F) => Promise { let timer: NodeJS.Timeout; - return (...params: any[]) => new Promise((resolve, reject) => { + return (...params: any[]) => new Promise(resolve => { clearTimeout(timer); timer = global.setTimeout(() => resolve(func.apply(this, params)), timeout); }); diff --git a/src/common/utils/escapeRegExp.ts b/src/common/utils/escapeRegExp.ts index dbf10e4bfb..b79188f33d 100644 --- a/src/common/utils/escapeRegExp.ts +++ b/src/common/utils/escapeRegExp.ts @@ -1,5 +1,5 @@ // Helper to sanitize / escape special chars for passing to RegExp-constructor export function escapeRegExp(str: string) { - return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string + return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string } diff --git a/src/extensions/__tests__/extension-loader.test.ts b/src/extensions/__tests__/extension-loader.test.ts index dd09d4614e..d2eec85a79 100644 --- a/src/extensions/__tests__/extension-loader.test.ts +++ b/src/extensions/__tests__/extension-loader.test.ts @@ -8,7 +8,7 @@ jest.mock( "electron", () => ({ ipcRenderer: { - invoke: jest.fn(async (channel: string, ...args: any[]) => { + invoke: jest.fn(async (channel: string) => { if (channel === "extensions:loaded") { return [ [ diff --git a/src/extensions/cluster-feature.ts b/src/extensions/cluster-feature.ts index 3ee671e6c5..bb60e9d9b4 100644 --- a/src/extensions/cluster-feature.ts +++ b/src/extensions/cluster-feature.ts @@ -112,7 +112,7 @@ export abstract class ClusterFeature { fs.readdirSync(folderPath).forEach(filename => { const file = path.join(folderPath, filename); const raw = fs.readFileSync(file); - if (filename.endsWith('.hb')) { + if (filename.endsWith(".hb")) { const template = hb.compile(raw.toString()); resources.push(template(this.templateContext)); } else { diff --git a/src/extensions/extension-discovery.ts b/src/extensions/extension-discovery.ts index c249496fa6..10597c3ceb 100644 --- a/src/extensions/extension-discovery.ts +++ b/src/extensions/extension-discovery.ts @@ -162,7 +162,7 @@ export class ExtensionDiscovery { if (path.relative(this.localFolderPath, filePath) === extensionFolderName) { const extensionName: string | undefined = Object .entries(this.packagesJson.dependencies) - .find(([_name, extensionFolder]) => filePath === extensionFolder)?.[0]; + .find(([, extensionFolder]) => filePath === extensionFolder)?.[0]; if (extensionName !== undefined) { delete this.packagesJson.dependencies[extensionName]; @@ -244,7 +244,6 @@ export class ExtensionDiscovery { isBundled?: boolean; } = {}): Promise { let manifestJson: LensExtensionManifest; - let isEnabled: boolean; try { // check manifest file for existence diff --git a/src/extensions/extension-installer.ts b/src/extensions/extension-installer.ts index 46a7a31e6f..42863fe60e 100644 --- a/src/extensions/extension-installer.ts +++ b/src/extensions/extension-installer.ts @@ -1,4 +1,4 @@ -import AwaitLock from 'await-lock'; +import AwaitLock from "await-lock"; import child_process from "child_process"; import fs from "fs-extra"; import path from "path"; @@ -27,7 +27,7 @@ export class ExtensionInstaller { } get npmPath() { - return __non_webpack_require__.resolve('npm/bin/npm-cli'); + return __non_webpack_require__.resolve("npm/bin/npm-cli"); } installDependencies(): Promise { diff --git a/src/extensions/extensions-store.ts b/src/extensions/extensions-store.ts index b81c415f85..2f865a165b 100644 --- a/src/extensions/extensions-store.ts +++ b/src/extensions/extensions-store.ts @@ -21,13 +21,9 @@ export class ExtensionsStore extends BaseStore { @computed get enabledExtensions() { - const extensions: string[] = []; - this.state.forEach((state, id) => { - if (state.enabled) { - extensions.push(state.name); - } - }); - return extensions; + return Array.from(this.state.values()) + .filter(({enabled}) => enabled) + .map(({name}) => name); } protected state = observable.map(); diff --git a/src/extensions/lens-main-extension.ts b/src/extensions/lens-main-extension.ts index 4947d76108..ab4d7a2a1f 100644 --- a/src/extensions/lens-main-extension.ts +++ b/src/extensions/lens-main-extension.ts @@ -1,5 +1,4 @@ import type { MenuRegistration } from "./registries/menu-registry"; -import { observable } from "mobx"; import { LensExtension } from "./lens-extension"; import { WindowManager } from "../main/window-manager"; import { getExtensionPageUrl } from "./registries/page-registry"; diff --git a/src/extensions/lens-renderer-extension.ts b/src/extensions/lens-renderer-extension.ts index 0ed286e94a..0c11306efd 100644 --- a/src/extensions/lens-renderer-extension.ts +++ b/src/extensions/lens-renderer-extension.ts @@ -1,6 +1,5 @@ import type { AppPreferenceRegistration, ClusterFeatureRegistration, KubeObjectDetailRegistration, KubeObjectMenuRegistration, KubeObjectStatusRegistration, PageMenuRegistration, PageRegistration, StatusBarRegistration, } from "./registries"; import type { Cluster } from "../main/cluster"; -import { observable } from "mobx"; import { LensExtension } from "./lens-extension"; import { getExtensionPageUrl } from "./registries/page-registry"; @@ -30,6 +29,7 @@ export class LensRendererExtension extends LensExtension { /** * Defines if extension is enabled for a given cluster. Defaults to `true`. */ + // eslint-disable-next-line unused-imports/no-unused-vars-ts async isEnabledForCluster(cluster: Cluster): Promise { return true; } diff --git a/src/extensions/registries/__tests__/page-registry.test.ts b/src/extensions/registries/__tests__/page-registry.test.ts index 0467ae7ea4..b7f2cd1252 100644 --- a/src/extensions/registries/__tests__/page-registry.test.ts +++ b/src/extensions/registries/__tests__/page-registry.test.ts @@ -1,4 +1,4 @@ -import { getExtensionPageUrl, globalPageRegistry, PageRegistration } from "../page-registry"; +import { getExtensionPageUrl, globalPageRegistry } from "../page-registry"; import { LensExtension } from "../../lens-extension"; import React from "react"; @@ -53,18 +53,18 @@ describe("globalPageRegistry", () => { { id: "test-page", components: { - Page: () => React.createElement('Text') + Page: () => React.createElement("Text") } }, { id: "another-page", components: { - Page: () => React.createElement('Text') + Page: () => React.createElement("Text") }, }, { components: { - Page: () => React.createElement('Default') + Page: () => React.createElement("Default") } }, ], ext); diff --git a/src/extensions/registries/page-menu-registry.ts b/src/extensions/registries/page-menu-registry.ts index 53131f507b..9f5c4861a4 100644 --- a/src/extensions/registries/page-menu-registry.ts +++ b/src/extensions/registries/page-menu-registry.ts @@ -1,7 +1,7 @@ // Extensions-api -> Register page menu items import type { IconProps } from "../../renderer/components/icon"; import type React from "react"; -import { action, computed } from "mobx"; +import { action } from "mobx"; import { BaseRegistry } from "./base-registry"; import { LensExtension } from "../lens-extension"; import { RegisteredPage } from "./page-registry"; diff --git a/src/main/__test__/cluster.test.ts b/src/main/__test__/cluster.test.ts index 95177408af..c057501eac 100644 --- a/src/main/__test__/cluster.test.ts +++ b/src/main/__test__/cluster.test.ts @@ -146,7 +146,7 @@ describe("create clusters", () => { } })); - mockedRequest.mockImplementationOnce(((uri: any, _options: any) => { + mockedRequest.mockImplementationOnce(((uri: any) => { expect(uri).toBe(`http://localhost:${port}/api-kube/version`); return Promise.resolve({ gitVersion: "1.2.3" }); }) as any); diff --git a/src/main/__test__/kube-auth-proxy.test.ts b/src/main/__test__/kube-auth-proxy.test.ts index dbb3e308e3..ac8322d75b 100644 --- a/src/main/__test__/kube-auth-proxy.test.ts +++ b/src/main/__test__/kube-auth-proxy.test.ts @@ -31,10 +31,10 @@ import { Cluster } from "../cluster"; import { KubeAuthProxy } from "../kube-auth-proxy"; import { getFreePort } from "../port"; import { broadcastMessage } from "../../common/ipc"; -import { ChildProcess, spawn, SpawnOptions } from "child_process"; +import { ChildProcess, spawn } from "child_process"; import { bundledKubectlPath, Kubectl } from "../kubectl"; -import { mock, MockProxy } from 'jest-mock-extended'; -import { waitUntilUsed } from 'tcp-port-used'; +import { mock, MockProxy } from "jest-mock-extended"; +import { waitUntilUsed } from "tcp-port-used"; import { Readable } from "stream"; const mockBroadcastIpc = broadcastMessage as jest.MockedFunction; @@ -81,7 +81,7 @@ describe("kube auth proxy tests", () => { listeners[`stdout/${event}`] = listener; return mockedCP.stdout; }); - mockSpawn.mockImplementationOnce((command: string, args: readonly string[], options: SpawnOptions): ChildProcess => { + mockSpawn.mockImplementationOnce((command: string): ChildProcess => { expect(command).toBe(bundledKubectlPath()); return mockedCP; }); diff --git a/src/main/cluster.ts b/src/main/cluster.ts index 80b0289c08..5ee7457529 100644 --- a/src/main/cluster.ts +++ b/src/main/cluster.ts @@ -9,7 +9,7 @@ import { ContextHandler } from "./context-handler"; import { AuthorizationV1Api, CoreV1Api, KubeConfig, V1ResourceAttributes } from "@kubernetes/client-node"; import { Kubectl } from "./kubectl"; import { KubeconfigManager } from "./kubeconfig-manager"; -import { getNodeWarningConditions, loadConfig, podHasIssues } from "../common/kube-helpers"; +import { loadConfig } from "../common/kube-helpers"; import request, { RequestPromiseOptions } from "request-promise-native"; import { apiResources } from "../common/rbac"; import logger from "./logger"; diff --git a/src/main/developer-tools.ts b/src/main/developer-tools.ts index 274ff46e91..3a3d5009f8 100644 --- a/src/main/developer-tools.ts +++ b/src/main/developer-tools.ts @@ -3,8 +3,8 @@ * The dependency is not bundled to the production build. */ export const installDeveloperTools = async () => { - if (process.env.NODE_ENV === 'development') { - const { default: devToolsInstaller, REACT_DEVELOPER_TOOLS } = await import('electron-devtools-installer'); + if (process.env.NODE_ENV === "development") { + const { default: devToolsInstaller, REACT_DEVELOPER_TOOLS } = await import("electron-devtools-installer"); return devToolsInstaller([REACT_DEVELOPER_TOOLS]); } diff --git a/src/main/exit-app.ts b/src/main/exit-app.ts index b58a6e4dfc..a998a2811f 100644 --- a/src/main/exit-app.ts +++ b/src/main/exit-app.ts @@ -11,7 +11,7 @@ export function exitApp() { appEventBus.emit({ name: "service", action: "close" }); windowManager.hide(); clusterManager.stop(); - logger.info('SERVICE:QUIT'); + logger.info("SERVICE:QUIT"); setTimeout(() => { app.exit(); }, 1000); diff --git a/src/main/helm/helm-chart-manager.ts b/src/main/helm/helm-chart-manager.ts index 42c1a30ed2..a5920afb71 100644 --- a/src/main/helm/helm-chart-manager.ts +++ b/src/main/helm/helm-chart-manager.ts @@ -36,10 +36,10 @@ export class HelmChartManager { public async getReadme(name: string, version = "") { const helm = await helmCli.binaryPath(); if(version && version != "") { - const { stdout, stderr} = await promiseExec(`"${helm}" show readme ${this.repo.name}/${name} --version ${version}`).catch((error) => { throw(error.stderr);}); + const { stdout } = await promiseExec(`"${helm}" show readme ${this.repo.name}/${name} --version ${version}`).catch((error) => { throw(error.stderr);}); return stdout; } else { - const { stdout, stderr} = await promiseExec(`"${helm}" show readme ${this.repo.name}/${name}`).catch((error) => { throw(error.stderr);}); + const { stdout } = await promiseExec(`"${helm}" show readme ${this.repo.name}/${name}`).catch((error) => { throw(error.stderr);}); return stdout; } } @@ -47,11 +47,11 @@ export class HelmChartManager { public async getValues(name: string, version = "") { const helm = await helmCli.binaryPath(); if(version && version != "") { - const { stdout, stderr} = await promiseExec(`"${helm}" show values ${this.repo.name}/${name} --version ${version}`).catch((error) => { throw(error.stderr);}); + const { stdout } = await promiseExec(`"${helm}" show values ${this.repo.name}/${name} --version ${version}`).catch((error) => { throw(error.stderr);}); return stdout; } else { - const { stdout, stderr} = await promiseExec(`"${helm}" show values ${this.repo.name}/${name}`).catch((error) => { throw(error.stderr);}); + const { stdout } = await promiseExec(`"${helm}" show values ${this.repo.name}/${name}`).catch((error) => { throw(error.stderr);}); return stdout; } @@ -59,12 +59,12 @@ export class HelmChartManager { protected async cachedYaml(): Promise { if (!(this.repo.name in this.cache)) { - const cacheFile = await fs.promises.readFile(this.repo.cacheFilePath, 'utf-8'); + const cacheFile = await fs.promises.readFile(this.repo.cacheFilePath, "utf-8"); const data = yaml.safeLoad(cacheFile); for(const key in data["entries"]) { data["entries"][key].forEach((version: any) => { - version['repo'] = this.repo.name; - version['created'] = Date.parse(version.created).toString(); + version["repo"] = this.repo.name; + version["created"] = Date.parse(version.created).toString(); }); } this.cache[this.repo.name] = Buffer.from(JSON.stringify(data)); diff --git a/src/main/helm/helm-release-manager.ts b/src/main/helm/helm-release-manager.ts index e468cdaef7..a669ff2a6c 100644 --- a/src/main/helm/helm-release-manager.ts +++ b/src/main/helm/helm-release-manager.ts @@ -34,8 +34,8 @@ export class HelmReleaseManager { generateName = "--generate-name"; name = ""; } - const { stdout, stderr } = await promiseExec(`"${helm}" install ${name} ${chart} --version ${version} -f ${fileName} --namespace ${namespace} --kubeconfig ${pathToKubeconfig} ${generateName}`).catch((error) => { throw(error.stderr);}); - const releaseName = stdout.split("\n")[0].split(' ')[1].trim(); + const { stdout } = await promiseExec(`"${helm}" install ${name} ${chart} --version ${version} -f ${fileName} --namespace ${namespace} --kubeconfig ${pathToKubeconfig} ${generateName}`).catch((error) => { throw(error.stderr);}); + const releaseName = stdout.split("\n")[0].split(" ")[1].trim(); return { log: stdout, release: { @@ -54,7 +54,7 @@ export class HelmReleaseManager { await fs.promises.writeFile(fileName, yaml.safeDump(values)); try { - const { stdout, stderr } = await promiseExec(`"${helm}" upgrade ${name} ${chart} --version ${version} -f ${fileName} --namespace ${namespace} --kubeconfig ${cluster.getProxyKubeconfigPath()}`).catch((error) => { throw(error.stderr);}); + const { stdout } = await promiseExec(`"${helm}" upgrade ${name} ${chart} --version ${version} -f ${fileName} --namespace ${namespace} --kubeconfig ${cluster.getProxyKubeconfigPath()}`).catch((error) => { throw(error.stderr);}); return { log: stdout, release: this.getRelease(name, namespace, cluster) @@ -66,7 +66,7 @@ export class HelmReleaseManager { public async getRelease(name: string, namespace: string, cluster: Cluster) { const helm = await helmCli.binaryPath(); - const {stdout, stderr} = await promiseExec(`"${helm}" status ${name} --output json --namespace ${namespace} --kubeconfig ${cluster.getProxyKubeconfigPath()}`).catch((error) => { throw(error.stderr);}); + const { stdout } = await promiseExec(`"${helm}" status ${name} --output json --namespace ${namespace} --kubeconfig ${cluster.getProxyKubeconfigPath()}`).catch((error) => { throw(error.stderr);}); const release = JSON.parse(stdout); release.resources = await this.getResources(name, namespace, cluster); return release; @@ -74,26 +74,26 @@ export class HelmReleaseManager { public async deleteRelease(name: string, namespace: string, pathToKubeconfig: string) { const helm = await helmCli.binaryPath(); - const { stdout, stderr } = await promiseExec(`"${helm}" delete ${name} --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr);}); + const { stdout } = await promiseExec(`"${helm}" delete ${name} --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr);}); return stdout; } public async getValues(name: string, namespace: string, pathToKubeconfig: string) { const helm = await helmCli.binaryPath(); - const { stdout, stderr } = await promiseExec(`"${helm}" get values ${name} --all --output yaml --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr);}); + const { stdout, } = await promiseExec(`"${helm}" get values ${name} --all --output yaml --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr);}); return stdout; } public async getHistory(name: string, namespace: string, pathToKubeconfig: string) { const helm = await helmCli.binaryPath(); - const {stdout, stderr} = await promiseExec(`"${helm}" history ${name} --output json --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr);}); + const { stdout } = await promiseExec(`"${helm}" history ${name} --output json --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr);}); return JSON.parse(stdout); } public async rollback(name: string, namespace: string, revision: number, pathToKubeconfig: string) { const helm = await helmCli.binaryPath(); - const {stdout, stderr} = await promiseExec(`"${helm}" rollback ${name} ${revision} --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr);}); + const { stdout } = await promiseExec(`"${helm}" rollback ${name} ${revision} --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr);}); return stdout; } @@ -101,7 +101,7 @@ export class HelmReleaseManager { const helm = await helmCli.binaryPath(); const kubectl = await cluster.kubeCtl.getPath(); const pathToKubeconfig = cluster.getProxyKubeconfigPath(); - const { stdout } = await promiseExec(`"${helm}" get manifest ${name} --namespace ${namespace} --kubeconfig ${pathToKubeconfig} | "${kubectl}" get -n ${namespace} --kubeconfig ${pathToKubeconfig} -f - -o=json`).catch((error) => { + const { stdout } = await promiseExec(`"${helm}" get manifest ${name} --namespace ${namespace} --kubeconfig ${pathToKubeconfig} | "${kubectl}" get -n ${namespace} --kubeconfig ${pathToKubeconfig} -f - -o=json`).catch(() => { return { stdout: JSON.stringify({items: []})}; }); return stdout; diff --git a/src/main/helm/helm-repo-manager.ts b/src/main/helm/helm-repo-manager.ts index 30ce8e3435..fea000fec2 100644 --- a/src/main/helm/helm-repo-manager.ts +++ b/src/main/helm/helm-repo-manager.ts @@ -77,7 +77,7 @@ export class HelmRepoManager extends Singleton { } try { const repoConfigFile = this.helmEnv.HELM_REPOSITORY_CONFIG; - const { repositories }: HelmRepoConfig = await readFile(repoConfigFile, 'utf8') + const { repositories }: HelmRepoConfig = await readFile(repoConfigFile, "utf8") .then((yamlContent: string) => yaml.safeLoad(yamlContent)) .catch(() => ({ repositories: [] @@ -121,7 +121,7 @@ export class HelmRepoManager extends Singleton { public async removeRepo({ name, url }: HelmRepo): Promise { logger.info(`[HELM]: removing repo "${name}" from ${url}`); const helm = await helmCli.binaryPath(); - const { stdout, stderr } = await promiseExec(`"${helm}" repo remove ${name}`).catch((error) => { + const { stdout } = await promiseExec(`"${helm}" repo remove ${name}`).catch((error) => { throw(error.stderr); }); return stdout; diff --git a/src/main/helm/helm-service.ts b/src/main/helm/helm-service.ts index 88ca4dda3e..0ccec256ed 100644 --- a/src/main/helm/helm-service.ts +++ b/src/main/helm/helm-service.ts @@ -85,7 +85,7 @@ class HelmService { for (const key in entries) { entries[key] = entries[key].filter((entry: any) => { if (Array.isArray(entry)) { - return entry[0]['deprecated'] != true; + return entry[0]["deprecated"] != true; } return entry["deprecated"] != true; }); diff --git a/src/main/index.ts b/src/main/index.ts index 1d6aadfd43..315526862c 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -77,6 +77,7 @@ app.on("ready", async () => { // run proxy try { + // eslint-disable-next-line unused-imports/no-unused-vars-ts proxyServer = LensProxy.create(proxyPort, clusterManager); } catch (error) { logger.error(`Could not start proxy (127.0.0:${proxyPort}): ${error.message}`); @@ -108,7 +109,7 @@ app.on("ready", async () => { }); app.on("activate", (event, hasVisibleWindows) => { - logger.info('APP:ACTIVATE', { hasVisibleWindows }); + logger.info("APP:ACTIVATE", { hasVisibleWindows }); if (!hasVisibleWindows) { windowManager.initMainWindow(); } @@ -116,7 +117,7 @@ app.on("activate", (event, hasVisibleWindows) => { // Quit app on Cmd+Q (MacOS) app.on("will-quit", (event) => { - logger.info('APP:QUIT'); + logger.info("APP:QUIT"); appEventBus.emit({name: "app", action: "close"}); event.preventDefault(); // prevent app's default shutdown (e.g. required for telemetry, etc.) clusterManager?.stop(); // close cluster connections diff --git a/src/main/kube-auth-proxy.ts b/src/main/kube-auth-proxy.ts index 3ad76e52b0..791b242104 100644 --- a/src/main/kube-auth-proxy.ts +++ b/src/main/kube-auth-proxy.ts @@ -60,7 +60,7 @@ export class KubeAuthProxy { this.exit(); }); - this.proxyProcess.stdout.on('data', (data) => { + this.proxyProcess.stdout.on("data", (data) => { let logItem = data.toString(); if (logItem.startsWith("Starting to serve on")) { logItem = "Authentication proxy started\n"; @@ -68,7 +68,7 @@ export class KubeAuthProxy { this.sendIpcLogMessage({ data: logItem }); }); - this.proxyProcess.stderr.on('data', (data) => { + this.proxyProcess.stderr.on("data", (data) => { this.lastError = this.parseError(data.toString()); this.sendIpcLogMessage({ data: data.toString(), error: true }); }); diff --git a/src/main/kubeconfig-manager.ts b/src/main/kubeconfig-manager.ts index a8b3ae3fce..4cbc060f7f 100644 --- a/src/main/kubeconfig-manager.ts +++ b/src/main/kubeconfig-manager.ts @@ -41,7 +41,7 @@ export class KubeconfigManager { * This way any user of the config does not need to know anything about the auth etc. details. */ protected async createProxyKubeconfig(): Promise { - const { configDir, cluster, contextHandler } = this; + const { configDir, cluster } = this; const { contextName, kubeConfigPath, id } = cluster; const tempFile = path.join(configDir, `kubeconfig-${id}`); const kubeConfig = loadConfig(kubeConfigPath); @@ -81,7 +81,7 @@ export class KubeconfigManager { return; } - logger.info('Deleting temporary kubeconfig: ' + this.tempFile); + logger.info("Deleting temporary kubeconfig: " + this.tempFile); await fs.unlink(this.tempFile); this.tempFile = undefined; } diff --git a/src/main/kubectl.ts b/src/main/kubectl.ts index 5d3f12746e..d0e190438d 100644 --- a/src/main/kubectl.ts +++ b/src/main/kubectl.ts @@ -123,6 +123,10 @@ export class Kubectl { } public async getPath(bundled = false): Promise { + if (bundled) { + return this.getBundledPath(); + } + if (userStore.preferences?.downloadKubectlBinaries === false) { return this.getPathFromPreferences(); } @@ -167,7 +171,7 @@ export class Kubectl { return true; } let version: string = output.clientVersion.gitVersion; - if (version[0] === 'v') { + if (version[0] === "v") { version = version.slice(1); } if (version === this.kubectlVersion) { @@ -274,7 +278,7 @@ export class Kubectl { const kubectlPath = userStore.preferences?.downloadKubectlBinaries ? this.dirname : path.dirname(this.getPathFromPreferences()); const helmPath = helmCli.getBinaryDir(); const fsPromises = fs.promises; - const bashScriptPath = path.join(this.dirname, '.bash_set_path'); + const bashScriptPath = path.join(this.dirname, ".bash_set_path"); let bashScript = "" + initScriptVersionString; bashScript += "tempkubeconfig=\"$KUBECONFIG\"\n"; @@ -297,7 +301,7 @@ export class Kubectl { bashScript += "unset tempkubeconfig\n"; await fsPromises.writeFile(bashScriptPath, bashScript.toString(), { mode: 0o644 }); - const zshScriptPath = path.join(this.dirname, '.zlogin'); + const zshScriptPath = path.join(this.dirname, ".zlogin"); let zshScript = "" + initScriptVersionString; diff --git a/src/main/lens-binary.ts b/src/main/lens-binary.ts index fc6b59ee74..7b0cae23c7 100644 --- a/src/main/lens-binary.ts +++ b/src/main/lens-binary.ts @@ -121,12 +121,12 @@ export class LensBinary { } protected async untarBinary() { - return new Promise((resolve, reject) => { + return new Promise(resolve => { this.logger.debug(`Extracting ${this.originalBinaryName} binary`); tar.x({ file: this.tarPath, cwd: this.dirname - }).then((_ => { + }).then((() => { resolve(); })); }); diff --git a/src/main/lens-proxy.ts b/src/main/lens-proxy.ts index 03b1b15d29..305312f90c 100644 --- a/src/main/lens-proxy.ts +++ b/src/main/lens-proxy.ts @@ -88,23 +88,23 @@ export class LensProxy { proxySocket.setTimeout(0); socket.setTimeout(0); - proxySocket.on('data', function (chunk) { + proxySocket.on("data", function (chunk) { socket.write(chunk); }); - proxySocket.on('end', function () { + proxySocket.on("end", function () { socket.end(); }); - proxySocket.on('error', function (err) { + proxySocket.on("error", function () { socket.write("HTTP/" + req.httpVersion + " 500 Connection error\r\n\r\n"); socket.end(); }); - socket.on('data', function (chunk) { + socket.on("data", function (chunk) { proxySocket.write(chunk); }); - socket.on('end', function () { + socket.on("end", function () { proxySocket.end(); }); - socket.on('error', function () { + socket.on("error", function () { proxySocket.end(); }); } diff --git a/src/main/menu.ts b/src/main/menu.ts index 06bd9095cb..feccbafa21 100644 --- a/src/main/menu.ts +++ b/src/main/menu.ts @@ -65,31 +65,31 @@ export function buildMenu(windowManager: WindowManager) { showAbout(browserWindow); } }, - { type: 'separator' }, + { type: "separator" }, { - label: 'Preferences', - accelerator: 'CmdOrCtrl+,', + label: "Preferences", + accelerator: "CmdOrCtrl+,", click() { navigate(preferencesURL()); } }, { - label: 'Extensions', - accelerator: 'CmdOrCtrl+Shift+E', + label: "Extensions", + accelerator: "CmdOrCtrl+Shift+E", click() { navigate(extensionsURL()); } }, - { type: 'separator' }, - { role: 'services' }, - { type: 'separator' }, - { role: 'hide' }, - { role: 'hideOthers' }, - { role: 'unhide' }, - { type: 'separator' }, + { type: "separator" }, + { role: "services" }, + { type: "separator" }, + { role: "hide" }, + { role: "hideOthers" }, + { role: "unhide" }, + { type: "separator" }, { - label: 'Quit', - accelerator: 'Cmd+Q', + label: "Quit", + accelerator: "Cmd+Q", click() { exitApp(); } @@ -101,16 +101,16 @@ export function buildMenu(windowManager: WindowManager) { label: "File", submenu: [ { - label: 'Add Cluster', - accelerator: 'CmdOrCtrl+Shift+A', + label: "Add Cluster", + accelerator: "CmdOrCtrl+Shift+A", click() { navigate(addClusterURL()); } }, ...activeClusterOnly([ { - label: 'Cluster Settings', - accelerator: 'CmdOrCtrl+Shift+S', + label: "Cluster Settings", + accelerator: "CmdOrCtrl+Shift+S", click() { navigate(clusterSettingsURL({ params: { @@ -121,32 +121,32 @@ export function buildMenu(windowManager: WindowManager) { } ]), ...ignoreOnMac([ - { type: 'separator' }, + { type: "separator" }, { - label: 'Preferences', - accelerator: 'Ctrl+,', + label: "Preferences", + accelerator: "Ctrl+,", click() { navigate(preferencesURL()); } }, { - label: 'Extensions', - accelerator: 'Ctrl+Shift+E', + label: "Extensions", + accelerator: "Ctrl+Shift+E", click() { navigate(extensionsURL()); } } ]), - { type: 'separator' }, + { type: "separator" }, { - role: 'close', + role: "close", label: "Close Window" }, ...ignoreOnMac([ - { type: 'separator' }, + { type: "separator" }, { - label: 'Exit', - accelerator: 'Alt+F4', + label: "Exit", + accelerator: "Alt+F4", click() { exitApp(); } @@ -156,56 +156,56 @@ export function buildMenu(windowManager: WindowManager) { }; const editMenu: MenuItemConstructorOptions = { - label: 'Edit', + label: "Edit", submenu: [ - { role: 'undo' }, - { role: 'redo' }, - { type: 'separator' }, - { role: 'cut' }, - { role: 'copy' }, - { role: 'paste' }, - { role: 'delete' }, - { type: 'separator' }, - { role: 'selectAll' }, + { role: "undo" }, + { role: "redo" }, + { type: "separator" }, + { role: "cut" }, + { role: "copy" }, + { role: "paste" }, + { role: "delete" }, + { type: "separator" }, + { role: "selectAll" }, ] }; const viewMenu: MenuItemConstructorOptions = { - label: 'View', + label: "View", submenu: [ { - label: 'Back', - accelerator: 'CmdOrCtrl+[', + label: "Back", + accelerator: "CmdOrCtrl+[", click() { webContents.getFocusedWebContents()?.goBack(); } }, { - label: 'Forward', - accelerator: 'CmdOrCtrl+]', + label: "Forward", + accelerator: "CmdOrCtrl+]", click() { webContents.getFocusedWebContents()?.goForward(); } }, { - label: 'Reload', - accelerator: 'CmdOrCtrl+R', + label: "Reload", + accelerator: "CmdOrCtrl+R", click() { windowManager.reload(); } }, - { role: 'toggleDevTools' }, - { type: 'separator' }, - { role: 'resetZoom' }, - { role: 'zoomIn' }, - { role: 'zoomOut' }, - { type: 'separator' }, - { role: 'togglefullscreen' } + { role: "toggleDevTools" }, + { type: "separator" }, + { role: "resetZoom" }, + { role: "zoomIn" }, + { role: "zoomOut" }, + { type: "separator" }, + { role: "togglefullscreen" } ] }; const helpMenu: MenuItemConstructorOptions = { - role: 'help', + role: "help", submenu: [ { label: "What's new?", @@ -265,7 +265,7 @@ export function buildMenu(windowManager: WindowManager) { if (isTestEnv) { // this is a workaround for the test environment (spectron) not being able to directly access // the application menus (https://github.com/electron-userland/spectron/issues/21) - ipcMain.on('test-menu-item-click', (event: IpcMainEvent, ...names: string[]) => { + ipcMain.on("test-menu-item-click", (event: IpcMainEvent, ...names: string[]) => { let menu: Menu = Menu.getApplicationMenu(); const parentLabels: string[] = []; let menuItem: MenuItem; @@ -286,7 +286,7 @@ export function buildMenu(windowManager: WindowManager) { } const { enabled, visible, click } = menuItem; - if (enabled === false || visible === false || typeof click !== 'function') { + if (enabled === false || visible === false || typeof click !== "function") { logger.info(`[MENU:test-menu-item-click] Menu item ${menuPath} not clickable`); return; } diff --git a/src/main/node-shell-session.ts b/src/main/node-shell-session.ts index 3d48afebc5..ea85b8ac2a 100644 --- a/src/main/node-shell-session.ts +++ b/src/main/node-shell-session.ts @@ -24,7 +24,7 @@ export class NodeShellSession extends ShellSession { const shell = await this.kubectl.getPath(); let args = []; if (this.createNodeShellPod(this.podId, this.nodeName)) { - await this.waitForRunningPod(this.podId).catch((error) => { + await this.waitForRunningPod(this.podId).catch(() => { this.exit(1001); }); } @@ -108,7 +108,7 @@ export class NodeShellSession extends ShellSession { const req = await watch.watch(`/api/v1/namespaces/kube-system/pods`, {}, // callback is called for each received object. - (_type, obj) => { + (type, obj) => { if (obj.metadata.name == podId && obj.status.phase === "Running") { resolve(true); } diff --git a/src/main/port_spec.ts b/src/main/port_spec.ts index bf01eb5dde..279bf5951e 100644 --- a/src/main/port_spec.ts +++ b/src/main/port_spec.ts @@ -1,4 +1,4 @@ -import { EventEmitter } from 'events'; +import { EventEmitter } from "events"; import { getFreePort } from "./port"; let newPort = 0; @@ -8,7 +8,7 @@ jest.mock("net", () => { createServer() { return new class MockServer extends EventEmitter { listen = jest.fn(() => { - this.emit('listening'); + this.emit("listening"); return this; }); address = () => { diff --git a/src/main/prometheus/lens.ts b/src/main/prometheus/lens.ts index eddd2457a3..725771a033 100644 --- a/src/main/prometheus/lens.ts +++ b/src/main/prometheus/lens.ts @@ -24,7 +24,7 @@ export class PrometheusLens implements PrometheusProvider { public getQueries(opts: PrometheusQueryOpts): PrometheusQuery { switch(opts.category) { - case 'cluster': + case "cluster": return { memoryUsage: ` sum( @@ -43,7 +43,7 @@ export class PrometheusLens implements PrometheusProvider { fsSize: `sum(node_filesystem_size_bytes{kubernetes_node=~"${opts.nodes}", mountpoint="/"}) by (kubernetes_node)`, fsUsage: `sum(node_filesystem_size_bytes{kubernetes_node=~"${opts.nodes}", mountpoint="/"} - node_filesystem_avail_bytes{kubernetes_node=~"${opts.nodes}", mountpoint="/"}) by (kubernetes_node)` }; - case 'nodes': + case "nodes": return { memoryUsage: `sum (node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) by (kubernetes_node)`, memoryCapacity: `sum(kube_node_status_capacity{resource="memory"}) by (node)`, @@ -52,7 +52,7 @@ export class PrometheusLens implements PrometheusProvider { fsSize: `sum(node_filesystem_size_bytes{mountpoint="/"}) by (kubernetes_node)`, fsUsage: `sum(node_filesystem_size_bytes{mountpoint="/"} - node_filesystem_avail_bytes{mountpoint="/"}) by (kubernetes_node)` }; - case 'pods': + case "pods": return { cpuUsage: `sum(rate(container_cpu_usage_seconds_total{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, cpuRequests: `sum(kube_pod_container_resource_requests{pod=~"${opts.pods}",resource="cpu",namespace="${opts.namespace}"}) by (${opts.selector})`, @@ -64,12 +64,12 @@ export class PrometheusLens implements PrometheusProvider { networkReceive: `sum(rate(container_network_receive_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, networkTransmit: `sum(rate(container_network_transmit_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})` }; - case 'pvc': + case "pvc": return { diskUsage: `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)`, diskCapacity: `sum(kubelet_volume_stats_capacity_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)` }; - case 'ingress': + case "ingress": const bytesSent = (ingress: string, statuses: string) => `sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)`; return { diff --git a/src/main/prometheus/operator.ts b/src/main/prometheus/operator.ts index cb7b9944f7..6880d4c27c 100644 --- a/src/main/prometheus/operator.ts +++ b/src/main/prometheus/operator.ts @@ -32,7 +32,7 @@ export class PrometheusOperator implements PrometheusProvider { public getQueries(opts: PrometheusQueryOpts): PrometheusQuery { switch(opts.category) { - case 'cluster': + case "cluster": return { memoryUsage: ` sum( @@ -51,7 +51,7 @@ export class PrometheusOperator implements PrometheusProvider { fsSize: `sum(node_filesystem_size_bytes{mountpoint="/"} * on (pod,namespace) group_left(node) kube_pod_info{node=~"${opts.nodes}"})`, fsUsage: `sum(node_filesystem_size_bytes{mountpoint="/"} * on (pod,namespace) group_left(node) kube_pod_info{node=~"${opts.nodes}"} - node_filesystem_avail_bytes{mountpoint="/"} * on (pod,namespace) group_left(node) kube_pod_info{node=~"${opts.nodes}"})` }; - case 'nodes': + case "nodes": return { memoryUsage: `sum((node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) * on (pod,namespace) group_left(node) kube_pod_info) by (node)`, memoryCapacity: `sum(kube_node_status_capacity{resource="memory"}) by (node)`, @@ -60,7 +60,7 @@ export class PrometheusOperator implements PrometheusProvider { fsSize: `sum(node_filesystem_size_bytes{mountpoint="/"} * on (pod,namespace) group_left(node) kube_pod_info) by (node)`, fsUsage: `sum((node_filesystem_size_bytes{mountpoint="/"} - node_filesystem_avail_bytes{mountpoint="/"}) * on (pod,namespace) group_left(node) kube_pod_info) by (node)` }; - case 'pods': + case "pods": return { cpuUsage: `sum(rate(container_cpu_usage_seconds_total{container!="POD",container!="",image!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, cpuRequests: `sum(kube_pod_container_resource_requests{pod=~"${opts.pods}",resource="cpu",namespace="${opts.namespace}"}) by (${opts.selector})`, @@ -72,12 +72,12 @@ export class PrometheusOperator implements PrometheusProvider { networkReceive: `sum(rate(container_network_receive_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, networkTransmit: `sum(rate(container_network_transmit_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})` }; - case 'pvc': + case "pvc": return { diskUsage: `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)`, diskCapacity: `sum(kubelet_volume_stats_capacity_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)` }; - case 'ingress': + case "ingress": const bytesSent = (ingress: string, statuses: string) => `sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)`; return { diff --git a/src/main/prometheus/stacklight.ts b/src/main/prometheus/stacklight.ts index 116ad728bb..84892214a1 100644 --- a/src/main/prometheus/stacklight.ts +++ b/src/main/prometheus/stacklight.ts @@ -24,7 +24,7 @@ export class PrometheusStacklight implements PrometheusProvider { public getQueries(opts: PrometheusQueryOpts): PrometheusQuery { switch(opts.category) { - case 'cluster': + case "cluster": return { memoryUsage: ` sum( @@ -43,7 +43,7 @@ export class PrometheusStacklight implements PrometheusProvider { fsSize: `sum(node_filesystem_size_bytes{node=~"${opts.nodes}", mountpoint="/"}) by (node)`, fsUsage: `sum(node_filesystem_size_bytes{node=~"${opts.nodes}", mountpoint="/"} - node_filesystem_avail_bytes{node=~"${opts.nodes}", mountpoint="/"}) by (node)` }; - case 'nodes': + case "nodes": return { memoryUsage: `sum (node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) by (node)`, memoryCapacity: `sum(kube_node_status_capacity{resource="memory"}) by (node)`, @@ -52,7 +52,7 @@ export class PrometheusStacklight implements PrometheusProvider { fsSize: `sum(node_filesystem_size_bytes{mountpoint="/"}) by (node)`, fsUsage: `sum(node_filesystem_size_bytes{mountpoint="/"} - node_filesystem_avail_bytes{mountpoint="/"}) by (node)` }; - case 'pods': + case "pods": return { cpuUsage: `sum(rate(container_cpu_usage_seconds_total{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, cpuRequests: `sum(kube_pod_container_resource_requests{pod=~"${opts.pods}",resource="cpu",namespace="${opts.namespace}"}) by (${opts.selector})`, @@ -64,12 +64,12 @@ export class PrometheusStacklight implements PrometheusProvider { networkReceive: `sum(rate(container_network_receive_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, networkTransmit: `sum(rate(container_network_transmit_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})` }; - case 'pvc': + case "pvc": return { diskUsage: `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)`, diskCapacity: `sum(kubelet_volume_stats_capacity_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)` }; - case 'ingress': + case "ingress": const bytesSent = (ingress: string, statuses: string) => `sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)`; return { diff --git a/src/main/resource-applier.ts b/src/main/resource-applier.ts index 0f4647a60f..24812a3102 100644 --- a/src/main/resource-applier.ts +++ b/src/main/resource-applier.ts @@ -75,7 +75,7 @@ export class ResourceApplier { delete resource.metadata?.resourceVersion; const annotations = resource.metadata?.annotations; if (annotations) { - delete annotations['kubectl.kubernetes.io/last-applied-configuration']; + delete annotations["kubectl.kubernetes.io/last-applied-configuration"]; } return resource; } diff --git a/src/main/router.ts b/src/main/router.ts index a386ef221b..27a25fa50f 100644 --- a/src/main/router.ts +++ b/src/main/router.ts @@ -100,11 +100,11 @@ export class Router { try { const filename = path.basename(req.url); // redirect requests to [appName].js, [appName].html /sockjs-node/ to webpack-dev-server (for hot-reload support) - const toWebpackDevServer = filename.includes(appName) || filename.includes('hot-update') || req.url.includes('sockjs-node'); + const toWebpackDevServer = filename.includes(appName) || filename.includes("hot-update") || req.url.includes("sockjs-node"); if (isDevelopment && toWebpackDevServer) { const redirectLocation = `http://localhost:${webpackDevServerPort}` + req.url; res.statusCode = 307; - res.setHeader('Location', redirectLocation); + res.setHeader("Location", redirectLocation); res.end(); return; } @@ -126,8 +126,8 @@ export class Router { protected addRoutes() { // Static assets this.router.add( - { method: 'get', path: '/{path*}' }, - ({ params, response, path, raw: { req } }: LensApiRequest) => { + { method: "get", path: "/{path*}" }, + ({ params, response, raw: { req } }: LensApiRequest) => { this.handleStaticFile(params.path, response, req); }); diff --git a/src/main/routes/kubeconfig-route.ts b/src/main/routes/kubeconfig-route.ts index 1c04b9525d..088bf1167f 100644 --- a/src/main/routes/kubeconfig-route.ts +++ b/src/main/routes/kubeconfig-route.ts @@ -6,36 +6,36 @@ import { CoreV1Api, V1Secret } from "@kubernetes/client-node"; function generateKubeConfig(username: string, secret: V1Secret, cluster: Cluster) { const tokenData = Buffer.from(secret.data["token"], "base64"); return { - 'apiVersion': 'v1', - 'kind': 'Config', - 'clusters': [ + "apiVersion": "v1", + "kind": "Config", + "clusters": [ { - 'name': cluster.contextName, - 'cluster': { - 'server': cluster.apiUrl, - 'certificate-authority-data': secret.data["ca.crt"] + "name": cluster.contextName, + "cluster": { + "server": cluster.apiUrl, + "certificate-authority-data": secret.data["ca.crt"] } } ], - 'users': [ + "users": [ { - 'name': username, - 'user': { - 'token': tokenData.toString("utf8"), + "name": username, + "user": { + "token": tokenData.toString("utf8"), } } ], - 'contexts': [ + "contexts": [ { - 'name': cluster.contextName, - 'context': { - 'user': username, - 'cluster': cluster.contextName, - 'namespace': secret.metadata.namespace, + "name": cluster.contextName, + "context": { + "user": username, + "cluster": cluster.contextName, + "namespace": secret.metadata.namespace, } } ], - 'current-context': cluster.contextName + "current-context": cluster.contextName }; } diff --git a/src/main/routes/watch-route.ts b/src/main/routes/watch-route.ts index dd42460a9d..52aec70b4c 100644 --- a/src/main/routes/watch-route.ts +++ b/src/main/routes/watch-route.ts @@ -72,7 +72,7 @@ class ApiWatcher { class WatchRoute extends LensApi { public async routeWatch(request: LensApiRequest) { - const { params, response, cluster} = request; + const { response, cluster} = request; const apis: string[] = request.query.getAll("api"); const watchers: ApiWatcher[] = []; diff --git a/src/main/shell-session.ts b/src/main/shell-session.ts index 3614abe28f..e5aaa0991f 100644 --- a/src/main/shell-session.ts +++ b/src/main/shell-session.ts @@ -73,7 +73,7 @@ export class ShellSession extends EventEmitter { case "powershell.exe": return ["-NoExit", "-command", `& {Set-Location $Env:USERPROFILE; $Env:PATH="${this.helmBinDir};${this.kubectlPathDir};$Env:PATH"}`]; case "bash": - return ["--init-file", path.join(this.kubectlBinDir, '.bash_set_path')]; + return ["--init-file", path.join(this.kubectlBinDir, ".bash_set_path")]; case "fish": return ["--login", "--init-command", `export PATH="${this.helmBinDir}:${this.kubectlPathDir}:$PATH"; export KUBECONFIG="${this.kubeconfigPath}"`]; case "zsh": @@ -156,7 +156,7 @@ export class ShellSession extends EventEmitter { this.shellProcess.resize(resizeMsgObj["Width"], resizeMsgObj["Height"]); break; case "9": - this.emit('newToken', message); + this.emit("newToken", message); break; } }); @@ -164,7 +164,7 @@ export class ShellSession extends EventEmitter { protected exit(code = 1000) { if (this.websocket.readyState == this.websocket.OPEN) this.websocket.close(code); - this.emit('exit'); + this.emit("exit"); } protected closeWebsocketOnProcessExit() { diff --git a/src/main/shell-sync.ts b/src/main/shell-sync.ts index 46d5788c12..80e07a8ac5 100644 --- a/src/main/shell-sync.ts +++ b/src/main/shell-sync.ts @@ -25,7 +25,7 @@ export async function shellSync() { const env: Env = JSON.parse(JSON.stringify(envVars)); if (!env.LANG) { // the LANG env var expects an underscore instead of electron's dash - env.LANG = `${app.getLocale().replace('-', '_')}.UTF-8`; + env.LANG = `${app.getLocale().replace("-", "_")}.UTF-8`; } else if (!env.LANG.endsWith(".UTF-8")) { env.LANG += ".UTF-8"; } diff --git a/src/main/tray.ts b/src/main/tray.ts index f98c064bdd..2c5ba736f2 100644 --- a/src/main/tray.ts +++ b/src/main/tray.ts @@ -66,7 +66,7 @@ export function createTrayMenu(windowManager: WindowManager): Menu { showAbout(browserWindow); }, }, - { type: 'separator' }, + { type: "separator" }, { label: "Open Lens", async click() { @@ -91,7 +91,7 @@ export function createTrayMenu(windowManager: WindowManager): Menu { submenu: clusters.map(cluster => { const { id: clusterId, name: label, online, workspace } = cluster; return { - label: `${online ? '✓' : '\x20'.repeat(3)/*offset*/}${label}`, + label: `${online ? "✓" : "\x20".repeat(3)/*offset*/}${label}`, toolTip: clusterId, async click() { workspaceStore.setActive(workspace); @@ -115,9 +115,9 @@ export function createTrayMenu(windowManager: WindowManager): Menu { } }, }, - { type: 'separator' }, + { type: "separator" }, { - label: 'Quit App', + label: "Quit App", click() { exitApp(); } diff --git a/src/migrations/cluster-store/2.0.0-beta.2.ts b/src/migrations/cluster-store/2.0.0-beta.2.ts index 245e9c019c..d7f1ef73f0 100644 --- a/src/migrations/cluster-store/2.0.0-beta.2.ts +++ b/src/migrations/cluster-store/2.0.0-beta.2.ts @@ -5,12 +5,12 @@ import { migration } from "../migration-wrapper"; export default migration({ version: "2.0.0-beta.2", - run(store, log) { + run(store) { for (const value of store) { 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__" || value[1].hasOwnProperty("kubeConfig")) continue; store.set(contextName, { kubeConfig: value[1] }); } } -}); \ No newline at end of file +}); diff --git a/src/migrations/cluster-store/2.4.1.ts b/src/migrations/cluster-store/2.4.1.ts index f9de1ed6d8..2bde7755f1 100644 --- a/src/migrations/cluster-store/2.4.1.ts +++ b/src/migrations/cluster-store/2.4.1.ts @@ -3,7 +3,7 @@ import { migration } from "../migration-wrapper"; export default migration({ version: "2.4.1", - run(store, log) { + run(store) { for (const value of store) { const contextName = value[0]; if (contextName === "__internal__") continue; diff --git a/src/migrations/cluster-store/2.6.0-beta.2.ts b/src/migrations/cluster-store/2.6.0-beta.2.ts index 3114202ed1..ed4b648ce1 100644 --- a/src/migrations/cluster-store/2.6.0-beta.2.ts +++ b/src/migrations/cluster-store/2.6.0-beta.2.ts @@ -3,7 +3,7 @@ import { migration } from "../migration-wrapper"; export default migration({ version: "2.6.0-beta.2", - run(store, log) { + run(store) { for (const value of store) { const clusterKey = value[0]; if (clusterKey === "__internal__") continue; diff --git a/src/migrations/cluster-store/2.6.0-beta.3.ts b/src/migrations/cluster-store/2.6.0-beta.3.ts index eae6a137be..63decfac1e 100644 --- a/src/migrations/cluster-store/2.6.0-beta.3.ts +++ b/src/migrations/cluster-store/2.6.0-beta.3.ts @@ -10,7 +10,7 @@ export default migration({ const cluster = value[1]; if (!cluster.kubeConfig) continue; const kubeConfig = yaml.safeLoad(cluster.kubeConfig); - if (!kubeConfig.hasOwnProperty('users')) continue; + if (!kubeConfig.hasOwnProperty("users")) continue; const userObj = kubeConfig.users[0]; if (userObj) { const user = userObj.user; diff --git a/src/migrations/cluster-store/2.7.0-beta.0.ts b/src/migrations/cluster-store/2.7.0-beta.0.ts index f1af3de3c9..a3c103769f 100644 --- a/src/migrations/cluster-store/2.7.0-beta.0.ts +++ b/src/migrations/cluster-store/2.7.0-beta.0.ts @@ -3,7 +3,7 @@ import { migration } from "../migration-wrapper"; export default migration({ version: "2.7.0-beta.0", - run(store, log) { + run(store) { for (const value of store) { const clusterKey = value[0]; if (clusterKey === "__internal__") continue; diff --git a/src/migrations/cluster-store/2.7.0-beta.1.ts b/src/migrations/cluster-store/2.7.0-beta.1.ts index 52e60ba527..73eb66ec2f 100644 --- a/src/migrations/cluster-store/2.7.0-beta.1.ts +++ b/src/migrations/cluster-store/2.7.0-beta.1.ts @@ -4,7 +4,7 @@ import { v4 as uuid } from "uuid"; export default migration({ version: "2.7.0-beta.1", - run(store, log) { + run(store) { const clusters: any[] = []; for (const value of store) { const clusterKey = value[0]; diff --git a/src/migrations/cluster-store/3.6.0-beta.1.ts b/src/migrations/cluster-store/3.6.0-beta.1.ts index c7e5889cd9..597aab4713 100644 --- a/src/migrations/cluster-store/3.6.0-beta.1.ts +++ b/src/migrations/cluster-store/3.6.0-beta.1.ts @@ -44,7 +44,7 @@ export default migration({ const iconPath = cluster.preferences.icon.replace("store://", ""); const fileData = fse.readFileSync(path.join(userDataPath, iconPath)); - cluster.preferences.icon = `data:;base64,${fileData.toString('base64')}`; + cluster.preferences.icon = `data:;base64,${fileData.toString("base64")}`; } else { delete cluster.preferences?.icon; } diff --git a/src/migrations/cluster-store/snap.ts b/src/migrations/cluster-store/snap.ts index 1136607cd7..699f88716f 100644 --- a/src/migrations/cluster-store/snap.ts +++ b/src/migrations/cluster-store/snap.ts @@ -1,7 +1,7 @@ // Fix embedded kubeconfig paths under snap config import { migration } from "../migration-wrapper"; -import { ClusterModel, ClusterStore } from "../../common/cluster-store"; +import { ClusterModel } from "../../common/cluster-store"; import { getAppVersion } from "../../common/utils/app-version"; import fs from "fs"; diff --git a/src/renderer/api/api-manager.ts b/src/renderer/api/api-manager.ts index 98dbe206c7..6c72f633f3 100644 --- a/src/renderer/api/api-manager.ts +++ b/src/renderer/api/api-manager.ts @@ -14,7 +14,7 @@ export class ApiManager { return this.apis.get(pathOrCallback) || this.apis.get(KubeApi.parseApi(pathOrCallback).apiBase); } - return Array.from(this.apis.values()).find(pathOrCallback ?? ((api: KubeApi) => true)); + return Array.from(this.apis.values()).find(pathOrCallback ?? (() => true)); } registerApi(apiBase: string, api: KubeApi) { diff --git a/src/renderer/api/endpoints/deployment.api.ts b/src/renderer/api/endpoints/deployment.api.ts index 0279d63ed1..5c0fd039df 100644 --- a/src/renderer/api/endpoints/deployment.api.ts +++ b/src/renderer/api/endpoints/deployment.api.ts @@ -40,7 +40,7 @@ export class DeploymentApi extends KubeApi { }, { headers: { - 'content-type': 'application/strategic-merge-patch+json' + "content-type": "application/strategic-merge-patch+json" } }); } diff --git a/src/renderer/api/endpoints/metrics.api.ts b/src/renderer/api/endpoints/metrics.api.ts index 7f30487d44..86c829bcd6 100644 --- a/src/renderer/api/endpoints/metrics.api.ts +++ b/src/renderer/api/endpoints/metrics.api.ts @@ -40,7 +40,7 @@ export const metricsApi = { if (!start && !end) { const timeNow = Date.now() / 1000; - const now = moment.unix(timeNow).startOf('minute').unix(); // round date to minutes + const now = moment.unix(timeNow).startOf("minute").unix(); // round date to minutes start = now - range; end = now; } diff --git a/src/renderer/api/endpoints/persistent-volume-claims.api.ts b/src/renderer/api/endpoints/persistent-volume-claims.api.ts index 9aa73bb0bc..529aefa951 100644 --- a/src/renderer/api/endpoints/persistent-volume-claims.api.ts +++ b/src/renderer/api/endpoints/persistent-volume-claims.api.ts @@ -7,8 +7,8 @@ import { KubeApi } from "../kube-api"; export class PersistentVolumeClaimsApi extends KubeApi { getMetrics(pvcName: string, namespace: string): Promise { return metricsApi.getMetrics({ - diskUsage: { category: 'pvc', pvc: pvcName }, - diskCapacity: { category: 'pvc', pvc: pvcName } + diskUsage: { category: "pvc", pvc: pvcName }, + diskCapacity: { category: "pvc", pvc: pvcName } }, { namespace }); diff --git a/src/renderer/api/json-api.ts b/src/renderer/api/json-api.ts index 8d30f08a57..177aa3c9c2 100644 --- a/src/renderer/api/json-api.ts +++ b/src/renderer/api/json-api.ts @@ -34,7 +34,7 @@ export interface JsonApiConfig { export class JsonApi { static reqInitDefault: RequestInit = { headers: { - 'content-type': 'application/json' + "content-type": "application/json" } }; @@ -132,9 +132,9 @@ export class JsonApi { protected writeLog(log: JsonApiLog) { if (!this.config.debug) return; const { method, reqUrl, ...params } = log; - let textStyle = 'font-weight: bold;'; - if (params.data) textStyle += 'background: green; color: white;'; - if (params.error) textStyle += 'background: red; color: white;'; + let textStyle = "font-weight: bold;"; + if (params.data) textStyle += "background: green; color: white;"; + if (params.error) textStyle += "background: red; color: white;"; console.log(`%c${method} ${reqUrl}`, textStyle, params); } } diff --git a/src/renderer/api/kube-api-parse.ts b/src/renderer/api/kube-api-parse.ts index 5d7ad091ee..174fdae918 100644 --- a/src/renderer/api/kube-api-parse.ts +++ b/src/renderer/api/kube-api-parse.ts @@ -77,7 +77,7 @@ export function parseKubeApi(path: string): IKubeApiParsed { * 3. otherwise assume apiVersion <- left[0] * 4. always resource, name <- left[(0 or 1)+1..] */ - if (left[0].includes('.') || left[1].match(/^v[0-9]/)) { + if (left[0].includes(".") || left[1].match(/^v[0-9]/)) { [apiGroup, apiVersion] = left; resource = left.slice(2).join("/"); } else { diff --git a/src/renderer/api/kube-watch-api.ts b/src/renderer/api/kube-watch-api.ts index 8ce44fb77c..30875220e1 100644 --- a/src/renderer/api/kube-watch-api.ts +++ b/src/renderer/api/kube-watch-api.ts @@ -142,7 +142,7 @@ export class KubeWatchApi { protected writeLog(...data: any[]) { if (isDevelopment) { - console.log('%cKUBE-WATCH-API:', `font-weight: bold`, ...data); + console.log("%cKUBE-WATCH-API:", `font-weight: bold`, ...data); } } diff --git a/src/renderer/api/terminal-api.ts b/src/renderer/api/terminal-api.ts index 4f66544f86..6f28b53aa2 100644 --- a/src/renderer/api/terminal-api.ts +++ b/src/renderer/api/terminal-api.ts @@ -91,7 +91,6 @@ export class TerminalApi extends WebSocketApi { } reconnect() { - const { reconnectDelaySeconds } = this.params; super.reconnect(); } diff --git a/src/renderer/api/websocket-api.ts b/src/renderer/api/websocket-api.ts index 934d6cded6..6bc915b5af 100644 --- a/src/renderer/api/websocket-api.ts +++ b/src/renderer/api/websocket-api.ts @@ -88,7 +88,7 @@ export class WebSocketApi { reconnect() { const { reconnectDelaySeconds } = this.params; if (!reconnectDelaySeconds) return; - this.writeLog('reconnect after', reconnectDelaySeconds + "ms"); + this.writeLog("reconnect after", reconnectDelaySeconds + "ms"); this.reconnectTimer = setTimeout(() => this.connect(), reconnectDelaySeconds * 1000); this.readyState = WebSocketApiState.RECONNECTING; } @@ -136,17 +136,17 @@ export class WebSocketApi { this.onOpen.emit(); if (this.params.flushOnOpen) this.flush(); this.readyState = WebSocketApiState.OPEN; - this.writeLog('%cOPEN', 'color:green;font-weight:bold;', evt); + this.writeLog("%cOPEN", "color:green;font-weight:bold;", evt); } protected _onMessage(evt: MessageEvent) { const data = this.parseMessage(evt.data); this.onData.emit(data); - this.writeLog('%cMESSAGE', 'color:black;font-weight:bold;', data); + this.writeLog("%cMESSAGE", "color:black;font-weight:bold;", data); } protected _onError(evt: Event) { - this.writeLog('%cERROR', 'color:red;font-weight:bold;', evt); + this.writeLog("%cERROR", "color:red;font-weight:bold;", evt); } protected _onClose(evt: CloseEvent) { @@ -158,7 +158,7 @@ export class WebSocketApi { this.readyState = WebSocketApiState.CLOSED; this.onClose.emit(); } - this.writeLog('%cCLOSE', `color:${error ? "red" : "black"};font-weight:bold;`, evt); + this.writeLog("%cCLOSE", `color:${error ? "red" : "black"};font-weight:bold;`, evt); } protected writeLog(...data: any[]) { diff --git a/src/renderer/components/+add-cluster/add-cluster.tsx b/src/renderer/components/+add-cluster/add-cluster.tsx index 139ebd392c..e18a655f97 100644 --- a/src/renderer/components/+add-cluster/add-cluster.tsx +++ b/src/renderer/components/+add-cluster/add-cluster.tsx @@ -1,6 +1,6 @@ import "./add-cluster.scss"; import os from "os"; -import React, { Fragment } from "react"; +import React from "react"; import { observer } from "mobx-react"; import { action, observable, runInAction } from "mobx"; import { remote } from "electron"; @@ -12,7 +12,6 @@ import { DropFileInput, Input } from "../input"; import { AceEditor } from "../ace-editor"; import { Button } from "../button"; import { Icon } from "../icon"; -import { WizardLayout } from "../layout/wizard-layout"; import { kubeConfigDefaultPath, loadConfig, splitConfig, validateConfig, validateKubeConfig } from "../../../common/kube-helpers"; import { ClusterModel, ClusterStore, clusterStore } from "../../../common/cluster-store"; import { workspaceStore } from "../../../common/workspace-store"; @@ -67,7 +66,7 @@ export class AddCluster extends React.Component { userStore.kubeConfigPath = filePath; // save to store } catch (err) { Notifications.error( -
Can't setup {filePath} as kubeconfig: {String(err)}
+
Can't setup {filePath} as kubeconfig: {String(err)}
); if (throwError) { throw err; @@ -197,9 +196,9 @@ export class AddCluster extends React.Component { return (

Add clusters by clicking the Add Cluster button. - You'll need to obtain a working kubeconfig for the cluster you want to add. + You'll need to obtain a working kubeconfig for the cluster you want to add. You can either browse it from the file system or paste it as a text from the clipboard. - Read more about adding clusters here. + Read more about adding clusters here.

); } @@ -301,7 +300,7 @@ export class AddCluster extends React.Component { ); } - onKubeConfigInputBlur = (evt: React.FocusEvent) => { + onKubeConfigInputBlur = () => { const isChanged = this.kubeConfigPath !== userStore.kubeConfigPath; if (isChanged) { this.kubeConfigPath = this.kubeConfigPath.replace("~", os.homedir()); @@ -332,14 +331,12 @@ export class AddCluster extends React.Component { }; render() { - const addDisabled = this.selectedContexts.length === 0; + const submitDisabled = this.selectedContexts.length === 0; return ( - Add Clusters}> -

Add Clusters from Kubeconfig

- - {this.renderInfo()} - - + + Add Clusters}> +

Add Clusters from Kubeconfig

+ {this.renderInfo()} {this.renderKubeConfigSource()} {this.renderContextSelector()}
@@ -357,7 +354,7 @@ export class AddCluster extends React.Component { theme="round-black" /> - {'A HTTP proxy server URL (format: http://
:).'} + {"A HTTP proxy server URL (format: http://
:)."}
)} @@ -368,16 +365,16 @@ export class AddCluster extends React.Component {
-
-
+ + ); } } diff --git a/src/renderer/components/+apps-helm-charts/helm-chart-details.tsx b/src/renderer/components/+apps-helm-charts/helm-chart-details.tsx index a446c4dd52..fb7657291d 100644 --- a/src/renderer/components/+apps-helm-charts/helm-chart-details.tsx +++ b/src/renderer/components/+apps-helm-charts/helm-chart-details.tsx @@ -93,11 +93,11 @@ export class HelmChartDetails extends Component { /> - {selectedChart.getHome()} + {selectedChart.getHome()} {selectedChart.getMaintainers().map(({ name, email, url }) => - {name} + {name} )} {selectedChart.getKeywords().length > 0 && ( diff --git a/src/renderer/components/+apps-helm-charts/helm-charts.tsx b/src/renderer/components/+apps-helm-charts/helm-charts.tsx index c8b5312800..d1e221240d 100644 --- a/src/renderer/components/+apps-helm-charts/helm-charts.tsx +++ b/src/renderer/components/+apps-helm-charts/helm-charts.tsx @@ -84,7 +84,7 @@ export class HelmCharts extends Component { ]} renderTableContents={(chart: HelmChart) => [ -
+
evt.currentTarget.classList.add("visible")} diff --git a/src/renderer/components/+apps-releases/release-menu.tsx b/src/renderer/components/+apps-releases/release-menu.tsx index aae3f34b79..4bdaa3a184 100644 --- a/src/renderer/components/+apps-releases/release-menu.tsx +++ b/src/renderer/components/+apps-releases/release-menu.tsx @@ -56,8 +56,9 @@ export class HelmReleaseMenu extends React.Component { {...menuProps} className={cssNames("HelmReleaseMenu", className)} removeAction={this.remove} - children={this.renderContent()} - /> + > + {this.renderContent()} + ); } } diff --git a/src/renderer/components/+apps-releases/releases.tsx b/src/renderer/components/+apps-releases/releases.tsx index 29dd11deb8..94ca7ce935 100644 --- a/src/renderer/components/+apps-releases/releases.tsx +++ b/src/renderer/components/+apps-releases/releases.tsx @@ -70,7 +70,7 @@ export class HelmReleases extends Component {
Remove {releaseNames}?

- Note: StatefulSet Volumes won't be deleted automatically + Note: StatefulSet Volumes won't be deleted automatically

); @@ -146,4 +146,4 @@ export class HelmReleases extends Component { ); } -} \ No newline at end of file +} diff --git a/src/renderer/components/+cluster-settings/components/cluster-accessible-namespaces.tsx b/src/renderer/components/+cluster-settings/components/cluster-accessible-namespaces.tsx index f4c9e2731d..df7aeedecd 100644 --- a/src/renderer/components/+cluster-settings/components/cluster-accessible-namespaces.tsx +++ b/src/renderer/components/+cluster-settings/components/cluster-accessible-namespaces.tsx @@ -19,7 +19,7 @@ export class ClusterAccessibleNamespaces extends React.Component { return ( <> -

This setting is useful for manually specifying which namespaces you have access to. This is useful when you don't have permissions to list namespaces.

+

This setting is useful for manually specifying which namespaces you have access to. This is useful when you don't have permissions to list namespaces.

{ diff --git a/src/renderer/components/+cluster-settings/components/cluster-icon-setting.tsx b/src/renderer/components/+cluster-settings/components/cluster-icon-setting.tsx index 6f893a48fb..bc9d45818a 100644 --- a/src/renderer/components/+cluster-settings/components/cluster-icon-setting.tsx +++ b/src/renderer/components/+cluster-settings/components/cluster-icon-setting.tsx @@ -28,7 +28,7 @@ export class ClusterIconSetting extends React.Component { try { if (file) { const buf = Buffer.from(await file.arrayBuffer()); - cluster.preferences.icon = `data:${file.type};base64,${buf.toString('base64')}`; + cluster.preferences.icon = `data:${file.type};base64,${buf.toString("base64")}`; } else { // this has to be done as a seperate branch (and not always) because `cluster` // is observable and triggers an update loop. diff --git a/src/renderer/components/+cluster-settings/components/cluster-prometheus-setting.tsx b/src/renderer/components/+cluster-settings/components/cluster-prometheus-setting.tsx index d3bc9b4e46..90df9b780c 100644 --- a/src/renderer/components/+cluster-settings/components/cluster-prometheus-setting.tsx +++ b/src/renderer/components/+cluster-settings/components/cluster-prometheus-setting.tsx @@ -78,7 +78,7 @@ export class ClusterPrometheusSetting extends React.Component {

Use pre-installed Prometheus service for metrics. Please refer to the{" "} - guide{" "} + guide{" "} for possible configuration changes.

Prometheus installation method.

@@ -103,11 +103,11 @@ export class ClusterPrometheusSetting extends React.Component { /> An address to an existing Prometheus installation{" "} - ({'/:'}). Lens tries to auto-detect address if left empty. + ({"/:"}). Lens tries to auto-detect address if left empty. )} ); } -} \ No newline at end of file +} diff --git a/src/renderer/components/+cluster-settings/features.tsx b/src/renderer/components/+cluster-settings/features.tsx index 271a6e69b1..d2a0720ecf 100644 --- a/src/renderer/components/+cluster-settings/features.tsx +++ b/src/renderer/components/+cluster-settings/features.tsx @@ -14,16 +14,18 @@ export class Features extends React.Component { return (

Features

- { clusterFeatureRegistry.getItems().map((f) => { - return ( - - <> - -

- -
- ); - })} + { + clusterFeatureRegistry + .getItems() + .map((f) => ( + + <> + +

+ +
+ )) + }
); } diff --git a/src/renderer/components/+config-autoscalers/hpa.tsx b/src/renderer/components/+config-autoscalers/hpa.tsx index f955ce098d..cd07c386fd 100644 --- a/src/renderer/components/+config-autoscalers/hpa.tsx +++ b/src/renderer/components/+config-autoscalers/hpa.tsx @@ -62,7 +62,7 @@ export class HorizontalPodAutoscalers extends React.Component { ]} renderTableContents={(hpa: HorizontalPodAutoscaler) => [ hpa.getName(), - , + , hpa.getNs(), this.getTargets(hpa), hpa.getMinPods(), @@ -85,4 +85,3 @@ export class HorizontalPodAutoscalers extends React.Component { ); } } - diff --git a/src/renderer/components/+config-maps/config-maps.tsx b/src/renderer/components/+config-maps/config-maps.tsx index 67b4fe8e0e..c67c1f0aa4 100644 --- a/src/renderer/components/+config-maps/config-maps.tsx +++ b/src/renderer/components/+config-maps/config-maps.tsx @@ -5,11 +5,9 @@ import { observer } from "mobx-react"; import { Trans } from "@lingui/macro"; import { RouteComponentProps } from "react-router"; import { configMapsStore } from "./config-maps.store"; -import { ConfigMap, configMapApi } from "../../api/endpoints/configmap.api"; -import { KubeObjectMenu, KubeObjectMenuProps } from "../kube-object/kube-object-menu"; +import { ConfigMap } from "../../api/endpoints/configmap.api"; import { KubeObjectListLayout } from "../kube-object"; import { IConfigMapsRouteParams } from "./config-maps.route"; -import { apiManager } from "../../api/api-manager"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; enum sortBy { @@ -48,7 +46,7 @@ export class ConfigMaps extends React.Component { ]} renderTableContents={(configMap: ConfigMap) => [ configMap.getName(), - , + , configMap.getNs(), configMap.getKeys().join(", "), configMap.getAge(), @@ -57,4 +55,3 @@ export class ConfigMaps extends React.Component { ); } } - diff --git a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets-details.tsx b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets-details.tsx index 25925f6436..59f91070c0 100644 --- a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets-details.tsx +++ b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets-details.tsx @@ -19,18 +19,17 @@ export class PodDisruptionBudgetDetails extends React.Component { render() { const { object: pdb } = this.props; if (!pdb) return null; - const { status, spec } = pdb; const selectors = pdb.getSelectors(); return (
{selectors.length > 0 && - Selector} labelsOnly> - { - selectors.map(label => ) - } - + Selector} labelsOnly> + { + selectors.map(label => ) + } + } Min Available}> diff --git a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.tsx b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.tsx index 4a7bb04ddd..80f9f1a424 100644 --- a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.tsx +++ b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.tsx @@ -3,13 +3,9 @@ import "./pod-disruption-budgets.scss"; import * as React from "react"; import { observer } from "mobx-react"; import { Trans } from "@lingui/macro"; -import { RouteComponentProps } from "react-router"; import { podDisruptionBudgetsStore } from "./pod-disruption-budgets.store"; -import { PodDisruptionBudget, pdbApi } from "../../api/endpoints/poddisruptionbudget.api"; -import { KubeObjectMenu, KubeObjectMenuProps } from "../kube-object/kube-object-menu"; +import { PodDisruptionBudget } from "../../api/endpoints/poddisruptionbudget.api"; import { KubeObjectDetailsProps, KubeObjectListLayout } from "../kube-object"; -import { IPodDisruptionBudgetsRouteParams } from "./pod-disruption-budgets.route"; -import { apiManager } from "../../api/api-manager"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; enum sortBy { @@ -58,7 +54,7 @@ export class PodDisruptionBudgets extends React.Component { renderTableContents={(pdb: PodDisruptionBudget) => { return [ pdb.getName(), - , + , pdb.getNs(), pdb.getMinAvailable(), pdb.getMaxUnavailable(), diff --git a/src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx b/src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx index 534c494268..0c7158bee8 100644 --- a/src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx +++ b/src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx @@ -63,7 +63,7 @@ export class AddQuotaDialog extends React.Component { @computed get quotaEntries() { return Object.entries(this.quotas) - .filter(([type, value]) => !!value.trim()); + .filter(([, value]) => !!value.trim()); } @computed get quotaOptions() { @@ -201,4 +201,4 @@ export class AddQuotaDialog extends React.Component { ); } -} \ No newline at end of file +} diff --git a/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx b/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx index c8fc913531..38309efac1 100644 --- a/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx +++ b/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx @@ -16,8 +16,6 @@ import { ReplicaSetDetails } from "../+workloads-replicasets"; interface Props extends KubeObjectDetailsProps { } -const onlyNumbers = /$[0-9]*^/g; - function transformUnit(name: string, value: string): number { if (name.includes("memory") || name.includes("storage")) { return unitsToBytes(value); diff --git a/src/renderer/components/+config-resource-quotas/resource-quotas.tsx b/src/renderer/components/+config-resource-quotas/resource-quotas.tsx index 971e606fa8..05bb7c085f 100644 --- a/src/renderer/components/+config-resource-quotas/resource-quotas.tsx +++ b/src/renderer/components/+config-resource-quotas/resource-quotas.tsx @@ -4,13 +4,11 @@ import React from "react"; import { observer } from "mobx-react"; import { Trans } from "@lingui/macro"; import { RouteComponentProps } from "react-router"; -import { KubeObjectMenu, KubeObjectMenuProps } from "../kube-object/kube-object-menu"; import { KubeObjectListLayout } from "../kube-object"; -import { ResourceQuota, resourceQuotaApi } from "../../api/endpoints/resource-quota.api"; +import { ResourceQuota } from "../../api/endpoints/resource-quota.api"; import { AddQuotaDialog } from "./add-quota-dialog"; import { resourceQuotaStore } from "./resource-quotas.store"; import { IResourceQuotaRouteParams } from "./resource-quotas.route"; -import { apiManager } from "../../api/api-manager"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; enum sortBy { @@ -47,7 +45,7 @@ export class ResourceQuotas extends React.Component { ]} renderTableContents={(resourceQuota: ResourceQuota) => [ resourceQuota.getName(), - , + , resourceQuota.getNs(), resourceQuota.getAge(), ]} diff --git a/src/renderer/components/+config-secrets/secrets.tsx b/src/renderer/components/+config-secrets/secrets.tsx index 5149aa1002..2e1c2c0197 100644 --- a/src/renderer/components/+config-secrets/secrets.tsx +++ b/src/renderer/components/+config-secrets/secrets.tsx @@ -4,14 +4,12 @@ import React from "react"; import { observer } from "mobx-react"; import { Trans } from "@lingui/macro"; import { RouteComponentProps } from "react-router"; -import { Secret, secretsApi } from "../../api/endpoints"; -import { KubeObjectMenu, KubeObjectMenuProps } from "../kube-object/kube-object-menu"; +import { Secret } from "../../api/endpoints"; import { AddSecretDialog } from "./add-secret-dialog"; import { ISecretsRouteParams } from "./secrets.route"; import { KubeObjectListLayout } from "../kube-object"; import { Badge } from "../badge"; import { secretsStore } from "./secrets.store"; -import { apiManager } from "../../api/api-manager"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; enum sortBy { @@ -57,7 +55,7 @@ export class Secrets extends React.Component { ]} renderTableContents={(secret: Secret) => [ secret.getName(), - , + , secret.getNs(), secret.getLabels().map(label => ), secret.getKeys().join(", "), diff --git a/src/renderer/components/+custom-resources/crd-details.tsx b/src/renderer/components/+custom-resources/crd-details.tsx index 637a0de1b6..2ab52b2bad 100644 --- a/src/renderer/components/+custom-resources/crd-details.tsx +++ b/src/renderer/components/+custom-resources/crd-details.tsx @@ -4,8 +4,7 @@ import React from "react"; import { Trans } from "@lingui/macro"; import { Link } from "react-router-dom"; import { observer } from "mobx-react"; -import { apiManager } from "../../api/api-manager"; -import { crdApi, CustomResourceDefinition } from "../../api/endpoints/crd.api"; +import { CustomResourceDefinition } from "../../api/endpoints/crd.api"; import { cssNames } from "../../utils"; import { AceEditor } from "../ace-editor"; import { Badge } from "../badge"; diff --git a/src/renderer/components/+custom-resources/crd-list.tsx b/src/renderer/components/+custom-resources/crd-list.tsx index bfad4d501c..1d91a1738b 100644 --- a/src/renderer/components/+custom-resources/crd-list.tsx +++ b/src/renderer/components/+custom-resources/crd-list.tsx @@ -90,19 +90,16 @@ export class CrdList extends React.Component { { title: Scope, className: "scope", sortBy: sortBy.scope }, { title: Age, className: "age", sortBy: sortBy.age }, ]} - renderTableContents={(crd: CustomResourceDefinition) => { - return [ - - {crd.getResourceTitle()} - , - crd.getGroup(), - crd.getVersion(), - crd.getScope(), - crd.getAge(), - ]; - }} + renderTableContents={(crd: CustomResourceDefinition) => [ + + {crd.getResourceTitle()} + , + crd.getGroup(), + crd.getVersion(), + crd.getScope(), + crd.getAge(), + ]} /> ); } } - diff --git a/src/renderer/components/+events/events.tsx b/src/renderer/components/+events/events.tsx index 0a6aab3730..f50f2adcb9 100644 --- a/src/renderer/components/+events/events.tsx +++ b/src/renderer/components/+events/events.tsx @@ -102,7 +102,7 @@ export class Events extends React.Component { }, event.getNs(), kind, - {name}, + {name}, event.getSource(), event.count, event.getAge(), diff --git a/src/renderer/components/+extensions/__tests__/extensions.test.tsx b/src/renderer/components/+extensions/__tests__/extensions.test.tsx index b5a036ad88..f02f157ffb 100644 --- a/src/renderer/components/+extensions/__tests__/extensions.test.tsx +++ b/src/renderer/components/+extensions/__tests__/extensions.test.tsx @@ -1,11 +1,22 @@ import '@testing-library/jest-dom/extend-expect'; -import { fireEvent, render, screen } from '@testing-library/react'; +import { fireEvent, render, screen, waitFor } from '@testing-library/react'; +import fse from "fs-extra"; import React from 'react'; import { extensionDiscovery } from "../../../../extensions/extension-discovery"; import { ConfirmDialog } from "../../confirm-dialog"; import { Notifications } from "../../notifications"; import { Extensions } from "../extensions"; +jest.mock("fs-extra"); + +jest.mock("../../../../common/utils", () => ({ + ...jest.requireActual("../../../../common/utils"), + downloadFile: jest.fn(() => ({ + promise: Promise.resolve() + })), + extractTar: jest.fn(() => Promise.resolve()) +})); + jest.mock("../../../../extensions/extension-discovery", () => ({ ...jest.requireActual("../../../../extensions/extension-discovery"), extensionDiscovery: { @@ -70,10 +81,30 @@ describe("Extensions", () => { // Approve confirm dialog fireEvent.click(screen.getByText("Yes")); - setTimeout(() => { + waitFor(() => { expect(screen.getByText("Disable").closest("button")).not.toBeDisabled(); expect(screen.getByText("Uninstall").closest("button")).not.toBeDisabled(); expect(Notifications.error).toHaveBeenCalledTimes(1); - }, 100); + }); + }); + + it("disables install button while installing", () => { + render(); + + fireEvent.change(screen.getByPlaceholderText("Path or URL to an extension package", { + exact: false + }), { + target: { + value: "https://test.extensionurl/package.tgz" + } + }); + + fireEvent.click(screen.getByText("Install")); + + waitFor(() => { + expect(screen.getByText("Install").closest("button")).toBeDisabled(); + expect(fse.move).toHaveBeenCalledWith(""); + expect(Notifications.error).not.toHaveBeenCalled(); + }); }); }); diff --git a/src/renderer/components/+extensions/extensions.tsx b/src/renderer/components/+extensions/extensions.tsx index b7185725b0..9ed952f1e0 100644 --- a/src/renderer/components/+extensions/extensions.tsx +++ b/src/renderer/components/+extensions/extensions.tsx @@ -42,7 +42,7 @@ interface InstallRequestValidated extends InstallRequestPreloaded { interface ExtensionState { displayName: string; // Possible states the extension can be - state: "uninstalling"; + state: "installing" | "uninstalling"; } @observer @@ -71,19 +71,31 @@ export class Extensions extends React.Component { ).map(([id, extension]) => ({ ...extension, id })); } + /** + * Extensions that were added to extensions but are still in "installing" state + */ + @computed get addedInstalling() { + return Array.from(this.extensionState.entries()).filter(([id, extension]) => + extension.state === "installing" && this.extensions.find(extension => extension.id === id) + ).map(([id, extension]) => ({ ...extension, id })); + } + componentDidMount() { disposeOnUnmount(this, - reaction(() => this.extensions, (extensions) => { - const removedUninstalling = this.removedUninstalling; - - removedUninstalling.forEach(({ displayName }) => { + reaction(() => this.extensions, () => { + this.removedUninstalling.forEach(({ id, displayName }) => { Notifications.ok(

Extension {displayName} successfully uninstalled!

); + this.extensionState.delete(id); }); - removedUninstalling.forEach(({ id }) => { + this.addedInstalling.forEach(({ id, displayName }) => { + Notifications.ok( +

Extension {displayName} successfully installed!

+ ); this.extensionState.delete(id); + this.installPath = ""; }); }) ); @@ -91,6 +103,7 @@ export class Extensions extends React.Component { @computed get extensions() { const searchText = this.search.toLowerCase(); + return Array.from(extensionLoader.userExtensions.values()).filter(ext => { const { name, description } = ext.manifest; return [ @@ -123,6 +136,7 @@ export class Extensions extends React.Component { { name: "tarball", extensions: this.supportedFormats } ] }); + if (!canceled && filePaths.length) { this.requestInstall( filePaths.map(filePath => ({ @@ -137,6 +151,7 @@ export class Extensions extends React.Component { const { installPath } = this; if (!installPath) return; const fileName = path.basename(installPath); + try { // install via url // fixme: improve error messages for non-tar-file URLs @@ -157,7 +172,7 @@ export class Extensions extends React.Component { }; installOnDrop = (files: File[]) => { - logger.info('Install from D&D'); + logger.info("Install from D&D"); return this.requestInstall( files.map(file => ({ fileName: path.basename(file.path), @@ -172,13 +187,13 @@ export class Extensions extends React.Component { await Promise.all( requests .filter(req => !req.data && req.filePath) - .map(req => { - return fse.readFile(req.filePath).then(data => { - req.data = data; - preloadedRequests.push(req); + .map(request => { + return fse.readFile(request.filePath).then(data => { + request.data = data; + preloadedRequests.push(request); }).catch(error => { if (showError) { - Notifications.error(`Error while reading "${req.filePath}": ${String(error)}`); + Notifications.error(`Error while reading "${request.filePath}": ${String(error)}`); } }); }) @@ -198,11 +213,13 @@ export class Extensions extends React.Component { if (!tarFiles.includes(manifestLocation)) { throw new Error(`invalid extension bundle, ${manifestFilename} not found`); } + const manifest = await readFileFromTar({ tarPath: filePath, filePath: manifestLocation, parseJson: true, }); + if (!manifest.lens && !manifest.renderer) { throw new Error(`${manifestFilename} must specify "main" and/or "renderer" fields`); } @@ -214,6 +231,7 @@ export class Extensions extends React.Component { // copy files to temp await fse.ensureDir(this.getExtensionPackageTemp()); + requests.forEach(req => { const tempFile = this.getExtensionPackageTemp(req.fileName); fse.writeFileSync(tempFile, req.data); @@ -225,6 +243,7 @@ export class Extensions extends React.Component { const tempFile = this.getExtensionPackageTemp(req.fileName); try { const manifest = await this.validatePackage(tempFile); + validatedRequests.push({ ...req, manifest, @@ -232,6 +251,7 @@ export class Extensions extends React.Component { }); } catch (error) { fse.unlink(tempFile).catch(() => null); // remove invalid temp package + if (showErrors) { Notifications.error(
@@ -255,6 +275,7 @@ export class Extensions extends React.Component { const { name, version, description } = install.manifest; const extensionFolder = this.getExtensionDestFolder(name); const folderExists = fse.existsSync(extensionFolder); + if (!folderExists) { // auto-install extension if not yet exists this.unpackExtension(install); @@ -280,10 +301,18 @@ export class Extensions extends React.Component { } async unpackExtension({ fileName, tempFile, manifest: { name, version } }: InstallRequestValidated) { - const extName = extensionDisplayName(name, version); - logger.info(`Unpacking extension ${extName}`, { fileName, tempFile }); - const unpackingTempFolder = path.join(path.dirname(tempFile), path.basename(tempFile) + "-unpacked"); + const displayName = extensionDisplayName(name, version); const extensionFolder = this.getExtensionDestFolder(name); + const unpackingTempFolder = path.join(path.dirname(tempFile), path.basename(tempFile) + "-unpacked"); + const extensionId = path.join(extensionDiscovery.nodeModulesPath, name, "package.json"); + + logger.info(`Unpacking extension ${displayName}`, { fileName, tempFile }); + + this.extensionState.set(extensionId, { + state: "installing", + displayName + }); + try { // extract to temp folder first await fse.remove(unpackingTempFolder).catch(Function); @@ -293,20 +322,23 @@ export class Extensions extends React.Component { // move contents to extensions folder const unpackedFiles = await fse.readdir(unpackingTempFolder); let unpackedRootFolder = unpackingTempFolder; + if (unpackedFiles.length === 1) { // check if %extension.tgz was packed with single top folder, // e.g. "npm pack %ext_name" downloads file with "package" root folder within tarball unpackedRootFolder = path.join(unpackingTempFolder, unpackedFiles[0]); } + await fse.ensureDir(extensionFolder); await fse.move(unpackedRootFolder, extensionFolder, { overwrite: true }); - Notifications.ok( -

Extension {extName} successfully installed!

- ); } catch (error) { Notifications.error( -

Installing extension {extName} has failed: {error}

+

Installing extension {displayName} has failed: {error}

); + // Remove install state on install failure + if (this.extensionState.get(extensionId)?.state === "installing") { + this.extensionState.delete(extensionId); + } } finally { // clean up fse.remove(unpackingTempFolder).catch(Function); @@ -340,7 +372,9 @@ export class Extensions extends React.Component {

Uninstalling extension {displayName} has failed: {error?.message ?? ""}

); // Remove uninstall state on uninstall failure - this.extensionState.delete(extension.id); + if (this.extensionState.get(extension.id)?.state === "uninstalling") { + this.extensionState.delete(extension.id); + } } } @@ -394,9 +428,17 @@ export class Extensions extends React.Component { }); } + /** + * True if at least one extension is in installing state + */ + @computed get isInstalling() { + return [...this.extensionState.values()].some(extension => extension.state === "installing"); + } + render() { const topHeader =

Manage Lens Extensions

; - const { installPath, extensions } = this; + const { installPath } = this; + return ( @@ -412,11 +454,12 @@ export class Extensions extends React.Component { this.installPath = v} + onChange={value => this.installPath = value} onSubmit={this.installFromUrlOrPath} iconLeft="link" iconRight={ @@ -432,11 +475,12 @@ export class Extensions extends React.Component {
diff --git a/src/renderer/components/+namespaces/namespaces.tsx b/src/renderer/components/+namespaces/namespaces.tsx index f4bb96aa14..ba1949d9cd 100644 --- a/src/renderer/components/+namespaces/namespaces.tsx +++ b/src/renderer/components/+namespaces/namespaces.tsx @@ -49,7 +49,7 @@ export class Namespaces extends React.Component { ]} renderTableContents={(item: Namespace) => [ item.getName(), - , + , item.getLabels().map(label => ), item.getAge(), { title: item.getStatus(), className: item.getStatus().toLowerCase() }, diff --git a/src/renderer/components/+network-endpoints/endpoint-details.tsx b/src/renderer/components/+network-endpoints/endpoint-details.tsx index df01cf612e..e6730cd520 100644 --- a/src/renderer/components/+network-endpoints/endpoint-details.tsx +++ b/src/renderer/components/+network-endpoints/endpoint-details.tsx @@ -7,7 +7,6 @@ import { DrawerTitle } from "../drawer"; import { KubeEventDetails } from "../+events/kube-event-details"; import { KubeObjectDetailsProps } from "../kube-object"; import { Endpoint } from "../../api/endpoints"; -import { _i18n } from "../../i18n"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { EndpointSubsetList } from "./endpoint-subset-list"; import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; @@ -25,11 +24,9 @@ export class EndpointDetails extends React.Component { Subsets}/> { - endpoint.getEndpointSubsets().map((subset) => { - return( - - ); - }) + endpoint.getEndpointSubsets().map((subset) => ( + + )) }
); diff --git a/src/renderer/components/+network-endpoints/endpoint-subset-list.tsx b/src/renderer/components/+network-endpoints/endpoint-subset-list.tsx index 0c3c5c0436..ae02e8bf29 100644 --- a/src/renderer/components/+network-endpoints/endpoint-subset-list.tsx +++ b/src/renderer/components/+network-endpoints/endpoint-subset-list.tsx @@ -3,8 +3,6 @@ import "./endpoint-subset-list.scss"; import React from "react"; import { observer } from "mobx-react"; import { EndpointSubset, Endpoint, EndpointAddress} from "../../api/endpoints"; -import { _i18n } from "../../i18n"; -import { DrawerItem, DrawerTitle } from "../drawer"; import { Trans } from "@lingui/macro"; import { Table, TableCell, TableHead, TableRow } from "../table"; import { autobind } from "../../utils"; diff --git a/src/renderer/components/+network-endpoints/endpoints.tsx b/src/renderer/components/+network-endpoints/endpoints.tsx index b8862841cb..d1b1880c17 100644 --- a/src/renderer/components/+network-endpoints/endpoints.tsx +++ b/src/renderer/components/+network-endpoints/endpoints.tsx @@ -43,7 +43,7 @@ export class Endpoints extends React.Component { ]} renderTableContents={(endpoint: Endpoint) => [ endpoint.getName(), - , + , endpoint.getNs(), endpoint.toString(), endpoint.getAge(), diff --git a/src/renderer/components/+network-ingresses/ingress-details.tsx b/src/renderer/components/+network-ingresses/ingress-details.tsx index e2d80da651..30d41d5255 100644 --- a/src/renderer/components/+network-ingresses/ingress-details.tsx +++ b/src/renderer/components/+network-ingresses/ingress-details.tsx @@ -100,12 +100,12 @@ export class IngressDetails extends React.Component { const ingressPoints = status?.loadBalancer?.ingress; const { metrics } = ingressStore; const metricTabs = [ - Network, - Duration, + Network, + Duration, ]; const { serviceName, servicePort } = ingress.getServiceNamePort(); - + return (
{ ]} renderTableContents={(ingress: Ingress) => [ ingress.getName(), - , + , ingress.getNs(), ingress.getLoadBalancers().map(lb =>

{lb}

), ingress.getRoutes().map(route =>

{route}

), diff --git a/src/renderer/components/+network-policies/network-policies.tsx b/src/renderer/components/+network-policies/network-policies.tsx index b54b6a80aa..a76845a633 100644 --- a/src/renderer/components/+network-policies/network-policies.tsx +++ b/src/renderer/components/+network-policies/network-policies.tsx @@ -43,7 +43,7 @@ export class NetworkPolicies extends React.Component { ]} renderTableContents={(item: NetworkPolicy) => [ item.getName(), - , + , item.getNs(), item.getTypes().join(", "), item.getAge(), diff --git a/src/renderer/components/+network-services/services.tsx b/src/renderer/components/+network-services/services.tsx index 0aacbb602e..1f3a99a471 100644 --- a/src/renderer/components/+network-services/services.tsx +++ b/src/renderer/components/+network-services/services.tsx @@ -61,7 +61,7 @@ export class Services extends React.Component { ]} renderTableContents={(service: Service) => [ service.getName(), - , + , service.getNs(), service.getType(), service.getClusterIp(), diff --git a/src/renderer/components/+nodes/node-charts.tsx b/src/renderer/components/+nodes/node-charts.tsx index 9f5e6ce6f8..7f43d7c49a 100644 --- a/src/renderer/components/+nodes/node-charts.tsx +++ b/src/renderer/components/+nodes/node-charts.tsx @@ -26,11 +26,9 @@ export const NodeCharts = observer(() => { const [ memoryUsage, memoryRequests, - memoryLimits, memoryCapacity, cpuUsage, cpuRequests, - cpuLimits, cpuCapacity, podUsage, podCapacity, @@ -151,4 +149,4 @@ export const NodeCharts = observer(() => { data={{ datasets: datasets[tabId] }} /> ); -}); \ No newline at end of file +}); diff --git a/src/renderer/components/+nodes/node-details.tsx b/src/renderer/components/+nodes/node-details.tsx index 653fff8d2b..94bf0f66df 100644 --- a/src/renderer/components/+nodes/node-details.tsx +++ b/src/renderer/components/+nodes/node-details.tsx @@ -49,10 +49,10 @@ export class NodeDetails extends React.Component { const childPods = podsStore.getPodsByNode(node.getName()); const metrics = nodesStore.nodeMetrics; const metricTabs = [ - CPU, - Memory, - Disk, - Pods, + CPU, + Memory, + Disk, + Pods, ]; return (
diff --git a/src/renderer/components/+nodes/nodes.tsx b/src/renderer/components/+nodes/nodes.tsx index 82efc4ce92..debdcdc3f9 100644 --- a/src/renderer/components/+nodes/nodes.tsx +++ b/src/renderer/components/+nodes/nodes.tsx @@ -163,7 +163,7 @@ export class Nodes extends React.Component { const tooltipId = `node-taints-${node.getId()}`; return [ node.getName(), - , + , this.renderCpuUsage(node), this.renderMemoryUsage(node), this.renderDiskUsage(node), diff --git a/src/renderer/components/+pod-security-policies/pod-security-policies.tsx b/src/renderer/components/+pod-security-policies/pod-security-policies.tsx index 779a3a75ff..750e37624e 100644 --- a/src/renderer/components/+pod-security-policies/pod-security-policies.tsx +++ b/src/renderer/components/+pod-security-policies/pod-security-policies.tsx @@ -5,7 +5,7 @@ import { observer } from "mobx-react"; import { Trans } from "@lingui/macro"; import { KubeObjectListLayout } from "../kube-object"; import { podSecurityPoliciesStore } from "./pod-security-policies.store"; -import { PodSecurityPolicy, pspApi } from "../../api/endpoints"; +import { PodSecurityPolicy } from "../../api/endpoints"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; enum sortBy { @@ -45,7 +45,7 @@ export class PodSecurityPolicies extends React.Component { renderTableContents={(item: PodSecurityPolicy) => { return [ item.getName(), - , + , item.isPrivileged() ? Yes : No, item.getVolumes().join(", "), item.getAge(), diff --git a/src/renderer/components/+pod-security-policies/pod-security-policy-details.tsx b/src/renderer/components/+pod-security-policies/pod-security-policy-details.tsx index 5e0b812346..9f7e9570fa 100644 --- a/src/renderer/components/+pod-security-policies/pod-security-policy-details.tsx +++ b/src/renderer/components/+pod-security-policies/pod-security-policy-details.tsx @@ -48,9 +48,9 @@ export class PodSecurityPolicyDetails extends React.Component { } const { allowedHostPaths, allowedCapabilities, allowedCSIDrivers, allowedFlexVolumes, allowedProcMountTypes, - allowedUnsafeSysctls, allowPrivilegeEscalation, defaultAddCapabilities, defaultAllowPrivilegeEscalation, - forbiddenSysctls, fsGroup, hostIPC, hostNetwork, hostPID, hostPorts, privileged, readOnlyRootFilesystem, - requiredDropCapabilities, runAsGroup, runAsUser, runtimeClass, seLinux, supplementalGroups, volumes + allowedUnsafeSysctls, allowPrivilegeEscalation, defaultAddCapabilities, forbiddenSysctls, fsGroup, + hostIPC, hostNetwork, hostPID, hostPorts, privileged, readOnlyRootFilesystem, requiredDropCapabilities, + runAsGroup, runAsUser, runtimeClass, seLinux, supplementalGroups, volumes, } = psp.spec; return (
diff --git a/src/renderer/components/+preferences/kubectl-binaries.tsx b/src/renderer/components/+preferences/kubectl-binaries.tsx index 118298c561..b865a2e794 100644 --- a/src/renderer/components/+preferences/kubectl-binaries.tsx +++ b/src/renderer/components/+preferences/kubectl-binaries.tsx @@ -1,12 +1,12 @@ -import React, { useState } from 'react'; -import { Trans } from '@lingui/macro'; -import { Checkbox } from '../checkbox'; -import { Input, InputValidators } from '../input'; -import { SubTitle } from '../layout/sub-title'; -import { UserPreferences, userStore } from '../../../common/user-store'; -import { observer } from 'mobx-react'; -import { bundledKubectlPath } from '../../../main/kubectl'; -import { SelectOption, Select } from '../select'; +import React, { useState } from "react"; +import { Trans } from "@lingui/macro"; +import { Checkbox } from "../checkbox"; +import { Input, InputValidators } from "../input"; +import { SubTitle } from "../layout/sub-title"; +import { UserPreferences, userStore } from "../../../common/user-store"; +import { observer } from "mobx-react"; +import { bundledKubectlPath } from "../../../main/kubectl"; +import { SelectOption, Select } from "../select"; export const KubectlBinaries = observer(({ preferences }: { preferences: UserPreferences }) => { const [downloadPath, setDownloadPath] = useState(preferences.downloadBinariesPath || ""); diff --git a/src/renderer/components/+storage-classes/storage-classes.tsx b/src/renderer/components/+storage-classes/storage-classes.tsx index b4133c8918..d074a5f754 100644 --- a/src/renderer/components/+storage-classes/storage-classes.tsx +++ b/src/renderer/components/+storage-classes/storage-classes.tsx @@ -4,7 +4,7 @@ import React from "react"; import { RouteComponentProps } from "react-router-dom"; import { observer } from "mobx-react"; import { Trans } from "@lingui/macro"; -import { StorageClass, storageClassApi } from "../../api/endpoints/storage-class.api"; +import { StorageClass } from "../../api/endpoints/storage-class.api"; import { KubeObjectListLayout } from "../kube-object"; import { IStorageClassesRouteParams } from "./storage-classes.route"; import { storageClassStore } from "./storage-class.store"; @@ -48,7 +48,7 @@ export class StorageClasses extends React.Component { ]} renderTableContents={(storageClass: StorageClass) => [ storageClass.getName(), - , + , storageClass.provisioner, storageClass.getReclaimPolicy(), storageClass.isDefault() ? Yes : null, diff --git a/src/renderer/components/+storage-volume-claims/volume-claim-details.tsx b/src/renderer/components/+storage-volume-claims/volume-claim-details.tsx index 5df839c979..f0e642b6f4 100644 --- a/src/renderer/components/+storage-volume-claims/volume-claim-details.tsx +++ b/src/renderer/components/+storage-volume-claims/volume-claim-details.tsx @@ -42,7 +42,7 @@ export class PersistentVolumeClaimDetails extends React.Component { const { metrics } = volumeClaimStore; const pods = volumeClaim.getPods(podsStore.items); const metricTabs = [ - Disk + Disk ]; return (
diff --git a/src/renderer/components/+storage-volume-claims/volume-claims.tsx b/src/renderer/components/+storage-volume-claims/volume-claims.tsx index 84e8b9dd92..301dcd01dc 100644 --- a/src/renderer/components/+storage-volume-claims/volume-claims.tsx +++ b/src/renderer/components/+storage-volume-claims/volume-claims.tsx @@ -68,9 +68,9 @@ export class PersistentVolumeClaims extends React.Component { })); return [ pvc.getName(), - , + , pvc.getNs(), - + {storageClassName} , pvc.getStorage(), diff --git a/src/renderer/components/+storage-volumes/volumes.tsx b/src/renderer/components/+storage-volumes/volumes.tsx index d67a9a9b09..57797a474e 100644 --- a/src/renderer/components/+storage-volumes/volumes.tsx +++ b/src/renderer/components/+storage-volumes/volumes.tsx @@ -59,8 +59,8 @@ export class PersistentVolumes extends React.Component { })); return [ volume.getName(), - , - + , + {storageClassName} , volume.getCapacity(), diff --git a/src/renderer/components/+storage/storage.tsx b/src/renderer/components/+storage/storage.tsx index 97bd014760..3d0403056c 100644 --- a/src/renderer/components/+storage/storage.tsx +++ b/src/renderer/components/+storage/storage.tsx @@ -23,7 +23,7 @@ export class Storage extends React.Component { routePath: volumeClaimsRoute.path.toString(), }); - if (isAllowedResource('persistentvolumes')) { + if (isAllowedResource("persistentvolumes")) { tabRoutes.push({ title: Persistent Volumes, component: PersistentVolumes, @@ -32,7 +32,7 @@ export class Storage extends React.Component { }); } - if (isAllowedResource('storageclasses')) { + if (isAllowedResource("storageclasses")) { tabRoutes.push({ title: Storage Classes, component: StorageClasses, diff --git a/src/renderer/components/+user-management-roles-bindings/role-binding-details.tsx b/src/renderer/components/+user-management-roles-bindings/role-binding-details.tsx index 178aada344..b4534105da 100644 --- a/src/renderer/components/+user-management-roles-bindings/role-binding-details.tsx +++ b/src/renderer/components/+user-management-roles-bindings/role-binding-details.tsx @@ -27,7 +27,7 @@ export class RoleBindingDetails extends React.Component { async componentDidMount() { disposeOnUnmount(this, [ - reaction(() => this.props.object, (obj) => { + reaction(() => this.props.object, () => { this.selectedSubjects.clear(); }) ]); diff --git a/src/renderer/components/+user-management-roles-bindings/role-bindings.tsx b/src/renderer/components/+user-management-roles-bindings/role-bindings.tsx index 7d9352e3bf..0844d2406a 100644 --- a/src/renderer/components/+user-management-roles-bindings/role-bindings.tsx +++ b/src/renderer/components/+user-management-roles-bindings/role-bindings.tsx @@ -48,7 +48,7 @@ export class RoleBindings extends React.Component { ]} renderTableContents={(binding: RoleBinding) => [ binding.getName(), - , + , binding.getSubjectNames(), binding.getNs() || "-", binding.getAge(), diff --git a/src/renderer/components/+user-management-roles/roles.tsx b/src/renderer/components/+user-management-roles/roles.tsx index 015ec2d630..6b8959f021 100644 --- a/src/renderer/components/+user-management-roles/roles.tsx +++ b/src/renderer/components/+user-management-roles/roles.tsx @@ -45,7 +45,7 @@ export class Roles extends React.Component { ]} renderTableContents={(role: Role) => [ role.getName(), - , + , role.getNs() || "-", role.getAge(), ]} diff --git a/src/renderer/components/+user-management-service-accounts/service-accounts-details.tsx b/src/renderer/components/+user-management-service-accounts/service-accounts-details.tsx index 70aea97d00..c5c61a5016 100644 --- a/src/renderer/components/+user-management-service-accounts/service-accounts-details.tsx +++ b/src/renderer/components/+user-management-service-accounts/service-accounts-details.tsx @@ -39,7 +39,7 @@ export class ServiceAccountsDetails extends React.Component { }); this.secrets = await Promise.all(secrets); const imagePullSecrets = serviceAccount.getImagePullSecrets().map(async({ name }) => { - return secretsStore.load({ name, namespace }).catch(_err => { return this.generateDummySecretObject(name); }); + return secretsStore.load({ name, namespace }).catch(() => this.generateDummySecretObject(name)); }); this.imagePullSecrets = await Promise.all(imagePullSecrets); }); diff --git a/src/renderer/components/+user-management-service-accounts/service-accounts.tsx b/src/renderer/components/+user-management-service-accounts/service-accounts.tsx index d612dd2376..fbf1747384 100644 --- a/src/renderer/components/+user-management-service-accounts/service-accounts.tsx +++ b/src/renderer/components/+user-management-service-accounts/service-accounts.tsx @@ -49,7 +49,7 @@ export class ServiceAccounts extends React.Component { ]} renderTableContents={(account: ServiceAccount) => [ account.getName(), - , + , account.getNs(), account.getAge(), ]} diff --git a/src/renderer/components/+workloads-cronjobs/cronjob-trigger-dialog.tsx b/src/renderer/components/+workloads-cronjobs/cronjob-trigger-dialog.tsx index 5dda5989ae..69235df25f 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjob-trigger-dialog.tsx +++ b/src/renderer/components/+workloads-cronjobs/cronjob-trigger-dialog.tsx @@ -6,7 +6,7 @@ import { observer } from "mobx-react"; import { Trans } from "@lingui/macro"; import { Dialog, DialogProps } from "../dialog"; import { Wizard, WizardStep } from "../wizard"; -import { CronJob, cronJobApi, jobApi, Job } from "../../api/endpoints"; +import { CronJob, cronJobApi, jobApi } from "../../api/endpoints"; import { Notifications } from "../notifications"; import { cssNames } from "../../utils"; import { Input } from "../input"; diff --git a/src/renderer/components/+workloads-cronjobs/cronjobs.tsx b/src/renderer/components/+workloads-cronjobs/cronjobs.tsx index b5cf6d328f..57fd04eb86 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjobs.tsx +++ b/src/renderer/components/+workloads-cronjobs/cronjobs.tsx @@ -62,7 +62,7 @@ export class CronJobs extends React.Component { ]} renderTableContents={(cronJob: CronJob) => [ cronJob.getName(), - , + , cronJob.getNs(), cronJob.isNeverRun() ? never : cronJob.getSchedule(), cronJob.getSuspendFlag(), diff --git a/src/renderer/components/+workloads-daemonsets/daemonsets.tsx b/src/renderer/components/+workloads-daemonsets/daemonsets.tsx index a087d8a267..fb3bbbde27 100644 --- a/src/renderer/components/+workloads-daemonsets/daemonsets.tsx +++ b/src/renderer/components/+workloads-daemonsets/daemonsets.tsx @@ -64,7 +64,7 @@ export class DaemonSets extends React.Component { daemonSet.getName(), daemonSet.getNs(), this.getPodsLength(daemonSet), - , + , this.renderNodeSelector(daemonSet), daemonSet.getAge(), ]} @@ -72,4 +72,3 @@ export class DaemonSets extends React.Component { ); } } - diff --git a/src/renderer/components/+workloads-deployments/deployment-details.tsx b/src/renderer/components/+workloads-deployments/deployment-details.tsx index 0c5f4f8548..cb97e0f22c 100644 --- a/src/renderer/components/+workloads-deployments/deployment-details.tsx +++ b/src/renderer/components/+workloads-deployments/deployment-details.tsx @@ -6,7 +6,7 @@ import { disposeOnUnmount, observer } from "mobx-react"; import { t, Trans } from "@lingui/macro"; import { DrawerItem } from "../drawer"; import { Badge } from "../badge"; -import { Deployment, deploymentApi } from "../../api/endpoints"; +import { Deployment } from "../../api/endpoints"; import { cssNames } from "../../utils"; import { PodDetailsTolerations } from "../+workloads-pods/pod-details-tolerations"; import { PodDetailsAffinities } from "../+workloads-pods/pod-details-affinities"; diff --git a/src/renderer/components/+workloads-deployments/deployment-scale-dialog.test.tsx b/src/renderer/components/+workloads-deployments/deployment-scale-dialog.test.tsx index 00aaef161e..8a1ade6353 100644 --- a/src/renderer/components/+workloads-deployments/deployment-scale-dialog.test.tsx +++ b/src/renderer/components/+workloads-deployments/deployment-scale-dialog.test.tsx @@ -1,54 +1,54 @@ -import React from 'react'; -import { render, waitFor, fireEvent } from '@testing-library/react'; -import '@testing-library/jest-dom/extend-expect'; +import React from "react"; +import { render, waitFor, fireEvent } from "@testing-library/react"; +import "@testing-library/jest-dom/extend-expect"; import { DeploymentScaleDialog } from "./deployment-scale-dialog"; jest.mock("../../api/endpoints"); import { deploymentApi } from "../../api/endpoints"; const dummyDeployment = { - apiVersion: 'v1', - kind: 'dummy', + apiVersion: "v1", + kind: "dummy", metadata: { - uid: 'dummy', - name: 'dummy', - creationTimestamp: 'dummy', - resourceVersion: 'dummy', - selfLink: 'link', + uid: "dummy", + name: "dummy", + creationTimestamp: "dummy", + resourceVersion: "dummy", + selfLink: "link", }, - selfLink: 'link', + selfLink: "link", spec: { replicas: 1, - selector: { matchLabels: { dummy: 'label' } }, + selector: { matchLabels: { dummy: "label" } }, template: { metadata: { - labels: { dummy: 'label' }, + labels: { dummy: "label" }, }, spec: { containers: [{ - name: 'dummy', - image: 'dummy', + name: "dummy", + image: "dummy", resources: { requests: { - cpu: '1', - memory: '10Mi', + cpu: "1", + memory: "10Mi", }, }, - terminationMessagePath: 'dummy', - terminationMessagePolicy: 'dummy', - imagePullPolicy: 'dummy', + terminationMessagePath: "dummy", + terminationMessagePolicy: "dummy", + imagePullPolicy: "dummy", }], - restartPolicy: 'dummy', + restartPolicy: "dummy", terminationGracePeriodSeconds: 10, - dnsPolicy: 'dummy', - serviceAccountName: 'dummy', - serviceAccount: 'dummy', + dnsPolicy: "dummy", + serviceAccountName: "dummy", + serviceAccount: "dummy", securityContext: {}, - schedulerName: 'dummy', + schedulerName: "dummy", }, }, strategy: { - type: 'dummy', + type: "dummy", rollingUpdate: { maxUnavailable: 1, maxSurge: 10, @@ -61,12 +61,12 @@ const dummyDeployment = { updatedReplicas: 1, readyReplicas: 1, conditions: [{ - type: 'dummy', - status: 'dummy', - lastUpdateTime: 'dummy', - lastTransitionTime: 'dummy', - reason: 'dummy', - message: 'dummy', + type: "dummy", + status: "dummy", + lastUpdateTime: "dummy", + lastTransitionTime: "dummy", + reason: "dummy", + message: "dummy", }], }, getConditions: jest.fn(), @@ -93,14 +93,14 @@ const dummyDeployment = { delete: jest.fn(), }; -describe('', () => { +describe("", () => { - it('renders w/o errors', () => { + it("renders w/o errors", () => { const { container } = render(); expect(container).toBeInstanceOf(HTMLElement); }); - it('inits with a dummy deployment with mocked current/desired scale', async () => { + it("inits with a dummy deployment with mocked current/desired scale", async () => { // mock deploymentApi.getReplicas() which will be called // when rendered. const initReplicas = 3; @@ -111,8 +111,8 @@ describe('', () => { // because there is an in which renders null at start. await waitFor(async () => { const [currentScale, desiredScale] = await Promise.all([ - getByTestId('current-scale'), - getByTestId('desired-scale'), + getByTestId("current-scale"), + getByTestId("desired-scale"), ]); expect(currentScale).toHaveTextContent(`${initReplicas}`); expect(desiredScale).toHaveTextContent(`${initReplicas}`); @@ -120,31 +120,31 @@ describe('', () => { }); - it('changes the desired scale when clicking the icon buttons +/-', async () => { + it("changes the desired scale when clicking the icon buttons +/-", async () => { const initReplicas = 1; deploymentApi.getReplicas = jest.fn().mockImplementationOnce(async () => initReplicas); const { getByTestId } = render(); DeploymentScaleDialog.open(dummyDeployment); await waitFor(async () => { - const desiredScale = await getByTestId('desired-scale'); + const desiredScale = await getByTestId("desired-scale"); expect(desiredScale).toHaveTextContent(`${initReplicas}`); }); - const up = await getByTestId('desired-replicas-up'); - const down = await getByTestId('desired-replicas-down'); + const up = await getByTestId("desired-replicas-up"); + const down = await getByTestId("desired-replicas-down"); fireEvent.click(up); - expect(await getByTestId('desired-scale')).toHaveTextContent(`${initReplicas + 1}`); + expect(await getByTestId("desired-scale")).toHaveTextContent(`${initReplicas + 1}`); fireEvent.click(down); - expect(await getByTestId('desired-scale')).toHaveTextContent('1'); + expect(await getByTestId("desired-scale")).toHaveTextContent("1"); // edge case, desiredScale must > 0 fireEvent.click(down); fireEvent.click(down); - expect(await getByTestId('desired-scale')).toHaveTextContent('1'); + expect(await getByTestId("desired-scale")).toHaveTextContent("1"); const times = 120; // edge case, desiredScale must < scaleMax (100) for (let i = 0; i < times; i++) { fireEvent.click(up); } - expect(await getByTestId('desired-scale')).toHaveTextContent('100'); + expect(await getByTestId("desired-scale")).toHaveTextContent("100"); }); }); diff --git a/src/renderer/components/+workloads-deployments/deployments.tsx b/src/renderer/components/+workloads-deployments/deployments.tsx index bb0fd59a3c..d8e9021c22 100644 --- a/src/renderer/components/+workloads-deployments/deployments.tsx +++ b/src/renderer/components/+workloads-deployments/deployments.tsx @@ -80,7 +80,7 @@ export class Deployments extends React.Component { ]} renderTableContents={(deployment: Deployment) => [ deployment.getName(), - , + , deployment.getNs(), this.renderPods(deployment), deployment.getReplicas(), diff --git a/src/renderer/components/+workloads-jobs/jobs.tsx b/src/renderer/components/+workloads-jobs/jobs.tsx index 2f6a83fea0..81dc8d1024 100644 --- a/src/renderer/components/+workloads-jobs/jobs.tsx +++ b/src/renderer/components/+workloads-jobs/jobs.tsx @@ -54,7 +54,7 @@ export class Jobs extends React.Component { job.getName(), job.getNs(), `${job.getCompletions()} / ${job.getDesiredCompletions()}`, - , + , job.getAge(), condition && { title: condition.type, diff --git a/src/renderer/components/+workloads-overview/overview-statuses.tsx b/src/renderer/components/+workloads-overview/overview-statuses.tsx index 0bdfad1030..3e84c31de5 100644 --- a/src/renderer/components/+workloads-overview/overview-statuses.tsx +++ b/src/renderer/components/+workloads-overview/overview-statuses.tsx @@ -12,7 +12,6 @@ import { NamespaceSelectFilter } from "../+namespaces/namespace-select"; import { isAllowedResource, KubeResource } from "../../../common/rbac"; import { ResourceNames } from "../../../renderer/utils/rbac"; import { autobind } from "../../utils"; -import { _i18n } from "../../i18n"; const resources: KubeResource[] = [ "pods", diff --git a/src/renderer/components/+workloads-overview/overview-workload-status.tsx b/src/renderer/components/+workloads-overview/overview-workload-status.tsx index 127fce2778..352083fcc4 100644 --- a/src/renderer/components/+workloads-overview/overview-workload-status.tsx +++ b/src/renderer/components/+workloads-overview/overview-workload-status.tsx @@ -2,14 +2,18 @@ import "./overview-workload-status.scss"; import React from "react"; import capitalize from "lodash/capitalize"; -import { findDOMNode } from 'react-dom'; +import { findDOMNode } from "react-dom"; import { observable } from "mobx"; import { observer } from "mobx-react"; import { PieChart } from "../chart"; import { cssVar } from "../../utils"; -import { ChartData } from "chart.js"; +import { ChartData, ChartDataSets } from "chart.js"; import { themeStore } from "../../theme.store"; +interface SimpleChartDataSets extends ChartDataSets { + backgroundColor?: string[]; +} + interface Props { status: { [key: string]: number; @@ -21,6 +25,7 @@ export class OverviewWorkloadStatus extends React.Component { @observable elem: HTMLElement; componentDidMount() { + // eslint-disable-next-line react/no-find-dom-node this.elem = findDOMNode(this) as HTMLElement; } @@ -40,8 +45,8 @@ export class OverviewWorkloadStatus extends React.Component { label: "Empty" }] }; - if (statuses.some(([key, val]) => val > 0)) { - const dataset: any = { + if (statuses.some(([, val]) => val > 0)) { + const dataset: SimpleChartDataSets = { data: [], backgroundColor: [], label: "Status", diff --git a/src/renderer/components/+workloads-pods/pod-charts.tsx b/src/renderer/components/+workloads-pods/pod-charts.tsx index 40b2c072ed..fd1dda2524 100644 --- a/src/renderer/components/+workloads-pods/pod-charts.tsx +++ b/src/renderer/components/+workloads-pods/pod-charts.tsx @@ -11,10 +11,10 @@ import { WorkloadKubeObject } from "../../api/workload-kube-object"; import { themeStore } from "../../theme.store"; export const podMetricTabs = [ - CPU, - Memory, - Network, - Filesystem, + CPU, + Memory, + Network, + Filesystem, ]; type IContext = IResourceMetricsValue; @@ -128,4 +128,4 @@ export const PodCharts = observer(() => { data={{ datasets: datasets[tabId] }} /> ); -}); \ No newline at end of file +}); diff --git a/src/renderer/components/+workloads-pods/pod-container-env.tsx b/src/renderer/components/+workloads-pods/pod-container-env.tsx index 62b48cd44d..13c751e530 100644 --- a/src/renderer/components/+workloads-pods/pod-container-env.tsx +++ b/src/renderer/components/+workloads-pods/pod-container-env.tsx @@ -40,7 +40,7 @@ export const ContainerEnvironment = observer((props: Props) => { ); const renderEnv = () => { - const orderedEnv = _.sortBy(env, 'name'); + const orderedEnv = _.sortBy(env, "name"); return orderedEnv.map(variable => { const { name, value, valueFrom } = variable; diff --git a/src/renderer/components/+workloads-pods/pod-container-port.tsx b/src/renderer/components/+workloads-pods/pod-container-port.tsx index f9e3c0b37c..505cfe355e 100644 --- a/src/renderer/components/+workloads-pods/pod-container-port.tsx +++ b/src/renderer/components/+workloads-pods/pod-container-port.tsx @@ -3,7 +3,7 @@ import "./pod-container-port.scss"; import React from "react"; import { observer } from "mobx-react"; import { t } from "@lingui/macro"; -import { Pod, IPodContainer } from "../../api/endpoints"; +import { Pod } from "../../api/endpoints"; import { _i18n } from "../../i18n"; import { apiBase } from "../../api"; import { observable } from "mobx"; @@ -39,7 +39,7 @@ export class PodContainerPort extends React.Component { render() { const { port } = this.props; const { name, containerPort, protocol } = port; - const text = (name ? name + ': ' : '')+`${containerPort}/${protocol}`; + const text = (name ? name + ": " : "")+`${containerPort}/${protocol}`; return (
this.portForward() }> diff --git a/src/renderer/components/+workloads-pods/pod-details-container.tsx b/src/renderer/components/+workloads-pods/pod-details-container.tsx index 52ed7571bd..58b99d3e8a 100644 --- a/src/renderer/components/+workloads-pods/pod-details-container.tsx +++ b/src/renderer/components/+workloads-pods/pod-details-container.tsx @@ -21,27 +21,27 @@ interface Props { } export class PodDetailsContainer extends React.Component { - + renderStatus(state: string, status: IPodContainerStatus) { const ready = status ? status.ready : ""; return ( {state}{ready ? `, ${_i18n._(t`ready`)}` : ""} - {state === 'terminated' ? ` - ${status.state.terminated.reason} (${_i18n._(t`exit code`)}: ${status.state.terminated.exitCode})` : ''} - + {state === "terminated" ? ` - ${status.state.terminated.reason} (${_i18n._(t`exit code`)}: ${status.state.terminated.exitCode})` : ""} + ); } renderLastState(lastState: string, status: IPodContainerStatus) { - if (lastState === 'terminated') { + if (lastState === "terminated") { return ( - {lastState}
- {_i18n._(t`Reason`)}: {status.lastState.terminated.reason} - {_i18n._(t`exit code`)}: {status.lastState.terminated.exitCode}
- {_i18n._(t`Started at`)}: {status.lastState.terminated.startedAt}
- {_i18n._(t`Finished at`)}: {status.lastState.terminated.finishedAt}
+ {lastState}
+ {_i18n._(t`Reason`)}: {status.lastState.terminated.reason} - {_i18n._(t`exit code`)}: {status.lastState.terminated.exitCode}
+ {_i18n._(t`Started at`)}: {status.lastState.terminated.startedAt}
+ {_i18n._(t`Finished at`)}: {status.lastState.terminated.finishedAt}
- ); + ); } } @@ -57,9 +57,9 @@ export class PodDetailsContainer extends React.Component { const readiness = pod.getReadinessProbe(container); const isInitContainer = !!pod.getInitContainers().find(c => c.name == name); const metricTabs = [ - CPU, - Memory, - Filesystem, + CPU, + Memory, + Filesystem, ]; return (
@@ -110,7 +110,7 @@ export class PodDetailsContainer extends React.Component { return ( {mountPath} - from {name} ({readOnly ? 'ro' : 'rw'}) + from {name} ({readOnly ? "ro" : "rw"}) ); }) @@ -137,16 +137,16 @@ export class PodDetailsContainer extends React.Component { } {command && Command}> - {command.join(' ')} + {command.join(" ")} } {args && Arguments}> - {args.join(' ')} + {args.join(" ")} }
); } -} \ No newline at end of file +} diff --git a/src/renderer/components/+workloads-pods/pod-details-list.tsx b/src/renderer/components/+workloads-pods/pod-details-list.tsx index 111562d06a..494f6de7c2 100644 --- a/src/renderer/components/+workloads-pods/pod-details-list.tsx +++ b/src/renderer/components/+workloads-pods/pod-details-list.tsx @@ -107,7 +107,7 @@ export class PodDetailsList extends React.Component { onClick={prevDefault(() => showDetails(pod.selfLink, false))} > {pod.getName()} - + {pod.getNs()} {this.renderCpuUsage(`cpu-${pod.getId()}`, metrics.cpu)} {this.renderMemoryUsage(`memory-${pod.getId()}`, metrics.memory)} diff --git a/src/renderer/components/+workloads-pods/pods.tsx b/src/renderer/components/+workloads-pods/pods.tsx index c72197bc09..ee1ef16a65 100644 --- a/src/renderer/components/+workloads-pods/pods.tsx +++ b/src/renderer/components/+workloads-pods/pods.tsx @@ -102,7 +102,7 @@ export class Pods extends React.Component { ]} renderTableContents={(pod: Pod) => [ pod.getName(), - , + , pod.getNs(), this.renderContainersStatus(pod), pod.getRestartsCount(), diff --git a/src/renderer/components/+workloads-replicasets/replicasets.tsx b/src/renderer/components/+workloads-replicasets/replicasets.tsx index 41e8d9a0a9..98c0a0a8e7 100644 --- a/src/renderer/components/+workloads-replicasets/replicasets.tsx +++ b/src/renderer/components/+workloads-replicasets/replicasets.tsx @@ -3,7 +3,7 @@ import "./replicasets.scss"; import React from "react"; import { observer } from "mobx-react"; import { Trans } from "@lingui/macro"; -import { ReplicaSet, replicaSetApi } from "../../api/endpoints"; +import { ReplicaSet } from "../../api/endpoints"; import { KubeObjectMenu, KubeObjectMenuProps } from "../kube-object/kube-object-menu"; import { replicaSetStore } from "./replicasets.store"; import { Spinner } from "../spinner"; @@ -11,7 +11,6 @@ import { prevDefault, stopPropagation } from "../../utils"; import { DrawerTitle } from "../drawer"; import { Table, TableCell, TableHead, TableRow } from "../table"; import { showDetails } from "../../navigation"; -import { apiManager } from "../../api/api-manager"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; enum sortBy { @@ -73,7 +72,7 @@ export class ReplicaSets extends React.Component { onClick={prevDefault(() => showDetails(replica.selfLink, false))} > {replica.getName()} - + {replica.getNs()} {this.getPodsLength(replica)} {replica.getAge()} diff --git a/src/renderer/components/+workloads-statefulsets/statefulset-scale-dialog.test.tsx b/src/renderer/components/+workloads-statefulsets/statefulset-scale-dialog.test.tsx index 7a7f484cbe..0f1a7940e5 100755 --- a/src/renderer/components/+workloads-statefulsets/statefulset-scale-dialog.test.tsx +++ b/src/renderer/components/+workloads-statefulsets/statefulset-scale-dialog.test.tsx @@ -1,65 +1,65 @@ -import '@testing-library/jest-dom/extend-expect'; +import "@testing-library/jest-dom/extend-expect"; jest.mock("../../api/endpoints"); import { statefulSetApi } from "../../api/endpoints"; import { StatefulSetScaleDialog } from "./statefulset-scale-dialog"; -import { render, waitFor, fireEvent } from '@testing-library/react'; -import React from 'react'; +import { render, waitFor, fireEvent } from "@testing-library/react"; +import React from "react"; const dummyStatefulSet = { - apiVersion: 'v1', - kind: 'dummy', + apiVersion: "v1", + kind: "dummy", metadata: { - uid: 'dummy', - name: 'dummy', - creationTimestamp: 'dummy', - resourceVersion: 'dummy', - selfLink: 'link', + uid: "dummy", + name: "dummy", + creationTimestamp: "dummy", + resourceVersion: "dummy", + selfLink: "link", }, - selfLink: 'link', + selfLink: "link", spec: { - serviceName: 'dummy', + serviceName: "dummy", replicas: 1, selector: { - matchLabels: { 'label': 'label' } + matchLabels: { "label": "label" } }, template: { metadata: { labels: { - app: 'app', + app: "app", }, }, spec: { containers: [{ - name: 'dummy', - image: 'dummy', + name: "dummy", + image: "dummy", ports: [{ containerPort: 1234, - name: 'dummy', + name: "dummy", }], volumeMounts: [{ - name: 'dummy', - mountPath: 'dummy', + name: "dummy", + mountPath: "dummy", }], }], tolerations: [{ - key: 'dummy', - operator: 'dummy', - effect: 'dummy', + key: "dummy", + operator: "dummy", + effect: "dummy", tolerationSeconds: 1, }], }, }, volumeClaimTemplates: [{ metadata: { - name: 'dummy', + name: "dummy", }, spec: { - accessModes: ['dummy'], + accessModes: ["dummy"], resources: { requests: { - storage: 'dummy', + storage: "dummy", }, }, }, @@ -70,8 +70,8 @@ const dummyStatefulSet = { replicas: 1, currentReplicas: 1, readyReplicas: 1, - currentRevision: 'dummy', - updateRevision: 'dummy', + currentRevision: "dummy", + updateRevision: "dummy", collisionCount: 1, }, @@ -98,13 +98,13 @@ const dummyStatefulSet = { delete: jest.fn(), }; -describe('', () => { - it('renders w/o errors', () => { +describe("", () => { + it("renders w/o errors", () => { const { container } = render(); expect(container).toBeInstanceOf(HTMLElement); }); - it('init with a dummy stateful set and mocked current/desired scale', async () => { + it("init with a dummy stateful set and mocked current/desired scale", async () => { // mock statefulSetApi.getReplicas() which will be called // when rendered. const initReplicas = 1; @@ -115,53 +115,53 @@ describe('', () => { // because there is an in which renders null at start. await waitFor(async () => { const [currentScale, desiredScale] = await Promise.all([ - getByTestId('current-scale'), - getByTestId('desired-scale'), + getByTestId("current-scale"), + getByTestId("desired-scale"), ]); expect(currentScale).toHaveTextContent(`${initReplicas}`); expect(desiredScale).toHaveTextContent(`${initReplicas}`); }); }); - it('changes the desired scale when clicking the icon buttons +/-', async () => { + it("changes the desired scale when clicking the icon buttons +/-", async () => { const initReplicas = 1; statefulSetApi.getReplicas = jest.fn().mockImplementationOnce(async () => initReplicas); const component = render(); StatefulSetScaleDialog.open(dummyStatefulSet); await waitFor(async () => { - expect(await component.findByTestId('desired-scale')).toHaveTextContent(`${initReplicas}`); - expect(await component.findByTestId('current-scale')).toHaveTextContent(`${initReplicas}`); - expect((await component.baseElement.querySelector('input').value)).toBe(`${initReplicas}`); + expect(await component.findByTestId("desired-scale")).toHaveTextContent(`${initReplicas}`); + expect(await component.findByTestId("current-scale")).toHaveTextContent(`${initReplicas}`); + expect((await component.baseElement.querySelector("input").value)).toBe(`${initReplicas}`); }); - const up = await component.findByTestId('desired-replicas-up'); - const down = await component.findByTestId('desired-replicas-down'); + const up = await component.findByTestId("desired-replicas-up"); + const down = await component.findByTestId("desired-replicas-down"); fireEvent.click(up); - expect(await component.findByTestId('desired-scale')).toHaveTextContent(`${initReplicas + 1}`); - expect(await component.findByTestId('current-scale')).toHaveTextContent(`${initReplicas}`); - expect((await component.baseElement.querySelector('input').value)).toBe(`${initReplicas + 1}`); + expect(await component.findByTestId("desired-scale")).toHaveTextContent(`${initReplicas + 1}`); + expect(await component.findByTestId("current-scale")).toHaveTextContent(`${initReplicas}`); + expect((await component.baseElement.querySelector("input").value)).toBe(`${initReplicas + 1}`); fireEvent.click(down); - expect(await component.findByTestId('desired-scale')).toHaveTextContent(`${initReplicas}`); - expect(await component.findByTestId('current-scale')).toHaveTextContent(`${initReplicas}`); - expect((await component.baseElement.querySelector('input').value)).toBe(`${initReplicas}`); + expect(await component.findByTestId("desired-scale")).toHaveTextContent(`${initReplicas}`); + expect(await component.findByTestId("current-scale")).toHaveTextContent(`${initReplicas}`); + expect((await component.baseElement.querySelector("input").value)).toBe(`${initReplicas}`); // edge case, desiredScale must >= 0 let times = 10; for (let i = 0; i < times; i++) { fireEvent.click(down); } - expect(await component.findByTestId('desired-scale')).toHaveTextContent('0'); - expect((await component.baseElement.querySelector('input').value)).toBe('0'); + expect(await component.findByTestId("desired-scale")).toHaveTextContent("0"); + expect((await component.baseElement.querySelector("input").value)).toBe("0"); // edge case, desiredScale must <= scaleMax (100) times = 120; for (let i = 0; i < times; i++) { fireEvent.click(up); } - expect(await component.findByTestId('desired-scale')).toHaveTextContent('100'); - expect((component.baseElement.querySelector("input").value)).toBe('100'); - expect(await component.findByTestId('warning')) - .toHaveTextContent('High number of replicas may cause cluster performance issues'); + expect(await component.findByTestId("desired-scale")).toHaveTextContent("100"); + expect((component.baseElement.querySelector("input").value)).toBe("100"); + expect(await component.findByTestId("warning")) + .toHaveTextContent("High number of replicas may cause cluster performance issues"); }); }); diff --git a/src/renderer/components/+workloads-statefulsets/statefulsets.tsx b/src/renderer/components/+workloads-statefulsets/statefulsets.tsx index 7bd4ea35ff..cf0eb77f4a 100644 --- a/src/renderer/components/+workloads-statefulsets/statefulsets.tsx +++ b/src/renderer/components/+workloads-statefulsets/statefulsets.tsx @@ -4,7 +4,7 @@ import React from "react"; import { observer } from "mobx-react"; import { RouteComponentProps } from "react-router"; import { t, Trans } from "@lingui/macro"; -import { StatefulSet, statefulSetApi } from "../../api/endpoints"; +import { StatefulSet } from "../../api/endpoints"; import { podsStore } from "../+workloads-pods/pods.store"; import { statefulSetStore } from "./statefulset.store"; import { nodesStore } from "../+nodes/nodes.store"; @@ -64,7 +64,7 @@ export class StatefulSets extends React.Component { statefulSet.getNs(), this.renderPods(statefulSet), statefulSet.getReplicas(), - , + , statefulSet.getAge(), ]} renderItemMenu={(item: StatefulSet) => { diff --git a/src/renderer/components/+workspaces/workspaces.tsx b/src/renderer/components/+workspaces/workspaces.tsx index 0f1d600137..ccffcca3b7 100644 --- a/src/renderer/components/+workspaces/workspaces.tsx +++ b/src/renderer/components/+workspaces/workspaces.tsx @@ -107,7 +107,7 @@ export class Workspaces extends React.Component { }; onInputKeypress = (evt: React.KeyboardEvent, workspaceId: WorkspaceId) => { - if (evt.key == 'Enter') { + if (evt.key == "Enter") { // Trigget input validation evt.currentTarget.blur(); evt.currentTarget.focus(); diff --git a/src/renderer/components/animate/index.ts b/src/renderer/components/animate/index.ts index a4e4547423..080c5446c8 100644 --- a/src/renderer/components/animate/index.ts +++ b/src/renderer/components/animate/index.ts @@ -1 +1 @@ -export * from './animate'; \ No newline at end of file +export * from "./animate"; \ No newline at end of file diff --git a/src/renderer/components/app.tsx b/src/renderer/components/app.tsx index 59b95f776c..1a4cb5393b 100755 --- a/src/renderer/components/app.tsx +++ b/src/renderer/components/app.tsx @@ -34,11 +34,11 @@ import { Terminal } from "./dock/terminal"; import { getHostedCluster, getHostedClusterId } from "../../common/cluster-store"; import logger from "../../main/logger"; import { webFrame } from "electron"; -import { clusterPageRegistry, getExtensionPageUrl, PageRegistration, RegisteredPage } from "../../extensions/registries/page-registry"; +import { clusterPageRegistry, getExtensionPageUrl } from "../../extensions/registries/page-registry"; import { extensionLoader } from "../../extensions/extension-loader"; import { appEventBus } from "../../common/event-bus"; import { broadcastMessage, requestMain } from "../../common/ipc"; -import whatInput from 'what-input'; +import whatInput from "what-input"; import { clusterSetFrameIdHandler } from "../../common/cluster-ipc"; import { ClusterPageMenuRegistration, clusterPageMenuRegistry } from "../../extensions/registries"; import { TabLayoutRoute, TabLayout } from "./layout/tab-layout"; diff --git a/src/renderer/components/button/button.tsx b/src/renderer/components/button/button.tsx index ee73195509..fb1a767c83 100644 --- a/src/renderer/components/button/button.tsx +++ b/src/renderer/components/button/button.tsx @@ -28,7 +28,7 @@ export class Button extends React.PureComponent { const btnProps = props as Partial; if (hidden) return null; - btnProps.className = cssNames('Button', className, { + btnProps.className = cssNames("Button", className, { waiting, primary, accent, plain, active, big, round, outlined }); diff --git a/src/renderer/components/button/index.ts b/src/renderer/components/button/index.ts index eaf5eea7f1..98d55acde6 100644 --- a/src/renderer/components/button/index.ts +++ b/src/renderer/components/button/index.ts @@ -1 +1 @@ -export * from './button'; +export * from "./button"; diff --git a/src/renderer/components/chart/chart.tsx b/src/renderer/components/chart/chart.tsx index 5de0c9cf44..0ed3ddb540 100644 --- a/src/renderer/components/chart/chart.tsx +++ b/src/renderer/components/chart/chart.tsx @@ -1,7 +1,7 @@ import "./chart.scss"; import React from "react"; import ChartJS from "chart.js"; -import { isEqual, remove } from "lodash"; +import { remove } from "lodash"; import { cssNames } from "../../utils"; import { StatusBrick } from "../status-brick"; import { Badge } from "../badge"; diff --git a/src/renderer/components/checkbox/checkbox.tsx b/src/renderer/components/checkbox/checkbox.tsx index 2efa6adc6f..becbf996f0 100644 --- a/src/renderer/components/checkbox/checkbox.tsx +++ b/src/renderer/components/checkbox/checkbox.tsx @@ -1,5 +1,5 @@ -import './checkbox.scss'; -import React from 'react'; +import "./checkbox.scss"; +import React from "react"; import { autobind, cssNames } from "../../utils"; export interface CheckboxProps { @@ -29,7 +29,7 @@ export class Checkbox extends React.PureComponent { render() { const { label, inline, className, value, theme, children, ...inputProps } = this.props; - const componentClass = cssNames('Checkbox flex', className, { + const componentClass = cssNames("Checkbox flex", className, { inline, checked: value, disabled: this.props.disabled, diff --git a/src/renderer/components/checkbox/index.ts b/src/renderer/components/checkbox/index.ts index 7d2e810506..7af8873e06 100644 --- a/src/renderer/components/checkbox/index.ts +++ b/src/renderer/components/checkbox/index.ts @@ -1 +1 @@ -export * from './checkbox'; \ No newline at end of file +export * from "./checkbox"; \ No newline at end of file diff --git a/src/renderer/components/clipboard/clipboard.tsx b/src/renderer/components/clipboard/clipboard.tsx index 77543ea8f4..b04b7a5332 100644 --- a/src/renderer/components/clipboard/clipboard.tsx +++ b/src/renderer/components/clipboard/clipboard.tsx @@ -25,6 +25,7 @@ export class Clipboard extends React.Component { static defaultProps = defaultProps as object; get rootElem(): HTMLElement { + // eslint-disable-next-line react/no-find-dom-node return findDOMNode(this) as HTMLElement; } @@ -59,4 +60,4 @@ export class Clipboard extends React.Component { return this.rootReactElem; } } -} \ No newline at end of file +} diff --git a/src/renderer/components/cluster-icon/cluster-icon.tsx b/src/renderer/components/cluster-icon/cluster-icon.tsx index 8ee7c79aaf..cd85f8fb81 100644 --- a/src/renderer/components/cluster-icon/cluster-icon.tsx +++ b/src/renderer/components/cluster-icon/cluster-icon.tsx @@ -8,10 +8,8 @@ import { Cluster } from "../../../main/cluster"; import { cssNames, IClassName } from "../../utils"; import { Badge } from "../badge"; import { Tooltip } from "../tooltip"; -import { eventStore } from "../+events/event.store"; -import { forCluster } from "../../api/kube-api"; -import { subscribeToBroadcast, unsubscribeAllFromBroadcast } from "../../../common/ipc"; -import { observable, when } from "mobx"; +import { subscribeToBroadcast } from "../../../common/ipc"; +import { observable } from "mobx"; interface Props extends DOMAttributes { cluster: Cluster; diff --git a/src/renderer/components/confirm-dialog/index.ts b/src/renderer/components/confirm-dialog/index.ts index 2c2bf03c63..dfcd83ded3 100644 --- a/src/renderer/components/confirm-dialog/index.ts +++ b/src/renderer/components/confirm-dialog/index.ts @@ -1 +1 @@ -export * from './confirm-dialog'; \ No newline at end of file +export * from "./confirm-dialog"; \ No newline at end of file diff --git a/src/renderer/components/dialog/dialog.tsx b/src/renderer/components/dialog/dialog.tsx index 7b08ab6e5d..571ce3c1d1 100644 --- a/src/renderer/components/dialog/dialog.tsx +++ b/src/renderer/components/dialog/dialog.tsx @@ -49,6 +49,7 @@ export class Dialog extends React.PureComponent { }; get elem() { + // eslint-disable-next-line react/no-find-dom-node return findDOMNode(this) as HTMLElement; } @@ -91,17 +92,17 @@ export class Dialog extends React.PureComponent { onOpen = () => { this.props.onOpen(); if (!this.props.pinned) { - if (this.elem) this.elem.addEventListener('click', this.onClickOutside); + if (this.elem) this.elem.addEventListener("click", this.onClickOutside); // Using document.body target to handle keydown event before Drawer does - document.body.addEventListener('keydown', this.onEscapeKey); + document.body.addEventListener("keydown", this.onEscapeKey); } }; onClose = () => { this.props.onClose(); if (!this.props.pinned) { - if (this.elem) this.elem.removeEventListener('click', this.onClickOutside); - document.body.removeEventListener('keydown', this.onEscapeKey); + if (this.elem) this.elem.removeEventListener("click", this.onClickOutside); + document.body.removeEventListener("keydown", this.onEscapeKey); } }; diff --git a/src/renderer/components/dialog/index.ts b/src/renderer/components/dialog/index.ts index 20da8e550a..e5c2874810 100644 --- a/src/renderer/components/dialog/index.ts +++ b/src/renderer/components/dialog/index.ts @@ -1 +1 @@ -export * from './dialog'; +export * from "./dialog"; diff --git a/src/renderer/components/dock/dock.tsx b/src/renderer/components/dock/dock.tsx index 112a02b09b..dfdd792750 100644 --- a/src/renderer/components/dock/dock.tsx +++ b/src/renderer/components/dock/dock.tsx @@ -106,8 +106,9 @@ export class Dock extends React.Component { autoFocus={isOpen} className="dock-tabs" value={selectedTab} onChange={this.onChangeTab} - children={tabs.map(tab => {this.renderTab(tab)})} - /> + > + {tabs.map(tab => {this.renderTab(tab)})} +
New tab }} closeOnScroll={false}> diff --git a/src/renderer/components/dock/edit-resource.store.ts b/src/renderer/components/dock/edit-resource.store.ts index 8ae0dee2c5..b54dc3dbef 100644 --- a/src/renderer/components/dock/edit-resource.store.ts +++ b/src/renderer/components/dock/edit-resource.store.ts @@ -47,7 +47,7 @@ export class EditResourceStore extends DockTabStore { } getTabByResource(object: KubeObject): IDockTab { - const [tabId] = Array.from(this.data).find(([tabId, { resource }]) => { + const [tabId] = Array.from(this.data).find(([, { resource }]) => { return object.selfLink === resource; }) || []; return dockStore.getTabById(tabId); @@ -87,4 +87,4 @@ export function editResourceTab(object: KubeObject, tabParams: Partial export function isEditResourceTab(tab: IDockTab) { return tab && tab.kind === TabKind.EDIT_RESOURCE; -} \ No newline at end of file +} diff --git a/src/renderer/components/dock/install-chart.store.ts b/src/renderer/components/dock/install-chart.store.ts index 68c129f12a..860c795c60 100644 --- a/src/renderer/components/dock/install-chart.store.ts +++ b/src/renderer/components/dock/install-chart.store.ts @@ -60,17 +60,15 @@ export class InstallChartStore extends DockTabStore { } @action - async loadValues(tabId: TabId) { + async loadValues(tabId: TabId, attempt = 0): Promise { const data = this.getData(tabId); const { repo, name, version } = data; - // This loop is for "retrying" the "getValues" call - for (const _ of Array(3)) { - const values = await helmChartsApi.getValues(repo, name, version); - if (values) { - this.setData(tabId, { ...data, values }); - return; - } + const values = await helmChartsApi.getValues(repo, name, version); + if (values) { + this.setData(tabId, { ...data, values }); + } else if (attempt < 4) { + return this.loadValues(tabId, attempt + 1); } } } diff --git a/src/renderer/components/dock/pod-logs.tsx b/src/renderer/components/dock/pod-logs.tsx index 71579be112..49aa156f7c 100644 --- a/src/renderer/components/dock/pod-logs.tsx +++ b/src/renderer/components/dock/pod-logs.tsx @@ -56,7 +56,7 @@ export class PodLogs extends React.Component { * @param query {string} A text from search field */ @autobind() - onSearch(query: string) { + onSearch() { this.toOverlay(); } diff --git a/src/renderer/components/drawer/drawer.tsx b/src/renderer/components/drawer/drawer.tsx index 0c425c1624..de4003990e 100644 --- a/src/renderer/components/drawer/drawer.tsx +++ b/src/renderer/components/drawer/drawer.tsx @@ -80,7 +80,7 @@ export class Drawer extends React.Component { return; } const clickedElem = evt.target as HTMLElement; - const isOutsideAnyDrawer = !clickedElem.closest('.Drawer'); + const isOutsideAnyDrawer = !clickedElem.closest(".Drawer"); if (isOutsideAnyDrawer) { close(); } diff --git a/src/renderer/components/error-boundary/error-boundary.tsx b/src/renderer/components/error-boundary/error-boundary.tsx index 87a214ff67..77708a281c 100644 --- a/src/renderer/components/error-boundary/error-boundary.tsx +++ b/src/renderer/components/error-boundary/error-boundary.tsx @@ -38,8 +38,8 @@ export class ErrorBoundary extends React.Component { render() { const { error, errorInfo } = this.state; if (error) { - const slackLink = Slack; - const githubLink = Github; + const slackLink = Slack; + const githubLink = Github; const pageUrl = location.href; return (
diff --git a/src/renderer/components/icon/icon.tsx b/src/renderer/components/icon/icon.tsx index bc7534d167..d8786181a3 100644 --- a/src/renderer/components/icon/icon.tsx +++ b/src/renderer/components/icon/icon.tsx @@ -1,9 +1,9 @@ -import './icon.scss'; +import "./icon.scss"; import React, { ReactNode } from "react"; import { findDOMNode } from "react-dom"; import { NavLink } from "react-router-dom"; -import { LocationDescriptor } from 'history'; +import { LocationDescriptor } from "history"; import { autobind, cssNames } from "../../utils"; import { TooltipDecoratorProps, withTooltip } from "../tooltip"; import isNumber from "lodash/isNumber"; @@ -49,11 +49,13 @@ export class Icon extends React.PureComponent { onKeyDown(evt: React.KeyboardEvent) { switch (evt.nativeEvent.code) { case "Space": - case "Enter": + case "Enter": { + // eslint-disable-next-line react/no-find-dom-node const icon = findDOMNode(this) as HTMLElement; setTimeout(() => icon.click()); evt.preventDefault(); break; + } } if (this.props.onKeyDown) { this.props.onKeyDown(evt); diff --git a/src/renderer/components/input/index.ts b/src/renderer/components/input/index.ts index 2e807d0be6..10379450e5 100644 --- a/src/renderer/components/input/index.ts +++ b/src/renderer/components/input/index.ts @@ -1,5 +1,5 @@ -export * from './input'; -export * from './search-input'; -export * from './search-input-url'; -export * from './file-input'; -export * from './drop-file-input'; +export * from "./input"; +export * from "./search-input"; +export * from "./search-input-url"; +export * from "./file-input"; +export * from "./drop-file-input"; diff --git a/src/renderer/components/input/input_validators.ts b/src/renderer/components/input/input_validators.ts index ea2cf4d4a8..e315127509 100644 --- a/src/renderer/components/input/input_validators.ts +++ b/src/renderer/components/input/input_validators.ts @@ -1,7 +1,7 @@ import type { InputProps } from "./input"; import { ReactNode } from "react"; import { t } from "@lingui/macro"; -import { _i18n } from '../../i18n'; +import { _i18n } from "../../i18n"; import fse from "fs-extra"; export interface InputValidator { diff --git a/src/renderer/components/kube-object/kube-object-meta.tsx b/src/renderer/components/kube-object/kube-object-meta.tsx index 0aae32ad04..51bce3e233 100644 --- a/src/renderer/components/kube-object/kube-object-meta.tsx +++ b/src/renderer/components/kube-object/kube-object-meta.tsx @@ -37,7 +37,7 @@ export class KubeObjectMeta extends React.Component { {getAge(true, false)} ago ({creationTimestamp}) Name} hidden={this.isHidden("name")}> - {getName()} + {getName()} Namespace} hidden={this.isHidden("namespace") || !getNs()}> {getNs()} diff --git a/src/renderer/components/layout/login-layout.tsx b/src/renderer/components/layout/login-layout.tsx index 7aa4b32089..8eb44827a2 100755 --- a/src/renderer/components/layout/login-layout.tsx +++ b/src/renderer/components/layout/login-layout.tsx @@ -16,7 +16,7 @@ export class LoginLayout extends React.Component { render() { const { className, header, title, footer, children } = this.props; return ( -
+
{header}
diff --git a/src/renderer/components/layout/page-layout.tsx b/src/renderer/components/layout/page-layout.tsx index c99ef6bf84..876969c7f0 100644 --- a/src/renderer/components/layout/page-layout.tsx +++ b/src/renderer/components/layout/page-layout.tsx @@ -36,11 +36,11 @@ export class PageLayout extends React.Component { } async componentDidMount() { - window.addEventListener('keydown', this.onEscapeKey); + window.addEventListener("keydown", this.onEscapeKey); } componentWillUnmount() { - window.removeEventListener('keydown', this.onEscapeKey); + window.removeEventListener("keydown", this.onEscapeKey); } onEscapeKey = (evt: KeyboardEvent) => { diff --git a/src/renderer/components/layout/sidebar.tsx b/src/renderer/components/layout/sidebar.tsx index 32e55bebc4..5306e2f22a 100644 --- a/src/renderer/components/layout/sidebar.tsx +++ b/src/renderer/components/layout/sidebar.tsx @@ -26,10 +26,10 @@ import { Network } from "../+network"; import { crdStore } from "../+custom-resources/crd.store"; import { CrdList, crdResourcesRoute, crdRoute, crdURL } from "../+custom-resources"; import { CustomResources } from "../+custom-resources/custom-resources"; -import { isActiveRoute, navigation } from "../../navigation"; +import { isActiveRoute } from "../../navigation"; import { isAllowedResource } from "../../../common/rbac"; import { Spinner } from "../spinner"; -import { ClusterPageMenuRegistration, clusterPageMenuRegistry, clusterPageRegistry, getExtensionPageUrl, RegisteredPage } from "../../../extensions/registries"; +import { ClusterPageMenuRegistration, clusterPageMenuRegistry, clusterPageRegistry, getExtensionPageUrl } from "../../../extensions/registries"; const SidebarContext = React.createContext({ pinned: false }); type SidebarContextValue = { @@ -102,16 +102,13 @@ export class Sidebar extends React.Component { const registeredPage = clusterPageRegistry.getByPageMenuTarget(menuItem.target); const tabRoutes = this.getTabLayoutRoutes(menuItem); let pageUrl: string; - let routePath: string; let isActive = false; if (registeredPage) { const { extensionId, id: pageId } = registeredPage; pageUrl = getExtensionPageUrl({ extensionId, pageId, params: menuItem.target.params }); - routePath = registeredPage.routePath; isActive = isActiveRoute(registeredPage.routePath); } else if (tabRoutes.length > 0) { pageUrl = tabRoutes[0].url; - routePath = tabRoutes[0].routePath; isActive = isActiveRoute(tabRoutes.map((tab) => tab.routePath)); } else { return; diff --git a/src/renderer/components/line-progress/index.ts b/src/renderer/components/line-progress/index.ts index 449fa2c9b8..91942d706a 100644 --- a/src/renderer/components/line-progress/index.ts +++ b/src/renderer/components/line-progress/index.ts @@ -1 +1 @@ -export * from './line-progress'; \ No newline at end of file +export * from "./line-progress"; \ No newline at end of file diff --git a/src/renderer/components/markdown-viewer/markdown-viewer.tsx b/src/renderer/components/markdown-viewer/markdown-viewer.tsx index b50e4e2c16..5eef34cb5f 100644 --- a/src/renderer/components/markdown-viewer/markdown-viewer.tsx +++ b/src/renderer/components/markdown-viewer/markdown-viewer.tsx @@ -7,10 +7,10 @@ import marked from "marked"; import DOMPurify from "dompurify"; import { cssNames } from "../../utils"; -DOMPurify.addHook('afterSanitizeAttributes', function (node) { +DOMPurify.addHook("afterSanitizeAttributes", function (node) { // Set all elements owning target to target=_blank - if ('target' in node as any as HTMLElement) { - node.setAttribute('target', '_blank'); + if ("target" in node as any as HTMLElement) { + node.setAttribute("target", "_blank"); } }); diff --git a/src/renderer/components/menu/index.ts b/src/renderer/components/menu/index.ts index d3ef6f3401..2b3d873c64 100644 --- a/src/renderer/components/menu/index.ts +++ b/src/renderer/components/menu/index.ts @@ -1,2 +1,2 @@ -export * from './menu'; -export * from './menu-actions'; +export * from "./menu"; +export * from "./menu-actions"; diff --git a/src/renderer/components/menu/menu.tsx b/src/renderer/components/menu/menu.tsx index f9869726c7..3d453392f1 100644 --- a/src/renderer/components/menu/menu.tsx +++ b/src/renderer/components/menu/menu.tsx @@ -1,4 +1,4 @@ -import './menu.scss'; +import "./menu.scss"; import React, { Fragment, ReactElement, ReactNode } from "react"; import { createPortal } from "react-dom"; @@ -64,30 +64,30 @@ export class Menu extends React.Component { if (!this.props.usePortal) { const parent = this.elem.parentElement; const position = window.getComputedStyle(parent).position; - if (position === 'static') parent.style.position = 'relative'; + if (position === "static") parent.style.position = "relative"; } else if (this.isOpen) { this.refreshPosition(); } this.opener = document.getElementById(this.props.htmlFor); // might not exist in sub-menus if (this.opener) { - this.opener.addEventListener('click', this.toggle); - this.opener.addEventListener('keydown', this.onKeyDown); + this.opener.addEventListener("click", this.toggle); + this.opener.addEventListener("keydown", this.onKeyDown); } - this.elem.addEventListener('keydown', this.onKeyDown); - window.addEventListener('resize', this.onWindowResize); - window.addEventListener('click', this.onClickOutside, true); - window.addEventListener('scroll', this.onScrollOutside, true); + this.elem.addEventListener("keydown", this.onKeyDown); + window.addEventListener("resize", this.onWindowResize); + window.addEventListener("click", this.onClickOutside, true); + window.addEventListener("scroll", this.onScrollOutside, true); } componentWillUnmount() { if (this.opener) { - this.opener.removeEventListener('click', this.toggle); - this.opener.removeEventListener('keydown', this.onKeyDown); + this.opener.removeEventListener("click", this.toggle); + this.opener.removeEventListener("keydown", this.onKeyDown); } - this.elem.removeEventListener('keydown', this.onKeyDown); - window.removeEventListener('resize', this.onWindowResize); - window.removeEventListener('click', this.onClickOutside, true); - window.removeEventListener('scroll', this.onScrollOutside, true); + this.elem.removeEventListener("keydown", this.onKeyDown); + window.removeEventListener("resize", this.onWindowResize); + window.removeEventListener("click", this.onClickOutside, true); + window.removeEventListener("scroll", this.onScrollOutside, true); } protected get focusableItems() { @@ -188,7 +188,7 @@ export class Menu extends React.Component { } } - onWindowResize(evt: UIEvent) { + onWindowResize() { if (!this.isOpen) return; this.refreshPosition(); } @@ -224,7 +224,7 @@ export class Menu extends React.Component { render() { const { position, id } = this.props; let { className, usePortal } = this.props; - className = cssNames('Menu', className, this.state.position || position, { + className = cssNames("Menu", className, this.state.position || position, { portal: usePortal, }); diff --git a/src/renderer/components/notifications/index.ts b/src/renderer/components/notifications/index.ts index 1141b374e0..1fd49bd26a 100644 --- a/src/renderer/components/notifications/index.ts +++ b/src/renderer/components/notifications/index.ts @@ -1,2 +1,2 @@ -export * from './notifications'; -export * from './notifications.store'; +export * from "./notifications"; +export * from "./notifications.store"; diff --git a/src/renderer/components/notifications/notifications.tsx b/src/renderer/components/notifications/notifications.tsx index 4d9f7ef6f3..d9569edde3 100644 --- a/src/renderer/components/notifications/notifications.tsx +++ b/src/renderer/components/notifications/notifications.tsx @@ -1,6 +1,6 @@ -import './notifications.scss'; +import "./notifications.scss"; -import React from 'react'; +import React from "react"; import { reaction } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; import { JsonApiErrorParsed } from "../../api/json-api"; diff --git a/src/renderer/components/radio/radio.tsx b/src/renderer/components/radio/radio.tsx index 671248ba0c..849eb68f37 100644 --- a/src/renderer/components/radio/radio.tsx +++ b/src/renderer/components/radio/radio.tsx @@ -65,7 +65,7 @@ export class Radio extends React.Component { render() { const { className, label, checked, children, ...inputProps } = this.props; - const componentClass = cssNames('Radio flex align-center', className, { + const componentClass = cssNames("Radio flex align-center", className, { checked, disabled: this.props.disabled, }); diff --git a/src/renderer/components/resizing-anchor/index.ts b/src/renderer/components/resizing-anchor/index.ts index d99b33186b..b5d4b857eb 100644 --- a/src/renderer/components/resizing-anchor/index.ts +++ b/src/renderer/components/resizing-anchor/index.ts @@ -1 +1 @@ -export * from './resizing-anchor'; +export * from "./resizing-anchor"; diff --git a/src/renderer/components/resizing-anchor/resizing-anchor.tsx b/src/renderer/components/resizing-anchor/resizing-anchor.tsx index e481c89bd3..c7e4fae3ec 100644 --- a/src/renderer/components/resizing-anchor/resizing-anchor.tsx +++ b/src/renderer/components/resizing-anchor/resizing-anchor.tsx @@ -2,7 +2,6 @@ import "./resizing-anchor.scss"; import React from "react"; import { action, observable } from "mobx"; import _ from "lodash"; -import { findDOMNode } from "react-dom"; import { cssNames, noop } from "../../utils"; export enum ResizeDirection { @@ -262,7 +261,7 @@ export class ResizingAnchor extends React.PureComponent { }, 100); @action - onDragEnd = (_event: MouseEvent) => { + onDragEnd = () => { this.props.onEnd(); document.removeEventListener("mousemove", this.onDrag); document.removeEventListener("mouseup", this.onDragEnd); diff --git a/src/renderer/components/select/index.ts b/src/renderer/components/select/index.ts index c7396734d3..e1856bb30b 100644 --- a/src/renderer/components/select/index.ts +++ b/src/renderer/components/select/index.ts @@ -1 +1 @@ -export * from './select'; +export * from "./select"; diff --git a/src/renderer/components/spinner/cube-spinner.tsx b/src/renderer/components/spinner/cube-spinner.tsx index 054b8fb77f..adcab8a804 100644 --- a/src/renderer/components/spinner/cube-spinner.tsx +++ b/src/renderer/components/spinner/cube-spinner.tsx @@ -1,5 +1,5 @@ -import './cube-spinner.scss'; -import React from 'react'; +import "./cube-spinner.scss"; +import React from "react"; import { cssNames } from "../../utils"; export interface CubeSpinnerProps { diff --git a/src/renderer/components/spinner/index.ts b/src/renderer/components/spinner/index.ts index ce2d8a3a8c..6647cfde95 100644 --- a/src/renderer/components/spinner/index.ts +++ b/src/renderer/components/spinner/index.ts @@ -1,2 +1,2 @@ -export * from './spinner'; -export * from './cube-spinner'; +export * from "./spinner"; +export * from "./cube-spinner"; diff --git a/src/renderer/components/spinner/spinner.tsx b/src/renderer/components/spinner/spinner.tsx index 3e14ae51c9..9708221252 100644 --- a/src/renderer/components/spinner/spinner.tsx +++ b/src/renderer/components/spinner/spinner.tsx @@ -1,6 +1,6 @@ -import './spinner.scss'; +import "./spinner.scss"; -import React from 'react'; +import React from "react"; import { cssNames } from "../../utils"; export interface SpinnerProps extends React.HTMLProps { @@ -17,7 +17,7 @@ export class Spinner extends React.Component { render() { const { center, singleColor, centerHorizontal, className, ...props } = this.props; - const classNames = cssNames('Spinner', className, { singleColor, center, centerHorizontal }); + const classNames = cssNames("Spinner", className, { singleColor, center, centerHorizontal }); return
; } diff --git a/src/renderer/components/status-brick/index.ts b/src/renderer/components/status-brick/index.ts index 656a9a594b..e16a2a8093 100644 --- a/src/renderer/components/status-brick/index.ts +++ b/src/renderer/components/status-brick/index.ts @@ -1 +1 @@ -export * from './status-brick'; \ No newline at end of file +export * from "./status-brick"; \ No newline at end of file diff --git a/src/renderer/components/stepper/index.ts b/src/renderer/components/stepper/index.ts index ef1c3dd027..586feefec2 100644 --- a/src/renderer/components/stepper/index.ts +++ b/src/renderer/components/stepper/index.ts @@ -1 +1 @@ -export * from './stepper'; +export * from "./stepper"; diff --git a/src/renderer/components/stepper/stepper.tsx b/src/renderer/components/stepper/stepper.tsx index 8641934668..e92e48941d 100644 --- a/src/renderer/components/stepper/stepper.tsx +++ b/src/renderer/components/stepper/stepper.tsx @@ -18,7 +18,7 @@ export class Stepper extends React.Component { let { step } = this.props; step = Math.min(Math.max(1, step), stepsCount); return ( -
+
{steps.map(({ title }, i) => { const stepNumber = i + 1; const isLast = i === stepsCount - 1; diff --git a/src/renderer/components/table/index.ts b/src/renderer/components/table/index.ts index cc7647bed8..39a8424b03 100644 --- a/src/renderer/components/table/index.ts +++ b/src/renderer/components/table/index.ts @@ -1,5 +1,5 @@ -export * from './table'; -export * from './table-head'; -export * from './table-row'; -export * from './table-cell'; +export * from "./table"; +export * from "./table-head"; +export * from "./table-row"; +export * from "./table-cell"; diff --git a/src/renderer/components/tabs/index.ts b/src/renderer/components/tabs/index.ts index c2d1b4e91b..811d3d4a72 100644 --- a/src/renderer/components/tabs/index.ts +++ b/src/renderer/components/tabs/index.ts @@ -1 +1 @@ -export * from './tabs'; +export * from "./tabs"; diff --git a/src/renderer/components/tooltip/index.ts b/src/renderer/components/tooltip/index.ts index 049ceda2a6..52b3b6c1d5 100644 --- a/src/renderer/components/tooltip/index.ts +++ b/src/renderer/components/tooltip/index.ts @@ -1,2 +1,2 @@ -export * from './tooltip'; -export * from './withTooltip'; +export * from "./tooltip"; +export * from "./withTooltip"; diff --git a/src/renderer/components/tooltip/tooltip.tsx b/src/renderer/components/tooltip/tooltip.tsx index 75173bfdc4..daa996eb73 100644 --- a/src/renderer/components/tooltip/tooltip.tsx +++ b/src/renderer/components/tooltip/tooltip.tsx @@ -1,4 +1,4 @@ -import './tooltip.scss'; +import "./tooltip.scss"; import React from "react"; import { createPortal } from "react-dom"; @@ -74,13 +74,13 @@ export class Tooltip extends React.Component { } @autobind() - protected onEnterTarget(evt: MouseEvent) { + protected onEnterTarget() { this.isVisible = true; this.refreshPosition(); } @autobind() - protected onLeaveTarget(evt: MouseEvent) { + protected onLeaveTarget() { this.isVisible = false; } diff --git a/src/renderer/components/virtual-list/virtual-list.tsx b/src/renderer/components/virtual-list/virtual-list.tsx index ed63a7a5ab..16dc4a59a7 100644 --- a/src/renderer/components/virtual-list/virtual-list.tsx +++ b/src/renderer/components/virtual-list/virtual-list.tsx @@ -106,9 +106,10 @@ export class VirtualList extends Component { overscanCount={overscanCount} ref={this.listRef} outerRef={outerRef} - children={Row} onScroll={onScroll} - /> + > + {Row} +
); } @@ -133,4 +134,4 @@ const Row = observer((props: RowProps) => { return React.cloneElement(row, { style: Object.assign({}, row.props.style, style) }); -}); \ No newline at end of file +}); diff --git a/src/renderer/components/wizard/index.ts b/src/renderer/components/wizard/index.ts index c2aab1f543..b217e311a9 100644 --- a/src/renderer/components/wizard/index.ts +++ b/src/renderer/components/wizard/index.ts @@ -1 +1 @@ -export * from './wizard'; \ No newline at end of file +export * from "./wizard"; \ No newline at end of file diff --git a/src/renderer/i18n.ts b/src/renderer/i18n.ts index a55d2b7da1..b753d58efe 100644 --- a/src/renderer/i18n.ts +++ b/src/renderer/i18n.ts @@ -4,7 +4,7 @@ import { setupI18n } from "@lingui/core"; import orderBy from "lodash/orderBy"; import { autobind, createStorage } from "./utils"; -const plurals: Record = require('make-plural/plurals'); // eslint-disable-line @typescript-eslint/no-var-requires +const plurals: Record = require("make-plural/plurals"); // eslint-disable-line @typescript-eslint/no-var-requires export interface ILanguage { code: string; diff --git a/src/renderer/item.store.ts b/src/renderer/item.store.ts index a8ba236c58..4adabd7297 100644 --- a/src/renderer/item.store.ts +++ b/src/renderer/item.store.ts @@ -155,6 +155,7 @@ export abstract class ItemStore { async removeSelectedItems?(): Promise; + // eslint-disable-next-line unused-imports/no-unused-vars-ts subscribe(...args: any[]) { return noop; } diff --git a/src/renderer/lens-app.tsx b/src/renderer/lens-app.tsx index 78533e4f5b..bdf0875fca 100644 --- a/src/renderer/lens-app.tsx +++ b/src/renderer/lens-app.tsx @@ -1,6 +1,5 @@ import "../common/system-ca"; import React from "react"; -import { ipcRenderer } from "electron"; import { Route, Router, Switch } from "react-router"; import { observer } from "mobx-react"; import { userStore } from "../common/user-store"; diff --git a/src/renderer/navigation.ts b/src/renderer/navigation.ts index eee1f5dfaa..7089fd7dd3 100644 --- a/src/renderer/navigation.ts +++ b/src/renderer/navigation.ts @@ -1,6 +1,5 @@ // Navigation helpers -import { ipcRenderer } from "electron"; import { matchPath, RouteProps } from "react-router"; import { reaction } from "mobx"; import { createObservableHistory } from "mobx-observable-history"; diff --git a/src/renderer/utils/convertMemory.ts b/src/renderer/utils/convertMemory.ts index eb714d3142..8227e87e84 100644 --- a/src/renderer/utils/convertMemory.ts +++ b/src/renderer/utils/convertMemory.ts @@ -1,14 +1,14 @@ // Helper to convert memory from units Ki, Mi, Gi, Ti, Pi to bytes and vise versa const base = 1024; -const suffixes = ['K', 'M', 'G', 'T', 'P', 'E']; // Equivalents: Ki, Mi, Gi, Ti, Pi, Ei +const suffixes = ["K", "M", "G", "T", "P", "E"]; // Equivalents: Ki, Mi, Gi, Ti, Pi, Ei export function unitsToBytes(value: string) { if (!suffixes.some(suffix => value.includes(suffix))) { return parseFloat(value); } - const suffix = value.replace(/[0-9]|i|\./g, ''); + const suffix = value.replace(/[0-9]|i|\./g, ""); const index = suffixes.indexOf(suffix); return parseInt( (parseFloat(value) * Math.pow(base, index + 1)).toFixed(1) diff --git a/src/renderer/utils/cssNames.ts b/src/renderer/utils/cssNames.ts index 711c021f33..38d25da963 100755 --- a/src/renderer/utils/cssNames.ts +++ b/src/renderer/utils/cssNames.ts @@ -16,7 +16,7 @@ export function cssNames(...args: IClassName[]): string { } }); return Object.entries(map) - .filter(([className, isActive]) => !!isActive) + .filter(([, isActive]) => !!isActive) .map(([className]) => className.trim()) - .join(' '); + .join(" "); } diff --git a/src/renderer/utils/formatDuration.ts b/src/renderer/utils/formatDuration.ts index 84f90731b5..f0f7fbeccd 100644 --- a/src/renderer/utils/formatDuration.ts +++ b/src/renderer/utils/formatDuration.ts @@ -19,8 +19,8 @@ export function formatDuration(timeValue: number, compact: boolean) { const meaningfulValues = durationValues .map((a, i): [number, string] => [a, suffixes[i]]) - .filter(([dur, _suf]) => dur > 0) - .filter(([_dur, suf], i) => i === 0 || suf !== "s") // remove seconds, unless it is the only one + .filter(([dur]) => dur > 0) + .filter(([, suf], i) => i === 0 || suf !== "s") // remove seconds, unless it is the only one .map(([dur, suf]) => dur + suf); if (meaningfulValues.length === 0) { diff --git a/yarn.lock b/yarn.lock index caaf0bd5d2..acb8db159e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1094,6 +1094,22 @@ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46" integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== +"@eslint/eslintrc@^0.2.1": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.2.1.tgz#f72069c330461a06684d119384435e12a5d76e3c" + integrity sha512-XRUeBZ5zBWLYgSANMpThFddrZZkEbGHgUdt5UJjZfnlN9BGCiUBrf+nvbRupSjMvqzwnQN0qwCmOxITt1cfywA== + dependencies: + ajv "^6.12.4" + debug "^4.1.1" + espree "^7.3.0" + globals "^12.1.0" + ignore "^4.0.6" + import-fresh "^3.2.1" + js-yaml "^3.13.1" + lodash "^4.17.19" + minimatch "^3.0.4" + strip-json-comments "^3.1.1" + "@hapi/address@4.x.x": version "4.0.1" resolved "https://registry.yarnpkg.com/@hapi/address/-/address-4.0.1.tgz#267301ddf7bc453718377a6fb3832a2f04a721dd" @@ -2562,6 +2578,19 @@ semver "^7.3.2" tsutils "^3.17.1" +"@typescript-eslint/eslint-plugin@^4.5.0": + version "4.8.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.8.2.tgz#cf9102ec800391caa574f589ffe0623cca1d9308" + integrity sha512-gQ06QLV5l1DtvYtqOyFLXD9PdcILYqlrJj2l+CGDlPtmgLUzc1GpqciJFIRvyfvgLALpnxYINFuw+n9AZhPBKQ== + dependencies: + "@typescript-eslint/experimental-utils" "4.8.2" + "@typescript-eslint/scope-manager" "4.8.2" + debug "^4.1.1" + functional-red-black-tree "^1.0.1" + regexpp "^3.0.0" + semver "^7.3.2" + tsutils "^3.17.1" + "@typescript-eslint/experimental-utils@4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.0.0.tgz#fbec21a3b5ab59127edb6ce2e139ed378cc50eb5" @@ -2574,14 +2603,26 @@ eslint-scope "^5.0.0" eslint-utils "^2.0.0" -"@typescript-eslint/parser@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.0.0.tgz#0b19c25ad404b617caf33121e05f7dad14a594aa" - integrity sha512-KuBwTUzc3G3dD5k9ybTjgqIQjjJPY6WPaEoxdNS5vN5XV/Tixp0itA14+NQlbeswTHvsELaKXZhynxD/O2wHFA== +"@typescript-eslint/experimental-utils@4.8.2": + version "4.8.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.8.2.tgz#8909a5732f19329cf5ef0c39766170476bff5e50" + integrity sha512-hpTw6o6IhBZEsQsjuw/4RWmceRyESfAiEzAEnXHKG1X7S5DXFaZ4IO1JO7CW1aQ604leQBzjZmuMI9QBCAJX8Q== dependencies: - "@typescript-eslint/scope-manager" "4.0.0" - "@typescript-eslint/types" "4.0.0" - "@typescript-eslint/typescript-estree" "4.0.0" + "@types/json-schema" "^7.0.3" + "@typescript-eslint/scope-manager" "4.8.2" + "@typescript-eslint/types" "4.8.2" + "@typescript-eslint/typescript-estree" "4.8.2" + eslint-scope "^5.0.0" + eslint-utils "^2.0.0" + +"@typescript-eslint/parser@^4.0.0": + version "4.8.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.8.2.tgz#78dccbe5124de2b8dea2d4c363dee9f769151ca8" + integrity sha512-u0leyJqmclYr3KcXOqd2fmx6SDGBO0MUNHHAjr0JS4Crbb3C3d8dwAdlazy133PLCcPn+aOUFiHn72wcuc5wYw== + dependencies: + "@typescript-eslint/scope-manager" "4.8.2" + "@typescript-eslint/types" "4.8.2" + "@typescript-eslint/typescript-estree" "4.8.2" debug "^4.1.1" "@typescript-eslint/scope-manager@4.0.0": @@ -2592,11 +2633,24 @@ "@typescript-eslint/types" "4.0.0" "@typescript-eslint/visitor-keys" "4.0.0" +"@typescript-eslint/scope-manager@4.8.2": + version "4.8.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.8.2.tgz#a18388c63ae9c17adde519384f539392f2c4f0d9" + integrity sha512-qHQ8ODi7mMin4Sq2eh/6eu03uVzsf5TX+J43xRmiq8ujng7ViQSHNPLOHGw/Wr5dFEoxq/ubKhzClIIdQy5q3g== + dependencies: + "@typescript-eslint/types" "4.8.2" + "@typescript-eslint/visitor-keys" "4.8.2" + "@typescript-eslint/types@4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.0.0.tgz#ec1f9fc06b8558a1d5afa6e337182d08beece7f5" integrity sha512-bK+c2VLzznX2fUWLK6pFDv3cXGTp7nHIuBMq1B9klA+QCsqLHOOqe5TQReAQDl7DN2RfH+neweo0oC5hYlG7Rg== +"@typescript-eslint/types@4.8.2": + version "4.8.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.8.2.tgz#c862dd0e569d9478eb82d6aee662ea53f5661a36" + integrity sha512-z1/AVcVF8ju5ObaHe2fOpZYEQrwHyZ7PTOlmjd3EoFeX9sv7UekQhfrCmgUO7PruLNfSHrJGQvrW3Q7xQ8EoAw== + "@typescript-eslint/typescript-estree@4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.0.0.tgz#2244c63de2f2190bc5718eb0fb3fd2c437d42097" @@ -2611,6 +2665,20 @@ semver "^7.3.2" tsutils "^3.17.1" +"@typescript-eslint/typescript-estree@4.8.2": + version "4.8.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.8.2.tgz#eeec34707d8577600fb21661b5287226cc8b3bed" + integrity sha512-HToGNwI6fekH0dOw3XEVESUm71Onfam0AKin6f26S2FtUmO7o3cLlWgrIaT1q3vjB3wCTdww3Dx2iGq5wtUOCg== + dependencies: + "@typescript-eslint/types" "4.8.2" + "@typescript-eslint/visitor-keys" "4.8.2" + debug "^4.1.1" + globby "^11.0.1" + is-glob "^4.0.1" + lodash "^4.17.15" + semver "^7.3.2" + tsutils "^3.17.1" + "@typescript-eslint/visitor-keys@4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.0.0.tgz#e2bbb69d98076d6a3f06abcb2048225a74362c33" @@ -2619,6 +2687,14 @@ "@typescript-eslint/types" "4.0.0" eslint-visitor-keys "^2.0.0" +"@typescript-eslint/visitor-keys@4.8.2": + version "4.8.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.8.2.tgz#62cd3fbbbf65f8eccfbe6f159eb1b84a243a3f77" + integrity sha512-Vg+/SJTMZJEKKGHW7YC21QxgKJrSbxoYYd3MEUGtW7zuytHuEcksewq0DUmo4eh/CTNrVJGSdIY9AtRb6riWFw== + dependencies: + "@typescript-eslint/types" "4.8.2" + eslint-visitor-keys "^2.0.0" + "@webassemblyjs/ast@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" @@ -2900,6 +2976,16 @@ ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.0, ajv@^6.12.2, ajv@^6.5.5: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" @@ -3144,6 +3230,15 @@ array-flatten@^2.1.0: resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== +array-includes@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.1.tgz#cdd67e6852bdf9c1215460786732255ed2459348" + integrity sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0" + is-string "^1.0.5" + array-move@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/array-move/-/array-move-3.0.0.tgz#b646a2f4980be78f04d28d7572a72036150d364e" @@ -3171,6 +3266,16 @@ array-unique@^0.3.2: resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= +array.prototype.flatmap@^1.2.3: + version "1.2.4" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz#94cfd47cc1556ec0747d97f7c7738c58122004c9" + integrity sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + es-abstract "^1.18.0-next.1" + function-bind "^1.1.1" + asap@^2.0.0: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" @@ -5001,13 +5106,20 @@ debug@^3.0.0, debug@^3.1.0, debug@^3.1.1, debug@^3.2.5, debug@^3.2.6: dependencies: ms "^2.1.1" -debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: +debug@^4.0.1, debug@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== dependencies: ms "^2.1.1" +debug@^4.1.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" + integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== + dependencies: + ms "2.1.2" + debug@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/debug/-/debug-4.2.0.tgz#7f150f93920e94c58f5574c2fd01a3110effe7f1" @@ -5303,6 +5415,13 @@ dns-txt@^2.0.2: dependencies: buffer-indexof "^1.0.0" +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + doctrine@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" @@ -5712,6 +5831,23 @@ error-stack-parser@^2.0.6: dependencies: stackframe "^1.1.1" +es-abstract@^1.17.0: + version "1.17.7" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.7.tgz#a4de61b2f66989fc7421676c1cb9787573ace54c" + integrity sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g== + dependencies: + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + is-callable "^1.2.2" + is-regex "^1.1.1" + object-inspect "^1.8.0" + object-keys "^1.1.1" + object.assign "^4.1.1" + string.prototype.trimend "^1.0.1" + string.prototype.trimstart "^1.0.1" + es-abstract@^1.17.0-next.1, es-abstract@^1.17.5: version "1.17.5" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.5.tgz#d8c9d1d66c8981fb9200e2251d799eee92774ae9" @@ -5729,7 +5865,7 @@ es-abstract@^1.17.0-next.1, es-abstract@^1.17.5: string.prototype.trimleft "^2.1.1" string.prototype.trimright "^2.1.1" -es-abstract@^1.18.0-next.1: +es-abstract@^1.18.0-next.0, es-abstract@^1.18.0-next.1: version "1.18.0-next.1" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.1.tgz#6e3a0a4bda717e5023ab3b8e90bec36108d22c68" integrity sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA== @@ -5810,6 +5946,39 @@ escodegen@^1.14.1, escodegen@^1.8.1: optionalDependencies: source-map "~0.6.1" +eslint-plugin-react@^7.21.5: + version "7.21.5" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.21.5.tgz#50b21a412b9574bfe05b21db176e8b7b3b15bff3" + integrity sha512-8MaEggC2et0wSF6bUeywF7qQ46ER81irOdWS4QWxnnlAEsnzeBevk1sWh7fhpCghPpXb+8Ks7hvaft6L/xsR6g== + dependencies: + array-includes "^3.1.1" + array.prototype.flatmap "^1.2.3" + doctrine "^2.1.0" + has "^1.0.3" + jsx-ast-utils "^2.4.1 || ^3.0.0" + object.entries "^1.1.2" + object.fromentries "^2.0.2" + object.values "^1.1.1" + prop-types "^15.7.2" + resolve "^1.18.1" + string.prototype.matchall "^4.0.2" + +eslint-plugin-unused-imports@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-1.0.0.tgz#4e47514a5a262731f0ef26ce1e0826b425e93183" + integrity sha512-3r5ZMHyvy0ww6TuUoRUZNOIhd3EDD3+PQsoz0tdx86PjJ12qWv8Gl1JCW1rxOyFF9u8A61+1P7UId2hzQ95vuQ== + dependencies: + "@typescript-eslint/eslint-plugin" "^4.5.0" + eslint "^7.11.0" + eslint-rule-composer "^0.3.0" + requireindex "~1.2.0" + typescript "^4.0.3" + +eslint-rule-composer@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz#79320c927b0c5c0d3d3d2b76c8b4a488f25bbaf9" + integrity sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg== + eslint-scope@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" @@ -5826,6 +5995,14 @@ eslint-scope@^5.0.0, eslint-scope@^5.1.0: esrecurse "^4.1.0" estraverse "^4.1.1" +eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + eslint-utils@^2.0.0, eslint-utils@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" @@ -5843,6 +6020,49 @@ eslint-visitor-keys@^2.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8" integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== +eslint@^7.11.0: + version "7.14.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.14.0.tgz#2d2cac1d28174c510a97b377f122a5507958e344" + integrity sha512-5YubdnPXrlrYAFCKybPuHIAH++PINe1pmKNc5wQRB9HSbqIK1ywAnntE3Wwua4giKu0bjligf1gLF6qxMGOYRA== + dependencies: + "@babel/code-frame" "^7.0.0" + "@eslint/eslintrc" "^0.2.1" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.0.1" + doctrine "^3.0.0" + enquirer "^2.3.5" + eslint-scope "^5.1.1" + eslint-utils "^2.1.0" + eslint-visitor-keys "^2.0.0" + espree "^7.3.0" + esquery "^1.2.0" + esutils "^2.0.2" + file-entry-cache "^5.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.0.0" + globals "^12.1.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash "^4.17.19" + minimatch "^3.0.4" + natural-compare "^1.4.0" + optionator "^0.9.1" + progress "^2.0.0" + regexpp "^3.1.0" + semver "^7.2.1" + strip-ansi "^6.0.0" + strip-json-comments "^3.1.0" + table "^5.2.3" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + eslint@^7.7.0: version "7.7.0" resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.7.0.tgz#18beba51411927c4b64da0a8ceadefe4030d6073" @@ -5885,7 +6105,7 @@ eslint@^7.7.0: text-table "^0.2.0" v8-compile-cache "^2.0.3" -espree@^7.2.0: +espree@^7.2.0, espree@^7.3.0: version "7.3.0" resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.0.tgz#dc30437cf67947cf576121ebd780f15eeac72348" integrity sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw== @@ -5918,6 +6138,13 @@ esrecurse@^4.1.0: dependencies: estraverse "^4.1.0" +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: version "4.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" @@ -5928,6 +6155,11 @@ estraverse@^5.1.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.1.0.tgz#374309d39fd935ae500e7b92e8a6b4c720e59642" integrity sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw== +estraverse@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" + integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== + esutils@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" @@ -6203,9 +6435,9 @@ fast-safe-stringify@^2.0.4: integrity sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA== fastq@^1.6.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.8.0.tgz#550e1f9f59bbc65fe185cb6a9b4d95357107f481" - integrity sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q== + version "1.9.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.9.0.tgz#e16a72f338eaca48e91b5c23593bcc2ef66b7947" + integrity sha512-i7FVWL8HhVY+CTkwFxkN2mk3h+787ixS5S63eb78diVRc1MCssarHq3W5cj0av7YDSwmaV928RNag+U1etRQ7w== dependencies: reusify "^1.0.4" @@ -7444,6 +7676,14 @@ import-fresh@^3.0.0, import-fresh@^3.1.0: parent-module "^1.0.0" resolve-from "^4.0.0" +import-fresh@^3.2.1: + version "3.2.2" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.2.tgz#fc129c160c5d68235507f4331a6baad186bdbc3e" + integrity sha512-cTPNrlvJT6twpYy+YmKUKrTSjWFs3bjYjAhCwm+z4EOCubZxAuO+hHpRN64TqjEaYSHs7tJAE0w1CKMGmsG/lw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + import-lazy@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" @@ -7596,6 +7836,15 @@ internal-ip@^4.3.0: default-gateway "^4.2.0" ipaddr.js "^1.9.0" +internal-slot@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.2.tgz#9c2e9fb3cd8e5e4256c6f45fe310067fcfa378a3" + integrity sha512-2cQNfwhAfJIkU4KZPkDI+Gj5yNNnbqi40W9Gge6dfnk4TocEVm00B3bdiL+JINrbGJil2TeHvM4rETGzk/f/0g== + dependencies: + es-abstract "^1.17.0-next.1" + has "^1.0.3" + side-channel "^1.0.2" + interpret@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" @@ -7743,6 +7992,13 @@ is-cidr@^3.0.0: dependencies: cidr-regex "^2.0.10" +is-core-module@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.1.0.tgz#a4cc031d9b1aca63eecbd18a650e13cb4eeab946" + integrity sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA== + dependencies: + has "^1.0.3" + is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" @@ -8003,6 +8259,11 @@ is-stream@^2.0.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== +is-string@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" + integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== + is-symbol@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" @@ -8862,6 +9123,14 @@ jss@10.2.0, jss@^10.0.3: is-in-browser "^1.1.3" tiny-warning "^1.0.2" +"jsx-ast-utils@^2.4.1 || ^3.0.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.1.0.tgz#642f1d7b88aa6d7eb9d8f2210e166478444fa891" + integrity sha512-d4/UOjg+mxAWxCiF0c5UTSwyqbchkbqCvK87aBovhnh8GtysTjWmgC63tY0cJx/HzGgm9qnA147jVBdpOiQ2RA== + dependencies: + array-includes "^3.1.1" + object.assign "^4.1.1" + jszip@^3.1.0: version "3.5.0" resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.5.0.tgz#b4fd1f368245346658e781fec9675802489e15f6" @@ -10638,6 +10907,25 @@ object.assign@^4.1.1: has-symbols "^1.0.1" object-keys "^1.1.1" +object.entries@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.2.tgz#bc73f00acb6b6bb16c203434b10f9a7e797d3add" + integrity sha512-BQdB9qKmb/HyNdMNWVr7O3+z5MUIx3aiegEIJqjMBbBf0YT9RRxTJSim4mzFqtyr7PDAHigq0N9dO0m0tRakQA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + has "^1.0.3" + +object.fromentries@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.2.tgz#4a09c9b9bb3843dd0f89acdb517a794d4f355ac9" + integrity sha512-r3ZiBH7MQppDJVLx6fhD618GKNG40CZYH9wgwdhKxBDDbQgjeWGGd4AtkZad84d291YxvWe7bJGuE65Anh0dxQ== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + function-bind "^1.1.1" + has "^1.0.3" + object.getownpropertydescriptors@^2.0.3: version "2.1.0" resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649" @@ -10653,6 +10941,16 @@ object.pick@^1.3.0: dependencies: isobject "^3.0.1" +object.values@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.1.tgz#68a99ecde356b7e9295a3c5e0ce31dc8c953de5e" + integrity sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + function-bind "^1.1.1" + has "^1.0.3" + obuf@^1.0.0, obuf@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" @@ -12206,7 +12504,7 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexp.prototype.flags@^1.2.0: +regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz#7aba89b3c13a64509dabcf3ca8d9fbb9bdf5cb75" integrity sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ== @@ -12367,6 +12665,11 @@ require-main-filename@^2.0.0: resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== +requireindex@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/requireindex/-/requireindex-1.2.0.tgz#3463cdb22ee151902635aa6c9535d4de9c2ef1ef" + integrity sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww== + requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" @@ -12426,6 +12729,14 @@ resolve@^1.1.6, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.17.0, resolve@^1.3. dependencies: path-parse "^1.0.6" +resolve@^1.18.1: + version "1.19.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c" + integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg== + dependencies: + is-core-module "^2.1.0" + path-parse "^1.0.6" + responselike@1.0.2, responselike@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" @@ -12531,9 +12842,9 @@ run-async@^2.2.0, run-async@^2.4.0: integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== run-parallel@^1.1.9: - version "1.1.9" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" - integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== + version "1.1.10" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.10.tgz#60a51b2ae836636c81377df16cb107351bcd13ef" + integrity sha512-zb/1OuZ6flOlH6tQyMPUrE3x3Ulxjlo9WIVXR4yVYi4H9UXQaeIsPbLn2R3O3vQCnDKkAl2qHiuocKKX4Tz/Sw== run-queue@^1.0.0, run-queue@^1.0.3: version "1.0.3" @@ -12908,6 +13219,14 @@ shellwords@^0.1.1: resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== +side-channel@^1.0.2, side-channel@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.3.tgz#cdc46b057550bbab63706210838df5d4c19519c3" + integrity sha512-A6+ByhlLkksFoUepsGxfj5x1gTSrs+OydsRptUxeNCabQpCFUvcwIczgOigI8vhY/OJCnPnyE9rGiwgvr9cS1g== + dependencies: + es-abstract "^1.18.0-next.0" + object-inspect "^1.8.0" + signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" @@ -13401,6 +13720,19 @@ string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" +string.prototype.matchall@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.3.tgz#24243399bc31b0a49d19e2b74171a15653ec996a" + integrity sha512-OBxYDA2ifZQ2e13cP82dWFMaCV9CGF8GzmN4fljBVw5O5wep0lu4gacm1OL6MjROoUnB8VbkWRThqkV2YFLNxw== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + es-abstract "^1.18.0-next.1" + has-symbols "^1.0.1" + internal-slot "^1.0.2" + regexp.prototype.flags "^1.3.0" + side-channel "^1.0.3" + string.prototype.trimend@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913" @@ -13549,6 +13881,11 @@ strip-json-comments@^3.1.0: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.0.tgz#7638d31422129ecf4457440009fba03f9f9ac180" integrity sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w== +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" @@ -14061,11 +14398,16 @@ ts-node@^8.10.2: source-map-support "^0.5.17" yn "3.1.1" -tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: +tslib@^1.10.0, tslib@^1.9.0, tslib@^1.9.3: version "1.13.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q== +tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + tsutils@^3.17.1: version "3.17.1" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" @@ -14208,6 +14550,11 @@ typescript@^4.0.2: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.2.tgz#7ea7c88777c723c681e33bf7988be5d008d05ac2" integrity sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ== +typescript@^4.0.3: + version "4.1.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.2.tgz#6369ef22516fe5e10304aae5a5c4862db55380e9" + integrity sha512-thGloWsGH3SOxv1SoY7QojKi0tc+8FnOmiarEGMbd/lar7QOEd3hvlx3Fp5y6FlDUGl9L+pd4n2e+oToGMmhRQ== + uglify-js@^3.1.4: version "3.9.4" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.9.4.tgz#867402377e043c1fc7b102253a22b64e5862401b"