mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Merge branch 'master' into ui-table-empty-state-lines
This commit is contained in:
commit
1d99ea36c4
10
.eslintrc.js
10
.eslintrc.js
@ -129,6 +129,16 @@ module.exports = {
|
|||||||
"@typescript-eslint/ban-ts-comment": "off",
|
"@typescript-eslint/ban-ts-comment": "off",
|
||||||
"@typescript-eslint/no-empty-function": "off",
|
"@typescript-eslint/no-empty-function": "off",
|
||||||
"@typescript-eslint/no-unused-vars": "off",
|
"@typescript-eslint/no-unused-vars": "off",
|
||||||
|
"@typescript-eslint/member-delimiter-style": ["error", {
|
||||||
|
"multiline": {
|
||||||
|
"delimiter": "semi",
|
||||||
|
"requireLast": true,
|
||||||
|
},
|
||||||
|
"singleline": {
|
||||||
|
"delimiter": "semi",
|
||||||
|
"requireLast": false,
|
||||||
|
},
|
||||||
|
}],
|
||||||
"react/display-name": "off",
|
"react/display-name": "off",
|
||||||
"space-before-function-paren": "off",
|
"space-before-function-paren": "off",
|
||||||
"@typescript-eslint/space-before-function-paren": ["error", {
|
"@typescript-eslint/space-before-function-paren": ["error", {
|
||||||
|
|||||||
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@ -42,7 +42,7 @@ jobs:
|
|||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-yarn-
|
${{ runner.os }}-yarn-
|
||||||
|
|
||||||
- uses: nick-invision/retry@v2
|
- uses: nick-fields/retry@v2
|
||||||
name: Install dependencies
|
name: Install dependencies
|
||||||
with:
|
with:
|
||||||
timeout_minutes: 10
|
timeout_minutes: 10
|
||||||
@ -53,7 +53,7 @@ jobs:
|
|||||||
- run: make build-npm
|
- run: make build-npm
|
||||||
name: Generate npm package
|
name: Generate npm package
|
||||||
|
|
||||||
- uses: nick-invision/retry@v2
|
- uses: nick-fields/retry@v2
|
||||||
name: Build bundled extensions
|
name: Build bundled extensions
|
||||||
with:
|
with:
|
||||||
timeout_minutes: 15
|
timeout_minutes: 15
|
||||||
|
|||||||
@ -3,4 +3,4 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default ""; // mostly path to bundled file or data-url (webpack)
|
export default {};
|
||||||
3452
extensions/kube-object-event-status/package-lock.json
generated
3452
extensions/kube-object-event-status/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -18,8 +18,8 @@
|
|||||||
"dependencies": {},
|
"dependencies": {},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@k8slens/extensions": "file:../../src/extensions/npm/extensions",
|
"@k8slens/extensions": "file:../../src/extensions/npm/extensions",
|
||||||
"ts-loader": "latest",
|
"ts-loader": "^8.0.4",
|
||||||
"typescript": "latest",
|
"typescript": "^4.3.2",
|
||||||
"webpack": "latest"
|
"webpack": "^4.46.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
5624
extensions/metrics-cluster-feature/package-lock.json
generated
5624
extensions/metrics-cluster-feature/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -19,10 +19,10 @@
|
|||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@k8slens/extensions": "file:../../src/extensions/npm/extensions",
|
"@k8slens/extensions": "file:../../src/extensions/npm/extensions",
|
||||||
|
"jest": "^26.6.3",
|
||||||
"semver": "^7.3.2",
|
"semver": "^7.3.2",
|
||||||
"jest": "latest",
|
"ts-loader": "^8.0.4",
|
||||||
"ts-loader": "latest",
|
"typescript": "^4.3.2",
|
||||||
"typescript": "latest",
|
"webpack": "^4.44.2"
|
||||||
"webpack": "latest"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
5939
extensions/node-menu/package-lock.json
generated
5939
extensions/node-menu/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -18,9 +18,9 @@
|
|||||||
"dependencies": {},
|
"dependencies": {},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@k8slens/extensions": "file:../../src/extensions/npm/extensions",
|
"@k8slens/extensions": "file:../../src/extensions/npm/extensions",
|
||||||
"jest": "latest",
|
"jest": "^26.6.3",
|
||||||
"ts-loader": "latest",
|
"ts-loader": "^8.0.4",
|
||||||
"typescript": "latest",
|
"typescript": "^4.3.2",
|
||||||
"webpack": "latest"
|
"webpack": "^4.46.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
5939
extensions/pod-menu/package-lock.json
generated
5939
extensions/pod-menu/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -18,9 +18,9 @@
|
|||||||
"dependencies": {},
|
"dependencies": {},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@k8slens/extensions": "file:../../src/extensions/npm/extensions",
|
"@k8slens/extensions": "file:../../src/extensions/npm/extensions",
|
||||||
"jest": "latest",
|
"jest": "^26.6.3",
|
||||||
"ts-loader": "latest",
|
"ts-loader": "^8.0.4",
|
||||||
"typescript": "latest",
|
"typescript": "^4.3.2",
|
||||||
"webpack": "latest"
|
"webpack": "^4.46.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,9 +60,7 @@ describe("preferences page tests", () => {
|
|||||||
// Skipping, but will turn it on again in the follow up PR
|
// Skipping, but will turn it on again in the follow up PR
|
||||||
it.skip("ensures helm repos", async () => {
|
it.skip("ensures helm repos", async () => {
|
||||||
await window.click("[data-testid=kubernetes-tab]");
|
await window.click("[data-testid=kubernetes-tab]");
|
||||||
await window.waitForSelector("[data-testid=repository-name]", {
|
await window.waitForSelector("[data-testid=repository-name]");
|
||||||
timeout: 140_000,
|
|
||||||
});
|
|
||||||
await window.click("#HelmRepoSelect");
|
await window.click("#HelmRepoSelect");
|
||||||
await window.waitForSelector("div.Select__option");
|
await window.waitForSelector("div.Select__option");
|
||||||
}, 10*60*1000);
|
}, 10*60*1000);
|
||||||
|
|||||||
58
package.json
58
package.json
@ -3,7 +3,7 @@
|
|||||||
"productName": "OpenLens",
|
"productName": "OpenLens",
|
||||||
"description": "OpenLens - Open Source IDE for Kubernetes",
|
"description": "OpenLens - Open Source IDE for Kubernetes",
|
||||||
"homepage": "https://github.com/lensapp/lens",
|
"homepage": "https://github.com/lensapp/lens",
|
||||||
"version": "5.4.0-beta.1",
|
"version": "5.4.0-beta.2",
|
||||||
"main": "static/build/main.js",
|
"main": "static/build/main.js",
|
||||||
"copyright": "© 2021 OpenLens Authors",
|
"copyright": "© 2021 OpenLens Authors",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -16,9 +16,9 @@
|
|||||||
"dev-build": "concurrently yarn:compile:*",
|
"dev-build": "concurrently yarn:compile:*",
|
||||||
"debug-build": "concurrently yarn:compile:main yarn:compile:extension-types",
|
"debug-build": "concurrently yarn:compile:main yarn:compile:extension-types",
|
||||||
"dev-run": "nodemon --watch static/build/main.js --exec \"electron --remote-debugging-port=9223 --inspect .\"",
|
"dev-run": "nodemon --watch static/build/main.js --exec \"electron --remote-debugging-port=9223 --inspect .\"",
|
||||||
"dev:main": "yarn run compile:main --watch --progress",
|
"dev:main": "yarn run compile:main --watch",
|
||||||
"dev:renderer": "yarn run compile:renderer --watch --progress",
|
"dev:renderer": "yarn run webpack-dev-server --config webpack.renderer.ts",
|
||||||
"dev:extension-types": "yarn run compile:extension-types --watch --progress",
|
"dev:extension-types": "yarn run compile:extension-types --watch",
|
||||||
"compile": "env NODE_ENV=production concurrently yarn:compile:*",
|
"compile": "env NODE_ENV=production concurrently yarn:compile:*",
|
||||||
"compile:main": "yarn run webpack --config webpack.main.ts",
|
"compile:main": "yarn run webpack --config webpack.main.ts",
|
||||||
"compile:renderer": "yarn run webpack --config webpack.renderer.ts",
|
"compile:renderer": "yarn run webpack --config webpack.renderer.ts",
|
||||||
@ -62,7 +62,7 @@
|
|||||||
},
|
},
|
||||||
"moduleNameMapper": {
|
"moduleNameMapper": {
|
||||||
"\\.(css|scss)$": "<rootDir>/__mocks__/styleMock.ts",
|
"\\.(css|scss)$": "<rootDir>/__mocks__/styleMock.ts",
|
||||||
"\\.(svg|png|jpg|eot|woff2?|ttf)$": "<rootDir>/__mocks__/assetMock.ts"
|
"\\.(svg)$": "<rootDir>/__mocks__/imageMock.ts"
|
||||||
},
|
},
|
||||||
"modulePathIgnorePatterns": [
|
"modulePathIgnorePatterns": [
|
||||||
"<rootDir>/dist",
|
"<rootDir>/dist",
|
||||||
@ -268,7 +268,7 @@
|
|||||||
"@material-ui/core": "^4.12.3",
|
"@material-ui/core": "^4.12.3",
|
||||||
"@material-ui/icons": "^4.11.2",
|
"@material-ui/icons": "^4.11.2",
|
||||||
"@material-ui/lab": "^4.0.0-alpha.60",
|
"@material-ui/lab": "^4.0.0-alpha.60",
|
||||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.4",
|
"@pmmmwh/react-refresh-webpack-plugin": "^0.4.3",
|
||||||
"@sentry/types": "^6.14.1",
|
"@sentry/types": "^6.14.1",
|
||||||
"@testing-library/jest-dom": "^5.16.1",
|
"@testing-library/jest-dom": "^5.16.1",
|
||||||
"@testing-library/react": "^11.2.7",
|
"@testing-library/react": "^11.2.7",
|
||||||
@ -291,11 +291,12 @@
|
|||||||
"@types/lodash": "^4.14.177",
|
"@types/lodash": "^4.14.177",
|
||||||
"@types/marked": "^4.0.1",
|
"@types/marked": "^4.0.1",
|
||||||
"@types/md5-file": "^4.0.2",
|
"@types/md5-file": "^4.0.2",
|
||||||
"@types/mini-css-extract-plugin": "^2.4.0",
|
"@types/mini-css-extract-plugin": "^0.9.1",
|
||||||
"@types/mock-fs": "^4.13.1",
|
"@types/mock-fs": "^4.13.1",
|
||||||
"@types/node": "14.17.33",
|
"@types/node": "14.17.33",
|
||||||
"@types/node-fetch": "^2.5.12",
|
"@types/node-fetch": "^2.5.12",
|
||||||
"@types/npm": "^2.0.32",
|
"@types/npm": "^2.0.32",
|
||||||
|
"@types/progress-bar-webpack-plugin": "^2.1.2",
|
||||||
"@types/proper-lockfile": "^4.1.2",
|
"@types/proper-lockfile": "^4.1.2",
|
||||||
"@types/randomcolor": "^0.5.6",
|
"@types/randomcolor": "^0.5.6",
|
||||||
"@types/react": "^17.0.34",
|
"@types/react": "^17.0.34",
|
||||||
@ -318,10 +319,10 @@
|
|||||||
"@types/triple-beam": "^1.3.2",
|
"@types/triple-beam": "^1.3.2",
|
||||||
"@types/url-parse": "^1.4.5",
|
"@types/url-parse": "^1.4.5",
|
||||||
"@types/uuid": "^8.3.3",
|
"@types/uuid": "^8.3.3",
|
||||||
"@types/webpack": "^5.28.0",
|
"@types/webpack": "^4.41.32",
|
||||||
"@types/webpack-dev-server": "^4.7.2",
|
"@types/webpack-dev-server": "^3.11.6",
|
||||||
"@types/webpack-env": "^1.16.3",
|
"@types/webpack-env": "^1.16.3",
|
||||||
"@types/webpack-node-externals": "^2.5.3",
|
"@types/webpack-node-externals": "^1.7.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.10.1",
|
"@typescript-eslint/eslint-plugin": "^5.10.1",
|
||||||
"@typescript-eslint/parser": "^5.10.1",
|
"@typescript-eslint/parser": "^5.10.1",
|
||||||
"ansi_up": "^5.1.0",
|
"ansi_up": "^5.1.0",
|
||||||
@ -329,24 +330,25 @@
|
|||||||
"circular-dependency-plugin": "^5.2.2",
|
"circular-dependency-plugin": "^5.2.2",
|
||||||
"color": "^3.2.1",
|
"color": "^3.2.1",
|
||||||
"concurrently": "^5.3.0",
|
"concurrently": "^5.3.0",
|
||||||
"css-loader": "^6.5.1",
|
"css-loader": "^5.2.7",
|
||||||
"deepdash": "^5.3.9",
|
"deepdash": "^5.3.9",
|
||||||
"dompurify": "^2.3.4",
|
"dompurify": "^2.3.4",
|
||||||
"electron": "^14.2.4",
|
"electron": "^14.2.4",
|
||||||
"electron-builder": "^22.14.5",
|
"electron-builder": "^22.14.5",
|
||||||
"electron-notarize": "^0.3.0",
|
"electron-notarize": "^0.3.0",
|
||||||
"esbuild": "^0.13.15",
|
"esbuild": "^0.13.15",
|
||||||
"esbuild-loader": "^2.18.0",
|
"esbuild-loader": "^2.16.0",
|
||||||
"eslint": "^8.7.0",
|
"eslint": "^8.7.0",
|
||||||
"eslint-plugin-header": "^3.1.1",
|
"eslint-plugin-header": "^3.1.1",
|
||||||
"eslint-plugin-import": "^2.25.4",
|
"eslint-plugin-import": "^2.25.4",
|
||||||
"eslint-plugin-react": "^7.28.0",
|
"eslint-plugin-react": "^7.28.0",
|
||||||
"eslint-plugin-react-hooks": "^4.3.0",
|
"eslint-plugin-react-hooks": "^4.3.0",
|
||||||
"eslint-plugin-unused-imports": "^2.0.0",
|
"eslint-plugin-unused-imports": "^2.0.0",
|
||||||
|
"file-loader": "^6.2.0",
|
||||||
"flex.box": "^3.4.4",
|
"flex.box": "^3.4.4",
|
||||||
"fork-ts-checker-webpack-plugin": "^6.5.0",
|
"fork-ts-checker-webpack-plugin": "^5.2.1",
|
||||||
"hoist-non-react-statics": "^3.3.2",
|
"hoist-non-react-statics": "^3.3.2",
|
||||||
"html-webpack-plugin": "^5.5.0",
|
"html-webpack-plugin": "^4.5.2",
|
||||||
"ignore-loader": "^0.1.2",
|
"ignore-loader": "^0.1.2",
|
||||||
"include-media": "^1.4.9",
|
"include-media": "^1.4.9",
|
||||||
"jest": "26.6.3",
|
"jest": "26.6.3",
|
||||||
@ -354,41 +356,43 @@
|
|||||||
"jest-fetch-mock": "^3.0.3",
|
"jest-fetch-mock": "^3.0.3",
|
||||||
"jest-mock-extended": "^1.0.18",
|
"jest-mock-extended": "^1.0.18",
|
||||||
"make-plural": "^6.2.2",
|
"make-plural": "^6.2.2",
|
||||||
"mini-css-extract-plugin": "^2.5.2",
|
"mini-css-extract-plugin": "^1.6.2",
|
||||||
"node-gyp": "7.1.2",
|
"node-gyp": "7.1.2",
|
||||||
"node-loader": "^2.0.0",
|
"node-loader": "^1.0.3",
|
||||||
"nodemon": "^2.0.15",
|
"nodemon": "^2.0.15",
|
||||||
"playwright": "^1.17.1",
|
"playwright": "^1.17.1",
|
||||||
"postcss": "^8.4.5",
|
"postcss": "^8.4.5",
|
||||||
"postcss-loader": "^6.2.1",
|
"postcss-loader": "^4.3.0",
|
||||||
|
"progress-bar-webpack-plugin": "^2.1.0",
|
||||||
"randomcolor": "^0.6.2",
|
"randomcolor": "^0.6.2",
|
||||||
|
"raw-loader": "^4.0.2",
|
||||||
"react-beautiful-dnd": "^13.1.0",
|
"react-beautiful-dnd": "^13.1.0",
|
||||||
"react-refresh": "^0.11.0",
|
"react-refresh": "^0.9.0",
|
||||||
"react-refresh-typescript": "^2.0.3",
|
|
||||||
"react-router-dom": "^5.3.0",
|
"react-router-dom": "^5.3.0",
|
||||||
"react-select": "3.2.0",
|
"react-select": "3.2.0",
|
||||||
"react-select-event": "^5.1.0",
|
"react-select-event": "^5.1.0",
|
||||||
"react-table": "^7.7.0",
|
"react-table": "^7.7.0",
|
||||||
"react-window": "^1.8.6",
|
"react-window": "^1.8.6",
|
||||||
"sass": "^1.45.1",
|
"sass": "^1.45.1",
|
||||||
"sass-loader": "^12.4.0",
|
"sass-loader": "^10.2.0",
|
||||||
"sharp": "^0.29.3",
|
"sharp": "^0.29.3",
|
||||||
"style-loader": "^3.3.1",
|
"style-loader": "^2.0.0",
|
||||||
"tailwindcss": "^3.0.7",
|
"tailwindcss": "^3.0.7",
|
||||||
"ts-jest": "26.5.6",
|
"ts-jest": "26.5.6",
|
||||||
"ts-loader": "^9.2.6",
|
"ts-loader": "^7.0.5",
|
||||||
"ts-node": "^10.4.0",
|
"ts-node": "^10.4.0",
|
||||||
"type-fest": "^1.0.2",
|
"type-fest": "^1.0.2",
|
||||||
"typed-emitter": "^1.4.0",
|
"typed-emitter": "^1.4.0",
|
||||||
"typedoc": "0.22.10",
|
"typedoc": "0.22.10",
|
||||||
"typedoc-plugin-markdown": "^3.11.12",
|
"typedoc-plugin-markdown": "^3.11.3",
|
||||||
"typeface-roboto": "^1.1.13",
|
"typeface-roboto": "^1.1.13",
|
||||||
"typescript": "^4.5.2",
|
"typescript": "^4.5.2",
|
||||||
"typescript-plugin-css-modules": "^3.4.0",
|
"typescript-plugin-css-modules": "^3.4.0",
|
||||||
"webpack": "^5.67.0",
|
"url-loader": "^4.1.1",
|
||||||
"webpack-cli": "^4.9.1",
|
"webpack": "^4.46.0",
|
||||||
"webpack-dev-server": "^4.7.4",
|
"webpack-cli": "^3.3.12",
|
||||||
"webpack-node-externals": "^3.0.0",
|
"webpack-dev-server": "^3.11.3",
|
||||||
|
"webpack-node-externals": "^1.7.2",
|
||||||
"xterm": "^4.15.0",
|
"xterm": "^4.15.0",
|
||||||
"xterm-addon-fit": "^0.5.0"
|
"xterm-addon-fit": "^0.5.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,26 +44,26 @@ users:
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
interface kubeconfig {
|
interface kubeconfig {
|
||||||
apiVersion: string,
|
apiVersion: string;
|
||||||
clusters: [{
|
clusters: [{
|
||||||
name: string,
|
name: string;
|
||||||
cluster: {
|
cluster: {
|
||||||
server: string
|
server: string;
|
||||||
}
|
};
|
||||||
}],
|
}];
|
||||||
contexts: [{
|
contexts: [{
|
||||||
context: {
|
context: {
|
||||||
cluster: string,
|
cluster: string;
|
||||||
user: string,
|
user: string;
|
||||||
},
|
};
|
||||||
name: string
|
name: string;
|
||||||
}],
|
}];
|
||||||
users: [{
|
users: [{
|
||||||
name: string
|
name: string;
|
||||||
}],
|
}];
|
||||||
kind: string,
|
kind: string;
|
||||||
"current-context": string,
|
"current-context": string;
|
||||||
preferences: {}
|
preferences: {};
|
||||||
}
|
}
|
||||||
|
|
||||||
let mockKubeConfig: kubeconfig;
|
let mockKubeConfig: kubeconfig;
|
||||||
|
|||||||
@ -11,7 +11,6 @@ import { app } from "electron";
|
|||||||
import type { CatalogEntitySpec } from "../catalog/catalog-entity";
|
import type { CatalogEntitySpec } from "../catalog/catalog-entity";
|
||||||
import { IpcRendererNavigationEvents } from "../../renderer/navigation/events";
|
import { IpcRendererNavigationEvents } from "../../renderer/navigation/events";
|
||||||
import { requestClusterActivation, requestClusterDisconnection } from "../../renderer/ipc";
|
import { requestClusterActivation, requestClusterDisconnection } from "../../renderer/ipc";
|
||||||
import KubeClusterCategoryIcon from "./icons/kubernetes.svg";
|
|
||||||
|
|
||||||
export interface KubernetesClusterPrometheusMetrics {
|
export interface KubernetesClusterPrometheusMetrics {
|
||||||
address?: {
|
address?: {
|
||||||
@ -139,7 +138,7 @@ class KubernetesClusterCategory extends CatalogCategory {
|
|||||||
public readonly kind = "CatalogCategory";
|
public readonly kind = "CatalogCategory";
|
||||||
public metadata = {
|
public metadata = {
|
||||||
name: "Clusters",
|
name: "Clusters",
|
||||||
icon: KubeClusterCategoryIcon,
|
icon: require(`!!raw-loader!./icons/kubernetes.svg`).default, // eslint-disable-line
|
||||||
};
|
};
|
||||||
public spec: CatalogCategorySpec = {
|
public spec: CatalogCategorySpec = {
|
||||||
group: "entity.k8slens.dev",
|
group: "entity.k8slens.dev",
|
||||||
|
|||||||
@ -3,16 +3,17 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { action, computed, observable, makeObservable } from "mobx";
|
||||||
|
import type { Disposer } from "../utils";
|
||||||
|
import { strictSet, iter, getOrInsertMap } from "../utils";
|
||||||
import { once } from "lodash";
|
import { once } from "lodash";
|
||||||
import { action, computed, makeObservable, observable } from "mobx";
|
|
||||||
import { CatalogCategory, CatalogEntityData, CatalogEntityKindData } from "./catalog-entity";
|
import { CatalogCategory, CatalogEntityData, CatalogEntityKindData } from "./catalog-entity";
|
||||||
import { ExtendedMap, iter, type Disposer } from "../utils";
|
|
||||||
|
|
||||||
export type CategoryFilter = (category: CatalogCategory) => any;
|
export type CategoryFilter = (category: CatalogCategory) => any;
|
||||||
|
|
||||||
export class CatalogCategoryRegistry {
|
export class CatalogCategoryRegistry {
|
||||||
protected categories = observable.set<CatalogCategory>();
|
protected categories = observable.set<CatalogCategory>();
|
||||||
protected groupKinds = new ExtendedMap<string, ExtendedMap<string, CatalogCategory>>();
|
protected groupKinds = new Map<string, Map<string, CatalogCategory>>();
|
||||||
protected filters = observable.set<CategoryFilter>([], {
|
protected filters = observable.set<CategoryFilter>([], {
|
||||||
deep: false,
|
deep: false,
|
||||||
});
|
});
|
||||||
@ -22,14 +23,14 @@ export class CatalogCategoryRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@action add(category: CatalogCategory): Disposer {
|
@action add(category: CatalogCategory): Disposer {
|
||||||
|
const byGroup = getOrInsertMap(this.groupKinds, category.spec.group);
|
||||||
|
|
||||||
this.categories.add(category);
|
this.categories.add(category);
|
||||||
this.groupKinds
|
strictSet(byGroup, category.spec.names.kind, category);
|
||||||
.getOrInsert(category.spec.group, ExtendedMap.new)
|
|
||||||
.strictSet(category.spec.names.kind, category);
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
this.categories.delete(category);
|
this.categories.delete(category);
|
||||||
this.groupKinds.get(category.spec.group).delete(category.spec.names.kind);
|
byGroup.delete(category.spec.names.kind);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -165,7 +165,7 @@ export abstract class CatalogCategory extends (EventEmitter as new () => TypedEm
|
|||||||
* @param id The id of a category is parse
|
* @param id The id of a category is parse
|
||||||
* @returns The group and kind parts of the ID
|
* @returns The group and kind parts of the ID
|
||||||
*/
|
*/
|
||||||
public static parseId(id: string): { group?: string, kind?: string } {
|
public static parseId(id: string): { group?: string; kind?: string } {
|
||||||
const [group, kind] = id.split("/") ?? [];
|
const [group, kind] = id.split("/") ?? [];
|
||||||
|
|
||||||
return { group, kind };
|
return { group, kind };
|
||||||
@ -250,7 +250,7 @@ export interface CatalogEntityContextMenu {
|
|||||||
*/
|
*/
|
||||||
confirm?: {
|
confirm?: {
|
||||||
message: string;
|
message: string;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CatalogEntityAddMenu extends CatalogEntityContextMenu {
|
export interface CatalogEntityAddMenu extends CatalogEntityContextMenu {
|
||||||
@ -262,7 +262,7 @@ export interface CatalogEntitySettingsMenu {
|
|||||||
group?: string;
|
group?: string;
|
||||||
title: string;
|
title: string;
|
||||||
components: {
|
components: {
|
||||||
View: React.ComponentType<any>
|
View: React.ComponentType<any>;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import { observable } from "mobx";
|
|||||||
|
|
||||||
export interface ClusterFrameInfo {
|
export interface ClusterFrameInfo {
|
||||||
frameId: number;
|
frameId: number;
|
||||||
processId: number
|
processId: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const clusterFrameMap = observable.map<string, ClusterFrameInfo>();
|
export const clusterFrameMap = observable.map<string, ClusterFrameInfo>();
|
||||||
|
|||||||
@ -22,7 +22,7 @@ export interface ClusterStoreModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
createCluster: (model: ClusterModel) => Cluster
|
createCluster: (model: ClusterModel) => Cluster;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
||||||
|
|||||||
@ -157,7 +157,7 @@ export const initialNodeShellImage = "docker.io/alpine:3.13";
|
|||||||
* The arguments for requesting to refresh a cluster's metadata
|
* The arguments for requesting to refresh a cluster's metadata
|
||||||
*/
|
*/
|
||||||
export interface ClusterRefreshOptions {
|
export interface ClusterRefreshOptions {
|
||||||
refreshMetadata?: boolean
|
refreshMetadata?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -170,7 +170,7 @@ export interface ClusterState {
|
|||||||
accessible: boolean;
|
accessible: boolean;
|
||||||
ready: boolean;
|
ready: boolean;
|
||||||
isAdmin: boolean;
|
isAdmin: boolean;
|
||||||
allowedNamespaces: string[]
|
allowedNamespaces: string[];
|
||||||
allowedResources: string[]
|
allowedResources: string[];
|
||||||
isGlobalWatchEnabled: boolean;
|
isGlobalWatchEnabled: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,17 +4,18 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import esbuild from "esbuild";
|
import esbuild from "esbuild";
|
||||||
import type { Options as TSLoaderOptions } from "ts-loader";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A function returning webpack ts/tsx loader
|
* A function returning webpack ts/tsx loader
|
||||||
|
*
|
||||||
* depends on env LENS_DEV_USE_ESBUILD_LOADER to use esbuild-loader (faster) or good-old ts-loader
|
* depends on env LENS_DEV_USE_ESBUILD_LOADER to use esbuild-loader (faster) or good-old ts-loader
|
||||||
|
*
|
||||||
|
* @param testRegExp - the regex for webpack to conditional find the files
|
||||||
* @returns ts/tsx webpack loader configuration object
|
* @returns ts/tsx webpack loader configuration object
|
||||||
*/
|
*/
|
||||||
const getTSLoader = (options: Partial<TSLoaderOptions> = {}, testRegExp?: RegExp) => {
|
const getTSLoader = (
|
||||||
testRegExp ??= /\.tsx?$/; // by default covers react/jsx-stuff
|
testRegExp: RegExp, transpileOnly = true,
|
||||||
options.transpileOnly ??= true;
|
) => {
|
||||||
|
|
||||||
if (process.env.LENS_DEV_USE_ESBUILD_LOADER === "true") {
|
if (process.env.LENS_DEV_USE_ESBUILD_LOADER === "true") {
|
||||||
console.info(`\n🚀 using esbuild-loader for ts(x)`);
|
console.info(`\n🚀 using esbuild-loader for ts(x)`);
|
||||||
|
|
||||||
@ -34,7 +35,9 @@ const getTSLoader = (options: Partial<TSLoaderOptions> = {}, testRegExp?: RegExp
|
|||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
use: {
|
use: {
|
||||||
loader: "ts-loader",
|
loader: "ts-loader",
|
||||||
options,
|
options: {
|
||||||
|
transpileOnly,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -14,7 +14,7 @@ export interface HotbarItem {
|
|||||||
};
|
};
|
||||||
params?: {
|
params?: {
|
||||||
[key: string]: string;
|
[key: string]: string;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Hotbar = Required<CreateHotbarData>;
|
export type Hotbar = Required<CreateHotbarData>;
|
||||||
|
|||||||
@ -29,10 +29,10 @@ export function onceCorrect<
|
|||||||
listener,
|
listener,
|
||||||
verifier,
|
verifier,
|
||||||
}: {
|
}: {
|
||||||
source: IPC,
|
source: IPC;
|
||||||
channel: string,
|
channel: string;
|
||||||
listener: Listener,
|
listener: Listener;
|
||||||
verifier: ListVerifier<Rest<Parameters<Listener>>>,
|
verifier: ListVerifier<Rest<Parameters<Listener>>>;
|
||||||
}): void {
|
}): void {
|
||||||
function wrappedListener(event: ListenerEvent<IPC>, ...args: unknown[]): void {
|
function wrappedListener(event: ListenerEvent<IPC>, ...args: unknown[]): void {
|
||||||
if (verifier(args)) {
|
if (verifier(args)) {
|
||||||
@ -63,10 +63,10 @@ export function onCorrect<
|
|||||||
listener,
|
listener,
|
||||||
verifier,
|
verifier,
|
||||||
}: {
|
}: {
|
||||||
source: IPC,
|
source: IPC;
|
||||||
channel: string,
|
channel: string;
|
||||||
listener: Listener,
|
listener: Listener;
|
||||||
verifier: ListVerifier<Rest<Parameters<Listener>>>,
|
verifier: ListVerifier<Rest<Parameters<Listener>>>;
|
||||||
}): Disposer {
|
}): Disposer {
|
||||||
function wrappedListener(event: ListenerEvent<IPC>, ...args: unknown[]) {
|
function wrappedListener(event: ListenerEvent<IPC>, ...args: unknown[]) {
|
||||||
if (verifier(args)) {
|
if (verifier(args)) {
|
||||||
@ -89,9 +89,9 @@ export function handleCorrect<
|
|||||||
handler,
|
handler,
|
||||||
verifier,
|
verifier,
|
||||||
}: {
|
}: {
|
||||||
channel: string,
|
channel: string;
|
||||||
handler: Handler,
|
handler: Handler;
|
||||||
verifier: ListVerifier<Rest<Parameters<Handler>>>,
|
verifier: ListVerifier<Rest<Parameters<Handler>>>;
|
||||||
}): Disposer {
|
}): Disposer {
|
||||||
function wrappedHandler(event: Electron.IpcMainInvokeEvent, ...args: unknown[]): ReturnType<Handler> {
|
function wrappedHandler(event: Electron.IpcMainInvokeEvent, ...args: unknown[]): ReturnType<Handler> {
|
||||||
if (verifier(args)) {
|
if (verifier(args)) {
|
||||||
|
|||||||
@ -90,7 +90,7 @@ export interface RawHelmChart {
|
|||||||
urls?: string[];
|
urls?: string[];
|
||||||
maintainers?: HelmChartMaintainer[];
|
maintainers?: HelmChartMaintainer[];
|
||||||
dependencies?: RawHelmChartDependency[];
|
dependencies?: RawHelmChartDependency[];
|
||||||
annotations?: Record<string, string>,
|
annotations?: Record<string, string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const helmChartMaintainerValidator = Joi.object<HelmChartMaintainer>({
|
const helmChartMaintainerValidator = Joi.object<HelmChartMaintainer>({
|
||||||
|
|||||||
@ -70,8 +70,8 @@ export interface IReleaseRevision {
|
|||||||
|
|
||||||
type EndpointParams = {}
|
type EndpointParams = {}
|
||||||
| { namespace: string }
|
| { namespace: string }
|
||||||
| { namespace: string, name: string }
|
| { namespace: string; name: string }
|
||||||
| { namespace: string, name: string, route: string };
|
| { namespace: string; name: string; route: string };
|
||||||
|
|
||||||
interface EndpointQuery {
|
interface EndpointQuery {
|
||||||
all?: boolean;
|
all?: boolean;
|
||||||
@ -163,13 +163,13 @@ interface HelmReleaseDto {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface HelmRelease extends HelmReleaseDto, ItemObject {
|
export interface HelmRelease extends HelmReleaseDto, ItemObject {
|
||||||
getNs: () => string
|
getNs: () => string;
|
||||||
getChart: (withVersion?: boolean) => string
|
getChart: (withVersion?: boolean) => string;
|
||||||
getRevision: () => number
|
getRevision: () => number;
|
||||||
getStatus: () => string
|
getStatus: () => string;
|
||||||
getVersion: () => string
|
getVersion: () => string;
|
||||||
getUpdated: (humanize?: boolean, compact?: boolean) => string | number
|
getUpdated: (humanize?: boolean, compact?: boolean) => string | number;
|
||||||
getRepo: () => Promise<string>
|
getRepo: () => Promise<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const toHelmRelease = (release: HelmReleaseDto) : HelmRelease => ({
|
const toHelmRelease = (release: HelmReleaseDto) : HelmRelease => ({
|
||||||
|
|||||||
@ -58,7 +58,7 @@ export interface IIngressService {
|
|||||||
port: {
|
port: {
|
||||||
name?: string;
|
name?: string;
|
||||||
number?: number;
|
number?: number;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getBackendServiceNamePort = (backend: IIngressBackend) => {
|
export const getBackendServiceNamePort = (backend: IIngressBackend) => {
|
||||||
@ -96,8 +96,8 @@ export interface Ingress {
|
|||||||
apiGroup: string;
|
apiGroup: string;
|
||||||
kind: string;
|
kind: string;
|
||||||
name: string;
|
name: string;
|
||||||
}
|
};
|
||||||
}>
|
}>;
|
||||||
};
|
};
|
||||||
status: {
|
status: {
|
||||||
loadBalancer: {
|
loadBalancer: {
|
||||||
|
|||||||
@ -33,7 +33,7 @@ export enum LimitPart {
|
|||||||
type LimitRangeParts = Partial<Record<LimitPart, Record<string, string>>>;
|
type LimitRangeParts = Partial<Record<LimitPart, Record<string, string>>>;
|
||||||
|
|
||||||
export interface LimitRangeItem extends LimitRangeParts {
|
export interface LimitRangeItem extends LimitRangeParts {
|
||||||
type: string
|
type: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LimitRange {
|
export interface LimitRange {
|
||||||
|
|||||||
@ -101,8 +101,8 @@ export interface Node {
|
|||||||
daemonEndpoints?: {
|
daemonEndpoints?: {
|
||||||
kubeletEndpoint: {
|
kubeletEndpoint: {
|
||||||
Port: number; //it must be uppercase for backwards compatibility
|
Port: number; //it must be uppercase for backwards compatibility
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
nodeInfo?: {
|
nodeInfo?: {
|
||||||
machineID: string;
|
machineID: string;
|
||||||
systemUUID: string;
|
systemUUID: string;
|
||||||
|
|||||||
@ -16,10 +16,10 @@ export interface PodDisruptionBudget {
|
|||||||
selector: LabelSelector;
|
selector: LabelSelector;
|
||||||
};
|
};
|
||||||
status: {
|
status: {
|
||||||
currentHealthy: number
|
currentHealthy: number;
|
||||||
desiredHealthy: number
|
desiredHealthy: number;
|
||||||
disruptionsAllowed: number
|
disruptionsAllowed: number;
|
||||||
expectedPods: number
|
expectedPods: number;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -43,9 +43,9 @@ export interface IPodMetrics<T = IMetrics> {
|
|||||||
[metric: string]: T;
|
[metric: string]: T;
|
||||||
cpuUsage: T;
|
cpuUsage: T;
|
||||||
memoryUsage: T;
|
memoryUsage: T;
|
||||||
fsUsage: T,
|
fsUsage: T;
|
||||||
fsWrites: T,
|
fsWrites: T;
|
||||||
fsReads: T,
|
fsReads: T;
|
||||||
networkReceive: T;
|
networkReceive: T;
|
||||||
networkTransmit: T;
|
networkTransmit: T;
|
||||||
cpuRequests?: T;
|
cpuRequests?: T;
|
||||||
@ -117,7 +117,7 @@ export interface IPodContainer extends Partial<Record<PodContainerProbe, IContai
|
|||||||
};
|
};
|
||||||
secretRef?: {
|
secretRef?: {
|
||||||
name: string;
|
name: string;
|
||||||
}
|
};
|
||||||
}[];
|
}[];
|
||||||
volumeMounts?: {
|
volumeMounts?: {
|
||||||
name: string;
|
name: string;
|
||||||
@ -273,7 +273,7 @@ export class Pod extends WorkloadKubeObject {
|
|||||||
hostIP: string;
|
hostIP: string;
|
||||||
podIP: string;
|
podIP: string;
|
||||||
podIPs?: {
|
podIPs?: {
|
||||||
ip: string
|
ip: string;
|
||||||
}[];
|
}[];
|
||||||
startTime: string;
|
startTime: string;
|
||||||
initContainerStatuses?: IPodContainerStatus[];
|
initContainerStatuses?: IPodContainerStatus[];
|
||||||
|
|||||||
@ -88,7 +88,7 @@ export interface KubeApiListOptions {
|
|||||||
export interface IKubePreferredVersion {
|
export interface IKubePreferredVersion {
|
||||||
preferredVersion?: {
|
preferredVersion?: {
|
||||||
version: string;
|
version: string;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IKubeResourceList {
|
export interface IKubeResourceList {
|
||||||
@ -105,7 +105,7 @@ export interface IKubeResourceList {
|
|||||||
export interface ILocalKubeApiConfig {
|
export interface ILocalKubeApiConfig {
|
||||||
metadata: {
|
metadata: {
|
||||||
uid: string;
|
uid: string;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PropagationPolicy = undefined | "Orphan" | "Foreground" | "Background";
|
export type PropagationPolicy = undefined | "Orphan" | "Foreground" | "Background";
|
||||||
@ -116,7 +116,7 @@ export type PropagationPolicy = undefined | "Orphan" | "Foreground" | "Backgroun
|
|||||||
export interface IKubeApiCluster extends ILocalKubeApiConfig { }
|
export interface IKubeApiCluster extends ILocalKubeApiConfig { }
|
||||||
|
|
||||||
export type PartialKubeObject<T extends KubeObject> = Partial<Omit<T, "metadata">> & {
|
export type PartialKubeObject<T extends KubeObject> = Partial<Omit<T, "metadata">> & {
|
||||||
metadata?: Partial<T["metadata"]>,
|
metadata?: Partial<T["metadata"]>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface IRemoteKubeApiConfig {
|
export interface IRemoteKubeApiConfig {
|
||||||
@ -124,12 +124,12 @@ export interface IRemoteKubeApiConfig {
|
|||||||
server: string;
|
server: string;
|
||||||
caData?: string;
|
caData?: string;
|
||||||
skipTLSVerify?: boolean;
|
skipTLSVerify?: boolean;
|
||||||
}
|
};
|
||||||
user: {
|
user: {
|
||||||
token?: string | (() => Promise<string>);
|
token?: string | (() => Promise<string>);
|
||||||
clientCertificateData?: string;
|
clientCertificateData?: string;
|
||||||
clientKeyData?: string;
|
clientKeyData?: string;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function forCluster<T extends KubeObject, Y extends KubeApi<T> = KubeApi<T>>(cluster: ILocalKubeApiConfig, kubeClass: KubeObjectConstructor<T>, apiClass: new (apiOpts: IKubeApiOptions<T>) => Y = null): KubeApi<T> {
|
export function forCluster<T extends KubeObject, Y extends KubeApi<T> = KubeApi<T>>(cluster: ILocalKubeApiConfig, kubeClass: KubeObjectConstructor<T>, apiClass: new (apiOpts: IKubeApiOptions<T>) => Y = null): KubeApi<T> {
|
||||||
@ -219,7 +219,7 @@ export type KubeApiWatchCallback = (data: IKubeWatchEvent<KubeJsonApiData>, erro
|
|||||||
export type KubeApiWatchOptions = {
|
export type KubeApiWatchOptions = {
|
||||||
namespace: string;
|
namespace: string;
|
||||||
callback?: KubeApiWatchCallback;
|
callback?: KubeApiWatchCallback;
|
||||||
abortController?: AbortController
|
abortController?: AbortController;
|
||||||
watchId?: string;
|
watchId?: string;
|
||||||
retry?: boolean;
|
retry?: boolean;
|
||||||
|
|
||||||
|
|||||||
@ -247,7 +247,7 @@ export abstract class KubeObjectStore<T extends KubeObject> extends ItemStore<T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
async reloadAll(opts: { force?: boolean, namespaces?: string[], merge?: boolean } = {}) {
|
async reloadAll(opts: { force?: boolean; namespaces?: string[]; merge?: boolean } = {}) {
|
||||||
const { force = false, ...loadingOptions } = opts;
|
const { force = false, ...loadingOptions } = opts;
|
||||||
|
|
||||||
if (this.isLoading || (this.isLoaded && !force)) {
|
if (this.isLoading || (this.isLoaded && !force)) {
|
||||||
|
|||||||
@ -147,7 +147,7 @@ export function loadConfigFromString(content: string): ConfigResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface SplitConfigEntry {
|
export interface SplitConfigEntry {
|
||||||
config: KubeConfig,
|
config: KubeConfig;
|
||||||
error?: string;
|
error?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -63,8 +63,8 @@ export function foldAttemptResults(mainAttempt: RouteAttempt, rendererAttempt: R
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
extensionLoader: ExtensionLoader
|
extensionLoader: ExtensionLoader;
|
||||||
extensionsStore: ExtensionsStore
|
extensionsStore: ExtensionsStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class LensProtocolRouter {
|
export abstract class LensProtocolRouter {
|
||||||
|
|||||||
@ -327,7 +327,7 @@ export type ExtensionRegistry = {
|
|||||||
location: ExtensionRegistryLocation.DEFAULT | ExtensionRegistryLocation.NPMRC;
|
location: ExtensionRegistryLocation.DEFAULT | ExtensionRegistryLocation.NPMRC;
|
||||||
customUrl?: undefined;
|
customUrl?: undefined;
|
||||||
} | {
|
} | {
|
||||||
location: ExtensionRegistryLocation.CUSTOM,
|
location: ExtensionRegistryLocation.CUSTOM;
|
||||||
customUrl: string;
|
customUrl: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -5,13 +5,13 @@
|
|||||||
|
|
||||||
import { app, ipcMain } from "electron";
|
import { app, ipcMain } from "electron";
|
||||||
import semver, { SemVer } from "semver";
|
import semver, { SemVer } from "semver";
|
||||||
import { action, computed, makeObservable, observable, reaction } from "mobx";
|
import { action, computed, observable, reaction, makeObservable, isObservableArray, isObservableSet, isObservableMap } from "mobx";
|
||||||
import { BaseStore } from "../base-store";
|
import { BaseStore } from "../base-store";
|
||||||
import migrations, { fileNameMigration } from "../../migrations/user-store";
|
import migrations, { fileNameMigration } from "../../migrations/user-store";
|
||||||
import { getAppVersion } from "../utils/app-version";
|
import { getAppVersion } from "../utils/app-version";
|
||||||
import { kubeConfigDefaultPath } from "../kube-helpers";
|
import { kubeConfigDefaultPath } from "../kube-helpers";
|
||||||
import { appEventBus } from "../app-event-bus/event-bus";
|
import { appEventBus } from "../app-event-bus/event-bus";
|
||||||
import { getOrInsertSet, toggle, toJS } from "../../renderer/utils";
|
import { getOrInsertSet, toggle, toJS, entries, fromEntries } from "../../renderer/utils";
|
||||||
import { DESCRIPTORS } from "./preferences-helpers";
|
import { DESCRIPTORS } from "./preferences-helpers";
|
||||||
import type { EditorConfiguration, ExtensionRegistry, KubeconfigSyncValue, UserPreferencesModel, TerminalConfig } from "./preferences-helpers";
|
import type { EditorConfiguration, ExtensionRegistry, KubeconfigSyncValue, UserPreferencesModel, TerminalConfig } from "./preferences-helpers";
|
||||||
import logger from "../../main/logger";
|
import logger from "../../main/logger";
|
||||||
@ -165,55 +165,31 @@ export class UserStore extends BaseStore<UserStoreModel> /* implements UserStore
|
|||||||
this.lastSeenAppVersion = lastSeenAppVersion;
|
this.lastSeenAppVersion = lastSeenAppVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.httpsProxy = DESCRIPTORS.httpsProxy.fromStore(preferences?.httpsProxy);
|
for (const [key, { fromStore }] of entries(DESCRIPTORS)) {
|
||||||
this.shell = DESCRIPTORS.shell.fromStore(preferences?.shell);
|
const curVal = this[key];
|
||||||
this.colorTheme = DESCRIPTORS.colorTheme.fromStore(preferences?.colorTheme);
|
const newVal = fromStore((preferences)?.[key] as never) as never;
|
||||||
this.terminalTheme = DESCRIPTORS.terminalTheme.fromStore(preferences?.terminalTheme);
|
|
||||||
this.localeTimezone = DESCRIPTORS.localeTimezone.fromStore(preferences?.localeTimezone);
|
if (
|
||||||
this.allowUntrustedCAs = DESCRIPTORS.allowUntrustedCAs.fromStore(preferences?.allowUntrustedCAs);
|
isObservableArray(curVal)
|
||||||
this.allowTelemetry = DESCRIPTORS.allowTelemetry.fromStore(preferences?.allowTelemetry);
|
|| isObservableSet(curVal)
|
||||||
this.allowErrorReporting = DESCRIPTORS.allowErrorReporting.fromStore(preferences?.allowErrorReporting);
|
|| isObservableMap(curVal)
|
||||||
this.downloadMirror = DESCRIPTORS.downloadMirror.fromStore(preferences?.downloadMirror);
|
) {
|
||||||
this.downloadKubectlBinaries = DESCRIPTORS.downloadKubectlBinaries.fromStore(preferences?.downloadKubectlBinaries);
|
curVal.replace(newVal);
|
||||||
this.downloadBinariesPath = DESCRIPTORS.downloadBinariesPath.fromStore(preferences?.downloadBinariesPath);
|
} else {
|
||||||
this.kubectlBinariesPath = DESCRIPTORS.kubectlBinariesPath.fromStore(preferences?.kubectlBinariesPath);
|
this[key] = newVal;
|
||||||
this.openAtLogin = DESCRIPTORS.openAtLogin.fromStore(preferences?.openAtLogin);
|
}
|
||||||
this.hiddenTableColumns.replace(DESCRIPTORS.hiddenTableColumns.fromStore(preferences?.hiddenTableColumns));
|
}
|
||||||
this.syncKubeconfigEntries.replace(DESCRIPTORS.syncKubeconfigEntries.fromStore(preferences?.syncKubeconfigEntries));
|
|
||||||
this.editorConfiguration = DESCRIPTORS.editorConfiguration.fromStore(preferences?.editorConfiguration);
|
|
||||||
this.terminalCopyOnSelect = DESCRIPTORS.terminalCopyOnSelect.fromStore(preferences?.terminalCopyOnSelect);
|
|
||||||
this.terminalConfig = DESCRIPTORS.terminalConfig.fromStore(preferences?.terminalConfig);
|
|
||||||
this.updateChannel = DESCRIPTORS.updateChannel.fromStore(preferences?.updateChannel);
|
|
||||||
this.extensionRegistryUrl = DESCRIPTORS.extensionRegistryUrl.fromStore(preferences?.extensionRegistryUrl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toJSON(): UserStoreModel {
|
toJSON(): UserStoreModel {
|
||||||
const model: UserStoreModel = {
|
const preferences = fromEntries(
|
||||||
lastSeenAppVersion: this.lastSeenAppVersion,
|
entries(DESCRIPTORS)
|
||||||
preferences: {
|
.map(([key, { toStore }]) => [key, toStore(this[key] as never)]),
|
||||||
httpsProxy: DESCRIPTORS.httpsProxy.toStore(this.httpsProxy),
|
) as UserPreferencesModel;
|
||||||
shell: DESCRIPTORS.shell.toStore(this.shell),
|
|
||||||
colorTheme: DESCRIPTORS.colorTheme.toStore(this.colorTheme),
|
|
||||||
terminalTheme: DESCRIPTORS.terminalTheme.toStore(this.terminalTheme),
|
|
||||||
localeTimezone: DESCRIPTORS.localeTimezone.toStore(this.localeTimezone),
|
|
||||||
allowUntrustedCAs: DESCRIPTORS.allowUntrustedCAs.toStore(this.allowUntrustedCAs),
|
|
||||||
allowTelemetry: DESCRIPTORS.allowTelemetry.toStore(this.allowTelemetry),
|
|
||||||
allowErrorReporting: DESCRIPTORS.allowErrorReporting.toStore(this.allowErrorReporting),
|
|
||||||
downloadMirror: DESCRIPTORS.downloadMirror.toStore(this.downloadMirror),
|
|
||||||
downloadKubectlBinaries: DESCRIPTORS.downloadKubectlBinaries.toStore(this.downloadKubectlBinaries),
|
|
||||||
downloadBinariesPath: DESCRIPTORS.downloadBinariesPath.toStore(this.downloadBinariesPath),
|
|
||||||
kubectlBinariesPath: DESCRIPTORS.kubectlBinariesPath.toStore(this.kubectlBinariesPath),
|
|
||||||
openAtLogin: DESCRIPTORS.openAtLogin.toStore(this.openAtLogin),
|
|
||||||
hiddenTableColumns: DESCRIPTORS.hiddenTableColumns.toStore(this.hiddenTableColumns),
|
|
||||||
syncKubeconfigEntries: DESCRIPTORS.syncKubeconfigEntries.toStore(this.syncKubeconfigEntries),
|
|
||||||
editorConfiguration: DESCRIPTORS.editorConfiguration.toStore(this.editorConfiguration),
|
|
||||||
terminalCopyOnSelect: DESCRIPTORS.terminalCopyOnSelect.toStore(this.terminalCopyOnSelect),
|
|
||||||
terminalConfig: DESCRIPTORS.terminalConfig.toStore(this.terminalConfig),
|
|
||||||
updateChannel: DESCRIPTORS.updateChannel.toStore(this.updateChannel),
|
|
||||||
extensionRegistryUrl: DESCRIPTORS.extensionRegistryUrl.toStore(this.extensionRegistryUrl),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
return toJS(model);
|
return toJS({
|
||||||
|
lastSeenAppVersion: this.lastSeenAppVersion,
|
||||||
|
preferences,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,8 +21,8 @@ export function getOrInsert<K, V>(map: Map<K, V>, key: K, value: V): V {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Like `getOrInsert` but specifically for when `V` is `Map<any, any>` so that
|
* Like `getOrInsert` but specifically for when `V` is `Map<MK, MV>` so that
|
||||||
* the typings are inferred.
|
* the typings are inferred correctly.
|
||||||
*/
|
*/
|
||||||
export function getOrInsertMap<K, MK, MV>(map: Map<K, Map<MK, MV>>, key: K): Map<MK, MV> {
|
export function getOrInsertMap<K, MK, MV>(map: Map<K, Map<MK, MV>>, key: K): Map<MK, MV> {
|
||||||
return getOrInsert(map, key, new Map<MK, MV>());
|
return getOrInsert(map, key, new Map<MK, MV>());
|
||||||
@ -37,11 +37,39 @@ export function getOrInsertSet<K, SK>(map: Map<K, Set<SK>>, key: K): Set<SK> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Like `getOrInsert` but with delayed creation of the item
|
* Like `getOrInsert` but with delayed creation of the item. Which is useful
|
||||||
|
* if it is very expensive to create the initial value.
|
||||||
*/
|
*/
|
||||||
export function getOrInsertWith<K, V>(map: Map<K, V>, key: K, value: () => V): V {
|
export function getOrInsertWith<K, V>(map: Map<K, V>, key: K, builder: () => V): V {
|
||||||
if (!map.has(key)) {
|
if (!map.has(key)) {
|
||||||
map.set(key, value());
|
map.set(key, builder());
|
||||||
|
}
|
||||||
|
|
||||||
|
return map.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the value associated with `key` iff there was not a previous value
|
||||||
|
* @param map The map to interact with
|
||||||
|
* @throws if `key` already in map
|
||||||
|
* @returns `this` so that `strictSet` can be chained
|
||||||
|
*/
|
||||||
|
export function strictSet<K, V>(map: Map<K, V>, key: K, val: V): typeof map {
|
||||||
|
if (map.has(key)) {
|
||||||
|
throw new TypeError("Duplicate key in map");
|
||||||
|
}
|
||||||
|
|
||||||
|
return map.set(key, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value associated with `key`
|
||||||
|
* @param map The map to interact with
|
||||||
|
* @throws if `key` did not a value associated with it
|
||||||
|
*/
|
||||||
|
export function strictGet<K, V>(map: Map<K, V>, key: K): V {
|
||||||
|
if (!map.has(key)) {
|
||||||
|
throw new TypeError("key not in map");
|
||||||
}
|
}
|
||||||
|
|
||||||
return map.get(key);
|
return map.get(key);
|
||||||
|
|||||||
@ -1,70 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { action, ObservableMap, runInAction } from "mobx";
|
|
||||||
|
|
||||||
export function multiSet<T, V>(map: Map<T, V>, newEntries: [T, V][]): void {
|
|
||||||
runInAction(() => {
|
|
||||||
for (const [key, val] of newEntries) {
|
|
||||||
map.set(key, val);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ExtendedMap<K, V> extends Map<K, V> {
|
|
||||||
static new<K, V>(entries?: readonly (readonly [K, V])[] | null): ExtendedMap<K, V> {
|
|
||||||
return new ExtendedMap<K, V>(entries);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the value behind `key`. If it was not present, first insert the value returned by `getVal`
|
|
||||||
* @param key The key to insert into the map with
|
|
||||||
* @param getVal A function that returns a new instance of `V`.
|
|
||||||
* @returns The value in the map
|
|
||||||
*/
|
|
||||||
getOrInsert(key: K, getVal: () => V): V {
|
|
||||||
if (this.has(key)) {
|
|
||||||
return this.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.set(key, getVal()).get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the value associated with `key` iff there was not a previous value
|
|
||||||
* @throws if `key` already in map
|
|
||||||
* @returns `this` so that `strictSet` can be chained
|
|
||||||
*/
|
|
||||||
strictSet(key: K, val: V): this {
|
|
||||||
if (this.has(key)) {
|
|
||||||
throw new TypeError("Duplicate key in map");
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.set(key, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the value associated with `key`
|
|
||||||
* @throws if `key` did not a value associated with it
|
|
||||||
*/
|
|
||||||
strictGet(key: K): V {
|
|
||||||
if (!this.has(key)) {
|
|
||||||
throw new TypeError("key not in map");
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.get(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ExtendedObservableMap<K, V> extends ObservableMap<K, V> {
|
|
||||||
@action
|
|
||||||
getOrInsert(key: K, getVal: () => V): V {
|
|
||||||
if (this.has(key)) {
|
|
||||||
return this.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.set(key, getVal()).get(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -25,13 +25,12 @@ export * from "./delay";
|
|||||||
export * from "./disposer";
|
export * from "./disposer";
|
||||||
export * from "./downloadFile";
|
export * from "./downloadFile";
|
||||||
export * from "./escapeRegExp";
|
export * from "./escapeRegExp";
|
||||||
export * from "./extended-map";
|
|
||||||
export * from "./formatDuration";
|
export * from "./formatDuration";
|
||||||
export * from "./getRandId";
|
export * from "./getRandId";
|
||||||
export * from "./hash-set";
|
export * from "./hash-set";
|
||||||
export * from "./n-fircate";
|
export * from "./n-fircate";
|
||||||
export * from "./objects";
|
export * from "./objects";
|
||||||
export * from "./openExternal";
|
export * from "./openBrowser";
|
||||||
export * from "./paths";
|
export * from "./paths";
|
||||||
export * from "./promise-exec";
|
export * from "./promise-exec";
|
||||||
export * from "./reject-promise";
|
export * from "./reject-promise";
|
||||||
|
|||||||
@ -7,6 +7,10 @@
|
|||||||
* A better typed version of `Object.fromEntries` where the keys are known to
|
* A better typed version of `Object.fromEntries` where the keys are known to
|
||||||
* be a specific subset
|
* be a specific subset
|
||||||
*/
|
*/
|
||||||
export function fromEntries<T, Key extends string>(entries: Iterable<readonly [Key, T]>): { [k in Key]: T } {
|
export function fromEntries<T, Key extends string>(entries: Iterable<readonly [Key, T]>): Record<Key, T> {
|
||||||
return Object.fromEntries(entries) as { [k in Key]: T };
|
return Object.fromEntries(entries) as { [k in Key]: T };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function entries<T extends Record<string, any>>(obj: T): [keyof T, T[keyof T]][] {
|
||||||
|
return Object.entries(obj);
|
||||||
|
}
|
||||||
|
|||||||
29
src/common/utils/openBrowser.ts
Normal file
29
src/common/utils/openBrowser.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { shell } from "electron";
|
||||||
|
|
||||||
|
const allowedProtocols = new Set(["http:", "https:"]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens a link using the program configured as the default browser
|
||||||
|
* on the target platform. Will reject URLs with a scheme other than
|
||||||
|
* http or https to prevent programs other than the default browser
|
||||||
|
* running.
|
||||||
|
*
|
||||||
|
* @param url The URL to open
|
||||||
|
*/
|
||||||
|
export function openBrowser(url: string): Promise<void> {
|
||||||
|
if (allowedProtocols.has(new URL(url).protocol)) {
|
||||||
|
return shell.openExternal(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.reject(new TypeError("not an http(s) URL"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use openBrowser
|
||||||
|
*/
|
||||||
|
export const openExternal = openBrowser;
|
||||||
@ -1,11 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Opens a link in external browser
|
|
||||||
import { shell } from "electron";
|
|
||||||
|
|
||||||
export function openExternal(url: string) {
|
|
||||||
return shell.openExternal(url);
|
|
||||||
}
|
|
||||||
@ -3,6 +3,6 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export { Singleton, openExternal } from "../../common/utils";
|
export { Singleton, openExternal, openBrowser } from "../../common/utils";
|
||||||
export { prevDefault, stopPropagation } from "../../renderer/utils/prevDefault";
|
export { prevDefault, stopPropagation } from "../../renderer/utils/prevDefault";
|
||||||
export { cssNames } from "../../renderer/utils/cssNames";
|
export { cssNames } from "../../renderer/utils/cssNames";
|
||||||
|
|||||||
@ -32,7 +32,7 @@ interface Dependencies {
|
|||||||
isCompatibleExtension: (manifest: LensExtensionManifest) => boolean;
|
isCompatibleExtension: (manifest: LensExtensionManifest) => boolean;
|
||||||
|
|
||||||
installExtension: (name: string) => Promise<void>;
|
installExtension: (name: string) => Promise<void>;
|
||||||
installExtensions: (packageJsonPath: string, packagesJson: PackageJson) => Promise<void>
|
installExtensions: (packageJsonPath: string, packagesJson: PackageJson) => Promise<void>;
|
||||||
extensionPackageRootDirectory: string;
|
extensionPackageRootDirectory: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import type { PackageJson } from "type-fest";
|
|||||||
const logModule = "[EXTENSION-INSTALLER]";
|
const logModule = "[EXTENSION-INSTALLER]";
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
extensionPackageRootDirectory: string
|
extensionPackageRootDirectory: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -17,7 +17,7 @@ interface FSProvisionModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
directoryForExtensionData: string
|
directoryForExtensionData: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FileSystemProvisionerStore extends BaseStore<FSProvisionModel> {
|
export class FileSystemProvisionerStore extends BaseStore<FSProvisionModel> {
|
||||||
|
|||||||
@ -23,13 +23,13 @@ import { requestExtensionLoaderInitialState } from "../../renderer/ipc";
|
|||||||
const logModule = "[EXTENSIONS-LOADER]";
|
const logModule = "[EXTENSIONS-LOADER]";
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
updateExtensionsState: (extensionsState: Record<LensExtensionId, LensExtensionState>) => void
|
updateExtensionsState: (extensionsState: Record<LensExtensionId, LensExtensionState>) => void;
|
||||||
createExtensionInstance: (ExtensionClass: LensExtensionConstructor, extension: InstalledExtension) => LensExtension,
|
createExtensionInstance: (ExtensionClass: LensExtensionConstructor, extension: InstalledExtension) => LensExtension;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExtensionLoading {
|
export interface ExtensionLoading {
|
||||||
isBundled: boolean,
|
isBundled: boolean;
|
||||||
loaded: Promise<void>
|
loaded: Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -36,7 +36,7 @@ export class ExtensionsStore extends BaseStore<LensExtensionsStoreModel> {
|
|||||||
|
|
||||||
protected state = observable.map<LensExtensionId, LensExtensionState>();
|
protected state = observable.map<LensExtensionId, LensExtensionState>();
|
||||||
|
|
||||||
isEnabled({ id, isBundled }: { id: string, isBundled: boolean }): boolean {
|
isEnabled({ id, isBundled }: { id: string; isBundled: boolean }): boolean {
|
||||||
// By default false, so that copied extensions are disabled by default.
|
// By default false, so that copied extensions are disabled by default.
|
||||||
// If user installs the extension from the UI, the Extensions component will specifically enable it.
|
// If user installs the extension from the UI, the Extensions component will specifically enable it.
|
||||||
return isBundled || Boolean(this.state.get(id)?.enabled);
|
return isBundled || Boolean(this.state.get(id)?.enabled);
|
||||||
|
|||||||
@ -10,5 +10,5 @@ import type { FileSystemProvisionerStore } from "./extension-loader/create-exten
|
|||||||
export const setLensExtensionDependencies = Symbol("set-lens-extension-dependencies");
|
export const setLensExtensionDependencies = Symbol("set-lens-extension-dependencies");
|
||||||
|
|
||||||
export interface LensExtensionDependencies {
|
export interface LensExtensionDependencies {
|
||||||
fileSystemProvisionerStore: FileSystemProvisionerStore
|
fileSystemProvisionerStore: FileSystemProvisionerStore;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,7 +38,7 @@ export interface PageParams<V = any> {
|
|||||||
export interface PageComponentProps<P extends PageParams = {}> {
|
export interface PageComponentProps<P extends PageParams = {}> {
|
||||||
params?: {
|
params?: {
|
||||||
[N in keyof P]: PageParam<P[N]>;
|
[N in keyof P]: PageParam<P[N]>;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RegisteredPage {
|
export interface RegisteredPage {
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import { pathNames, PathName } from "../../common/app-paths/app-path-names";
|
|||||||
import type { AppPaths } from "../../common/app-paths/app-path-injection-token";
|
import type { AppPaths } from "../../common/app-paths/app-path-injection-token";
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
getAppPath: (name: PathName) => string
|
getAppPath: (name: PathName) => string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getAppPaths = ({ getAppPath }: Dependencies) =>
|
export const getAppPaths = ({ getAppPath }: Dependencies) =>
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import { FSWatcher, watch } from "chokidar";
|
|||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import type stream from "stream";
|
import type stream from "stream";
|
||||||
import { bytesToUnits, Disposer, ExtendedObservableMap, iter, noop } from "../../../common/utils";
|
import { bytesToUnits, Disposer, getOrInsertWith, iter, noop } from "../../../common/utils";
|
||||||
import logger from "../../logger";
|
import logger from "../../logger";
|
||||||
import type { KubeConfig } from "@kubernetes/client-node";
|
import type { KubeConfig } from "@kubernetes/client-node";
|
||||||
import { loadConfigFromString, splitConfig } from "../../../common/kube-helpers";
|
import { loadConfigFromString, splitConfig } from "../../../common/kube-helpers";
|
||||||
@ -48,8 +48,8 @@ const folderSyncMaxAllowedFileReadSize = 2 * 1024 * 1024; // 2 MiB
|
|||||||
const fileSyncMaxAllowedFileReadSize = 16 * folderSyncMaxAllowedFileReadSize; // 32 MiB
|
const fileSyncMaxAllowedFileReadSize = 16 * folderSyncMaxAllowedFileReadSize; // 32 MiB
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
directoryForKubeConfigs: string
|
directoryForKubeConfigs: string;
|
||||||
createCluster: (model: ClusterModel) => Cluster
|
createCluster: (model: ClusterModel) => Cluster;
|
||||||
}
|
}
|
||||||
|
|
||||||
const kubeConfigSyncName = "lens:kube-sync";
|
const kubeConfigSyncName = "lens:kube-sync";
|
||||||
@ -294,7 +294,7 @@ const diffChangedConfigFor = (dependencies: Dependencies) => ({ filePath, source
|
|||||||
};
|
};
|
||||||
|
|
||||||
const watchFileChanges = (filePath: string, dependencies: Dependencies): [IComputedValue<CatalogEntity[]>, Disposer] => {
|
const watchFileChanges = (filePath: string, dependencies: Dependencies): [IComputedValue<CatalogEntity[]>, Disposer] => {
|
||||||
const rootSource = new ExtendedObservableMap<string, ObservableMap<string, RootSourceValue>>();
|
const rootSource = observable.map<string, ObservableMap<string, RootSourceValue>>();
|
||||||
const derivedSource = computed(() => Array.from(iter.flatMap(rootSource.values(), from => iter.map(from.values(), child => child[1]))));
|
const derivedSource = computed(() => Array.from(iter.flatMap(rootSource.values(), from => iter.map(from.values(), child => child[1]))));
|
||||||
|
|
||||||
let watcher: FSWatcher;
|
let watcher: FSWatcher;
|
||||||
@ -335,7 +335,7 @@ const watchFileChanges = (filePath: string, dependencies: Dependencies): [ICompu
|
|||||||
cleanup();
|
cleanup();
|
||||||
cleanupFns.set(childFilePath, diffChangedConfig({
|
cleanupFns.set(childFilePath, diffChangedConfig({
|
||||||
filePath: childFilePath,
|
filePath: childFilePath,
|
||||||
source: rootSource.getOrInsert(childFilePath, observable.map),
|
source: getOrInsertWith(rootSource, childFilePath, observable.map),
|
||||||
stats,
|
stats,
|
||||||
maxAllowedFileReadSize,
|
maxAllowedFileReadSize,
|
||||||
}));
|
}));
|
||||||
@ -353,7 +353,7 @@ const watchFileChanges = (filePath: string, dependencies: Dependencies): [ICompu
|
|||||||
|
|
||||||
cleanupFns.set(childFilePath, diffChangedConfig({
|
cleanupFns.set(childFilePath, diffChangedConfig({
|
||||||
filePath: childFilePath,
|
filePath: childFilePath,
|
||||||
source: rootSource.getOrInsert(childFilePath, observable.map),
|
source: getOrInsertWith(rootSource, childFilePath, observable.map),
|
||||||
stats,
|
stats,
|
||||||
maxAllowedFileReadSize,
|
maxAllowedFileReadSize,
|
||||||
}));
|
}));
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { action, computed, type IComputedValue, type IObservableArray, makeObservable, observable } from "mobx";
|
import { action, computed, IComputedValue, IObservableArray, makeObservable, observable } from "mobx";
|
||||||
import { CatalogCategoryRegistry, catalogCategoryRegistry, CatalogEntity, CatalogEntityConstructor } from "../../common/catalog";
|
import { CatalogCategoryRegistry, catalogCategoryRegistry, CatalogEntity, CatalogEntityConstructor } from "../../common/catalog";
|
||||||
import { iter } from "../../common/utils";
|
import { iter } from "../../common/utils";
|
||||||
|
|
||||||
|
|||||||
@ -8,8 +8,8 @@ import type { Cluster } from "../../common/cluster/cluster";
|
|||||||
import { k8sRequest } from "../k8s-request";
|
import { k8sRequest } from "../k8s-request";
|
||||||
|
|
||||||
export type ClusterDetectionResult = {
|
export type ClusterDetectionResult = {
|
||||||
value: string | number | boolean
|
value: string | number | boolean;
|
||||||
accuracy: number
|
accuracy: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class BaseClusterDetector {
|
export class BaseClusterDetector {
|
||||||
|
|||||||
@ -26,7 +26,7 @@ interface PrometheusServicePreferences {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
createKubeAuthProxy: (cluster: Cluster, environmentVariables: NodeJS.ProcessEnv) => KubeAuthProxy
|
createKubeAuthProxy: (cluster: Cluster, environmentVariables: NodeJS.ProcessEnv) => KubeAuthProxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ContextHandler {
|
export class ContextHandler {
|
||||||
|
|||||||
@ -14,8 +14,8 @@ import type { RepoHelmChartList } from "../../common/k8s-api/endpoints/helm-char
|
|||||||
import { iter, sortCharts } from "../../common/utils";
|
import { iter, sortCharts } from "../../common/utils";
|
||||||
|
|
||||||
interface ChartCacheEntry {
|
interface ChartCacheEntry {
|
||||||
data: Buffer,
|
data: Buffer;
|
||||||
mtimeMs: number,
|
mtimeMs: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HelmCacheFile {
|
export interface HelmCacheFile {
|
||||||
|
|||||||
@ -104,10 +104,8 @@ export async function upgradeRelease(name: string, chart: string, values: any, n
|
|||||||
];
|
];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const output = await execHelm(args);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
log: output,
|
log: await execHelm(args),
|
||||||
release: getRelease(name, namespace, kubeconfigPath, kubectlPath),
|
release: getRelease(name, namespace, kubeconfigPath, kubectlPath),
|
||||||
};
|
};
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@ -19,19 +19,19 @@ export type HelmEnv = Record<string, string> & {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export interface HelmRepoConfig {
|
export interface HelmRepoConfig {
|
||||||
repositories: HelmRepo[]
|
repositories: HelmRepo[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HelmRepo {
|
export interface HelmRepo {
|
||||||
name: string;
|
name: string;
|
||||||
url: string;
|
url: string;
|
||||||
cacheFilePath?: string
|
cacheFilePath?: string;
|
||||||
caFile?: string,
|
caFile?: string;
|
||||||
certFile?: string,
|
certFile?: string;
|
||||||
insecureSkipTlsVerify?: boolean,
|
insecureSkipTlsVerify?: boolean;
|
||||||
keyFile?: string,
|
keyFile?: string;
|
||||||
username?: string,
|
username?: string;
|
||||||
password?: string,
|
password?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function execHelm(args: string[], options?: BaseEncodingOptions & ExecFileOptions): Promise<string> {
|
async function execHelm(args: string[], options?: BaseEncodingOptions & ExecFileOptions): Promise<string> {
|
||||||
@ -49,9 +49,9 @@ async function execHelm(args: string[], options?: BaseEncodingOptions & ExecFile
|
|||||||
export class HelmRepoManager extends Singleton {
|
export class HelmRepoManager extends Singleton {
|
||||||
protected repos: HelmRepo[];
|
protected repos: HelmRepo[];
|
||||||
protected helmEnv: HelmEnv;
|
protected helmEnv: HelmEnv;
|
||||||
protected initialized: boolean;
|
protected didUpdateOnce: boolean;
|
||||||
|
|
||||||
public static async loadAvailableRepos(): Promise<HelmRepo[]> {
|
public async loadAvailableRepos(): Promise<HelmRepo[]> {
|
||||||
const res = await customRequestPromise({
|
const res = await customRequestPromise({
|
||||||
uri: "https://github.com/lensapp/artifact-hub-repositories/releases/download/latest/repositories.json",
|
uri: "https://github.com/lensapp/artifact-hub-repositories/releases/download/latest/repositories.json",
|
||||||
json: true,
|
json: true,
|
||||||
@ -59,21 +59,31 @@ export class HelmRepoManager extends Singleton {
|
|||||||
timeout: 10000,
|
timeout: 10000,
|
||||||
});
|
});
|
||||||
|
|
||||||
return orderBy<HelmRepo>(res.body, repo => repo.name);
|
return orderBy(res.body as HelmRepo[], repo => repo.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async init() {
|
private async ensureInitialized() {
|
||||||
helmCli.setLogger(logger);
|
helmCli.setLogger(logger);
|
||||||
await helmCli.ensureBinary();
|
await helmCli.ensureBinary();
|
||||||
|
|
||||||
if (!this.initialized) {
|
this.helmEnv ??= await this.parseHelmEnv();
|
||||||
this.helmEnv = await HelmRepoManager.parseHelmEnv();
|
|
||||||
await HelmRepoManager.update();
|
const repos = await this.list();
|
||||||
this.initialized = true;
|
|
||||||
|
if (repos.length === 0) {
|
||||||
|
await this.addRepo({
|
||||||
|
name: "bitnami",
|
||||||
|
url: "https://charts.bitnami.com/bitnami",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.didUpdateOnce) {
|
||||||
|
await this.update();
|
||||||
|
this.didUpdateOnce = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static async parseHelmEnv() {
|
protected async parseHelmEnv() {
|
||||||
const output = await execHelm(["env"]);
|
const output = await execHelm(["env"]);
|
||||||
const lines = output.split(/\r?\n/); // split by new line feed
|
const lines = output.split(/\r?\n/); // split by new line feed
|
||||||
const env: HelmEnv = {};
|
const env: HelmEnv = {};
|
||||||
@ -95,38 +105,28 @@ export class HelmRepoManager extends Singleton {
|
|||||||
return repos.find(repo => repo.name === name);
|
return repos.find(repo => repo.name === name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async readConfig(): Promise<HelmRepoConfig> {
|
private async list(): Promise<HelmRepo[]> {
|
||||||
try {
|
try {
|
||||||
const rawConfig = await readFile(this.helmEnv.HELM_REPOSITORY_CONFIG, "utf8");
|
const rawConfig = await readFile(this.helmEnv.HELM_REPOSITORY_CONFIG, "utf8");
|
||||||
const parsedConfig = yaml.load(rawConfig);
|
const parsedConfig = yaml.load(rawConfig) as HelmRepoConfig;
|
||||||
|
|
||||||
if (typeof parsedConfig === "object" && parsedConfig) {
|
if (typeof parsedConfig === "object" && parsedConfig) {
|
||||||
return parsedConfig as HelmRepoConfig;
|
return parsedConfig.repositories;
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// ignore error
|
// ignore error
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return [];
|
||||||
repositories: [],
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async repositories(): Promise<HelmRepo[]> {
|
public async repositories(): Promise<HelmRepo[]> {
|
||||||
try {
|
try {
|
||||||
if (!this.initialized) {
|
await this.ensureInitialized();
|
||||||
await this.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
const { repositories } = await this.readConfig();
|
const repos = await this.list();
|
||||||
|
|
||||||
if (!repositories.length) {
|
return repos.map(repo => ({
|
||||||
await HelmRepoManager.addRepo({ name: "bitnami", url: "https://charts.bitnami.com/bitnami" });
|
|
||||||
|
|
||||||
return await this.repositories();
|
|
||||||
}
|
|
||||||
|
|
||||||
return repositories.map(repo => ({
|
|
||||||
...repo,
|
...repo,
|
||||||
cacheFilePath: `${this.helmEnv.HELM_REPOSITORY_CACHE}/${repo.name}-index.yaml`,
|
cacheFilePath: `${this.helmEnv.HELM_REPOSITORY_CACHE}/${repo.name}-index.yaml`,
|
||||||
}));
|
}));
|
||||||
@ -137,25 +137,14 @@ export class HelmRepoManager extends Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async update() {
|
public async update() {
|
||||||
return execHelm([
|
return execHelm([
|
||||||
"repo",
|
"repo",
|
||||||
"update",
|
"update",
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async addRepo({ name, url }: HelmRepo) {
|
public async addRepo({ name, url, insecureSkipTlsVerify, username, password, caFile, keyFile, certFile }: HelmRepo) {
|
||||||
logger.info(`[HELM]: adding repo "${name}" from ${url}`);
|
|
||||||
|
|
||||||
return execHelm([
|
|
||||||
"repo",
|
|
||||||
"add",
|
|
||||||
name,
|
|
||||||
url,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async addCustomRepo({ name, url, insecureSkipTlsVerify, username, password, caFile, keyFile, certFile }: HelmRepo) {
|
|
||||||
logger.info(`[HELM]: adding repo ${name} from ${url}`);
|
logger.info(`[HELM]: adding repo ${name} from ${url}`);
|
||||||
const args = [
|
const args = [
|
||||||
"repo",
|
"repo",
|
||||||
@ -191,7 +180,7 @@ export class HelmRepoManager extends Singleton {
|
|||||||
return execHelm(args);
|
return execHelm(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async removeRepo({ name, url }: HelmRepo): Promise<string> {
|
public async removeRepo({ name, url }: HelmRepo): Promise<string> {
|
||||||
logger.info(`[HELM]: removing repo ${name} (${url})`);
|
logger.info(`[HELM]: removing repo ${name} (${url})`);
|
||||||
|
|
||||||
return execHelm([
|
return execHelm([
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import * as Mobx from "mobx";
|
|||||||
import * as LensExtensionsCommonApi from "../extensions/common-api";
|
import * as LensExtensionsCommonApi from "../extensions/common-api";
|
||||||
import * as LensExtensionsMainApi from "../extensions/main-api";
|
import * as LensExtensionsMainApi from "../extensions/main-api";
|
||||||
import { app, autoUpdater, dialog, powerMonitor } from "electron";
|
import { app, autoUpdater, dialog, powerMonitor } from "electron";
|
||||||
import { appName, isIntegrationTesting, isMac, isWindows, productName, isDevelopment } from "../common/vars";
|
import { appName, isIntegrationTesting, isMac, isWindows, productName } from "../common/vars";
|
||||||
import { LensProxy } from "./lens-proxy";
|
import { LensProxy } from "./lens-proxy";
|
||||||
import { WindowManager } from "./window-manager";
|
import { WindowManager } from "./window-manager";
|
||||||
import { ClusterManager } from "./cluster-manager";
|
import { ClusterManager } from "./cluster-manager";
|
||||||
@ -176,7 +176,7 @@ di.runSetups().then(() => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
logger.info("🔌 Starting LensProxy");
|
logger.info("🔌 Starting LensProxy");
|
||||||
await lensProxy.listen(); // lensProxy.port available
|
await lensProxy.listen();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
dialog.showErrorBox("Lens Error", `Could not start proxy: ${error?.message || "unknown error"}`);
|
dialog.showErrorBox("Lens Error", `Could not start proxy: ${error?.message || "unknown error"}`);
|
||||||
|
|
||||||
@ -228,16 +228,6 @@ di.runSetups().then(() => {
|
|||||||
logger.info("🖥️ Starting WindowManager");
|
logger.info("🖥️ Starting WindowManager");
|
||||||
const windowManager = WindowManager.createInstance();
|
const windowManager = WindowManager.createInstance();
|
||||||
|
|
||||||
// Override main content view url to local webpack-dev-server to support HMR / live-reload
|
|
||||||
if (isDevelopment) {
|
|
||||||
const { createDevServer } = await import("../../webpack.dev-server");
|
|
||||||
const devServer = createDevServer(lensProxy.port);
|
|
||||||
|
|
||||||
windowManager.mainContentUrl = `http://localhost:${devServer.options.port}`;
|
|
||||||
|
|
||||||
await devServer.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
const menuItems = di.inject(electronMenuItemsInjectable);
|
const menuItems = di.inject(electronMenuItemsInjectable);
|
||||||
const trayMenuItems = di.inject(trayMenuItemsInjectable);
|
const trayMenuItems = di.inject(trayMenuItemsInjectable);
|
||||||
|
|
||||||
|
|||||||
@ -26,7 +26,7 @@ import { showOpenDialog } from "../../ipc/dialog";
|
|||||||
import { windowActionHandleChannel, windowLocationChangedChannel, windowOpenAppMenuAsContextMenuChannel } from "../../../common/ipc/window";
|
import { windowActionHandleChannel, windowLocationChangedChannel, windowOpenAppMenuAsContextMenuChannel } from "../../../common/ipc/window";
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
electronMenuItems: IComputedValue<MenuRegistration[]>,
|
electronMenuItems: IComputedValue<MenuRegistration[]>;
|
||||||
directoryForLensLocalStorage: string;
|
directoryForLensLocalStorage: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import { BrowserWindow, dialog, OpenDialogOptions } from "electron";
|
import { BrowserWindow, dialog, OpenDialogOptions } from "electron";
|
||||||
|
|
||||||
export async function showOpenDialog(dialogOptions: OpenDialogOptions): Promise<{ canceled: boolean; filePaths: string[]; }> {
|
export async function showOpenDialog(dialogOptions: OpenDialogOptions): Promise<{ canceled: boolean; filePaths: string[] }> {
|
||||||
const { canceled, filePaths } = await dialog.showOpenDialog(BrowserWindow.getFocusedWindow(), dialogOptions);
|
const { canceled, filePaths } = await dialog.showOpenDialog(BrowserWindow.getFocusedWindow(), dialogOptions);
|
||||||
|
|
||||||
return { canceled, filePaths };
|
return { canceled, filePaths };
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import logger from "../logger";
|
|||||||
import { LensProxy } from "../lens-proxy";
|
import { LensProxy } from "../lens-proxy";
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
directoryForTemp: string
|
directoryForTemp: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class KubeconfigManager {
|
export class KubeconfigManager {
|
||||||
|
|||||||
@ -64,10 +64,10 @@ interface Dependencies {
|
|||||||
directoryForKubectlBinaries: string;
|
directoryForKubectlBinaries: string;
|
||||||
|
|
||||||
userStore: {
|
userStore: {
|
||||||
kubectlBinariesPath?: string
|
kubectlBinariesPath?: string;
|
||||||
downloadBinariesPath?: string
|
downloadBinariesPath?: string;
|
||||||
downloadKubectlBinaries: boolean
|
downloadKubectlBinaries: boolean;
|
||||||
downloadMirror: string
|
downloadMirror: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,7 @@ import { getBoolean } from "./utils/parse-query";
|
|||||||
type GetClusterForRequest = (req: http.IncomingMessage) => Cluster | null;
|
type GetClusterForRequest = (req: http.IncomingMessage) => Cluster | null;
|
||||||
|
|
||||||
export interface LensProxyFunctions {
|
export interface LensProxyFunctions {
|
||||||
getClusterForRequest: GetClusterForRequest,
|
getClusterForRequest: GetClusterForRequest;
|
||||||
shellApiRequest: (args: ProxyApiRequestArgs) => void | Promise<void>;
|
shellApiRequest: (args: ProxyApiRequestArgs) => void | Promise<void>;
|
||||||
kubeApiRequest: (args: ProxyApiRequestArgs) => void | Promise<void>;
|
kubeApiRequest: (args: ProxyApiRequestArgs) => void | Promise<void>;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,14 +2,15 @@
|
|||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
import { app, BrowserWindow, dialog, Menu, MenuItem, MenuItemConstructorOptions, webContents, shell } from "electron";
|
import { app, BrowserWindow, dialog, Menu, MenuItem, MenuItemConstructorOptions, webContents } from "electron";
|
||||||
import { autorun, IComputedValue } from "mobx";
|
import { autorun, IComputedValue } from "mobx";
|
||||||
import type { WindowManager } from "../window-manager";
|
import type { WindowManager } from "../window-manager";
|
||||||
import { appName, isMac, isWindows, docsUrl, supportUrl, productName } from "../../common/vars";
|
import { appName, isMac, isWindows, docsUrl, supportUrl, productName } from "../../common/vars";
|
||||||
import logger from "../logger";
|
import logger from "../logger";
|
||||||
import { exitApp } from "../exit-app";
|
import { exitApp } from "../exit-app";
|
||||||
import { broadcastMessage } from "../../common/ipc";
|
import { broadcastMessage } from "../../common/ipc";
|
||||||
import packageJson from "../../../package.json";
|
import { openBrowser } from "../../common/utils";
|
||||||
|
import * as packageJson from "../../../package.json";
|
||||||
import { preferencesURL, extensionsURL, addClusterURL, catalogURL, welcomeURL } from "../../common/routes";
|
import { preferencesURL, extensionsURL, addClusterURL, catalogURL, welcomeURL } from "../../common/routes";
|
||||||
import { checkForUpdates, isAutoUpdateEnabled } from "../app-updater";
|
import { checkForUpdates, isAutoUpdateEnabled } from "../app-updater";
|
||||||
import type { MenuRegistration } from "./menu-registration";
|
import type { MenuRegistration } from "./menu-registration";
|
||||||
@ -261,14 +262,18 @@ export function getAppMenu(
|
|||||||
label: "Documentation",
|
label: "Documentation",
|
||||||
id: "documentation",
|
id: "documentation",
|
||||||
click: async () => {
|
click: async () => {
|
||||||
shell.openExternal(docsUrl);
|
openBrowser(docsUrl).catch(error => {
|
||||||
|
logger.error("[MENU]: failed to open browser", { error });
|
||||||
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Support",
|
label: "Support",
|
||||||
id: "support",
|
id: "support",
|
||||||
click: async () => {
|
click: async () => {
|
||||||
shell.openExternal(supportUrl);
|
openBrowser(supportUrl).catch(error => {
|
||||||
|
logger.error("[MENU]: failed to open browser", { error });
|
||||||
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
...ignoreIf(isMac, [
|
...ignoreIf(isMac, [
|
||||||
|
|||||||
@ -37,8 +37,8 @@ function checkHost<Query>(url: URLParse<Query>): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
extensionLoader: ExtensionLoader
|
extensionLoader: ExtensionLoader;
|
||||||
extensionsStore: ExtensionsStore
|
extensionsStore: ExtensionsStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class LensProtocolRouterMain extends proto.LensProtocolRouter {
|
export class LensProtocolRouterMain extends proto.LensProtocolRouter {
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import type { Cluster } from "../../../common/cluster/cluster";
|
|||||||
import type { ClusterId } from "../../../common/cluster-types";
|
import type { ClusterId } from "../../../common/cluster-types";
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
authenticateRequest: (clusterId: ClusterId, tabId: string, shellToken: string) => boolean,
|
authenticateRequest: (clusterId: ClusterId, tabId: string, shellToken: string) => boolean;
|
||||||
|
|
||||||
createShellSession: (args: {
|
createShellSession: (args: {
|
||||||
webSocket: WebSocket;
|
webSocket: WebSocket;
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
import { ExtendedMap } from "../../../../common/utils";
|
import { getOrInsertMap } from "../../../../common/utils";
|
||||||
import type { ClusterId } from "../../../../common/cluster-types";
|
import type { ClusterId } from "../../../../common/cluster-types";
|
||||||
import { ipcMainHandle } from "../../../../common/ipc";
|
import { ipcMainHandle } from "../../../../common/ipc";
|
||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
@ -11,15 +11,14 @@ import { promisify } from "util";
|
|||||||
const randomBytes = promisify(crypto.randomBytes);
|
const randomBytes = promisify(crypto.randomBytes);
|
||||||
|
|
||||||
export class ShellRequestAuthenticator {
|
export class ShellRequestAuthenticator {
|
||||||
private tokens = new ExtendedMap<ClusterId, Map<string, Uint8Array>>();
|
private tokens = new Map<ClusterId, Map<string, Uint8Array>>();
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
ipcMainHandle("cluster:shell-api", async (event, clusterId, tabId) => {
|
ipcMainHandle("cluster:shell-api", async (event, clusterId, tabId) => {
|
||||||
const authToken = Uint8Array.from(await randomBytes(128));
|
const authToken = Uint8Array.from(await randomBytes(128));
|
||||||
|
const forCluster = getOrInsertMap(this.tokens, clusterId);
|
||||||
|
|
||||||
this.tokens
|
forCluster.set(tabId, authToken);
|
||||||
.getOrInsert(clusterId, () => new Map())
|
|
||||||
.set(tabId, authToken);
|
|
||||||
|
|
||||||
return authToken;
|
return authToken;
|
||||||
});
|
});
|
||||||
|
|||||||
@ -8,8 +8,8 @@ import type net from "net";
|
|||||||
import type { Cluster } from "../../common/cluster/cluster";
|
import type { Cluster } from "../../common/cluster/cluster";
|
||||||
|
|
||||||
export interface ProxyApiRequestArgs {
|
export interface ProxyApiRequestArgs {
|
||||||
req: http.IncomingMessage,
|
req: http.IncomingMessage;
|
||||||
socket: net.Socket,
|
socket: net.Socket;
|
||||||
head: Buffer,
|
head: Buffer;
|
||||||
cluster: Cluster,
|
cluster: Cluster;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import type http from "http";
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
import { readFile } from "fs-extra";
|
import { readFile } from "fs-extra";
|
||||||
import type { Cluster } from "../common/cluster/cluster";
|
import type { Cluster } from "../common/cluster/cluster";
|
||||||
import { apiPrefix, appName, publicPath } from "../common/vars";
|
import { apiPrefix, appName, publicPath, isDevelopment, webpackDevServerPort } from "../common/vars";
|
||||||
import { HelmApiRoute, KubeconfigRoute, MetricsRoute, PortForwardRoute, ResourceApplierApiRoute, VersionRoute } from "./routes";
|
import { HelmApiRoute, KubeconfigRoute, MetricsRoute, PortForwardRoute, ResourceApplierApiRoute, VersionRoute } from "./routes";
|
||||||
import logger from "./logger";
|
import logger from "./logger";
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ export interface LensApiRequest<P = any> {
|
|||||||
query: URLSearchParams;
|
query: URLSearchParams;
|
||||||
raw: {
|
raw: {
|
||||||
req: http.IncomingMessage;
|
req: http.IncomingMessage;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMimeType(filename: string) {
|
function getMimeType(filename: string) {
|
||||||
@ -61,7 +61,7 @@ function getMimeType(filename: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
routePortForward: (request: LensApiRequest) => Promise<void>
|
routePortForward: (request: LensApiRequest) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Router {
|
export class Router {
|
||||||
@ -110,7 +110,7 @@ export class Router {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static async handleStaticFile({ params, response }: LensApiRequest): Promise<void> {
|
protected static async handleStaticFile({ params, response, raw: { req }}: LensApiRequest): Promise<void> {
|
||||||
let filePath = params.path;
|
let filePath = params.path;
|
||||||
|
|
||||||
for (let retryCount = 0; retryCount < 5; retryCount += 1) {
|
for (let retryCount = 0; retryCount < 5; retryCount += 1) {
|
||||||
@ -124,6 +124,19 @@ export class Router {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const filename = path.basename(req.url);
|
||||||
|
// redirect requests to [appName].js, [appName].html /sockjs-node/ to webpack-dev-server (for hot-reload support)
|
||||||
|
const toWebpackDevServer = filename.includes(appName) || filename.includes("hot-update") || req.url.includes("sockjs-node");
|
||||||
|
|
||||||
|
if (isDevelopment && toWebpackDevServer) {
|
||||||
|
const redirectLocation = `http://localhost:${webpackDevServerPort}${req.url}`;
|
||||||
|
|
||||||
|
response.statusCode = 307;
|
||||||
|
response.setHeader("Location", redirectLocation);
|
||||||
|
|
||||||
|
return response.end();
|
||||||
|
}
|
||||||
|
|
||||||
const data = await readFile(asset);
|
const data = await readFile(asset);
|
||||||
|
|
||||||
response.setHeader("Content-Type", getMimeType(asset));
|
response.setHeader("Content-Type", getMimeType(asset));
|
||||||
|
|||||||
@ -19,7 +19,7 @@ export interface PortForwardArgs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
getKubectlBinPath: (bundled: boolean) => Promise<string>
|
getKubectlBinPath: (bundled: boolean) => Promise<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PortForward {
|
export class PortForward {
|
||||||
|
|||||||
@ -133,7 +133,7 @@ export abstract class ShellSession {
|
|||||||
|
|
||||||
protected abstract get cwd(): string | undefined;
|
protected abstract get cwd(): string | undefined;
|
||||||
|
|
||||||
protected ensureShellProcess(shell: string, args: string[], env: Record<string, string>, cwd: string): { shellProcess: pty.IPty, resume: boolean } {
|
protected ensureShellProcess(shell: string, args: string[], env: Record<string, string>, cwd: string): { shellProcess: pty.IPty; resume: boolean } {
|
||||||
const resume = ShellSession.processes.has(this.terminalId);
|
const resume = ShellSession.processes.has(this.terminalId);
|
||||||
|
|
||||||
if (!resume) {
|
if (!resume) {
|
||||||
|
|||||||
@ -7,8 +7,8 @@ export interface TrayMenuRegistration {
|
|||||||
label?: string;
|
label?: string;
|
||||||
click?: (menuItem: TrayMenuRegistration) => void;
|
click?: (menuItem: TrayMenuRegistration) => void;
|
||||||
id?: string;
|
id?: string;
|
||||||
type?: "normal" | "separator" | "submenu"
|
type?: "normal" | "separator" | "submenu";
|
||||||
toolTip?: string;
|
toolTip?: string;
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
submenu?: TrayMenuRegistration[]
|
submenu?: TrayMenuRegistration[];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,11 +5,11 @@
|
|||||||
|
|
||||||
import type { ClusterId } from "../common/cluster-types";
|
import type { ClusterId } from "../common/cluster-types";
|
||||||
import { makeObservable, observable } from "mobx";
|
import { makeObservable, observable } from "mobx";
|
||||||
import { app, BrowserWindow, dialog, ipcMain, shell, webContents } from "electron";
|
import { app, BrowserWindow, dialog, ipcMain, webContents } from "electron";
|
||||||
import windowStateKeeper from "electron-window-state";
|
import windowStateKeeper from "electron-window-state";
|
||||||
import { appEventBus } from "../common/app-event-bus/event-bus";
|
import { appEventBus } from "../common/app-event-bus/event-bus";
|
||||||
import { ipcMainOn } from "../common/ipc";
|
import { ipcMainOn } from "../common/ipc";
|
||||||
import { delay, iter, Singleton } from "../common/utils";
|
import { delay, iter, Singleton, openBrowser } from "../common/utils";
|
||||||
import { ClusterFrameInfo, clusterFrameMap } from "../common/cluster-frames";
|
import { ClusterFrameInfo, clusterFrameMap } from "../common/cluster-frames";
|
||||||
import { IpcRendererNavigationEvents } from "../renderer/navigation/events";
|
import { IpcRendererNavigationEvents } from "../renderer/navigation/events";
|
||||||
import logger from "./logger";
|
import logger from "./logger";
|
||||||
@ -28,8 +28,6 @@ export interface SendToViewArgs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class WindowManager extends Singleton {
|
export class WindowManager extends Singleton {
|
||||||
public mainContentUrl = `http://localhost:${LensProxy.getInstance().port}`;
|
|
||||||
|
|
||||||
protected mainWindow: BrowserWindow;
|
protected mainWindow: BrowserWindow;
|
||||||
protected splashWindow: BrowserWindow;
|
protected splashWindow: BrowserWindow;
|
||||||
protected windowState: windowStateKeeper.State;
|
protected windowState: windowStateKeeper.State;
|
||||||
@ -43,6 +41,10 @@ export class WindowManager extends Singleton {
|
|||||||
this.bindEvents();
|
this.bindEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get mainUrl() {
|
||||||
|
return `http://localhost:${LensProxy.getInstance().port}`;
|
||||||
|
}
|
||||||
|
|
||||||
private async initMainWindow(showSplash: boolean) {
|
private async initMainWindow(showSplash: boolean) {
|
||||||
// Manage main window size and position with state persistence
|
// Manage main window size and position with state persistence
|
||||||
if (!this.windowState) {
|
if (!this.windowState) {
|
||||||
@ -132,7 +134,9 @@ export class WindowManager extends Singleton {
|
|||||||
webPreferences.nodeIntegration = false;
|
webPreferences.nodeIntegration = false;
|
||||||
})
|
})
|
||||||
.setWindowOpenHandler((details) => {
|
.setWindowOpenHandler((details) => {
|
||||||
shell.openExternal(details.url);
|
openBrowser(details.url).catch(error => {
|
||||||
|
logger.error("[WINDOW-MANAGER]: failed to open browser", { error });
|
||||||
|
});
|
||||||
|
|
||||||
return { action: "deny" };
|
return { action: "deny" };
|
||||||
});
|
});
|
||||||
@ -140,8 +144,8 @@ export class WindowManager extends Singleton {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (showSplash) await this.showSplash();
|
if (showSplash) await this.showSplash();
|
||||||
logger.info(`[WINDOW-MANAGER]: Loading Main window from url: ${this.mainContentUrl} ...`);
|
logger.info(`[WINDOW-MANAGER]: Loading Main window from url: ${this.mainUrl} ...`);
|
||||||
await this.mainWindow.loadURL(this.mainContentUrl);
|
await this.mainWindow.loadURL(this.mainUrl);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error("Loading main window failed", { error });
|
logger.error("Loading main window failed", { error });
|
||||||
dialog.showErrorBox("ERROR!", error.toString());
|
dialog.showErrorBox("ERROR!", error.toString());
|
||||||
|
|||||||
@ -75,7 +75,7 @@ function mergeClusterModel(prev: ClusterModel, right: Omit<ClusterModel, "id">):
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function moveStorageFolder({ folder, newId, oldId }: { folder: string, newId: string, oldId: string }): void {
|
function moveStorageFolder({ folder, newId, oldId }: { folder: string; newId: string; oldId: string }): void {
|
||||||
const oldPath = path.resolve(folder, `${oldId}.json`);
|
const oldPath = path.resolve(folder, `${oldId}.json`);
|
||||||
const newPath = path.resolve(folder, `${newId}.json`);
|
const newPath = path.resolve(folder, `${newId}.json`);
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import type Conf from "conf";
|
import type Conf from "conf";
|
||||||
import type { Migrations } from "conf/dist/source/types";
|
import type { Migrations } from "conf/dist/source/types";
|
||||||
import { ExtendedMap, iter } from "../common/utils";
|
import { getOrInsert, iter } from "../common/utils";
|
||||||
import { isTestEnv } from "../common/vars";
|
import { isTestEnv } from "../common/vars";
|
||||||
|
|
||||||
export function migrationLog(...args: any[]) {
|
export function migrationLog(...args: any[]) {
|
||||||
@ -15,15 +15,15 @@ export function migrationLog(...args: any[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface MigrationDeclaration {
|
export interface MigrationDeclaration {
|
||||||
version: string,
|
version: string;
|
||||||
run(store: Conf<any>): void;
|
run(store: Conf<any>): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function joinMigrations(...declarations: MigrationDeclaration[]): Migrations<any> {
|
export function joinMigrations(...declarations: MigrationDeclaration[]): Migrations<any> {
|
||||||
const migrations = new ExtendedMap<string, ((store: Conf<any>) => void)[]>();
|
const migrations = new Map<string, ((store: Conf<any>) => void)[]>();
|
||||||
|
|
||||||
for (const decl of declarations) {
|
for (const decl of declarations) {
|
||||||
migrations.getOrInsert(decl.version, () => []).push(decl.run);
|
getOrInsert(migrations, decl.version, []).push(decl.run);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Object.fromEntries(
|
return Object.fromEntries(
|
||||||
|
|||||||
@ -5,6 +5,6 @@
|
|||||||
|
|
||||||
import { createHash } from "crypto";
|
import { createHash } from "crypto";
|
||||||
|
|
||||||
export function generateNewIdFor(cluster: { kubeConfigPath: string, contextName: string }): string {
|
export function generateNewIdFor(cluster: { kubeConfigPath: string; contextName: string }): string {
|
||||||
return createHash("md5").update(`${cluster.kubeConfigPath}:${cluster.contextName}`).digest("hex");
|
return createHash("md5").update(`${cluster.kubeConfigPath}:${cluster.contextName}`).digest("hex");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import { CatalogCategory, CatalogEntity, CatalogEntityData, catalogCategoryRegis
|
|||||||
import "../../common/catalog-entities";
|
import "../../common/catalog-entities";
|
||||||
import type { Cluster } from "../../common/cluster/cluster";
|
import type { Cluster } from "../../common/cluster/cluster";
|
||||||
import { ClusterStore } from "../../common/cluster-store/cluster-store";
|
import { ClusterStore } from "../../common/cluster-store/cluster-store";
|
||||||
import { type Disposer, iter } from "../utils";
|
import { Disposer, iter } from "../utils";
|
||||||
import { once } from "lodash";
|
import { once } from "lodash";
|
||||||
import logger from "../../common/logger";
|
import logger from "../../common/logger";
|
||||||
import { CatalogRunEvent } from "../../common/catalog/catalog-run-event";
|
import { CatalogRunEvent } from "../../common/catalog/catalog-run-event";
|
||||||
|
|||||||
@ -21,19 +21,19 @@ export enum TerminalChannels {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type TerminalMessage = {
|
export type TerminalMessage = {
|
||||||
type: TerminalChannels.STDIN,
|
type: TerminalChannels.STDIN;
|
||||||
data: string,
|
data: string;
|
||||||
} | {
|
} | {
|
||||||
type: TerminalChannels.STDOUT,
|
type: TerminalChannels.STDOUT;
|
||||||
data: string,
|
data: string;
|
||||||
} | {
|
} | {
|
||||||
type: TerminalChannels.CONNECTED
|
type: TerminalChannels.CONNECTED;
|
||||||
} | {
|
} | {
|
||||||
type: TerminalChannels.RESIZE,
|
type: TerminalChannels.RESIZE;
|
||||||
data: {
|
data: {
|
||||||
width: number,
|
width: number;
|
||||||
height: number,
|
height: number;
|
||||||
},
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
enum TerminalColor {
|
enum TerminalColor {
|
||||||
|
|||||||
@ -57,7 +57,7 @@ export enum WebSocketApiState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface WebSocketEvents {
|
export interface WebSocketEvents {
|
||||||
open: () => void,
|
open: () => void;
|
||||||
data: (message: string) => void;
|
data: (message: string) => void;
|
||||||
close: () => void;
|
close: () => void;
|
||||||
}
|
}
|
||||||
@ -65,7 +65,7 @@ export interface WebSocketEvents {
|
|||||||
type Defaulted<Params, DefaultParams extends keyof Params> = Required<Pick<Params, DefaultParams>> & Omit<Params, DefaultParams>;
|
type Defaulted<Params, DefaultParams extends keyof Params> = Required<Pick<Params, DefaultParams>> & Omit<Params, DefaultParams>;
|
||||||
|
|
||||||
export class WebSocketApi<Events extends WebSocketEvents> extends (EventEmitter as { new<T>(): TypedEventEmitter<T> })<Events> {
|
export class WebSocketApi<Events extends WebSocketEvents> extends (EventEmitter as { new<T>(): TypedEventEmitter<T> })<Events> {
|
||||||
protected socket: WebSocket;
|
protected socket?: WebSocket | null;
|
||||||
protected pendingCommands: (string | ArrayBufferLike | Blob | ArrayBufferView)[] = [];
|
protected pendingCommands: (string | ArrayBufferLike | Blob | ArrayBufferView)[] = [];
|
||||||
protected reconnectTimer?: any;
|
protected reconnectTimer?: any;
|
||||||
protected pingTimer?: any;
|
protected pingTimer?: any;
|
||||||
@ -181,7 +181,7 @@ export class WebSocketApi<Events extends WebSocketEvents> extends (EventEmitter
|
|||||||
if (error) {
|
if (error) {
|
||||||
const { reconnectDelay } = this.params;
|
const { reconnectDelay } = this.params;
|
||||||
|
|
||||||
if (reconnectDelay) {
|
if (reconnectDelay && this.socket) {
|
||||||
const url = this.socket.url;
|
const url = this.socket.url;
|
||||||
|
|
||||||
this.writeLog("will reconnect in", `${reconnectDelay}s`);
|
this.writeLog("will reconnect in", `${reconnectDelay}s`);
|
||||||
|
|||||||
@ -136,14 +136,7 @@ export async function bootstrap(di: DependencyInjectionContainer) {
|
|||||||
App = (await import("./frames/cluster-frame/cluster-frame")).ClusterFrame;
|
App = (await import("./frames/cluster-frame/cluster-frame")).ClusterFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
await initializeApp(rootElem);
|
||||||
await initializeApp(rootElem);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`[BOOTSTRAP]: view initialization error: ${error}`, {
|
|
||||||
origin: location.href,
|
|
||||||
isTopFrameView: process.isMainFrame,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
render(
|
render(
|
||||||
<DiContextProvider value={{ di }}>
|
<DiContextProvider value={{ di }}>
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import type { ClusterContext } from "../../common/k8s-api/cluster-context";
|
|||||||
import { computed, makeObservable } from "mobx";
|
import { computed, makeObservable } from "mobx";
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
namespaceStore: NamespaceStore
|
namespaceStore: NamespaceStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ClusterFrameContext implements ClusterContext {
|
export class ClusterFrameContext implements ClusterContext {
|
||||||
|
|||||||
@ -34,7 +34,7 @@ interface Option {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
getCustomKubeConfigDirectory: (directoryName: string) => string
|
getCustomKubeConfigDirectory: (directoryName: string) => string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getContexts(config: KubeConfig): Map<string, Option> {
|
function getContexts(config: KubeConfig): Map<string, Option> {
|
||||||
|
|||||||
@ -16,7 +16,7 @@ import { navigate } from "../../navigation";
|
|||||||
import { catalogCategoryRegistry } from "../../api/catalog-category-registry";
|
import { catalogCategoryRegistry } from "../../api/catalog-category-registry";
|
||||||
|
|
||||||
export type CatalogAddButtonProps = {
|
export type CatalogAddButtonProps = {
|
||||||
category: CatalogCategory
|
category: CatalogCategory;
|
||||||
};
|
};
|
||||||
|
|
||||||
type CategoryId = string;
|
type CategoryId = string;
|
||||||
|
|||||||
@ -25,7 +25,7 @@ interface Props<T extends CatalogEntity> {
|
|||||||
@observer
|
@observer
|
||||||
export class CatalogEntityDetails<T extends CatalogEntity> extends Component<Props<T>> {
|
export class CatalogEntityDetails<T extends CatalogEntity> extends Component<Props<T>> {
|
||||||
categoryIcon(category: CatalogCategory) {
|
categoryIcon(category: CatalogCategory) {
|
||||||
if (Icon.isSvg(category.metadata.icon)) {
|
if (category.metadata.icon.includes("<svg")) {
|
||||||
return <Icon svg={category.metadata.icon} smallest />;
|
return <Icon svg={category.metadata.icon} smallest />;
|
||||||
} else {
|
} else {
|
||||||
return <Icon material={category.metadata.icon} smallest />;
|
return <Icon material={category.metadata.icon} smallest />;
|
||||||
|
|||||||
@ -65,7 +65,7 @@ export class CatalogEntityDrawerMenu<T extends CatalogEntity> extends React.Comp
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const key = Icon.isSvg(menuItem.icon) ? "svg" : "material";
|
const key = menuItem.icon.includes("<svg") ? "svg" : "material";
|
||||||
|
|
||||||
items.push(
|
items.push(
|
||||||
<MenuItem key={menuItem.title} onClick={() => this.onMenuItemClick(menuItem)}>
|
<MenuItem key={menuItem.title} onClick={() => this.onMenuItemClick(menuItem)}>
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import { CatalogCategory, catalogCategoryRegistry } from "../../../../common/cat
|
|||||||
import { autoBind, disposer } from "../../../../common/utils";
|
import { autoBind, disposer } from "../../../../common/utils";
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
registry: CatalogEntityRegistry
|
registry: CatalogEntityRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CatalogEntityStore extends ItemStore<CatalogEntity> {
|
export class CatalogEntityStore extends ItemStore<CatalogEntity> {
|
||||||
|
|||||||
@ -28,7 +28,7 @@ function getCategoryIcon(category: CatalogCategory) {
|
|||||||
const { icon } = category.metadata ?? {};
|
const { icon } = category.metadata ?? {};
|
||||||
|
|
||||||
if (typeof icon === "string") {
|
if (typeof icon === "string") {
|
||||||
return Icon.isSvg(icon)
|
return icon.includes("<svg")
|
||||||
? <Icon small svg={icon}/>
|
? <Icon small svg={icon}/>
|
||||||
: <Icon small material={icon}/>;
|
: <Icon small material={icon}/>;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import { MenuItem } from "../menu";
|
|||||||
|
|
||||||
import type { CatalogEntity } from "../../api/catalog-entity";
|
import type { CatalogEntity } from "../../api/catalog-entity";
|
||||||
|
|
||||||
export function HotbarToggleMenuItem(props: { entity: CatalogEntity, addContent: ReactNode, removeContent: ReactNode }) {
|
export function HotbarToggleMenuItem(props: { entity: CatalogEntity; addContent: ReactNode; removeContent: ReactNode }) {
|
||||||
const store = HotbarStore.getInstance();
|
const store = HotbarStore.getInstance();
|
||||||
const [itemInHotbar, setItemInHotbar] = useState(store.isAddedToActive(props.entity));
|
const [itemInHotbar, setItemInHotbar] = useState(store.isAddedToActive(props.entity));
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import clusterOverviewStoreInjectable from "./cluster-overview-store/cluster-ove
|
|||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
clusterOverviewStore: ClusterOverviewStore
|
clusterOverviewStore: ClusterOverviewStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
const NonInjectedClusterMetricSwitchers = observer(({ clusterOverviewStore }: Dependencies) => {
|
const NonInjectedClusterMetricSwitchers = observer(({ clusterOverviewStore }: Dependencies) => {
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import clusterOverviewStoreInjectable
|
|||||||
from "./cluster-overview-store/cluster-overview-store.injectable";
|
from "./cluster-overview-store/cluster-overview-store.injectable";
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
clusterOverviewStore: ClusterOverviewStore
|
clusterOverviewStore: ClusterOverviewStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
const NonInjectedClusterMetrics = observer(({ clusterOverviewStore: { metricType, metricNodeRole, getMetricsValues, metricsLoaded, metrics }}: Dependencies) => {
|
const NonInjectedClusterMetrics = observer(({ clusterOverviewStore: { metricType, metricNodeRole, getMetricsValues, metricsLoaded, metrics }}: Dependencies) => {
|
||||||
|
|||||||
@ -5,9 +5,9 @@
|
|||||||
|
|
||||||
import { action, observable, reaction, when, makeObservable } from "mobx";
|
import { action, observable, reaction, when, makeObservable } from "mobx";
|
||||||
import { KubeObjectStore } from "../../../../common/k8s-api/kube-object.store";
|
import { KubeObjectStore } from "../../../../common/k8s-api/kube-object.store";
|
||||||
import { Cluster, clusterApi, getMetricsByNodeNames, type IClusterMetrics } from "../../../../common/k8s-api/endpoints";
|
import { Cluster, clusterApi, getMetricsByNodeNames, IClusterMetrics } from "../../../../common/k8s-api/endpoints";
|
||||||
import { autoBind, StorageHelper } from "../../../utils";
|
import { autoBind, StorageHelper } from "../../../utils";
|
||||||
import { type IMetricsReqParams, normalizeMetrics } from "../../../../common/k8s-api/endpoints/metrics.api";
|
import { IMetricsReqParams, normalizeMetrics } from "../../../../common/k8s-api/endpoints/metrics.api";
|
||||||
import { nodesStore } from "../../+nodes/nodes.store";
|
import { nodesStore } from "../../+nodes/nodes.store";
|
||||||
|
|
||||||
export enum MetricType {
|
export enum MetricType {
|
||||||
@ -22,11 +22,11 @@ export enum MetricNodeRole {
|
|||||||
|
|
||||||
export interface ClusterOverviewStorageState {
|
export interface ClusterOverviewStorageState {
|
||||||
metricType: MetricType;
|
metricType: MetricType;
|
||||||
metricNodeRole: MetricNodeRole,
|
metricNodeRole: MetricNodeRole;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
storage: StorageHelper<ClusterOverviewStorageState>
|
storage: StorageHelper<ClusterOverviewStorageState>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ClusterOverviewStore extends KubeObjectStore<Cluster> implements ClusterOverviewStorageState {
|
export class ClusterOverviewStore extends KubeObjectStore<Cluster> implements ClusterOverviewStorageState {
|
||||||
|
|||||||
@ -28,8 +28,8 @@ import type { KubeObject } from "../../../common/k8s-api/kube-object";
|
|||||||
import clusterOverviewStoreInjectable from "./cluster-overview-store/cluster-overview-store.injectable";
|
import clusterOverviewStoreInjectable from "./cluster-overview-store/cluster-overview-store.injectable";
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
subscribeStores: (stores: KubeObjectStore<KubeObject>[]) => Disposer,
|
subscribeStores: (stores: KubeObjectStore<KubeObject>[]) => Disposer;
|
||||||
clusterOverviewStore: ClusterOverviewStore
|
clusterOverviewStore: ClusterOverviewStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
|
|||||||
@ -24,7 +24,7 @@ function createLabels(rawLabelData: [string, number | undefined][]): string[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
clusterOverviewStore: ClusterOverviewStore
|
clusterOverviewStore: ClusterOverviewStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
const NonInjectedClusterPieCharts = observer(({ clusterOverviewStore }: Dependencies) => {
|
const NonInjectedClusterPieCharts = observer(({ clusterOverviewStore }: Dependencies) => {
|
||||||
|
|||||||
@ -27,7 +27,7 @@ interface Props extends KubeObjectDetailsProps<Secret> {
|
|||||||
export class SecretDetails extends React.Component<Props> {
|
export class SecretDetails extends React.Component<Props> {
|
||||||
@observable isSaving = false;
|
@observable isSaving = false;
|
||||||
@observable data: { [name: string]: string } = {};
|
@observable data: { [name: string]: string } = {};
|
||||||
revealSecret = new Set<string>();
|
@observable revealSecret = observable.set<string>();
|
||||||
|
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|||||||
@ -23,7 +23,7 @@ export interface KubeEventDetailsProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
subscribeStores: (stores: KubeObjectStore<KubeObject>[]) => Disposer
|
subscribeStores: (stores: KubeObjectStore<KubeObject>[]) => Disposer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
|
|||||||
@ -22,7 +22,7 @@ export interface ExtensionInfo {
|
|||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
attemptInstall: (request: InstallRequest, d: ExtendableDisposer) => Promise<void>;
|
attemptInstall: (request: InstallRequest, d: ExtendableDisposer) => Promise<void>;
|
||||||
getBaseRegistryUrl: () => Promise<string>;
|
getBaseRegistryUrl: () => Promise<string>;
|
||||||
extensionInstallationStateStore: ExtensionInstallationStateStore
|
extensionInstallationStateStore: ExtensionInstallationStateStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const attemptInstallByInfo = ({ attemptInstall, getBaseRegistryUrl, extensionInstallationStateStore }: Dependencies) => async ({
|
export const attemptInstallByInfo = ({ attemptInstall, getBaseRegistryUrl, extensionInstallationStateStore }: Dependencies) => async ({
|
||||||
|
|||||||
@ -34,9 +34,9 @@ interface Dependencies {
|
|||||||
installRequest: InstallRequest,
|
installRequest: InstallRequest,
|
||||||
) => Promise<InstallRequestValidated | null>;
|
) => Promise<InstallRequestValidated | null>;
|
||||||
|
|
||||||
getExtensionDestFolder: (name: string) => string
|
getExtensionDestFolder: (name: string) => string;
|
||||||
|
|
||||||
extensionInstallationStateStore: ExtensionInstallationStateStore
|
extensionInstallationStateStore: ExtensionInstallationStateStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const attemptInstall =
|
export const attemptInstall =
|
||||||
|
|||||||
@ -26,7 +26,7 @@ export interface InstallRequestValidated {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
extensionDiscovery: ExtensionDiscovery
|
extensionDiscovery: ExtensionDiscovery;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createTempFilesAndValidate =
|
export const createTempFilesAndValidate =
|
||||||
|
|||||||
@ -16,9 +16,9 @@ import React from "react";
|
|||||||
import type { ExtensionInstallationStateStore } from "../../../../../extensions/extension-installation-state-store/extension-installation-state-store";
|
import type { ExtensionInstallationStateStore } from "../../../../../extensions/extension-installation-state-store/extension-installation-state-store";
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
extensionLoader: ExtensionLoader
|
extensionLoader: ExtensionLoader;
|
||||||
getExtensionDestFolder: (name: string) => string
|
getExtensionDestFolder: (name: string) => string;
|
||||||
extensionInstallationStateStore: ExtensionInstallationStateStore
|
extensionInstallationStateStore: ExtensionInstallationStateStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const unpackExtension =
|
export const unpackExtension =
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user