diff --git a/.eslintrc.js b/.eslintrc.js index 1426f74e7f..5cc4144b5d 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -31,18 +31,18 @@ module.exports = { settings: { react: { version: packageJson.devDependencies.react || "detect", - } + }, }, overrides: [ { files: [ - "**/*.js" + "**/*.js", ], extends: [ "eslint:recommended", ], env: { - node: true + node: true, }, parserOptions: { ecmaVersion: 2018, @@ -51,32 +51,44 @@ module.exports = { plugins: [ "header", "unused-imports", - "react-hooks" + "react-hooks", ], rules: { "header/header": [2, "./license-header"], + "comma-dangle": ["error", "always-multiline"], + "comma-spacing": "error", "indent": ["error", 2, { "SwitchCase": 1, }], "no-unused-vars": "off", + "space-before-function-paren": ["error", { + "anonymous": "always", + "named": "never", + "asyncArrow": "always", + }], "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, }], + "object-curly-spacing": ["error", "always", { + "objectsInObjects": false, + "arraysInObjects": true, + }], "linebreak-style": ["error", "unix"], "eol-last": ["error", "always"], "semi": ["error", "always"], "object-shorthand": "error", "prefer-template": "error", "template-curly-spacing": "error", + "no-unused-expressions": "error", "padding-line-between-statements": [ "error", { "blankLine": "always", "prev": "*", "next": "return" }, @@ -84,9 +96,10 @@ module.exports = { { "blankLine": "always", "prev": "*", "next": "function" }, { "blankLine": "always", "prev": "*", "next": "class" }, { "blankLine": "always", "prev": ["const", "let", "var"], "next": "*" }, - { "blankLine": "any", "prev": ["const", "let", "var"], "next": ["const", "let", "var"]}, - ] - } + { "blankLine": "any", "prev": ["const", "let", "var"], "next": ["const", "let", "var"] }, + ], + "no-template-curly-in-string": "error", + }, }, { files: [ @@ -98,7 +111,7 @@ module.exports = { ], plugins: [ "header", - "unused-imports" + "unused-imports", ], parserOptions: { ecmaVersion: 2018, @@ -115,14 +128,24 @@ module.exports = { "@typescript-eslint/ban-ts-comment": "off", "@typescript-eslint/no-empty-interface": "off", "@typescript-eslint/no-unused-vars": "off", + "space-before-function-paren": "off", + "@typescript-eslint/space-before-function-paren": ["error", { + "anonymous": "always", + "named": "never", + "asyncArrow": "always", + }], "unused-imports/no-unused-imports-ts": process.env.PROD === "true" ? "error" : "warn", "unused-imports/no-unused-vars-ts": [ "warn", { "vars": "all", "args": "after-used", "ignoreRestSiblings": true, - } + }, ], + "comman-dangle": "off", + "@typescript-eslint/comma-dangle": ["error", "always-multiline"], + "comma-spacing": "off", + "@typescript-eslint/comma-spacing": "error", "indent": ["error", 2, { "SwitchCase": 1, }], @@ -130,6 +153,11 @@ module.exports = { "avoidEscape": true, "allowTemplateLiterals": true, }], + "object-curly-spacing": "off", + "@typescript-eslint/object-curly-spacing": ["error", "always", { + "objectsInObjects": false, + "arraysInObjects": true, + }], "react/prop-types": "off", "semi": "off", "@typescript-eslint/semi": ["error"], @@ -138,6 +166,8 @@ module.exports = { "object-shorthand": "error", "prefer-template": "error", "template-curly-spacing": "error", + "no-unused-expressions": "off", + "@typescript-eslint/no-unused-expressions": "error", "padding-line-between-statements": [ "error", { "blankLine": "always", "prev": "*", "next": "return" }, @@ -145,8 +175,9 @@ module.exports = { { "blankLine": "always", "prev": "*", "next": "function" }, { "blankLine": "always", "prev": "*", "next": "class" }, { "blankLine": "always", "prev": ["const", "let", "var"], "next": "*" }, - { "blankLine": "any", "prev": ["const", "let", "var"], "next": ["const", "let", "var"]}, - ] + { "blankLine": "any", "prev": ["const", "let", "var"], "next": ["const", "let", "var"] }, + ], + "no-template-curly-in-string": "error", }, }, { @@ -156,7 +187,7 @@ module.exports = { parser: "@typescript-eslint/parser", plugins: [ "header", - "unused-imports" + "unused-imports", ], extends: [ "plugin:@typescript-eslint/recommended", @@ -183,14 +214,24 @@ module.exports = { "@typescript-eslint/no-empty-function": "off", "react/display-name": "off", "@typescript-eslint/no-unused-vars": "off", + "space-before-function-paren": "off", + "@typescript-eslint/space-before-function-paren": ["error", { + "anonymous": "always", + "named": "never", + "asyncArrow": "always", + }], "unused-imports/no-unused-imports-ts": process.env.PROD === "true" ? "error" : "warn", "unused-imports/no-unused-vars-ts": [ "warn", { "vars": "all", "args": "after-used", "ignoreRestSiblings": true, - } + }, ], + "comman-dangle": "off", + "@typescript-eslint/comma-dangle": ["error", "always-multiline"], + "comma-spacing": "off", + "@typescript-eslint/comma-spacing": "error", "indent": ["error", 2, { "SwitchCase": 1, }], @@ -198,6 +239,11 @@ module.exports = { "avoidEscape": true, "allowTemplateLiterals": true, }], + "object-curly-spacing": "off", + "@typescript-eslint/object-curly-spacing": ["error", "always", { + "objectsInObjects": false, + "arraysInObjects": true, + }], "react/prop-types": "off", "semi": "off", "@typescript-eslint/semi": ["error"], @@ -206,6 +252,8 @@ module.exports = { "object-shorthand": "error", "prefer-template": "error", "template-curly-spacing": "error", + "no-unused-expressions": "off", + "@typescript-eslint/no-unused-expressions": "error", "padding-line-between-statements": [ "error", { "blankLine": "always", "prev": "*", "next": "return" }, @@ -213,11 +261,12 @@ module.exports = { { "blankLine": "always", "prev": "*", "next": "function" }, { "blankLine": "always", "prev": "*", "next": "class" }, { "blankLine": "always", "prev": ["const", "let", "var"], "next": "*" }, - { "blankLine": "any", "prev": ["const", "let", "var"], "next": ["const", "let", "var"]}, + { "blankLine": "any", "prev": ["const", "let", "var"], "next": ["const", "let", "var"] }, ], "react-hooks/rules-of-hooks": "error", - "react-hooks/exhaustive-deps": "off" + "react-hooks/exhaustive-deps": "off", + "no-template-curly-in-string": "error", }, - } - ] + }, + ], }; diff --git a/.yarnrc b/.yarnrc index ef7784e7e3..756f21586a 100644 --- a/.yarnrc +++ b/.yarnrc @@ -1,3 +1,3 @@ disturl "https://atom.io/download/electron" -target "13.6.0" +target "13.6.1" runtime "electron" diff --git a/Makefile b/Makefile index 9fdb588215..6763e7e42a 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,7 @@ dev: binaries/client build-extensions static/build/LensDev.html yarn dev .PHONY: lint -lint: +lint: node_modules yarn lint .PHONY: tag-release diff --git a/RELEASE_GUIDE.md b/RELEASE_GUIDE.md index a2f7a6db32..896d0139f3 100644 --- a/RELEASE_GUIDE.md +++ b/RELEASE_GUIDE.md @@ -10,9 +10,9 @@ Lens releases are built by CICD automatically on git tags. The typical release p - `major` - `minor` - `patch` - - `premajor` [--preid=] - - `preminor` [--preid=] - - `prepatch` [--preid=] + - `premajor [--preid=]` + - `preminor [--preid=]` + - `prepatch [--preid=]` - `prerelease [--preid=]` where `` is generally one of: @@ -28,6 +28,8 @@ Lens releases are built by CICD automatically on git tags. The typical release p - `git tag -fa vX.Y.Z-beta.N` (move the tag locally to the current commit) - `git push origin --tags` (update the tags on https://github.com/lensapp/lens to reflect this local change) + Once the tag has been updated on origin (e.g. by `git push origin --tags`) the azure jobs are automatically triggered again. + 1. Once CI passes again go to the releases tab on GitHub. You can use the existing draft release prepared by k8slens-bot (select the correct tag). Or you can create a new release from the tag that was created, and make sure that the change log is the same as that of the PR, and the title is the tag. Either way, click the prerelease checkbox if this is not a new major, minor, or patch version before clicking `Publish release`. 1. Merge the release PR after the release is published. If it is a patch release then there is no need to squash the cherry-picked commits as part of the merge. GitHub should delete the branch once it is merged. 1. If you have just released a new major or minor version then create a new `release/vMAJOR.MINOR` branch from that same tag and push it to https://github.com/lensapp/lens. Given the commit of the merged release PR from the master branch you can do this like diff --git a/__mocks__/electron.ts b/__mocks__/electron.ts index 4c69a9bca0..1abb79855a 100644 --- a/__mocks__/electron.ts +++ b/__mocks__/electron.ts @@ -28,6 +28,6 @@ export default { }, dialog: jest.fn(), ipcRenderer: { - on: jest.fn() - } + on: jest.fn(), + }, }; diff --git a/build/download_helm.ts b/build/download_helm.ts index 6c606d06d5..b9d9714d92 100644 --- a/build/download_helm.ts +++ b/build/download_helm.ts @@ -28,7 +28,7 @@ const helmVersion = packageInfo.config.bundledHelmVersion; if (!isWindows) { Promise.all([ new HelmCli(path.join(process.cwd(), "binaries", "client", "x64"), helmVersion).ensureBinary(), - new HelmCli(path.join(process.cwd(), "binaries", "client", "arm64"), helmVersion).ensureBinary() + new HelmCli(path.join(process.cwd(), "binaries", "client", "arm64"), helmVersion).ensureBinary(), ]); } else { new HelmCli(path.join(process.cwd(), "binaries", "client", "x64"), helmVersion).ensureBinary(); diff --git a/build/download_kubectl.ts b/build/download_kubectl.ts index e87534d24f..5269bb39c8 100644 --- a/build/download_kubectl.ts +++ b/build/download_kubectl.ts @@ -47,7 +47,7 @@ class KubectlDownloader { const response = await requestPromise({ method: "HEAD", uri: this.url, - resolveWithFullResponse: true + resolveWithFullResponse: true, }).catch(console.error); if (response.headers["etag"]) { @@ -89,7 +89,7 @@ class KubectlDownloader { console.log(`Downloading kubectl ${this.kubectlVersion} from ${this.url} to ${this.path}`); const requestOpts: request.UriOptions & request.CoreOptions = { uri: this.url, - gzip: true + gzip: true, }; const stream = request(requestOpts); diff --git a/extensions/kube-object-event-status/renderer.tsx b/extensions/kube-object-event-status/renderer.tsx index 79e4aab424..5214eec2e6 100644 --- a/extensions/kube-object-event-status/renderer.tsx +++ b/extensions/kube-object-event-status/renderer.tsx @@ -27,37 +27,37 @@ export default class EventResourceStatusRendererExtension extends Renderer.LensE { kind: "Pod", apiVersions: ["v1"], - resolve: (pod: Renderer.K8sApi.Pod) => resolveStatusForPods(pod) + resolve: (pod: Renderer.K8sApi.Pod) => resolveStatusForPods(pod), }, { kind: "ReplicaSet", apiVersions: ["v1"], - resolve: (replicaSet: Renderer.K8sApi.ReplicaSet) => resolveStatus(replicaSet) + resolve: (replicaSet: Renderer.K8sApi.ReplicaSet) => resolveStatus(replicaSet), }, { kind: "Deployment", apiVersions: ["apps/v1"], - resolve: (deployment: Renderer.K8sApi.Deployment) => resolveStatus(deployment) + resolve: (deployment: Renderer.K8sApi.Deployment) => resolveStatus(deployment), }, { kind: "StatefulSet", apiVersions: ["apps/v1"], - resolve: (statefulSet: Renderer.K8sApi.StatefulSet) => resolveStatus(statefulSet) + resolve: (statefulSet: Renderer.K8sApi.StatefulSet) => resolveStatus(statefulSet), }, { kind: "DaemonSet", apiVersions: ["apps/v1"], - resolve: (daemonSet: Renderer.K8sApi.DaemonSet) => resolveStatus(daemonSet) + resolve: (daemonSet: Renderer.K8sApi.DaemonSet) => resolveStatus(daemonSet), }, { kind: "Job", apiVersions: ["batch/v1"], - resolve: (job: Renderer.K8sApi.Job) => resolveStatus(job) + resolve: (job: Renderer.K8sApi.Job) => resolveStatus(job), }, { kind: "CronJob", apiVersions: ["batch/v1"], - resolve: (cronJob: Renderer.K8sApi.CronJob) => resolveStatusForCronJobs(cronJob) + resolve: (cronJob: Renderer.K8sApi.CronJob) => resolveStatusForCronJobs(cronJob), }, ]; } diff --git a/extensions/kube-object-event-status/src/resolver.tsx b/extensions/kube-object-event-status/src/resolver.tsx index 4a4ebfe25d..0aeeb69465 100644 --- a/extensions/kube-object-event-status/src/resolver.tsx +++ b/extensions/kube-object-event-status/src/resolver.tsx @@ -42,7 +42,7 @@ export function resolveStatus(object: KubeObject): KubeObjectStatus { return { level: KubeObjectStatusLevel.WARNING, text: `${event.message}`, - timestamp: event.metadata.creationTimestamp + timestamp: event.metadata.creationTimestamp, }; } @@ -62,7 +62,7 @@ export function resolveStatusForPods(pod: Pod): KubeObjectStatus { return { level: KubeObjectStatusLevel.WARNING, text: `${event.message}`, - timestamp: event.metadata.creationTimestamp + timestamp: event.metadata.creationTimestamp, }; } @@ -83,6 +83,6 @@ export function resolveStatusForCronJobs(cronJob: CronJob): KubeObjectStatus { return { level: KubeObjectStatusLevel.WARNING, text: `${event.message}`, - timestamp: event.metadata.creationTimestamp + timestamp: event.metadata.creationTimestamp, }; } diff --git a/extensions/kube-object-event-status/webpack.config.js b/extensions/kube-object-event-status/webpack.config.js index b49801a1fb..1084f7255c 100644 --- a/extensions/kube-object-event-status/webpack.config.js +++ b/extensions/kube-object-event-status/webpack.config.js @@ -27,7 +27,7 @@ module.exports = [ target: "electron-renderer", mode: "production", optimization: { - minimize: false + minimize: false, }, module: { rules: [ @@ -43,8 +43,8 @@ module.exports = [ "@k8slens/extensions": "var global.LensExtensions", "react": "var global.React", "mobx": "var global.Mobx", - "mobx-react": "var global.MobxReact" - } + "mobx-react": "var global.MobxReact", + }, ], resolve: { extensions: [ ".tsx", ".ts", ".js" ], diff --git a/extensions/metrics-cluster-feature/renderer.tsx b/extensions/metrics-cluster-feature/renderer.tsx index 884f6cd7a2..fe734ca604 100644 --- a/extensions/metrics-cluster-feature/renderer.tsx +++ b/extensions/metrics-cluster-feature/renderer.tsx @@ -31,12 +31,12 @@ export default class ClusterMetricsFeatureExtension extends Renderer.LensExtensi title: "Lens Metrics", priority: 5, components: { - View: ({ entity = null }: { entity: Common.Catalog.KubernetesCluster}) => { + View: ({ entity = null }: { entity: Common.Catalog.KubernetesCluster }) => { return ( ); - } - } - } + }, + }, + }, ]; } diff --git a/extensions/metrics-cluster-feature/resources/12-kube-state-metrics-clusterrole.yml b/extensions/metrics-cluster-feature/resources/12-kube-state-metrics-clusterrole.yml index b74e08fc57..0568d6a560 100644 --- a/extensions/metrics-cluster-feature/resources/12-kube-state-metrics-clusterrole.yml +++ b/extensions/metrics-cluster-feature/resources/12-kube-state-metrics-clusterrole.yml @@ -31,6 +31,13 @@ rules: verbs: - list - watch + - apiGroups: + - networking.k8s.io + resources: + - ingresses + verbs: + - list + - watch - apiGroups: - apps resources: diff --git a/extensions/metrics-cluster-feature/src/metrics-feature.ts b/extensions/metrics-cluster-feature/src/metrics-feature.ts index 3401773cdc..7027e4f200 100644 --- a/extensions/metrics-cluster-feature/src/metrics-feature.ts +++ b/extensions/metrics-cluster-feature/src/metrics-feature.ts @@ -92,11 +92,11 @@ export class MetricsFeature { } async getStatus(): Promise { - const status: MetricsStatus = { installed: false, canUpgrade: false}; + const status: MetricsStatus = { installed: false, canUpgrade: false }; try { const namespaceApi = forCluster(this.cluster, Namespace); - const namespace = await namespaceApi.get({name: "lens-metrics"}); + const namespace = await namespaceApi.get({ name: "lens-metrics" }); if (namespace?.kind) { const currentVersion = namespace.metadata.annotations?.extensionVersion || "0.0.0"; diff --git a/extensions/metrics-cluster-feature/src/metrics-settings.tsx b/extensions/metrics-cluster-feature/src/metrics-settings.tsx index f05854b0f2..238d71bbf0 100644 --- a/extensions/metrics-cluster-feature/src/metrics-settings.tsx +++ b/extensions/metrics-cluster-feature/src/metrics-settings.tsx @@ -30,7 +30,7 @@ const { }, Component: { SubTitle, FormSwitch, Switcher, Button, - } + }, } = Renderer; interface Props { @@ -47,7 +47,7 @@ export class MetricsSettings extends React.Component { @observable featureStates = { prometheus: false, kubeStateMetrics: false, - nodeExporter: false + nodeExporter: false, }; @observable canUpgrade = false; @observable upgrading = false; @@ -56,7 +56,7 @@ export class MetricsSettings extends React.Component { config: MetricsConfiguration = { prometheus: { - enabled: false + enabled: false, }, persistence: { enabled: false, @@ -114,7 +114,7 @@ export class MetricsSettings extends React.Component { const statefulSet = forCluster(this.props.cluster, StatefulSet); try { - await statefulSet.get({name: "prometheus", namespace: "lens-metrics"}); + await statefulSet.get({ name: "prometheus", namespace: "lens-metrics" }); this.featureStates.prometheus = true; } catch(e) { if (e?.error?.code === 404) { @@ -127,7 +127,7 @@ export class MetricsSettings extends React.Component { const deployment = forCluster(this.props.cluster, Deployment); try { - await deployment.get({name: "kube-state-metrics", namespace: "lens-metrics"}); + await deployment.get({ name: "kube-state-metrics", namespace: "lens-metrics" }); this.featureStates.kubeStateMetrics = true; } catch(e) { if (e?.error?.code === 404) { @@ -140,7 +140,7 @@ export class MetricsSettings extends React.Component { const daemonSet = forCluster(this.props.cluster, DaemonSet); try { - await daemonSet.get({name: "node-exporter", namespace: "lens-metrics"}); + await daemonSet.get({ name: "node-exporter", namespace: "lens-metrics" }); this.featureStates.nodeExporter = true; } catch(e) { if (e?.error?.code === 404) { @@ -207,14 +207,14 @@ export class MetricsSettings extends React.Component { <> { this.props.cluster.status.phase !== "connected" && (
-

+

Lens Metrics settings requires established connection to the cluster.

)} { !this.isActiveMetricsProvider && (
-

+

Other metrics provider is currently active. See "Metrics" tab for details.

diff --git a/extensions/metrics-cluster-feature/webpack.config.js b/extensions/metrics-cluster-feature/webpack.config.js index 463d3acf9f..599976b6b2 100644 --- a/extensions/metrics-cluster-feature/webpack.config.js +++ b/extensions/metrics-cluster-feature/webpack.config.js @@ -27,7 +27,7 @@ module.exports = [ target: "electron-renderer", mode: "production", optimization: { - minimize: false + minimize: false, }, module: { rules: [ @@ -43,8 +43,8 @@ module.exports = [ "@k8slens/extensions": "var global.LensExtensions", "react": "var global.React", "mobx": "var global.Mobx", - "mobx-react": "var global.MobxReact" - } + "mobx-react": "var global.MobxReact", + }, ], resolve: { extensions: [ ".tsx", ".ts", ".js" ], @@ -56,7 +56,7 @@ module.exports = [ path: path.resolve(__dirname, "dist"), }, node: { - __dirname: false - } + __dirname: false, + }, }, ]; diff --git a/extensions/node-menu/renderer.tsx b/extensions/node-menu/renderer.tsx index b85ed7c162..8db7b0ccc5 100644 --- a/extensions/node-menu/renderer.tsx +++ b/extensions/node-menu/renderer.tsx @@ -29,8 +29,8 @@ export default class NodeMenuRendererExtension extends Renderer.LensExtension { kind: "Node", apiVersions: ["v1"], components: { - MenuItem: (props: NodeMenuProps) => - } - } + MenuItem: (props: NodeMenuProps) => , + }, + }, ]; } diff --git a/extensions/node-menu/src/node-menu.tsx b/extensions/node-menu/src/node-menu.tsx index 12ded04899..24ba659616 100644 --- a/extensions/node-menu/src/node-menu.tsx +++ b/extensions/node-menu/src/node-menu.tsx @@ -20,7 +20,7 @@ */ import React from "react"; -import { Renderer } from "@k8slens/extensions"; +import { Common, Renderer } from "@k8slens/extensions"; type Node = Renderer.K8sApi.Node; @@ -32,8 +32,11 @@ const { MenuItem, Icon, }, - Navigation + Navigation, } = Renderer; +const { + App, +} = Common; export interface NodeMenuProps extends Renderer.Component.KubeObjectMenuProps { @@ -42,8 +45,12 @@ export interface NodeMenuProps extends Renderer.Component.KubeObjectMenuProps { terminalStore.sendCommand(command, { @@ -62,15 +69,15 @@ export function NodeMenu(props: NodeMenuProps) { }; const cordon = () => { - sendToTerminal(`kubectl cordon ${nodeName}`); + sendToTerminal(`${kubectlPath} cordon ${nodeName}`); }; const unCordon = () => { - sendToTerminal(`kubectl uncordon ${nodeName}`); + sendToTerminal(`${kubectlPath} uncordon ${nodeName}`); }; const drain = () => { - const command = `kubectl drain ${nodeName} --delete-local-data --ignore-daemonsets --force`; + const command = `${kubectlPath} drain ${nodeName} --delete-local-data --ignore-daemonsets --force`; ConfirmDialog.open({ ok: () => sendToTerminal(command), diff --git a/extensions/node-menu/webpack.config.js b/extensions/node-menu/webpack.config.js index b49801a1fb..1084f7255c 100644 --- a/extensions/node-menu/webpack.config.js +++ b/extensions/node-menu/webpack.config.js @@ -27,7 +27,7 @@ module.exports = [ target: "electron-renderer", mode: "production", optimization: { - minimize: false + minimize: false, }, module: { rules: [ @@ -43,8 +43,8 @@ module.exports = [ "@k8slens/extensions": "var global.LensExtensions", "react": "var global.React", "mobx": "var global.Mobx", - "mobx-react": "var global.MobxReact" - } + "mobx-react": "var global.MobxReact", + }, ], resolve: { extensions: [ ".tsx", ".ts", ".js" ], diff --git a/extensions/pod-menu/renderer.tsx b/extensions/pod-menu/renderer.tsx index d25ab12d3f..9e712c6039 100644 --- a/extensions/pod-menu/renderer.tsx +++ b/extensions/pod-menu/renderer.tsx @@ -31,22 +31,22 @@ export default class PodMenuRendererExtension extends Renderer.LensExtension { kind: "Pod", apiVersions: ["v1"], components: { - MenuItem: (props: PodAttachMenuProps) => - } + MenuItem: (props: PodAttachMenuProps) => , + }, }, { kind: "Pod", apiVersions: ["v1"], components: { - MenuItem: (props: PodShellMenuProps) => - } + MenuItem: (props: PodShellMenuProps) => , + }, }, { kind: "Pod", apiVersions: ["v1"], components: { - MenuItem: (props: PodLogsMenuProps) => - } - } + MenuItem: (props: PodLogsMenuProps) => , + }, + }, ]; } diff --git a/extensions/pod-menu/src/attach-menu.tsx b/extensions/pod-menu/src/attach-menu.tsx index ad02782641..4b2378e79e 100644 --- a/extensions/pod-menu/src/attach-menu.tsx +++ b/extensions/pod-menu/src/attach-menu.tsx @@ -39,6 +39,7 @@ const { } = Renderer; const { Util, + App, } = Common; export interface PodAttachMenuProps extends Renderer.Component.KubeObjectMenuProps { @@ -47,22 +48,34 @@ export interface PodAttachMenuProps extends Renderer.Component.KubeObjectMenuPro export class PodAttachMenu extends React.Component { async attachToPod(container?: string) { const { object: pod } = this.props; - const containerParam = container ? `-c ${container}` : ""; - let command = `kubectl attach -i -t -n ${pod.getNs()} ${pod.getName()} ${containerParam}`; + + const kubectlPath = App.Preferences.getKubectlPath() || "kubectl"; + const commandParts = [ + kubectlPath, + "attach", + "-i", + "-t", + "-n", pod.getNs(), + pod.getName(), + ]; if (window.navigator.platform !== "Win32") { - command = `exec ${command}`; + commandParts.unshift("exec"); + } + + if (container) { + commandParts.push("-c", container); } const shell = createTerminalTab({ - title: `Pod: ${pod.getName()} (namespace: ${pod.getNs()}) [Attached]` + title: `Pod: ${pod.getName()} (namespace: ${pod.getNs()}) [Attached]`, }); - terminalStore.sendCommand(command, { + terminalStore.sendCommand(commandParts.join(" "), { enter: true, - tabId: shell.id + tabId: shell.id, }); - + Navigation.hideDetails(); } diff --git a/extensions/pod-menu/src/shell-menu.tsx b/extensions/pod-menu/src/shell-menu.tsx index 4c52379525..322d2192d0 100644 --- a/extensions/pod-menu/src/shell-menu.tsx +++ b/extensions/pod-menu/src/shell-menu.tsx @@ -39,6 +39,7 @@ const { } = Renderer; const { Util, + App, } = Common; export interface PodShellMenuProps extends Renderer.Component.KubeObjectMenuProps { @@ -46,29 +47,44 @@ export interface PodShellMenuProps extends Renderer.Component.KubeObjectMenuProp export class PodShellMenu extends React.Component { async execShell(container?: string) { - Navigation.hideDetails(); const { object: pod } = this.props; - const containerParam = container ? `-c ${container}` : ""; - let command = `kubectl exec -i -t -n ${pod.getNs()} ${pod.getName()} ${containerParam} "--"`; + + const kubectlPath = App.Preferences.getKubectlPath() || "kubectl"; + const commandParts = [ + kubectlPath, + "exec", + "-i", + "-t", + "-n", pod.getNs(), + pod.getName(), + ]; if (window.navigator.platform !== "Win32") { - command = `exec ${command}`; + commandParts.unshift("exec"); } + if (container) { + commandParts.push("-c", container); + } + + commandParts.push("--"); + if (pod.getSelectedNodeOs() === "windows") { - command = `${command} powershell`; + commandParts.push("powershell"); } else { - command = `${command} sh -c "clear; (bash || ash || sh)"`; + commandParts.push('sh -c "clear; (bash || ash || sh)"'); } const shell = createTerminalTab({ - title: `Pod: ${pod.getName()} (namespace: ${pod.getNs()})` + title: `Pod: ${pod.getName()} (namespace: ${pod.getNs()})`, }); - terminalStore.sendCommand(command, { + terminalStore.sendCommand(commandParts.join(" "), { enter: true, - tabId: shell.id + tabId: shell.id, }); + + Navigation.hideDetails(); } render() { diff --git a/extensions/pod-menu/webpack.config.js b/extensions/pod-menu/webpack.config.js index b49801a1fb..1084f7255c 100644 --- a/extensions/pod-menu/webpack.config.js +++ b/extensions/pod-menu/webpack.config.js @@ -27,7 +27,7 @@ module.exports = [ target: "electron-renderer", mode: "production", optimization: { - minimize: false + minimize: false, }, module: { rules: [ @@ -43,8 +43,8 @@ module.exports = [ "@k8slens/extensions": "var global.LensExtensions", "react": "var global.React", "mobx": "var global.Mobx", - "mobx-react": "var global.MobxReact" - } + "mobx-react": "var global.MobxReact", + }, ], resolve: { extensions: [ ".tsx", ".ts", ".js" ], diff --git a/integration/__tests__/cluster-pages.tests.ts b/integration/__tests__/cluster-pages.tests.ts index f54565e1a8..5280f10599 100644 --- a/integration/__tests__/cluster-pages.tests.ts +++ b/integration/__tests__/cluster-pages.tests.ts @@ -75,16 +75,16 @@ const commonPageTests: CommonPageTest[] = [{ name: "Cluster", href: "/overview", expectedSelector: "div[data-testid='cluster-overview-page'] div.label", - expectedText: "CPU" - } + expectedText: "CPU", + }, }, { page: { name: "Nodes", href: "/nodes", expectedSelector: "h5.title", - expectedText: "Nodes" - } + expectedText: "Nodes", + }, }, { drawerId: "workloads", @@ -93,51 +93,51 @@ const commonPageTests: CommonPageTest[] = [{ name: "Overview", href: "/workloads", expectedSelector: "h5.box", - expectedText: "Overview" + expectedText: "Overview", }, { name: "Pods", href: "/pods", expectedSelector: "h5.title", - expectedText: "Pods" + expectedText: "Pods", }, { name: "Deployments", href: "/deployments", expectedSelector: "h5.title", - expectedText: "Deployments" + expectedText: "Deployments", }, { name: "DaemonSets", href: "/daemonsets", expectedSelector: "h5.title", - expectedText: "Daemon Sets" + expectedText: "Daemon Sets", }, { name: "StatefulSets", href: "/statefulsets", expectedSelector: "h5.title", - expectedText: "Stateful Sets" + expectedText: "Stateful Sets", }, { name: "ReplicaSets", href: "/replicasets", expectedSelector: "h5.title", - expectedText: "Replica Sets" + expectedText: "Replica Sets", }, { name: "Jobs", href: "/jobs", expectedSelector: "h5.title", - expectedText: "Jobs" + expectedText: "Jobs", }, { name: "CronJobs", href: "/cronjobs", expectedSelector: "h5.title", - expectedText: "Cron Jobs" + expectedText: "Cron Jobs", }, - ] + ], }, { drawerId: "config", @@ -146,39 +146,39 @@ const commonPageTests: CommonPageTest[] = [{ name: "ConfigMaps", href: "/configmaps", expectedSelector: "h5.title", - expectedText: "Config Maps" + expectedText: "Config Maps", }, { name: "Secrets", href: "/secrets", expectedSelector: "h5.title", - expectedText: "Secrets" + expectedText: "Secrets", }, { name: "Resource Quotas", href: "/resourcequotas", expectedSelector: "h5.title", - expectedText: "Resource Quotas" + expectedText: "Resource Quotas", }, { name: "Limit Ranges", href: "/limitranges", expectedSelector: "h5.title", - expectedText: "Limit Ranges" + expectedText: "Limit Ranges", }, { name: "HPA", href: "/hpa", expectedSelector: "h5.title", - expectedText: "Horizontal Pod Autoscalers" + expectedText: "Horizontal Pod Autoscalers", }, { name: "Pod Disruption Budgets", href: "/poddisruptionbudgets", expectedSelector: "h5.title", - expectedText: "Pod Disruption Budgets" + expectedText: "Pod Disruption Budgets", }, - ] + ], }, { drawerId: "networks", @@ -187,27 +187,27 @@ const commonPageTests: CommonPageTest[] = [{ name: "Services", href: "/services", expectedSelector: "h5.title", - expectedText: "Services" + expectedText: "Services", }, { name: "Endpoints", href: "/endpoints", expectedSelector: "h5.title", - expectedText: "Endpoints" + expectedText: "Endpoints", }, { name: "Ingresses", href: "/ingresses", expectedSelector: "h5.title", - expectedText: "Ingresses" + expectedText: "Ingresses", }, { name: "Network Policies", href: "/network-policies", expectedSelector: "h5.title", - expectedText: "Network Policies" + expectedText: "Network Policies", }, - ] + ], }, { drawerId: "storage", @@ -216,37 +216,37 @@ const commonPageTests: CommonPageTest[] = [{ name: "Persistent Volume Claims", href: "/persistent-volume-claims", expectedSelector: "h5.title", - expectedText: "Persistent Volume Claims" + expectedText: "Persistent Volume Claims", }, { name: "Persistent Volumes", href: "/persistent-volumes", expectedSelector: "h5.title", - expectedText: "Persistent Volumes" + expectedText: "Persistent Volumes", }, { name: "Storage Classes", href: "/storage-classes", expectedSelector: "h5.title", - expectedText: "Storage Classes" + expectedText: "Storage Classes", }, - ] + ], }, { page: { name: "Namespaces", href: "/namespaces", expectedSelector: "h5.title", - expectedText: "Namespaces" - } + expectedText: "Namespaces", + }, }, { page: { name: "Events", href: "/events", expectedSelector: "h5.title", - expectedText: "Events" - } + expectedText: "Events", + }, }, { drawerId: "apps", @@ -260,9 +260,9 @@ const commonPageTests: CommonPageTest[] = [{ name: "Releases", href: "/apps/releases", expectedSelector: "h5.title", - expectedText: "Releases" + expectedText: "Releases", }, - ] + ], }, { drawerId: "users", @@ -271,39 +271,39 @@ const commonPageTests: CommonPageTest[] = [{ name: "Service Accounts", href: "/service-accounts", expectedSelector: "h5.title", - expectedText: "Service Accounts" + expectedText: "Service Accounts", }, { name: "Roles", href: "/roles", expectedSelector: "h5.title", - expectedText: "Roles" + expectedText: "Roles", }, { name: "Cluster Roles", href: "/cluster-roles", expectedSelector: "h5.title", - expectedText: "Cluster Roles" + expectedText: "Cluster Roles", }, { name: "Role Bindings", href: "/role-bindings", expectedSelector: "h5.title", - expectedText: "Role Bindings" + expectedText: "Role Bindings", }, { name: "Cluster Role Bindings", href: "/cluster-role-bindings", expectedSelector: "h5.title", - expectedText: "Cluster Role Bindings" + expectedText: "Cluster Role Bindings", }, { name: "Pod Security Policies", href: "/pod-security-policies", expectedSelector: "h5.title", - expectedText: "Pod Security Policies" + expectedText: "Pod Security Policies", }, - ] + ], }, { drawerId: "custom-resources", @@ -312,9 +312,9 @@ const commonPageTests: CommonPageTest[] = [{ name: "Definitions", href: "/crd/definitions", expectedSelector: "h5.title", - expectedText: "Custom Resources" + expectedText: "Custom Resources", }, - ] + ], }]; utils.describeIf(minikubeReady(TEST_NAMESPACE))("Minikube based tests", () => { @@ -440,7 +440,7 @@ utils.describeIf(minikubeReady(TEST_NAMESPACE))("Minikube based tests", () => { position: { y: 0, x: 0, - } + }, }); } catch (error) { console.log(error); diff --git a/integration/helpers/utils.ts b/integration/helpers/utils.ts index a33b93a8f4..ad140d346e 100644 --- a/integration/helpers/utils.ts +++ b/integration/helpers/utils.ts @@ -69,7 +69,7 @@ export async function start() { bypassCSP: true, env: { CICD, - ...process.env + ...process.env, }, timeout: 100_000, } as Parameters[0]); diff --git a/package.json b/package.json index b78e05cabd..d8629829ab 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "productName": "OpenLens", "description": "OpenLens - Open Source IDE for Kubernetes", "homepage": "https://github.com/lensapp/lens", - "version": "5.3.0-alpha.6", + "version": "5.3.0-alpha.8", "main": "static/build/main.js", "copyright": "© 2021 OpenLens Authors", "license": "MIT", @@ -196,7 +196,7 @@ "electron-devtools-installer": "^3.2.0", "electron-updater": "^4.6.1", "electron-window-state": "^5.0.3", - "filehound": "^1.17.4", + "filehound": "^1.17.5", "fs-extra": "^9.0.1", "glob-to-regexp": "^0.4.1", "got": "^11.8.2", @@ -214,12 +214,12 @@ "md5-file": "^5.0.0", "mobx": "^6.3.0", "mobx-observable-history": "^2.0.1", - "mobx-react": "^7.2.0", + "mobx-react": "^7.2.1", "mock-fs": "^4.14.0", "moment": "^2.29.1", "moment-timezone": "^0.5.33", "monaco-editor": "^0.26.1", - "node-fetch": "^2.6.5", + "node-fetch": "^2.6.6", "node-pty": "^0.10.1", "npm": "^6.14.15", "p-limit": "^3.1.0", @@ -255,9 +255,8 @@ "@material-ui/lab": "^4.0.0-alpha.60", "@pmmmwh/react-refresh-webpack-plugin": "^0.4.3", "@sentry/types": "^6.13.3", - "@testing-library/dom": "^8.9.0", - "@testing-library/jest-dom": "^5.14.1", - "@testing-library/react": "^11.2.6", + "@testing-library/jest-dom": "^5.15.0", + "@testing-library/react": "^11.2.7", "@testing-library/user-event": "^13.5.0", "@types/byline": "^4.2.33", "@types/chart.js": "^2.9.34", @@ -285,10 +284,10 @@ "@types/progress-bar-webpack-plugin": "^2.1.2", "@types/proper-lockfile": "^4.1.2", "@types/randomcolor": "^0.5.6", - "@types/react": "^17.0.29", + "@types/react": "^17.0.33", "@types/react-beautiful-dnd": "^13.1.2", "@types/react-dom": "^17.0.9", - "@types/react-router-dom": "^5.3.1", + "@types/react-router-dom": "^5.3.2", "@types/react-select": "3.1.2", "@types/react-table": "^7.7.7", "@types/react-virtualized-auto-sizer": "^1.0.1", @@ -296,9 +295,9 @@ "@types/readable-stream": "^2.3.11", "@types/request": "^2.48.7", "@types/request-promise-native": "^1.0.18", - "@types/semver": "^7.2.0", + "@types/semver": "^7.3.9", "@types/sharp": "^0.29.2", - "@types/spdy": "^3.4.4", + "@types/spdy": "^3.4.5", "@types/tar": "^4.0.5", "@types/tcp-port-used": "^1.0.0", "@types/tempy": "^0.3.0", @@ -310,7 +309,7 @@ "@types/webpack-env": "^1.16.3", "@types/webpack-node-externals": "^1.7.1", "@typescript-eslint/eslint-plugin": "^4.33.0", - "@typescript-eslint/parser": "^4.29.1", + "@typescript-eslint/parser": "^4.33.0", "ansi_up": "^5.0.1", "chart.js": "^2.9.4", "circular-dependency-plugin": "^5.2.2", @@ -319,7 +318,7 @@ "css-loader": "^5.2.7", "deepdash": "^5.3.9", "dompurify": "^2.3.3", - "electron": "13.6.0", + "electron": "^13.6.1", "electron-builder": "^22.11.11", "electron-notarize": "^0.3.0", "esbuild": "^0.13.8", @@ -345,7 +344,7 @@ "node-loader": "^1.0.3", "nodemon": "^2.0.14", "playwright": "^1.15.2", - "postcss": "^8.3.6", + "postcss": "^8.3.11", "postcss-loader": "4.3.0", "postinstall-postinstall": "^2.1.0", "progress-bar-webpack-plugin": "^2.1.0", @@ -357,17 +356,17 @@ "react-select": "3.2.0", "react-select-event": "^5.1.0", "react-table": "^7.7.0", - "react-window": "^1.8.5", - "sass": "^1.43.2", + "react-window": "^1.8.6", + "sass": "^1.43.4", "sass-loader": "^8.0.2", "sharp": "^0.29.2", "style-loader": "^2.0.0", "tailwindcss": "^2.2.17", "ts-jest": "26.5.6", "ts-loader": "^7.0.5", - "ts-node": "^10.3.0", + "ts-node": "^10.4.0", "type-fest": "^1.0.2", - "typed-emitter": "^1.3.1", + "typed-emitter": "^1.4.0", "typedoc": "0.22.7", "typedoc-plugin-markdown": "^3.11.3", "typeface-roboto": "^1.1.13", @@ -379,7 +378,7 @@ "webpack-dev-server": "^3.11.2", "webpack-node-externals": "^1.7.2", "what-input": "^5.2.10", - "xterm": "^4.12.0", + "xterm": "^4.14.1", "xterm-addon-fit": "^0.5.0" } } diff --git a/src/common/__tests__/catalog-category-registry.test.ts b/src/common/__tests__/catalog-category-registry.test.ts index 22d5527101..e400b6e819 100644 --- a/src/common/__tests__/catalog-category-registry.test.ts +++ b/src/common/__tests__/catalog-category-registry.test.ts @@ -34,8 +34,8 @@ class TestCatalogCategory extends CatalogCategory { group: "entity.k8slens.dev", versions: [], names: { - kind: "Test" - } + kind: "Test", + }, }; } @@ -50,8 +50,8 @@ class TestCatalogCategory2 extends CatalogCategory { group: "entity.k8slens.dev", versions: [], names: { - kind: "Test2" - } + kind: "Test2", + }, }; } diff --git a/src/common/__tests__/cluster-store.test.ts b/src/common/__tests__/cluster-store.test.ts index 33dd577635..1452dfadd5 100644 --- a/src/common/__tests__/cluster-store.test.ts +++ b/src/common/__tests__/cluster-store.test.ts @@ -84,7 +84,7 @@ jest.mock("electron", () => ({ removeAllListeners: jest.fn(), off: jest.fn(), send: jest.fn(), - } + }, })); AppPaths.init(); @@ -95,8 +95,8 @@ describe("empty config", () => { ClusterStore.resetInstance(); const mockOpts = { "tmp": { - "lens-cluster-store.json": JSON.stringify({}) - } + "lens-cluster-store.json": JSON.stringify({}), + }, }; mockFs(mockOpts); @@ -117,10 +117,10 @@ describe("empty config", () => { preferences: { terminalCWD: "/tmp", icon: "data:image/jpeg;base64, iVBORw0KGgoAAAANSUhEUgAAA1wAAAKoCAYAAABjkf5", - clusterName: "minikube" + clusterName: "minikube", }, - kubeConfigPath: embed("foo", kubeconfig) - }) + kubeConfigPath: embed("foo", kubeconfig), + }), ); }); @@ -141,17 +141,17 @@ describe("empty config", () => { id: "prod", contextName: "foo", preferences: { - clusterName: "prod" + clusterName: "prod", }, - kubeConfigPath: embed("prod", kubeconfig) + kubeConfigPath: embed("prod", kubeconfig), }); store.addCluster({ id: "dev", contextName: "foo2", preferences: { - clusterName: "dev" + clusterName: "dev", }, - kubeConfigPath: embed("dev", kubeconfig) + kubeConfigPath: embed("dev", kubeconfig), }); }); @@ -177,8 +177,8 @@ describe("config with existing clusters", () => { "lens-cluster-store.json": JSON.stringify({ __internal__: { migrations: { - version: "99.99.99" - } + version: "99.99.99", + }, }, clusters: [ { @@ -186,13 +186,13 @@ describe("config with existing clusters", () => { kubeConfigPath: "./temp-kube-config", contextName: "foo", preferences: { terminalCWD: "/foo" }, - workspace: "default" + workspace: "default", }, { id: "cluster2", kubeConfigPath: "./temp-kube-config", contextName: "foo2", - preferences: { terminalCWD: "/foo2" } + preferences: { terminalCWD: "/foo2" }, }, { id: "cluster3", @@ -200,11 +200,11 @@ describe("config with existing clusters", () => { contextName: "foo", preferences: { terminalCWD: "/foo" }, workspace: "foo", - ownerRef: "foo" + ownerRef: "foo", }, - ] - }) - } + ], + }), + }, }; mockFs(mockOpts); @@ -265,8 +265,8 @@ users: "lens-cluster-store.json": JSON.stringify({ __internal__: { migrations: { - version: "99.99.99" - } + version: "99.99.99", + }, }, clusters: [ { @@ -281,12 +281,12 @@ users: kubeConfigPath: "./valid-kube-config", contextName: "foo", preferences: { terminalCWD: "/foo" }, - workspace: "default" + workspace: "default", }, - ] - }) - } + ], + }), + }, }; mockFs(mockOpts); @@ -326,7 +326,7 @@ const minimalValidKubeConfig = JSON.stringify({ user: { "client-certificate": "/Users/foo/.minikube/client.crt", "client-key": "/Users/foo/.minikube/client.key", - } + }, }], kind: "Config", preferences: {}, @@ -340,12 +340,12 @@ describe("pre 2.0 config with an existing cluster", () => { "lens-cluster-store.json": JSON.stringify({ __internal__: { migrations: { - version: "1.0.0" - } + version: "1.0.0", + }, }, cluster1: minimalValidKubeConfig, - }) - } + }), + }, }; mockFs(mockOpts); @@ -372,8 +372,8 @@ describe("pre 2.6.0 config with a cluster that has arrays in auth config", () => "lens-cluster-store.json": JSON.stringify({ __internal__: { migrations: { - version: "2.4.1" - } + version: "2.4.1", + }, }, cluster1: { kubeConfig: JSON.stringify({ @@ -403,19 +403,19 @@ describe("pre 2.6.0 config with a cluster that has arrays in auth config", () => "auth-provider": { config: { "access-token": [ - "should be string" + "should be string", ], expiry: [ - "should be string" + "should be string", ], - } - } + }, + }, }, - }] + }], }), }, - }) - } + }), + }, }; mockFs(mockOpts); @@ -445,19 +445,19 @@ describe("pre 2.6.0 config with a cluster icon", () => { "lens-cluster-store.json": JSON.stringify({ __internal__: { migrations: { - version: "2.4.1" - } + version: "2.4.1", + }, }, cluster1: { kubeConfig: minimalValidKubeConfig, icon: "icon_path", preferences: { - terminalCWD: "/tmp" - } + terminalCWD: "/tmp", + }, }, }), "icon_path": testDataIcon, - } + }, }; mockFs(mockOpts); @@ -486,17 +486,17 @@ describe("for a pre 2.7.0-beta.0 config without a workspace", () => { "lens-cluster-store.json": JSON.stringify({ __internal__: { migrations: { - version: "2.6.6" - } + version: "2.6.6", + }, }, cluster1: { kubeConfig: minimalValidKubeConfig, preferences: { - terminalCWD: "/tmp" - } + terminalCWD: "/tmp", + }, }, - }) - } + }), + }, }; mockFs(mockOpts); @@ -517,8 +517,8 @@ describe("pre 3.6.0-beta.1 config with an existing cluster", () => { "lens-cluster-store.json": JSON.stringify({ __internal__: { migrations: { - version: "3.5.0" - } + version: "3.5.0", + }, }, clusters: [ { @@ -527,12 +527,12 @@ describe("pre 3.6.0-beta.1 config with an existing cluster", () => { contextName: "cluster", preferences: { icon: "store://icon_path", - } - } - ] + }, + }, + ], }), "icon_path": testDataIcon, - } + }, }; mockFs(mockOpts); diff --git a/src/common/__tests__/event-bus.test.ts b/src/common/__tests__/event-bus.test.ts index acc1b70d26..92e4d0628c 100644 --- a/src/common/__tests__/event-bus.test.ts +++ b/src/common/__tests__/event-bus.test.ts @@ -34,7 +34,7 @@ describe("event bus tests", () => { event = data; }); - appEventBus.emit({name: "foo", action: "bar"}); + appEventBus.emit({ name: "foo", action: "bar" }); expect(event.name).toBe("foo"); }); }); diff --git a/src/common/__tests__/hotbar-store.test.ts b/src/common/__tests__/hotbar-store.test.ts index a5632e06a0..092754394d 100644 --- a/src/common/__tests__/hotbar-store.test.ts +++ b/src/common/__tests__/hotbar-store.test.ts @@ -33,25 +33,25 @@ jest.mock("../../main/catalog/catalog-entity-registry", () => ({ metadata: { uid: "1dfa26e2ebab15780a3547e9c7fa785c", name: "mycluster", - source: "local" - } + source: "local", + }, }, { metadata: { uid: "55b42c3c7ba3b04193416cda405269a5", name: "my_shiny_cluster", - source: "remote" - } + source: "remote", + }, }, { metadata: { uid: "catalog-entity", name: "Catalog", - source: "app" + source: "app", }, }, - ] - } + ], + }, })); const testCluster = { @@ -60,7 +60,7 @@ const testCluster = { apiVersion: "v1", kind: "Cluster", status: { - phase: "Running" + phase: "Running", }, spec: {}, getName: jest.fn(), @@ -71,8 +71,8 @@ const testCluster = { metadata: { uid: "test", name: "test", - labels: {} - } + labels: {}, + }, }; const minikubeCluster = { @@ -81,7 +81,7 @@ const minikubeCluster = { apiVersion: "v1", kind: "Cluster", status: { - phase: "Running" + phase: "Running", }, spec: {}, getName: jest.fn(), @@ -92,8 +92,8 @@ const minikubeCluster = { metadata: { uid: "minikube", name: "minikube", - labels: {} - } + labels: {}, + }, }; const awsCluster = { @@ -102,7 +102,7 @@ const awsCluster = { apiVersion: "v1", kind: "Cluster", status: { - phase: "Running" + phase: "Running", }, spec: {}, getName: jest.fn(), @@ -113,8 +113,8 @@ const awsCluster = { metadata: { uid: "aws", name: "aws", - labels: {} - } + labels: {}, + }, }; jest.mock("electron", () => ({ @@ -139,8 +139,8 @@ describe("HotbarStore", () => { beforeEach(() => { mockFs({ "tmp": { - "lens-hotbar-store.json": JSON.stringify({}) - } + "lens-hotbar-store.json": JSON.stringify({}), + }, }); ClusterStore.createInstance(); HotbarStore.createInstance(); @@ -351,8 +351,8 @@ describe("HotbarStore", () => { "lens-hotbar-store.json": JSON.stringify({ __internal__: { migrations: { - version: "5.0.0-beta.3" - } + version: "5.0.0-beta.3", + }, }, "hotbars": [ { @@ -361,51 +361,51 @@ describe("HotbarStore", () => { "items": [ { "entity": { - "uid": "1dfa26e2ebab15780a3547e9c7fa785c" - } + "uid": "1dfa26e2ebab15780a3547e9c7fa785c", + }, }, { "entity": { - "uid": "55b42c3c7ba3b04193416cda405269a5" - } + "uid": "55b42c3c7ba3b04193416cda405269a5", + }, }, { "entity": { - "uid": "176fd331968660832f62283219d7eb6e" - } + "uid": "176fd331968660832f62283219d7eb6e", + }, }, { "entity": { "uid": "61c4fb45528840ebad1badc25da41d14", "name": "user1-context", - "source": "local" - } + "source": "local", + }, }, { "entity": { "uid": "27d6f99fe9e7548a6e306760bfe19969", "name": "foo2", - "source": "local" - } + "source": "local", + }, }, null, { "entity": { "uid": "c0b20040646849bb4dcf773e43a0bf27", "name": "multinode-demo", - "source": "local" - } + "source": "local", + }, }, null, null, null, null, - null - ] - } + null, + ], + }, ], - }) - } + }), + }, }; mockFs(mockOpts); @@ -436,16 +436,16 @@ describe("HotbarStore", () => { entity: { name: "mycluster", source: "local", - uid: "1dfa26e2ebab15780a3547e9c7fa785c" - } + uid: "1dfa26e2ebab15780a3547e9c7fa785c", + }, }); expect(items[1]).toEqual({ entity: { name: "my_shiny_cluster", source: "remote", - uid: "55b42c3c7ba3b04193416cda405269a5" - } + uid: "55b42c3c7ba3b04193416cda405269a5", + }, }); }); }); diff --git a/src/common/__tests__/kube-helpers.test.ts b/src/common/__tests__/kube-helpers.test.ts index 277398ee02..cbc3d6bd6f 100644 --- a/src/common/__tests__/kube-helpers.test.ts +++ b/src/common/__tests__/kube-helpers.test.ts @@ -100,7 +100,7 @@ describe("kube helpers", () => { describe("with invalid context object", () => { it("returns an error", () => { expect(String(validateKubeConfig(kc, "invalid"))).toEqual( - expect.stringContaining("No valid context object provided in kubeconfig for context 'invalid'") + expect.stringContaining("No valid context object provided in kubeconfig for context 'invalid'"), ); }); }); @@ -108,7 +108,7 @@ describe("kube helpers", () => { describe("with invalid cluster object", () => { it("returns an error", () => { expect(String(validateKubeConfig(kc, "invalidCluster"))).toEqual( - expect.stringContaining("No valid cluster object provided in kubeconfig for context 'invalidCluster'") + expect.stringContaining("No valid cluster object provided in kubeconfig for context 'invalidCluster'"), ); }); }); @@ -116,7 +116,7 @@ describe("kube helpers", () => { describe("with invalid user object", () => { it("returns an error", () => { expect(String(validateKubeConfig(kc, "invalidUser"))).toEqual( - expect.stringContaining("No valid user object provided in kubeconfig for context 'invalidUser'") + expect.stringContaining("No valid user object provided in kubeconfig for context 'invalidUser'"), ); }); }); @@ -174,7 +174,7 @@ describe("kube helpers", () => { }); it("multiple context is ok", async () => { - mockKubeConfig.contexts.push({context: {cluster: "cluster-2", user: "cluster-2"}, name: "cluster-2"}); + mockKubeConfig.contexts.push({ context: { cluster: "cluster-2", user: "cluster-2" }, name: "cluster-2" }); const { config } = loadConfigFromString(JSON.stringify(mockKubeConfig)); expect(config.getCurrentContext()).toBe("minikube"); @@ -209,7 +209,7 @@ describe("kube helpers", () => { }); it("empty name in context causes it to be removed", async () => { - mockKubeConfig.contexts.push({context: {cluster: "cluster-2", user: "cluster-2"}, name: ""}); + mockKubeConfig.contexts.push({ context: { cluster: "cluster-2", user: "cluster-2" }, name: "" }); expect(mockKubeConfig.contexts.length).toBe(2); const { config } = loadConfigFromString(JSON.stringify(mockKubeConfig)); @@ -218,7 +218,7 @@ describe("kube helpers", () => { }); it("empty cluster in context causes it to be removed", async () => { - mockKubeConfig.contexts.push({context: {cluster: "", user: "cluster-2"}, name: "cluster-2"}); + mockKubeConfig.contexts.push({ context: { cluster: "", user: "cluster-2" }, name: "cluster-2" }); expect(mockKubeConfig.contexts.length).toBe(2); const { config } = loadConfigFromString(JSON.stringify(mockKubeConfig)); @@ -227,7 +227,7 @@ describe("kube helpers", () => { }); it("empty user in context causes it to be removed", async () => { - mockKubeConfig.contexts.push({context: {cluster: "cluster-2", user: ""}, name: "cluster-2"}); + mockKubeConfig.contexts.push({ context: { cluster: "cluster-2", user: "" }, name: "cluster-2" }); expect(mockKubeConfig.contexts.length).toBe(2); const { config } = loadConfigFromString(JSON.stringify(mockKubeConfig)); @@ -236,8 +236,8 @@ describe("kube helpers", () => { }); it("invalid context in between valid contexts is removed", async () => { - mockKubeConfig.contexts.push({context: {cluster: "cluster-2", user: ""}, name: "cluster-2"}); - mockKubeConfig.contexts.push({context: {cluster: "cluster-3", user: "cluster-3"}, name: "cluster-3"}); + mockKubeConfig.contexts.push({ context: { cluster: "cluster-2", user: "" }, name: "cluster-2" }); + mockKubeConfig.contexts.push({ context: { cluster: "cluster-3", user: "cluster-3" }, name: "cluster-3" }); expect(mockKubeConfig.contexts.length).toBe(3); const { config } = loadConfigFromString(JSON.stringify(mockKubeConfig)); diff --git a/src/common/__tests__/search-store.test.ts b/src/common/__tests__/search-store.test.ts index abd6cd1510..b83477d42d 100644 --- a/src/common/__tests__/search-store.test.ts +++ b/src/common/__tests__/search-store.test.ts @@ -37,7 +37,7 @@ let searchStore: SearchStore = null; const logs = [ "1:M 30 Oct 2020 16:17:41.553 # Connection with replica 172.17.0.12:6379 lost", "1:M 30 Oct 2020 16:17:41.623 * Replica 172.17.0.12:6379 asks for synchronization", - "1:M 30 Oct 2020 16:17:41.623 * Starting Partial resynchronization request from 172.17.0.12:6379 accepted. Sending 0 bytes of backlog starting from offset 14407." + "1:M 30 Oct 2020 16:17:41.623 * Starting Partial resynchronization request from 172.17.0.12:6379 accepted. Sending 0 bytes of backlog starting from offset 14407.", ]; describe("search store tests", () => { diff --git a/src/common/__tests__/system-ca.test.ts b/src/common/__tests__/system-ca.test.ts new file mode 100644 index 0000000000..d1fd836c17 --- /dev/null +++ b/src/common/__tests__/system-ca.test.ts @@ -0,0 +1,113 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +import https from "https"; +import os from "os"; +import { getMacRootCA, getWinRootCA, injectCAs, DSTRootCAX3 } from "../system-ca"; +import { dependencies, devDependencies } from "../../../package.json"; + +const deps = { ...dependencies, ...devDependencies }; + +// Skip the test if mac-ca is not installed, or os is not darwin +(deps["mac-ca"] && os.platform().includes("darwin") ? describe: describe.skip)("inject CA for Mac", () => { + // for reset https.globalAgent.options.ca after testing + let _ca: string | Buffer | (string | Buffer)[]; + + beforeEach(() => { + _ca = https.globalAgent.options.ca; + }); + + afterEach(() => { + https.globalAgent.options.ca = _ca; + }); + + /** + * The test to ensure using getMacRootCA + injectCAs injects CAs in the same way as using + * the auto injection (require('mac-ca')) + */ + it("should inject the same ca as mac-ca", async () => { + const osxCAs = await getMacRootCA(); + + injectCAs(osxCAs); + const injected = https.globalAgent.options.ca as (string | Buffer)[]; + + await import("mac-ca"); + const injectedByMacCA = https.globalAgent.options.ca as (string | Buffer)[]; + + expect(new Set(injected)).toEqual(new Set(injectedByMacCA)); + }); + + it("shouldn't included the expired DST Root CA X3 on Mac", async () => { + const osxCAs = await getMacRootCA(); + + injectCAs(osxCAs); + const injected = https.globalAgent.options.ca; + + expect(injected.includes(DSTRootCAX3)).toBeFalsy(); + }); +}); + +// Skip the test if win-ca is not installed, or os is not win32 +(deps["win-ca"] && os.platform().includes("win32") ? describe: describe.skip)("inject CA for Windows", () => { + // for reset https.globalAgent.options.ca after testing + let _ca: string | Buffer | (string | Buffer)[]; + + beforeEach(() => { + _ca = https.globalAgent.options.ca; + }); + + afterEach(() => { + https.globalAgent.options.ca = _ca; + }); + + /** + * The test to ensure using win-ca/api injects CAs in the same way as using + * the auto injection (require('win-ca').inject('+')) + */ + it("should inject the same ca as winca.inject('+')", async () => { + const winCAs = await getWinRootCA(); + + const wincaAPI = await import("win-ca/api"); + + wincaAPI.inject("+", winCAs); + const injected = https.globalAgent.options.ca as (string | Buffer)[]; + + const winca = await import("win-ca"); + + winca.inject("+"); // see: https://github.com/ukoloff/win-ca#caveats + const injectedByWinCA = https.globalAgent.options.ca as (string | Buffer)[]; + + expect(new Set(injected)).toEqual(new Set(injectedByWinCA)); + }); + + it("shouldn't included the expired DST Root CA X3 on Windows", async () => { + const winCAs = await getWinRootCA(); + + const wincaAPI = await import("win-ca/api"); + + wincaAPI.inject("true", winCAs); + const injected = https.globalAgent.options.ca as (string | Buffer)[]; + + expect(injected.includes(DSTRootCAX3)).toBeFalsy(); + }); +}); + + + diff --git a/src/common/__tests__/user-store.test.ts b/src/common/__tests__/user-store.test.ts index adfe5ecf4b..ba7272f4c9 100644 --- a/src/common/__tests__/user-store.test.ts +++ b/src/common/__tests__/user-store.test.ts @@ -52,7 +52,7 @@ AppPaths.init(); describe("user store tests", () => { describe("for an empty config", () => { beforeEach(() => { - mockFs({ tmp: { "config.json": "{}", "kube_config": "{}" } }); + mockFs({ tmp: { "config.json": "{}", "kube_config": "{}" }}); (UserStore.createInstance() as any).refreshNewContexts = jest.fn(() => Promise.resolve()); }); @@ -106,7 +106,7 @@ describe("user store tests", () => { "config.json": JSON.stringify({ user: { username: "foobar" }, preferences: { colorTheme: "light" }, - lastSeenAppVersion: "1.2.3" + lastSeenAppVersion: "1.2.3", }), "lens-cluster-store.json": JSON.stringify({ clusters: [ @@ -118,15 +118,15 @@ describe("user store tests", () => { id: "barfoo", kubeConfigPath: "some/other/path", }, - ] + ], } as ClusterStoreModel), "extension_data": {}, }, "some": { "other": { "path": "is file", - } - } + }, + }, }); UserStore.createInstance(); diff --git a/src/common/catalog-entities/__tests__/kubernetes-cluster.test.ts b/src/common/catalog-entities/__tests__/kubernetes-cluster.test.ts index d14a093ee5..4ad026fb32 100644 --- a/src/common/catalog-entities/__tests__/kubernetes-cluster.test.ts +++ b/src/common/catalog-entities/__tests__/kubernetes-cluster.test.ts @@ -26,13 +26,13 @@ describe("kubernetesClusterCategory", () => { icon: "Icon", title: "Title", // eslint-disable-next-line @typescript-eslint/no-empty-function - onClick: () => {} + onClick: () => {}, }; const item2 = { icon: "Icon 2", title: "Title 2", // eslint-disable-next-line @typescript-eslint/no-empty-function - onClick: () => {} + onClick: () => {}, }; it("returns all items if no filter set", () => { diff --git a/src/common/catalog-entities/general.ts b/src/common/catalog-entities/general.ts index 5d13eeabee..228d3a1bed 100644 --- a/src/common/catalog-entities/general.ts +++ b/src/common/catalog-entities/general.ts @@ -57,19 +57,19 @@ export class GeneralCategory extends CatalogCategory { public readonly kind = "CatalogCategory"; public metadata = { name: "General", - icon: "settings" + icon: "settings", }; public spec = { group: "entity.k8slens.dev", versions: [ { name: "v1alpha1", - entityClass: GeneralEntity - } + entityClass: GeneralEntity, + }, ], names: { - kind: "General" - } + kind: "General", + }, }; } diff --git a/src/common/catalog-entities/kubernetes-cluster.ts b/src/common/catalog-entities/kubernetes-cluster.ts index 8a3c3e0858..02bfaf532f 100644 --- a/src/common/catalog-entities/kubernetes-cluster.ts +++ b/src/common/catalog-entities/kubernetes-cluster.ts @@ -59,7 +59,7 @@ export enum LensKubernetesClusterStatus { DELETING = "deleting", CONNECTING = "connecting", CONNECTED = "connected", - DISCONNECTED = "disconnected" + DISCONNECTED = "disconnected", } export interface KubernetesClusterMetadata extends CatalogEntityMetadata { @@ -128,14 +128,14 @@ export class KubernetesCluster extends CatalogEntity requestMain(clusterDisconnectHandler, this.metadata.uid) + onClick: () => requestMain(clusterDisconnectHandler, this.metadata.uid), }); break; case LensKubernetesClusterStatus.DISCONNECTED: context.menuItems.push({ title: "Connect", icon: "link", - onClick: () => context.navigate(`/cluster/${this.metadata.uid}`) + onClick: () => context.navigate(`/cluster/${this.metadata.uid}`), }); break; } @@ -158,12 +158,12 @@ class KubernetesClusterCategory extends CatalogCategory { versions: [ { name: "v1alpha1", - entityClass: KubernetesCluster - } + entityClass: KubernetesCluster, + }, ], names: { - kind: "KubernetesCluster" - } + kind: "KubernetesCluster", + }, }; } diff --git a/src/common/catalog-entities/web-link.ts b/src/common/catalog-entities/web-link.ts index a613a7e44e..870558e0b3 100644 --- a/src/common/catalog-entities/web-link.ts +++ b/src/common/catalog-entities/web-link.ts @@ -56,8 +56,8 @@ export class WebLink extends CatalogEntity WeblinkStore.getInstance().removeById(this.metadata.uid), confirm: { - message: `Remove Web Link "${this.metadata.name}" from ${productName}?` - } + message: `Remove Web Link "${this.metadata.name}" from ${productName}?`, + }, }); } @@ -72,19 +72,19 @@ export class WebLinkCategory extends CatalogCategory { public readonly kind = "CatalogCategory"; public metadata = { name: "Web Links", - icon: "public" + icon: "public", }; public spec = { group: "entity.k8slens.dev", versions: [ { name: "v1alpha1", - entityClass: WebLink - } + entityClass: WebLink, + }, ], names: { - kind: "WebLink" - } + kind: "WebLink", + }, }; public static onAdd?: () => void; @@ -97,7 +97,7 @@ export class WebLinkCategory extends CatalogCategory { title: "Add web link", onClick: () => { WebLinkCategory.onAdd(); - } + }, }); }); } diff --git a/src/common/catalog/catalog-category-registry.ts b/src/common/catalog/catalog-category-registry.ts index 735911aa51..620d8d23d3 100644 --- a/src/common/catalog/catalog-category-registry.ts +++ b/src/common/catalog/catalog-category-registry.ts @@ -59,7 +59,7 @@ export class CatalogCategoryRegistry { this.filters, iter.filter, this.items.values(), - ) + ), ); } diff --git a/src/common/catalog/catalog-entity.ts b/src/common/catalog/catalog-entity.ts index 9d549f89de..9015dbd828 100644 --- a/src/common/catalog/catalog-entity.ts +++ b/src/common/catalog/catalog-entity.ts @@ -106,7 +106,7 @@ export abstract class CatalogCategory extends (EventEmitter as new () => TypedEm this.filters, iter.filter, menuItems.values(), - ) + ), ); } } diff --git a/src/common/cluster-types.ts b/src/common/cluster-types.ts index cdd498a419..0c40f9ebed 100644 --- a/src/common/cluster-types.ts +++ b/src/common/cluster-types.ts @@ -119,7 +119,7 @@ export interface ClusterPrometheusPreferences { export enum ClusterStatus { AccessGranted = 2, AccessDenied = 1, - Offline = 0 + Offline = 0, } /** @@ -131,7 +131,7 @@ export enum ClusterMetadataKey { DISTRIBUTION = "distribution", NODES_COUNT = "nodes", LAST_SEEN = "lastSeen", - PROMETHEUS = "prometheus" + PROMETHEUS = "prometheus", } /** diff --git a/src/common/getTSLoader.ts b/src/common/getTSLoader.ts index 6c76770d5d..8b64186f5d 100644 --- a/src/common/getTSLoader.ts +++ b/src/common/getTSLoader.ts @@ -23,27 +23,25 @@ import esbuild from "esbuild"; /** * A function returning webpack ts/tsx loader - * + * * depends on env LENS_DEV_USE_ESBUILD_LOADER to use esbuild-loader (faster) or good-old ts-loader - * - * @param testRegExp - the regex for webpack to conditional find the files + * + * @param testRegExp - the regex for webpack to conditional find the files * @returns ts/tsx webpack loader configuration object */ const getTSLoader = ( - testRegExp: RegExp, transpileOnly = true + testRegExp: RegExp, transpileOnly = true, ) => { - const useEsbuildLoader = process.env.LENS_DEV_USE_ESBUILD_LOADER === "true"; + if (process.env.LENS_DEV_USE_ESBUILD_LOADER === "true") { + console.info(`\n🚀 using esbuild-loader for ts(x)`); - useEsbuildLoader && console.info(`\n🚀 using esbuild-loader for ts(x)`); - - if (useEsbuildLoader) { return { test: testRegExp, loader: "esbuild-loader", options: { loader: "tsx", target: "es2015", - implementation: esbuild + implementation: esbuild, }, }; } @@ -55,8 +53,8 @@ const getTSLoader = ( loader: "ts-loader", options: { transpileOnly, - } - } + }, + }, }; }; diff --git a/src/common/hotbar-store.ts b/src/common/hotbar-store.ts index f7b7de642d..72705bf7bf 100644 --- a/src/common/hotbar-store.ts +++ b/src/common/hotbar-store.ts @@ -73,8 +73,8 @@ export class HotbarStore extends BaseStore { protected fromStore(data: Partial = {}) { if (!data.hotbars || !data.hotbars.length) { const hotbar = getEmptyHotbar("Default"); - const { metadata: { uid, name, source } } = catalogEntity; - const initialItem = { entity: { uid, name, source } }; + const { metadata: { uid, name, source }} = catalogEntity; + const initialItem = { entity: { uid, name, source }}; hotbar.items[0] = initialItem; @@ -99,7 +99,7 @@ export class HotbarStore extends BaseStore { toJSON(): HotbarStoreModel { const model: HotbarStoreModel = { hotbars: this.hotbars, - activeHotbarId: this.activeHotbarId + activeHotbarId: this.activeHotbarId, }; return toJS(model); @@ -187,7 +187,7 @@ export class HotbarStore extends BaseStore { } else if (0 <= cellIndex && cellIndex < hotbar.items.length) { hotbar.items[cellIndex] = newItem; } else { - logger.error(`[HOTBAR-STORE]: cannot pin entity to hotbar outside of index range`, { entityId: uid, hotbarId: hotbar.id, cellIndex, }); + logger.error(`[HOTBAR-STORE]: cannot pin entity to hotbar outside of index range`, { entityId: uid, hotbarId: hotbar.id, cellIndex }); } } diff --git a/src/common/ipc/ipc.ts b/src/common/ipc/ipc.ts index 9ed51b7790..4a8b4f1f8d 100644 --- a/src/common/ipc/ipc.ts +++ b/src/common/ipc/ipc.ts @@ -49,20 +49,20 @@ function getSubFrames(): ClusterFrameInfo[] { } export function broadcastMessage(channel: string, ...args: any[]) { - const views: undefined | ReturnType | ReturnType = (webContents || electronRemote?.webContents)?.getAllWebContents(); - - if (!views || !Array.isArray(views) || views.length === 0) return; - args = args.map(sanitizePayload); - - ipcRenderer?.send(channel, ...args); - ipcMain?.emit(channel, ...args); - const subFramesP = ipcRenderer ? requestMain(subFramesChannel) : Promise.resolve(getSubFrames()); subFramesP .then(subFrames => { + const views: undefined | ReturnType | ReturnType = (webContents || electronRemote?.webContents)?.getAllWebContents(); + + if (!views || !Array.isArray(views) || views.length === 0) return; + args = args.map(sanitizePayload); + + ipcRenderer?.send(channel, ...args); + ipcMain?.emit(channel, ...args); + for (const view of views) { let viewType = "unknown"; diff --git a/src/common/ipc/type-enforced-ipc.ts b/src/common/ipc/type-enforced-ipc.ts index 95d4327b3e..29d0305b52 100644 --- a/src/common/ipc/type-enforced-ipc.ts +++ b/src/common/ipc/type-enforced-ipc.ts @@ -38,7 +38,7 @@ export type Rest = T extends [any, ...infer R] ? R : []; */ export function onceCorrect< IPC extends EventEmitter, - Listener extends (event: ListenerEvent, ...args: any[]) => any + Listener extends (event: ListenerEvent, ...args: any[]) => any, >({ source, channel, @@ -72,7 +72,7 @@ export function onceCorrect< */ export function onCorrect< IPC extends EventEmitter, - Listener extends (event: ListenerEvent, ...args: any[]) => any + Listener extends (event: ListenerEvent, ...args: any[]) => any, >({ source, channel, diff --git a/src/common/k8s-api/__tests__/crd.test.ts b/src/common/k8s-api/__tests__/crd.test.ts index a981cdda12..7e4d255d15 100644 --- a/src/common/k8s-api/__tests__/crd.test.ts +++ b/src/common/k8s-api/__tests__/crd.test.ts @@ -119,7 +119,7 @@ describe("Crds", () => { }, spec: { version: "abc", - } + }, }); expect(crd.getVersion()).toBe("abc"); diff --git a/src/common/k8s-api/__tests__/deployment.api.test.ts b/src/common/k8s-api/__tests__/deployment.api.test.ts index 65d9c93434..aeb3397106 100644 --- a/src/common/k8s-api/__tests__/deployment.api.test.ts +++ b/src/common/k8s-api/__tests__/deployment.api.test.ts @@ -41,19 +41,19 @@ describe("DeploymentApi", () => { it("requests Kubernetes API with PATCH verb and correct amount of replicas", () => { const patchSpy = jest.spyOn(requestMock, "patch"); - sub.scale({ namespace: "default", name: "deployment-1"}, 5); + sub.scale({ namespace: "default", name: "deployment-1" }, 5); expect(patchSpy).toHaveBeenCalledWith("/apis/apps/v1/namespaces/default/deployments/deployment-1/scale", { data: { spec: { - replicas: 5 - } - } + replicas: 5, + }, + }, }, { headers: { - "content-type": "application/merge-patch+json" - } + "content-type": "application/merge-patch+json", + }, }); }); }); diff --git a/src/common/k8s-api/__tests__/helm-charts.api.test.ts b/src/common/k8s-api/__tests__/helm-charts.api.test.ts index 43efd504b3..aa56826480 100644 --- a/src/common/k8s-api/__tests__/helm-charts.api.test.ts +++ b/src/common/k8s-api/__tests__/helm-charts.api.test.ts @@ -282,7 +282,7 @@ describe("HelmChart tests", () => { expect(warnFn).toHaveBeenCalledWith("HelmChart data has unexpected fields", { original: anyObject(), - unknownFields: ["asdjhajksdhadjks"] + unknownFields: ["asdjhajksdhadjks"], }); console.warn = warn; }); diff --git a/src/common/k8s-api/__tests__/kube-api-parse.test.ts b/src/common/k8s-api/__tests__/kube-api-parse.test.ts index 18b805212d..d8995673cf 100644 --- a/src/common/k8s-api/__tests__/kube-api-parse.test.ts +++ b/src/common/k8s-api/__tests__/kube-api-parse.test.ts @@ -26,7 +26,7 @@ jest.mock("../api-manager", () => ({ return { registerStore: jest.fn(), }; - } + }, })); import { IKubeApiParsed, parseKubeApi } from "../kube-api-parse"; @@ -45,7 +45,7 @@ const tests: KubeApiParseTestData[] = [ apiVersionWithGroup: "apiextensions.k8s.io/v1beta1", namespace: undefined, resource: "customresourcedefinitions", - name: "prometheuses.monitoring.coreos.com" + name: "prometheuses.monitoring.coreos.com", }], ["/api/v1/namespaces/kube-system/pods/coredns-6955765f44-v8p27", { apiBase: "/api/v1/pods", @@ -55,7 +55,7 @@ const tests: KubeApiParseTestData[] = [ apiVersionWithGroup: "v1", namespace: "kube-system", resource: "pods", - name: "coredns-6955765f44-v8p27" + name: "coredns-6955765f44-v8p27", }], ["/apis/stable.example.com/foo1/crontabs", { apiBase: "/apis/stable.example.com/foo1/crontabs", @@ -132,7 +132,7 @@ const tests: KubeApiParseTestData[] = [ const throwtests = [ undefined, "", - "ajklsmh" + "ajklsmh", ]; describe("parseApi unit tests", () => { diff --git a/src/common/k8s-api/__tests__/kube-api.test.ts b/src/common/k8s-api/__tests__/kube-api.test.ts index 363d3176f5..3cd0768689 100644 --- a/src/common/k8s-api/__tests__/kube-api.test.ts +++ b/src/common/k8s-api/__tests__/kube-api.test.ts @@ -28,11 +28,11 @@ describe("forRemoteCluster", () => { it("builds api client", async (done) => { const api = forRemoteCluster({ cluster: { - server: "https://127.0.0.1:6443" + server: "https://127.0.0.1:6443", }, user: { - token: "daa" - } + token: "daa", + }, }, Pod); (fetch as any).mockResponse(async (request: any) => { @@ -41,7 +41,7 @@ describe("forRemoteCluster", () => { done(); return { - body: "" + body: "", }; }); @@ -55,7 +55,7 @@ describe("KubeApi", () => { beforeEach(() => { request = new KubeJsonApi({ serverAddress: `http://127.0.0.1:9999`, - apiBase: "/api-kube" + apiBase: "/api-kube", }); }); @@ -65,24 +65,24 @@ describe("KubeApi", () => { return { body: JSON.stringify({ resources: [{ - name: "ingresses" - }] as any[] - }) + name: "ingresses", + }] as any[], + }), }; } else if (request.url === "http://127.0.0.1:9999/api-kube/apis/extensions/v1beta1") { // Even if the old API contains ingresses, KubeApi should prefer the apiBase url return { body: JSON.stringify({ resources: [{ - name: "ingresses" - }] as any[] - }) + name: "ingresses", + }] as any[], + }), }; } else { return { body: JSON.stringify({ - resources: [] as any[] - }) + resources: [] as any[], + }), }; } }); @@ -107,22 +107,22 @@ describe("KubeApi", () => { if (request.url === "http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1") { return { body: JSON.stringify({ - resources: [] as any[] - }) + resources: [] as any[], + }), }; } else if (request.url === "http://127.0.0.1:9999/api-kube/apis/extensions/v1beta1") { return { body: JSON.stringify({ resources: [{ - name: "ingresses" - }] as any[] - }) + name: "ingresses", + }] as any[], + }), }; } else { return { body: JSON.stringify({ - resources: [] as any[] - }) + resources: [] as any[], + }), }; } }); diff --git a/src/common/k8s-api/__tests__/kube-object.test.ts b/src/common/k8s-api/__tests__/kube-object.test.ts index 230f5c9d79..cb2a412a5e 100644 --- a/src/common/k8s-api/__tests__/kube-object.test.ts +++ b/src/common/k8s-api/__tests__/kube-object.test.ts @@ -45,12 +45,12 @@ describe("KubeObject", () => { { type TestCase = [string, any]; const tests: TestCase[] = [ - ["kind", { apiVersion: "", metadata: {uid: "", name: "", resourceVersion: "", selfLink: ""} }], - ["apiVersion", { kind: "", metadata: {uid: "", name: "", resourceVersion: "", selfLink: ""} }], + ["kind", { apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "" }}], + ["apiVersion", { kind: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "" }}], ["metadata", { kind: "", apiVersion: "" }], - ["metadata.uid", { kind: "", apiVersion: "", metadata: { name: "", resourceVersion: "", selfLink: ""} }], - ["metadata.name", { kind: "", apiVersion: "", metadata: { uid: "", resourceVersion: "", selfLink: "" } }], - ["metadata.resourceVersion", { kind: "", apiVersion: "", metadata: { uid: "", name: "", selfLink: "" } }], + ["metadata.uid", { kind: "", apiVersion: "", metadata: { name: "", resourceVersion: "", selfLink: "" }}], + ["metadata.name", { kind: "", apiVersion: "", metadata: { uid: "", resourceVersion: "", selfLink: "" }}], + ["metadata.resourceVersion", { kind: "", apiVersion: "", metadata: { uid: "", name: "", selfLink: "" }}], ]; it.each(tests)("should reject with missing: %s", (missingField, input) => { @@ -61,23 +61,23 @@ describe("KubeObject", () => { { type TestCase = [string, any]; const tests: TestCase[] = [ - ["kind", { kind: 1, apiVersion: "", metadata: {} }], - ["apiVersion", { apiVersion: 1, kind: "", metadata: {} }], + ["kind", { kind: 1, apiVersion: "", metadata: {}}], + ["apiVersion", { apiVersion: 1, kind: "", metadata: {}}], ["metadata", { kind: "", apiVersion: "", metadata: "" }], - ["metadata.uid", { kind: "", apiVersion: "", metadata: { uid: 1 } }], - ["metadata.name", { kind: "", apiVersion: "", metadata: { uid: "", name: 1 } }], - ["metadata.resourceVersion", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: 1 } }], - ["metadata.selfLink", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: 1 } }], - ["metadata.namespace", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", namespace: 1 } }], - ["metadata.creationTimestamp", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", creationTimestamp: 1 } }], - ["metadata.continue", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", continue: 1 } }], - ["metadata.finalizers", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", finalizers: 1 } }], - ["metadata.finalizers", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", finalizers: [1] } }], - ["metadata.finalizers", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", finalizers: {} } }], - ["metadata.labels", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", labels: 1 } }], - ["metadata.labels", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", labels: { food: 1 } } }], - ["metadata.annotations", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", annotations: 1 } }], - ["metadata.annotations", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", annotations: { food: 1 } } }], + ["metadata.uid", { kind: "", apiVersion: "", metadata: { uid: 1 }}], + ["metadata.name", { kind: "", apiVersion: "", metadata: { uid: "", name: 1 }}], + ["metadata.resourceVersion", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: 1 }}], + ["metadata.selfLink", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: 1 }}], + ["metadata.namespace", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", namespace: 1 }}], + ["metadata.creationTimestamp", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", creationTimestamp: 1 }}], + ["metadata.continue", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", continue: 1 }}], + ["metadata.finalizers", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", finalizers: 1 }}], + ["metadata.finalizers", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", finalizers: [1] }}], + ["metadata.finalizers", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", finalizers: {}}}], + ["metadata.labels", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", labels: 1 }}], + ["metadata.labels", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", labels: { food: 1 }}}], + ["metadata.annotations", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", annotations: 1 }}], + ["metadata.annotations", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", annotations: { food: 1 }}}], ]; it.each(tests)("should reject with wrong type for field: %s", (missingField, input) => { @@ -86,7 +86,7 @@ describe("KubeObject", () => { } it("should accept valid KubeJsonApiData (ignoring other fields)", () => { - const valid = { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", annotations: { food: "" } } }; + const valid = { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", annotations: { food: "" }}}; expect(KubeObject.isJsonApiData(valid)).toBe(true); }); @@ -118,8 +118,8 @@ describe("KubeObject", () => { { type TestCase = [string, any]; const tests: TestCase[] = [ - ["kind", { apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "" } }], - ["apiVersion", { kind: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "" } }], + ["kind", { apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "" }}], + ["apiVersion", { kind: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "" }}], ["metadata", { kind: "", apiVersion: "" }], ]; @@ -131,23 +131,23 @@ describe("KubeObject", () => { { type TestCase = [string, any]; const tests: TestCase[] = [ - ["kind", { kind: 1, apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "" } }], - ["apiVersion", { apiVersion: 1, kind: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "" } }], + ["kind", { kind: 1, apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "" }}], + ["apiVersion", { apiVersion: 1, kind: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "" }}], ["metadata", { kind: "", apiVersion: "", metadata: "" }], - ["metadata.uid", { kind: "", apiVersion: "", metadata: { uid: 1, name: "", resourceVersion: "", selfLink: "" } }], - ["metadata.name", { kind: "", apiVersion: "", metadata: { uid: "", name: 1, resourceVersion: "", selfLink: "" } }], - ["metadata.resourceVersion", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: 1, selfLink: "" } }], - ["metadata.selfLink", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: 1 } }], - ["metadata.namespace", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", namespace: 1 } }], - ["metadata.creationTimestamp", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", creationTimestamp: 1 } }], - ["metadata.continue", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", continue: 1 } }], - ["metadata.finalizers", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", finalizers: 1 } }], - ["metadata.finalizers", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", finalizers: [1] } }], - ["metadata.finalizers", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", finalizers: {} } }], - ["metadata.labels", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", labels: 1 } }], - ["metadata.labels", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", labels: { food: 1 } } }], - ["metadata.annotations", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", annotations: 1 } }], - ["metadata.annotations", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", annotations: { food: 1 } } }], + ["metadata.uid", { kind: "", apiVersion: "", metadata: { uid: 1, name: "", resourceVersion: "", selfLink: "" }}], + ["metadata.name", { kind: "", apiVersion: "", metadata: { uid: "", name: 1, resourceVersion: "", selfLink: "" }}], + ["metadata.resourceVersion", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: 1, selfLink: "" }}], + ["metadata.selfLink", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: 1 }}], + ["metadata.namespace", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", namespace: 1 }}], + ["metadata.creationTimestamp", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", creationTimestamp: 1 }}], + ["metadata.continue", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", continue: 1 }}], + ["metadata.finalizers", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", finalizers: 1 }}], + ["metadata.finalizers", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", finalizers: [1] }}], + ["metadata.finalizers", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", finalizers: {}}}], + ["metadata.labels", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", labels: 1 }}], + ["metadata.labels", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", labels: { food: 1 }}}], + ["metadata.annotations", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", annotations: 1 }}], + ["metadata.annotations", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", annotations: { food: 1 }}}], ]; it.each(tests)("should reject with wrong type for field: %s", (missingField, input) => { @@ -156,7 +156,7 @@ describe("KubeObject", () => { } it("should accept valid Partial (ignoring other fields)", () => { - const valid = { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", annotations: { food: "" } } }; + const valid = { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", annotations: { food: "" }}}; expect(KubeObject.isPartialJsonApiData(valid)).toBe(true); }); @@ -197,8 +197,8 @@ describe("KubeObject", () => { { type TestCase = [string, any]; const tests: TestCase[] = [ - ["kind", { apiVersion: "", items: [], metadata: { resourceVersion: "", selfLink: "" } }], - ["apiVersion", { kind: "", items: [], metadata: { resourceVersion: "", selfLink: "" } }], + ["kind", { apiVersion: "", items: [], metadata: { resourceVersion: "", selfLink: "" }}], + ["apiVersion", { kind: "", items: [], metadata: { resourceVersion: "", selfLink: "" }}], ["metadata", { kind: "", items: [], apiVersion: "" }], ]; @@ -210,15 +210,15 @@ describe("KubeObject", () => { { type TestCase = [string, any]; const tests: TestCase[] = [ - ["kind", { kind: 1, items: [], apiVersion: "", metadata: { resourceVersion: "", selfLink: "" } }], - ["apiVersion", { kind: "", items: [], apiVersion: 1, metadata: { resourceVersion: "", selfLink: "" } }], + ["kind", { kind: 1, items: [], apiVersion: "", metadata: { resourceVersion: "", selfLink: "" }}], + ["apiVersion", { kind: "", items: [], apiVersion: 1, metadata: { resourceVersion: "", selfLink: "" }}], ["metadata", { kind: "", items: [], apiVersion: "", metadata: 1 }], - ["metadata.resourceVersion", { kind: "", items: [], apiVersion: "", metadata: { resourceVersion: 1, selfLink: "" } }], - ["metadata.selfLink", { kind: "", items: [], apiVersion: "", metadata: { resourceVersion: "", selfLink: 1 } }], - ["items", { kind: "", items: 1, apiVersion: "", metadata: { resourceVersion: "", selfLink: "" } }], - ["items", { kind: "", items: "", apiVersion: "", metadata: { resourceVersion: "", selfLink: "" } }], - ["items", { kind: "", items: {}, apiVersion: "", metadata: { resourceVersion: "", selfLink: "" } }], - ["items[0]", { kind: "", items: [""], apiVersion: "", metadata: { resourceVersion: "", selfLink: "" } }], + ["metadata.resourceVersion", { kind: "", items: [], apiVersion: "", metadata: { resourceVersion: 1, selfLink: "" }}], + ["metadata.selfLink", { kind: "", items: [], apiVersion: "", metadata: { resourceVersion: "", selfLink: 1 }}], + ["items", { kind: "", items: 1, apiVersion: "", metadata: { resourceVersion: "", selfLink: "" }}], + ["items", { kind: "", items: "", apiVersion: "", metadata: { resourceVersion: "", selfLink: "" }}], + ["items", { kind: "", items: {}, apiVersion: "", metadata: { resourceVersion: "", selfLink: "" }}], + ["items[0]", { kind: "", items: [""], apiVersion: "", metadata: { resourceVersion: "", selfLink: "" }}], ]; it.each(tests)("should reject with wrong type for field: %s", (missingField, input) => { @@ -227,7 +227,7 @@ describe("KubeObject", () => { } it("should accept valid KubeJsonApiDataList (ignoring other fields)", () => { - const valid = { kind: "", items: [false], apiVersion: "", metadata: { resourceVersion: "", selfLink: "" } }; + const valid = { kind: "", items: [false], apiVersion: "", metadata: { resourceVersion: "", selfLink: "" }}; expect(KubeObject.isJsonApiDataList(valid, isBoolean)).toBe(true); }); diff --git a/src/common/k8s-api/__tests__/pods.test.ts b/src/common/k8s-api/__tests__/pods.test.ts index 3315581d04..1066b019a8 100644 --- a/src/common/k8s-api/__tests__/pods.test.ts +++ b/src/common/k8s-api/__tests__/pods.test.ts @@ -45,8 +45,8 @@ function getDummyPod(opts: GetDummyPodOptions = getDummyPodDefaultOptions()): Po uid: "1", name: "test", resourceVersion: "v1", - selfLink: "http" - } + selfLink: "http", + }, }); pod.spec = { @@ -82,9 +82,9 @@ function getDummyPod(opts: GetDummyPodOptions = getDummyPodDefaultOptions()): Po restartCount: i, state: { running: { - startedAt: "before" + startedAt: "before", }, - } + }, }); } @@ -107,9 +107,9 @@ function getDummyPod(opts: GetDummyPodOptions = getDummyPodDefaultOptions()): Po startedAt: "before", exitCode: i+1, finishedAt: "later", - reason: `reason_${i}` - } - } + reason: `reason_${i}`, + }, + }, }); } @@ -129,9 +129,9 @@ function getDummyPod(opts: GetDummyPodOptions = getDummyPodDefaultOptions()): Po restartCount: i, state: { running: { - startedAt: "before" - } - } + startedAt: "before", + }, + }, }); } @@ -154,9 +154,9 @@ function getDummyPod(opts: GetDummyPodOptions = getDummyPodDefaultOptions()): Po startedAt: "before", exitCode: i+1, finishedAt: "later", - reason: `reason_${i}` - } - } + reason: `reason_${i}`, + }, + }, }); } @@ -183,7 +183,7 @@ describe("Pods", () => { return { image: "dummy", imagePullPolicy: "dummy", - name + name, }; } @@ -231,7 +231,7 @@ describe("Pods", () => { const pod = getDummyPod(); pod.spec.nodeSelector = { - "kubernetes.io/os": "foobar" + "kubernetes.io/os": "foobar", }; expect(pod.getSelectedNodeOs()).toStrictEqual("foobar"); @@ -241,7 +241,7 @@ describe("Pods", () => { const pod = getDummyPod(); pod.spec.nodeSelector = { - "beta.kubernetes.io/os": "foobar1" + "beta.kubernetes.io/os": "foobar1", }; expect(pod.getSelectedNodeOs()).toStrictEqual("foobar1"); @@ -252,7 +252,7 @@ describe("Pods", () => { pod.spec.nodeSelector = { "kubernetes.io/os": "foobar2", - "beta.kubernetes.io/os": "foobar3" + "beta.kubernetes.io/os": "foobar3", }; expect(pod.getSelectedNodeOs()).toStrictEqual("foobar2"); @@ -273,7 +273,7 @@ describe("Pods", () => { type: "Ready", status: "foobar", lastProbeTime: 1, - lastTransitionTime: "longer ago" + lastTransitionTime: "longer ago", }); expect(pod.hasIssues()).toStrictEqual(true); @@ -286,7 +286,7 @@ describe("Pods", () => { type: "dummy", status: "foobar", lastProbeTime: 1, - lastTransitionTime: "longer ago" + lastTransitionTime: "longer ago", }); expect(pod.hasIssues()).toStrictEqual(false); @@ -298,8 +298,8 @@ describe("Pods", () => { pod.status.containerStatuses[0].state = { waiting: { reason: "CrashLookBackOff", - message: "too much foobar" - } + message: "too much foobar", + }, }; expect(pod.hasIssues()).toStrictEqual(true); diff --git a/src/common/k8s-api/__tests__/stateful-set.api.test.ts b/src/common/k8s-api/__tests__/stateful-set.api.test.ts index d1b90be181..dbed3e31d4 100644 --- a/src/common/k8s-api/__tests__/stateful-set.api.test.ts +++ b/src/common/k8s-api/__tests__/stateful-set.api.test.ts @@ -41,19 +41,19 @@ describe("StatefulSetApi", () => { it("requests Kubernetes API with PATCH verb and correct amount of replicas", () => { const patchSpy = jest.spyOn(requestMock, "patch"); - sub.scale({ namespace: "default", name: "statefulset-1"}, 5); + sub.scale({ namespace: "default", name: "statefulset-1" }, 5); expect(patchSpy).toHaveBeenCalledWith("/apis/apps/v1/namespaces/default/statefulsets/statefulset-1/scale", { data: { spec: { - replicas: 5 - } - } + replicas: 5, + }, + }, }, { headers: { - "content-type": "application/merge-patch+json" - } + "content-type": "application/merge-patch+json", + }, }); }); }); diff --git a/src/common/k8s-api/api-manager.ts b/src/common/k8s-api/api-manager.ts index 3070f932be..99b2b03cd5 100644 --- a/src/common/k8s-api/api-manager.ts +++ b/src/common/k8s-api/api-manager.ts @@ -98,7 +98,7 @@ export class ApiManager { lookupApiLink(ref: IKubeObjectRef, parentObject: KubeObject): string { const { kind, apiVersion, name, - namespace = parentObject.getNs() + namespace = parentObject.getNs(), } = ref; if (!kind) return ""; diff --git a/src/common/k8s-api/endpoints/cluster-role-binding.api.ts b/src/common/k8s-api/endpoints/cluster-role-binding.api.ts index 1508e3716f..8275f7ee2a 100644 --- a/src/common/k8s-api/endpoints/cluster-role-binding.api.ts +++ b/src/common/k8s-api/endpoints/cluster-role-binding.api.ts @@ -66,5 +66,5 @@ if (isClusterPageContext()) { } export { - clusterRoleBindingApi + clusterRoleBindingApi, }; diff --git a/src/common/k8s-api/endpoints/cluster-role.api.ts b/src/common/k8s-api/endpoints/cluster-role.api.ts index 1478e7dcd1..4680237e52 100644 --- a/src/common/k8s-api/endpoints/cluster-role.api.ts +++ b/src/common/k8s-api/endpoints/cluster-role.api.ts @@ -54,5 +54,5 @@ if (isClusterPageContext()) { // initialize automatically only when within a clu } export { - clusterRoleApi + clusterRoleApi, }; diff --git a/src/common/k8s-api/endpoints/cluster.api.ts b/src/common/k8s-api/endpoints/cluster.api.ts index 66fc1a8c5f..86f7f1e5c4 100644 --- a/src/common/k8s-api/endpoints/cluster.api.ts +++ b/src/common/k8s-api/endpoints/cluster.api.ts @@ -49,7 +49,7 @@ export function getMetricsByNodeNames(nodeNames: string[], params?: IMetricsReqP podCapacity: opts, podAllocatableCapacity: opts, fsSize: opts, - fsUsage: opts + fsUsage: opts, }, params); } @@ -57,7 +57,7 @@ export enum ClusterStatus { ACTIVE = "Active", CREATING = "Creating", REMOVING = "Removing", - ERROR = "Error" + ERROR = "Error", } export interface IClusterMetrics { @@ -135,5 +135,5 @@ if (isClusterPageContext()) { // initialize automatically only when within a clu } export { - clusterApi + clusterApi, }; diff --git a/src/common/k8s-api/endpoints/configmap.api.ts b/src/common/k8s-api/endpoints/configmap.api.ts index 153e1a3169..36af10b4c7 100644 --- a/src/common/k8s-api/endpoints/configmap.api.ts +++ b/src/common/k8s-api/endpoints/configmap.api.ts @@ -60,5 +60,5 @@ if (isClusterPageContext()) { } export { - configMapApi + configMapApi, }; diff --git a/src/common/k8s-api/endpoints/crd.api.ts b/src/common/k8s-api/endpoints/crd.api.ts index 98c8d38df0..1e9044e31a 100644 --- a/src/common/k8s-api/endpoints/crd.api.ts +++ b/src/common/k8s-api/endpoints/crd.api.ts @@ -117,7 +117,7 @@ export class CustomResourceDefinition extends KubeObject { params: { group: this.getGroup(), name: this.getPluralName(), - } + }, }); } @@ -163,7 +163,7 @@ export class CustomResourceDefinition extends KubeObject { } } else if (this.spec.version) { const { additionalPrinterColumns: apc } = this.spec; - const additionalPrinterColumns = apc?.map(({ JSONPath, ...apc}) => ({ ...apc, jsonPath: JSONPath })); + const additionalPrinterColumns = apc?.map(({ JSONPath, ...apc }) => ({ ...apc, jsonPath: JSONPath })); return { name: this.spec.version, @@ -217,7 +217,7 @@ export class CustomResourceDefinition extends KubeObject { return { ...condition, isReady: status === "True", - tooltip: `${message || reason} (${lastTransitionTime})` + tooltip: `${message || reason} (${lastTransitionTime})`, }; }); } @@ -236,5 +236,5 @@ if (isClusterPageContext()) { } export { - crdApi + crdApi, }; diff --git a/src/common/k8s-api/endpoints/cron-job.api.ts b/src/common/k8s-api/endpoints/cron-job.api.ts index 85936e4d32..2b59426175 100644 --- a/src/common/k8s-api/endpoints/cron-job.api.ts +++ b/src/common/k8s-api/endpoints/cron-job.api.ts @@ -33,14 +33,14 @@ export class CronJobApi extends KubeApi { return this.request.patch(this.getUrl(params), { data: { spec: { - suspend: true - } - } + suspend: true, + }, + }, }, { headers: { - "content-type": "application/strategic-merge-patch+json" - } + "content-type": "application/strategic-merge-patch+json", + }, }); } @@ -48,14 +48,14 @@ export class CronJobApi extends KubeApi { return this.request.patch(this.getUrl(params), { data: { spec: { - suspend: false - } - } + suspend: false, + }, + }, }, { headers: { - "content-type": "application/strategic-merge-patch+json" - } + "content-type": "application/strategic-merge-patch+json", + }, }); } } @@ -153,5 +153,5 @@ if (isClusterPageContext()) { } export { - cronJobApi + cronJobApi, }; diff --git a/src/common/k8s-api/endpoints/daemon-set.api.ts b/src/common/k8s-api/endpoints/daemon-set.api.ts index 4cd3eff4f4..44c99a13b8 100644 --- a/src/common/k8s-api/endpoints/daemon-set.api.ts +++ b/src/common/k8s-api/endpoints/daemon-set.api.ts @@ -129,5 +129,5 @@ if (isClusterPageContext()) { } export { - daemonSetApi + daemonSetApi, }; diff --git a/src/common/k8s-api/endpoints/deployment.api.ts b/src/common/k8s-api/endpoints/deployment.api.ts index 721db669b7..f4d82c64b3 100644 --- a/src/common/k8s-api/endpoints/deployment.api.ts +++ b/src/common/k8s-api/endpoints/deployment.api.ts @@ -44,14 +44,14 @@ export class DeploymentApi extends KubeApi { return this.request.patch(this.getScaleApiUrl(params), { data: { spec: { - replicas - } - } + replicas, + }, + }, }, { headers: { - "content-type": "application/merge-patch+json" - } + "content-type": "application/merge-patch+json", + }, }); } @@ -61,16 +61,16 @@ export class DeploymentApi extends KubeApi { spec: { template: { metadata: { - annotations: {"kubectl.kubernetes.io/restartedAt" : moment.utc().format()} - } - } - } - } + annotations: { "kubectl.kubernetes.io/restartedAt" : moment.utc().format() }, + }, + }, + }, + }, }, { headers: { - "content-type": "application/strategic-merge-patch+json" - } + "content-type": "application/strategic-merge-patch+json", + }, }); } } @@ -122,7 +122,7 @@ export class Deployment extends WorkloadKubeObject { declare spec: { replicas: number; - selector: { matchLabels: { [app: string]: string } }; + selector: { matchLabels: { [app: string]: string }}; template: { metadata: { creationTimestamp?: string; @@ -246,5 +246,5 @@ if (isClusterPageContext()) { } export { - deploymentApi + deploymentApi, }; diff --git a/src/common/k8s-api/endpoints/endpoint.api.ts b/src/common/k8s-api/endpoints/endpoint.api.ts index e6dceb2b8f..a8930880b0 100644 --- a/src/common/k8s-api/endpoints/endpoint.api.ts +++ b/src/common/k8s-api/endpoints/endpoint.api.ts @@ -83,7 +83,7 @@ export class EndpointAddress implements IEndpointAddress { getTargetRef(): ITargetRef { if (this.targetRef) { - return Object.assign(this.targetRef, {apiVersion: "v1"}); + return Object.assign(this.targetRef, { apiVersion: "v1" }); } else { return null; } @@ -159,5 +159,5 @@ if (isClusterPageContext()) { } export { - endpointApi + endpointApi, }; diff --git a/src/common/k8s-api/endpoints/events.api.ts b/src/common/k8s-api/endpoints/events.api.ts index f6b954be6b..a549cd777b 100644 --- a/src/common/k8s-api/endpoints/events.api.ts +++ b/src/common/k8s-api/endpoints/events.api.ts @@ -87,5 +87,5 @@ if (isClusterPageContext()) { } export { - eventApi + eventApi, }; diff --git a/src/common/k8s-api/endpoints/helm-charts.api.ts b/src/common/k8s-api/endpoints/helm-charts.api.ts index 706fcdf7f9..e87e73bafe 100644 --- a/src/common/k8s-api/endpoints/helm-charts.api.ts +++ b/src/common/k8s-api/endpoints/helm-charts.api.ts @@ -191,7 +191,7 @@ const helmChartValidator = Joi.object({ .items(Joi.string()) .options({ stripUnknown: { - arrays: true + arrays: true, }, }) .default(() => ([])), @@ -200,7 +200,7 @@ const helmChartValidator = Joi.object({ .items(Joi.string()) .options({ stripUnknown: { - arrays: true + arrays: true, }, }) .default(() => ([])), @@ -209,7 +209,7 @@ const helmChartValidator = Joi.object({ .items(Joi.string()) .options({ stripUnknown: { - arrays: true + arrays: true, }, }) .default(() => ([])), @@ -218,7 +218,7 @@ const helmChartValidator = Joi.object({ .items(helmChartMaintainerValidator) .options({ stripUnknown: { - arrays: true + arrays: true, }, }) .default(() => ([])), @@ -227,7 +227,7 @@ const helmChartValidator = Joi.object({ .items(helmChartDependencyValidator) .options({ stripUnknown: { - arrays: true + arrays: true, }, }) .default(() => ([])), diff --git a/src/common/k8s-api/endpoints/helm-releases.api.ts b/src/common/k8s-api/endpoints/helm-releases.api.ts index 7d6f45fa5c..8cbafa1e0c 100644 --- a/src/common/k8s-api/endpoints/helm-releases.api.ts +++ b/src/common/k8s-api/endpoints/helm-releases.api.ts @@ -108,7 +108,7 @@ export async function getRelease(name: string, namespace: string): Promise - metric.type == current.type && this.getMetricName(metric) == this.getMetricName(current) + metric.type == current.type && this.getMetricName(metric) == this.getMetricName(current), ); const current = currentMetric ? currentMetric[metricType] : null; const target = metric[metricType]; @@ -173,5 +173,5 @@ if (isClusterPageContext()) { } export { - hpaApi + hpaApi, }; diff --git a/src/common/k8s-api/endpoints/ingress.api.ts b/src/common/k8s-api/endpoints/ingress.api.ts index 5a1a404f20..277b47536c 100644 --- a/src/common/k8s-api/endpoints/ingress.api.ts +++ b/src/common/k8s-api/endpoints/ingress.api.ts @@ -30,13 +30,13 @@ export class IngressApi extends KubeApi { } export function getMetricsForIngress(ingress: string, namespace: string): Promise { - const opts = { category: "ingress", ingress }; + const opts = { category: "ingress", ingress, namespace }; return metricsApi.getMetrics({ bytesSentSuccess: opts, bytesSentFailure: opts, requestDurationSeconds: opts, - responseDurationSeconds: opts + responseDurationSeconds: opts, }, { namespace, }); @@ -128,7 +128,7 @@ export class Ingress extends KubeObject { } getRoutes() { - const { spec: { tls, rules } } = this; + const { spec: { tls, rules }} = this; if (!rules) return []; @@ -160,12 +160,12 @@ export class Ingress extends KubeObject { return { serviceName, - servicePort + servicePort, }; } getHosts() { - const { spec: { rules } } = this; + const { spec: { rules }} = this; if (!rules) return []; @@ -174,7 +174,7 @@ export class Ingress extends KubeObject { getPorts() { const ports: number[] = []; - const { spec: { tls, rules, backend, defaultBackend } } = this; + const { spec: { tls, rules, backend, defaultBackend }} = this; const httpPort = 80; const tlsPort = 443; // Note: not using the port name (string) @@ -196,7 +196,7 @@ export class Ingress extends KubeObject { } getLoadBalancers() { - const { status: { loadBalancer = { ingress: [] } } } = this; + const { status: { loadBalancer = { ingress: [] }}} = this; return (loadBalancer.ingress ?? []).map(address => ( address.hostname || address.ip @@ -216,5 +216,5 @@ if (isClusterPageContext()) { } export { - ingressApi + ingressApi, }; diff --git a/src/common/k8s-api/endpoints/job.api.ts b/src/common/k8s-api/endpoints/job.api.ts index 539e3dc902..a1c4b733db 100644 --- a/src/common/k8s-api/endpoints/job.api.ts +++ b/src/common/k8s-api/endpoints/job.api.ts @@ -124,7 +124,7 @@ export class Job extends WorkloadKubeObject { delete() { const params: JsonApiParams = { - query: { propagationPolicy: "Background" } + query: { propagationPolicy: "Background" }, }; return super.delete(params); @@ -158,5 +158,5 @@ if (isClusterPageContext()) { } export { - jobApi + jobApi, }; diff --git a/src/common/k8s-api/endpoints/limit-range.api.ts b/src/common/k8s-api/endpoints/limit-range.api.ts index 3c41aca1a1..e7afd1c0e8 100644 --- a/src/common/k8s-api/endpoints/limit-range.api.ts +++ b/src/common/k8s-api/endpoints/limit-range.api.ts @@ -90,5 +90,5 @@ if (isClusterPageContext()) { } export { - limitRangeApi + limitRangeApi, }; diff --git a/src/common/k8s-api/endpoints/metrics.api.ts b/src/common/k8s-api/endpoints/metrics.api.ts index b0e3c0bf9d..91587bff97 100644 --- a/src/common/k8s-api/endpoints/metrics.api.ts +++ b/src/common/k8s-api/endpoints/metrics.api.ts @@ -87,13 +87,13 @@ export const metricsApi = { query: { start, end, step, "kubernetes_namespace": namespace, - } + }, }); }, async getMetricProviders(): Promise { return apiBase.get("/metrics/providers"); - } + }, }; export function normalizeMetrics(metrics: IMetrics, frames = 60): IMetrics { @@ -103,7 +103,7 @@ export function normalizeMetrics(metrics: IMetrics, frames = 60): IMetrics { resultType: "", result: [{ metric: {}, - values: [] + values: [], } as IMetricsResult], }, status: "", @@ -144,7 +144,7 @@ export function normalizeMetrics(metrics: IMetrics, frames = 60): IMetrics { // always return at least empty values array result.push({ metric: {}, - values: [] + values: [], } as IMetricsResult); } diff --git a/src/common/k8s-api/endpoints/namespaces.api.ts b/src/common/k8s-api/endpoints/namespaces.api.ts index f973ceb1b6..08e9593399 100644 --- a/src/common/k8s-api/endpoints/namespaces.api.ts +++ b/src/common/k8s-api/endpoints/namespaces.api.ts @@ -79,5 +79,5 @@ if (isClusterPageContext()) { } export { - namespacesApi + namespacesApi, }; diff --git a/src/common/k8s-api/endpoints/network-policy.api.ts b/src/common/k8s-api/endpoints/network-policy.api.ts index 026aa0b047..1ee1f62371 100644 --- a/src/common/k8s-api/endpoints/network-policy.api.ts +++ b/src/common/k8s-api/endpoints/network-policy.api.ts @@ -106,5 +106,5 @@ if (isClusterPageContext()) { } export { - networkPolicyApi + networkPolicyApi, }; diff --git a/src/common/k8s-api/endpoints/nodes.api.ts b/src/common/k8s-api/endpoints/nodes.api.ts index bd09044776..3f4e0fb412 100644 --- a/src/common/k8s-api/endpoints/nodes.api.ts +++ b/src/common/k8s-api/endpoints/nodes.api.ts @@ -30,7 +30,7 @@ export class NodesApi extends KubeApi { } export function getMetricsForAllNodes(): Promise { - const opts = { category: "nodes"}; + const opts = { category: "nodes" }; return metricsApi.getMetrics({ memoryUsage: opts, @@ -40,7 +40,7 @@ export function getMetricsForAllNodes(): Promise { cpuUsage: opts, cpuCapacity: opts, fsSize: opts, - fsUsage: opts + fsUsage: opts, }); } @@ -259,5 +259,5 @@ if (isClusterPageContext()) { } export { - nodesApi + nodesApi, }; diff --git a/src/common/k8s-api/endpoints/persistent-volume-claims.api.ts b/src/common/k8s-api/endpoints/persistent-volume-claims.api.ts index a8822aed7b..6206058e63 100644 --- a/src/common/k8s-api/endpoints/persistent-volume-claims.api.ts +++ b/src/common/k8s-api/endpoints/persistent-volume-claims.api.ts @@ -35,9 +35,9 @@ export function getMetricsForPvc(pvc: PersistentVolumeClaim): Promise { return pod.getVolumes().filter(volume => volume.persistentVolumeClaim && - volume.persistentVolumeClaim.claimName === this.getName() + volume.persistentVolumeClaim.claimName === this.getName(), ).length > 0; }); } @@ -128,5 +128,5 @@ if (isClusterPageContext()) { } export { - pvcApi + pvcApi, }; diff --git a/src/common/k8s-api/endpoints/persistent-volume.api.ts b/src/common/k8s-api/endpoints/persistent-volume.api.ts index 3a7a10ea6c..c636d9f367 100644 --- a/src/common/k8s-api/endpoints/persistent-volume.api.ts +++ b/src/common/k8s-api/endpoints/persistent-volume.api.ts @@ -111,5 +111,5 @@ if (isClusterPageContext()) { } export { - persistentVolumeApi + persistentVolumeApi, }; diff --git a/src/common/k8s-api/endpoints/pod-metrics.api.ts b/src/common/k8s-api/endpoints/pod-metrics.api.ts index 8d89f306b1..849212d035 100644 --- a/src/common/k8s-api/endpoints/pod-metrics.api.ts +++ b/src/common/k8s-api/endpoints/pod-metrics.api.ts @@ -50,5 +50,5 @@ if (isClusterPageContext()) { } export { - podMetricsApi + podMetricsApi, }; diff --git a/src/common/k8s-api/endpoints/poddisruptionbudget.api.ts b/src/common/k8s-api/endpoints/poddisruptionbudget.api.ts index 1e57c1a3ec..b2ac2cd878 100644 --- a/src/common/k8s-api/endpoints/poddisruptionbudget.api.ts +++ b/src/common/k8s-api/endpoints/poddisruptionbudget.api.ts @@ -29,7 +29,7 @@ export interface PodDisruptionBudget { spec: { minAvailable: string; maxUnavailable: string; - selector: { matchLabels: { [app: string]: string } }; + selector: { matchLabels: { [app: string]: string }}; }; status: { currentHealthy: number @@ -82,5 +82,5 @@ if (isClusterPageContext()) { } export { - pdbApi + pdbApi, }; diff --git a/src/common/k8s-api/endpoints/pods.api.ts b/src/common/k8s-api/endpoints/pods.api.ts index 70fad21b4b..bdcddf035d 100644 --- a/src/common/k8s-api/endpoints/pods.api.ts +++ b/src/common/k8s-api/endpoints/pods.api.ts @@ -82,7 +82,7 @@ export enum PodStatus { PENDING = "Pending", RUNNING = "Running", SUCCEEDED = "Succeeded", - EVICTED = "Evicted" + EVICTED = "Evicted", } export interface IPodContainer extends Partial> { @@ -310,7 +310,7 @@ export class Pod extends WorkloadKubeObject { const runningContainerNames = new Set( this.getContainerStatuses() .filter(({ state }) => state.running) - .map(({ name }) => name) + .map(({ name }) => name), ); return this.getAllContainers() @@ -411,7 +411,7 @@ export class Pod extends WorkloadKubeObject { } getNodeSelectors(): string[] { - const { nodeSelector = {} } = this.spec; + const { nodeSelector = {}} = this.spec; return Object.entries(nodeSelector).map(values => values.join(": ")); } @@ -466,7 +466,7 @@ export class Pod extends WorkloadKubeObject { timeoutSeconds = 0, periodSeconds = 0, successThreshold = 0, - failureThreshold = 0 + failureThreshold = 0, } = probeData; // HTTP Request @@ -529,5 +529,5 @@ if (isClusterPageContext()) { } export { - podsApi + podsApi, }; diff --git a/src/common/k8s-api/endpoints/podsecuritypolicy.api.ts b/src/common/k8s-api/endpoints/podsecuritypolicy.api.ts index c1b29f3c6e..cf4eb1e16a 100644 --- a/src/common/k8s-api/endpoints/podsecuritypolicy.api.ts +++ b/src/common/k8s-api/endpoints/podsecuritypolicy.api.ts @@ -127,5 +127,5 @@ if (isClusterPageContext()) { } export { - pspApi + pspApi, }; diff --git a/src/common/k8s-api/endpoints/replica-set.api.ts b/src/common/k8s-api/endpoints/replica-set.api.ts index eeaf361557..7a9a76ec06 100644 --- a/src/common/k8s-api/endpoints/replica-set.api.ts +++ b/src/common/k8s-api/endpoints/replica-set.api.ts @@ -44,9 +44,9 @@ export class ReplicaSetApi extends KubeApi { data: { metadata: params, spec: { - replicas - } - } + replicas, + }, + }, }); } } @@ -78,7 +78,7 @@ export class ReplicaSet extends WorkloadKubeObject { declare spec: { replicas?: number; - selector: { matchLabels: { [app: string]: string } }; + selector: { matchLabels: { [app: string]: string }}; template?: { metadata: { labels: { @@ -133,5 +133,5 @@ if (isClusterPageContext()) { } export { - replicaSetApi + replicaSetApi, }; diff --git a/src/common/k8s-api/endpoints/resource-applier.api.ts b/src/common/k8s-api/endpoints/resource-applier.api.ts index ea86c266a2..9d7273c113 100644 --- a/src/common/k8s-api/endpoints/resource-applier.api.ts +++ b/src/common/k8s-api/endpoints/resource-applier.api.ts @@ -25,7 +25,7 @@ import { apiBase } from "../index"; import type { Patch } from "rfc6902"; export const annotations = [ - "kubectl.kubernetes.io/last-applied-configuration" + "kubectl.kubernetes.io/last-applied-configuration", ]; export async function update(resource: object | string): Promise { diff --git a/src/common/k8s-api/endpoints/resource-quota.api.ts b/src/common/k8s-api/endpoints/resource-quota.api.ts index 3f6493aa01..71d75bc495 100644 --- a/src/common/k8s-api/endpoints/resource-quota.api.ts +++ b/src/common/k8s-api/endpoints/resource-quota.api.ts @@ -90,5 +90,5 @@ if (isClusterPageContext()) { } export { - resourceQuotaApi + resourceQuotaApi, }; diff --git a/src/common/k8s-api/endpoints/role-binding.api.ts b/src/common/k8s-api/endpoints/role-binding.api.ts index df6b0c7bc5..9f94813334 100644 --- a/src/common/k8s-api/endpoints/role-binding.api.ts +++ b/src/common/k8s-api/endpoints/role-binding.api.ts @@ -71,5 +71,5 @@ if (isClusterPageContext()) { } export { - roleBindingApi + roleBindingApi, }; diff --git a/src/common/k8s-api/endpoints/role.api.ts b/src/common/k8s-api/endpoints/role.api.ts index f9c0be19fb..d16405a5c4 100644 --- a/src/common/k8s-api/endpoints/role.api.ts +++ b/src/common/k8s-api/endpoints/role.api.ts @@ -51,5 +51,5 @@ if (isClusterPageContext()) { } export{ - roleApi + roleApi, }; diff --git a/src/common/k8s-api/endpoints/secret.api.ts b/src/common/k8s-api/endpoints/secret.api.ts index 7c90c2e9c9..68e63fcdfe 100644 --- a/src/common/k8s-api/endpoints/secret.api.ts +++ b/src/common/k8s-api/endpoints/secret.api.ts @@ -79,5 +79,5 @@ if (isClusterPageContext()) { } export { - secretsApi + secretsApi, }; diff --git a/src/common/k8s-api/endpoints/selfsubjectrulesreviews.api.ts b/src/common/k8s-api/endpoints/selfsubjectrulesreviews.api.ts index 799abec798..7773c43de6 100644 --- a/src/common/k8s-api/endpoints/selfsubjectrulesreviews.api.ts +++ b/src/common/k8s-api/endpoints/selfsubjectrulesreviews.api.ts @@ -27,7 +27,7 @@ export class SelfSubjectRulesReviewApi extends KubeApi { create({ namespace = "default" }): Promise { return super.create({}, { spec: { - namespace + namespace, }, }); } @@ -82,7 +82,7 @@ export class SelfSubjectRulesReview extends KubeObject { const separator = apiGroup == "" ? "" : "."; return resource + separator + apiGroup; - }) + }), }; } } @@ -96,6 +96,6 @@ if (isClusterPageContext()) { } export { - selfSubjectRulesReviewApi + selfSubjectRulesReviewApi, }; diff --git a/src/common/k8s-api/endpoints/service-accounts.api.ts b/src/common/k8s-api/endpoints/service-accounts.api.ts index 678541afe4..140edce9b8 100644 --- a/src/common/k8s-api/endpoints/service-accounts.api.ts +++ b/src/common/k8s-api/endpoints/service-accounts.api.ts @@ -62,5 +62,5 @@ if (isClusterPageContext()) { } export { - serviceAccountsApi + serviceAccountsApi, }; diff --git a/src/common/k8s-api/endpoints/service.api.ts b/src/common/k8s-api/endpoints/service.api.ts index e5af9de828..b9e0188f10 100644 --- a/src/common/k8s-api/endpoints/service.api.ts +++ b/src/common/k8s-api/endpoints/service.api.ts @@ -53,7 +53,7 @@ export interface Service { clusterIP: string; clusterIPs?: string[]; externalTrafficPolicy?: string; - externalName: string; + externalName?: string; loadBalancerIP?: string; loadBalancerSourceRanges?: string[]; sessionAffinity: string; @@ -100,11 +100,15 @@ export class Service extends KubeObject { getExternalIps() { const lb = this.getLoadBalancer(); - if (lb && lb.ingress) { + if (lb?.ingress) { return lb.ingress.map(val => val.ip || val.hostname); } - return this.spec.externalIPs || []; + if (Array.isArray(this.spec?.externalIPs)) { + return this.spec.externalIPs; + } + + return []; } getType() { @@ -153,5 +157,5 @@ if (isClusterPageContext()) { } export { - serviceApi + serviceApi, }; diff --git a/src/common/k8s-api/endpoints/stateful-set.api.ts b/src/common/k8s-api/endpoints/stateful-set.api.ts index c8f742d7cd..dd97e01e05 100644 --- a/src/common/k8s-api/endpoints/stateful-set.api.ts +++ b/src/common/k8s-api/endpoints/stateful-set.api.ts @@ -42,14 +42,14 @@ export class StatefulSetApi extends KubeApi { return this.request.patch(this.getScaleApiUrl(params), { data: { spec: { - replicas - } - } + replicas, + }, + }, }, { headers: { - "content-type": "application/merge-patch+json" - } + "content-type": "application/merge-patch+json", + }, }); } } @@ -162,5 +162,5 @@ if (isClusterPageContext()) { } export { - statefulSetApi + statefulSetApi, }; diff --git a/src/common/k8s-api/endpoints/storage-class.api.ts b/src/common/k8s-api/endpoints/storage-class.api.ts index 3b44a2e124..9f52908ca8 100644 --- a/src/common/k8s-api/endpoints/storage-class.api.ts +++ b/src/common/k8s-api/endpoints/storage-class.api.ts @@ -72,5 +72,5 @@ if (isClusterPageContext()) { } export { - storageClassApi + storageClassApi, }; diff --git a/src/common/k8s-api/index.ts b/src/common/k8s-api/index.ts index e464c307d7..c4fcb9a1c1 100644 --- a/src/common/k8s-api/index.ts +++ b/src/common/k8s-api/index.ts @@ -42,8 +42,8 @@ if (typeof window === "undefined") { debug: isDevelopment || isDebugging, }, { headers: { - "Host": `localhost:${params.port}` - } + "Host": `localhost:${params.port}`, + }, }); }); } else { @@ -53,8 +53,8 @@ if (typeof window === "undefined") { debug: isDevelopment || isDebugging, }, { headers: { - "Host": window.location.host - } + "Host": window.location.host, + }, }); } @@ -62,15 +62,15 @@ if (isClusterPageContext()) { apiKube = new KubeJsonApi({ serverAddress: `http://127.0.0.1:${window.location.port}`, apiBase: apiKubePrefix, - debug: isDevelopment + debug: isDevelopment, }, { headers: { - "Host": window.location.host - } + "Host": window.location.host, + }, }); } export { apiBase, - apiKube + apiKube, }; diff --git a/src/common/k8s-api/json-api.ts b/src/common/k8s-api/json-api.ts index 15bad9864a..12bccc7a1b 100644 --- a/src/common/k8s-api/json-api.ts +++ b/src/common/k8s-api/json-api.ts @@ -57,12 +57,12 @@ export interface JsonApiConfig { export class JsonApi { static reqInitDefault: RequestInit = { headers: { - "content-type": "application/json" - } + "content-type": "application/json", + }, }; static configDefault: Partial = { - debug: false + debug: false, }; constructor(public readonly config: JsonApiConfig, protected reqInit?: RequestInit) { @@ -87,7 +87,7 @@ export class JsonApi { {}, this.reqInit, await this.getRequestOptions(), - init + init, ); const { query } = params || {} as P; @@ -126,7 +126,7 @@ export class JsonApi { {}, this.reqInit, await this.getRequestOptions(), - init + init, ); const { data, query } = params || {} as P; @@ -201,7 +201,7 @@ export class JsonApi { protected writeLog(log: JsonApiLog) { const { method, reqUrl, ...params } = log; - logger.info(`[JSON-API] request ${method} ${reqUrl}`, params); + logger.debug(`[JSON-API] request ${method} ${reqUrl}`, params); } } diff --git a/src/common/k8s-api/kube-api.ts b/src/common/k8s-api/kube-api.ts index 7e29500689..850d5dcb05 100644 --- a/src/common/k8s-api/kube-api.ts +++ b/src/common/k8s-api/kube-api.ts @@ -123,13 +123,13 @@ export function forCluster(cluster: ILocalKubeApiConfig, k debug: isDevelopment, }, { headers: { - "Host": `${cluster.metadata.uid}.localhost:${url.port}` - } + "Host": `${cluster.metadata.uid}.localhost:${url.port}`, + }, }); return new KubeApi({ objectConstructor: kubeClass, - request + request, }); } @@ -166,15 +166,15 @@ export function forRemoteCluster(config: IRemoteKubeApiCon ...(token ? { getRequestOptions: async () => ({ headers: { - "Authorization": `Bearer ${isFunction(token) ? await token() : token}` - } - }) - } : {}) + "Authorization": `Bearer ${isFunction(token) ? await token() : token}`, + }, + }), + } : {}), }, reqInit); return new KubeApi({ objectConstructor: kubeClass, - request + request, }); } @@ -221,7 +221,7 @@ export class KubeApi { objectConstructor, request = apiKube, kind = options.objectConstructor?.kind, - isNamespaced = options.objectConstructor?.namespaced + isNamespaced = options.objectConstructor?.namespaced, } = options || {}; if (!options.apiBase) { @@ -292,7 +292,7 @@ export class KubeApi { return { apiPrefix: this.apiPrefix, - apiGroup: this.apiGroup + apiGroup: this.apiGroup, }; } @@ -306,10 +306,10 @@ export class KubeApi { // The apiPrefix and apiGroup might change due to fallbackApiBases, so we must override them Object.defineProperty(this, "apiPrefix", { - value: apiPrefix + value: apiPrefix, }); Object.defineProperty(this, "apiGroup", { - value: apiGroup + value: apiGroup, }); const res = await this.request.get(`${this.apiPrefix}/${this.apiGroup}`); @@ -444,9 +444,9 @@ export class KubeApi { apiVersion: this.apiVersionWithGroup, metadata: { name, - namespace - } - }, data) + namespace, + }, + }, data), }); const parsed = this.parseResponse(res); diff --git a/src/common/k8s-api/kube-object.store.ts b/src/common/k8s-api/kube-object.store.ts index 6cf5ff6705..f4e0542f66 100644 --- a/src/common/k8s-api/kube-object.store.ts +++ b/src/common/k8s-api/kube-object.store.ts @@ -317,7 +317,7 @@ export abstract class KubeObjectStore extends ItemStore protected bindWatchEventsUpdater(delay = 1000) { reaction(() => this.eventsBuffer.length, this.updateFromEventsBuffer, { - delay + delay, }); } @@ -352,7 +352,7 @@ export abstract class KubeObjectStore extends ItemStore const watch = () => this.api.watch({ namespace, abortController, - callback + callback, }); const { signal } = abortController; @@ -375,8 +375,8 @@ export abstract class KubeObjectStore extends ItemStore timedRetry = setTimeout(() => { ( namespace - ? this.loadAll({ namespaces: [namespace], reqInit: { signal } }) - : this.loadAll({ merge: false, reqInit: { signal } }) + ? this.loadAll({ namespaces: [namespace], reqInit: { signal }}) + : this.loadAll({ merge: false, reqInit: { signal }}) ).then(watch); }, 1000); } else if (error) { // not sure what to do, best to retry diff --git a/src/common/k8s-api/kube-watch-api.ts b/src/common/k8s-api/kube-watch-api.ts index 5ce16dcfbd..2ab1123173 100644 --- a/src/common/k8s-api/kube-watch-api.ts +++ b/src/common/k8s-api/kube-watch-api.ts @@ -82,7 +82,7 @@ export class KubeWatchApi { } subscribeStores(stores: KubeObjectStore[], opts: IKubeWatchSubscribeStoreOptions = {}): Disposer { - const { preload = true, waitUntilLoaded = true, loadOnce = false, } = opts; + const { preload = true, waitUntilLoaded = true, loadOnce = false } = opts; const subscribingNamespaces = opts.namespaces ?? this.context?.allNamespaces ?? []; const unsubscribeList: Function[] = []; let isUnsubscribed = false; @@ -134,7 +134,7 @@ export class KubeWatchApi { }; } - protected log({ message, cssStyle = "", meta = {} }: IKubeWatchLog) { + protected log({ message, cssStyle = "", meta = {}}: IKubeWatchLog) { if (isProduction && !isDebugging) { return; } diff --git a/src/common/kube-helpers.ts b/src/common/kube-helpers.ts index 1b91a35e56..0dc678550f 100644 --- a/src/common/kube-helpers.ts +++ b/src/common/kube-helpers.ts @@ -121,7 +121,7 @@ function loadToOptions(rawYaml: string): OptionsResult { allowUnknown: true, stripUnknown: { arrays: true, - } + }, }); const { clusters: rawClusters, @@ -210,16 +210,16 @@ export function dumpConfigYaml(kubeConfig: Partial): string { "certificate-authority-data": cluster.caData, "certificate-authority": cluster.caFile, server: cluster.server, - "insecure-skip-tls-verify": cluster.skipTLSVerify - } + "insecure-skip-tls-verify": cluster.skipTLSVerify, + }, })); const contexts = kubeConfig.contexts.map(context => ({ name: context.name, context: { cluster: context.cluster, user: context.user, - namespace: context.namespace - } + namespace: context.namespace, + }, })); const users = kubeConfig.users.map(user => ({ name: user.name, @@ -232,8 +232,8 @@ export function dumpConfigYaml(kubeConfig: Partial): string { exec: user.exec, token: user.token, username: user.username, - password: user.password - } + password: user.password, + }, })); const config = { apiVersion: "v1", diff --git a/src/common/logger.ts b/src/common/logger.ts index 3f71c095df..69cda771c6 100644 --- a/src/common/logger.ts +++ b/src/common/logger.ts @@ -56,7 +56,7 @@ if (ipcMain) { }, }), ), - }) + }), ); if (!isTestEnv) { @@ -73,7 +73,7 @@ if (ipcMain) { maxsize: 16 * 1024, maxFiles: 16, tailable: true, - }) + }), ); } } else { diff --git a/src/common/routes/add-cluster.ts b/src/common/routes/add-cluster.ts index 93ac41f0bf..e29bc3db24 100644 --- a/src/common/routes/add-cluster.ts +++ b/src/common/routes/add-cluster.ts @@ -23,7 +23,7 @@ import type { RouteProps } from "react-router"; import { buildURL } from "../utils/buildUrl"; export const addClusterRoute: RouteProps = { - path: "/add-cluster" + path: "/add-cluster", }; export const addClusterURL = buildURL(addClusterRoute.path); diff --git a/src/common/routes/catalog.ts b/src/common/routes/catalog.ts index 7759d13b62..60b50e3dae 100644 --- a/src/common/routes/catalog.ts +++ b/src/common/routes/catalog.ts @@ -27,7 +27,7 @@ export interface CatalogViewRouteParam { kind?: string; } export const catalogRoute: RouteProps = { - path: "/catalog/:group?/:kind?" + path: "/catalog/:group?/:kind?", }; export const getPreviousTabUrl = (path: string) => { @@ -36,8 +36,8 @@ export const getPreviousTabUrl = (path: string) => { return catalogURL({ params: { group: group || browseCatalogTab, - kind - } + kind, + }, }); }; diff --git a/src/common/routes/cluster.ts b/src/common/routes/cluster.ts index 2ba39ae53f..8f8eaccb74 100644 --- a/src/common/routes/cluster.ts +++ b/src/common/routes/cluster.ts @@ -23,7 +23,7 @@ import type { RouteProps } from "react-router"; import { buildURL } from "../utils/buildUrl"; export const clusterRoute: RouteProps = { - path: "/overview" + path: "/overview", }; export const clusterURL = buildURL(clusterRoute.path); diff --git a/src/common/routes/config-maps.ts b/src/common/routes/config-maps.ts index 99aeaaf553..4205241f5c 100644 --- a/src/common/routes/config-maps.ts +++ b/src/common/routes/config-maps.ts @@ -23,7 +23,7 @@ import type { RouteProps } from "react-router"; import { buildURL } from "../utils/buildUrl"; export const configMapsRoute: RouteProps = { - path: "/configmaps" + path: "/configmaps", }; export interface ConfigMapsRouteParams { diff --git a/src/common/routes/config.ts b/src/common/routes/config.ts index 7dca290672..eafc279cba 100644 --- a/src/common/routes/config.ts +++ b/src/common/routes/config.ts @@ -35,8 +35,8 @@ export const configRoute: RouteProps = { resourceQuotaRoute, limitRangesRoute, hpaRoute, - pdbRoute - ].map(route => route.path.toString()) + pdbRoute, + ].map(route => route.path.toString()), }; export const configURL = (params?: URLParams) => configMapsURL(params); diff --git a/src/common/routes/crd.ts b/src/common/routes/crd.ts index 1a70fac875..a2284a78c9 100644 --- a/src/common/routes/crd.ts +++ b/src/common/routes/crd.ts @@ -23,15 +23,15 @@ import type { RouteProps } from "react-router"; import { buildURL } from "../utils/buildUrl"; export const crdRoute: RouteProps = { - path: "/crd" + path: "/crd", }; export const crdDefinitionsRoute: RouteProps = { - path: `${crdRoute.path}/definitions` + path: `${crdRoute.path}/definitions`, }; export const crdResourcesRoute: RouteProps = { - path: `${crdRoute.path}/:group/:name` + path: `${crdRoute.path}/:group/:name`, }; export interface CRDListQuery { diff --git a/src/common/routes/endpoints.ts b/src/common/routes/endpoints.ts index db09de66a0..7f8f38e03e 100644 --- a/src/common/routes/endpoints.ts +++ b/src/common/routes/endpoints.ts @@ -23,7 +23,7 @@ import type { RouteProps } from "react-router"; import { buildURL } from "../utils/buildUrl"; export const endpointRoute: RouteProps = { - path: "/endpoints" + path: "/endpoints", }; export interface EndpointRouteParams { diff --git a/src/common/routes/events.ts b/src/common/routes/events.ts index 73995ce6b0..f75a8587bb 100644 --- a/src/common/routes/events.ts +++ b/src/common/routes/events.ts @@ -23,7 +23,7 @@ import type { RouteProps } from "react-router"; import { buildURL } from "../utils/buildUrl"; export const eventRoute: RouteProps = { - path: "/events" + path: "/events", }; export const eventsURL = buildURL(eventRoute.path); diff --git a/src/common/routes/extensions.ts b/src/common/routes/extensions.ts index 6ef25d11c6..3a0172ed0a 100644 --- a/src/common/routes/extensions.ts +++ b/src/common/routes/extensions.ts @@ -23,7 +23,7 @@ import type { RouteProps } from "react-router"; import { buildURL } from "../utils/buildUrl"; export const extensionsRoute: RouteProps = { - path: "/extensions" + path: "/extensions", }; export const extensionsURL = buildURL(extensionsRoute.path); diff --git a/src/common/routes/helm-charts.ts b/src/common/routes/helm-charts.ts index 53b889073d..e79633c686 100644 --- a/src/common/routes/helm-charts.ts +++ b/src/common/routes/helm-charts.ts @@ -24,7 +24,7 @@ import { buildURL } from "../utils/buildUrl"; import { appsRoute } from "./apps"; export const helmChartsRoute: RouteProps = { - path: `${appsRoute.path}/charts/:repo?/:chartName?` + path: `${appsRoute.path}/charts/:repo?/:chartName?`, }; export interface HelmChartsRouteParams { diff --git a/src/common/routes/hpa.ts b/src/common/routes/hpa.ts index a6f89661c2..1163daa68f 100644 --- a/src/common/routes/hpa.ts +++ b/src/common/routes/hpa.ts @@ -23,7 +23,7 @@ import type { RouteProps } from "react-router"; import { buildURL } from "../utils/buildUrl"; export const hpaRoute: RouteProps = { - path: "/hpa" + path: "/hpa", }; export interface HpaRouteParams { diff --git a/src/common/routes/ingresses.ts b/src/common/routes/ingresses.ts index 66c37774d5..50b9704747 100644 --- a/src/common/routes/ingresses.ts +++ b/src/common/routes/ingresses.ts @@ -23,7 +23,7 @@ import type { RouteProps } from "react-router"; import { buildURL } from "../utils/buildUrl"; export const ingressRoute: RouteProps = { - path: "/ingresses" + path: "/ingresses", }; export interface IngressRouteParams { diff --git a/src/common/routes/limit-ranges.ts b/src/common/routes/limit-ranges.ts index 02b9258c67..43b0dffc70 100644 --- a/src/common/routes/limit-ranges.ts +++ b/src/common/routes/limit-ranges.ts @@ -23,7 +23,7 @@ import type { RouteProps } from "react-router"; import { buildURL } from "../utils/buildUrl"; export const limitRangesRoute: RouteProps = { - path: "/limitranges" + path: "/limitranges", }; export interface LimitRangeRouteParams { diff --git a/src/common/routes/namespaces.ts b/src/common/routes/namespaces.ts index 4a23950648..6a9988955d 100644 --- a/src/common/routes/namespaces.ts +++ b/src/common/routes/namespaces.ts @@ -23,7 +23,7 @@ import type { RouteProps } from "react-router"; import { buildURL } from "../utils/buildUrl"; export const namespacesRoute: RouteProps = { - path: "/namespaces" + path: "/namespaces", }; export interface NamespacesRouteParams { diff --git a/src/common/routes/network-policies.ts b/src/common/routes/network-policies.ts index b49094a418..393dccbbcb 100644 --- a/src/common/routes/network-policies.ts +++ b/src/common/routes/network-policies.ts @@ -23,7 +23,7 @@ import type { RouteProps } from "react-router"; import { buildURL } from "../utils/buildUrl"; export const networkPoliciesRoute: RouteProps = { - path: "/network-policies" + path: "/network-policies", }; export interface NetworkPoliciesRouteParams { diff --git a/src/common/routes/network.ts b/src/common/routes/network.ts index 15338675a6..85c1339c48 100644 --- a/src/common/routes/network.ts +++ b/src/common/routes/network.ts @@ -34,7 +34,7 @@ export const networkRoute: RouteProps = { ingressRoute, networkPoliciesRoute, portForwardsRoute, - ].map(route => route.path.toString()) + ].map(route => route.path.toString()), }; export const networkURL = (params?: URLParams) => servicesURL(params); diff --git a/src/common/routes/nodes.ts b/src/common/routes/nodes.ts index bfb6d8ea00..cc6abf6744 100644 --- a/src/common/routes/nodes.ts +++ b/src/common/routes/nodes.ts @@ -23,7 +23,7 @@ import type { RouteProps } from "react-router"; import { buildURL } from "../utils/buildUrl"; export const nodesRoute: RouteProps = { - path: "/nodes" + path: "/nodes", }; export interface NodesRouteParams { diff --git a/src/common/routes/pod-disruption-budgets.ts b/src/common/routes/pod-disruption-budgets.ts index 985752746a..02cd0db893 100644 --- a/src/common/routes/pod-disruption-budgets.ts +++ b/src/common/routes/pod-disruption-budgets.ts @@ -23,7 +23,7 @@ import type { RouteProps } from "react-router"; import { buildURL } from "../utils/buildUrl"; export const pdbRoute: RouteProps = { - path: "/poddisruptionbudgets" + path: "/poddisruptionbudgets", }; export interface PodDisruptionBudgetsRouteParams { diff --git a/src/common/routes/port-forwards.ts b/src/common/routes/port-forwards.ts index bf644e5003..436c98de28 100644 --- a/src/common/routes/port-forwards.ts +++ b/src/common/routes/port-forwards.ts @@ -23,7 +23,7 @@ import type { RouteProps } from "react-router"; import { buildURL } from "../utils/buildUrl"; export const portForwardsRoute: RouteProps = { - path: "/port-forwards/:forwardport?" + path: "/port-forwards/:forwardport?", }; export interface PortForwardsRouteParams { diff --git a/src/common/routes/preferences.ts b/src/common/routes/preferences.ts index 1c19e6e733..9b1932fd3d 100644 --- a/src/common/routes/preferences.ts +++ b/src/common/routes/preferences.ts @@ -23,31 +23,31 @@ import type { RouteProps } from "react-router"; import { buildURL } from "../utils/buildUrl"; export const preferencesRoute: RouteProps = { - path: "/preferences" + path: "/preferences", }; export const appRoute: RouteProps = { - path: `${preferencesRoute.path}/app` + path: `${preferencesRoute.path}/app`, }; export const proxyRoute: RouteProps = { - path: `${preferencesRoute.path}/proxy` + path: `${preferencesRoute.path}/proxy`, }; export const kubernetesRoute: RouteProps = { - path: `${preferencesRoute.path}/kubernetes` + path: `${preferencesRoute.path}/kubernetes`, }; export const editorRoute: RouteProps = { - path: `${preferencesRoute.path}/editor` + path: `${preferencesRoute.path}/editor`, }; export const telemetryRoute: RouteProps = { - path: `${preferencesRoute.path}/telemetry` + path: `${preferencesRoute.path}/telemetry`, }; export const extensionRoute: RouteProps = { - path: `${preferencesRoute.path}/extensions` + path: `${preferencesRoute.path}/extensions`, }; export const preferencesURL = buildURL(preferencesRoute.path); diff --git a/src/common/routes/releases.ts b/src/common/routes/releases.ts index 2984bfd245..5df6909a2b 100644 --- a/src/common/routes/releases.ts +++ b/src/common/routes/releases.ts @@ -24,7 +24,7 @@ import { buildURL } from "../utils/buildUrl"; import { appsRoute } from "./apps"; export const releaseRoute: RouteProps = { - path: `${appsRoute.path}/releases/:namespace?/:name?` + path: `${appsRoute.path}/releases/:namespace?/:name?`, }; export interface ReleaseRouteParams { diff --git a/src/common/routes/resource-quotas.ts b/src/common/routes/resource-quotas.ts index 7d8a5163a2..03200aa2bb 100644 --- a/src/common/routes/resource-quotas.ts +++ b/src/common/routes/resource-quotas.ts @@ -23,7 +23,7 @@ import type { RouteProps } from "react-router"; import { buildURL } from "../utils/buildUrl"; export const resourceQuotaRoute: RouteProps = { - path: "/resourcequotas" + path: "/resourcequotas", }; export interface ResourceQuotaRouteParams { diff --git a/src/common/routes/secrets.ts b/src/common/routes/secrets.ts index 10ee187f64..059ac836d8 100644 --- a/src/common/routes/secrets.ts +++ b/src/common/routes/secrets.ts @@ -23,7 +23,7 @@ import type { RouteProps } from "react-router"; import { buildURL } from "../utils/buildUrl"; export const secretsRoute: RouteProps = { - path: "/secrets" + path: "/secrets", }; export interface SecretsRouteParams { diff --git a/src/common/routes/services.ts b/src/common/routes/services.ts index b4e3acdad9..161ff20f79 100644 --- a/src/common/routes/services.ts +++ b/src/common/routes/services.ts @@ -23,7 +23,7 @@ import type { RouteProps } from "react-router"; import { buildURL } from "../utils/buildUrl"; export const servicesRoute: RouteProps = { - path: "/services" + path: "/services", }; export interface ServicesRouteParams { diff --git a/src/common/routes/storage-classes.ts b/src/common/routes/storage-classes.ts index 1a0128cbf8..c1fdc307dd 100644 --- a/src/common/routes/storage-classes.ts +++ b/src/common/routes/storage-classes.ts @@ -23,7 +23,7 @@ import type { RouteProps } from "react-router"; import { buildURL } from "../utils/buildUrl"; export const storageClassesRoute: RouteProps = { - path: "/storage-classes" + path: "/storage-classes", }; export interface StorageClassesRouteParams { diff --git a/src/common/routes/storage.ts b/src/common/routes/storage.ts index 5de524795d..28b1d12594 100644 --- a/src/common/routes/storage.ts +++ b/src/common/routes/storage.ts @@ -29,8 +29,8 @@ export const storageRoute: RouteProps = { path: [ volumeClaimsRoute, volumesRoute, - storageClassesRoute - ].map(route => route.path.toString()) + storageClassesRoute, + ].map(route => route.path.toString()), }; export const storageURL = (params?: URLParams) => volumeClaimsURL(params); diff --git a/src/common/routes/user-management.ts b/src/common/routes/user-management.ts index 97aef36e1f..93c7a74692 100644 --- a/src/common/routes/user-management.ts +++ b/src/common/routes/user-management.ts @@ -24,22 +24,22 @@ import { buildURL, URLParams } from "../utils/buildUrl"; // Routes export const serviceAccountsRoute: RouteProps = { - path: "/service-accounts" + path: "/service-accounts", }; export const podSecurityPoliciesRoute: RouteProps = { - path: "/pod-security-policies" + path: "/pod-security-policies", }; export const rolesRoute: RouteProps = { - path: "/roles" + path: "/roles", }; export const clusterRolesRoute: RouteProps = { - path: "/cluster-roles" + path: "/cluster-roles", }; export const roleBindingsRoute: RouteProps = { - path: "/role-bindings" + path: "/role-bindings", }; export const clusterRoleBindingsRoute: RouteProps = { - path: "/cluster-role-bindings" + path: "/cluster-role-bindings", }; export const usersManagementRoute: RouteProps = { @@ -50,7 +50,7 @@ export const usersManagementRoute: RouteProps = { clusterRoleBindingsRoute, rolesRoute, clusterRolesRoute, - ].map(route => route.path.toString()) + ].map(route => route.path.toString()), }; // Route params diff --git a/src/common/routes/volume-claims.ts b/src/common/routes/volume-claims.ts index 42171328df..64a68b022b 100644 --- a/src/common/routes/volume-claims.ts +++ b/src/common/routes/volume-claims.ts @@ -23,7 +23,7 @@ import type { RouteProps } from "react-router"; import { buildURL } from "../utils/buildUrl"; export const volumeClaimsRoute: RouteProps = { - path: "/persistent-volume-claims" + path: "/persistent-volume-claims", }; export interface VolumeClaimsRouteParams { diff --git a/src/common/routes/volumes.ts b/src/common/routes/volumes.ts index c5a969e988..e8be884498 100644 --- a/src/common/routes/volumes.ts +++ b/src/common/routes/volumes.ts @@ -23,7 +23,7 @@ import type { RouteProps } from "react-router"; import { buildURL } from "../utils/buildUrl"; export const volumesRoute: RouteProps = { - path: "/persistent-volumes" + path: "/persistent-volumes", }; export interface VolumesRouteParams { diff --git a/src/common/routes/welcome.ts b/src/common/routes/welcome.ts index dd854d11a1..804fa4c313 100644 --- a/src/common/routes/welcome.ts +++ b/src/common/routes/welcome.ts @@ -23,7 +23,7 @@ import type { RouteProps } from "react-router"; import { buildURL } from "../utils/buildUrl"; export const welcomeRoute: RouteProps = { - path: "/welcome" + path: "/welcome", }; export const welcomeURL = buildURL(welcomeRoute.path); diff --git a/src/common/routes/workloads.ts b/src/common/routes/workloads.ts index 94a9378d02..f676992e2c 100644 --- a/src/common/routes/workloads.ts +++ b/src/common/routes/workloads.ts @@ -25,28 +25,28 @@ import type { KubeResource } from "../rbac"; // Routes export const overviewRoute: RouteProps = { - path: "/workloads" + path: "/workloads", }; export const podsRoute: RouteProps = { - path: "/pods" + path: "/pods", }; export const deploymentsRoute: RouteProps = { - path: "/deployments" + path: "/deployments", }; export const daemonSetsRoute: RouteProps = { - path: "/daemonsets" + path: "/daemonsets", }; export const statefulSetsRoute: RouteProps = { - path: "/statefulsets" + path: "/statefulsets", }; export const replicaSetsRoute: RouteProps = { - path: "/replicasets" + path: "/replicasets", }; export const jobsRoute: RouteProps = { - path: "/jobs" + path: "/jobs", }; export const cronJobsRoute: RouteProps = { - path: "/cronjobs" + path: "/cronjobs", }; export const workloadsRoute: RouteProps = { @@ -58,8 +58,8 @@ export const workloadsRoute: RouteProps = { statefulSetsRoute, replicaSetsRoute, jobsRoute, - cronJobsRoute - ].map(route => route.path.toString()) + cronJobsRoute, + ].map(route => route.path.toString()), }; // Route params diff --git a/src/common/sentry.ts b/src/common/sentry.ts index 8c386c4499..4a7d39d908 100644 --- a/src/common/sentry.ts +++ b/src/common/sentry.ts @@ -71,7 +71,7 @@ export function SentryInit() { initialScope: { tags: { "process": processName, - } + }, }, environment: isProduction ? "production" : "development", }); diff --git a/src/common/system-ca.ts b/src/common/system-ca.ts index 7ed0120569..22d85e3b42 100644 --- a/src/common/system-ca.ts +++ b/src/common/system-ca.ts @@ -20,22 +20,93 @@ */ import { isMac, isWindows } from "./vars"; -import winca from "win-ca"; -import macca from "mac-ca"; -import logger from "../main/logger"; +import wincaAPI from "win-ca/api"; +import https from "https"; +import { promiseExec } from "./utils/promise-exec"; -if (isMac) { - for (const crt of macca.all()) { - const attributes = crt.issuer?.attributes?.map((a: any) => `${a.name}=${a.value}`); +// DST Root CA X3, which was expired on 9.30.2021 +export const DSTRootCAX3 = "-----BEGIN CERTIFICATE-----\nMIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/\nMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\nDkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow\nPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD\nEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\nAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O\nrz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq\nOLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b\nxiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw\n7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD\naeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV\nHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG\nSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69\nikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr\nAvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz\nR8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5\nJDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo\nOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ\n-----END CERTIFICATE-----\n"; - logger.debug(`Using host CA: ${attributes.join(",")}`); +export function isCertActive(cert: string) { + const isExpired = typeof cert !== "string" || cert.includes(DSTRootCAX3); + + return !isExpired; +} + +/** + * Get root CA certificate from MacOSX system keychain + * Only return non-expred certificates. + */ +export async function getMacRootCA() { + // inspired mac-ca https://github.com/jfromaniello/mac-ca + const args = "find-certificate -a -p"; + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Cheatsheet#other_assertions + const splitPattern = /(?=-----BEGIN\sCERTIFICATE-----)/g; + const systemRootCertsPath = "/System/Library/Keychains/SystemRootCertificates.keychain"; + const bin = "/usr/bin/security"; + const trusted = (await promiseExec(`${bin} ${args}`)).stdout.toString().split(splitPattern); + const rootCA = (await promiseExec(`${bin} ${args} ${systemRootCertsPath}`)).stdout.toString().split(splitPattern); + + return [...new Set([...trusted, ...rootCA])].filter(isCertActive); +} + +/** + * Get root CA certificate from Windows system certificate store. + * Only return non-expred certificates. + */ +export function getWinRootCA(): Promise { + return new Promise((resolve) => { + const CAs: string[] = []; + + wincaAPI({ + format: wincaAPI.der2.pem, + inject: false, + ondata: (ca: string) => { + CAs.push(ca); + }, + onend: () => { + resolve(CAs.filter(isCertActive)); + }, + }); + }); +} + + +/** + * Add (or merge) CAs to https.globalAgent.options.ca + */ +export function injectCAs(CAs: string[]) { + for (const cert of CAs) { + if (Array.isArray(https.globalAgent.options.ca) && !https.globalAgent.options.ca.includes(cert)) { + https.globalAgent.options.ca.push(cert); + } else { + https.globalAgent.options.ca = [cert]; + } } } -if (isWindows) { - try { - winca.inject("+"); // see: https://github.com/ukoloff/win-ca#caveats - } catch (error) { - logger.error(`[CA]: failed to force load: ${error}`); +/** + * Inject CAs found in OS's (Windoes/MacOSX only) root certificate store to https.globalAgent.options.ca + */ +export async function injectSystemCAs() { + if (isMac) { + try { + const osxRootCAs = await getMacRootCA(); + + injectCAs(osxRootCAs); + } catch (error) { + console.warn(`[MAC-CA]: Error injecting root CAs from MacOSX. ${error?.message}`); + } + } + + if (isWindows) { + try { + const winRootCAs = await getWinRootCA(); + + wincaAPI.inject("+", winRootCAs); + + } catch (error) { + console.warn(`[WIN-CA]: Error injecting root CAs from Windows. ${error?.message}`); + } } } diff --git a/src/common/user-store/preferences-helpers.ts b/src/common/user-store/preferences-helpers.ts index 72e08faa42..a20730acdb 100644 --- a/src/common/user-store/preferences-helpers.ts +++ b/src/common/user-store/preferences-helpers.ts @@ -24,7 +24,7 @@ import path from "path"; import os from "os"; import { ThemeStore } from "../../renderer/theme.store"; import { getAppVersion, ObservableToggleSet } from "../utils"; -import type {monaco} from "react-monaco-editor"; +import type { monaco } from "react-monaco-editor"; import merge from "lodash/merge"; import { SemVer } from "semver"; @@ -43,9 +43,9 @@ export interface EditorConfiguration { export const defaultEditorConfig: EditorConfiguration = { lineNumbers: "on", miniMap: { - enabled: true + enabled: true, }, - tabSize: 2 + tabSize: 2, }; interface PreferenceDescription { @@ -237,7 +237,7 @@ const terminalCopyOnSelect: PreferenceDescription = { const hiddenTableColumns: PreferenceDescription<[string, string[]][], Map>> = { fromStore(val) { return new Map( - (val ?? []).map(([tableId, columnIds]) => [tableId, new ObservableToggleSet(columnIds)]) + (val ?? []).map(([tableId, columnIds]) => [tableId, new ObservableToggleSet(columnIds)]), ); }, toStore(val) { @@ -260,7 +260,7 @@ const syncKubeconfigEntries: PreferenceDescription [filePath, rest]) - ?? [[mainKubeFolder, {}]] + ?? [[mainKubeFolder, {}]], ); }, toStore(val) { @@ -283,13 +283,13 @@ const editorConfiguration: PreferenceDescription = { } return val; - } + }, }; type PreferencesModelType = typeof DESCRIPTORS[field] extends PreferenceDescription ? T : never; diff --git a/src/common/user-store/user-store.ts b/src/common/user-store/user-store.ts index 40f230ccbd..1e4cae3089 100644 --- a/src/common/user-store/user-store.ts +++ b/src/common/user-store/user-store.ts @@ -92,7 +92,7 @@ export class UserStore extends BaseStore /* implements UserStore /** * Monaco editor configs */ - @observable editorConfiguration:EditorConfiguration = {tabSize: null, miniMap: null, lineNumbers: null}; + @observable editorConfiguration:EditorConfiguration = { tabSize: null, miniMap: null, lineNumbers: null }; /** * The set of file/folder paths to be synced @@ -107,7 +107,9 @@ export class UserStore extends BaseStore /* implements UserStore return this.shell || process.env.SHELL || process.env.PTYSHELL; } - readonly isAllowedToDowngrade = new SemVer(getAppVersion()).prerelease[0] !== "latest"; + @computed get isAllowedToDowngrade() { + return new SemVer(getAppVersion()).prerelease[0] !== this.updateChannel; + } startMainReactions() { // track telemetry availability @@ -120,7 +122,7 @@ export class UserStore extends BaseStore /* implements UserStore app.setLoginItemSettings({ openAtLogin, openAsHidden: true, - args: ["--hidden"] + args: ["--hidden"], }); }, { fireImmediately: true, @@ -133,7 +135,7 @@ export class UserStore extends BaseStore /* implements UserStore automaticLayout: true, tabSize: this.editorConfiguration.tabSize, minimap: this.editorConfiguration.miniMap, - lineNumbers: this.editorConfiguration.lineNumbers + lineNumbers: this.editorConfiguration.lineNumbers, }; } diff --git a/src/common/utils/__tests__/tuple.test.ts b/src/common/utils/__tests__/tuple.test.ts index 5de0b64a87..1c414844b1 100644 --- a/src/common/utils/__tests__/tuple.test.ts +++ b/src/common/utils/__tests__/tuple.test.ts @@ -35,7 +35,7 @@ describe("tuple tests", () => { expect(i.next()).toEqual({ done: false, - value: [1, 2] + value: [1, 2], }); expect(i.next()).toEqual({ done: true, @@ -48,7 +48,7 @@ describe("tuple tests", () => { expect(i.next()).toEqual({ done: false, - value: [1, 2] + value: [1, 2], }); expect(i.next()).toEqual({ done: true, diff --git a/src/common/utils/autobind.ts b/src/common/utils/autobind.ts index cdb6903259..583d4c4bc5 100644 --- a/src/common/utils/autobind.ts +++ b/src/common/utils/autobind.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import {boundMethod, boundClass} from "autobind-decorator"; +import { boundMethod, boundClass } from "autobind-decorator"; import autoBindClass, { Options } from "auto-bind"; import autoBindReactClass from "auto-bind/react"; diff --git a/src/common/utils/base64.ts b/src/common/utils/base64.ts index d629abe9ac..8484e128b1 100755 --- a/src/common/utils/base64.ts +++ b/src/common/utils/base64.ts @@ -29,5 +29,5 @@ export const base64 = { }, encode(data: string) { return Utf8.parse(data).toString(Base64); - } + }, }; diff --git a/src/common/utils/buildUrl.ts b/src/common/utils/buildUrl.ts index 20e6e7e861..03909917eb 100644 --- a/src/common/utils/buildUrl.ts +++ b/src/common/utils/buildUrl.ts @@ -45,7 +45,7 @@ export function buildURL

(path: str export function buildURLPositional

(path: string | any) { const builder = buildURL(path); - return function(params?: P, query?: Q, fragment?: string): string { + return function (params?: P, query?: Q, fragment?: string): string { return builder({ params, query, fragment }); }; } diff --git a/src/common/utils/convertMemory.ts b/src/common/utils/convertMemory.ts index 020355e101..ce909307b1 100644 --- a/src/common/utils/convertMemory.ts +++ b/src/common/utils/convertMemory.ts @@ -33,7 +33,7 @@ export function unitsToBytes(value: string) { const index = suffixes.indexOf(suffix); return parseInt( - (parseFloat(value) * Math.pow(base, index + 1)).toFixed(1) + (parseFloat(value) * Math.pow(base, index + 1)).toFixed(1), ); } diff --git a/src/common/utils/downloadFile.ts b/src/common/utils/downloadFile.ts index 6ec2f2ad4a..6b02b8741f 100644 --- a/src/common/utils/downloadFile.ts +++ b/src/common/utils/downloadFile.ts @@ -53,7 +53,7 @@ export function downloadFile({ url, timeout, gzip = true }: DownloadFileOptions) promise, cancel() { req.abort(); - } + }, }; } @@ -62,6 +62,6 @@ export function downloadJson(args: DownloadFileOptions): DownloadFileTicket return { promise: promise.then(res => JSON.parse(res.toString())), - ...rest + ...rest, }; } diff --git a/src/common/utils/hash-set.ts b/src/common/utils/hash-set.ts index 87fa8daa4c..272291e015 100644 --- a/src/common/utils/hash-set.ts +++ b/src/common/utils/hash-set.ts @@ -100,7 +100,7 @@ export class HashSet implements Set { return index < values.length ? { value: [keys[index], values[index]], done: false } : { done: true, value: undefined }; - } + }, }); } @@ -117,7 +117,7 @@ export class HashSet implements Set { return nextIndex < observableValues.length ? { value: observableValues[nextIndex++], done: false } : { done: true, value: undefined }; - } + }, }); } @@ -221,7 +221,7 @@ export class ObservableHashSet implements Set, IInterceptable implements Set, IInterceptable { const { id = uuid.v4(), name, - url + url, } = data; const weblink = { id, name, url }; @@ -84,7 +84,7 @@ export class WeblinkStore extends BaseStore { toJSON(): WeblinkStoreModel { const model: WeblinkStoreModel = { - weblinks: this.weblinks + weblinks: this.weblinks, }; return toJS(model); diff --git a/src/extensions/__tests__/extension-compatibility.test.ts b/src/extensions/__tests__/extension-compatibility.test.ts index d8e789a9d9..6bcac67501 100644 --- a/src/extensions/__tests__/extension-compatibility.test.ts +++ b/src/extensions/__tests__/extension-compatibility.test.ts @@ -37,9 +37,9 @@ describe("extension compatibility", () => { }); it("has no extension comparator", () => { - const manifest = { name: "extensionName", version: "0.0.1"}; + const manifest = { name: "extensionName", version: "0.0.1" }; - expect(isCompatibleExtension(manifest,)).toBe(false); + expect(isCompatibleExtension(manifest)).toBe(false); }); it.each([ @@ -76,9 +76,9 @@ describe("extension compatibility", () => { expected: false, }, ])("extension comparator test: %p", ({ comparator, expected }) => { - const manifest: LensExtensionManifest = { name: "extensionName", version: "0.0.1", engines: { lens: comparator}}; + const manifest: LensExtensionManifest = { name: "extensionName", version: "0.0.1", engines: { lens: comparator }}; - expect(isCompatibleExtension(manifest,)).toBe(expected); + expect(isCompatibleExtension(manifest)).toBe(expected); }); }); @@ -91,9 +91,9 @@ describe("extension compatibility", () => { }); it("has no extension comparator", () => { - const manifest = { name: "extensionName", version: "0.0.1"}; + const manifest = { name: "extensionName", version: "0.0.1" }; - expect(isCompatibleExtension(manifest,)).toBe(false); + expect(isCompatibleExtension(manifest)).toBe(false); }); it.each([ @@ -130,9 +130,9 @@ describe("extension compatibility", () => { expected: false, }, ])("extension comparator test: %p", ({ comparator, expected }) => { - const manifest: LensExtensionManifest = { name: "extensionName", version: "0.0.1", engines: { lens: comparator}}; + const manifest: LensExtensionManifest = { name: "extensionName", version: "0.0.1", engines: { lens: comparator }}; - expect(isCompatibleExtension(manifest,)).toBe(expected); + expect(isCompatibleExtension(manifest)).toBe(expected); }); }); }); diff --git a/src/extensions/__tests__/extension-discovery.test.ts b/src/extensions/__tests__/extension-discovery.test.ts index 6975d8a7f2..b7861cd5b0 100644 --- a/src/extensions/__tests__/extension-discovery.test.ts +++ b/src/extensions/__tests__/extension-discovery.test.ts @@ -32,13 +32,13 @@ jest.setTimeout(60_000); jest.mock("../../common/ipc"); jest.mock("chokidar", () => ({ - watch: jest.fn() + watch: jest.fn(), })); jest.mock("../extension-installer", () => ({ extensionInstaller: { extensionPackagesRoot: "", - installPackage: jest.fn() - } + installPackage: jest.fn(), + }, })); jest.mock("electron", () => ({ app: { @@ -72,7 +72,7 @@ describe("ExtensionDiscovery", () => { beforeEach(() => { mockFs({ [`${os.homedir()}/.k8slens/extensions/my-extension/package.json`]: JSON.stringify({ - name: "my-extension" + name: "my-extension", }), }); }); @@ -91,11 +91,11 @@ describe("ExtensionDiscovery", () => { } return mockWatchInstance; - }) + }), }; mockedWatch.mockImplementationOnce(() => - (mockWatchInstance) as any + (mockWatchInstance) as any, ); const extensionDiscovery = ExtensionDiscovery.createInstance(); @@ -134,11 +134,11 @@ describe("ExtensionDiscovery", () => { } return mockWatchInstance; - }) + }), }; mockedWatch.mockImplementationOnce(() => - (mockWatchInstance) as any + (mockWatchInstance) as any, ); const extensionDiscovery = ExtensionDiscovery.createInstance(); diff --git a/src/extensions/__tests__/extension-loader.test.ts b/src/extensions/__tests__/extension-loader.test.ts index e35afe5a1b..03f4257fdf 100644 --- a/src/extensions/__tests__/extension-loader.test.ts +++ b/src/extensions/__tests__/extension-loader.test.ts @@ -35,9 +35,9 @@ jest.mock("../extensions-store", () => ({ ExtensionsStore: { getInstance: () => ({ whenLoaded: Promise.resolve(true), - mergeState: jest.fn() - }) - } + mergeState: jest.fn(), + }), + }, })); jest.mock( @@ -118,13 +118,13 @@ jest.mock( ]); }, 10); } - } + }, ), }, }), { virtual: true, - } + }, ); describe("ExtensionLoader", () => { @@ -189,11 +189,11 @@ describe("ExtensionLoader", () => { expect(ExtensionsStore.getInstance().mergeState).toHaveBeenCalledWith({ "manifest/path": { enabled: false, - name: "TestExtension" + name: "TestExtension", }, "manifest/path2": { enabled: true, - name: "TestExtension2" + name: "TestExtension2", }}); }); }); diff --git a/src/extensions/__tests__/lens-extension.test.ts b/src/extensions/__tests__/lens-extension.test.ts index c9c52d1637..97f5b3c913 100644 --- a/src/extensions/__tests__/lens-extension.test.ts +++ b/src/extensions/__tests__/lens-extension.test.ts @@ -32,14 +32,14 @@ describe("lens extension", () => { ext = new LensExtension({ manifest: { name: "foo-bar", - version: "0.1.1" + version: "0.1.1", }, id: "/this/is/fake/package.json", absolutePath: "/absolute/fake/", manifestPath: "/this/is/fake/package.json", isBundled: false, isEnabled: true, - isCompatible: true + isCompatible: true, }); }); diff --git a/src/extensions/common-api/app.ts b/src/extensions/common-api/app.ts index 0b5e463962..401fc4d283 100644 --- a/src/extensions/common-api/app.ts +++ b/src/extensions/common-api/app.ts @@ -21,6 +21,7 @@ import { getAppVersion } from "../../common/utils"; import { ExtensionsStore } from "../extensions-store"; +import * as Preferences from "./user-preferences"; export const version = getAppVersion(); export { isSnap, isWindows, isMac, isLinux, appName, slackUrl, issuesTrackerUrl } from "../../common/vars"; @@ -28,3 +29,5 @@ export { isSnap, isWindows, isMac, isLinux, appName, slackUrl, issuesTrackerUrl export function getEnabledExtensions(): string[] { return ExtensionsStore.getInstance().enabledExtensions; } + +export { Preferences }; diff --git a/src/extensions/common-api/index.ts b/src/extensions/common-api/index.ts index 9fdf3a837b..19b4f3a930 100644 --- a/src/extensions/common-api/index.ts +++ b/src/extensions/common-api/index.ts @@ -35,5 +35,5 @@ export { Store, Types, Util, - logger + logger, }; diff --git a/src/extensions/common-api/user-preferences.ts b/src/extensions/common-api/user-preferences.ts new file mode 100644 index 0000000000..36ee2dd1e4 --- /dev/null +++ b/src/extensions/common-api/user-preferences.ts @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import { UserStore } from "../../common/user-store"; + +/** + * Get the configured kubectl binaries path. + */ +export function getKubectlPath(): string | undefined { + return UserStore.getInstance().kubectlBinariesPath; +} diff --git a/src/extensions/extension-discovery.ts b/src/extensions/extension-discovery.ts index 077f29d694..1463d6180d 100644 --- a/src/extensions/extension-discovery.ts +++ b/src/extensions/extension-discovery.ts @@ -175,8 +175,8 @@ export class ExtensionDiscovery extends Singleton { awaitWriteFinish: { // Wait 300ms until the file size doesn't change to consider the file written. // For a small file like package.json this should be plenty of time. - stabilityThreshold: 300 - } + stabilityThreshold: 300, + }, }) // Extension add is detected by watching "/package.json" add .on("add", this.handleWatchFileAdd) @@ -370,7 +370,7 @@ export class ExtensionDiscovery extends Singleton { manifest, isBundled, isEnabled, - isCompatible + isCompatible, }; } catch (error) { if (error.code === "ENOTDIR") { @@ -407,7 +407,7 @@ export class ExtensionDiscovery extends Singleton { */ installBundledPackages(packageJsonPath: string, extensions: InstalledExtension[]): Promise { const dependencies = Object.fromEntries( - extensions.map(extension => [extension.manifest.name, extension.absolutePath]) + extensions.map(extension => [extension.manifest.name, extension.absolutePath]), ); return extensionInstaller.installPackages(packageJsonPath, { dependencies }); @@ -482,7 +482,7 @@ export class ExtensionDiscovery extends Singleton { toJSON(): ExtensionDiscoveryChannelMessage { return toJS({ - isLoaded: this.isLoaded + isLoaded: this.isLoaded, }); } diff --git a/src/extensions/extension-installer.ts b/src/extensions/extension-installer.ts index 57e67183bf..97eab7999f 100644 --- a/src/extensions/extension-installer.ts +++ b/src/extensions/extension-installer.ts @@ -54,7 +54,7 @@ export class ExtensionInstaller { try { // Write the package.json which will be installed in .installDependencies() await fs.writeFile(path.join(packageJsonPath), JSON.stringify(packagesJson, null, 2), { - mode: 0o600 + mode: 0o600, }); logger.info(`${logModule} installing dependencies at ${extensionPackagesRoot()}`); @@ -86,7 +86,7 @@ export class ExtensionInstaller { const child = child_process.fork(this.npmPath, args, { cwd: extensionPackagesRoot(), silent: true, - env: {} + env: {}, }); let stderr = ""; diff --git a/src/extensions/extension-loader.ts b/src/extensions/extension-loader.ts index b6ed1a5a47..8d249355c3 100644 --- a/src/extensions/extension-loader.ts +++ b/src/extensions/extension-loader.ts @@ -133,7 +133,7 @@ export class ExtensionLoader extends Singleton { .map(([extId, extension]) => [extId, { enabled: extension.isEnabled, name: extension.manifest.name, - }]) + }]), ); } @@ -254,7 +254,7 @@ export class ExtensionLoader extends Singleton { this.autoInitExtensions(async (extension: LensMainExtension) => { // Each .add returns a function to remove the item const removeItems = [ - registries.MenuRegistry.getInstance().add(extension.appMenus) + registries.MenuRegistry.getInstance().add(extension.appMenus), ]; this.events.on("remove", (removedExtension: LensRendererExtension) => { diff --git a/src/extensions/extensions-store.ts b/src/extensions/extensions-store.ts index be40181242..681735bfbb 100644 --- a/src/extensions/extensions-store.ts +++ b/src/extensions/extensions-store.ts @@ -45,8 +45,8 @@ export class ExtensionsStore extends BaseStore { @computed get enabledExtensions() { return Array.from(this.state.values()) - .filter(({enabled}) => enabled) - .map(({name}) => name); + .filter(({ enabled }) => enabled) + .map(({ name }) => name); } protected state = observable.map(); diff --git a/src/extensions/ipc/ipc-main.ts b/src/extensions/ipc/ipc-main.ts index 09d26b00fb..05d225cb7c 100644 --- a/src/extensions/ipc/ipc-main.ts +++ b/src/extensions/ipc/ipc-main.ts @@ -44,12 +44,12 @@ export abstract class IpcMain extends IpcRegistrar { listen(channel: string, listener: (event: Electron.IpcRendererEvent, ...args: any[]) => any): Disposer { const prefixedChannel = `extensions@${this[IpcPrefix]}:${channel}`; const cleanup = once(() => { - logger.info(`[IPC-RENDERER]: removing extension listener`, { channel, extension: { name: this.extension.name, version: this.extension.version } }); + logger.info(`[IPC-RENDERER]: removing extension listener`, { channel, extension: { name: this.extension.name, version: this.extension.version }}); return ipcMain.removeListener(prefixedChannel, listener); }); - logger.info(`[IPC-RENDERER]: adding extension listener`, { channel, extension: { name: this.extension.name, version: this.extension.version } }); + logger.info(`[IPC-RENDERER]: adding extension listener`, { channel, extension: { name: this.extension.name, version: this.extension.version }}); ipcMain.addListener(prefixedChannel, listener); this.extension[Disposers].push(cleanup); @@ -64,10 +64,10 @@ export abstract class IpcMain extends IpcRegistrar { handle(channel: string, handler: (event: Electron.IpcMainInvokeEvent, ...args: any[]) => any): void { const prefixedChannel = `extensions@${this[IpcPrefix]}:${channel}`; - logger.info(`[IPC-RENDERER]: adding extension handler`, { channel, extension: { name: this.extension.name, version: this.extension.version } }); + logger.info(`[IPC-RENDERER]: adding extension handler`, { channel, extension: { name: this.extension.name, version: this.extension.version }}); ipcMainHandle(prefixedChannel, handler); this.extension[Disposers].push(() => { - logger.info(`[IPC-RENDERER]: removing extension handler`, { channel, extension: { name: this.extension.name, version: this.extension.version } }); + logger.info(`[IPC-RENDERER]: removing extension handler`, { channel, extension: { name: this.extension.name, version: this.extension.version }}); return ipcMain.removeHandler(prefixedChannel); }); diff --git a/src/extensions/ipc/ipc-renderer.ts b/src/extensions/ipc/ipc-renderer.ts index 364ebc5d73..6ec4b870b7 100644 --- a/src/extensions/ipc/ipc-renderer.ts +++ b/src/extensions/ipc/ipc-renderer.ts @@ -44,12 +44,12 @@ export abstract class IpcRenderer extends IpcRegistrar { listen(channel: string, listener: (event: Electron.IpcRendererEvent, ...args: any[]) => any): Disposer { const prefixedChannel = `extensions@${this[IpcPrefix]}:${channel}`; const cleanup = once(() => { - console.info(`[IPC-RENDERER]: removing extension listener`, { channel, extension: { name: this.extension.name, version: this.extension.version } }); + console.info(`[IPC-RENDERER]: removing extension listener`, { channel, extension: { name: this.extension.name, version: this.extension.version }}); return ipcRenderer.removeListener(prefixedChannel, listener); }); - console.info(`[IPC-RENDERER]: adding extension listener`, { channel, extension: { name: this.extension.name, version: this.extension.version } }); + console.info(`[IPC-RENDERER]: adding extension listener`, { channel, extension: { name: this.extension.name, version: this.extension.version }}); ipcRenderer.addListener(prefixedChannel, listener); this.extension[Disposers].push(cleanup); diff --git a/src/extensions/registries/__tests__/page-registry.test.ts b/src/extensions/registries/__tests__/page-registry.test.ts index 7be2fb851c..a6ff672401 100644 --- a/src/extensions/registries/__tests__/page-registry.test.ts +++ b/src/extensions/registries/__tests__/page-registry.test.ts @@ -59,14 +59,14 @@ describe("page registry tests", () => { ext = new LensExtension({ manifest: { name: "foo-bar", - version: "0.1.1" + version: "0.1.1", }, id: "/this/is/fake/package.json", absolutePath: "/absolute/fake/", manifestPath: "/this/is/fake/package.json", isBundled: false, isEnabled: true, - isCompatible: true + isCompatible: true, }); UserStore.createInstance(); ThemeStore.createInstance(); @@ -75,30 +75,30 @@ describe("page registry tests", () => { GlobalPageRegistry.createInstance().add({ id: "page-with-params", components: { - Page: () => React.createElement("Page with params") + Page: () => React.createElement("Page with params"), }, params: { test1: "test1-default", - test2: "" // no default value, just declaration + test2: "", // no default value, just declaration }, }, ext); GlobalPageRegistry.createInstance().add([ { 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); }); @@ -168,7 +168,7 @@ describe("page registry tests", () => { it("returns matching page", () => { const page = GlobalPageRegistry.getInstance().getByPageTarget({ pageId: "test-page", - extensionId: ext.name + extensionId: ext.name, }); expect(page.id).toEqual("test-page"); @@ -177,7 +177,7 @@ describe("page registry tests", () => { it("returns null if target not found", () => { const page = GlobalPageRegistry.getInstance().getByPageTarget({ pageId: "wrong-page", - extensionId: ext.name + extensionId: ext.name, }); expect(page).toBeNull(); diff --git a/src/extensions/registries/page-registry.ts b/src/extensions/registries/page-registry.ts index 3e97d15c3f..aa788681d5 100644 --- a/src/extensions/registries/page-registry.ts +++ b/src/extensions/registries/page-registry.ts @@ -66,7 +66,7 @@ export interface RegisteredPage { } export function getExtensionPageUrl(target: PageTarget): string { - const { extensionId, pageId = "", params: targetParams = {} } = target; + const { extensionId, pageId = "", params: targetParams = {}} = target; const pagePath = ["/extension", sanitizeExtensionName(extensionId), pageId] .filter(Boolean) @@ -137,7 +137,7 @@ class PageRegistry extends BaseRegistry { if (notAStringValue && !(parse || stringify)) { throw new Error( `PageRegistry: param's "${paramName}" initialization has failed: - paramInit.parse() and paramInit.stringify() are required for non string | string[] "defaultValue"` + paramInit.parse() and paramInit.stringify() are required for non string | string[] "defaultValue"`, ); } diff --git a/src/extensions/renderer-api/kube-object-status.ts b/src/extensions/renderer-api/kube-object-status.ts index 65a80b7867..cf2f079bec 100644 --- a/src/extensions/renderer-api/kube-object-status.ts +++ b/src/extensions/renderer-api/kube-object-status.ts @@ -28,5 +28,5 @@ export type KubeObjectStatus = { export enum KubeObjectStatusLevel { INFO = 1, WARNING = 2, - CRITICAL = 3 + CRITICAL = 3, } diff --git a/src/main/__test__/cluster.test.ts b/src/main/__test__/cluster.test.ts index 8c50518c85..ffd77da3d2 100644 --- a/src/main/__test__/cluster.test.ts +++ b/src/main/__test__/cluster.test.ts @@ -35,13 +35,13 @@ jest.mock("winston", () => ({ simple: jest.fn(), label: jest.fn(), timestamp: jest.fn(), - printf: jest.fn() + printf: jest.fn(), }, createLogger: jest.fn().mockReturnValue(logger), transports: { Console: jest.fn(), File: jest.fn(), - } + }, })); jest.mock("../../common/ipc"); @@ -85,7 +85,7 @@ describe("create clusters", () => { }], kind: "Config", preferences: {}, - }) + }), }; mockFs(mockOpts); @@ -93,7 +93,7 @@ describe("create clusters", () => { c = new Cluster({ id: "foo", contextName: "minikube", - kubeConfigPath: "minikube-config.yml" + kubeConfigPath: "minikube-config.yml", }); }); @@ -126,12 +126,12 @@ describe("create clusters", () => { }({ id: "foo", contextName: "minikube", - kubeConfigPath: "minikube-config.yml" + kubeConfigPath: "minikube-config.yml", }); c.contextHandler = { ensureServer: jest.fn(), - stopServer: jest.fn() + stopServer: jest.fn(), } as any; jest.spyOn(c, "reconnect"); diff --git a/src/main/__test__/context-handler.test.ts b/src/main/__test__/context-handler.test.ts index 8c2c49ef44..32a1acd2ef 100644 --- a/src/main/__test__/context-handler.test.ts +++ b/src/main/__test__/context-handler.test.ts @@ -91,7 +91,7 @@ AppPaths.init(); describe("ContextHandler", () => { beforeEach(() => { mockFs({ - "tmp": {} + "tmp": {}, }); PrometheusProviderRegistry.createInstance(); diff --git a/src/main/__test__/kube-auth-proxy.test.ts b/src/main/__test__/kube-auth-proxy.test.ts index faeaba0668..f04b948861 100644 --- a/src/main/__test__/kube-auth-proxy.test.ts +++ b/src/main/__test__/kube-auth-proxy.test.ts @@ -41,7 +41,7 @@ jest.mock("winston", () => ({ transports: { Console: jest.fn(), File: jest.fn(), - } + }, })); jest.mock("../../common/ipc"); diff --git a/src/main/__test__/kubeconfig-manager.test.ts b/src/main/__test__/kubeconfig-manager.test.ts index cfa0deeb51..f5d1f0181c 100644 --- a/src/main/__test__/kubeconfig-manager.test.ts +++ b/src/main/__test__/kubeconfig-manager.test.ts @@ -43,7 +43,7 @@ jest.mock("winston", () => ({ transports: { Console: jest.fn(), File: jest.fn(), - } + }, })); import { KubeconfigManager } from "../kubeconfig-manager"; @@ -102,7 +102,7 @@ describe("kubeconfig manager tests", () => { }], kind: "Config", preferences: {}, - }) + }), }; mockFs(mockOpts); diff --git a/src/main/__test__/lens-proxy.test.ts b/src/main/__test__/lens-proxy.test.ts index f7767fc685..c68da9cc94 100644 --- a/src/main/__test__/lens-proxy.test.ts +++ b/src/main/__test__/lens-proxy.test.ts @@ -25,7 +25,7 @@ describe("isLongRunningRequest", () => { it("returns true on watches", () => { ["watch=true", "watch=1", "watch"].forEach((param) => { expect( - isLongRunningRequest(`/api/v1/namespaces/default/pods?${param}`) + isLongRunningRequest(`/api/v1/namespaces/default/pods?${param}`), ).toBeTruthy(); }); }); @@ -33,7 +33,7 @@ describe("isLongRunningRequest", () => { it("returns false on disabled watches", () => { ["watch=false", "watch=0", ""].forEach((param) => { expect( - isLongRunningRequest(`/api/v1/namespaces/default/pods?${param}`) + isLongRunningRequest(`/api/v1/namespaces/default/pods?${param}`), ).toBeFalsy(); }); }); @@ -41,7 +41,7 @@ describe("isLongRunningRequest", () => { it("returns true on follows", () => { ["follow=true", "follow=1", "follow"].forEach((param) => { expect( - isLongRunningRequest(`/api/v1/namespaces/default/pods/foo/log?${param}`) + isLongRunningRequest(`/api/v1/namespaces/default/pods/foo/log?${param}`), ).toBeTruthy(); }); }); @@ -49,7 +49,7 @@ describe("isLongRunningRequest", () => { it("returns false on disabled follows", () => { ["follow=false", "follow=0", ""].forEach((param) => { expect( - isLongRunningRequest(`/api/v1/namespaces/default/pods/foo/log?${param}`) + isLongRunningRequest(`/api/v1/namespaces/default/pods/foo/log?${param}`), ).toBeFalsy(); }); }); diff --git a/src/main/__test__/router.test.ts b/src/main/__test__/router.test.ts index 102be317eb..278467eca0 100644 --- a/src/main/__test__/router.test.ts +++ b/src/main/__test__/router.test.ts @@ -44,7 +44,7 @@ describe("Router", () => { it("blocks path traversal attacks", async () => { const response: any = { statusCode: 200, - end: jest.fn() + end: jest.fn(), }; await (Router as any).handleStaticFile({ @@ -63,10 +63,10 @@ describe("Router", () => { statusCode: 200, write: jest.fn(), setHeader: jest.fn(), - end: jest.fn() + end: jest.fn(), }; const req: any = { - url: "" + url: "", }; await (Router as any).handleStaticFile({ diff --git a/src/main/app-updater.ts b/src/main/app-updater.ts index 3813d24bf1..dffe3b9999 100644 --- a/src/main/app-updater.ts +++ b/src/main/app-updater.ts @@ -131,9 +131,13 @@ export const startUpdateChecking = once(function (interval = 1000 * 60 * 60 * 24 }); export async function checkForUpdates(): Promise { + const userStore = UserStore.getInstance(); + try { logger.info(`📡 Checking for app updates`); + autoUpdater.channel = userStore.updateChannel; + autoUpdater.allowDowngrade = userStore.isAllowedToDowngrade; await autoUpdater.checkForUpdates(); } catch (error) { logger.error(`${AutoUpdateLogPrefix}: failed with an error`, { error: String(error) }); diff --git a/src/main/catalog-sources/__test__/kubeconfig-sync.test.ts b/src/main/catalog-sources/__test__/kubeconfig-sync.test.ts index 2e49b09c16..5c3a7094ae 100644 --- a/src/main/catalog-sources/__test__/kubeconfig-sync.test.ts +++ b/src/main/catalog-sources/__test__/kubeconfig-sync.test.ts @@ -67,7 +67,7 @@ describe("kubeconfig-sync.source tests", () => { clusters: [], users: [], contexts: [], - currentContext: "foobar" + currentContext: "foobar", }); expect(configToModels(config, "").length).toBe(0); @@ -88,7 +88,7 @@ describe("kubeconfig-sync.source tests", () => { name: "context-name", user: "user-name", }], - currentContext: "foobar" + currentContext: "foobar", }); const models = configToModels(config, "/bar"); @@ -135,7 +135,7 @@ describe("kubeconfig-sync.source tests", () => { user: "user-name", }, }], - currentContext: "foobar" + currentContext: "foobar", }); const rootSource = new ObservableMap(); const filePath = "/bar"; @@ -178,7 +178,7 @@ describe("kubeconfig-sync.source tests", () => { user: "user-name", }, }], - currentContext: "foobar" + currentContext: "foobar", }); const rootSource = new ObservableMap(); const filePath = "/bar"; @@ -232,7 +232,7 @@ describe("kubeconfig-sync.source tests", () => { user: "user-name", }, }], - currentContext: "foobar" + currentContext: "foobar", }); const rootSource = new ObservableMap(); const filePath = "/bar"; @@ -276,7 +276,7 @@ describe("kubeconfig-sync.source tests", () => { user: "user-name", }, }], - currentContext: "foobar" + currentContext: "foobar", }); computeDiff(newContents, rootSource, filePath); diff --git a/src/main/catalog-sources/general.ts b/src/main/catalog-sources/general.ts index a002228274..9c5cbd886d 100644 --- a/src/main/catalog-sources/general.ts +++ b/src/main/catalog-sources/general.ts @@ -29,18 +29,18 @@ export const catalogEntity = new GeneralEntity({ uid: "catalog-entity", name: "Catalog", source: "app", - labels: {} + labels: {}, }, spec: { path: catalogURL(), icon: { material: "view_list", - background: "#3d90ce" - } + background: "#3d90ce", + }, }, status: { phase: "active", - } + }, }); const preferencesEntity = new GeneralEntity({ @@ -48,18 +48,18 @@ const preferencesEntity = new GeneralEntity({ uid: "preferences-entity", name: "Preferences", source: "app", - labels: {} + labels: {}, }, spec: { path: preferencesURL(), icon: { material: "settings", - background: "#3d90ce" - } + background: "#3d90ce", + }, }, status: { phase: "active", - } + }, }); const welcomePageEntity = new GeneralEntity({ @@ -67,24 +67,24 @@ const welcomePageEntity = new GeneralEntity({ uid: "welcome-page-entity", name: "Welcome Page", source: "app", - labels: {} + labels: {}, }, spec: { path: welcomeURL(), icon: { material: "meeting_room", - background: "#3d90ce" - } + background: "#3d90ce", + }, }, status: { phase: "active", - } + }, }); const generalEntities = observable([ catalogEntity, preferencesEntity, - welcomePageEntity + welcomePageEntity, ]); export function syncGeneralEntities() { diff --git a/src/main/catalog-sources/kubeconfig-sync.ts b/src/main/catalog-sources/kubeconfig-sync.ts index 14d7bef128..e011ff6860 100644 --- a/src/main/catalog-sources/kubeconfig-sync.ts +++ b/src/main/catalog-sources/kubeconfig-sync.ts @@ -89,7 +89,7 @@ export class KubeconfigSyncManager extends Singleton { catalogEntityRegistry.addComputedSource(KubeconfigSyncManager.syncName, computed(() => ( Array.from(iter.flatMap( this.sources.values(), - ([entities]) => entities.get() + ([entities]) => entities.get(), )) ))); @@ -212,7 +212,7 @@ export function computeDiff(contents: string, source: RootSource, filePath: stri // add new clusters to the source try { const clusterId = createHash("md5").update(`${filePath}:${contextName}`).digest("hex"); - const cluster = ClusterStore.getInstance().getById(clusterId) || new Cluster({ ...model, id: clusterId}); + const cluster = ClusterStore.getInstance().getById(clusterId) || new Cluster({ ...model, id: clusterId }); if (!cluster.apiUrl) { throw new Error("Cluster constructor failed, see above error"); diff --git a/src/main/catalog-sources/weblinks.ts b/src/main/catalog-sources/weblinks.ts index c8e983f3be..7c7917aa1d 100644 --- a/src/main/catalog-sources/weblinks.ts +++ b/src/main/catalog-sources/weblinks.ts @@ -75,15 +75,15 @@ export function syncWeblinks() { uid: weblinkData.id, name: weblinkData.name, source: "local", - labels: {} + labels: {}, }, spec: { - url: weblinkData.url + url: weblinkData.url, }, status: { phase: "available", - active: true - } + active: true, + }, }); webLinkEntities.set(weblinkData.id, [ @@ -100,7 +100,7 @@ export function syncWeblinks() { webLinkEntities.delete(weblinkId); } } - }, {fireImmediately: true}); + }, { fireImmediately: true }); catalogEntityRegistry.addComputedSource("weblinks", computed(() => Array.from(webLinkEntities.values(), ([link]) => link))); } diff --git a/src/main/catalog/__tests__/catalog-entity-registry.test.ts b/src/main/catalog/__tests__/catalog-entity-registry.test.ts index ee8450ae26..b389bdfbca 100644 --- a/src/main/catalog/__tests__/catalog-entity-registry.test.ts +++ b/src/main/catalog/__tests__/catalog-entity-registry.test.ts @@ -52,28 +52,28 @@ describe("CatalogEntityRegistry", () => { uid: "test", name: "test-link", source: "test", - labels: {} + labels: {}, }, spec: { - url: "https://k8slens.dev" + url: "https://k8slens.dev", }, status: { - phase: "available" - } + phase: "available", + }, }); const invalidEntity = new InvalidEntity({ metadata: { uid: "invalid", name: "test-link", source: "test", - labels: {} + labels: {}, }, spec: { - url: "https://k8slens.dev" + url: "https://k8slens.dev", }, status: { - phase: "available" - } + phase: "available", + }, }); beforeEach(() => { diff --git a/src/main/catalog/catalog-entity-registry.ts b/src/main/catalog/catalog-entity-registry.ts index e9e441ae2b..063f6f2356 100644 --- a/src/main/catalog/catalog-entity-registry.ts +++ b/src/main/catalog/catalog-entity-registry.ts @@ -46,8 +46,8 @@ export class CatalogEntityRegistry { return Array.from( iter.filter( iter.flatMap(this.sources.values(), source => source.get()), - entity => this.categoryRegistry.getCategoryForEntity(entity) - ) + entity => this.categoryRegistry.getCategoryForEntity(entity), + ), ); } diff --git a/src/main/cluster-detectors/detector-registry.ts b/src/main/cluster-detectors/detector-registry.ts index 5d3461b0bb..5f4f12175e 100644 --- a/src/main/cluster-detectors/detector-registry.ts +++ b/src/main/cluster-detectors/detector-registry.ts @@ -35,7 +35,7 @@ export class DetectorRegistry extends Singleton { } async detectForCluster(cluster: Cluster): Promise { - const results: {[key: string]: ClusterDetectionResult } = {}; + const results: { [key: string]: ClusterDetectionResult } = {}; for (const detectorClass of this.registry) { const detector = new detectorClass(cluster); diff --git a/src/main/cluster-detectors/distribution-detector.ts b/src/main/cluster-detectors/distribution-detector.ts index 98173ef81c..6ad2df8815 100644 --- a/src/main/cluster-detectors/distribution-detector.ts +++ b/src/main/cluster-detectors/distribution-detector.ts @@ -30,86 +30,86 @@ export class DistributionDetector extends BaseClusterDetector { this.version = await this.getKubernetesVersion(); if (this.isRke()) { - return { value: "rke", accuracy: 80}; + return { value: "rke", accuracy: 80 }; } if (this.isRancherDesktop()) { - return { value: "rancher-desktop", accuracy: 80}; + return { value: "rancher-desktop", accuracy: 80 }; } if (this.isK3s()) { - return { value: "k3s", accuracy: 80}; + return { value: "k3s", accuracy: 80 }; } if (this.isGKE()) { - return { value: "gke", accuracy: 80}; + return { value: "gke", accuracy: 80 }; } if (this.isEKS()) { - return { value: "eks", accuracy: 80}; + return { value: "eks", accuracy: 80 }; } if (this.isIKS()) { - return { value: "iks", accuracy: 80}; + return { value: "iks", accuracy: 80 }; } if (this.isAKS()) { - return { value: "aks", accuracy: 80}; + return { value: "aks", accuracy: 80 }; } if (this.isDigitalOcean()) { - return { value: "digitalocean", accuracy: 90}; + return { value: "digitalocean", accuracy: 90 }; } if (this.isK0s()) { - return { value: "k0s", accuracy: 80}; + return { value: "k0s", accuracy: 80 }; } if (this.isVMWare()) { - return { value: "vmware", accuracy: 90}; + return { value: "vmware", accuracy: 90 }; } if (this.isMirantis()) { - return { value: "mirantis", accuracy: 90}; + return { value: "mirantis", accuracy: 90 }; } if (this.isAlibaba()) { - return { value: "alibaba", accuracy: 90}; + return { value: "alibaba", accuracy: 90 }; } if (this.isHuawei()) { - return { value: "huawei", accuracy: 90}; + return { value: "huawei", accuracy: 90 }; } if (this.isTke()) { - return { value: "tencent", accuracy: 90}; + return { value: "tencent", accuracy: 90 }; } if (this.isMinikube()) { - return { value: "minikube", accuracy: 80}; + return { value: "minikube", accuracy: 80 }; } if (this.isMicrok8s()) { - return { value: "microk8s", accuracy: 80}; + return { value: "microk8s", accuracy: 80 }; } if (this.isKind()) { - return { value: "kind", accuracy: 70}; + return { value: "kind", accuracy: 70 }; } if (this.isDockerDesktop()) { - return { value: "docker-desktop", accuracy: 80}; + return { value: "docker-desktop", accuracy: 80 }; } if (this.isCustom() && await this.isOpenshift()) { - return { value: "openshift", accuracy: 90}; + return { value: "openshift", accuracy: 90 }; } if (this.isCustom()) { - return { value: "custom", accuracy: 10}; + return { value: "custom", accuracy: 10 }; } - return { value: "unknown", accuracy: 10}; + return { value: "unknown", accuracy: 10 }; } public async getKubernetesVersion() { diff --git a/src/main/cluster-detectors/nodes-count-detector.ts b/src/main/cluster-detectors/nodes-count-detector.ts index 2cb224b46a..75f478549b 100644 --- a/src/main/cluster-detectors/nodes-count-detector.ts +++ b/src/main/cluster-detectors/nodes-count-detector.ts @@ -29,7 +29,7 @@ export class NodesCountDetector extends BaseClusterDetector { if (!this.cluster.accessible) return null; const nodeCount = await this.getNodeCount(); - return { value: nodeCount, accuracy: 100}; + return { value: nodeCount, accuracy: 100 }; } protected async getNodeCount(): Promise { diff --git a/src/main/cluster-detectors/version-detector.ts b/src/main/cluster-detectors/version-detector.ts index 36d7e06dd1..ecabb1ec49 100644 --- a/src/main/cluster-detectors/version-detector.ts +++ b/src/main/cluster-detectors/version-detector.ts @@ -29,7 +29,7 @@ export class VersionDetector extends BaseClusterDetector { public async detect() { const version = await this.getKubernetesVersion(); - return { value: version, accuracy: 100}; + return { value: version, accuracy: 100 }; } public async getKubernetesVersion() { diff --git a/src/main/cluster-manager.ts b/src/main/cluster-manager.ts index c082bc78c9..5991cd9d2f 100644 --- a/src/main/cluster-manager.ts +++ b/src/main/cluster-manager.ts @@ -51,14 +51,14 @@ export class ClusterManager extends Singleton { reaction( () => this.store.clustersList.map(c => c.getState()), () => this.updateCatalog(this.store.clustersList), - { fireImmediately: false, } + { fireImmediately: false }, ); // reacting to every cluster's preferences change and total amount of items reaction( () => this.store.clustersList.map(c => toJS(c.preferences)), () => this.updateCatalog(this.store.clustersList), - { fireImmediately: false, } + { fireImmediately: false }, ); reaction(() => catalogEntityRegistry.getItemsForApiKind("entity.k8slens.dev/v1alpha1", "KubernetesCluster"), (entities) => { @@ -263,7 +263,7 @@ export function catalogEntityFromCluster(cluster: Cluster) { spec: { kubeconfigPath: cluster.kubeConfigPath, kubeconfigContext: cluster.contextName, - icon: {} + icon: {}, }, status: { phase: cluster.disconnected @@ -271,7 +271,7 @@ export function catalogEntityFromCluster(cluster: Cluster) { : LensKubernetesClusterStatus.CONNECTED, reason: "", message: "", - active: !cluster.disconnected - } + active: !cluster.disconnected, + }, }); } diff --git a/src/main/cluster.ts b/src/main/cluster.ts index 4ac4074ca5..6f465c909b 100644 --- a/src/main/cluster.ts +++ b/src/main/cluster.ts @@ -251,7 +251,7 @@ export class Cluster implements ClusterModel, ClusterState { logger.debug(`[CLUSTER]: Cluster init success`, { id: this.id, context: this.contextName, - apiUrl: this.apiUrl + apiUrl: this.apiUrl, }); } } @@ -306,7 +306,7 @@ export class Cluster implements ClusterModel, ClusterState { if (ipcMain) { this.eventDisposers.push( reaction(() => this.getState(), () => this.pushState()), - reaction(() => this.prometheusPreferences, (prefs) => this.contextHandler.setupPrometheus(prefs), { equals: comparer.structural, }), + reaction(() => this.prometheusPreferences, (prefs) => this.contextHandler.setupPrometheus(prefs), { equals: comparer.structural }), () => { clearInterval(refreshTimer); clearInterval(refreshMetadataTimer); @@ -545,7 +545,7 @@ export class Cluster implements ClusterModel, ClusterState { const accessReview = await authApi.createSelfSubjectAccessReview({ apiVersion: "authorization.k8s.io/v1", kind: "SelfSubjectAccessReview", - spec: { resourceAttributes } + spec: { resourceAttributes }, }); return accessReview.body.status.allowed; @@ -651,7 +651,7 @@ export class Cluster implements ClusterModel, ClusterState { const api = (await this.getProxyKubeconfig()).makeApiClient(CoreV1Api); try { - const { body: { items } } = await api.listNamespace(); + const { body: { items }} = await api.listNamespace(); const namespaces = items.map(ns => ns.metadata.name); return namespaces; @@ -687,7 +687,7 @@ export class Cluster implements ClusterModel, ClusterState { resource: apiResource.apiName, group: apiResource.group, verb: "list", - namespace + namespace, }); this.resourceAccessStatuses.set(apiResource, result); diff --git a/src/main/context-handler.ts b/src/main/context-handler.ts index ce1273646b..76458bdd30 100644 --- a/src/main/context-handler.ts +++ b/src/main/context-handler.ts @@ -90,7 +90,7 @@ export class ContextHandler { const proxyConfig = await this.cluster.getProxyKubeconfig(); const apiClient = proxyConfig.makeApiClient(CoreV1Api); const potentialServices = await Promise.allSettled( - providers.map(provider => provider.getPrometheusService(apiClient)) + providers.map(provider => provider.getPrometheusService(apiClient)), ); for (const result of potentialServices) { diff --git a/src/main/extension-filesystem.ts b/src/main/extension-filesystem.ts index 849165afa4..97c8bf06a3 100644 --- a/src/main/extension-filesystem.ts +++ b/src/main/extension-filesystem.ts @@ -68,7 +68,7 @@ export class FilesystemProvisionerStore extends BaseStore { } @action - protected fromStore({ extensions }: FSProvisionModel = { extensions: {} }): void { + protected fromStore({ extensions }: FSProvisionModel = { extensions: {}}): void { this.registeredExtensions.merge(extensions); } diff --git a/src/main/helm/__mocks__/helm-chart-manager.ts b/src/main/helm/__mocks__/helm-chart-manager.ts index 09f071f842..11e9846c0a 100644 --- a/src/main/helm/__mocks__/helm-chart-manager.ts +++ b/src/main/helm/__mocks__/helm-chart-manager.ts @@ -74,7 +74,7 @@ const charts = new Map([ repo: "stable", digest: "test", created: "now", - } + }, ]), "redis": sortCharts([ { @@ -92,7 +92,7 @@ const charts = new Map([ repo: "stable", digest: "test", created: "now", - } + }, ]), }], ["experiment", { @@ -113,7 +113,7 @@ const charts = new Map([ digest: "test", deprecated: true, created: "now", - } + }, ]), }], ["bitnami", { @@ -133,7 +133,7 @@ const charts = new Map([ repo: "bitnami", digest: "test", created: "now", - } + }, ]), "pretzel": sortCharts([ { @@ -151,7 +151,7 @@ const charts = new Map([ repo: "bitnami", digest: "test", created: "now", - } + }, ]), }], ]); diff --git a/src/main/helm/__tests__/helm-service.test.ts b/src/main/helm/__tests__/helm-service.test.ts index 7eaf865464..9cddb45f9c 100644 --- a/src/main/helm/__tests__/helm-service.test.ts +++ b/src/main/helm/__tests__/helm-service.test.ts @@ -62,7 +62,7 @@ describe("Helm Service tests", () => { repo: "stable", digest: "test", created: "now", - } + }, ], "invalid-semver": [ { @@ -114,8 +114,8 @@ describe("Helm Service tests", () => { repo: "stable", digest: "test", created: "now", - } - ] + }, + ], }, experiment: { "fairwind": [ @@ -136,8 +136,8 @@ describe("Helm Service tests", () => { digest: "test", created: "now", }, - ] - } + ], + }, }); }); @@ -189,9 +189,9 @@ describe("Helm Service tests", () => { repo: "bitnami", digest: "test", created: "now", - } - ] - } + }, + ], + }, }); }); }); diff --git a/src/main/helm/helm-chart-manager.ts b/src/main/helm/helm-chart-manager.ts index b7afb6ff3d..522107e8a7 100644 --- a/src/main/helm/helm-chart-manager.ts +++ b/src/main/helm/helm-chart-manager.ts @@ -24,7 +24,7 @@ import v8 from "v8"; import * as yaml from "js-yaml"; import type { HelmRepo } from "./helm-repo-manager"; import logger from "../logger"; -import { promiseExecFile } from "../promise-exec"; +import { promiseExecFile } from "../../common/utils/promise-exec"; import { helmCli } from "./helm-cli"; import type { RepoHelmChartList } from "../../common/k8s-api/endpoints/helm-charts.api"; import { iter, sortCharts } from "../../common/utils"; @@ -143,9 +143,9 @@ function normalizeHelmCharts(repoName: string, entries: RepoHelmChartList): Repo repo: repoName, })), ), - ] as const + ] as const, ), ([, charts]) => !charts.every(chart => chart.deprecated), - ) + ), ); } diff --git a/src/main/helm/helm-cli.ts b/src/main/helm/helm-cli.ts index 2ce575ee4e..ceeebe36a5 100644 --- a/src/main/helm/helm-cli.ts +++ b/src/main/helm/helm-cli.ts @@ -31,7 +31,7 @@ export class HelmCli extends LensBinary { version, baseDir, originalBinaryName: "helm", - newBinaryName: "helm3" + newBinaryName: "helm3", }; super(opts); diff --git a/src/main/helm/helm-release-manager.ts b/src/main/helm/helm-release-manager.ts index 1f989c6428..4f96562e5d 100644 --- a/src/main/helm/helm-release-manager.ts +++ b/src/main/helm/helm-release-manager.ts @@ -22,7 +22,7 @@ import * as tempy from "tempy"; import fse from "fs-extra"; import * as yaml from "js-yaml"; -import { promiseExec } from "../promise-exec"; +import { promiseExec } from "../../common/utils/promise-exec"; import { helmCli } from "./helm-cli"; import type { Cluster } from "../cluster"; import { toCamelCase } from "../../common/utils/camelCase"; @@ -69,8 +69,8 @@ export async function installChart(chart: string, values: any, name: string | un log: stdout, release: { name: releaseName, - namespace - } + namespace, + }, }; } catch (error) { throw error?.stderr || error; @@ -91,7 +91,7 @@ export async function upgradeRelease(name: string, chart: string, values: any, n return { log: stdout, - release: getRelease(name, namespace, cluster) + release: getRelease(name, namespace, cluster), }; } catch (error) { throw error?.stderr || error; diff --git a/src/main/helm/helm-repo-manager.ts b/src/main/helm/helm-repo-manager.ts index 2da7cfff18..1c36bef2be 100644 --- a/src/main/helm/helm-repo-manager.ts +++ b/src/main/helm/helm-repo-manager.ts @@ -21,7 +21,7 @@ import yaml from "js-yaml"; import { readFile } from "fs-extra"; -import { promiseExec } from "../promise-exec"; +import { promiseExec } from "../../common/utils/promise-exec"; import { helmCli } from "./helm-cli"; import { Singleton } from "../../common/utils/singleton"; import { customRequestPromise } from "../../common/request"; @@ -112,7 +112,7 @@ export class HelmRepoManager extends Singleton { } catch { } return { - repositories: [] + repositories: [], }; } @@ -132,7 +132,7 @@ export class HelmRepoManager extends Singleton { return repositories.map(repo => ({ ...repo, - cacheFilePath: `${this.helmEnv.HELM_REPOSITORY_CACHE}/${repo.name}-index.yaml` + cacheFilePath: `${this.helmEnv.HELM_REPOSITORY_CACHE}/${repo.name}-index.yaml`, })); } catch (error) { logger.error(`[HELM]: repositories listing error "${error}"`); diff --git a/src/main/helm/helm-service.ts b/src/main/helm/helm-service.ts index 41c8438cb3..2e86e36513 100644 --- a/src/main/helm/helm-service.ts +++ b/src/main/helm/helm-service.ts @@ -42,7 +42,7 @@ class HelmService { const repositories = await HelmRepoManager.getInstance().repositories(); return Object.fromEntries( - await Promise.all(repositories.map(async repo => [repo.name, await HelmChartManager.forRepo(repo).charts()])) + await Promise.all(repositories.map(async repo => [repo.name, await HelmChartManager.forRepo(repo).charts()])), ); } diff --git a/src/main/index.ts b/src/main/index.ts index 786a79a7b7..4315679fec 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -21,7 +21,7 @@ // Main process -import "../common/system-ca"; +import { injectSystemCAs } from "../common/system-ca"; import { initialize as initializeRemote } from "@electron/remote/main"; import * as Mobx from "mobx"; import * as LensExtensionsCommonApi from "../extensions/common-api"; @@ -66,13 +66,15 @@ import { initTray } from "./tray"; import { kubeApiRequest, shellApiRequest } from "./proxy-functions"; import { AppPaths } from "../common/app-paths"; +injectSystemCAs(); + const onCloseCleanup = disposer(); const onQuitCleanup = disposer(); - SentryInit(); app.setName(appName); + logger.info(`📟 Setting ${productName} as protocol client for lens://`); if (app.setAsDefaultProtocolClient("lens")) { @@ -120,7 +122,7 @@ app.on("second-instance", (event, argv) => { WindowManager.getInstance(false)?.ensureMainWindow(); }); -app.on("ready", async () => { +app.on("ready", async () => { logger.info(`🚀 Starting ${productName} from "${AppPaths.get("exe")}"`); logger.info("🐚 Syncing shell environment"); await shellSync(); diff --git a/src/main/kube-auth-proxy.ts b/src/main/kube-auth-proxy.ts index 4362f4f314..c1e76e40fb 100644 --- a/src/main/kube-auth-proxy.ts +++ b/src/main/kube-auth-proxy.ts @@ -82,7 +82,7 @@ export class KubeAuthProxy { "--context", `${this.cluster.contextName}`, "--accept-hosts", this.acceptHosts, "--reject-paths", "^[^/]", - "--api-prefix", this.apiPrefix + "--api-prefix", this.apiPrefix, ]; if (process.env.DEBUG_PROXY === "true") { @@ -90,7 +90,7 @@ export class KubeAuthProxy { } logger.debug(`spawning kubectl proxy with args: ${args}`); - this.proxyProcess = spawn(proxyBin, args, { env: this.env, }); + this.proxyProcess = spawn(proxyBin, args, { env: this.env }); this.proxyProcess.on("error", (error) => { this.sendIpcLogMessage({ data: error.message, error: true }); this.exit(); diff --git a/src/main/kubeconfig-manager.ts b/src/main/kubeconfig-manager.ts index bd9b4a5ab0..9ad90a2dc5 100644 --- a/src/main/kubeconfig-manager.ts +++ b/src/main/kubeconfig-manager.ts @@ -105,7 +105,7 @@ export class KubeconfigManager { name: contextName, server: this.resolveProxyUrl, skipTLSVerify: undefined, - } + }, ], users: [ { name: "proxy" }, @@ -116,8 +116,8 @@ export class KubeconfigManager { name: contextName, cluster: contextName, namespace: cluster.defaultNamespace || kubeConfig.getContextObject(contextName).namespace, - } - ] + }, + ], }; // write const configYaml = dumpConfigYaml(proxyConfig); diff --git a/src/main/kubectl.ts b/src/main/kubectl.ts index c68e00b2dd..79a1a56d42 100644 --- a/src/main/kubectl.ts +++ b/src/main/kubectl.ts @@ -21,7 +21,7 @@ import path from "path"; import fs from "fs"; -import { promiseExec } from "./promise-exec"; +import { promiseExec } from "../common/utils/promise-exec"; import logger from "./logger"; import { ensureDir, pathExists } from "fs-extra"; import * as lockFile from "proper-lockfile"; @@ -50,7 +50,7 @@ const kubectlMap: Map = new Map([ ["1.18", "1.18.20"], ["1.19", "1.19.12"], ["1.20", "1.20.8"], - ["1.21", bundledVersion] + ["1.21", bundledVersion], ]); let bundledPath: string; const initScriptVersionString = "# lens-initscript v3\n"; @@ -346,10 +346,10 @@ export class Kubectl { bashScript += `export PATH="${helmPath}:${kubectlPath}:$PATH"\n`; bashScript += "export KUBECONFIG=\"$tempkubeconfig\"\n"; - bashScript += "NO_PROXY=\",${NO_PROXY:-localhost},\"\n"; - bashScript += "NO_PROXY=\"${NO_PROXY//,localhost,/,}\"\n"; - bashScript += "NO_PROXY=\"${NO_PROXY//,127.0.0.1,/,}\"\n"; - bashScript += "NO_PROXY=\"localhost,127.0.0.1${NO_PROXY%,}\"\n"; + bashScript += `NO_PROXY=\",\${NO_PROXY:-localhost},\"\n`; + bashScript += `NO_PROXY=\"\${NO_PROXY//,localhost,/,}\"\n`; + bashScript += `NO_PROXY=\"\${NO_PROXY//,127.0.0.1,/,}\"\n`; + bashScript += `NO_PROXY=\"localhost,127.0.0.1\${NO_PROXY%,}\"\n`; bashScript += "export NO_PROXY\n"; bashScript += "unset tempkubeconfig\n"; await fsPromises.writeFile(bashScriptPath, bashScript.toString(), { mode: 0o644 }); @@ -371,24 +371,26 @@ export class Kubectl { zshScript += `helmpath=\"${helmPath}"\n`; zshScript += "p=\":$kubectlpath:\"\n"; zshScript += "d=\":$PATH:\"\n"; - zshScript += "d=${d//$p/:}\n"; - zshScript += "d=${d/#:/}\n"; - zshScript += "export PATH=\"$helmpath:$kubectlpath:${d/%:/}\"\n"; + zshScript += `d=\${d//$p/:}\n`; + zshScript += `d=\${d/#:/}\n`; + zshScript += `export PATH=\"$helmpath:$kubectlpath:\${d/%:/}\"\n`; zshScript += "export KUBECONFIG=\"$tempkubeconfig\"\n"; - zshScript += "NO_PROXY=\",${NO_PROXY:-localhost},\"\n"; - zshScript += "NO_PROXY=\"${NO_PROXY//,localhost,/,}\"\n"; - zshScript += "NO_PROXY=\"${NO_PROXY//,127.0.0.1,/,}\"\n"; - zshScript += "NO_PROXY=\"localhost,127.0.0.1${NO_PROXY%,}\"\n"; + zshScript += `NO_PROXY=\",\${NO_PROXY:-localhost},\"\n`; + zshScript += `NO_PROXY=\"\${NO_PROXY//,localhost,/,}\"\n`; + zshScript += `NO_PROXY=\"\${NO_PROXY//,127.0.0.1,/,}\"\n`; + zshScript += `NO_PROXY=\"localhost,127.0.0.1\${NO_PROXY%,}\"\n`; zshScript += "export NO_PROXY\n"; zshScript += "unset tempkubeconfig\n"; zshScript += "unset OLD_ZDOTDIR\n"; await fsPromises.writeFile(zshScriptPath, zshScript.toString(), { mode: 0o644 }); } - protected getDownloadMirror() { + protected getDownloadMirror(): string { // MacOS packages are only available from default - return packageMirrors.get(UserStore.getInstance().downloadMirror) + const mirror = packageMirrors.get(UserStore.getInstance().downloadMirror) ?? packageMirrors.get(defaultPackageMirror); + + return mirror.url; } } diff --git a/src/main/lens-binary.ts b/src/main/lens-binary.ts index 2c52b05db5..5a4420108f 100644 --- a/src/main/lens-binary.ts +++ b/src/main/lens-binary.ts @@ -154,7 +154,7 @@ export class LensBinary { this.logger.debug(`Extracting ${this.originalBinaryName} binary`); tar.x({ file: this.tarPath, - cwd: this.dirname + cwd: this.dirname, }).then((() => { resolve(); })); @@ -187,7 +187,7 @@ export class LensBinary { const requestOpts: request.UriOptions & request.CoreOptions = { uri: url, gzip: true, - ...this.requestOpts + ...this.requestOpts, }; const stream = request(requestOpts); diff --git a/src/main/lens-proxy.ts b/src/main/lens-proxy.ts index 7ce2ec29df..a3bee528cd 100644 --- a/src/main/lens-proxy.ts +++ b/src/main/lens-proxy.ts @@ -70,8 +70,8 @@ export class LensProxy extends Singleton { this.proxyServer = spdy.createServer({ spdy: { plain: true, - protocols: ["http/1.1", "spdy/3.1"] - } + protocols: ["http/1.1", "spdy/3.1"], + }, }, (req: http.IncomingMessage, res: http.ServerResponse) => { this.handleRequest(req, res); }); diff --git a/src/main/menu.ts b/src/main/menu.ts index 8073f7e47c..6718cf0003 100644 --- a/src/main/menu.ts +++ b/src/main/menu.ts @@ -38,7 +38,7 @@ interface MenuItemsOpts extends MenuItemConstructorOptions { export function initMenu(windowManager: WindowManager) { return autorun(() => buildMenu(windowManager), { - delay: 100 + delay: 100, }); } @@ -56,7 +56,7 @@ export function showAbout(browserWindow: BrowserWindow) { type: "info", buttons: ["Close"], message: productName, - detail: appInfo.join("\r\n") + detail: appInfo.join("\r\n"), }); } @@ -81,7 +81,7 @@ export function buildMenu(windowManager: WindowManager) { id: "about", click(menuItem: MenuItem, browserWindow: BrowserWindow) { showAbout(browserWindow); - } + }, }, { type: "separator" }, { @@ -98,7 +98,7 @@ export function buildMenu(windowManager: WindowManager) { id: "extensions", click() { navigate(extensionsURL()); - } + }, }, { type: "separator" }, { role: "services" }, @@ -113,8 +113,8 @@ export function buildMenu(windowManager: WindowManager) { id: "quit", click() { exitApp(); - } - } + }, + }, ], }; const fileMenu: MenuItemsOpts = { @@ -127,7 +127,7 @@ export function buildMenu(windowManager: WindowManager) { id: "add-cluster", click() { navigate(addClusterURL()); - } + }, }, ...ignoreOnMac([ { type: "separator" }, @@ -137,15 +137,15 @@ export function buildMenu(windowManager: WindowManager) { accelerator: "Ctrl+,", click() { navigate(preferencesURL()); - } + }, }, { label: "Extensions", accelerator: "Ctrl+Shift+E", click() { navigate(extensionsURL()); - } - } + }, + }, ]), { type: "separator" }, @@ -154,8 +154,8 @@ export function buildMenu(windowManager: WindowManager) { { role: "close", label: "Close Window", - accelerator: "Shift+Cmd+W" - } + accelerator: "Shift+Cmd+W", + }, ] as MenuItemConstructorOptions[] : []), ...ignoreOnMac([ @@ -165,9 +165,9 @@ export function buildMenu(windowManager: WindowManager) { id: "quit", click() { exitApp(); - } - } - ]) + }, + }, + ]), ], }; const editMenu: MenuItemsOpts = { @@ -183,7 +183,7 @@ export function buildMenu(windowManager: WindowManager) { { role: "delete" }, { type: "separator" }, { role: "selectAll" }, - ] + ], }; const viewMenu: MenuItemsOpts = { label: "View", @@ -195,7 +195,7 @@ export function buildMenu(windowManager: WindowManager) { id: "catalog", click() { navigate(catalogURL()); - } + }, }, { label: "Command Palette...", @@ -203,7 +203,7 @@ export function buildMenu(windowManager: WindowManager) { id: "command-palette", click() { broadcastMessage("command-palette:open"); - } + }, }, { type: "separator" }, { @@ -212,7 +212,7 @@ export function buildMenu(windowManager: WindowManager) { id: "go-back", click() { webContents.getAllWebContents().filter(wc => wc.getType() === "window").forEach(wc => wc.goBack()); - } + }, }, { label: "Forward", @@ -220,7 +220,7 @@ export function buildMenu(windowManager: WindowManager) { id: "go-forward", click() { webContents.getAllWebContents().filter(wc => wc.getType() === "window").forEach(wc => wc.goForward()); - } + }, }, { label: "Reload", @@ -228,7 +228,7 @@ export function buildMenu(windowManager: WindowManager) { id: "reload", click() { windowManager.reload(); - } + }, }, { role: "toggleDevTools" }, { type: "separator" }, @@ -236,8 +236,8 @@ export function buildMenu(windowManager: WindowManager) { { role: "zoomIn" }, { role: "zoomOut" }, { type: "separator" }, - { role: "togglefullscreen" } - ] + { role: "togglefullscreen" }, + ], }; const helpMenu: MenuItemsOpts = { role: "help", @@ -270,10 +270,10 @@ export function buildMenu(windowManager: WindowManager) { id: "about", click(menuItem: MenuItem, browserWindow: BrowserWindow) { showAbout(browserWindow); - } - } - ]) - ] + }, + }, + ]), + ], }; // Prepare menu items order const appMenu = new Map([ diff --git a/src/main/prometheus/lens.ts b/src/main/prometheus/lens.ts index c00bc31069..7cd7923238 100644 --- a/src/main/prometheus/lens.ts +++ b/src/main/prometheus/lens.ts @@ -39,7 +39,7 @@ export class PrometheusLens extends PrometheusProvider { id: this.id, namespace: service.metadata.namespace, service: service.metadata.name, - port: service.spec.ports[0].port + port: service.spec.ports[0].port, }; } catch(error) { logger.warn(`PrometheusLens: failed to list services: ${error.response.body.message}`); diff --git a/src/main/prometheus/provider-registry.ts b/src/main/prometheus/provider-registry.ts index be4dcef737..8c67bbba9f 100644 --- a/src/main/prometheus/provider-registry.ts +++ b/src/main/prometheus/provider-registry.ts @@ -46,14 +46,14 @@ export abstract class PrometheusProvider { protected async getFirstNamespacedServer(client: CoreV1Api, ...selectors: string[]): Promise { try { for (const selector of selectors) { - const { body: { items: [service] } } = await client.listServiceForAllNamespaces(null, null, null, selector); + const { body: { items: [service] }} = await client.listServiceForAllNamespaces(null, null, null, selector); if (service) { return { id: this.id, namespace: service.metadata.namespace, service: service.metadata.name, - port: service.spec.ports[0].port + port: service.spec.ports[0].port, }; } } diff --git a/src/main/prometheus/stacklight.ts b/src/main/prometheus/stacklight.ts index 8148f3bff7..7d2c07134d 100644 --- a/src/main/prometheus/stacklight.ts +++ b/src/main/prometheus/stacklight.ts @@ -39,7 +39,7 @@ export class PrometheusStacklight extends PrometheusProvider { id: this.id, namespace: service.metadata.namespace, service: service.metadata.name, - port: service.spec.ports[0].port + port: service.spec.ports[0].port, }; } catch(error) { logger.warn(`PrometheusLens: failed to list services: ${error.response.body.message}`); diff --git a/src/main/protocol-handler/__test__/router.test.ts b/src/main/protocol-handler/__test__/router.test.ts index d46036dbf9..9e73eff559 100644 --- a/src/main/protocol-handler/__test__/router.test.ts +++ b/src/main/protocol-handler/__test__/router.test.ts @@ -60,7 +60,7 @@ function throwIfDefined(val: any): void { describe("protocol router tests", () => { beforeEach(() => { mockFs({ - "tmp": {} + "tmp": {}, }); ExtensionsStore.createInstance(); ExtensionLoader.createInstance(); diff --git a/src/main/resource-applier.ts b/src/main/resource-applier.ts index e6200b9d30..7be1eec94d 100644 --- a/src/main/resource-applier.ts +++ b/src/main/resource-applier.ts @@ -30,7 +30,7 @@ import logger from "./logger"; import { appEventBus } from "../common/event-bus"; import { cloneJsonObject } from "../common/utils"; import type { Patch } from "rfc6902"; -import { promiseExecFile } from "./promise-exec"; +import { promiseExecFile } from "../common/utils/promise-exec"; export class ResourceApplier { constructor(protected cluster: Cluster) {} @@ -62,7 +62,7 @@ export class ResourceApplier { args.push( "--type", "json", "--patch", JSON.stringify(patch), - "-o", "json" + "-o", "json", ); try { diff --git a/src/main/router.ts b/src/main/router.ts index 9a7ded8a37..96ed7cdd02 100644 --- a/src/main/router.ts +++ b/src/main/router.ts @@ -70,7 +70,7 @@ function getMimeType(filename: string) { svg: "image/svg+xml", js: "application/javascript", woff2: "font/woff2", - ttf: "font/ttf" + ttf: "font/ttf", }; return mimeTypes[path.extname(filename).slice(1)] || "text/plain"; @@ -118,11 +118,11 @@ export class Router { response: res, query: url.searchParams, payload, - params + params, }; } - protected static async handleStaticFile({ params, response, raw: { req } }: LensApiRequest): Promise { + protected static async handleStaticFile({ params, response, raw: { req }}: LensApiRequest): Promise { let filePath = params.path; for (let retryCount = 0; retryCount < 5; retryCount += 1) { diff --git a/src/main/routes/kubeconfig-route.ts b/src/main/routes/kubeconfig-route.ts index f4bd7f038e..14b09489f0 100644 --- a/src/main/routes/kubeconfig-route.ts +++ b/src/main/routes/kubeconfig-route.ts @@ -35,17 +35,17 @@ function generateKubeConfig(username: string, secret: V1Secret, cluster: Cluster "name": cluster.contextName, "cluster": { "server": cluster.apiUrl, - "certificate-authority-data": secret.data["ca.crt"] - } - } + "certificate-authority-data": secret.data["ca.crt"], + }, + }, ], "users": [ { "name": username, "user": { "token": tokenData.toString("utf8"), - } - } + }, + }, ], "contexts": [ { @@ -54,16 +54,16 @@ function generateKubeConfig(username: string, secret: V1Secret, cluster: Cluster "user": username, "cluster": cluster.contextName, "namespace": secret.metadata.namespace, - } - } + }, + }, ], - "current-context": cluster.contextName + "current-context": cluster.contextName, }; } export class KubeconfigRoute { static async routeServiceAccountRoute(request: LensApiRequest) { - const { params, response, cluster} = request; + const { params, response, cluster } = request; const client = (await cluster.getProxyKubeconfig()).makeApiClient(CoreV1Api); const secretList = await client.listNamespacedSecret(params.namespace); const secret = secretList.body.items.find(secret => { diff --git a/src/main/routes/metrics-route.ts b/src/main/routes/metrics-route.ts index eef0c19800..b130670213 100644 --- a/src/main/routes/metrics-route.ts +++ b/src/main/routes/metrics-route.ts @@ -75,7 +75,7 @@ export class MetricsRoute { try { const [prometheusPath, prometheusProvider] = await Promise.all([ cluster.contextHandler.getPrometheusPath(), - cluster.contextHandler.getPrometheusProvider() + cluster.contextHandler.getPrometheusProvider(), ]); prometheusMetadata.provider = prometheusProvider?.id; diff --git a/src/main/routes/port-forward-route.ts b/src/main/routes/port-forward-route.ts index 9951967ffe..17e4b1146e 100644 --- a/src/main/routes/port-forward-route.ts +++ b/src/main/routes/port-forward-route.ts @@ -79,11 +79,11 @@ class PortForward { "port-forward", "-n", this.namespace, `${this.kind}/${this.name}`, - `${this.forwardPort ?? ""}:${this.port}` + `${this.forwardPort ?? ""}:${this.port}`, ]; this.process = spawn(kubectlBin, args, { - env: process.env + env: process.env, }); PortForward.portForwards.push(this); this.process.on("exit", () => { @@ -158,7 +158,7 @@ export class PortForwardRoute { logger.error("[PORT-FORWARD-ROUTE]: failed to start a port-forward", { namespace, port, resourceType, resourceName }); return respondJson(response, { - message: `Failed to forward port ${port} to ${thePort ? forwardPort : "random port"}` + message: `Failed to forward port ${port} to ${thePort ? forwardPort : "random port"}`, }, 400); } } @@ -168,7 +168,7 @@ export class PortForwardRoute { logger.error(`[PORT-FORWARD-ROUTE]: failed to open a port-forward: ${error}`, { namespace, port, resourceType, resourceName }); return respondJson(response, { - message: `Failed to forward port ${port}` + message: `Failed to forward port ${port}`, }, 400); } } @@ -200,7 +200,7 @@ export class PortForwardRoute { port: f.port, forwardPort: f.forwardPort, protocol: f.protocol, - }) + }), ); respondJson(response, { portForwards }); @@ -224,7 +224,7 @@ export class PortForwardRoute { logger.error("[PORT-FORWARD-ROUTE]: error stopping a port-forward", { namespace, port, forwardPort, resourceType, resourceName }); return respondJson(response, { - message: `error stopping a forward port ${port}` + message: `error stopping a forward port ${port}`, }, 400); } } diff --git a/src/main/routes/version-route.ts b/src/main/routes/version-route.ts index 14a1624489..fa92509d0e 100644 --- a/src/main/routes/version-route.ts +++ b/src/main/routes/version-route.ts @@ -27,6 +27,6 @@ export class VersionRoute { static async getVersion(request: LensApiRequest) { const { response } = request; - respondJson(response, { version: getAppVersion()}, 200); + respondJson(response, { version: getAppVersion() }, 200); } } diff --git a/src/main/shell-session/node-shell-session.ts b/src/main/shell-session/node-shell-session.ts index 5f36e1d2f0..494137de7d 100644 --- a/src/main/shell-session/node-shell-session.ts +++ b/src/main/shell-session/node-shell-session.ts @@ -74,7 +74,7 @@ export class NodeShellSession extends ShellSession { .createNamespacedPod("kube-system", { metadata: { name: this.podId, - namespace: "kube-system" + namespace: "kube-system", }, spec: { nodeName: this.nodeName, @@ -84,7 +84,7 @@ export class NodeShellSession extends ShellSession { hostIPC: true, hostNetwork: true, tolerations: [{ - operator: "Exists" + operator: "Exists", }], containers: [{ name: "shell", @@ -93,10 +93,10 @@ export class NodeShellSession extends ShellSession { privileged: true, }, command: ["nsenter"], - args: ["-t", "1", "-m", "-u", "-i", "-n", "sleep", "14000"] + args: ["-t", "1", "-m", "-u", "-i", "-n", "sleep", "14000"], }], imagePullSecrets, - } + }, }); } @@ -117,7 +117,7 @@ export class NodeShellSession extends ShellSession { (err) => { console.log(err); reject(err); - } + }, ) .then(req => { setTimeout(() => { diff --git a/src/main/shell-session/shell-session.ts b/src/main/shell-session/shell-session.ts index 4771ec8b77..987a00afdd 100644 --- a/src/main/shell-session/shell-session.ts +++ b/src/main/shell-session/shell-session.ts @@ -154,7 +154,7 @@ export abstract class ShellSession { env.LENS_SESSION = "true"; env.WSLENV = [ process.env.WSLENV, - "KUBECONFIG/up:LENS_SESSION/u" + "KUBECONFIG/up:LENS_SESSION/u", ] .filter(Boolean) .join(":"); @@ -183,7 +183,7 @@ export abstract class ShellSession { env.NO_PROXY = [ "localhost", "127.0.0.1", - env.NO_PROXY + env.NO_PROXY, ] .filter(Boolean) .join(); diff --git a/src/main/tray.ts b/src/main/tray.ts index 3a772503f8..c1b4aa4f78 100644 --- a/src/main/tray.ts +++ b/src/main/tray.ts @@ -40,7 +40,7 @@ export function getTrayIcon(): string { return path.resolve( __static, isDevelopment ? "../build/tray" : "icons", // copied within electron-builder extras - "trayIconTemplate.png" + "trayIconTemplate.png", ); } @@ -95,7 +95,7 @@ function createTrayMenu(windowManager: WindowManager): Menu { .navigate(preferencesURL()) .catch(error => logger.error(`${TRAY_LOG_PREFIX}: Failed to navigate to Preferences`, { error })); }, - } + }, ]; if (isAutoUpdateEnabled()) { @@ -122,7 +122,7 @@ function createTrayMenu(windowManager: WindowManager): Menu { label: "Quit App", click() { exitApp(); - } - } + }, + }, ])); } diff --git a/src/main/utils/clear-kube-env-vars.ts b/src/main/utils/clear-kube-env-vars.ts index f01fc030c6..c134841ef6 100644 --- a/src/main/utils/clear-kube-env-vars.ts +++ b/src/main/utils/clear-kube-env-vars.ts @@ -32,6 +32,6 @@ const anyKubeconfig = /^kubeconfig$/i; export function clearKubeconfigEnvVars(env: Record): Record { return Object.fromEntries( Object.entries(env) - .filter(([key]) => anyKubeconfig.exec(key) === null) + .filter(([key]) => anyKubeconfig.exec(key) === null), ); } diff --git a/src/main/utils/shell-env.ts b/src/main/utils/shell-env.ts index 18a9545af9..eaaaa33a5e 100644 --- a/src/main/utils/shell-env.ts +++ b/src/main/utils/shell-env.ts @@ -52,7 +52,7 @@ export async function shellEnv(shell?: string, forceRetry = false) : Promise setTimeout(() => { reject(new Error("Resolving shell environment is taking very long. Please review your shell configuration.")); - }, 30_000)) + }, 30_000)), ]); } catch (error) { logger.error(`shellEnv: ${error}`); diff --git a/src/main/window-manager.ts b/src/main/window-manager.ts index f751d79790..38b0698de1 100644 --- a/src/main/window-manager.ts +++ b/src/main/window-manager.ts @@ -263,7 +263,7 @@ export class WindowManager extends Singleton { enableRemoteModule: true, contextIsolation: false, nodeIntegrationInSubFrames: true, - } + }, }); await this.splashWindow.loadURL("static://splash.html"); } 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 db2fd0bff0..e3a89b37d3 100644 --- a/src/migrations/cluster-store/2.0.0-beta.2.ts +++ b/src/migrations/cluster-store/2.0.0-beta.2.ts @@ -36,5 +36,5 @@ export default { if (contextName === "__internal__" || value[1].hasOwnProperty("kubeConfig")) continue; store.set(contextName, { kubeConfig: value[1] }); } - } + }, } as MigrationDeclaration; diff --git a/src/migrations/cluster-store/2.4.1.ts b/src/migrations/cluster-store/2.4.1.ts index 192f7f3dc8..9b9735ded4 100644 --- a/src/migrations/cluster-store/2.4.1.ts +++ b/src/migrations/cluster-store/2.4.1.ts @@ -32,7 +32,7 @@ export default { if (contextName === "__internal__") continue; const cluster = value[1]; - store.set(contextName, { kubeConfig: cluster.kubeConfig, icon: cluster.icon || null, preferences: cluster.preferences || {} }); + store.set(contextName, { kubeConfig: cluster.kubeConfig, icon: cluster.icon || null, preferences: cluster.preferences || {}}); } - } + }, } as MigrationDeclaration; 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 a1d7df0c1b..1caf231a5a 100644 --- a/src/migrations/cluster-store/2.6.0-beta.2.ts +++ b/src/migrations/cluster-store/2.6.0-beta.2.ts @@ -39,5 +39,5 @@ export default { } store.set(clusterKey, { contextName: clusterKey, kubeConfig: value[1].kubeConfig, preferences: value[1].preferences }); } - } + }, } as MigrationDeclaration; 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 60373d756a..a33dd7523f 100644 --- a/src/migrations/cluster-store/2.6.0-beta.3.ts +++ b/src/migrations/cluster-store/2.6.0-beta.3.ts @@ -58,12 +58,12 @@ export default { user["auth-provider"].config = authConfig; kubeConfig.users = [{ name: userObj.name, - user + user, }]; cluster.kubeConfig = yaml.dump(kubeConfig); store.set(clusterKey, cluster); } } } - } + }, } as MigrationDeclaration; 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 150cb3f8ce..a6b8c4da7e 100644 --- a/src/migrations/cluster-store/2.7.0-beta.0.ts +++ b/src/migrations/cluster-store/2.7.0-beta.0.ts @@ -34,5 +34,5 @@ export default { cluster.workspace = "default"; store.set(clusterKey, cluster); } - } + }, } as MigrationDeclaration; 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 b7f9c8b0a0..7dc47916a7 100644 --- a/src/migrations/cluster-store/2.7.0-beta.1.ts +++ b/src/migrations/cluster-store/2.7.0-beta.1.ts @@ -47,5 +47,5 @@ export default { if (clusters.length > 0) { store.set("clusters", clusters); } - } + }, } as MigrationDeclaration; 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 00b2842983..55e2812b9e 100644 --- a/src/migrations/cluster-store/3.6.0-beta.1.ts +++ b/src/migrations/cluster-store/3.6.0-beta.1.ts @@ -87,5 +87,5 @@ export default { } store.set("clusters", migratedClusters); - } + }, } as MigrationDeclaration; diff --git a/src/migrations/cluster-store/5.0.0-beta.13.ts b/src/migrations/cluster-store/5.0.0-beta.13.ts index b75b938a14..e5c81e90bc 100644 --- a/src/migrations/cluster-store/5.0.0-beta.13.ts +++ b/src/migrations/cluster-store/5.0.0-beta.13.ts @@ -59,7 +59,7 @@ function mergePreferences(left: ClusterPreferences, right: ClusterPreferences): function mergeLabels(left: Record, right: Record): Record { return { ...right, - ...left + ...left, }; } @@ -129,5 +129,5 @@ export default { } store.set("clusters", [...clusters.values()]); - } + }, } as MigrationDeclaration; diff --git a/src/migrations/cluster-store/snap.ts b/src/migrations/cluster-store/snap.ts index 965d03ee5a..1c9a4d1f37 100644 --- a/src/migrations/cluster-store/snap.ts +++ b/src/migrations/cluster-store/snap.ts @@ -53,5 +53,5 @@ export default { store.set("clusters", migratedClusters); - } + }, } as MigrationDeclaration; diff --git a/src/migrations/helpers.ts b/src/migrations/helpers.ts index 8ed4242652..b7344e22e6 100644 --- a/src/migrations/helpers.ts +++ b/src/migrations/helpers.ts @@ -51,7 +51,7 @@ export function joinMigrations(...declarations: MigrationDeclaration[]): Migrati for (const fn of fns) { fn(store); } - }] - ) + }], + ), ); } diff --git a/src/migrations/hotbar-store/5.0.0-alpha.0.ts b/src/migrations/hotbar-store/5.0.0-alpha.0.ts index 4ba145b662..f6f533f782 100644 --- a/src/migrations/hotbar-store/5.0.0-alpha.0.ts +++ b/src/migrations/hotbar-store/5.0.0-alpha.0.ts @@ -28,10 +28,10 @@ export default { version: "5.0.0-alpha.0", run(store) { const hotbar = getEmptyHotbar("default"); - const { metadata: { uid, name, source } } = catalogEntity; + const { metadata: { uid, name, source }} = catalogEntity; - hotbar.items[0] = { entity: { uid, name, source } }; + hotbar.items[0] = { entity: { uid, name, source }}; store.set("hotbars", [hotbar]); - } + }, } as MigrationDeclaration; diff --git a/src/migrations/hotbar-store/5.0.0-alpha.2.ts b/src/migrations/hotbar-store/5.0.0-alpha.2.ts index 6eeb759779..48c28a3c7b 100644 --- a/src/migrations/hotbar-store/5.0.0-alpha.2.ts +++ b/src/migrations/hotbar-store/5.0.0-alpha.2.ts @@ -32,7 +32,7 @@ export default { store.set("hotbars", hotbars.map((hotbar) => ({ id: uuid.v4(), - ...hotbar + ...hotbar, }))); - } + }, } as MigrationDeclaration; diff --git a/src/migrations/hotbar-store/5.0.0-beta.10.ts b/src/migrations/hotbar-store/5.0.0-beta.10.ts index e5691d3622..196b61c15f 100644 --- a/src/migrations/hotbar-store/5.0.0-beta.10.ts +++ b/src/migrations/hotbar-store/5.0.0-beta.10.ts @@ -53,9 +53,9 @@ export default { // Hotbars might be empty, if some of the previous migrations weren't run if (hotbars.length === 0) { const hotbar = getEmptyHotbar("default"); - const { metadata: { uid, name, source } } = catalogEntity; + const { metadata: { uid, name, source }} = catalogEntity; - hotbar.items[0] = { entity: { uid, name, source } }; + hotbar.items[0] = { entity: { uid, name, source }}; hotbars.push(hotbar); } @@ -104,7 +104,7 @@ export default { entity: { uid: generateNewIdFor(cluster), name: cluster.preferences.clusterName || cluster.contextName, - } + }, }); } } @@ -132,7 +132,7 @@ export default { if (hotbars.every(hotbar => hotbar.items.every(item => item?.entity?.uid !== "catalog-entity"))) { // note, we will add a new whole hotbar here called "default" if that was previously removed const defaultHotbar = hotbars.find(hotbar => hotbar.name === "default"); - const { metadata: { uid, name, source } } = catalogEntity; + const { metadata: { uid, name, source }} = catalogEntity; if (defaultHotbar) { const freeIndex = defaultHotbar.items.findIndex(isNull); @@ -142,15 +142,15 @@ export default { // called "default" is full than overriding a hotbar item const hotbar = getEmptyHotbar("initial"); - hotbar.items[0] = { entity: { uid, name, source } }; + hotbar.items[0] = { entity: { uid, name, source }}; hotbars.unshift(hotbar); } else { - defaultHotbar.items[freeIndex] = { entity: { uid, name, source } }; + defaultHotbar.items[freeIndex] = { entity: { uid, name, source }}; } } else { const hotbar = getEmptyHotbar("default"); - hotbar.items[0] = { entity: { uid, name, source } }; + hotbar.items[0] = { entity: { uid, name, source }}; hotbars.unshift(hotbar); } } @@ -163,5 +163,5 @@ export default { } store.set("hotbars", hotbars); - } + }, } as MigrationDeclaration; diff --git a/src/migrations/hotbar-store/5.0.0-beta.5.ts b/src/migrations/hotbar-store/5.0.0-beta.5.ts index 40f36e13fe..1f4f278b05 100644 --- a/src/migrations/hotbar-store/5.0.0-beta.5.ts +++ b/src/migrations/hotbar-store/5.0.0-beta.5.ts @@ -42,12 +42,12 @@ export default { hotbar.items[i].entity = { ...item.entity, name: entity.metadata.name, - source: entity.metadata.source + source: entity.metadata.source, }; } } } store.set("hotbars", hotbars); - } + }, } as MigrationDeclaration; diff --git a/src/migrations/user-store/2.1.0-beta.4.ts b/src/migrations/user-store/2.1.0-beta.4.ts index 12aa3d1cf0..f961f65b06 100644 --- a/src/migrations/user-store/2.1.0-beta.4.ts +++ b/src/migrations/user-store/2.1.0-beta.4.ts @@ -26,5 +26,5 @@ export default { version: "2.1.0-beta.4", run(store) { store.set("lastSeenAppVersion", "0.0.0"); - } + }, } as MigrationDeclaration; diff --git a/src/migrations/user-store/5.0.0-alpha.3.ts b/src/migrations/user-store/5.0.0-alpha.3.ts index 3f70240164..b7d520702f 100644 --- a/src/migrations/user-store/5.0.0-alpha.3.ts +++ b/src/migrations/user-store/5.0.0-alpha.3.ts @@ -35,5 +35,5 @@ export default { preferences.hiddenTableColumns = Object.entries(oldHiddenTableColumns); store.set("preferences", preferences); - } + }, } as MigrationDeclaration; diff --git a/src/migrations/user-store/index.ts b/src/migrations/user-store/index.ts index 87628daeef..7c5814f478 100644 --- a/src/migrations/user-store/index.ts +++ b/src/migrations/user-store/index.ts @@ -29,7 +29,7 @@ import version503Beta1 from "./5.0.3-beta.1"; import { fileNameMigration } from "./file-name-migration"; export { - fileNameMigration + fileNameMigration, }; export default joinMigrations( diff --git a/src/migrations/weblinks-store/5.1.4.ts b/src/migrations/weblinks-store/5.1.4.ts index 84aaad5e6d..08693a6198 100644 --- a/src/migrations/weblinks-store/5.1.4.ts +++ b/src/migrations/weblinks-store/5.1.4.ts @@ -35,9 +35,9 @@ export default { { id: slackUrl, name: "Lens Community Slack", url: slackUrl }, { id: "https://kubernetes.io/docs/home/", name: "Kubernetes Documentation", url: "https://kubernetes.io/docs/home/" }, { id: "https://twitter.com/k8slens", name: "Lens on Twitter", url: "https://twitter.com/k8slens" }, - { id: "https://medium.com/k8slens", name: "Lens Official Blog", url: "https://medium.com/k8slens" } + { id: "https://medium.com/k8slens", name: "Lens Official Blog", url: "https://medium.com/k8slens" }, ); store.set("weblinks", weblinks); - } + }, } as MigrationDeclaration; diff --git a/src/preload.ts b/src/preload.ts index 71c601c2fa..cb51847ae3 100644 --- a/src/preload.ts +++ b/src/preload.ts @@ -22,5 +22,5 @@ import fetch from "node-fetch"; export { - fetch + fetch, }; diff --git a/src/renderer/api/__tests__/catalog-entity-registry.test.ts b/src/renderer/api/__tests__/catalog-entity-registry.test.ts index 527cb4d328..f4261df995 100644 --- a/src/renderer/api/__tests__/catalog-entity-registry.test.ts +++ b/src/renderer/api/__tests__/catalog-entity-registry.test.ts @@ -37,19 +37,19 @@ class FooBarCategory extends CatalogCategory { public readonly kind = "CatalogCategory"; public metadata = { name: "FooBars", - icon: "broken" + icon: "broken", }; public spec = { group: "entity.k8slens.dev", versions: [ { name: "v1alpha1", - entityClass: WebLink - } + entityClass: WebLink, + }, ], names: { - kind: "FooBar" - } + kind: "FooBar", + }, }; } const entity = new WebLink({ @@ -57,43 +57,43 @@ const entity = new WebLink({ uid: "test", name: "test-link", source: "test", - labels: {} + labels: {}, }, spec: { - url: "https://k8slens.dev" + url: "https://k8slens.dev", }, status: { - phase: "available" - } + phase: "available", + }, }); const entity2 = new WebLink({ metadata: { uid: "test2", name: "test-link", source: "test", - labels: {} + labels: {}, }, spec: { - url: "https://k8slens.dev" + url: "https://k8slens.dev", }, status: { - phase: "available" - } + phase: "available", + }, }); const entitykc = new KubernetesCluster({ metadata: { uid: "test3", name: "test-link", source: "test", - labels: {} + labels: {}, }, spec: { kubeconfigPath: "", kubeconfigContext: "", }, status: { - phase: "connected" - } + phase: "connected", + }, }); describe("CatalogEntityRegistry", () => { @@ -107,12 +107,12 @@ describe("CatalogEntityRegistry", () => { uid: "123", name: "foobar", source: "test", - labels: {} + labels: {}, }, status: { - phase: "disconnected" + phase: "disconnected", }, - spec: {} + spec: {}, }]; catalog.replaceItems(items); @@ -125,12 +125,12 @@ describe("CatalogEntityRegistry", () => { uid: "456", name: "barbaz", source: "test", - labels: {} + labels: {}, }, status: { - phase: "disconnected" + phase: "disconnected", }, - spec: {} + spec: {}, }); catalog.replaceItems(items); @@ -146,12 +146,12 @@ describe("CatalogEntityRegistry", () => { uid: "123", name: "foobar", source: "test", - labels: {} + labels: {}, }, status: { - phase: "disconnected" + phase: "disconnected", }, - spec: {} + spec: {}, }]; catalog.replaceItems(items); @@ -174,12 +174,12 @@ describe("CatalogEntityRegistry", () => { uid: "123", name: "foobar", source: "test", - labels: {} + labels: {}, }, status: { - phase: "disconnected" + phase: "disconnected", }, - spec: {} + spec: {}, }]; catalog.replaceItems(items); @@ -201,12 +201,12 @@ describe("CatalogEntityRegistry", () => { uid: "123", name: "foobar", source: "test", - labels: {} + labels: {}, }, status: { - phase: "disconnected" + phase: "disconnected", }, - spec: {} + spec: {}, }, { apiVersion: "entity.k8slens.dev/v1alpha1", @@ -215,13 +215,13 @@ describe("CatalogEntityRegistry", () => { uid: "456", name: "barbaz", source: "test", - labels: {} + labels: {}, }, status: { - phase: "disconnected" + phase: "disconnected", }, - spec: {} - } + spec: {}, + }, ]; catalog.replaceItems(items); @@ -243,12 +243,12 @@ describe("CatalogEntityRegistry", () => { uid: "123", name: "foobar", source: "test", - labels: {} + labels: {}, }, status: { - phase: "disconnected" + phase: "disconnected", }, - spec: {} + spec: {}, }, { apiVersion: "entity.k8slens.dev/v1alpha1", @@ -257,13 +257,13 @@ describe("CatalogEntityRegistry", () => { uid: "456", name: "barbaz", source: "test", - labels: {} + labels: {}, }, status: { - phase: "disconnected" + phase: "disconnected", }, - spec: {} - } + spec: {}, + }, ]; catalog.replaceItems(items); @@ -281,13 +281,13 @@ describe("CatalogEntityRegistry", () => { uid: "456", name: "barbaz", source: "test", - labels: {} + labels: {}, }, status: { - phase: "disconnected" + phase: "disconnected", }, - spec: {} - } + spec: {}, + }, ]; catalog.replaceItems(items); diff --git a/src/renderer/api/catalog-entity-registry.ts b/src/renderer/api/catalog-entity-registry.ts index acf65219a5..2a302aa07c 100644 --- a/src/renderer/api/catalog-entity-registry.ts +++ b/src/renderer/api/catalog-entity-registry.ts @@ -131,19 +131,19 @@ export class CatalogEntityRegistry { this.filters, iter.filter, this.items.values(), - ) + ), ); } @computed get entities(): Map { return new Map( - this.items.map(entity => [entity.getId(), entity]) + this.items.map(entity => [entity.getId(), entity]), ); } @computed get filteredEntities(): Map { return new Map( - this.filteredItems.map(entity => [entity.getId(), entity]) + this.filteredItems.map(entity => [entity.getId(), entity]), ); } diff --git a/src/renderer/api/catalog-entity.ts b/src/renderer/api/catalog-entity.ts index 212c64464b..1d07291659 100644 --- a/src/renderer/api/catalog-entity.ts +++ b/src/renderer/api/catalog-entity.ts @@ -38,5 +38,5 @@ export const catalogEntityRunContext = { navigate: (url: string) => navigate(url), setCommandPaletteContext: (entity?: CatalogEntity) => { catalogEntityRegistry.activeEntity = entity; - } + }, }; diff --git a/src/renderer/api/terminal-api.ts b/src/renderer/api/terminal-api.ts index 59e248fba5..1a66b25f46 100644 --- a/src/renderer/api/terminal-api.ts +++ b/src/renderer/api/terminal-api.ts @@ -170,7 +170,7 @@ export class TerminalApi extends WebSocketApi { protected emitError(error: string) { this.emitStatus(error, { - color: TerminalColor.RED + color: TerminalColor.RED, }); } } diff --git a/src/renderer/bootstrap.tsx b/src/renderer/bootstrap.tsx index 1a29faa0ae..9839cb6f42 100644 --- a/src/renderer/bootstrap.tsx +++ b/src/renderer/bootstrap.tsx @@ -110,7 +110,7 @@ export async function bootstrap(comp: () => Promise) { const { base, ...params } = cloudsMidnight; const baseTheme = base as monaco.editor.BuiltinTheme; - monaco.editor.defineTheme("clouds-midnight", {base: baseTheme, ...params}); + monaco.editor.defineTheme("clouds-midnight", { base: baseTheme, ...params }); // ThemeStore depends on: UserStore ThemeStore.createInstance(); @@ -140,7 +140,7 @@ export async function bootstrap(comp: () => Promise) { bootstrap( async () => process.isMainFrame ? (await import("./lens-app")).LensApp - : (await import("./components/app")).App + : (await import("./components/app")).App, ); diff --git a/src/renderer/components/+add-cluster/add-cluster.scss b/src/renderer/components/+add-cluster/add-cluster.scss index faac757c40..2ede9dc271 100644 --- a/src/renderer/components/+add-cluster/add-cluster.scss +++ b/src/renderer/components/+add-cluster/add-cluster.scss @@ -50,4 +50,8 @@ display: block; padding-top: 6px; } + + a[href] { + color: var(--colorInfo); + } } diff --git a/src/renderer/components/+add-cluster/add-cluster.tsx b/src/renderer/components/+add-cluster/add-cluster.tsx index 81a75019fa..7773ba5e9c 100644 --- a/src/renderer/components/+add-cluster/add-cluster.tsx +++ b/src/renderer/components/+add-cluster/add-cluster.tsx @@ -53,7 +53,7 @@ function getContexts(config: KubeConfig): Map { .map(({ config, error }) => [config.currentContext, { config, error, - }]) + }]), ); } @@ -76,7 +76,7 @@ export class AddCluster extends React.Component { @computed get allErrors(): string[] { return [ ...this.errors, - ...iter.map(this.kubeContexts.values(), ({ error }) => error) + ...iter.map(this.kubeContexts.values(), ({ error }) => error), ].filter(Boolean); } @@ -119,12 +119,12 @@ export class AddCluster extends React.Component {

Add Clusters from Kubeconfig

- Clusters added here are not merged into the ~/.kube/config file. - Read more about adding clusters here. + Clusters added here are not merged into the ~/.kube/config file.{" "} + Read more about adding clusters.

{ try { this.abortController?.abort(); this.abortController = new AbortController(); - const { chart: { name, repo } } = this.props; + const { chart: { name, repo }} = this.props; const { readme } = await getChartDetails(repo, name, { version: chart.version, reqInit: { signal: this.abortController.signal }}); this.readme = readme; @@ -148,7 +148,7 @@ export class HelmChartDetails extends Component { {selectedChart.getMaintainers().map(({ name, email, url }) => - {name} + {name}, )} {selectedChart.getKeywords().length > 0 && ( diff --git a/src/renderer/components/+apps-helm-charts/helm-chart.store.ts b/src/renderer/components/+apps-helm-charts/helm-chart.store.ts index e97e9fc276..e1ab3a5be8 100644 --- a/src/renderer/components/+apps-helm-charts/helm-chart.store.ts +++ b/src/renderer/components/+apps-helm-charts/helm-chart.store.ts @@ -61,7 +61,7 @@ export class HelmChartStore extends ItemStore { protected sortVersions = (versions: IChartVersion[]) => { return versions - .map(chartVersion => ({ ...chartVersion, __version: semver.coerce(chartVersion.version, { includePrerelease: true, loose: true }), })) + .map(chartVersion => ({ ...chartVersion, __version: semver.coerce(chartVersion.version, { includePrerelease: true, loose: true }) })) .sort(sortCompareChartVersions) .map(({ __version, ...chartVersion }) => chartVersion); }; @@ -78,7 +78,7 @@ export class HelmChartStore extends ItemStore { return versions.map(chart => ({ repo, - version: chart.getVersion() + version: chart.getVersion(), })); }; diff --git a/src/renderer/components/+apps-helm-charts/helm-charts.scss b/src/renderer/components/+apps-helm-charts/helm-charts.scss index 0a4c25f1a7..afa998d944 100644 --- a/src/renderer/components/+apps-helm-charts/helm-charts.scss +++ b/src/renderer/components/+apps-helm-charts/helm-charts.scss @@ -37,12 +37,14 @@ } &.icon { - display: flex; - flex-grow: 0.3; + $iconSize: $unit * 3.5; + padding: 0; + display: flex; + flex-grow: 0; + flex-basis: $iconSize; figure { - $iconSize: $unit * 3.5; width: $iconSize; height: $iconSize; border-radius: 50%; diff --git a/src/renderer/components/+apps-helm-charts/helm-charts.tsx b/src/renderer/components/+apps-helm-charts/helm-charts.tsx index da5f9f8c5a..6d8710a6b3 100644 --- a/src/renderer/components/+apps-helm-charts/helm-charts.tsx +++ b/src/renderer/components/+apps-helm-charts/helm-charts.tsx @@ -50,7 +50,7 @@ export class HelmCharts extends Component { } get selectedChart() { - const { match: { params: { chartName, repo } } } = this.props; + const { match: { params: { chartName, repo }}} = this.props; return helmChartStore.getByName(chartName, repo); } @@ -72,7 +72,7 @@ export class HelmCharts extends Component { params: { chartName: chart.getName(), repo: chart.getRepository(), - } + }, })); } }; @@ -104,7 +104,7 @@ export class HelmCharts extends Component { searchProps: { ...searchProps, placeholder: "Search Helm Charts...", - } + }, })} renderTableHeader={[ { className: "icon", showWithColumn: columnId.name }, @@ -126,7 +126,7 @@ export class HelmCharts extends Component { chart.getVersion(), chart.getAppVersion(), { title: chart.getRepository(), className: chart.getRepository().toLowerCase() }, - { className: "menu" } + { className: "menu" }, ]} detailsItem={this.selectedChart} onDetails={this.onDetails} diff --git a/src/renderer/components/+apps-releases/release-details.tsx b/src/renderer/components/+apps-releases/release-details.tsx index aa04d895c1..ad0db6b1b4 100644 --- a/src/renderer/components/+apps-releases/release-details.tsx +++ b/src/renderer/components/+apps-releases/release-details.tsx @@ -128,7 +128,7 @@ export class ReleaseDetails extends Component { chart: release.getChart(), repo: await release.getRepo(), version: release.getVersion(), - values: this.values + values: this.values, }; this.saving = true; @@ -136,7 +136,7 @@ export class ReleaseDetails extends Component { try { await releaseStore.update(name, namespace, data); Notifications.ok( -

Release {name} successfully updated!

+

Release {name} successfully updated!

, ); } catch (err) { Notifications.error(err); @@ -169,8 +169,8 @@ export class ReleaseDetails extends Component { value={values} onChange={text => this.values = text} theme={ThemeStore.getInstance().activeTheme.monacoTheme} - className={cssNames("MonacoEditor", {loading: valuesLoading})} - options={{readOnly: valuesLoading, ...UserStore.getInstance().getEditorOptions()}} + className={cssNames("MonacoEditor", { loading: valuesLoading })} + options={{ readOnly: valuesLoading, ...UserStore.getInstance().getEditorOptions() }} > {valuesLoading && }
diff --git a/src/renderer/components/+apps-releases/release-menu.tsx b/src/renderer/components/+apps-releases/release-menu.tsx index a53298460f..13532c22e4 100644 --- a/src/renderer/components/+apps-releases/release-menu.tsx +++ b/src/renderer/components/+apps-releases/release-menu.tsx @@ -21,7 +21,7 @@ import React from "react"; import type { HelmRelease } from "../../../common/k8s-api/endpoints/helm-releases.api"; -import { boundMethod, cssNames } from "../../utils"; +import { cssNames } from "../../utils"; import { releaseStore } from "./release.store"; import { MenuActions, MenuActionsProps } from "../menu/menu-actions"; import { MenuItem } from "../menu"; @@ -35,23 +35,20 @@ interface Props extends MenuActionsProps { } export class HelmReleaseMenu extends React.Component { - @boundMethod - remove() { + remove = () => { return releaseStore.remove(this.props.release); - } + }; - @boundMethod - upgrade() { + upgrade = () => { const { release, hideDetails } = this.props; createUpgradeChartTab(release); hideDetails?.(); - } + }; - @boundMethod - rollback() { + rollback = () => { ReleaseRollbackDialog.open(this.props.release); - } + }; renderContent() { const { release, toolbar } = this.props; @@ -67,6 +64,10 @@ export class HelmReleaseMenu extends React.Component { Rollback )} + + + Upgrade + ); } diff --git a/src/renderer/components/+apps-releases/release.store.ts b/src/renderer/components/+apps-releases/release.store.ts index 93b5cf5eef..081b637447 100644 --- a/src/renderer/components/+apps-releases/release.store.ts +++ b/src/renderer/components/+apps-releases/release.store.ts @@ -77,7 +77,7 @@ export class ReleaseStore extends ItemStore { getReleaseSecret(release: HelmRelease) { return secretsStore.getByLabel({ owner: "helm", - name: release.getName() + name: release.getName(), }) .find(secret => secret.getNs() == release.getNs()); } diff --git a/src/renderer/components/+apps-releases/releases.tsx b/src/renderer/components/+apps-releases/releases.tsx index b7777b8c67..8b01baf476 100644 --- a/src/renderer/components/+apps-releases/releases.tsx +++ b/src/renderer/components/+apps-releases/releases.tsx @@ -46,7 +46,7 @@ enum columnId { version = "version", appVersion = "app-version", status = "status", - updated = "update" + updated = "update", } interface Props extends RouteComponentProps { @@ -55,7 +55,7 @@ interface Props extends RouteComponentProps { @observer export class HelmReleases extends Component { componentDidMount() { - const { match: { params: { namespace } } } = this.props; + const { match: { params: { namespace }}} = this.props; if (namespace) { namespaceStore.selectNamespaces(namespace); @@ -68,7 +68,7 @@ export class HelmReleases extends Component { } get selectedRelease() { - const { match: { params: { name, namespace } } } = this.props; + const { match: { params: { name, namespace }}} = this.props; return releaseStore.items.find(release => { return release.getName() == name && release.getNs() == namespace; @@ -87,8 +87,8 @@ export class HelmReleases extends Component { navigation.push(releaseURL({ params: { name: item.getName(), - namespace: item.getNs() - } + namespace: item.getNs(), + }, })); }; @@ -174,7 +174,7 @@ export class HelmReleases extends Component { /> )} customizeRemoveDialog={selectedItems => ({ - message: this.renderRemoveDialogMessage(selectedItems) + message: this.renderRemoveDialogMessage(selectedItems), })} detailsItem={this.selectedRelease} onDetails={this.onDetails} diff --git a/src/renderer/components/+catalog/__tests__/catalog-add-button.test.tsx b/src/renderer/components/+catalog/__tests__/catalog-add-button.test.tsx index c8dc5ced76..d3f691af8b 100644 --- a/src/renderer/components/+catalog/__tests__/catalog-add-button.test.tsx +++ b/src/renderer/components/+catalog/__tests__/catalog-add-button.test.tsx @@ -35,8 +35,8 @@ class TestCatalogCategory extends CatalogCategory { group: "entity.k8slens.dev", versions: [], names: { - kind: "Test" - } + kind: "Test", + }, }; } @@ -49,8 +49,8 @@ describe("CatalogAddButton", () => { { icon: "text_snippet", title: "Add from kubeconfig", - onClick: () => {} - } + onClick: () => {}, + }, ); }); @@ -68,15 +68,15 @@ describe("CatalogAddButton", () => { { icon: "text_snippet", title: "foobar", - onClick: () => {} - } + onClick: () => {}, + }, ); ctx.menuItems.push( { icon: "text_snippet", title: "Add from kubeconfig", - onClick: () => {} - } + onClick: () => {}, + }, ); }); diff --git a/src/renderer/components/+catalog/catalog-add-button.scss b/src/renderer/components/+catalog/catalog-add-button.scss index 757ee68d9b..8e98cdd2b9 100644 --- a/src/renderer/components/+catalog/catalog-add-button.scss +++ b/src/renderer/components/+catalog/catalog-add-button.scss @@ -26,6 +26,7 @@ .MuiFab-primary { background-color: var(--blue); + border-radius: 50%; &:hover { background-color: #317bb3; diff --git a/src/renderer/components/+catalog/catalog-add-button.tsx b/src/renderer/components/+catalog/catalog-add-button.tsx index 558cdca3db..00c4d01831 100644 --- a/src/renderer/components/+catalog/catalog-add-button.tsx +++ b/src/renderer/components/+catalog/catalog-add-button.tsx @@ -23,21 +23,24 @@ import "./catalog-add-button.scss"; import React from "react"; import { SpeedDial, SpeedDialAction } from "@material-ui/lab"; import { Icon } from "../icon"; -import { disposeOnUnmount, observer } from "mobx-react"; -import { observable, reaction, makeObservable } from "mobx"; +import { observer } from "mobx-react"; +import { observable, makeObservable, action } from "mobx"; import { boundMethod } from "../../../common/utils"; import type { CatalogCategory, CatalogEntityAddMenuContext, CatalogEntityAddMenu } from "../../api/catalog-entity"; import { EventEmitter } from "events"; import { navigate } from "../../navigation"; +import { catalogCategoryRegistry } from "../../api/catalog-category-registry"; export type CatalogAddButtonProps = { category: CatalogCategory }; +type CategoryId = string; + @observer export class CatalogAddButton extends React.Component { @observable protected isOpen = false; - protected menuItems = observable.array([]); + @observable menuItems = new Map(); constructor(props: CatalogAddButtonProps) { super(props); @@ -45,22 +48,49 @@ export class CatalogAddButton extends React.Component { } componentDidMount() { - disposeOnUnmount(this, [ - reaction(() => this.props.category, (category) => { - this.menuItems.clear(); - - if (category && category instanceof EventEmitter) { - const context: CatalogEntityAddMenuContext = { - navigate: (url: string) => navigate(url), - menuItems: this.menuItems - }; - - category.emit("catalogAddMenu", context); - } - }, { fireImmediately: true }) - ]); + this.updateMenuItems(); } + componentDidUpdate(prevProps: CatalogAddButtonProps) { + if (prevProps.category != this.props.category) { + this.updateMenuItems(); + } + } + + get categories() { + return catalogCategoryRegistry.filteredItems; + } + + @action + updateMenuItems() { + this.menuItems.clear(); + + if (this.props.category) { + this.updateCategoryItems(this.props.category); + } else { + // Show menu items from all categories + this.categories.forEach(this.updateCategoryItems); + } + } + + @action + updateCategoryItems = (category: CatalogCategory) => { + if (category instanceof EventEmitter) { + const menuItems: CatalogEntityAddMenu[] = []; + const context: CatalogEntityAddMenuContext = { + navigate: (url: string) => navigate(url), + menuItems, + }; + + category.emit("catalogAddMenu", context); + this.menuItems.set(category.getId(), menuItems); + } + }; + + getCategoryFilteredItems = (category: CatalogCategory) => { + return category.filteredItems(this.menuItems.get(category.getId()) || []); + }; + @boundMethod onOpen() { this.isOpen = true; @@ -73,16 +103,21 @@ export class CatalogAddButton extends React.Component { @boundMethod onButtonClick() { - const defaultAction = this.menuItems.find(item => item.defaultAction)?.onClick; - const clickAction = defaultAction || (this.menuItems.length === 1 ? this.menuItems[0].onClick : null); + const defaultAction = this.items.find(item => item.defaultAction)?.onClick; + const clickAction = defaultAction || (this.items.length === 1 ? this.items[0].onClick : null); clickAction?.(); } - render() { - const filteredItems = this.props.category ? this.props.category.filteredItems(this.menuItems) : []; + get items() { + const { category } = this.props; - if (filteredItems.length === 0) { + return category ? this.getCategoryFilteredItems(category) : + this.categories.map(this.getCategoryFilteredItems).flat(); + } + + render() { + if (this.items.length === 0) { return null; } @@ -97,7 +132,7 @@ export class CatalogAddButton extends React.Component { direction="up" onClick={this.onButtonClick} > - {filteredItems.map((menuItem, index) => { + {this.items.map((menuItem, index) => { return } @@ -107,7 +142,7 @@ export class CatalogAddButton extends React.Component { menuItem.onClick(); }} TooltipClasses={{ - popper: "catalogSpeedDialPopper" + popper: "catalogSpeedDialPopper", }} />; })} diff --git a/src/renderer/components/+catalog/catalog-entity-drawer-menu.tsx b/src/renderer/components/+catalog/catalog-entity-drawer-menu.tsx index f356f31a8e..44c2c6f6cc 100644 --- a/src/renderer/components/+catalog/catalog-entity-drawer-menu.tsx +++ b/src/renderer/components/+catalog/catalog-entity-drawer-menu.tsx @@ -63,7 +63,7 @@ export class CatalogEntityDrawerMenu extends React.Comp ok: () => { menuItem.onClick(); }, - message: menuItem.confirm.message + message: menuItem.confirm.message, }); } else { menuItem.onClick(); @@ -90,7 +90,7 @@ export class CatalogEntityDrawerMenu extends React.Comp tooltip={menuItem.title} {...{ [key]: menuItem.icon }} /> - + , ); } @@ -100,7 +100,7 @@ export class CatalogEntityDrawerMenu extends React.Comp entity={entity} addContent={} removeContent={} - /> + />, ); return items; diff --git a/src/renderer/components/+catalog/catalog-entity.store.tsx b/src/renderer/components/+catalog/catalog-entity.store.tsx index 8bbc335010..d4a5dbbc36 100644 --- a/src/renderer/components/+catalog/catalog-entity.store.tsx +++ b/src/renderer/components/+catalog/catalog-entity.store.tsx @@ -52,7 +52,7 @@ export class CatalogEntityStore extends ItemStore this.entities, () => this.loadAll()), - reaction(() => this.activeCategory, () => this.loadAll(), { delay: 100}), + reaction(() => this.activeCategory, () => this.loadAll(), { delay: 100 }), ); } diff --git a/src/renderer/components/+catalog/catalog.test.tsx b/src/renderer/components/+catalog/catalog.test.tsx index 47395fb008..7d3aaa23e4 100644 --- a/src/renderer/components/+catalog/catalog.test.tsx +++ b/src/renderer/components/+catalog/catalog.test.tsx @@ -53,7 +53,7 @@ jest.mock("electron", () => ({ AppPaths.init(); jest.mock("./hotbar-toggle-menu-item", () => ({ - HotbarToggleMenuItem: () =>
menu item
+ HotbarToggleMenuItem: () =>
menu item
, })); class MockCatalogEntity extends CatalogEntity { @@ -146,7 +146,7 @@ describe("", () => { expect(onRun).toHaveBeenCalled(); done(); }, 500); - } + }, ); render( @@ -155,7 +155,7 @@ describe("", () => { location={mockLocation} match={mockMatch} catalogEntityStore={catalogEntityStore} - /> + />, ); userEvent.click(screen.getByTestId("detail-panel-hot-bar-icon")); @@ -180,7 +180,7 @@ describe("", () => { done(); }, 500); e.preventDefault(); - } + }, ); render( @@ -189,7 +189,7 @@ describe("", () => { location={mockLocation} match={mockMatch} catalogEntityStore={catalogEntityStore} - /> + />, ); userEvent.click(screen.getByTestId("detail-panel-hot-bar-icon")); @@ -215,7 +215,7 @@ describe("", () => { }, 500); throw new Error("error!"); - } + }, ); render( @@ -224,7 +224,7 @@ describe("", () => { location={mockLocation} match={mockMatch} catalogEntityStore={catalogEntityStore} - /> + />, ); userEvent.click(screen.getByTestId("detail-panel-hot-bar-icon")); @@ -245,7 +245,7 @@ describe("", () => { catalogEntityRegistry.addOnBeforeRun( async () => { // no op - } + }, ); render( @@ -254,7 +254,7 @@ describe("", () => { location={mockLocation} match={mockMatch} catalogEntityStore={catalogEntityStore} - /> + />, ); userEvent.click(screen.getByTestId("detail-panel-hot-bar-icon")); @@ -282,7 +282,7 @@ describe("", () => { }, 500); e.preventDefault(); - } + }, ); render( @@ -291,7 +291,7 @@ describe("", () => { location={mockLocation} match={mockMatch} catalogEntityStore={catalogEntityStore} - /> + />, ); userEvent.click(screen.getByTestId("detail-panel-hot-bar-icon")); @@ -317,7 +317,7 @@ describe("", () => { }, 500); throw new Error("rejection!"); - } + }, ); render( @@ -326,7 +326,7 @@ describe("", () => { location={mockLocation} match={mockMatch} catalogEntityStore={catalogEntityStore} - /> + />, ); userEvent.click(screen.getByTestId("detail-panel-hot-bar-icon")); diff --git a/src/renderer/components/+catalog/catalog.tsx b/src/renderer/components/+catalog/catalog.tsx index 5c4f84e84e..a502dce2aa 100644 --- a/src/renderer/components/+catalog/catalog.tsx +++ b/src/renderer/components/+catalog/catalog.tsx @@ -52,7 +52,7 @@ enum sortBy { name = "name", kind = "kind", source = "source", - status = "status" + status = "status", } interface Props extends RouteComponentProps { @@ -107,7 +107,7 @@ export class Catalog extends React.Component { console.error(error); Notifications.error(

Unknown category: {routeTab}

); } - }, {fireImmediately: true}), + }, { fireImmediately: true }), ]); // If active category is filtered out, automatically switch to the first category @@ -151,7 +151,7 @@ export class Catalog extends React.Component { ok: () => { menuItem.onClick(); }, - message: menuItem.confirm.message + message: menuItem.confirm.message, }); } else { menuItem.onClick(); @@ -167,7 +167,7 @@ export class Catalog extends React.Component { const activeCategory = this.categories.find(category => category.getId() === tabId); if (activeCategory) { - navigate(catalogURL({ params: {group: activeCategory.spec.group, kind: activeCategory.spec.names.kind }})); + navigate(catalogURL({ params: { group: activeCategory.spec.group, kind: activeCategory.spec.names.kind }})); } else { navigate(catalogURL({ params: { group: browseCatalogTab }})); } diff --git a/src/renderer/components/+catalog/hotbar-toggle-menu-item.tsx b/src/renderer/components/+catalog/hotbar-toggle-menu-item.tsx index 00f6f3600f..da89ff3f26 100644 --- a/src/renderer/components/+catalog/hotbar-toggle-menu-item.tsx +++ b/src/renderer/components/+catalog/hotbar-toggle-menu-item.tsx @@ -27,14 +27,17 @@ import type { CatalogEntity } from "../../api/catalog-entity"; export function HotbarToggleMenuItem(props: { entity: CatalogEntity, addContent: ReactNode, removeContent: ReactNode }) { const store = HotbarStore.getInstance(); - const add = () => store.addToHotbar(props.entity); - const remove = () => store.removeFromHotbar(props.entity.getId()); const [itemInHotbar, setItemInHotbar] = useState(store.isAddedToActive(props.entity)); return ( { - itemInHotbar ? remove() : add(); - setItemInHotbar(!itemInHotbar); + if (itemInHotbar) { + store.removeFromHotbar(props.entity.getId()); + setItemInHotbar(false); + } else { + store.addToHotbar(props.entity); + setItemInHotbar(true); + } }}> {itemInHotbar ? props.removeContent : props.addContent } diff --git a/src/renderer/components/+cluster/cluster-metrics.tsx b/src/renderer/components/+cluster/cluster-metrics.tsx index 882244c8c7..f4cc72e8d2 100644 --- a/src/renderer/components/+cluster/cluster-metrics.tsx +++ b/src/renderer/components/+cluster/cluster-metrics.tsx @@ -40,23 +40,23 @@ export const ClusterMetrics = observer(() => { const colors = { cpu: "#3D90CE", memory: "#C93DCE" }; const data = metricValues.map(value => ({ x: value[0], - y: parseFloat(value[1]).toFixed(3) + y: parseFloat(value[1]).toFixed(3), })); const datasets = [{ id: metricType + metricNodeRole, label: `${metricType.toUpperCase()} usage`, borderColor: colors[metricType], - data + data, }]; const cpuOptions: ChartOptions = { scales: { yAxes: [{ ticks: { suggestedMax: cpuCapacity, - callback: (value) => value - } - }] + callback: (value) => value, + }, + }], }, tooltips: { callbacks: { @@ -64,18 +64,18 @@ export const ClusterMetrics = observer(() => { const value = data.datasets[0].data[index] as ChartPoint; return value.y.toString(); - } - } - } + }, + }, + }, }; const memoryOptions: ChartOptions = { scales: { yAxes: [{ ticks: { suggestedMax: memoryCapacity, - callback: (value: string) => !value ? 0 : bytesToUnits(parseInt(value)) - } - }] + callback: (value: string) => !value ? 0 : bytesToUnits(parseInt(value)), + }, + }], }, tooltips: { callbacks: { @@ -83,9 +83,9 @@ export const ClusterMetrics = observer(() => { const value = data.datasets[0].data[index] as ChartPoint; return bytesToUnits(parseInt(value.y as string), 3); - } - } - } + }, + }, + }, }; const options = metricType === MetricType.CPU ? cpuOptions : memoryOptions; diff --git a/src/renderer/components/+cluster/cluster-overview.store.ts b/src/renderer/components/+cluster/cluster-overview.store.ts index 17cc100109..130797c4f8 100644 --- a/src/renderer/components/+cluster/cluster-overview.store.ts +++ b/src/renderer/components/+cluster/cluster-overview.store.ts @@ -29,12 +29,12 @@ import { apiManager } from "../../../common/k8s-api/api-manager"; export enum MetricType { MEMORY = "memory", - CPU = "cpu" + CPU = "cpu", } export enum MetricNodeRole { MASTER = "master", - WORKER = "worker" + WORKER = "worker", } export interface ClusterOverviewStorageState { diff --git a/src/renderer/components/+cluster/cluster-overview.tsx b/src/renderer/components/+cluster/cluster-overview.tsx index b4fa25da45..1815fee001 100644 --- a/src/renderer/components/+cluster/cluster-overview.tsx +++ b/src/renderer/components/+cluster/cluster-overview.tsx @@ -60,7 +60,7 @@ export class ClusterOverview extends React.Component { }), reaction( () => clusterOverviewStore.metricNodeRole, // Toggle Master/Worker node switcher - () => this.metricPoller.restart(true) + () => this.metricPoller.restart(true), ), ]); } diff --git a/src/renderer/components/+cluster/cluster-pie-charts.tsx b/src/renderer/components/+cluster/cluster-pie-charts.tsx index 94e4ede5c9..80df2c1a9c 100644 --- a/src/renderer/components/+cluster/cluster-pie-charts.tsx +++ b/src/renderer/components/+cluster/cluster-pie-charts.tsx @@ -69,7 +69,7 @@ export const ClusterPieCharts = observer(() => { defaultColor, ], id: "cpuUsage", - label: "Usage" + label: "Usage", }, { data: [ @@ -81,7 +81,7 @@ export const ClusterPieCharts = observer(() => { defaultColor, ], id: "cpuRequests", - label: "Requests" + label: "Requests", }, { data: [ @@ -93,7 +93,7 @@ export const ClusterPieCharts = observer(() => { defaultColor, ], id: "cpuLimits", - label: "Limits" + label: "Limits", }, ], labels: createLabels([ @@ -116,7 +116,7 @@ export const ClusterPieCharts = observer(() => { defaultColor, ], id: "memoryUsage", - label: "Usage" + label: "Usage", }, { data: [ @@ -128,7 +128,7 @@ export const ClusterPieCharts = observer(() => { defaultColor, ], id: "memoryRequests", - label: "Requests" + label: "Requests", }, { data: [ @@ -140,7 +140,7 @@ export const ClusterPieCharts = observer(() => { defaultColor, ], id: "memoryLimits", - label: "Limits" + label: "Limits", }, ], labels: [ @@ -148,8 +148,8 @@ export const ClusterPieCharts = observer(() => { `Requests: ${bytesToUnits(memoryRequests)}`, `Limits: ${bytesToUnits(memoryLimits)}`, `Allocatable Capacity: ${bytesToUnits(memoryAllocatableCapacity)}`, - `Capacity: ${bytesToUnits(memoryCapacity)}` - ] + `Capacity: ${bytesToUnits(memoryCapacity)}`, + ], }; const podsData: ChartData = { datasets: [ @@ -163,13 +163,13 @@ export const ClusterPieCharts = observer(() => { defaultColor, ], id: "podUsage", - label: "Usage" + label: "Usage", }, ], labels: [ `Usage: ${podUsage || 0}`, `Capacity: ${podAllocatableCapacity}`, - ] + ], }; return ( diff --git a/src/renderer/components/+config-autoscalers/hpa.tsx b/src/renderer/components/+config-autoscalers/hpa.tsx index c620e6c629..428a84b369 100644 --- a/src/renderer/components/+config-autoscalers/hpa.tsx +++ b/src/renderer/components/+config-autoscalers/hpa.tsx @@ -40,7 +40,7 @@ enum columnId { maxPods = "max-pods", replicas = "replicas", age = "age", - status = "status" + status = "status", } interface Props extends RouteComponentProps { @@ -72,7 +72,7 @@ export class HorizontalPodAutoscalers extends React.Component { [columnId.age]: item => item.getTimeDiffFromNow(), }} searchFilters={[ - item => item.getSearchFields() + item => item.getSearchFields(), ]} renderHeaderTitle="Horizontal Pod Autoscalers" renderTableHeader={[ @@ -107,7 +107,7 @@ export class HorizontalPodAutoscalers extends React.Component { expandable={false} /> ); - }) + }), ]} /> ); diff --git a/src/renderer/components/+config-maps/config-map-details.tsx b/src/renderer/components/+config-maps/config-map-details.tsx index 082a340a88..a8ce769a96 100644 --- a/src/renderer/components/+config-maps/config-map-details.tsx +++ b/src/renderer/components/+config-maps/config-map-details.tsx @@ -55,7 +55,7 @@ export class ConfigMapDetails extends React.Component { if (configMap) { this.data.replace(configMap.data); // refresh } - }) + }), ]); } @@ -71,7 +71,7 @@ export class ConfigMapDetails extends React.Component { Notifications.ok(

<>ConfigMap {configMap.getName()} successfully updated. -

+

, ); } catch (error) { Notifications.error(`Failed to save config map: ${error}`); diff --git a/src/renderer/components/+config-maps/config-maps.tsx b/src/renderer/components/+config-maps/config-maps.tsx index 9733846994..04ffb11d71 100644 --- a/src/renderer/components/+config-maps/config-maps.tsx +++ b/src/renderer/components/+config-maps/config-maps.tsx @@ -55,7 +55,7 @@ export class ConfigMaps extends React.Component { }} searchFilters={[ item => item.getSearchFields(), - item => item.getKeys() + item => item.getKeys(), ]} renderHeaderTitle="Config Maps" renderTableHeader={[ 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 0fc2149e45..237280d440 100644 --- a/src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx +++ b/src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx @@ -135,8 +135,8 @@ export class AddQuotaDialog extends React.Component { await resourceQuotaApi.create({ namespace, name: quotaName }, { spec: { - hard: quotas - } + hard: quotas, + }, }); this.close(); } catch (err) { 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 29db4fda7f..97ad62123d 100644 --- a/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx +++ b/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx @@ -48,7 +48,7 @@ function transformUnit(name: string, value: string): number { } function renderQuotas(quota: ResourceQuota): JSX.Element[] { - const { hard = {}, used = {} } = quota.status; + const { hard = {}, used = {}} = quota.status; return Object.entries(hard) .filter(([name]) => used[name]) diff --git a/src/renderer/components/+config-resource-quotas/resource-quotas.tsx b/src/renderer/components/+config-resource-quotas/resource-quotas.tsx index 060b1e29fa..2cc0ec549a 100644 --- a/src/renderer/components/+config-resource-quotas/resource-quotas.tsx +++ b/src/renderer/components/+config-resource-quotas/resource-quotas.tsx @@ -33,7 +33,7 @@ import type { ResourceQuotaRouteParams } from "../../../common/routes"; enum columnId { name = "name", namespace = "namespace", - age = "age" + age = "age", } interface Props extends RouteComponentProps { @@ -72,7 +72,7 @@ export class ResourceQuotas extends React.Component { ]} addRemoveButtons={{ onAdd: () => AddQuotaDialog.open(), - addTooltip: "Create new ResourceQuota" + addTooltip: "Create new ResourceQuota", }} /> diff --git a/src/renderer/components/+config-secrets/__tests__/secret-details.test.tsx b/src/renderer/components/+config-secrets/__tests__/secret-details.test.tsx index 292f228cf9..51d6889a37 100644 --- a/src/renderer/components/+config-secrets/__tests__/secret-details.test.tsx +++ b/src/renderer/components/+config-secrets/__tests__/secret-details.test.tsx @@ -35,7 +35,7 @@ describe("SecretDetails tests", () => { metadata: { name: "test", resourceVersion: "1", - uid: "uid" + uid: "uid", }, data: { foobar: "", diff --git a/src/renderer/components/+config-secrets/add-secret-dialog.tsx b/src/renderer/components/+config-secrets/add-secret-dialog.tsx index d74a523dc5..eec38eddc9 100644 --- a/src/renderer/components/+config-secrets/add-secret-dialog.tsx +++ b/src/renderer/components/+config-secrets/add-secret-dialog.tsx @@ -81,7 +81,7 @@ export class AddSecretDialog extends React.Component { [SecretType.ServiceAccountToken]: { annotations: [ { key: "kubernetes.io/service-account.name", required: true }, - { key: "kubernetes.io/service-account.uid", required: true } + { key: "kubernetes.io/service-account.uid", required: true }, ], }, }; @@ -127,7 +127,7 @@ export class AddSecretDialog extends React.Component { namespace, annotations: this.getDataFromFields(annotations), labels: this.getDataFromFields(labels), - } as KubeObjectMetadata + } as KubeObjectMetadata, }; try { diff --git a/src/renderer/components/+config-secrets/secret-details.tsx b/src/renderer/components/+config-secrets/secret-details.tsx index 30aff8640f..97e430936c 100644 --- a/src/renderer/components/+config-secrets/secret-details.tsx +++ b/src/renderer/components/+config-secrets/secret-details.tsx @@ -59,7 +59,7 @@ export class SecretDetails extends React.Component { this.data = secret.data; this.revealSecret.clear(); } - }) + }), ]); } diff --git a/src/renderer/components/+config-secrets/secrets.tsx b/src/renderer/components/+config-secrets/secrets.tsx index 7e75b04d0e..8b4cd1f01f 100644 --- a/src/renderer/components/+config-secrets/secrets.tsx +++ b/src/renderer/components/+config-secrets/secrets.tsx @@ -85,7 +85,7 @@ export class Secrets extends React.Component { ]} addRemoveButtons={{ onAdd: () => AddSecretDialog.open(), - addTooltip: "Create new Secret" + addTooltip: "Create new Secret", }} /> diff --git a/src/renderer/components/+custom-resources/crd-details.tsx b/src/renderer/components/+custom-resources/crd-details.tsx index 2fcc702ba4..3fd616742e 100644 --- a/src/renderer/components/+custom-resources/crd-details.tsx +++ b/src/renderer/components/+custom-resources/crd-details.tsx @@ -157,7 +157,7 @@ export class CRDDetails extends React.Component { <> { } render() { - const { props: { object, crd } } = this; + const { props: { object, crd }} = this; if (!object || !crd) { return null; diff --git a/src/renderer/components/+custom-resources/crd-resources.tsx b/src/renderer/components/+custom-resources/crd-resources.tsx index b8645dfbd1..e8f5caa21b 100644 --- a/src/renderer/components/+custom-resources/crd-resources.tsx +++ b/src/renderer/components/+custom-resources/crd-resources.tsx @@ -95,7 +95,7 @@ export class CrdResources extends React.Component { ...searchProps, placeholder: `${crd.getResourceKind()} search ...`, }, - ...headerPlaceholders + ...headerPlaceholders, })} renderTableHeader={[ { title: "Name", className: "name", sortBy: columnId.name, id: columnId.name }, @@ -107,7 +107,7 @@ export class CrdResources extends React.Component { title: name, className: name.toLowerCase(), sortBy: name, - id: name + id: name, }; }), { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, diff --git a/src/renderer/components/+custom-resources/custom-resources.tsx b/src/renderer/components/+custom-resources/custom-resources.tsx index 2d1a09aac9..4ef2b65d11 100644 --- a/src/renderer/components/+custom-resources/custom-resources.tsx +++ b/src/renderer/components/+custom-resources/custom-resources.tsx @@ -36,7 +36,7 @@ export class CustomResources extends React.Component { component: CustomResources, url: crdURL(), routePath: String(crdDefinitionsRoute.path), - } + }, ]; } diff --git a/src/renderer/components/+events/events.tsx b/src/renderer/components/+events/events.tsx index 456de9e2aa..bea552dd55 100644 --- a/src/renderer/components/+events/events.tsx +++ b/src/renderer/components/+events/events.tsx @@ -135,7 +135,7 @@ export class Events extends React.Component { /> , title, - ...headerPlaceholders + ...headerPlaceholders, }; }; @@ -193,7 +193,7 @@ export class Events extends React.Component { {message} - ) + ), }, event.getNs(), diff --git a/src/renderer/components/+events/kube-event-icon.tsx b/src/renderer/components/+events/kube-event-icon.tsx index 8fe83d2940..9c53286dc9 100644 --- a/src/renderer/components/+events/kube-event-icon.tsx +++ b/src/renderer/components/+events/kube-event-icon.tsx @@ -66,7 +66,7 @@ export class KubeEventIcon extends React.Component { {event.getAge(undefined, undefined, true)}
- ) + ), }} /> ); diff --git a/src/renderer/components/+extensions/__tests__/extensions.test.tsx b/src/renderer/components/+extensions/__tests__/extensions.test.tsx index 08dfb6dc47..d2ec4906ab 100644 --- a/src/renderer/components/+extensions/__tests__/extensions.test.tsx +++ b/src/renderer/components/+extensions/__tests__/extensions.test.tsx @@ -75,7 +75,7 @@ AppPaths.init(); describe("Extensions", () => { beforeEach(async () => { mockFs({ - "tmp": {} + "tmp": {}, }); ExtensionInstallationStateStore.reset(); @@ -84,13 +84,13 @@ describe("Extensions", () => { id: "extensionId", manifest: { name: "test", - version: "1.2.3" + version: "1.2.3", }, absolutePath: "/absolute/path", manifestPath: "/symlinked/path/package.json", isBundled: false, isEnabled: true, - isCompatible: true + isCompatible: true, }); ExtensionDiscovery.createInstance().uninstallExtension = jest.fn(() => Promise.resolve()); UserStore.createInstance(); @@ -136,11 +136,11 @@ describe("Extensions", () => { (fse.unlink as jest.MockedFunction).mockReturnValue(Promise.resolve() as any); fireEvent.change(res.getByPlaceholderText("File path or URL", { - exact: false + exact: false, }), { target: { - value: "https://test.extensionurl/package.tgz" - } + value: "https://test.extensionurl/package.tgz", + }, }); fireEvent.click(res.getByText("Install")); diff --git a/src/renderer/components/+extensions/extensions.tsx b/src/renderer/components/+extensions/extensions.tsx index 46b7a26919..985ef3e044 100644 --- a/src/renderer/components/+extensions/extensions.tsx +++ b/src/renderer/components/+extensions/extensions.tsx @@ -31,10 +31,10 @@ import path from "path"; import React from "react"; import { SemVer } from "semver"; import URLParse from "url-parse"; -import { Disposer, disposer, downloadFile, downloadJson, ExtendableDisposer, extractTar, listTarEntries, noop, readFileFromTar, } from "../../../common/utils"; +import { Disposer, disposer, downloadFile, downloadJson, ExtendableDisposer, extractTar, listTarEntries, noop, readFileFromTar } from "../../../common/utils"; import { ExtensionDiscovery, InstalledExtension, manifestFilename } from "../../../extensions/extension-discovery"; import { ExtensionLoader } from "../../../extensions/extension-loader"; -import { extensionDisplayName, LensExtensionId, LensExtensionManifest, sanitizeExtensionName, } from "../../../extensions/lens-extension"; +import { extensionDisplayName, LensExtensionId, LensExtensionManifest, sanitizeExtensionName } from "../../../extensions/lens-extension"; import logger from "../../../main/logger"; import { Button } from "../button"; import { ConfirmDialog } from "../confirm-dialog"; @@ -121,7 +121,7 @@ async function uninstallExtension(extensionId: LensExtensionId): Promise !loader.userExtensions.has(extensionId)); Notifications.ok( -

Extension {displayName} successfully uninstalled!

+

Extension {displayName} successfully uninstalled!

, ); return true; @@ -238,7 +238,7 @@ async function createTempFilesAndValidate({ fileName, dataP }: InstallRequest):

Installing {fileName} has failed, skipping.

Reason: {message}

-
+ , ); } @@ -246,7 +246,7 @@ async function createTempFilesAndValidate({ fileName, dataP }: InstallRequest): } async function unpackExtension(request: InstallRequestValidated, disposeDownloading?: Disposer) { - const { id, fileName, tempFile, manifest: { name, version } } = request; + const { id, fileName, tempFile, manifest: { name, version }} = request; ExtensionInstallationStateStore.setInstalling(id); disposeDownloading?.(); @@ -283,7 +283,7 @@ async function unpackExtension(request: InstallRequestValidated, disposeDownload ExtensionLoader.getInstance().setIsEnabled(id, true); Notifications.ok( -

Extension {displayName} successfully installed!

+

Extension {displayName} successfully installed!

, ); } catch (error) { const message = getMessageFromError(error); @@ -375,7 +375,7 @@ async function attemptInstall(request: InstallRequest, d?: ExtendableDisposer): Extension Install Collision:

The {name} extension is currently {curState.toLowerCase()}.

Will not proceed with this current install request.

- + , ); } @@ -386,7 +386,7 @@ async function attemptInstall(request: InstallRequest, d?: ExtendableDisposer): // install extension if not yet exists await unpackExtension(validatedRequest, dispose); } else { - const { manifest: { version: oldVersion } } = ExtensionLoader.getInstance().getExtension(validatedRequest.id); + const { manifest: { version: oldVersion }} = ExtensionLoader.getInstance().getExtension(validatedRequest.id); // otherwise confirmation required (re-install / update) const removeNotification = Notifications.info( @@ -410,7 +410,7 @@ async function attemptInstall(request: InstallRequest, d?: ExtendableDisposer): , { onClose: dispose, - } + }, ); } } @@ -451,7 +451,7 @@ async function installFromInput(input: string) { await attemptInstall({ fileName, dataP: readFileNotify(input) }); } else if (InputValidators.isExtensionNameInstall.validate(input)) { - const [{ groups: { name, version } }] = [...input.matchAll(InputValidators.isExtensionNameInstallRegex)]; + const [{ groups: { name, version }}] = [...input.matchAll(InputValidators.isExtensionNameInstallRegex)]; await attemptInstallByInfo({ name, version }); } @@ -474,8 +474,8 @@ async function installFromSelectFileDialog() { message: `Select extensions to install (formats: ${supportedFormats.join(", ")}), `, buttonLabel: "Use configuration", filters: [ - { name: "tarball", extensions: supportedFormats } - ] + { name: "tarball", extensions: supportedFormats }, + ], }); if (!canceled) { @@ -503,7 +503,7 @@ export class Extensions extends React.Component { when(() => !ExtensionInstallationStateStore.anyInstalling, () => this.installPath = ""), ]); } - }) + }), ]); } diff --git a/src/renderer/components/+extensions/installed-extensions.tsx b/src/renderer/components/+extensions/installed-extensions.tsx index 0da09e5ec9..14e490bed5 100644 --- a/src/renderer/components/+extensions/installed-extensions.tsx +++ b/src/renderer/components/+extensions/installed-extensions.tsx @@ -76,16 +76,16 @@ export const InstalledExtensions = observer(({ extensions, uninstall, enable, di }, { Header: "Status", - accessor: "status" + accessor: "status", }, { Header: "", accessor: "actions", disableSortBy: true, width: 20, - className: "actions" - } - ], [] + className: "actions", + }, + ], [], ); const data = useMemo( @@ -106,7 +106,7 @@ export const InstalledExtensions = observer(({ extensions, uninstall, enable, di ), version, status: ( -
+
{getStatus(extension)}
), @@ -142,10 +142,10 @@ export const InstalledExtensions = observer(({ extensions, uninstall, enable, di Uninstall - ) + ), }; }); - }, [extensions, ExtensionInstallationStateStore.anyUninstalling] + }, [extensions, ExtensionInstallationStateStore.anyUninstalling], ); if (!ExtensionDiscovery.getInstance().isLoaded) { diff --git a/src/renderer/components/+namespaces/namespace-select-filter.tsx b/src/renderer/components/+namespaces/namespace-select-filter.tsx index 436f0a8a80..929530aa97 100644 --- a/src/renderer/components/+namespaces/namespace-select-filter.tsx +++ b/src/renderer/components/+namespaces/namespace-select-filter.tsx @@ -37,15 +37,15 @@ const Placeholder = observer((props: PlaceholderProps) => { const getPlaceholder = (): React.ReactNode => { const namespaces = namespaceStore.contextNamespaces; - switch (namespaces.length) { - case 0: - case namespaceStore.allowedNamespaces.length: - return <>All namespaces; - case 1: - return <>Namespace: {namespaces[0]}; - default: - return <>Namespaces: {namespaces.join(", ")}; + if (namespaceStore.areAllSelectedImplicitly || !namespaces.length) { + return <>All namespaces; } + + if (namespaces.length === 1) { + return <>Namespace: {namespaces[0]}; + } + + return <>Namespaces: {namespaces.join(", ")}; }; return ( @@ -60,6 +60,9 @@ export class NamespaceSelectFilter extends React.Component { static isMultiSelection = observable.box(false); static isMenuOpen = observable.box(false); + /** + * Only updated on every open + */ private selected = observable.set(); private didToggle = false; @@ -88,7 +91,7 @@ export class NamespaceSelectFilter extends React.Component { disposeOnUnmount(this, [ reaction(() => this.isMenuOpen, newVal => { if (newVal) { // rising edge of selection - this.selected.replace(namespaceStore.selectedNamespaces); + this.selected.replace(namespaceStore.selectedNames); this.didToggle = false; } }), @@ -101,9 +104,9 @@ export class NamespaceSelectFilter extends React.Component { return (
- + {namespace} - {isSelected && } + {isSelected && }
); } @@ -116,15 +119,12 @@ export class NamespaceSelectFilter extends React.Component { if (namespace) { if (this.isMultiSelection) { this.didToggle = true; - namespaceStore.toggleContext(namespace); - } else { namespaceStore.toggleSingle(namespace); + } else { + namespaceStore.selectSingle(namespace); } } else { - /** - * WARNING: only ever call this method with `false` as an argument - */ - namespaceStore.toggleAll(false); + namespaceStore.selectAll(); } }; diff --git a/src/renderer/components/+namespaces/namespace-select.tsx b/src/renderer/components/+namespaces/namespace-select.tsx index 0cefdb2905..aadfa601a2 100644 --- a/src/renderer/components/+namespaces/namespace-select.tsx +++ b/src/renderer/components/+namespaces/namespace-select.tsx @@ -55,7 +55,7 @@ export class NamespaceSelect extends React.Component { kubeWatchApi.subscribeStores([namespaceStore], { preload: true, loadOnce: true, // skip reloading namespaces on every render / page visit - }) + }), ]); } diff --git a/src/renderer/components/+namespaces/namespace.store.ts b/src/renderer/components/+namespaces/namespace.store.ts index 54f98702fc..093a3301ae 100644 --- a/src/renderer/components/+namespaces/namespace.store.ts +++ b/src/renderer/components/+namespaces/namespace.store.ts @@ -19,8 +19,8 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { action, comparer, computed, IReactionDisposer, IReactionOptions, makeObservable, reaction, } from "mobx"; -import { autoBind, createStorage, noop } from "../../utils"; +import { action, comparer, computed, IReactionDisposer, IReactionOptions, makeObservable, reaction } from "mobx"; +import { autoBind, createStorage, noop, ToggleSet } from "../../utils"; import { KubeObjectStore, KubeObjectStoreLoadingParams } from "../../../common/k8s-api/kube-object.store"; import { Namespace, namespacesApi } from "../../../common/k8s-api/endpoints/namespaces.api"; import { apiManager } from "../../../common/k8s-api/api-manager"; @@ -78,7 +78,11 @@ export class NamespaceStore extends KubeObjectStore { return []; } - @computed get selectedNamespaces(): string[] { + /** + * @private + * The current value (list of namespaces names) in the storage layer + */ + @computed private get selectedNamespaces(): string[] { return this.storage.get() ?? []; } @@ -89,6 +93,9 @@ export class NamespaceStore extends KubeObjectStore { ].flat())); } + /** + * The list of selected namespace names (for filtering) + */ @computed get contextNamespaces(): string[] { if (!this.selectedNamespaces.length) { return this.allowedNamespaces; // show all namespaces when nothing selected @@ -97,6 +104,23 @@ export class NamespaceStore extends KubeObjectStore { return this.selectedNamespaces; } + /** + * The set of select namespace names (for filtering) + */ + @computed get selectedNames(): Set { + return new Set(this.contextNamespaces); + } + + /** + * Is true when the the set of namespace names selected is implicitly all + * + * Namely, this will be true if the user has deselected all namespaces from + * the filter or if the user has clicked the "All Namespaces" option + */ + @computed get areAllSelectedImplicitly(): boolean { + return this.selectedNamespaces.length === 0; + } + subscribe() { /** * if user has given static list of namespaces let's not start watches @@ -142,42 +166,78 @@ export class NamespaceStore extends KubeObjectStore { } } + /** + * Checks if namespace names are selected for filtering + * @param namespaces One or several names of namespaces to check if they are selected + * @returns `true` if all the provided names are selected + */ hasContext(namespaces: string | string[]): boolean { return [namespaces] .flat() - .every(namespace => this.selectedNamespaces.includes(namespace)); + .every(namespace => this.selectedNames.has(namespace)); } + /** + * Is `true` if all available namespaces are selected, otherwise `false` + */ @computed get hasAllContexts(): boolean { - return this.selectedNamespaces.length === this.allowedNamespaces.length; + return this.contextNamespaces.length === this.allowedNamespaces.length; } + /** + * Acts like `toggleSingle` but can work on several at a time + * @param namespaces One or many names of namespaces to select + */ @action toggleContext(namespaces: string | string[]) { - if (this.hasContext(namespaces)) { - this.clearSelected(namespaces); - } else { - this.selectNamespaces([this.selectedNamespaces, namespaces].flat()); + const nextState = new ToggleSet(this.contextNamespaces); + + for (const namespace of [namespaces].flat()) { + nextState.toggle(namespace); } + + this.storage.set([...nextState]); } - @action + /** + * Toggles the selection state of `namespace`. Namely, if it was previously + * specifically or implicitly selected then after this call it will be + * explicitly deselected. + * @param namespace The name of a namespace + */ toggleSingle(namespace: string){ - this.clearSelected(); - this.selectNamespaces(namespace); + const nextState = new ToggleSet(this.contextNamespaces); + + nextState.toggle(namespace); + this.storage.set([...nextState]); } - @action - toggleAll(showAll?: boolean) { - if (typeof showAll === "boolean") { - if (showAll) { - this.selectNamespaces(this.allowedNamespaces); - } else { - this.selectNamespaces([]); // empty context considered as "All namespaces" - } - } else { - this.toggleAll(!this.hasAllContexts); - } + /** + * Makes the given namespace the sole selected namespace + */ + selectSingle(namespace: string) { + this.storage.set([namespace]); + } + + /** + * Selects all available namespaces. + * + * Note: If new namespaces appear in the future those will be selected too + */ + selectAll() { + this.selectNamespaces([]); + } + + /** + * This function selects all namespaces implicitly. + * + * NOTE: does not toggle any namespaces + * @param selectAll NOT USED + * @deprecated Use `NamespaceStore.selectAll` instead. + */ + toggleAll(selectAll?: boolean) { + void selectAll; + this.selectAll(); } @action @@ -198,7 +258,7 @@ export function getDummyNamespace(name: string) { name, uid: "", resourceVersion: "", - selfLink: `/api/v1/namespaces/${name}` - } + selfLink: `/api/v1/namespaces/${name}`, + }, }); } diff --git a/src/renderer/components/+namespaces/namespaces.tsx b/src/renderer/components/+namespaces/namespaces.tsx index f0d3164e23..53e38b95b6 100644 --- a/src/renderer/components/+namespaces/namespaces.tsx +++ b/src/renderer/components/+namespaces/namespaces.tsx @@ -58,7 +58,7 @@ export class Namespaces extends React.Component { }} searchFilters={[ item => item.getSearchFields(), - item => item.getStatus() + item => item.getStatus(), ]} renderHeaderTitle="Namespaces" renderTableHeader={[ diff --git a/src/renderer/components/+network-endpoints/endpoint-subset-list.tsx b/src/renderer/components/+network-endpoints/endpoint-subset-list.tsx index 7dcb1fc99b..aa4226f06a 100644 --- a/src/renderer/components/+network-endpoints/endpoint-subset-list.tsx +++ b/src/renderer/components/+network-endpoints/endpoint-subset-list.tsx @@ -23,7 +23,7 @@ import "./endpoint-subset-list.scss"; import React from "react"; import { observer } from "mobx-react"; -import { EndpointSubset, Endpoint, EndpointAddress} from "../../../common/k8s-api/endpoints"; +import { EndpointSubset, Endpoint, EndpointAddress } from "../../../common/k8s-api/endpoints"; import { Table, TableCell, TableHead, TableRow } from "../table"; import { boundMethod } from "../../utils"; import { apiManager } from "../../../common/k8s-api/api-manager"; @@ -47,7 +47,7 @@ export class EndpointSubsetList extends React.Component { @boundMethod getNotReadyAddressTableRow(ip: string) { - const { subset} = this.props; + const { subset } = this.props; const address = subset.getNotReadyAddresses().find(address => address.getId() == ip); return this.renderAddressTableRow(address); diff --git a/src/renderer/components/+network-endpoints/endpoints.tsx b/src/renderer/components/+network-endpoints/endpoints.tsx index 38c99fc19c..4f33e11dab 100644 --- a/src/renderer/components/+network-endpoints/endpoints.tsx +++ b/src/renderer/components/+network-endpoints/endpoints.tsx @@ -53,7 +53,7 @@ export class Endpoints extends React.Component { [columnId.age]: endpoint => endpoint.getTimeDiffFromNow(), }} searchFilters={[ - endpoint => endpoint.getSearchFields() + endpoint => endpoint.getSearchFields(), ]} renderHeaderTitle="Endpoints" renderTableHeader={[ @@ -75,7 +75,7 @@ export class Endpoints extends React.Component { const lines = item.getEndpointSubsets().length || 1; return lines * lineHeight + paddings; - } + }, }} /> ); diff --git a/src/renderer/components/+network-ingresses/ingress-charts.tsx b/src/renderer/components/+network-ingresses/ingress-charts.tsx index 0811209450..8e34566fa4 100644 --- a/src/renderer/components/+network-ingresses/ingress-charts.tsx +++ b/src/renderer/components/+network-ingresses/ingress-charts.tsx @@ -44,7 +44,7 @@ export const IngressCharts = observer(() => { bytesSentSuccess, bytesSentFailure, requestDurationSeconds, - responseDurationSeconds + responseDurationSeconds, ] = values; const datasets = [ @@ -55,14 +55,14 @@ export const IngressCharts = observer(() => { label: `Bytes sent, status 2xx`, tooltip: `Bytes sent by Ingress controller with successful status`, borderColor: "#46cd9e", - data: bytesSentSuccess.map(([x, y]) => ({ x, y })) + data: bytesSentSuccess.map(([x, y]) => ({ x, y })), }, { id: `${id}-bytesSentFailure`, label: `Bytes sent, status 5xx`, tooltip: `Bytes sent by Ingress controller with error status`, borderColor: "#cd465a", - data: bytesSentFailure.map(([x, y]) => ({ x, y })) + data: bytesSentFailure.map(([x, y]) => ({ x, y })), }, ], // Duration @@ -72,25 +72,25 @@ export const IngressCharts = observer(() => { label: `Request`, tooltip: `Request duration in seconds`, borderColor: "#48b18d", - data: requestDurationSeconds.map(([x, y]) => ({ x, y })) + data: requestDurationSeconds.map(([x, y]) => ({ x, y })), }, { id: `${id}-responseDurationSeconds`, label: `Response`, tooltip: `Response duration in seconds`, borderColor: "#73ba3c", - data: responseDurationSeconds.map(([x, y]) => ({ x, y })) + data: responseDurationSeconds.map(([x, y]) => ({ x, y })), }, - ] + ], ]; const durationOptions: ChartOptions = { scales: { yAxes: [{ ticks: { - callback: value => value - } - }] + callback: value => value, + }, + }], }, tooltips: { callbacks: { @@ -100,9 +100,9 @@ export const IngressCharts = observer(() => { const chartTooltipSec = `sec`; return `${label}: ${parseFloat(value.y as string).toFixed(3)} ${chartTooltipSec}`; - } - } - } + }, + }, + }, }; const options = [memoryOptions, durationOptions]; diff --git a/src/renderer/components/+network-ingresses/ingress-details.tsx b/src/renderer/components/+network-ingresses/ingress-details.tsx index 76515250b2..a0ec3ce8ca 100644 --- a/src/renderer/components/+network-ingresses/ingress-details.tsx +++ b/src/renderer/components/+network-ingresses/ingress-details.tsx @@ -62,7 +62,7 @@ export class IngressDetails extends React.Component { } renderPaths(ingress: Ingress) { - const { spec: { rules } } = ingress; + const { spec: { rules }} = ingress; if (!rules || !rules.length) return null; diff --git a/src/renderer/components/+network-ingresses/ingresses.tsx b/src/renderer/components/+network-ingresses/ingresses.tsx index cfe71e7c8c..a59e5f9c96 100644 --- a/src/renderer/components/+network-ingresses/ingresses.tsx +++ b/src/renderer/components/+network-ingresses/ingresses.tsx @@ -79,7 +79,7 @@ export class Ingresses extends React.Component { const lines = item.getRoutes().length || 1; return lines * lineHeight + paddings; - } + }, }} /> ); diff --git a/src/renderer/components/+network-policies/network-policy-details.tsx b/src/renderer/components/+network-policies/network-policy-details.tsx index 2ce5fc9034..29cbd45041 100644 --- a/src/renderer/components/+network-policies/network-policy-details.tsx +++ b/src/renderer/components/+network-policies/network-policy-details.tsx @@ -80,7 +80,7 @@ export class NetworkPolicyDetails extends React.Component { else { return ((empty)); } - }) + }), )} ); @@ -95,7 +95,7 @@ export class NetworkPolicyDetails extends React.Component { <> {to.map(item => { - const { ipBlock: { cidr, except } = {} } = item; + const { ipBlock: { cidr, except } = {}} = item; if (!cidr) return null; diff --git a/src/renderer/components/+network-port-forwards/port-forward-details.tsx b/src/renderer/components/+network-port-forwards/port-forward-details.tsx index 73f8f2fe1f..f39df3cb17 100644 --- a/src/renderer/components/+network-port-forwards/port-forward-details.tsx +++ b/src/renderer/components/+network-port-forwards/port-forward-details.tsx @@ -42,7 +42,7 @@ export class PortForwardDetails extends React.Component { const name = portForward.getName(); const api = { "service": serviceApi, - "pod": podsApi + "pod": podsApi, }[portForward.kind]; if (!api) { diff --git a/src/renderer/components/+network-port-forwards/port-forwards.tsx b/src/renderer/components/+network-port-forwards/port-forwards.tsx index 17b1c40c20..a76588619d 100644 --- a/src/renderer/components/+network-port-forwards/port-forwards.tsx +++ b/src/renderer/components/+network-port-forwards/port-forwards.tsx @@ -54,7 +54,7 @@ export class PortForwards extends React.Component { } get selectedPortForward() { - const { match: { params: { forwardport } } } = this.props; + const { match: { params: { forwardport }}} = this.props; return portForwardStore.getById(forwardport); } @@ -71,7 +71,7 @@ export class PortForwards extends React.Component { navigation.push(portForwardsURL({ params: { forwardport: String(item.getForwardPort()), - } + }, })); }; @@ -135,7 +135,7 @@ export class PortForwards extends React.Component { /> )} customizeRemoveDialog={selectedItems => ({ - message: this.renderRemoveDialogMessage(selectedItems) + message: this.renderRemoveDialogMessage(selectedItems), })} detailsItem={this.selectedPortForward} onDetails={this.onDetails} diff --git a/src/renderer/components/+network-services/service-details.tsx b/src/renderer/components/+network-services/service-details.tsx index 5948765089..d247e7908c 100644 --- a/src/renderer/components/+network-services/service-details.tsx +++ b/src/renderer/components/+network-services/service-details.tsx @@ -67,6 +67,11 @@ export class ServiceDetails extends React.Component { const { spec } = service; const endpoint = endpointStore.getByName(service.getName(), service.getNs()); + const externalIps = service.getExternalIps(); + + if (externalIps.length === 0 && spec?.externalName) { + externalIps.push(spec.externalName); + } return (
@@ -106,9 +111,9 @@ export class ServiceDetails extends React.Component { {service.getIpFamilyPolicy()} - {service.getExternalIps().length > 0 && ( + {externalIps.length > 0 && ( - {service.getExternalIps().map(ip =>
{ip}
)} + {externalIps.map(ip =>
{ip}
)}
)} diff --git a/src/renderer/components/+network-services/services.tsx b/src/renderer/components/+network-services/services.tsx index fe3b2b40ab..e29cc737cd 100644 --- a/src/renderer/components/+network-services/services.tsx +++ b/src/renderer/components/+network-services/services.tsx @@ -81,18 +81,26 @@ export class Services extends React.Component { { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, { title: "Status", className: "status", sortBy: columnId.status, id: columnId.status }, ]} - renderTableContents={service => [ - service.getName(), - , - service.getNs(), - service.getType(), - service.getClusterIp(), - service.getPorts().join(", "), - service.getExternalIps().join(", ") || "-", - service.getSelector().map(label => ), - service.getAge(), - { title: service.getStatus(), className: service.getStatus().toLowerCase() }, - ]} + renderTableContents={service => { + const externalIps = service.getExternalIps(); + + if (externalIps.length === 0 && service.spec?.externalName) { + externalIps.push(service.spec.externalName); + } + + return [ + service.getName(), + , + service.getNs(), + service.getType(), + service.getClusterIp(), + service.getPorts().join(", "), + externalIps.join(", ") || "-", + service.getSelector().map(label => ), + service.getAge(), + { title: service.getStatus(), className: service.getStatus().toLowerCase() }, + ]; + }} /> ); } diff --git a/src/renderer/components/+nodes/node-charts.tsx b/src/renderer/components/+nodes/node-charts.tsx index 6f9495fce5..f718ec7f57 100644 --- a/src/renderer/components/+nodes/node-charts.tsx +++ b/src/renderer/components/+nodes/node-charts.tsx @@ -58,7 +58,7 @@ export const NodeCharts = observer(() => { podUsage, podCapacity, fsSize, - fsUsage + fsUsage, } = mapValues(metrics, metric => normalizeMetrics(metric).data.result[0].values); const datasets = [ @@ -69,29 +69,29 @@ export const NodeCharts = observer(() => { label: `Usage`, tooltip: `CPU cores usage`, borderColor: "#3D90CE", - data: cpuUsage.map(([x, y]) => ({ x, y })) + data: cpuUsage.map(([x, y]) => ({ x, y })), }, { id: `${id}-cpuRequests`, label: `Requests`, tooltip: `CPU requests`, borderColor: "#30b24d", - data: cpuRequests.map(([x, y]) => ({ x, y })) + data: cpuRequests.map(([x, y]) => ({ x, y })), }, { id: `${id}-cpuAllocatableCapacity`, label: `Allocatable Capacity`, tooltip: `CPU allocatable capacity`, borderColor: "#032b4d", - data: cpuAllocatableCapacity.map(([x, y]) => ({ x, y })) + data: cpuAllocatableCapacity.map(([x, y]) => ({ x, y })), }, { id: `${id}-cpuCapacity`, label: `Capacity`, tooltip: `CPU capacity`, borderColor: chartCapacityColor, - data: cpuCapacity.map(([x, y]) => ({ x, y })) - } + data: cpuCapacity.map(([x, y]) => ({ x, y })), + }, ], // Memory [ @@ -100,36 +100,36 @@ export const NodeCharts = observer(() => { label: `Usage`, tooltip: `Memory usage`, borderColor: "#c93dce", - data: memoryUsage.map(([x, y]) => ({ x, y })) + data: memoryUsage.map(([x, y]) => ({ x, y })), }, { id: `${id}-workloadMemoryUsage`, label: `Workload Memory Usage`, tooltip: `Workload memory usage`, borderColor: "#9cd3ce", - data: workloadMemoryUsage.map(([x, y]) => ({ x, y })) + data: workloadMemoryUsage.map(([x, y]) => ({ x, y })), }, { id: "memoryRequests", label: `Requests`, tooltip: `Memory requests`, borderColor: "#30b24d", - data: memoryRequests.map(([x, y]) => ({ x, y })) + data: memoryRequests.map(([x, y]) => ({ x, y })), }, { id: `${id}-memoryAllocatableCapacity`, label: `Allocatable Capacity`, tooltip: `Memory allocatable capacity`, borderColor: "#032b4d", - data: memoryAllocatableCapacity.map(([x, y]) => ({ x, y })) + data: memoryAllocatableCapacity.map(([x, y]) => ({ x, y })), }, { id: `${id}-memoryCapacity`, label: `Capacity`, tooltip: `Memory capacity`, borderColor: chartCapacityColor, - data: memoryCapacity.map(([x, y]) => ({ x, y })) - } + data: memoryCapacity.map(([x, y]) => ({ x, y })), + }, ], // Disk [ @@ -138,15 +138,15 @@ export const NodeCharts = observer(() => { label: `Usage`, tooltip: `Node filesystem usage in bytes`, borderColor: "#ffc63d", - data: fsUsage.map(([x, y]) => ({ x, y })) + data: fsUsage.map(([x, y]) => ({ x, y })), }, { id: `${id}-fsSize`, label: `Size`, tooltip: `Node filesystem size in bytes`, borderColor: chartCapacityColor, - data: fsSize.map(([x, y]) => ({ x, y })) - } + data: fsSize.map(([x, y]) => ({ x, y })), + }, ], // Pods [ @@ -155,25 +155,25 @@ export const NodeCharts = observer(() => { label: `Usage`, tooltip: `Number of running Pods`, borderColor: "#30b24d", - data: podUsage.map(([x, y]) => ({ x, y })) + data: podUsage.map(([x, y]) => ({ x, y })), }, { id: `${id}-podCapacity`, label: `Capacity`, tooltip: `Node Pods capacity`, borderColor: chartCapacityColor, - data: podCapacity.map(([x, y]) => ({ x, y })) - } - ] + data: podCapacity.map(([x, y]) => ({ x, y })), + }, + ], ]; const podOptions: ChartOptions = { scales: { yAxes: [{ ticks: { - callback: value => value - } - }] + callback: value => value, + }, + }], }, tooltips: { callbacks: { @@ -182,9 +182,9 @@ export const NodeCharts = observer(() => { const value = data[index] as ChartPoint; return `${label}: ${value.y}`; - } - } - } + }, + }, + }, }; const options = [cpuOptions, memoryOptions, memoryOptions, podOptions]; diff --git a/src/renderer/components/+nodes/node-details.tsx b/src/renderer/components/+nodes/node-details.tsx index 00ac9ca08d..350ba563b8 100644 --- a/src/renderer/components/+nodes/node-details.tsx +++ b/src/renderer/components/+nodes/node-details.tsx @@ -164,8 +164,8 @@ export class NodeDetails extends React.Component {
{upperFirst(key)}
{value}
-
- ) +
, + ), }} /> ); diff --git a/src/renderer/components/+nodes/nodes.tsx b/src/renderer/components/+nodes/nodes.tsx index 73a6977a2d..a2b5849611 100644 --- a/src/renderer/components/+nodes/nodes.tsx +++ b/src/renderer/components/+nodes/nodes.tsx @@ -115,7 +115,7 @@ export class Nodes extends React.Component { value={usage} tooltip={{ preferredPositions: TooltipPosition.BOTTOM, - children: `CPU: ${cpuUsagePercentLabel}\%, cores: ${cores}` + children: `CPU: ${cpuUsagePercentLabel}\%, cores: ${cores}`, }} /> ); @@ -134,7 +134,7 @@ export class Nodes extends React.Component { value={usage} tooltip={{ preferredPositions: TooltipPosition.BOTTOM, - children: `Memory: ${Math.ceil(usage * 100 / capacity)}%, ${bytesToUnits(usage, 3)}` + children: `Memory: ${Math.ceil(usage * 100 / capacity)}%, ${bytesToUnits(usage, 3)}`, }} /> ); @@ -153,7 +153,7 @@ export class Nodes extends React.Component { value={usage} tooltip={{ preferredPositions: TooltipPosition.BOTTOM, - children: `Disk: ${Math.ceil(usage * 100 / capacity)}%, ${bytesToUnits(usage, 3)}` + children: `Disk: ${Math.ceil(usage * 100 / capacity)}%, ${bytesToUnits(usage, 3)}`, }} /> ); @@ -177,7 +177,7 @@ export class Nodes extends React.Component {
{upperFirst(key)}
{value}
-
+
, )} ); diff --git a/src/renderer/components/+preferences/add-helm-repo-dialog.tsx b/src/renderer/components/+preferences/add-helm-repo-dialog.tsx index 8ec68dc395..d6760fa561 100644 --- a/src/renderer/components/+preferences/add-helm-repo-dialog.tsx +++ b/src/renderer/components/+preferences/add-helm-repo-dialog.tsx @@ -53,10 +53,10 @@ const dialogState = observable.object({ @observer export class AddHelmRepoDialog extends React.Component { - private emptyRepo = {name: "", url: "", username: "", password: "", insecureSkipTlsVerify: false, caFile:"", keyFile: "", certFile: ""}; + private emptyRepo = { name: "", url: "", username: "", password: "", insecureSkipTlsVerify: false, caFile:"", keyFile: "", certFile: "" }; private static keyExtensions = ["key", "keystore", "jks", "p12", "pfx", "pem"]; - private static certExtensions = ["crt", "cer", "ca-bundle", "p7b", "p7c" , "p7s", "p12", "pfx", "pem"]; + private static certExtensions = ["crt", "cer", "ca-bundle", "p7b", "p7c", "p7s", "p12", "pfx", "pem"]; constructor(props: Props) { super(props); @@ -96,8 +96,8 @@ export class AddHelmRepoDialog extends React.Component { buttonLabel: `Use file`, filters: [ fileFilter, - { name: "Any", extensions: ["*"]} - ] + { name: "Any", extensions: ["*"] }, + ], }); if (!canceled && filePaths.length) { @@ -116,7 +116,7 @@ export class AddHelmRepoDialog extends React.Component { } } - renderFileInput(placeholder:string, fileType:FileType ,fileExtensions:string[]){ + renderFileInput(placeholder:string, fileType:FileType, fileExtensions:string[]){ return(
{ /> this.selectFileDialog(fileType, {name: placeholder, extensions: fileExtensions})} + onClick={() => this.selectFileDialog(fileType, { name: placeholder, extensions: fileExtensions })} tooltip="Browse" />
); diff --git a/src/renderer/components/+preferences/editor.tsx b/src/renderer/components/+preferences/editor.tsx index 707bb14428..c5b24172c2 100644 --- a/src/renderer/components/+preferences/editor.tsx +++ b/src/renderer/components/+preferences/editor.tsx @@ -31,10 +31,11 @@ enum EditorLineNumbersStyles { on = "On", off = "Off", relative = "Relative", - interval = "Interval" + interval = "Interval", } export const Editor = observer(() => { + const userStore = UserStore.getInstance(); return (
@@ -43,8 +44,8 @@ export const Editor = observer(() => { UserStore.getInstance().enableEditorMinimap(v.target.checked)} + checked={userStore.editorConfiguration.miniMap.enabled} + onChange={v => userStore.enableEditorMinimap(v.target.checked)} name="minimap" /> } @@ -54,9 +55,9 @@ export const Editor = observer(() => {