From 1675c56e59f7a35f4991d2eb4b07ec9fd1fde514 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Thu, 4 May 2023 13:15:30 -0400 Subject: [PATCH] chore: Turn on @typescript-eslint/strict-boolean-expressions - Fix some bugs about bad conditions Signed-off-by: Sebastian Malton --- package-lock.json | 599 +++++------------- packages/core/.eslintrc.js | 6 + .../app-paths/app-paths-state.injectable.ts | 11 +- .../core/src/common/catalog/catalog-entity.ts | 8 +- .../lens-proxy-certificate.injectable.ts | 11 +- packages/core/src/common/ipc/ipc.ts | 6 +- .../common/k8s-api/api-manager/api-manager.ts | 6 +- ...-kube-api-for-remote-cluster.injectable.ts | 3 +- .../common/k8s-api/endpoints/metrics.api.ts | 16 +- .../metrics.api/request-metrics.injectable.ts | 10 +- .../src/common/k8s-api/kube-object.store.ts | 2 +- .../src/common/protocol-handler/router.ts | 3 +- packages/core/src/common/rbac.ts | 10 +- .../common/utils/reactive-now/reactive-now.ts | 9 +- .../extension-discovery.ts | 1 + .../extension-loader/extension-loader.ts | 2 + .../src/extensions/lens-renderer-extension.ts | 4 +- .../src/extensions/renderer-api/components.ts | 9 +- .../src/extensions/renderer-api/k8s-api.ts | 5 +- ...cation-menu-item-registrator.injectable.ts | 11 +- .../update-button/update-button.tsx | 9 +- .../selected-update-channel.injectable.ts | 2 +- .../common/inject-system-cas.injectable.ts | 3 +- .../storage/main/5.0.0-beta.10.injectable.ts | 19 +- ...trator-for-preference-items.injectable.tsx | 9 +- ...egistrator-for-top-bar-items.injectable.ts | 3 +- packages/core/src/jest.setup.tsx | 2 +- .../prometheus-handler/prometheus-handler.ts | 8 +- .../store-migrations/snap.injectable.ts | 2 +- .../core/src/main/helm/helm-chart-manager.ts | 6 +- .../get-cluster-for-request.injectable.ts | 15 +- .../core/src/main/lens-proxy/lens-proxy.ts | 12 +- .../kube-api-upgrade-request.injectable.ts | 4 +- .../core/src/main/logger/console-format.ts | 11 +- .../main/prometheus/get-by-kind.injectable.ts | 12 +- .../prometheus/helm-provider.injectable.ts | 15 +- .../prometheus/lens-provider.injectable.ts | 15 +- .../operator-provider.injectable.ts.ts | 15 +- .../stacklight-provider.injectable.ts | 15 +- .../lens-protocol-router-main.ts | 4 +- .../create-handler-for-route.injectable.ts | 6 +- packages/core/src/main/router/route.ts | 2 +- .../src/main/router/router-content-types.ts | 11 +- .../routes/files/production.injectable.ts | 3 +- .../node-shell-session/node-shell-session.ts | 3 +- .../src/main/shell-session/shell-session.ts | 2 +- .../tray-menu-item-registrator.injectable.ts | 6 +- .../renderer/api/catalog/entity/registry.ts | 8 +- .../src/renderer/components/avatar/avatar.tsx | 36 +- .../src/renderer/components/badge/badge.tsx | 20 +- .../components/catalog/catalog-add-button.tsx | 23 +- .../catalog/catalog-category-label.tsx | 3 +- .../catalog/catalog-entity-drawer-menu.tsx | 4 - .../kubernetes-cluster-details.injectable.tsx | 36 +- .../renderer/components/chart/bar-chart.tsx | 4 +- .../src/renderer/components/chart/options.ts | 8 +- .../renderer/components/chart/pie-chart.tsx | 2 +- .../renderer/components/checkbox/checkbox.tsx | 4 +- .../cluster-manager/cluster-manager.tsx | 4 +- .../cluster-settings/prometheus-setting.tsx | 4 +- .../components/cluster/cluster-no-metrics.tsx | 2 +- .../internal-commands.injectable.tsx | 4 +- .../details.tsx | 8 +- .../limit-range-details.tsx | 4 - .../config-maps/config-map-details.tsx | 8 +- .../webhook-config.tsx | 12 +- .../resource-quota-details.tsx | 4 - .../config-secrets/secret-details.tsx | 10 +- .../vpa-details.tsx | 9 +- .../custom-resource-definitions/details.tsx | 4 - .../components/custom-resources/details.tsx | 4 +- .../dock/dock-tab-store/dock-tab.store.ts | 3 +- .../src/renderer/components/dock/dock-tab.tsx | 12 +- .../src/renderer/components/dock/dock.tsx | 6 +- .../renderer/components/dock/info-panel.tsx | 6 +- .../renderer/components/dock/logs/search.tsx | 2 +- .../dock/terminal/send-command.injectable.ts | 23 +- .../components/dock/terminal/terminal.ts | 24 +- .../components/drawer/drawer-item-labels.tsx | 2 +- .../components/drawer/drawer-title.tsx | 10 +- .../components/events/event-details.tsx | 4 - .../components/events/kube-event-details.tsx | 6 +- .../attempt-install-by-info.injectable.tsx | 6 +- .../get-message-from-error.ts | 4 +- .../extensions/installed-extensions.tsx | 13 +- .../helm-charts/helm-chart-details.tsx | 21 +- .../renderer/components/helm-charts/icon.tsx | 2 +- .../components/helm-releases/release-menu.tsx | 5 +- .../components/hotbar/hotbar-entity-icon.tsx | 9 +- .../components/hotbar/hotbar-icon.tsx | 8 +- .../src/renderer/components/input/input.tsx | 18 +- .../components/input/input_validators.ts | 14 +- .../components/input/search-input.tsx | 4 +- .../components/item-object-list/content.tsx | 4 +- .../components/item-object-list/header.tsx | 4 +- .../item-object-list/list-layout.tsx | 2 +- .../kube-object-list-layout.tsx | 16 +- .../kube-object-menu/kube-object-menu.tsx | 6 +- .../kube-object-meta/kube-object-meta.tsx | 4 - .../kubeconfig-dialog/kubeconfig-dialog.tsx | 4 +- ...on-sidebar-item-registrator.injectable.tsx | 2 +- .../components/layout/setting-layout.tsx | 4 +- .../renderer/components/layout/sidebar.tsx | 2 +- .../window-controls/window-controls.tsx | 7 +- .../components/layout/wizard-layout.tsx | 6 +- .../renderer/components/menu/menu-actions.tsx | 4 +- .../src/renderer/components/menu/menu.tsx | 42 +- .../monaco-editor/monaco-editor.tsx | 58 +- .../namespaces/namespace-details.tsx | 8 +- .../renderer/components/namespaces/store.ts | 4 +- .../network-endpoints/endpoint-details.tsx | 4 - .../network-ingresses/ingress-details.tsx | 6 +- .../network-policy-details.tsx | 4 - .../port-forward-details.tsx | 24 +- .../port-forward-menu.tsx | 2 - .../service-details-endpoint.tsx | 4 - .../network-services/service-details.tsx | 4 - .../components/network-services/services.tsx | 2 +- .../renderer/components/no-items/no-items.tsx | 4 +- .../src/renderer/components/nodes/details.tsx | 6 +- .../src/renderer/components/nodes/route.tsx | 6 +- .../pod-security-policy-details.tsx | 4 - .../src/renderer/components/radio/radio.tsx | 4 +- ...status-bar-item-registrator.injectable.tsx | 3 +- .../storage-classes/storage-class-details.tsx | 4 - .../volume-claim-details.tsx | 4 - .../storage-volumes/volume-details.tsx | 4 - .../src/renderer/components/switch/switch.tsx | 2 +- .../renderer/components/table/table-cell.tsx | 4 +- .../src/renderer/components/table/table.tsx | 16 +- .../components/tree-view/tree-view.tsx | 17 +- .../cluster-role-bindings/details.tsx | 4 - .../user-management/cluster-roles/details.tsx | 10 +- .../user-management/role-bindings/details.tsx | 4 - .../user-management/roles/details.tsx | 10 +- .../service-accounts/details.tsx | 16 +- .../src/renderer/components/wizard/wizard.tsx | 16 +- .../workloads-cronjobs/cronjob-details.tsx | 4 - .../daemonset-details.tsx | 4 - .../deployment-details.tsx | 4 - .../components/workloads-jobs/job-details.tsx | 4 - .../details/volumes/variant.tsx | 82 ++- .../workloads-pods/pod-container-env.tsx | 10 +- .../workloads-pods/pod-details-container.tsx | 4 +- .../components/workloads-pods/pod-details.tsx | 4 - .../components/workloads-pods/store.ts | 2 +- .../replicaset-details.tsx | 4 - .../statefulset-details.tsx | 4 - packages/core/tsconfig.json | 3 +- .../specifics/horizontal-pod-autoscaler.ts | 2 +- packages/kube-object/src/specifics/ingress.ts | 5 +- .../kube-object/src/specifics/pod-metrics.ts | 2 +- .../src/specifics/pod-security-policy.ts | 4 +- packages/kube-object/src/specifics/service.ts | 10 +- .../src/specifics/storage-class.ts | 4 +- .../src/specifics/vertical-pod-autoscaler.ts | 2 +- packages/ui-components/icon/src/icon.tsx | 18 +- .../utility-features/json-api/src/json-api.ts | 10 +- .../kube-api/src/kube-api-parse.ts | 4 + .../utility-features/kube-api/src/kube-api.ts | 6 +- .../utilities/src/collection-functions.ts | 14 + .../utility-features/utilities/src/iter.ts | 29 +- .../utility-features/utilities/src/tuple.ts | 2 +- .../utilities/src/type-narrowing.ts | 14 + tsconfig.json | 1 + 165 files changed, 853 insertions(+), 1141 deletions(-) diff --git a/package-lock.json b/package-lock.json index fd667d2919..1410a57a3f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7539,7 +7539,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", "integrity": "sha512-0VLab/pcLTLcfbxi6THSIMVYcw9hEUBGvjwwaGpW77mMgRXfGF+a76t7BxTGyLh1y68tBvrffp8UWnqvm76+yg==", - "dev": true, "dependencies": { "postcss": "^8.0.0" } @@ -7548,7 +7547,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/postcss-modules-scope/-/postcss-modules-scope-3.0.1.tgz", "integrity": "sha512-LNkp3c4ML9EQj2dgslp4i80Jxj72YK3HjYzrTn6ftUVylW1zaKFGqrMlNIyqBmPWmIhZ/Y5r0Y4T49Hk1IuDUg==", - "dev": true, "dependencies": { "postcss": "^8.0.0" } @@ -11757,6 +11755,7 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "dev": true, "engines": { "node": ">=0.10" } @@ -34819,10 +34818,11 @@ "version": "6.5.0", "license": "MIT", "dependencies": { - "typescript": "^4.9.3" + "typescript": "^4.9.3", + "typescript-plugin-css-modules": "^5.0.1" }, "devDependencies": { - "typescript-plugin-css-modules": "^5.0.1" + "@k8slens/eslint-config": "^6.5.0-alpha.3" } }, "packages/infrastructure/webpack": { @@ -38893,7 +38893,7 @@ "typedoc": "^0.24.6", "typedoc-plugin-markdown": "^3.15.1", "typescript": "^4.9.5", - "typescript-plugin-css-modules": "^3.4.0", + "typescript-plugin-css-modules": "^5.0.1", "url-parse": "^1.5.10", "uuid": "^8.3.2", "webpack": "^5.81.0", @@ -38910,6 +38910,78 @@ "zod": "^3.21.4" }, "dependencies": { + "dotenv": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", + "dev": true + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true + }, + "stylus": { + "version": "0.59.0", + "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.59.0.tgz", + "integrity": "sha512-lQ9w/XIOH5ZHVNuNbWW8D822r+/wBSO/d6XvtyHLF7LW4KaCIDeVbvn5DF8fGCJAUCwVhVi/h6J0NUcnylUEjg==", + "dev": true, + "requires": { + "@adobe/css-tools": "^4.0.1", + "debug": "^4.3.2", + "glob": "^7.1.6", + "sax": "~1.2.4", + "source-map": "^0.7.3" + } + }, + "tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, + "requires": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "typescript-plugin-css-modules": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/typescript-plugin-css-modules/-/typescript-plugin-css-modules-5.0.1.tgz", + "integrity": "sha512-hKXObfwfjx2/myRq4JeQ8D3xIWYTFqusi0hS/Aka7RFX1xQEoEkdOGDWyXNb8LmObawsUzbI30gQnZvqYXCrkA==", + "dev": true, + "requires": { + "@types/postcss-modules-local-by-default": "^4.0.0", + "@types/postcss-modules-scope": "^3.0.1", + "dotenv": "^16.0.3", + "icss-utils": "^5.1.0", + "less": "^4.1.3", + "lodash.camelcase": "^4.3.0", + "postcss": "^8.4.21", + "postcss-load-config": "^3.1.4", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "reserved-words": "^0.1.2", + "sass": "^1.58.3", + "source-map-js": "^1.0.2", + "stylus": "^0.59.0", + "tsconfig-paths": "^4.1.2" + }, + "dependencies": { + "postcss-load-config": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", + "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", + "dev": true, + "requires": { + "lilconfig": "^2.0.5", + "yaml": "^1.10.2" + } + } + } + }, "xterm": { "version": "4.19.0", "resolved": "https://registry.npmjs.org/xterm/-/xterm-4.19.0.tgz", @@ -38993,7 +39065,7 @@ "typedoc": "^0.24.6", "typedoc-plugin-markdown": "^3.15.1", "typescript": "^4.9.5", - "typescript-plugin-css-modules": "^4.1.1", + "typescript-plugin-css-modules": "^5.0.1", "webpack": "^5.81.0", "webpack-cli": "^5.0.1" }, @@ -39086,9 +39158,9 @@ } }, "typescript-plugin-css-modules": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/typescript-plugin-css-modules/-/typescript-plugin-css-modules-4.2.3.tgz", - "integrity": "sha512-jEEP2oUPOqR89QGgvPK2HSTZLkrCeKZQ9EwiNxm9VUcufUbNY1Tv053fPKRq6c13PMQjlBU3WrQjKN8u0j5Y6w==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/typescript-plugin-css-modules/-/typescript-plugin-css-modules-5.0.1.tgz", + "integrity": "sha512-hKXObfwfjx2/myRq4JeQ8D3xIWYTFqusi0hS/Aka7RFX1xQEoEkdOGDWyXNb8LmObawsUzbI30gQnZvqYXCrkA==", "dev": true, "requires": { "@types/postcss-modules-local-by-default": "^4.0.0", @@ -39642,7 +39714,75 @@ "requires": { "@k8slens/eslint-config": "^6.5.0-alpha.2", "typescript": "^4.9.3", - "typescript-plugin-css-modules": "^3.4.0" + "typescript-plugin-css-modules": "^5.0.1" + }, + "dependencies": { + "dotenv": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==" + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==" + }, + "stylus": { + "version": "0.59.0", + "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.59.0.tgz", + "integrity": "sha512-lQ9w/XIOH5ZHVNuNbWW8D822r+/wBSO/d6XvtyHLF7LW4KaCIDeVbvn5DF8fGCJAUCwVhVi/h6J0NUcnylUEjg==", + "requires": { + "@adobe/css-tools": "^4.0.1", + "debug": "^4.3.2", + "glob": "^7.1.6", + "sax": "~1.2.4", + "source-map": "^0.7.3" + } + }, + "tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "requires": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "typescript-plugin-css-modules": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/typescript-plugin-css-modules/-/typescript-plugin-css-modules-5.0.1.tgz", + "integrity": "sha512-hKXObfwfjx2/myRq4JeQ8D3xIWYTFqusi0hS/Aka7RFX1xQEoEkdOGDWyXNb8LmObawsUzbI30gQnZvqYXCrkA==", + "requires": { + "@types/postcss-modules-local-by-default": "^4.0.0", + "@types/postcss-modules-scope": "^3.0.1", + "dotenv": "^16.0.3", + "icss-utils": "^5.1.0", + "less": "^4.1.3", + "lodash.camelcase": "^4.3.0", + "postcss": "^8.4.21", + "postcss-load-config": "^3.1.4", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "reserved-words": "^0.1.2", + "sass": "^1.58.3", + "source-map-js": "^1.0.2", + "stylus": "^0.59.0", + "tsconfig-paths": "^4.1.2" + }, + "dependencies": { + "postcss-load-config": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", + "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", + "requires": { + "lilconfig": "^2.0.5", + "yaml": "^1.10.2" + } + } + } + } } }, "@k8slens/utilities": { @@ -43423,7 +43563,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", "integrity": "sha512-0VLab/pcLTLcfbxi6THSIMVYcw9hEUBGvjwwaGpW77mMgRXfGF+a76t7BxTGyLh1y68tBvrffp8UWnqvm76+yg==", - "dev": true, "requires": { "postcss": "^8.0.0" } @@ -43432,7 +43571,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/postcss-modules-scope/-/postcss-modules-scope-3.0.1.tgz", "integrity": "sha512-LNkp3c4ML9EQj2dgslp4i80Jxj72YK3HjYzrTn6ftUVylW1zaKFGqrMlNIyqBmPWmIhZ/Y5r0Y4T49Hk1IuDUg==", - "dev": true, "requires": { "postcss": "^8.0.0" } @@ -44785,11 +44923,6 @@ "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" - }, "atomically": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/atomically/-/atomically-1.7.0.tgz", @@ -46526,24 +46659,6 @@ "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==" }, - "css": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", - "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", - "requires": { - "inherits": "^2.0.3", - "source-map": "^0.6.1", - "source-map-resolve": "^0.5.2", - "urix": "^0.1.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, "css-box-model": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz", @@ -46568,14 +46683,6 @@ "semver": "^7.3.8" } }, - "css-parse": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-2.0.0.tgz", - "integrity": "sha512-UNIFik2RgSbiTwIW1IsFwXWn6vs+bYdq83LKTSOsx7NJR7WII9dxewkHLltfTLVppoUApHV0118a4RZRI9FLwA==", - "requires": { - "css": "^2.0.0" - } - }, "css-select": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", @@ -46589,15 +46696,6 @@ "nth-check": "^2.0.1" } }, - "css-selector-tokenizer": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz", - "integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==", - "requires": { - "cssesc": "^3.0.0", - "fastparse": "^1.1.2" - } - }, "css-vendor": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", @@ -46742,7 +46840,8 @@ "decode-uri-component": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", - "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==" + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "dev": true }, "decompress-response": { "version": "6.0.0", @@ -47239,7 +47338,8 @@ "dotenv": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "dev": true }, "dotenv-expand": { "version": "5.1.0", @@ -48986,11 +49086,6 @@ "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==" }, - "fastparse": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", - "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==" - }, "fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", @@ -49496,42 +49591,6 @@ "wide-align": "^1.1.5" } }, - "generic-names": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/generic-names/-/generic-names-1.0.3.tgz", - "integrity": "sha512-b6OHfQuKasIKM9b6YPkX+KUj/TLBTx3B/1aT1T5F12FEuEqyFMdr59OMS53aoaSw8eVtapdqieX6lbg5opaOhA==", - "requires": { - "loader-utils": "^0.2.16" - }, - "dependencies": { - "big.js": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", - "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==" - }, - "emojis-list": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha512-knHEZMgs8BB+MInokmNTg/OyPlAddghe1YBgNwJBc5zsJi/uyIcXoSDsL/W9ymOsBoBGdPIHXYJ9+qKFwRwDng==" - }, - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw==" - }, - "loader-utils": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", - "integrity": "sha512-tiv66G0SmiOx+pLWMtGEkfSEejxvb6N6uRrQjfWJIT79W9GMpgKeCAmm9aVBKtd4WEgntciI8CsGqjpDoCWJug==", - "requires": { - "big.js": "^3.1.3", - "emojis-list": "^2.0.0", - "json5": "^0.5.0", - "object-assign": "^4.0.1" - } - } - } - }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -57682,7 +57741,7 @@ "type-fest": "^2.14.0", "typed-emitter": "^1.4.0", "typescript": "^4.9.5", - "typescript-plugin-css-modules": "^4.1.1", + "typescript-plugin-css-modules": "^5.0.1", "webpack": "^5.81.0", "webpack-cli": "^4.9.2", "webpack-dev-server": "^4.13.3", @@ -57727,9 +57786,9 @@ } }, "typescript-plugin-css-modules": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/typescript-plugin-css-modules/-/typescript-plugin-css-modules-4.2.3.tgz", - "integrity": "sha512-jEEP2oUPOqR89QGgvPK2HSTZLkrCeKZQ9EwiNxm9VUcufUbNY1Tv053fPKRq6c13PMQjlBU3WrQjKN8u0j5Y6w==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/typescript-plugin-css-modules/-/typescript-plugin-css-modules-5.0.1.tgz", + "integrity": "sha512-hKXObfwfjx2/myRq4JeQ8D3xIWYTFqusi0hS/Aka7RFX1xQEoEkdOGDWyXNb8LmObawsUzbI30gQnZvqYXCrkA==", "dev": true, "requires": { "@types/postcss-modules-local-by-default": "^4.0.0", @@ -58669,255 +58728,6 @@ "source-map-js": "^1.0.2" } }, - "postcss-filter-plugins": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/postcss-filter-plugins/-/postcss-filter-plugins-3.0.1.tgz", - "integrity": "sha512-tRKbW4wWBEkSSFuJtamV2wkiV9rj6Yy7P3Y13+zaynlPEEZt8EgYKn3y/RBpMeIhNmHXFlSdzofml65hD5OafA==", - "requires": { - "postcss": "^6.0.14" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" - }, - "postcss": { - "version": "6.0.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", - "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", - "requires": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.4.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-icss-keyframes": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/postcss-icss-keyframes/-/postcss-icss-keyframes-0.2.1.tgz", - "integrity": "sha512-4m+hLY5TVqoTM198KKnzdNudyu1OvtqwD+8kVZ9PNiEO4+IfHYoyVvEXsOHjV8nZ1k6xowf+nY4HlUfZhOFvvw==", - "requires": { - "icss-utils": "^3.0.1", - "postcss": "^6.0.2", - "postcss-value-parser": "^3.3.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" - }, - "icss-utils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-3.0.1.tgz", - "integrity": "sha512-ANhVLoEfe0KoC9+z4yiTaXOneB49K6JIXdS+yAgH0NERELpdIT7kkj2XxUPuHafeHnn8umXnECSpsfk1RTaUew==", - "requires": { - "postcss": "^6.0.2" - } - }, - "postcss": { - "version": "6.0.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", - "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", - "requires": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.4.0" - } - }, - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-icss-selectors": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/postcss-icss-selectors/-/postcss-icss-selectors-2.0.3.tgz", - "integrity": "sha512-dxFtq+wscbU9faJaH8kIi98vvCPDbt+qg1g9GoG0os1PY3UvgY1Y2G06iZrZb1iVC9cyFfafwSY1IS+IQpRQ4w==", - "requires": { - "css-selector-tokenizer": "^0.7.0", - "generic-names": "^1.0.2", - "icss-utils": "^3.0.1", - "lodash": "^4.17.4", - "postcss": "^6.0.2" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" - }, - "icss-utils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-3.0.1.tgz", - "integrity": "sha512-ANhVLoEfe0KoC9+z4yiTaXOneB49K6JIXdS+yAgH0NERELpdIT7kkj2XxUPuHafeHnn8umXnECSpsfk1RTaUew==", - "requires": { - "postcss": "^6.0.2" - } - }, - "postcss": { - "version": "6.0.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", - "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", - "requires": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.4.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, "postcss-import": { "version": "15.1.0", "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", @@ -60191,11 +60001,6 @@ "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==" - }, "resolve.exports": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", @@ -60966,18 +60771,6 @@ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" }, - "source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, "source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", @@ -60994,11 +60787,6 @@ } } }, - "source-map-url": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==" - }, "spawn-command": { "version": "0.0.2-1", "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", @@ -61494,41 +61282,6 @@ "integrity": "sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==", "dev": true }, - "stylus": { - "version": "0.54.8", - "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.8.tgz", - "integrity": "sha512-vr54Or4BZ7pJafo2mpf0ZcwA74rpuYCZbxrHBsH8kbcXOwSfvBFwsRfpGO5OD5fhG5HDCFW737PKaawI7OqEAg==", - "requires": { - "css-parse": "~2.0.0", - "debug": "~3.1.0", - "glob": "^7.1.6", - "mkdirp": "~1.0.4", - "safer-buffer": "^2.1.2", - "sax": "~1.2.4", - "semver": "^6.3.0", - "source-map": "^0.7.3" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, "sucrase": { "version": "3.32.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz", @@ -62629,37 +62382,6 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==" }, - "typescript-plugin-css-modules": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/typescript-plugin-css-modules/-/typescript-plugin-css-modules-3.4.0.tgz", - "integrity": "sha512-2MdjfSg4MGex1csCWRUwKD+MpgnvcvLLr9bSAMemU/QYGqBsXdez0cc06H/fFhLtRoKJjXg6PSTur3Gy1Umhpw==", - "requires": { - "dotenv": "^10.0.0", - "icss-utils": "^5.1.0", - "less": "^4.1.1", - "lodash.camelcase": "^4.3.0", - "postcss": "^8.3.0", - "postcss-filter-plugins": "^3.0.1", - "postcss-icss-keyframes": "^0.2.1", - "postcss-icss-selectors": "^2.0.3", - "postcss-load-config": "^3.0.1", - "reserved-words": "^0.1.2", - "sass": "^1.32.13", - "stylus": "^0.54.8", - "tsconfig-paths": "^3.9.0" - }, - "dependencies": { - "postcss-load-config": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", - "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", - "requires": { - "lilconfig": "^2.0.5", - "yaml": "^1.10.2" - } - } - } - }, "typical": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", @@ -62815,11 +62537,6 @@ "punycode": "^2.1.0" } }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==" - }, "url-parse": { "version": "1.5.10", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", diff --git a/packages/core/.eslintrc.js b/packages/core/.eslintrc.js index 21b5837f9a..7e42c43b92 100644 --- a/packages/core/.eslintrc.js +++ b/packages/core/.eslintrc.js @@ -125,6 +125,7 @@ module.exports = { "no-constant-condition": ["error", { "checkLoops": false, }], + "no-extra-boolean-cast": "off", "header/header": [2, "../../license-header"], "react/prop-types": "off", "no-invalid-this": "off", @@ -136,6 +137,11 @@ module.exports = { "@typescript-eslint/explicit-module-boundary-types": "off", "@typescript-eslint/no-empty-function": "off", "@typescript-eslint/no-unnecessary-type-assertion": "off", + "@typescript-eslint/strict-boolean-expressions": ["error", { + "allowNullableString": true, + "allowNullableBoolean": true, + "allowNullableNumber": true, + }], "no-restricted-imports": ["error", { "paths": [ { diff --git a/packages/core/src/common/app-paths/app-paths-state.injectable.ts b/packages/core/src/common/app-paths/app-paths-state.injectable.ts index 5487d428b2..6be0de0c77 100644 --- a/packages/core/src/common/app-paths/app-paths-state.injectable.ts +++ b/packages/core/src/common/app-paths/app-paths-state.injectable.ts @@ -3,27 +3,24 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; +import assert from "assert"; import type { AppPaths } from "./app-path-injection-token"; const appPathsStateInjectable = getInjectable({ id: "app-paths-state", instantiate: () => { - let state: AppPaths; + let state: AppPaths | undefined; return { get: () =>{ - if (!state) { - throw new Error("Tried to get app paths before state is setupped."); - } + assert(state, "Tried to get app paths before initialization"); return state; }, set: (newState: AppPaths) => { - if (state) { - throw new Error("Tried to overwrite existing state of app paths."); - } + assert(!state, "Tried to overwrite existing state of app paths"); state = newState; }, diff --git a/packages/core/src/common/catalog/catalog-entity.ts b/packages/core/src/common/catalog/catalog-entity.ts index f673cc232f..d3694b90f2 100644 --- a/packages/core/src/common/catalog/catalog-entity.ts +++ b/packages/core/src/common/catalog/catalog-entity.ts @@ -8,7 +8,7 @@ import type TypedEmitter from "typed-emitter"; import { observable, makeObservable } from "mobx"; import { once } from "lodash"; import type { Disposer, StrictReactNode } from "@k8slens/utilities"; -import { iter } from "@k8slens/utilities"; +import { isObject, iter } from "@k8slens/utilities"; import type { CategoryColumnRegistration, TitleCellProps } from "../../renderer/components/catalog/custom-category-columns"; import type { Literal, Metadata } from "../cluster-types"; @@ -364,15 +364,15 @@ export abstract class CatalogEntity< constructor({ metadata, status, spec }: CatalogEntityData) { makeObservable(this); - if (!metadata || typeof metadata !== "object") { + if (!isObject(metadata)) { throw new TypeError("CatalogEntity's metadata must be a defined object"); } - if (!status || typeof status !== "object") { + if (!isObject(status)) { throw new TypeError("CatalogEntity's status must be a defined object"); } - if (!spec || typeof spec !== "object") { + if (!isObject(spec)) { throw new TypeError("CatalogEntity's spec must be a defined object"); } diff --git a/packages/core/src/common/certificate/lens-proxy-certificate.injectable.ts b/packages/core/src/common/certificate/lens-proxy-certificate.injectable.ts index b5e00e0094..968695e2b8 100644 --- a/packages/core/src/common/certificate/lens-proxy-certificate.injectable.ts +++ b/packages/core/src/common/certificate/lens-proxy-certificate.injectable.ts @@ -3,24 +3,21 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; +import assert from "assert"; import type { SelfSignedCert } from "selfsigned"; const lensProxyCertificateInjectable = getInjectable({ id: "lens-proxy-certificate", instantiate: () => { - let certState: SelfSignedCert; + let certState: SelfSignedCert | undefined; const cert = { get: () => { - if (!certState) { - throw "certificate has not been set"; - } + assert(certState, "certificate has not been set"); return certState; }, set: (certificate: SelfSignedCert) => { - if (certState) { - throw "certificate has already been set"; - } + assert(!certState, "certificate has already been set"); certState = certificate; }, diff --git a/packages/core/src/common/ipc/ipc.ts b/packages/core/src/common/ipc/ipc.ts index ab8f7b6b04..a27e8e348a 100644 --- a/packages/core/src/common/ipc/ipc.ts +++ b/packages/core/src/common/ipc/ipc.ts @@ -30,12 +30,14 @@ export function ipcMainHandle(channel: string, listener: (event: Electron.IpcMai } export async function broadcastMessage(channel: string, ...args: unknown[]): Promise { + // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions if (ipcRenderer) { await ipcRenderer.invoke(broadcastMainChannel, channel, ...args.map(toJS)); return; } + // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions if (!webContents) { return; } @@ -56,9 +58,9 @@ export async function broadcastMessage(channel: string, ...args: unknown[]): Pro ); }); - const views = webContents.getAllWebContents(); + const views = webContents.getAllWebContents() ?? []; - if (!views || !isArray(views) || views.length === 0) return; + if (!isArray(views) || views.length === 0) return; args = args.map(toJS); diff --git a/packages/core/src/common/k8s-api/api-manager/api-manager.ts b/packages/core/src/common/k8s-api/api-manager/api-manager.ts index 29fa71fbc9..7506a4db6c 100644 --- a/packages/core/src/common/k8s-api/api-manager/api-manager.ts +++ b/packages/core/src/common/k8s-api/api-manager/api-manager.ts @@ -10,7 +10,7 @@ import { autorun, action, observable } from "mobx"; import type { KubeApi } from "@k8slens/kube-api"; import type { KubeObject, ObjectReference } from "@k8slens/kube-object"; import { parseKubeApi, createKubeApiURL } from "@k8slens/kube-api"; -import { getOrInsertWith, iter } from "@k8slens/utilities"; +import { getOrInsertWith, isDefined, iter } from "@k8slens/utilities"; import type { CreateCustomResourceStore } from "./create-custom-resource-store.injectable"; // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -142,7 +142,7 @@ export class ApiManager { */ getStore(api: string | KubeApi): Store | undefined ; getStore(apiOrBase: string | KubeApi | undefined): KubeObjectStore | undefined { - if (!apiOrBase) { + if (!isDefined(apiOrBase) || apiOrBase === "") { return undefined; } @@ -152,7 +152,7 @@ export class ApiManager { const api = apiBase && this.getApi(apiBase); - if (!api) { + if (!isDefined(api) || api === "") { return undefined; } diff --git a/packages/core/src/common/k8s-api/create-kube-api-for-remote-cluster.injectable.ts b/packages/core/src/common/k8s-api/create-kube-api-for-remote-cluster.injectable.ts index 4fc43f9209..6bebc059f1 100644 --- a/packages/core/src/common/k8s-api/create-kube-api-for-remote-cluster.injectable.ts +++ b/packages/core/src/common/k8s-api/create-kube-api-for-remote-cluster.injectable.ts @@ -12,6 +12,7 @@ import createKubeJsonApiInjectable from "./create-kube-json-api.injectable"; import type { KubeApiOptions } from "@k8slens/kube-api"; import { KubeApi } from "@k8slens/kube-api"; import type { KubeJsonApiDataFor, KubeObject, KubeObjectConstructor } from "@k8slens/kube-object"; +import { isDefined } from "@k8slens/utilities"; export interface CreateKubeApiForRemoteClusterConfig { cluster: { @@ -92,7 +93,7 @@ const createKubeApiForRemoteClusterInjectable = getInjectable({ serverAddress: config.cluster.server, apiBase: "", debug: isDevelopment, - ...(token ? { + ...(isDefined(token) ? { getRequestOptions: async () => ({ headers: { "Authorization": `Bearer ${typeof token === "function" ? await token() : token}`, diff --git a/packages/core/src/common/k8s-api/endpoints/metrics.api.ts b/packages/core/src/common/k8s-api/endpoints/metrics.api.ts index 69465bbf6e..7db0c6e19b 100644 --- a/packages/core/src/common/k8s-api/endpoints/metrics.api.ts +++ b/packages/core/src/common/k8s-api/endpoints/metrics.api.ts @@ -49,10 +49,10 @@ export function normalizeMetrics(metrics: MetricData | undefined | null, frames if (frames > 0) { // fill the gaps result.forEach(res => { - if (!res.values || !res.values.length) return; + if (!res.values.length) return; let now = moment().startOf("minute").subtract(1, "minute").unix(); - let timestamp = res.values[0][0]; + let timestamp = res.values[0]?.[0] ?? 0; while (timestamp <= now) { timestamp = moment.unix(timestamp).add(1, "minute").unix(); @@ -63,7 +63,7 @@ export function normalizeMetrics(metrics: MetricData | undefined | null, frames } while (res.values.length < frames) { - const timestamp = moment.unix(res.values[0][0]).subtract(1, "minute").unix(); + const timestamp = moment.unix(res.values[0]?.[0] ?? 0).subtract(1, "minute").unix(); if (!res.values.find((value) => value[0] === timestamp)) { res.values.unshift([timestamp, "0"]); @@ -101,9 +101,11 @@ export function getItemMetrics(metrics: Partial Object.values(res.metric)[0] == itemName); + const item = itemMetrics[metric]; - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - itemMetrics[metric]!.data.result = result ? [result] : []; + if (item) { + item.data.result = result ? [result] : []; + } } return itemMetrics; @@ -114,7 +116,9 @@ export function getMetricLastPoints(metrics: Partial { try { - return [metricName, +metric.data.result[0].values.slice(-1)[0][1]] as const; + const [value = [0, "0"]] = metric.data.result[0]?.values.slice(-1) ?? []; + + return [metricName, +value[1]] as const; } catch { return undefined; } diff --git a/packages/core/src/common/k8s-api/endpoints/metrics.api/request-metrics.injectable.ts b/packages/core/src/common/k8s-api/endpoints/metrics.api/request-metrics.injectable.ts index 861305b2e6..620b3c2a59 100644 --- a/packages/core/src/common/k8s-api/endpoints/metrics.api/request-metrics.injectable.ts +++ b/packages/core/src/common/k8s-api/endpoints/metrics.api/request-metrics.injectable.ts @@ -48,14 +48,8 @@ const requestMetricsInjectable = getInjectable({ function requestMetrics(query: Record>>, params?: RequestMetricsParams): Promise>; async function requestMetrics(metricsQuery: string | string[] | Partial>>>, params: RequestMetricsParams = {}): Promise>> { const { range = 3600, step = 60, namespace } = params; - let { start, end } = params; - - if (!start && !end) { - const now = getSecondsFromUnixEpoch(); - - start = now - range; - end = now; - } + const now = getSecondsFromUnixEpoch(); + const { start = now - range, end = now } = params; return apiBase.post("/metrics", { data: metricsQuery, diff --git a/packages/core/src/common/k8s-api/kube-object.store.ts b/packages/core/src/common/k8s-api/kube-object.store.ts index f539153090..6a772e137d 100644 --- a/packages/core/src/common/k8s-api/kube-object.store.ts +++ b/packages/core/src/common/k8s-api/kube-object.store.ts @@ -306,7 +306,7 @@ export class KubeObjectStore< } protected resetOnError(error: unknown) { - if (error) this.reset(); + if (Boolean(error)) this.reset(); } protected async loadItem(params: { name: string; namespace?: string }): Promise { diff --git a/packages/core/src/common/protocol-handler/router.ts b/packages/core/src/common/protocol-handler/router.ts index 096e5968a3..da1b352bf5 100644 --- a/packages/core/src/common/protocol-handler/router.ts +++ b/packages/core/src/common/protocol-handler/router.ts @@ -122,7 +122,7 @@ export abstract class LensProtocolRouter { return -1; } - return countBy(b.path)["/"] - countBy(a.path)["/"]; + return (countBy(b.path)["/"] ?? 0) - (countBy(a.path)["/"] ?? 0); })[0] ?? null; } @@ -204,6 +204,7 @@ export abstract class LensProtocolRouter { const extension = extensionLoader.getInstanceByName(name) as LensExtension | undefined; if (!extension) { + // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions this.dependencies.logger.info(`${LensProtocolRouter.LoggingPrefix}: Extension ${name} matched, but does not have a class for ${ipcRenderer ? "renderer" : "main"}`); return name; diff --git a/packages/core/src/common/rbac.ts b/packages/core/src/common/rbac.ts index f42b07e775..b7e6a879d2 100644 --- a/packages/core/src/common/rbac.ts +++ b/packages/core/src/common/rbac.ts @@ -3,13 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -export type KubeResource = - "namespaces" | "nodes" | "events" | "resourcequotas" | "services" | "limitranges" | "leases" | - "secrets" | "configmaps" | "ingresses" | "ingressclasses" | "networkpolicies" | "persistentvolumeclaims" | "persistentvolumes" | "storageclasses" | - "pods" | "daemonsets" | "deployments" | "statefulsets" | "replicasets" | "replicationcontrollers" | "jobs" | "cronjobs" | - "endpoints" | "customresourcedefinitions" | "horizontalpodautoscalers" | "verticalpodautoscalers" | "podsecuritypolicies" | "poddisruptionbudgets" | - "priorityclasses" | "runtimeclasses" | - "roles" | "clusterroles" | "rolebindings" | "clusterrolebindings" | "serviceaccounts" | "mutatingwebhookconfigurations" | "validatingwebhookconfigurations"; +export type KubeResource = keyof typeof apiResourceRecord; export interface KubeApiResource { kind: string; @@ -35,7 +29,7 @@ export interface KubeApiResourceData { namespaced: boolean; } -export const apiResourceRecord: Record = { +export const apiResourceRecord = { clusterroles: { kind: "ClusterRole", group: "rbac.authorization.k8s.io", diff --git a/packages/core/src/common/utils/reactive-now/reactive-now.ts b/packages/core/src/common/utils/reactive-now/reactive-now.ts index febac37010..d140410c00 100644 --- a/packages/core/src/common/utils/reactive-now/reactive-now.ts +++ b/packages/core/src/common/utils/reactive-now/reactive-now.ts @@ -20,15 +20,16 @@ export function reactiveNow(interval?: number | "frame") { // Note: This is the kludge until https://github.com/mobxjs/mobx-utils/issues/306 is fixed const synchronizationIsEnabled = !process.env.JEST_WORKER_ID; + let ticker = tickers[interval]; - if (!tickers[interval] || !synchronizationIsEnabled) { + if (!ticker || !synchronizationIsEnabled) { if (typeof interval === "number") - tickers[interval] = createIntervalTicker(interval); + ticker = tickers[interval] = createIntervalTicker(interval); else - tickers[interval] = createAnimationFrameTicker(); + ticker = tickers[interval] = createAnimationFrameTicker(); } - return tickers[interval].current(); + return ticker.current(); } function createIntervalTicker(interval: number) { diff --git a/packages/core/src/extensions/extension-discovery/extension-discovery.ts b/packages/core/src/extensions/extension-discovery/extension-discovery.ts index cdeee413fa..e0d4cd3609 100644 --- a/packages/core/src/extensions/extension-discovery/extension-discovery.ts +++ b/packages/core/src/extensions/extension-discovery/extension-discovery.ts @@ -109,6 +109,7 @@ export class ExtensionDiscovery { * Initializes the class and setups the file watcher for added/removed local extensions. */ async init() { + // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions if (ipcRenderer) { await this.initRenderer(); } else { diff --git a/packages/core/src/extensions/extension-loader/extension-loader.ts b/packages/core/src/extensions/extension-loader/extension-loader.ts index 160ee4ec21..32fe28e89f 100644 --- a/packages/core/src/extensions/extension-loader/extension-loader.ts +++ b/packages/core/src/extensions/extension-loader/extension-loader.ts @@ -101,6 +101,7 @@ export class ExtensionLoader { )); async init() { + // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions if (ipcMain) { await this.initMain(); } else { @@ -211,6 +212,7 @@ export class ExtensionLoader { } broadcastExtensions() { + // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions const channel = ipcRenderer ? extensionLoaderFromRendererChannel : extensionLoaderFromMainChannel; diff --git a/packages/core/src/extensions/lens-renderer-extension.ts b/packages/core/src/extensions/lens-renderer-extension.ts index 56aad1d3b2..62944884e4 100644 --- a/packages/core/src/extensions/lens-renderer-extension.ts +++ b/packages/core/src/extensions/lens-renderer-extension.ts @@ -145,7 +145,9 @@ export class LensRendererExtension extends LensExtension { */ // eslint-disable-next-line @typescript-eslint/ban-types async isEnabledForCluster(cluster: KubernetesCluster): Promise { - return Promise.resolve((void cluster) || true); + void cluster; + + return Promise.resolve(true); } /** diff --git a/packages/core/src/extensions/renderer-api/components.ts b/packages/core/src/extensions/renderer-api/components.ts index 36ce3bba0a..6ac6078799 100644 --- a/packages/core/src/extensions/renderer-api/components.ts +++ b/packages/core/src/extensions/renderer-api/components.ts @@ -146,10 +146,13 @@ export const logTabStore = Object.assign( createWorkloadTab: asLegacyGlobalFunctionForExtensionApi(createWorkloadLogsTabInjectable), renameTab: (tabId: string): void => { const { selectedPodId } = logTabStore.getData(tabId) ?? {}; - const pod = selectedPodId && podStore.getById(selectedPodId); - if (pod) { - renameTab(tabId, `Pod ${pod.getName()}`); + if (selectedPodId) { + const pod = podStore.getById(selectedPodId); + + if (pod) { + renameTab(tabId, `Pod ${pod.getName()}`); + } } }, tabs: undefined, diff --git a/packages/core/src/extensions/renderer-api/k8s-api.ts b/packages/core/src/extensions/renderer-api/k8s-api.ts index 7dc9abca43..73d2816840 100644 --- a/packages/core/src/extensions/renderer-api/k8s-api.ts +++ b/packages/core/src/extensions/renderer-api/k8s-api.ts @@ -38,12 +38,13 @@ import roleBindingApiInjectable from "../../common/k8s-api/endpoints/role-bindin import customResourceDefinitionApiInjectable from "../../common/k8s-api/endpoints/custom-resource-definition.api.injectable"; import { shouldShowResourceInjectionToken } from "../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import requestMetricsInjectable from "../../common/k8s-api/endpoints/metrics.api/request-metrics.injectable"; +import { maybeGet } from "@k8slens/utilities"; export function isAllowedResource(resources: KubeResource | KubeResource[]) { const di = getLegacyGlobalDiForExtensionApi(); - return [resources].flat().every((resourceName) => { - const resource = apiResourceRecord[resourceName]; + return [resources].flat().every((resourceName: string) => { + const resource = maybeGet(apiResourceRecord, resourceName); if (!resource) { return true; diff --git a/packages/core/src/features/application-menu/main/application-menu-item-registrator.injectable.ts b/packages/core/src/features/application-menu/main/application-menu-item-registrator.injectable.ts index a4f5c79639..ec41edde40 100644 --- a/packages/core/src/features/application-menu/main/application-menu-item-registrator.injectable.ts +++ b/packages/core/src/features/application-menu/main/application-menu-item-registrator.injectable.ts @@ -81,11 +81,12 @@ const toRecursedInjectablesFor = (logError: (errorMessage: string) => void) => { injectionToken: applicationMenuItemInjectionToken, }), - ...((registration.submenu as MenuRegistration[]) - ? (registration.submenu as MenuRegistration[]).flatMap( - toRecursedInjectables(currentIdPath), - ) - : []), + ...( + registration.submenu + ? (registration.submenu as MenuRegistration[]) + .flatMap(toRecursedInjectables(currentIdPath)) + : [] + ), ]; }; diff --git a/packages/core/src/features/application-update/child-features/application-update-using-top-bar/renderer/update-application-top-bar-item/update-button/update-button.tsx b/packages/core/src/features/application-update/child-features/application-update-using-top-bar/renderer/update-application-top-bar-item/update-button/update-button.tsx index b8191b3258..63b0f861fb 100644 --- a/packages/core/src/features/application-update/child-features/application-update-using-top-bar/renderer/update-application-top-bar-item/update-button/update-button.tsx +++ b/packages/core/src/features/application-update/child-features/application-update-using-top-bar/renderer/update-application-top-bar-item/update-button/update-button.tsx @@ -40,10 +40,11 @@ const NonInjectedUpdateButton = observer(({ warningLevel, update, id }: UpdateBu data-testid="update-button" data-warning-level={level} id={buttonId} - className={cssNames(styles.updateButton, { - [styles.warningHigh]: level === "high", - [styles.warningMedium]: level === "medium", - })} + className={cssNames( + styles.updateButton, + level === "high" && styles.warningHigh, + level === "medium" && styles.warningMedium, + )} > Update diff --git a/packages/core/src/features/application-update/common/selected-update-channel.injectable.ts b/packages/core/src/features/application-update/common/selected-update-channel.injectable.ts index 00cf44611b..2f92932e8b 100644 --- a/packages/core/src/features/application-update/common/selected-update-channel.injectable.ts +++ b/packages/core/src/features/application-update/common/selected-update-channel.injectable.ts @@ -26,7 +26,7 @@ const selectedUpdateChannelInjectable = getInjectable({ setValue: action((channelId) => { const targetUpdateChannel = - channelId && updateChannels[channelId] + channelId && (channelId in updateChannels) ? updateChannels[channelId] : defaultUpdateChannel; diff --git a/packages/core/src/features/certificate-authorities/common/inject-system-cas.injectable.ts b/packages/core/src/features/certificate-authorities/common/inject-system-cas.injectable.ts index f75dcd6c70..af41aa52fd 100644 --- a/packages/core/src/features/certificate-authorities/common/inject-system-cas.injectable.ts +++ b/packages/core/src/features/certificate-authorities/common/inject-system-cas.injectable.ts @@ -3,6 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ +import { isTruthy } from "@k8slens/utilities"; import { getInjectable } from "@ogre-tools/injectable"; import { globalAgent } from "https"; import { requestSystemCAsInjectionToken } from "./request-system-cas-token"; @@ -34,7 +35,7 @@ const injectSystemCAsInjectable = getInjectable({ return globalAgent.options.ca; } - if (globalAgent.options.ca) { + if (isTruthy(globalAgent.options.ca)) { return [globalAgent.options.ca]; } diff --git a/packages/core/src/features/hotbar/storage/main/5.0.0-beta.10.injectable.ts b/packages/core/src/features/hotbar/storage/main/5.0.0-beta.10.injectable.ts index 0bc91ee02f..bad02d7ab6 100644 --- a/packages/core/src/features/hotbar/storage/main/5.0.0-beta.10.injectable.ts +++ b/packages/core/src/features/hotbar/storage/main/5.0.0-beta.10.injectable.ts @@ -73,13 +73,17 @@ const v500Beta10HotbarStoreMigrationInjectable = getInjectable({ { // grab the default named hotbar or the first. const defaultHotbarIndex = Math.max(0, hotbars.findIndex(hotbar => hotbar.name === "default")); - const [{ name, id, items }] = hotbars.splice(defaultHotbarIndex, 1); + const [hotbar] = hotbars.splice(defaultHotbarIndex, 1); - workspaceHotbars.set("default", { - name, - id, - items: items.filter(isDefined), - }); + if (hotbar) { + const { name, id, items } = hotbar; + + workspaceHotbars.set("default", { + name, + id, + items: items.filter(isDefined), + }); + } } for (const cluster of clusters) { @@ -130,7 +134,8 @@ const v500Beta10HotbarStoreMigrationInjectable = getInjectable({ const defaultHotbarIndex = hotbars.findIndex(hotbar => hotbar.name === "default"); if (defaultHotbarIndex >= 0) { - const defaultHotbar = createHotbar(hotbars[defaultHotbarIndex]); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const defaultHotbar = createHotbar(hotbars[defaultHotbarIndex]!); if (defaultHotbar.isFull()) { // making a new hotbar is less destructive if the first hotbar diff --git a/packages/core/src/features/preferences/renderer/compliance-for-legacy-extension-api/registrator-for-preference-items.injectable.tsx b/packages/core/src/features/preferences/renderer/compliance-for-legacy-extension-api/registrator-for-preference-items.injectable.tsx index c69ee37e80..646ec81e29 100644 --- a/packages/core/src/features/preferences/renderer/compliance-for-legacy-extension-api/registrator-for-preference-items.injectable.tsx +++ b/packages/core/src/features/preferences/renderer/compliance-for-legacy-extension-api/registrator-for-preference-items.injectable.tsx @@ -113,11 +113,10 @@ const registratorForPreferenceItemsInjectable = getInjectable({ const items = extension.appPreferences.map((registration, i) => { const itemId = `${commonId}-item-${registration.id ?? i}`; - const itemIsInSpecialTab = - registration.showInPreferencesTab && - ["telemetry", "application"].includes( - registration.showInPreferencesTab, - ); + const itemIsInSpecialTab = ( + registration.showInPreferencesTab === "telemetry" + || registration.showInPreferencesTab === "application" + ); return getInjectable({ id: itemId, diff --git a/packages/core/src/features/top-bar/extension-api/renderer/legacy-extension-api-registrator-for-top-bar-items.injectable.ts b/packages/core/src/features/top-bar/extension-api/renderer/legacy-extension-api-registrator-for-top-bar-items.injectable.ts index 8eef409b1a..d578fa16a1 100644 --- a/packages/core/src/features/top-bar/extension-api/renderer/legacy-extension-api-registrator-for-top-bar-items.injectable.ts +++ b/packages/core/src/features/top-bar/extension-api/renderer/legacy-extension-api-registrator-for-top-bar-items.injectable.ts @@ -9,6 +9,7 @@ import type { LensRendererExtension } from "../../../../extensions/lens-renderer import { pipeline } from "@ogre-tools/fp"; import { topBarItemOnRightSideInjectionToken } from "../../../../renderer/components/layout/top-bar/top-bar-items/top-bar-item-injection-token"; import { computed } from "mobx"; +import type { PartialDeep } from "type-fest"; const legacyExtensionApiRegistratorForTopBarItemsInjectable = getInjectable({ id: "legacy-extension-api-registrator-for-top-bar-items", @@ -19,7 +20,7 @@ const legacyExtensionApiRegistratorForTopBarItemsInjectable = getInjectable({ return pipeline( extension.topBarItems, - reject((registration) => !registration?.components?.Item), + reject((registration) => !(registration as PartialDeep)?.components?.Item), (validTopBarRegistrations) => validTopBarRegistrations.map((registration, index) => { diff --git a/packages/core/src/jest.setup.tsx b/packages/core/src/jest.setup.tsx index de19c00ca4..6a31a96e22 100644 --- a/packages/core/src/jest.setup.tsx +++ b/packages/core/src/jest.setup.tsx @@ -64,7 +64,7 @@ jest.mock("@k8slens/tooltip", () => ({ void tooltipOverrideDisabled; const ResolvedTarget = Target as React.FunctionComponent; - if (tooltip) { + if (Boolean(tooltip)) { const testId = props["data-testid"] as string | undefined; return ( diff --git a/packages/core/src/main/cluster/prometheus-handler/prometheus-handler.ts b/packages/core/src/main/cluster/prometheus-handler/prometheus-handler.ts index ca124128f5..3b83374816 100644 --- a/packages/core/src/main/cluster/prometheus-handler/prometheus-handler.ts +++ b/packages/core/src/main/cluster/prometheus-handler/prometheus-handler.ts @@ -111,9 +111,7 @@ export const createClusterPrometheusHandler = (...args: [Dependencies, Cluster]) break; case "fulfilled": - if (res.value) { - return res.value; - } + return res.value; } } @@ -130,6 +128,10 @@ export const createClusterPrometheusHandler = (...args: [Dependencies, Cluster]) const prometheusPath = ensurePrometheusPath(service); const provider = ensurePrometheusProvider(service); + if (!provider) { + return undefined; + } + return { prometheusPath, provider }; }; diff --git a/packages/core/src/main/cluster/store-migrations/snap.injectable.ts b/packages/core/src/main/cluster/store-migrations/snap.injectable.ts index ecb576df3a..1be4566a14 100644 --- a/packages/core/src/main/cluster/store-migrations/snap.injectable.ts +++ b/packages/core/src/main/cluster/store-migrations/snap.injectable.ts @@ -29,7 +29,7 @@ const clusterStoreSnapMigrationInjectable = getInjectable({ } logger.info("Migrating embedded kubeconfig paths"); - const storedClusters = (store.get("clusters") || []) as ClusterModel[]; + const storedClusters = (store.get("clusters") as (ClusterModel[] | undefined) ?? []); if (!storedClusters.length) return; diff --git a/packages/core/src/main/helm/helm-chart-manager.ts b/packages/core/src/main/helm/helm-chart-manager.ts index 6cd5562076..4b8157eecb 100644 --- a/packages/core/src/main/helm/helm-chart-manager.ts +++ b/packages/core/src/main/helm/helm-chart-manager.ts @@ -4,7 +4,7 @@ */ import * as yaml from "js-yaml"; -import { iter, put, sortBySemverVersion } from "@k8slens/utilities"; +import { isObject, iter, put, sortBySemverVersion } from "@k8slens/utilities"; import type { HelmRepo } from "../../common/helm/helm-repo"; import type { HelmChartManagerCache } from "./helm-chart-manager-cache.injectable"; import type { Logger } from "@k8slens/logger"; @@ -71,11 +71,11 @@ export class HelmChartManager { const cacheFileStats = await this.dependencies.stat(this.repo.cacheFilePath); const data = yaml.load(cacheFile) as string | number | HelmCacheFile; - if (!data || typeof data !== "object" || typeof data.entries !== "object") { + if (!isObject(data) || !isObject(data.entries)) { throw Object.assign(new TypeError("Helm Cache file does not parse correctly"), { file: this.repo.cacheFilePath, data }); } - const normalized = normalizeHelmCharts(this.repo.name, data.entries); + const normalized = normalizeHelmCharts(this.repo.name, data.entries as RepoHelmChartList); return put( this.dependencies.cache, diff --git a/packages/core/src/main/lens-proxy/get-cluster-for-request.injectable.ts b/packages/core/src/main/lens-proxy/get-cluster-for-request.injectable.ts index 8be8d1d4e4..8bf36d94d8 100644 --- a/packages/core/src/main/lens-proxy/get-cluster-for-request.injectable.ts +++ b/packages/core/src/main/lens-proxy/get-cluster-for-request.injectable.ts @@ -21,14 +21,17 @@ const getClusterForRequestInjectable = getInjectable({ // lens-server is connecting to 127.0.0.1:/ if (req.url && req.headers.host.startsWith("127.0.0.1")) { const clusterId = req.url.split("/")[1]; - const cluster = getClusterById(clusterId); - if (cluster) { - // we need to swap path prefix so that request is proxied to kube api - req.url = req.url.replace(`/${clusterId}`, apiKubePrefix); + if (clusterId) { + const cluster = getClusterById(clusterId); + + if (cluster) { + // we need to swap path prefix so that request is proxied to kube api + req.url = req.url.replace(`/${clusterId}`, apiKubePrefix); + } + + return cluster; } - - return cluster; } const clusterId = getClusterIdFromHost(req.headers.host); diff --git a/packages/core/src/main/lens-proxy/lens-proxy.ts b/packages/core/src/main/lens-proxy/lens-proxy.ts index aadfe90b0b..ea013beff1 100644 --- a/packages/core/src/main/lens-proxy/lens-proxy.ts +++ b/packages/core/src/main/lens-proxy/lens-proxy.ts @@ -200,7 +200,7 @@ export class LensProxy { this.dependencies.logger.error(`[LENS-PROXY]: http proxy errored for cluster: ${String(error)}`, { url: req.url }); - if (target) { + if (target !== undefined) { this.dependencies.logger.debug(`Failed proxy to target: ${JSON.stringify(target, null, 2)}`); if (req.method === "GET" && (!res.statusCode || res.statusCode >= 500)) { @@ -245,12 +245,10 @@ export class LensProxy { const kubeAuthProxyServer = this.dependencies.getKubeAuthProxyServer(cluster); const proxyTarget = await kubeAuthProxyServer.getApiTarget(isLongRunningRequest(req.url)); - if (proxyTarget) { - return this.dependencies.proxy.web(req, res, proxyTarget); - } + this.dependencies.proxy.web(req, res, proxyTarget); + } else { + res.setHeader("Content-Security-Policy", this.dependencies.contentSecurityPolicy); + await this.dependencies.router.route(cluster, req, res); } - - res.setHeader("Content-Security-Policy", this.dependencies.contentSecurityPolicy); - await this.dependencies.router.route(cluster, req, res); } } diff --git a/packages/core/src/main/lens-proxy/proxy-functions/kube-api-upgrade-request.injectable.ts b/packages/core/src/main/lens-proxy/proxy-functions/kube-api-upgrade-request.injectable.ts index 68e6f053ce..891f869189 100644 --- a/packages/core/src/main/lens-proxy/proxy-functions/kube-api-upgrade-request.injectable.ts +++ b/packages/core/src/main/lens-proxy/proxy-functions/kube-api-upgrade-request.injectable.ts @@ -3,7 +3,6 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { chunk } from "lodash"; import type { ConnectionOptions } from "tls"; import { connect } from "tls"; import url from "url"; @@ -13,6 +12,7 @@ import type { LensProxyApiRequest } from "../lens-proxy"; import kubeAuthProxyServerInjectable from "../../cluster/kube-auth-proxy-server.injectable"; import kubeAuthProxyCertificateInjectable from "../../kube-auth-proxy/kube-auth-proxy-certificate.injectable"; import clusterApiUrlInjectable from "../../../features/cluster/connections/main/api-url.injectable"; +import { iter } from "@k8slens/utilities"; const skipRawHeaders = new Set(["Host", "Authorization"]); @@ -35,7 +35,7 @@ const kubeApiUpgradeRequestInjectable = getInjectable({ proxySocket.write(`${req.method} ${pUrl.path ?? ""} HTTP/1.1\r\n`); proxySocket.write(`Host: ${clusterApiUrl.host}\r\n`); - for (const [key, value] of chunk(req.rawHeaders, 2)) { + for (const [key, value] of iter.chunks(req.rawHeaders, 2)) { if (skipRawHeaders.has(key)) { continue; } diff --git a/packages/core/src/main/logger/console-format.ts b/packages/core/src/main/logger/console-format.ts index 4fc7e83f1a..1a8aa7c0e5 100644 --- a/packages/core/src/main/logger/console-format.ts +++ b/packages/core/src/main/logger/console-format.ts @@ -9,6 +9,7 @@ import type { InspectOptions } from "util"; import { inspect } from "util"; import { omit } from "lodash"; import type { Format, TransformableInfo } from "logform"; +import { isObject, isTruthy } from "@k8slens/utilities"; // The following license was copied from https://github.com/duccio/winston-console-format/blob/master/LICENSE // This was modified to support formatting causes @@ -116,9 +117,15 @@ export class ConsoleFormat implements Format { private _cause(source: unknown): string[] { const messages: string[] = []; - if (source instanceof Error && source.cause) { + if (source instanceof Error && isTruthy(source.cause)) { messages.push("Cause:"); - messages.push(...this.getLines(omit(source.cause, "response")).map(l => ` ${l}`)); + + if (isObject(source.cause)) { + messages.push(...this.getLines(omit(source.cause, "response")).map(l => ` ${l}`)); + } else { + messages.push(...this.getLines(source.cause).map(l => ` ${l}`)); + } + messages.push(...this._cause(source.cause)); } diff --git a/packages/core/src/main/prometheus/get-by-kind.injectable.ts b/packages/core/src/main/prometheus/get-by-kind.injectable.ts index 93d7567f6e..28e0313eaa 100644 --- a/packages/core/src/main/prometheus/get-by-kind.injectable.ts +++ b/packages/core/src/main/prometheus/get-by-kind.injectable.ts @@ -7,22 +7,14 @@ import { matches } from "lodash/fp"; import type { PrometheusProvider } from "./provider"; import prometheusProvidersInjectable from "./providers.injectable"; -export type GetPrometheusProviderByKind = (kind: string) => PrometheusProvider; +export type GetPrometheusProviderByKind = (kind: string) => PrometheusProvider | undefined; const getPrometheusProviderByKindInjectable = getInjectable({ id: "get-prometheus-provider-by-kind", instantiate: (di): GetPrometheusProviderByKind => { const providers = di.inject(prometheusProvidersInjectable); - return (kind) => { - const provider = providers.get().find(matches({ kind })); - - if (!provider) { - throw new Error(`Provider of kind "${kind}" does not exist`); - } - - return provider; - }; + return (kind) => providers.get().find(matches({ kind })); }, }); diff --git a/packages/core/src/main/prometheus/helm-provider.injectable.ts b/packages/core/src/main/prometheus/helm-provider.injectable.ts index 953bd68277..05b5ef337d 100644 --- a/packages/core/src/main/prometheus/helm-provider.injectable.ts +++ b/packages/core/src/main/prometheus/helm-provider.injectable.ts @@ -6,11 +6,14 @@ import type { PrometheusProvider } from "./provider"; import { createPrometheusProvider, bytesSent, findFirstNamespacedService, prometheusProviderInjectionToken } from "./provider"; import { getInjectable } from "@ogre-tools/injectable"; +import assert from "assert"; export const getHelmLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string }): PrometheusProvider["getQuery"] => ( (opts, queryName) => { switch(opts.category) { case "cluster": + assert(opts.nodes, 'Missing "nodes" option when "category" option is "cluster"'); + switch (queryName) { case "memoryUsage": return `sum(node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) by (component)`.replace(/_bytes/g, `_bytes{node=~"${opts.nodes}"}`); @@ -69,6 +72,10 @@ export const getHelmLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string }): } break; case "pods": + assert(opts.pods, 'Missing "pods" option when "category" option is "pods"'); + assert(opts.namespace, 'Missing "namespace" option when "category" option is "pods"'); + assert(opts.selector, 'Missing "selector" option when "category" option is "pods"'); + switch (queryName) { case "cpuUsage": return `sum(rate(container_cpu_usage_seconds_total{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}[${rateAccuracy}])) by (${opts.selector})`; @@ -95,6 +102,9 @@ export const getHelmLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string }): } break; case "pvc": + assert(opts.pvc, 'Missing "pvc" option when "category" option is "pvc"'); + assert(opts.namespace, 'Missing "namespace" option when "category" option is "pvc"'); + switch (queryName) { case "diskUsage": return `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}",namespace="${opts.namespace}"}) by (persistentvolumeclaim, namespace)`; @@ -103,6 +113,9 @@ export const getHelmLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string }): } break; case "ingress": + assert(opts.ingress, 'Missing "ingress" option when "category" option is "ingress"'); + assert(opts.namespace, 'Missing "namespace" option when "category" option is "ingress"'); + switch (queryName) { case "bytesSentSuccess": return bytesSent({ @@ -126,7 +139,7 @@ export const getHelmLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string }): break; } - throw new Error(`Unknown queryName="${queryName}" for category="${opts.category}"`); + throw new Error(`Unknown queryName="${queryName}" for category="${String(opts.category)}"`); } ); diff --git a/packages/core/src/main/prometheus/lens-provider.injectable.ts b/packages/core/src/main/prometheus/lens-provider.injectable.ts index c523c72582..0552cb78f5 100644 --- a/packages/core/src/main/prometheus/lens-provider.injectable.ts +++ b/packages/core/src/main/prometheus/lens-provider.injectable.ts @@ -6,11 +6,14 @@ import { bytesSent, prometheusProviderInjectionToken, findNamespacedService, createPrometheusProvider } from "./provider"; import type { PrometheusProvider } from "./provider"; import { getInjectable } from "@ogre-tools/injectable"; +import assert from "assert"; export const getLensLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string }): PrometheusProvider["getQuery"] => ( (opts, queryName) => { switch(opts.category) { case "cluster": + assert(opts.nodes, 'Missing "nodes" option when "category" option is "cluster"'); + switch (queryName) { case "memoryUsage": return `sum(node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) by (kubernetes_name)`.replace(/_bytes/g, `_bytes{kubernetes_node=~"${opts.nodes}"}`); @@ -69,6 +72,10 @@ export const getLensLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string }): } break; case "pods": + assert(opts.pods, 'Missing "pods" option when "category" option is "pods"'); + assert(opts.namespace, 'Missing "namespace" option when "category" option is "pods"'); + assert(opts.selector, 'Missing "selector" option when "category" option is "pods"'); + switch (queryName) { case "cpuUsage": return `sum(rate(container_cpu_usage_seconds_total{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}[${rateAccuracy}])) by (${opts.selector})`; @@ -95,6 +102,9 @@ export const getLensLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string }): } break; case "pvc": + assert(opts.pvc, 'Missing "pvc" option when "category" option is "pvc"'); + assert(opts.namespace, 'Missing "namespace" option when "category" option is "pvc"'); + switch (queryName) { case "diskUsage": return `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}",namespace="${opts.namespace}"}) by (persistentvolumeclaim, namespace)`; @@ -103,6 +113,9 @@ export const getLensLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string }): } break; case "ingress": + assert(opts.ingress, 'Missing "ingress" option when "category" option is "ingress"'); + assert(opts.namespace, 'Missing "namespace" option when "category" option is "ingress"'); + switch (queryName) { case "bytesSentSuccess": return bytesSent({ @@ -126,7 +139,7 @@ export const getLensLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string }): break; } - throw new Error(`Unknown queryName="${queryName}" for category="${opts.category}"`); + throw new Error(`Unknown queryName="${queryName}" for category="${String(opts.category)}"`); } ); diff --git a/packages/core/src/main/prometheus/operator-provider.injectable.ts.ts b/packages/core/src/main/prometheus/operator-provider.injectable.ts.ts index 5215f2dff2..6b3a3a4195 100644 --- a/packages/core/src/main/prometheus/operator-provider.injectable.ts.ts +++ b/packages/core/src/main/prometheus/operator-provider.injectable.ts.ts @@ -6,11 +6,14 @@ import type { PrometheusProvider } from "./provider"; import { bytesSent, createPrometheusProvider, findFirstNamespacedService, prometheusProviderInjectionToken } from "./provider"; import { getInjectable } from "@ogre-tools/injectable"; +import assert from "assert"; export const getOperatorLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string }): PrometheusProvider["getQuery"] => ( (opts, queryName) => { switch(opts.category) { case "cluster": + assert(opts.nodes, 'Missing "nodes" option when "category" option is "cluster"'); + switch (queryName) { case "memoryUsage": return `sum(node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes))`.replace(/_bytes/g, `_bytes * on (pod,namespace) group_left(node) kube_pod_info{node=~"${opts.nodes}"}`); @@ -69,6 +72,10 @@ export const getOperatorLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string } break; case "pods": + assert(opts.pods, 'Missing "pods" option when "category" option is "pods"'); + assert(opts.namespace, 'Missing "namespace" option when "category" option is "pods"'); + assert(opts.selector, 'Missing "selector" option when "category" option is "pods"'); + switch (queryName) { case "cpuUsage": return `sum(rate(container_cpu_usage_seconds_total{pod=~"${opts.pods}", namespace="${opts.namespace}"}[${rateAccuracy}])) by (${opts.selector})`; @@ -95,6 +102,9 @@ export const getOperatorLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string } break; case "pvc": + assert(opts.pvc, 'Missing "pvc" option when "category" option is "pvc"'); + assert(opts.namespace, 'Missing "namespace" option when "category" option is "pvc"'); + switch (queryName) { case "diskUsage": return `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}", namespace="${opts.namespace}"}) by (persistentvolumeclaim, namespace)`; @@ -103,6 +113,9 @@ export const getOperatorLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string } break; case "ingress": + assert(opts.ingress, 'Missing "ingress" option when "category" option is "ingress"'); + assert(opts.namespace, 'Missing "namespace" option when "category" option is "ingress"'); + switch (queryName) { case "bytesSentSuccess": return bytesSent({ @@ -126,7 +139,7 @@ export const getOperatorLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string break; } - throw new Error(`Unknown queryName="${queryName}" for category="${opts.category}"`); + throw new Error(`Unknown queryName="${queryName}" for category="${String(opts.category)}"`); } ); diff --git a/packages/core/src/main/prometheus/stacklight-provider.injectable.ts b/packages/core/src/main/prometheus/stacklight-provider.injectable.ts index ca7a946466..f4fdea0756 100644 --- a/packages/core/src/main/prometheus/stacklight-provider.injectable.ts +++ b/packages/core/src/main/prometheus/stacklight-provider.injectable.ts @@ -6,11 +6,14 @@ import type { PrometheusProvider } from "./provider"; import { bytesSent, createPrometheusProvider, findFirstNamespacedService, prometheusProviderInjectionToken } from "./provider"; import { getInjectable } from "@ogre-tools/injectable"; +import assert from "assert"; export const getStacklightLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string }): PrometheusProvider["getQuery"] => ( (opts, queryName) => { switch(opts.category) { case "cluster": + assert(opts.nodes, 'Missing "nodes" option when "category" option is "cluster"'); + switch (queryName) { case "memoryUsage": return `sum(node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) by (kubernetes_name)`.replace(/_bytes/g, `_bytes{node=~"${opts.nodes}"}`); @@ -69,6 +72,10 @@ export const getStacklightLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: stri } break; case "pods": + assert(opts.pods, 'Missing "pods" option when "category" option is "pods"'); + assert(opts.namespace, 'Missing "namespace" option when "category" option is "pods"'); + assert(opts.selector, 'Missing "selector" option when "category" option is "pods"'); + switch (queryName) { case "cpuUsage": return `sum(rate(container_cpu_usage_seconds_total{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}[${rateAccuracy}])) by (${opts.selector})`; @@ -95,6 +102,9 @@ export const getStacklightLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: stri } break; case "pvc": + assert(opts.pvc, 'Missing "pvc" option when "category" option is "pvc"'); + assert(opts.namespace, 'Missing "namespace" option when "category" option is "pvc"'); + switch (queryName) { case "diskUsage": return `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}",namespace="${opts.namespace}"}) by (persistentvolumeclaim, namespace)`; @@ -103,6 +113,9 @@ export const getStacklightLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: stri } break; case "ingress": + assert(opts.ingress, 'Missing "ingress" option when "category" option is "ingress"'); + assert(opts.namespace, 'Missing "namespace" option when "category" option is "ingress"'); + switch (queryName) { case "bytesSentSuccess": return bytesSent({ @@ -126,7 +139,7 @@ export const getStacklightLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: stri break; } - throw new Error(`Unknown queryName="${queryName}" for category="${opts.category}"`); + throw new Error(`Unknown queryName="${queryName}" for category="${String(opts.category)}"`); } ); diff --git a/packages/core/src/main/protocol-handler/lens-protocol-router-main/lens-protocol-router-main.ts b/packages/core/src/main/protocol-handler/lens-protocol-router-main/lens-protocol-router-main.ts index aa9b087d98..b3fef45ded 100644 --- a/packages/core/src/main/protocol-handler/lens-protocol-router-main/lens-protocol-router-main.ts +++ b/packages/core/src/main/protocol-handler/lens-protocol-router-main/lens-protocol-router-main.ts @@ -9,7 +9,7 @@ import type { LensExtension } from "../../../extensions/lens-extension"; import { observable, when } from "mobx"; import type { LensProtocolRouterDependencies, RouteAttempt } from "../../../common/protocol-handler"; import { ProtocolHandlerInvalid } from "../../../common/protocol-handler"; -import { disposer, noop } from "@k8slens/utilities"; +import { disposer, isTruthy, noop } from "@k8slens/utilities"; import type { BroadcastMessage } from "../../../common/ipc/broadcast-message.injectable"; export interface FallbackHandler { @@ -79,7 +79,7 @@ export class LensProtocolRouterMain extends proto.LensProtocolRouter { await this._routeToExtension(url); } } catch (error) { - void this.dependencies.broadcastMessage(ProtocolHandlerInvalid, error ? String(error) : "unknown error", rawUrl); + void this.dependencies.broadcastMessage(ProtocolHandlerInvalid, isTruthy(error) ? String(error) : "unknown error", rawUrl); if (error instanceof proto.RoutingError) { this.dependencies.logger.error(`${proto.LensProtocolRouter.LoggingPrefix}: ${String(error)}`, { url: error.url }); diff --git a/packages/core/src/main/router/create-handler-for-route.injectable.ts b/packages/core/src/main/router/create-handler-for-route.injectable.ts index a277dacc99..75d279760d 100644 --- a/packages/core/src/main/router/create-handler-for-route.injectable.ts +++ b/packages/core/src/main/router/create-handler-for-route.injectable.ts @@ -5,7 +5,7 @@ import { getInjectable } from "@ogre-tools/injectable"; import type { ServerResponse } from "http"; import { loggerInjectionToken } from "@k8slens/logger"; -import { object } from "@k8slens/utilities"; +import { isDefined, object } from "@k8slens/utilities"; import type { LensApiRequest, Route } from "./route"; import { contentTypes } from "./router-content-types"; @@ -34,7 +34,7 @@ const writeServerResponseFor = (serverResponse: ServerResponse) => ({ if (content instanceof Buffer) { serverResponse.write(content); serverResponse.end(); - } else if (content) { + } else if (isDefined(content)) { serverResponse.end(content); } else { serverResponse.end(); @@ -67,7 +67,7 @@ const createHandlerForRouteInjectable = getInjectable({ } catch(error) { const mappedResult = contentTypes.txt.resultMapper({ statusCode: 500, - error: error ? String(error) : "unknown error", + error: isDefined(error) ? String(error) : "unknown error", }); logger.error(`[ROUTER]: route ${route.path}, called with ${request.path}, threw an error`, error); diff --git a/packages/core/src/main/router/route.ts b/packages/core/src/main/router/route.ts index 7849917eec..cbe66a26f5 100644 --- a/packages/core/src/main/router/route.ts +++ b/packages/core/src/main/router/route.ts @@ -54,7 +54,7 @@ export interface ClusterLensApiRequest extends LensApiReque export interface LensApiResult { statusCode?: number; response?: Response; - error?: unknown; + error?: string | Error; contentType?: LensApiResultContentType; headers?: Partial>; proxy?: httpProxy; diff --git a/packages/core/src/main/router/router-content-types.ts b/packages/core/src/main/router/router-content-types.ts index 1bc00380b1..650693ea7f 100644 --- a/packages/core/src/main/router/router-content-types.ts +++ b/packages/core/src/main/router/router-content-types.ts @@ -2,6 +2,7 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ +import { isDefined } from "@k8slens/utilities"; import type { LensApiResult } from "./route"; export interface LensApiResultContentType { @@ -14,19 +15,15 @@ export interface LensApiResultContentType { const resultMapperFor = (contentType: string): LensApiResultContentType["resultMapper"] => - ({ response, error, statusCode= error ? 400 : 200, headers = {}}) => ({ + ({ response, error, statusCode = isDefined(error) ? 200 : 400, headers = {}}) => ({ statusCode, - content: error || response, + content: isDefined(error) ? error : response, headers: { ...headers, "Content-Type": contentType }, }); export type SupportedFileExtension = "json" | "txt" | "html" | "css" | "gif" | "jpg" | "png" | "svg" | "js" | "woff2" | "ttf"; -export interface ContentTypes extends Record { - [key: string]: LensApiResultContentType | undefined; -} - -export const contentTypes: ContentTypes = { +export const contentTypes: Record = { json: { resultMapper: (result: LensApiResult) => { const resultMapper = resultMapperFor("application/json"); diff --git a/packages/core/src/main/routes/files/production.injectable.ts b/packages/core/src/main/routes/files/production.injectable.ts index 408f3e98ea..9512f3aa02 100644 --- a/packages/core/src/main/routes/files/production.injectable.ts +++ b/packages/core/src/main/routes/files/production.injectable.ts @@ -10,6 +10,7 @@ import type { LensApiRequest } from "../../router/route"; import path from "path"; import { contentTypes } from "../../router/router-content-types"; import { prefixedLoggerInjectable } from "@k8slens/logger"; +import { maybeGet } from "@k8slens/utilities"; const prodStaticFileRouteHandlerInjectable = getInjectable({ id: "prod-static-file-route-handler", @@ -33,7 +34,7 @@ const prodStaticFileRouteHandlerInjectable = getInjectable({ } const fileExtension = path.extname(assetFilePath).slice(1); - const contentType = contentTypes[fileExtension] || contentTypes.txt; + const contentType = maybeGet(contentTypes, fileExtension) || contentTypes.txt; try { return { response: await readFileBuffer(assetFilePath), contentType }; diff --git a/packages/core/src/main/shell-session/node-shell-session/node-shell-session.ts b/packages/core/src/main/shell-session/node-shell-session/node-shell-session.ts index 506084e5ae..8d7aa06a30 100644 --- a/packages/core/src/main/shell-session/node-shell-session/node-shell-session.ts +++ b/packages/core/src/main/shell-session/node-shell-session/node-shell-session.ts @@ -16,6 +16,7 @@ import type { CreateKubeApi } from "../../../common/k8s-api/create-kube-api.inje import { initialNodeShellImage } from "../../../common/cluster-types"; import type { LoadProxyKubeconfig } from "../../cluster/load-proxy-kubeconfig.injectable"; import type { Pod } from "@k8slens/kube-object"; +import { isDefined } from "@k8slens/utilities"; export interface NodeShellSessionArgs extends ShellSessionArgs { nodeName: string; @@ -67,7 +68,7 @@ export class NodeShellSession extends ShellSession { this.send({ type: TerminalChannels.STDOUT, - data: `Error occurred: ${get(error, "response.body.message", error ? String(error) : "unknown error")}`, + data: `Error occurred: ${get(error, "response.body.message", isDefined(error) ? String(error) : "unknown error")}`, }); throw new ShellOpenError( diff --git a/packages/core/src/main/shell-session/shell-session.ts b/packages/core/src/main/shell-session/shell-session.ts index 4219cbaf7e..cca42b893c 100644 --- a/packages/core/src/main/shell-session/shell-session.ts +++ b/packages/core/src/main/shell-session/shell-session.ts @@ -271,7 +271,7 @@ export abstract class ShellSession { } }) .once("close", code => { - this.dependencies.logger.info(`[SHELL-SESSION]: websocket for ${this.terminalId} closed with code=${WebSocketCloseEvent[code]}(${code})`, { cluster: this.cluster.getMeta() }); + this.dependencies.logger.info(`[SHELL-SESSION]: websocket for ${this.terminalId} closed with code=${String(WebSocketCloseEvent[code])}(${code})`, { cluster: this.cluster.getMeta() }); const stopShellSession = this.running && ( diff --git a/packages/core/src/main/tray/tray-menu-item/tray-menu-item-registrator.injectable.ts b/packages/core/src/main/tray/tray-menu-item/tray-menu-item-registrator.injectable.ts index 9b161e4d75..362bd4b18c 100644 --- a/packages/core/src/main/tray/tray-menu-item/tray-menu-item-registrator.injectable.ts +++ b/packages/core/src/main/tray/tray-menu-item/tray-menu-item-registrator.injectable.ts @@ -55,15 +55,11 @@ const toItemInjectablesFor = (extension: LensMainExtension, withErrorLoggingFor: separator: registration.type === "separator", label: computed(() => { - if (!registration.label) { - return ""; - } - if (isString(registration.label)) { return registration.label; } - return registration.label.get(); + return registration.label?.get() ?? ""; }), tooltip: registration.toolTip, diff --git a/packages/core/src/renderer/api/catalog/entity/registry.ts b/packages/core/src/renderer/api/catalog/entity/registry.ts index aaf503938c..c44fb58a38 100644 --- a/packages/core/src/renderer/api/catalog/entity/registry.ts +++ b/packages/core/src/renderer/api/catalog/entity/registry.ts @@ -7,7 +7,7 @@ import { computed, observable, makeObservable, action, runInAction } from "mobx" import { ipcRendererOn } from "../../../../common/ipc"; import type { CatalogCategory, CatalogEntity, CatalogEntityData, CatalogCategoryRegistry, CatalogEntityKindData } from "../../../../common/catalog"; import type { Disposer } from "@k8slens/utilities"; -import { iter } from "@k8slens/utilities"; +import { isDefined, isString, iter } from "@k8slens/utilities"; import { once } from "lodash"; import { CatalogRunEvent } from "../../../../common/catalog/catalog-run-event"; import { ipcRenderer } from "electron"; @@ -60,7 +60,7 @@ export class CatalogEntityRegistry { // If the entity was not found but there are rawEntities to be processed, // try to process them and return the entity. // This might happen if an extension registered a new Catalog category. - if (this.activeEntityId && !entity && this.rawEntities.length > 0) { + if (this.activeEntityId.get() && !entity && this.rawEntities.length > 0) { this.processRawEntities(); return this.getActiveEntityById(); @@ -70,8 +70,8 @@ export class CatalogEntityRegistry { } set activeEntity(raw: CatalogEntity | string | undefined) { - if (raw) { - const id = typeof raw === "string" + if (isDefined(raw)) { + const id = isString(raw) ? raw : raw.getId(); diff --git a/packages/core/src/renderer/components/avatar/avatar.tsx b/packages/core/src/renderer/components/avatar/avatar.tsx index 8a815c75bd..5f55c024d2 100644 --- a/packages/core/src/renderer/components/avatar/avatar.tsx +++ b/packages/core/src/renderer/components/avatar/avatar.tsx @@ -9,7 +9,7 @@ import type { ImgHTMLAttributes, MouseEventHandler } from "react"; import React from "react"; import randomColor from "randomcolor"; import type { StrictReactNode } from "@k8slens/utilities"; -import { cssNames } from "@k8slens/utilities"; +import { isTruthy, cssNames } from "@k8slens/utilities"; import { computeDefaultShortName } from "../../../common/catalog/helpers"; export interface AvatarProps { @@ -44,11 +44,13 @@ export const Avatar = ({ "data-testid": dataTestId, }: AvatarProps) => (
- {src - ? ( - {title} - ) - : children || computeDefaultShortName(title)} + { + src + ? ( + {title} + ) + : isTruthy(children) + ? children + : computeDefaultShortName(title) + }
); diff --git a/packages/core/src/renderer/components/badge/badge.tsx b/packages/core/src/renderer/components/badge/badge.tsx index 19266e6af1..dd4cbd322e 100644 --- a/packages/core/src/renderer/components/badge/badge.tsx +++ b/packages/core/src/renderer/components/badge/badge.tsx @@ -63,15 +63,17 @@ export const Badge = withTooltip(observer(({ return (
diff --git a/packages/core/src/renderer/components/catalog/catalog-add-button.tsx b/packages/core/src/renderer/components/catalog/catalog-add-button.tsx index 1ef38c4f10..a1f333c57a 100644 --- a/packages/core/src/renderer/components/catalog/catalog-add-button.tsx +++ b/packages/core/src/renderer/components/catalog/catalog-add-button.tsx @@ -11,9 +11,7 @@ import { observer } from "mobx-react"; import { observable, action } from "mobx"; import type { CatalogCategory, CatalogEntityAddMenu } from "../../api/catalog-entity"; import { EventEmitter } from "events"; -import type { CatalogCategoryRegistry } from "../../../common/catalog"; import { withInjectables } from "@ogre-tools/injectable-react"; -import catalogCategoryRegistryInjectable from "../../../common/catalog/category-registry.injectable"; import type { Navigate } from "../../navigation/navigate.injectable"; import navigateInjectable from "../../navigation/navigate.injectable"; @@ -24,7 +22,6 @@ export interface CatalogAddButtonProps { type CategoryId = string; interface Dependencies { - catalogCategoryRegistry: CatalogCategoryRegistry; navigate: Navigate; } @@ -43,19 +40,9 @@ class NonInjectedCatalogAddButton extends React.Component { this.menuItems.clear(); - - if (this.props.category) { - this.updateCategoryItems(this.props.category); - } else { - // Show menu items from all categories - this.categories.forEach(this.updateCategoryItems); - } + this.updateCategoryItems(this.props.category); }); updateCategoryItems = action((category: CatalogCategory) => { @@ -84,16 +71,13 @@ class NonInjectedCatalogAddButton extends React.Component { const defaultAction = this.items.find(item => item.defaultAction)?.onClick; - const clickAction = defaultAction || (this.items.length === 1 ? this.items[0].onClick : null); + const clickAction = defaultAction ?? this.items[0]?.onClick; void clickAction?.(); }; get items() { - const { category } = this.props; - - return category ? this.getCategoryFilteredItems(category) : - this.categories.map(this.getCategoryFilteredItems).flat(); + return this.getCategoryFilteredItems(this.props.category); } render() { @@ -136,7 +120,6 @@ class NonInjectedCatalogAddButton extends React.Component(NonInjectedCatalogAddButton, { getProps: (di, props) => ({ ...props, - catalogCategoryRegistry: di.inject(catalogCategoryRegistryInjectable), navigate: di.inject(navigateInjectable), }), }); diff --git a/packages/core/src/renderer/components/catalog/catalog-category-label.tsx b/packages/core/src/renderer/components/catalog/catalog-category-label.tsx index 170d8e92b6..536925bfc9 100644 --- a/packages/core/src/renderer/components/catalog/catalog-category-label.tsx +++ b/packages/core/src/renderer/components/catalog/catalog-category-label.tsx @@ -2,6 +2,7 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ +import { isTruthy } from "@k8slens/utilities"; import React from "react"; import type { CatalogCategory } from "../../../common/catalog/catalog-entity"; @@ -18,7 +19,7 @@ export const CatalogCategoryLabel = ({ category }: CatalogCategoryLabelProps) => return (
{category.metadata.name}
- {badge ? (
{badge}
) : null} + {isTruthy(badge) ? (
{badge}
) : null}
); }; diff --git a/packages/core/src/renderer/components/catalog/catalog-entity-drawer-menu.tsx b/packages/core/src/renderer/components/catalog/catalog-entity-drawer-menu.tsx index 756a0803d2..3e72ea577d 100644 --- a/packages/core/src/renderer/components/catalog/catalog-entity-drawer-menu.tsx +++ b/packages/core/src/renderer/components/catalog/catalog-entity-drawer-menu.tsx @@ -43,10 +43,6 @@ class NonInjectedCatalogEntityDrawerMenu extends React. } getMenuItems(entity: T): React.ReactChild[] { - if (!entity) { - return []; - } - const items = this.menuItems .map(this.props.normalizeMenuItem) .filter(hasDefiniteField("icon")) diff --git a/packages/core/src/renderer/components/catalog/entity-details/internal/kubernetes-cluster-details.injectable.tsx b/packages/core/src/renderer/components/catalog/entity-details/internal/kubernetes-cluster-details.injectable.tsx index 89318bac15..fb6f02c9c9 100644 --- a/packages/core/src/renderer/components/catalog/entity-details/internal/kubernetes-cluster-details.injectable.tsx +++ b/packages/core/src/renderer/components/catalog/entity-details/internal/kubernetes-cluster-details.injectable.tsx @@ -15,22 +15,26 @@ const kubernetesClusterDetailsItemInjectable = getInjectable({ kind: KubernetesCluster.kind, orderNumber: 40, components: { - Details: ({ entity }) => ( - <> - Kubernetes Information -
- - {entity.metadata.distro || "unknown"} - - - {entity.metadata.kubeVersion || "unknown"} - -
- - ), + Details: ({ entity }) => { + const kube = entity as KubernetesCluster; + + return ( + <> + Kubernetes Information +
+ + {kube.metadata.distro || "unknown"} + + + {kube.metadata.kubeVersion || "unknown"} + +
+ + ); + }, }, }), injectionToken: catalogEntityDetailItemInjectionToken, diff --git a/packages/core/src/renderer/components/chart/bar-chart.tsx b/packages/core/src/renderer/components/chart/bar-chart.tsx index 1505dc37f0..57e7249451 100644 --- a/packages/core/src/renderer/components/chart/bar-chart.tsx +++ b/packages/core/src/renderer/components/chart/bar-chart.tsx @@ -137,7 +137,7 @@ const NonInjectedBarChart = observer(({ typeof datasetIndex === "number" ? { borderColor: "darkgray", - backgroundColor: datasets[datasetIndex].borderColor as string, + backgroundColor: datasets[datasetIndex]?.borderColor as string, } : { borderColor: "darkgray", @@ -181,7 +181,7 @@ const tooltipCallbackWith = (precision: number): ChartTooltipCallback["label"] = return ""; } - const { label, data } = datasets[datasetIndex]; + const { label, data } = datasets[datasetIndex] ?? {}; if (!label || !data) { return ""; diff --git a/packages/core/src/renderer/components/chart/options.ts b/packages/core/src/renderer/components/chart/options.ts index db38e4d679..d122594ffd 100644 --- a/packages/core/src/renderer/components/chart/options.ts +++ b/packages/core/src/renderer/components/chart/options.ts @@ -36,7 +36,7 @@ const memoryLikeOptions: ChartOptions = { return ""; } - const { label = "", data } = datasets[datasetIndex]; + const { label = "", data } = datasets[datasetIndex] ?? {}; if (!data) { return label; @@ -78,7 +78,7 @@ export const metricTabOptions: Record = { return ""; } - const { label = "", data } = datasets[datasetIndex]; + const { label = "", data } = datasets[datasetIndex] ?? {}; if (!data) { return label; @@ -106,7 +106,7 @@ export const metricTabOptions: Record = { return ""; } - const { label = "", data } = datasets[datasetIndex]; + const { label = "", data } = datasets[datasetIndex] ?? {}; if (!data) { return label; @@ -134,7 +134,7 @@ export const metricTabOptions: Record = { return ""; } - const { label = "", data } = datasets[datasetIndex]; + const { label = "", data } = datasets[datasetIndex] ?? {}; if (!data) { return label; diff --git a/packages/core/src/renderer/components/chart/pie-chart.tsx b/packages/core/src/renderer/components/chart/pie-chart.tsx index c2d3f355a7..8e0f7ddeb4 100644 --- a/packages/core/src/renderer/components/chart/pie-chart.tsx +++ b/packages/core/src/renderer/components/chart/pie-chart.tsx @@ -80,7 +80,7 @@ const NonInjectedPieChart = observer(({ return false; } - const { data = [] } = datasets[datasetIndex]; + const { data = [] } = datasets[datasetIndex] ?? {}; if (datasets.length === 1) return true; diff --git a/packages/core/src/renderer/components/checkbox/checkbox.tsx b/packages/core/src/renderer/components/checkbox/checkbox.tsx index d8f79c7bf1..0277a6a3a4 100644 --- a/packages/core/src/renderer/components/checkbox/checkbox.tsx +++ b/packages/core/src/renderer/components/checkbox/checkbox.tsx @@ -6,7 +6,7 @@ import "./checkbox.scss"; import React from "react"; import type { StrictReactNode } from "@k8slens/utilities"; -import { cssNames, noop } from "@k8slens/utilities"; +import { isTruthy, cssNames, noop } from "@k8slens/utilities"; export interface CheckboxProps { className?: string; @@ -35,7 +35,7 @@ export function Checkbox({ label, inline, className, value, children, onChange = onChange={event => onChange(event.target.checked, event)} /> - {label ? {label} : null} + {isTruthy(label) ? {label} : null} {children} ); diff --git a/packages/core/src/renderer/components/cluster-manager/cluster-manager.tsx b/packages/core/src/renderer/components/cluster-manager/cluster-manager.tsx index ef1d9fe0cb..8abb9b0019 100644 --- a/packages/core/src/renderer/components/cluster-manager/cluster-manager.tsx +++ b/packages/core/src/renderer/components/cluster-manager/cluster-manager.tsx @@ -16,7 +16,7 @@ import { TopBar } from "../layout/top-bar/top-bar"; import type { IComputedValue } from "mobx"; import currentRouteComponentInjectable from "../../routes/current-route-component.injectable"; import welcomeRouteInjectable from "../../../common/front-end-routing/routes/welcome/welcome-route.injectable"; -import { buildURL } from "@k8slens/utilities"; +import { buildURL, isDefined } from "@k8slens/utilities"; import type { WatchForGeneralEntityNavigation } from "../../api/helpers/watch-for-general-entity-navigation.injectable"; import watchForGeneralEntityNavigationInjectable from "../../api/helpers/watch-for-general-entity-navigation.injectable"; import currentPathInjectable from "../../routes/current-path.injectable"; @@ -39,7 +39,7 @@ class NonInjectedClusterManager extends React.Component { renderMainComponent() { const Component = this.props.currentRouteComponent.get(); - if (Component) { + if (isDefined(Component)) { return ; } diff --git a/packages/core/src/renderer/components/cluster-settings/prometheus-setting.tsx b/packages/core/src/renderer/components/cluster-settings/prometheus-setting.tsx index 98a3cf929a..c513b5cbe1 100644 --- a/packages/core/src/renderer/components/cluster-settings/prometheus-setting.tsx +++ b/packages/core/src/renderer/components/cluster-settings/prometheus-setting.tsx @@ -59,7 +59,7 @@ class NonInjectedClusterPrometheusSetting extends React.Component { - if (!this.selectedOption || !this.path) { + if (!this.path) { return undefined; } const parsed = this.path.split(/\/|:/, 3); diff --git a/packages/core/src/renderer/components/cluster/cluster-no-metrics.tsx b/packages/core/src/renderer/components/cluster/cluster-no-metrics.tsx index 4aa03e8c50..d6dc3cae3f 100644 --- a/packages/core/src/renderer/components/cluster/cluster-no-metrics.tsx +++ b/packages/core/src/renderer/components/cluster/cluster-no-metrics.tsx @@ -14,7 +14,7 @@ import navigateToEntitySettingsInjectable from "../../../common/front-end-routin import hostedClusterInjectable from "../../cluster-frame-context/hosted-cluster.injectable"; export interface ClusterNoMetricsProps { - className: string; + className?: string; } interface Dependencies { diff --git a/packages/core/src/renderer/components/command-palette/registered-commands/internal-commands.injectable.tsx b/packages/core/src/renderer/components/command-palette/registered-commands/internal-commands.injectable.tsx index 62c37477b4..aac0e06b23 100644 --- a/packages/core/src/renderer/components/command-palette/registered-commands/internal-commands.injectable.tsx +++ b/packages/core/src/renderer/components/command-palette/registered-commands/internal-commands.injectable.tsx @@ -212,9 +212,7 @@ function getInternalCommands(dependencies: Dependencies): CommandRegistration[] id: "entity.viewSettings", title: ({ entity }) => `${entity.kind}/${entity.getName()}: View Settings`, action: ({ entity }) => dependencies.navigateToEntitySettings(entity.getId()), - isActive: ({ entity }) => ( - entity && dependencies.hasCatalogEntitySettingItems(entity) - ), + isActive: ({ entity }) => dependencies.hasCatalogEntitySettingItems(entity), }, { id: "cluster.openTerminal", diff --git a/packages/core/src/renderer/components/config-horizontal-pod-autoscalers/details.tsx b/packages/core/src/renderer/components/config-horizontal-pod-autoscalers/details.tsx index 4333441078..1e33e154fd 100644 --- a/packages/core/src/renderer/components/config-horizontal-pod-autoscalers/details.tsx +++ b/packages/core/src/renderer/components/config-horizontal-pod-autoscalers/details.tsx @@ -54,7 +54,7 @@ class NonInjectedHorizontalPodAutoscalerDetails extends React.Component { + const renderName = (metric: HorizontalPodAutoscalerMetricSpec | undefined) => { const metricName = getMetricName(metric); switch (metric?.type) { @@ -95,7 +95,7 @@ class NonInjectedHorizontalPodAutoscalerDetails extends React.Component ( - {renderName(hpa.getMetrics()[index])} + {renderName(hpa.getMetrics()?.[index])} {metrics} )) @@ -107,10 +107,6 @@ class NonInjectedHorizontalPodAutoscalerDetails extends React.Component { const configMap = this.props.object as ConfigMap; - if (configMap) { - this.data.replace(configMap.data); // refresh - } + this.data.replace(configMap.data); // refresh }), ]); } @@ -79,10 +77,6 @@ class NonInjectedConfigMapDetails extends React.Component = ({ webhook }) => { {" "} {rule.operations.join(", ")}
- {rule.resources && ( -
- Resources: - {" "} - {rule.resources.join(", ")} -
- )} +
+ Resources: + {" "} + {rule.resources?.join(", ")} +
{rule.scope && (
Scope: diff --git a/packages/core/src/renderer/components/config-resource-quotas/resource-quota-details.tsx b/packages/core/src/renderer/components/config-resource-quotas/resource-quota-details.tsx index 14bed797bf..e939a00f66 100644 --- a/packages/core/src/renderer/components/config-resource-quotas/resource-quota-details.tsx +++ b/packages/core/src/renderer/components/config-resource-quotas/resource-quota-details.tsx @@ -83,10 +83,6 @@ class NonInjectedResourceQuotaDetails extends React.Component { const secret = this.props.object as Secret; - if (secret) { - this.data = secret.data; - this.revealSecret.clear(); - } + this.data = secret.data; + this.revealSecret.clear(); }), ]); } @@ -145,10 +143,6 @@ class NonInjectedSecretDetails extends React.Component - { - /* according to the spec there can be 0 or 1 recommenders, only */ - recommenders?.length ? recommenders[0].name : "default" - } + {recommenders?.[0]?.name ?? "default"} {vpa.status && this.renderStatus(vpa, vpa.status)} diff --git a/packages/core/src/renderer/components/custom-resource-definitions/details.tsx b/packages/core/src/renderer/components/custom-resource-definitions/details.tsx index d27c04b61a..ad22bb4594 100644 --- a/packages/core/src/renderer/components/custom-resource-definitions/details.tsx +++ b/packages/core/src/renderer/components/custom-resource-definitions/details.tsx @@ -28,10 +28,6 @@ class NonInjectedCustomResourceDefinitionDetails extends React.Component { findTabIdFromData(inspector: (val: T) => unknown): TabId | undefined { for (const [tabId, data] of this.data) { - if (inspector(data)) { + if (isTruthy(inspector(data))) { return tabId; } } diff --git a/packages/core/src/renderer/components/dock/dock-tab.tsx b/packages/core/src/renderer/components/dock/dock-tab.tsx index f5c40149a0..1683f3f5bd 100644 --- a/packages/core/src/renderer/components/dock/dock-tab.tsx +++ b/packages/core/src/renderer/components/dock/dock-tab.tsx @@ -78,10 +78,6 @@ class NonInjectedDockTab extends React.Component { render() { const { className, moreActions, dockStore, active, isMac, ...tabProps } = this.props; - if (!tabProps.value) { - return; - } - void dockStore; void active; void isMac; @@ -94,9 +90,11 @@ class NonInjectedDockTab extends React.Component { this.menuVisible.set(true)} label={(
diff --git a/packages/core/src/renderer/components/dock/dock.tsx b/packages/core/src/renderer/components/dock/dock.tsx index 3eae3be4b9..ef30675b5e 100644 --- a/packages/core/src/renderer/components/dock/dock.tsx +++ b/packages/core/src/renderer/components/dock/dock.tsx @@ -93,11 +93,11 @@ class NonInjectedDock extends React.Component { const currentIndex = tabs.indexOf(selectedTab); const nextIndex = currentIndex + direction; - // check if moving to the next or previous tab is possible. - if (nextIndex >= tabs.length || nextIndex < 0) return; - const nextElement = tabs[nextIndex]; + // check if moving to the next or previous tab is possible. + if (!nextElement) return; + this.onChangeTab(nextElement); }; diff --git a/packages/core/src/renderer/components/dock/info-panel.tsx b/packages/core/src/renderer/components/dock/info-panel.tsx index 76af350fd6..83424adefc 100644 --- a/packages/core/src/renderer/components/dock/info-panel.tsx +++ b/packages/core/src/renderer/components/dock/info-panel.tsx @@ -9,7 +9,7 @@ import React, { Component } from "react"; import { computed, observable, reaction, makeObservable } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; import type { StrictReactNode } from "@k8slens/utilities"; -import { cssNames } from "@k8slens/utilities"; +import { cssNames, isTruthy } from "@k8slens/utilities"; import { Button } from "@k8slens/button"; import { Icon } from "@k8slens/icon"; import { Spinner } from "../spinner"; @@ -90,7 +90,7 @@ class NonInjectedInfoPanel extends Component { try { const result = await this.props.submit?.(); - if (showNotifications && result) { + if (showNotifications && isTruthy(result)) { this.props.showSuccessNotification(result); } @@ -109,7 +109,7 @@ class NonInjectedInfoPanel extends Component { submitAndClose = async () => { const result = await this.submit(); - if (result) { + if (isTruthy(result)) { this.close(); } }; diff --git a/packages/core/src/renderer/components/dock/logs/search.tsx b/packages/core/src/renderer/components/dock/logs/search.tsx index 8ceacf4d70..b20aa645f4 100644 --- a/packages/core/src/renderer/components/dock/logs/search.tsx +++ b/packages/core/src/renderer/components/dock/logs/search.tsx @@ -32,7 +32,7 @@ export const LogSearch = observer((props: PodLogSearchProps) => { const logs = tabData.showTimestamps ? model.logs.get() : model.logsWithoutTimestamps.get(); - const jumpDisabled = !searchQuery || !occurrences.length; + const jumpDisabled = !searchQuery.get() || !occurrences.length; const setSearch = (query: string) => { searchStore.onSearch(logs, query); diff --git a/packages/core/src/renderer/components/dock/terminal/send-command.injectable.ts b/packages/core/src/renderer/components/dock/terminal/send-command.injectable.ts index e8d4f6c7c4..95b8095e68 100644 --- a/packages/core/src/renderer/components/dock/terminal/send-command.injectable.ts +++ b/packages/core/src/renderer/components/dock/terminal/send-command.injectable.ts @@ -4,7 +4,6 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { when } from "mobx"; -import { loggerInjectionToken } from "@k8slens/logger"; import { TerminalChannels } from "../../../../common/terminal/channels"; import { waitUntilDefined, noop } from "@k8slens/utilities"; import showSuccessNotificationInjectable from "../../notifications/show-success-notification.injectable"; @@ -40,7 +39,6 @@ const sendCommandInjectable = getInjectable({ const selectTab = di.inject(selectDockTabInjectable); const getTerminalApi = di.inject(getTerminalApiInjectable); const showSuccessNotification = di.inject(showSuccessNotificationInjectable); - const logger = di.inject(loggerInjectionToken); return async (command: string, options: SendCommandOptions = {}): Promise => { let tabId: string | undefined = options.tabId; @@ -70,21 +68,14 @@ const sendCommandInjectable = getInjectable({ await shellIsReady.catch(noop); clearTimeout(notifyVeryLong); - if (terminalApi) { - if (options.enter) { - command += "\r"; - } - - terminalApi.sendMessage({ - type: TerminalChannels.STDIN, - data: command, - }); - } else { - logger.warn( - "The selected tab is does not have a connection. Cannot send command.", - { tabId, command }, - ); + if (options.enter) { + command += "\r"; } + + terminalApi.sendMessage({ + type: TerminalChannels.STDIN, + data: command, + }); }; }, }); diff --git a/packages/core/src/renderer/components/dock/terminal/terminal.ts b/packages/core/src/renderer/components/dock/terminal/terminal.ts index 00a5948be2..f80687bf04 100644 --- a/packages/core/src/renderer/components/dock/terminal/terminal.ts +++ b/packages/core/src/renderer/components/dock/terminal/terminal.ts @@ -44,13 +44,11 @@ export class Terminal { protected readonly api: TerminalApi; private get elem() { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - return this.xterm.element!; + return this.xterm.element; } private get viewport() { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - return this.elem.querySelector(".xterm-viewport")!; + return this.elem?.querySelector(".xterm-viewport"); } attachTo(parentElem: HTMLElement) { @@ -99,8 +97,10 @@ export class Terminal { const onDataHandler = this.xterm.onData(this.onData); const clearOnce = once(this.onClear); - this.viewport.addEventListener("scroll", this.onScroll); - this.elem.addEventListener("contextmenu", this.onContextMenu); + const { viewport, elem } = this; + + viewport?.addEventListener("scroll", this.onScroll); + elem?.addEventListener("contextmenu", this.onContextMenu); this.api.once("ready", clearOnce); this.api.once("connected", clearOnce); this.api.on("data", this.onApiData); @@ -128,7 +128,8 @@ export class Terminal { () => this.fitAddon.dispose(), () => this.api.removeAllListeners(), () => window.removeEventListener("resize", this.onResize), - () => this.elem.removeEventListener("contextmenu", this.onContextMenu), + () => elem?.removeEventListener("contextmenu", this.onContextMenu), + () => viewport?.removeEventListener("scroll", this.onScroll), this.xterm.onResize(({ cols, rows }) => { this.api.sendTerminalSize(cols, rows); }), @@ -161,7 +162,7 @@ export class Terminal { }; onScroll = () => { - this.scrollPos = this.viewport.scrollTop; + this.scrollPos = this.viewport?.scrollTop ?? 0; }; onClear = () => { @@ -176,7 +177,12 @@ export class Terminal { onActivate = () => { this.fit(); setTimeout(() => this.focus(), 250); // delay used to prevent focus on active tab - this.viewport.scrollTop = this.scrollPos; // restore last scroll position + + const { viewport } = this; + + if (viewport) { + viewport.scrollTop = this.scrollPos; // restore last scroll position + } }; onContextMenu = () => { diff --git a/packages/core/src/renderer/components/drawer/drawer-item-labels.tsx b/packages/core/src/renderer/components/drawer/drawer-item-labels.tsx index cb76d4ed97..2b796b4eec 100644 --- a/packages/core/src/renderer/components/drawer/drawer-item-labels.tsx +++ b/packages/core/src/renderer/components/drawer/drawer-item-labels.tsx @@ -10,7 +10,7 @@ import { Badge } from "../badge"; import { KubeObject } from "@k8slens/kube-object"; export interface DrawerItemLabelsProps extends DrawerItemProps { - labels: string[] | Partial>; + labels?: string[] | Partial>; } export function DrawerItemLabels(props: DrawerItemLabelsProps) { diff --git a/packages/core/src/renderer/components/drawer/drawer-title.tsx b/packages/core/src/renderer/components/drawer/drawer-title.tsx index 02e5553109..279d2eed46 100644 --- a/packages/core/src/renderer/components/drawer/drawer-title.tsx +++ b/packages/core/src/renderer/components/drawer/drawer-title.tsx @@ -28,10 +28,12 @@ export interface DrawerTitleProps { export function DrawerTitle({ className, children, size = "title" }: DrawerTitleProps) { return (
{children}
diff --git a/packages/core/src/renderer/components/events/event-details.tsx b/packages/core/src/renderer/components/events/event-details.tsx index 16551ad8cf..26ee2ec71a 100644 --- a/packages/core/src/renderer/components/events/event-details.tsx +++ b/packages/core/src/renderer/components/events/event-details.tsx @@ -36,10 +36,6 @@ const NonInjectedEventDetails = observer(({ className, logger, }: Dependencies & KubeObjectDetailsProps) => { - if (!event) { - return null; - } - if (!(event instanceof KubeEvent)) { logger.error("[EventDetails]: passed object that is not an instanceof KubeEvent", event); diff --git a/packages/core/src/renderer/components/events/kube-event-details.tsx b/packages/core/src/renderer/components/events/kube-event-details.tsx index 73fbb67e4c..f6892e956b 100644 --- a/packages/core/src/renderer/components/events/kube-event-details.tsx +++ b/packages/core/src/renderer/components/events/kube-event-details.tsx @@ -43,10 +43,6 @@ class NonInjectedKubeEventDetails extends React.Component {events.map(event => (
-
+
{event.message}
diff --git a/packages/core/src/renderer/components/extensions/attempt-install-by-info.injectable.tsx b/packages/core/src/renderer/components/extensions/attempt-install-by-info.injectable.tsx index a118891f9d..4927499707 100644 --- a/packages/core/src/renderer/components/extensions/attempt-install-by-info.injectable.tsx +++ b/packages/core/src/renderer/components/extensions/attempt-install-by-info.injectable.tsx @@ -2,7 +2,7 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { isObject } from "@k8slens/utilities"; +import { isObject, isTruthy } from "@k8slens/utilities"; import React from "react"; import { SemVer } from "semver"; import URLParse from "url-parse"; @@ -76,8 +76,8 @@ const attemptInstallByInfoInjectable = getInjectable({ return disposer(); } - if (result.value.error || !isObject(result.value.versions)) { - const message = result.value.error ? `: ${String(result.value.error)}` : ""; + if (isTruthy(result.value.error) || !isObject(result.value.versions)) { + const message = isTruthy(result.value.error) ? `: ${String(result.value.error)}` : ""; showErrorNotification(`Failed to get registry information for extension${message}`); diff --git a/packages/core/src/renderer/components/extensions/get-message-from-error/get-message-from-error.ts b/packages/core/src/renderer/components/extensions/get-message-from-error/get-message-from-error.ts index ecebfb6e80..acb2b25b5f 100644 --- a/packages/core/src/renderer/components/extensions/get-message-from-error/get-message-from-error.ts +++ b/packages/core/src/renderer/components/extensions/get-message-from-error/get-message-from-error.ts @@ -3,10 +3,10 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { hasTypedProperty, isDefined } from "@k8slens/utilities"; +import { hasTypedProperty, isDefined, isObject } from "@k8slens/utilities"; export function getMessageFromError(error: unknown): string { - if (!error || typeof error !== "object") { + if (!isObject(error)) { return "an error has occurred"; } diff --git a/packages/core/src/renderer/components/extensions/installed-extensions.tsx b/packages/core/src/renderer/components/extensions/installed-extensions.tsx index 0cfe5e0c32..2b7df32c2c 100644 --- a/packages/core/src/renderer/components/extensions/installed-extensions.tsx +++ b/packages/core/src/renderer/components/extensions/installed-extensions.tsx @@ -51,7 +51,7 @@ const NonInjectedInstalledExtensions = observer(({ enableExtension, disableExtension, }: Dependencies) => { - if (!extensionDiscovery.isLoaded) { + if (!extensionDiscovery.isLoaded.get()) { return
; } @@ -85,8 +85,8 @@ const NonInjectedInstalledExtensions = observer(({ accessor: "extension", width: 200, sortType: (rowA, rowB) => { // Custom sorting for extension name - const nameA = extensions[rowA.index].manifest.name; - const nameB = extensions[rowB.index].manifest.name; + const nameA = extensions[rowA.index]?.manifest.name ?? ""; + const nameB = extensions[rowB.index]?.manifest.name ?? ""; if (nameA > nameB) return -1; if (nameB > nameA) return 1; @@ -126,7 +126,12 @@ const NonInjectedInstalledExtensions = observer(({ ), version, status: ( -
+
{getStatus(extension)}
), diff --git a/packages/core/src/renderer/components/helm-charts/helm-chart-details.tsx b/packages/core/src/renderer/components/helm-charts/helm-chart-details.tsx index 910e7818ee..285174b07b 100644 --- a/packages/core/src/renderer/components/helm-charts/helm-chart-details.tsx +++ b/packages/core/src/renderer/components/helm-charts/helm-chart-details.tsx @@ -25,7 +25,6 @@ import versionsOfSelectedHelmChartInjectable from "./details/versions-of-selecte import type { HelmChartDetailsVersionSelection } from "./details/versions/helm-chart-details-version-selection.injectable"; import helmChartDetailsVersionSelectionInjectable from "./details/versions/helm-chart-details-version-selection.injectable"; import assert from "assert"; -import autoBindReact from "auto-bind/react"; export interface HelmChartDetailsProps { hideDetails(): void; @@ -47,15 +46,6 @@ interface Dependencies { @observer class NonInjectedHelmChartDetails extends Component { - constructor(props: HelmChartDetailsProps & Dependencies) { - super(props); - autoBindReact(this); - } - - get chart() { - return this.props.chart; - } - install = () => { const chart = this.props.versionSelection.value.get(); @@ -144,13 +134,13 @@ class NonInjectedHelmChartDetails extends Component; } return (
- {this.renderIntroduction(this.chart)} + {this.renderIntroduction(this.props.chart)} {readmeIsLoading ? ( @@ -162,12 +152,13 @@ class NonInjectedHelmChartDetails extends Component {this.renderContent()} diff --git a/packages/core/src/renderer/components/helm-charts/icon.tsx b/packages/core/src/renderer/components/helm-charts/icon.tsx index 12e3c8761b..0ccd64d0f8 100644 --- a/packages/core/src/renderer/components/helm-charts/icon.tsx +++ b/packages/core/src/renderer/components/helm-charts/icon.tsx @@ -31,7 +31,7 @@ export const HelmChartIcon = ({ return (
1; - return ( <> - {hasRollback && ( + {(release.getRevision() > 1) && ( ); } @@ -107,7 +107,6 @@ class NonInjectedHotbarEntityIcon extends React.Component this.onMenuOpen()} - disabled={!entity} menuItems={this.menuItems} tooltip={( entity.metadata.source diff --git a/packages/core/src/renderer/components/hotbar/hotbar-icon.tsx b/packages/core/src/renderer/components/hotbar/hotbar-icon.tsx index 7a69786ea4..7bc620f901 100644 --- a/packages/core/src/renderer/components/hotbar/hotbar-icon.tsx +++ b/packages/core/src/renderer/components/hotbar/hotbar-icon.tsx @@ -50,7 +50,7 @@ const NonInjectedHotbarIcon = observer(({ }; return ( -
0 })}> +
0 && styles.contextMenuAvailable))}> {tooltip && ( {tooltip} @@ -61,7 +61,11 @@ const NonInjectedHotbarIcon = observer(({ id={id} title={title} colorHash={source ? `${title}-${source}` : title} - className={cssNames(styles.avatar, { [styles.active]: active, [styles.hasImage]: !!src })} + className={cssNames( + styles.avatar, + active && styles.active, + !!src && styles.hasImag, + )} disabled={disabled} size={size} src={src} diff --git a/packages/core/src/renderer/components/input/input.tsx b/packages/core/src/renderer/components/input/input.tsx index e5b71ac888..1d60d56f31 100644 --- a/packages/core/src/renderer/components/input/input.tsx +++ b/packages/core/src/renderer/components/input/input.tsx @@ -8,7 +8,7 @@ import "./input.scss"; import type { DOMAttributes, InputHTMLAttributes, TextareaHTMLAttributes } from "react"; import React from "react"; import type { StrictReactNode, SingleOrMany } from "@k8slens/utilities"; -import { isReactNode, isString, isFunction, debouncePromise, isPromiseSettledFulfilled, cssNames } from "@k8slens/utilities"; +import { isReactNode, isFalsy, isTruthy, isString, isFunction, debouncePromise, isPromiseSettledFulfilled, cssNames } from "@k8slens/utilities"; import { Icon } from "@k8slens/icon"; import type { TooltipProps } from "@k8slens/tooltip"; import { Tooltip } from "@k8slens/tooltip"; @@ -195,7 +195,13 @@ export class Input extends React.Component { return undefined; } catch (error) { - return this.getValidatorError(value, validator) || (error instanceof Error ? error.message : String(error)); + const validationError = this.getValidatorError(value, validator); + + return isTruthy(validationError) + ? validationError + : error instanceof Error + ? error.message + : String(error); } })()); } @@ -327,7 +333,7 @@ export class Input extends React.Component { get showMaxLenIndicator() { const { maxLength, multiLine } = this.props; - return maxLength && multiLine; + return Boolean(maxLength && multiLine); } get isUncontrolled() { @@ -440,12 +446,12 @@ export class Input extends React.Component { {errors.map((error, i) =>

{error}

)}
); - const componentId = id || showErrorsAsTooltip + const componentId = id || isTruthy(showErrorsAsTooltip) ? `input_tooltip_id_${uuid.v4()}` : undefined; let tooltipError: StrictReactNode; - if (showErrorsAsTooltip && showErrors) { + if (isTruthy(showErrorsAsTooltip) && showErrors) { const tooltipProps = typeof showErrorsAsTooltip === "object" ? showErrorsAsTooltip : {}; tooltipProps.className = cssNames("InputTooltipError", tooltipProps.className); @@ -473,7 +479,7 @@ export class Input extends React.Component { {contentRight}
- {!showErrorsAsTooltip && showErrors && errorsInfo} + {(isFalsy(showErrorsAsTooltip) && showErrors) && errorsInfo} {this.showMaxLenIndicator && (
{this.getValue().length} diff --git a/packages/core/src/renderer/components/input/input_validators.ts b/packages/core/src/renderer/components/input/input_validators.ts index 18f726da8c..91c0166c5c 100644 --- a/packages/core/src/renderer/components/input/input_validators.ts +++ b/packages/core/src/renderer/components/input/input_validators.ts @@ -59,6 +59,10 @@ export function isAsyncValidator(validator: InputValidator): validator is AsyncI return typeof validator.debounce === "number"; } +export function isSyncValidator(validator: InputValidator): validator is SyncInputValidator { + return typeof validator.debounce !== "number"; +} + /** * A helper function to create an {@link AsyncInputValidator} */ @@ -106,7 +110,11 @@ export function unionInputValidatorsAsync( debounce: longestDebounce, validate: async (value, props) => { for (const validator of validators) { - if (isAsyncValidator(validator)) { + if (isSyncValidator(validator)) { + if (validator.validate(value, props)) { + return; + } + } else { try { await validator.validate(value, props); @@ -114,10 +122,6 @@ export function unionInputValidatorsAsync( } catch { // Do nothing } - } else { - if (validator.validate(value, props)) { - return; - } } } diff --git a/packages/core/src/renderer/components/input/search-input.tsx b/packages/core/src/renderer/components/input/search-input.tsx index 9df56fc6fb..722f2764c4 100644 --- a/packages/core/src/renderer/components/input/search-input.tsx +++ b/packages/core/src/renderer/components/input/search-input.tsx @@ -7,7 +7,7 @@ import "./search-input.scss"; import React, { createRef } from "react"; import { observer } from "mobx-react"; -import { addWindowEventListener, cssNames, disposer } from "@k8slens/utilities"; +import { addWindowEventListener, cssNames, disposer, isTruthy } from "@k8slens/utilities"; import { Icon } from "@k8slens/icon"; import type { InputProps } from "./input"; import { Input } from "./input"; @@ -86,7 +86,7 @@ class NonInjectedSearchInput extends React.Component removeItems.apply(store, [selectedItems]) : isFunction(removeSelectedItems) - ? removeSelectedItems.bind(store) + ? () => removeSelectedItems.apply(store) : noop; openConfirmDialog({ @@ -328,7 +328,7 @@ class NonInjectedItemListLayoutContent< {() => ( 0 + (Boolean(store.removeItems) || Boolean(store.removeSelectedItems)) && selectedItems.length > 0 ? () => this.removeItemsDialog(selectedItems) : undefined } diff --git a/packages/core/src/renderer/components/item-object-list/header.tsx b/packages/core/src/renderer/components/item-object-list/header.tsx index 1acbe0a2f6..e39dc2574a 100644 --- a/packages/core/src/renderer/components/item-object-list/header.tsx +++ b/packages/core/src/renderer/components/item-object-list/header.tsx @@ -8,7 +8,7 @@ import "./item-list-layout.scss"; import React from "react"; import { observer } from "mobx-react"; import type { IClassName, StrictReactNode } from "@k8slens/utilities"; -import { isFunction, cssNames, isDefined } from "@k8slens/utilities"; +import { isTruthy, isFunction, cssNames, isDefined } from "@k8slens/utilities"; import type { ItemObject } from "@k8slens/list-layout"; import type { Filter } from "./page-filters/store"; import type { HeaderCustomizer, HeaderPlaceholders, ItemListStore, SearchFilter } from "./list-layout"; @@ -91,7 +91,7 @@ export class ItemListLayoutHeader {title} { - info && ( + isTruthy(info) && (
{info}
diff --git a/packages/core/src/renderer/components/item-object-list/list-layout.tsx b/packages/core/src/renderer/components/item-object-list/list-layout.tsx index 2a6104687a..54cc37c79e 100644 --- a/packages/core/src/renderer/components/item-object-list/list-layout.tsx +++ b/packages/core/src/renderer/components/item-object-list/list-layout.tsx @@ -346,7 +346,7 @@ export const ItemListLayout = withInjectables(props: ItemListLayoutProps) => React.ReactElement; function applyFilters(filters: ItemsFilter[], items: I[]): I[] { - if (!filters || !filters.length) { + if (!filters.length) { return items; } diff --git a/packages/core/src/renderer/components/kube-object-list-layout/kube-object-list-layout.tsx b/packages/core/src/renderer/components/kube-object-list-layout/kube-object-list-layout.tsx index 9280d55ac8..41b23705cc 100644 --- a/packages/core/src/renderer/components/kube-object-list-layout/kube-object-list-layout.tsx +++ b/packages/core/src/renderer/components/kube-object-list-layout/kube-object-list-layout.tsx @@ -76,7 +76,7 @@ const matchesApiFor = (api: SubscribableStore["api"]) => (column: GeneralKubeObj const getLoadErrorMessage = (error: unknown): string => { if (error instanceof Error) { - if (error.cause) { + if (Boolean(error.cause)) { return `${error.message}: ${getLoadErrorMessage(error.cause)}`; } @@ -166,7 +166,19 @@ class NonInjectedKubeObjectListLayout< sortingCallbacks = {}, ...layoutProps } = this.props; - const resourceName = this.props.resourceName || ResourceNames[ResourceKindMap[store.api.kind]] || store.api.kind; + const resourceName = (() => { + if (this.props.resourceName) { + return this.props.resourceName; + } + + const kubeResource = ResourceKindMap[store.api.kind]; + + if (kubeResource) { + return ResourceNames[kubeResource]; + } + + return store.api.kind; + })(); const targetColumns = [ ...(columns ?? []), ...generalColumns.filter(matchesApiFor(store.api)), diff --git a/packages/core/src/renderer/components/kube-object-menu/kube-object-menu.tsx b/packages/core/src/renderer/components/kube-object-menu/kube-object-menu.tsx index 40bd7c5f01..2406e383b3 100644 --- a/packages/core/src/renderer/components/kube-object-menu/kube-object-menu.tsx +++ b/packages/core/src/renderer/components/kube-object-menu/kube-object-menu.tsx @@ -51,7 +51,7 @@ class NonInjectedKubeObjectMenu extends React.Component private menuItems = observable.array(); componentDidUpdate(prevProps: Readonly & Dependencies>): void { - if (prevProps.object !== this.props.object && this.props.object) { + if (prevProps.object !== this.props.object) { this.emitOnContextMenuOpen(this.props.object); } } @@ -199,11 +199,11 @@ class NonInjectedKubeObjectMenu extends React.Component id={`menu-actions-for-kube-object-menu-for-${object?.getId()}`} data-testid={`menu-actions-for-kube-object-menu-for-${object?.getId()}`} className={cssNames("KubeObjectMenu", className)} - onOpen={object ? () => this.emitOnContextMenuOpen(object) : undefined} + onOpen={() => this.emitOnContextMenuOpen(object)} {...menuProps} > {this.renderMenuItems()} - {object && this.renderContextMenuItems(object)} + {this.renderContextMenuItems(object)} ); } diff --git a/packages/core/src/renderer/components/kube-object-meta/kube-object-meta.tsx b/packages/core/src/renderer/components/kube-object-meta/kube-object-meta.tsx index 3fce56f936..e318e10760 100644 --- a/packages/core/src/renderer/components/kube-object-meta/kube-object-meta.tsx +++ b/packages/core/src/renderer/components/kube-object-meta/kube-object-meta.tsx @@ -48,10 +48,6 @@ const NonInjectedKubeObjectMeta = observer((props : Dependencies & KubeObjectMet namespaceApi, } = props; - if (!object) { - return null; - } - if (!(object instanceof KubeObject)) { logger.error("[KubeObjectMeta]: passed object that is not an instanceof KubeObject", object); diff --git a/packages/core/src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx b/packages/core/src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx index c5b4ce288d..9b7601e73f 100644 --- a/packages/core/src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx +++ b/packages/core/src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx @@ -8,7 +8,7 @@ import React from "react"; import type { IObservableValue } from "mobx"; import { observer } from "mobx-react"; import type { StrictReactNode } from "@k8slens/utilities"; -import { cssNames } from "@k8slens/utilities"; +import { cssNames, isTruthy } from "@k8slens/utilities"; import { Button } from "@k8slens/button"; import type { DialogProps } from "../dialog"; import { Dialog } from "../dialog"; @@ -54,7 +54,7 @@ class NonInjectedKubeConfigDialog extends React.Component ( - { data.title || "Kubeconfig File" }}> + {isTruthy(data.title) ? data.title : "Kubeconfig File" }}> diff --git a/packages/core/src/renderer/components/layout/extension-sidebar-item-registrator.injectable.tsx b/packages/core/src/renderer/components/layout/extension-sidebar-item-registrator.injectable.tsx index 13a186c898..7da1d0a4ab 100644 --- a/packages/core/src/renderer/components/layout/extension-sidebar-item-registrator.injectable.tsx +++ b/packages/core/src/renderer/components/layout/extension-sidebar-item-registrator.injectable.tsx @@ -51,7 +51,7 @@ const extensionSidebarItemRegistratorInjectable = getInjectable({ parentId, isVisible: computed(() => extensionShouldBeEnabledForClusterFrame.value.get() && (visible?.get() ?? true)), title, - getIcon: () => (components.Icon && ), + getIcon: () => , onClick: () => { const route = targetRoute.get(); diff --git a/packages/core/src/renderer/components/layout/setting-layout.tsx b/packages/core/src/renderer/components/layout/setting-layout.tsx index e49a28b7d9..792649bdde 100644 --- a/packages/core/src/renderer/components/layout/setting-layout.tsx +++ b/packages/core/src/renderer/components/layout/setting-layout.tsx @@ -8,7 +8,7 @@ import "./setting-layout.scss"; import React from "react"; import { observer } from "mobx-react"; import type { IClassName, StrictReactNode } from "@k8slens/utilities"; -import { addWindowEventListener, disposer, cssNames } from "@k8slens/utilities"; +import { isTruthy, addWindowEventListener, disposer, cssNames } from "@k8slens/utilities"; import { CloseButton } from "./close-button"; import { getLegacyGlobalDiForExtensionApi } from "@k8slens/legacy-global-di"; import navigateToCatalogInjectable from "../../../common/front-end-routing/routes/catalog/navigate-to-catalog.injectable"; @@ -86,7 +86,7 @@ export class SettingLayout extends React.Component { return (
- { navigation && ( + {isTruthy(navigation) && (