mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Merge branch 'master' into typesafe-catalog-category-events
Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
commit
d31f4b15e7
@ -15,3 +15,7 @@ updates:
|
|||||||
versioning-strategy:
|
versioning-strategy:
|
||||||
lockfile-only: false
|
lockfile-only: false
|
||||||
increase: true
|
increase: true
|
||||||
|
ignore:
|
||||||
|
- dependency-name: *
|
||||||
|
update-types:
|
||||||
|
- version-update:semver-major
|
||||||
|
|||||||
15
Makefile
15
Makefile
@ -14,13 +14,13 @@ else
|
|||||||
DETECTED_OS := $(shell uname)
|
DETECTED_OS := $(shell uname)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
binaries/client: node_modules
|
|
||||||
yarn download-bins
|
|
||||||
|
|
||||||
node_modules: yarn.lock
|
node_modules: yarn.lock
|
||||||
yarn install --frozen-lockfile --network-timeout=100000
|
yarn install --frozen-lockfile --network-timeout=100000
|
||||||
yarn check --verify-tree --integrity
|
yarn check --verify-tree --integrity
|
||||||
|
|
||||||
|
binaries/client: node_modules
|
||||||
|
yarn download-bins
|
||||||
|
|
||||||
static/build/LensDev.html: node_modules
|
static/build/LensDev.html: node_modules
|
||||||
yarn compile:renderer
|
yarn compile:renderer
|
||||||
|
|
||||||
@ -51,11 +51,6 @@ test: binaries/client
|
|||||||
|
|
||||||
.PHONY: integration-linux
|
.PHONY: integration-linux
|
||||||
integration-linux: binaries/client build-extension-types build-extensions
|
integration-linux: binaries/client build-extension-types build-extensions
|
||||||
# ifdef XDF_CONFIG_HOME
|
|
||||||
# rm -rf ${XDG_CONFIG_HOME}/.config/Lens
|
|
||||||
# else
|
|
||||||
# rm -rf ${HOME}/.config/Lens
|
|
||||||
# endif
|
|
||||||
yarn build:linux
|
yarn build:linux
|
||||||
yarn integration
|
yarn integration
|
||||||
|
|
||||||
@ -81,7 +76,7 @@ else
|
|||||||
yarn run electron-builder --publish onTag
|
yarn run electron-builder --publish onTag
|
||||||
endif
|
endif
|
||||||
|
|
||||||
$(extension_node_modules):
|
$(extension_node_modules): node_modules
|
||||||
cd $(@:/node_modules=) && ../../node_modules/.bin/npm install --no-audit --no-fund
|
cd $(@:/node_modules=) && ../../node_modules/.bin/npm install --no-audit --no-fund
|
||||||
|
|
||||||
$(extension_dists): src/extensions/npm/extensions/dist
|
$(extension_dists): src/extensions/npm/extensions/dist
|
||||||
@ -102,7 +97,7 @@ copy-extension-themes:
|
|||||||
src/extensions/npm/extensions/__mocks__:
|
src/extensions/npm/extensions/__mocks__:
|
||||||
cp -r __mocks__ src/extensions/npm/extensions/
|
cp -r __mocks__ src/extensions/npm/extensions/
|
||||||
|
|
||||||
src/extensions/npm/extensions/dist:
|
src/extensions/npm/extensions/dist: node_modules
|
||||||
yarn compile:extension-types
|
yarn compile:extension-types
|
||||||
|
|
||||||
.PHONY: build-npm
|
.PHONY: build-npm
|
||||||
|
|||||||
@ -25,7 +25,7 @@ The following example code creates a store for the `appPreferences` guide exampl
|
|||||||
|
|
||||||
``` typescript
|
``` typescript
|
||||||
import { Store } from "@k8slens/extensions";
|
import { Store } from "@k8slens/extensions";
|
||||||
import { observable, toJS } from "mobx";
|
import { observable, makeObservable } from "mobx";
|
||||||
|
|
||||||
export type ExamplePreferencesModel = {
|
export type ExamplePreferencesModel = {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
@ -42,6 +42,7 @@ export class ExamplePreferencesStore extends Store.ExtensionStore<ExamplePrefere
|
|||||||
enabled: false
|
enabled: false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
makeObservable(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fromStore({ enabled }: ExamplePreferencesModel): void {
|
protected fromStore({ enabled }: ExamplePreferencesModel): void {
|
||||||
@ -49,11 +50,9 @@ export class ExamplePreferencesStore extends Store.ExtensionStore<ExamplePrefere
|
|||||||
}
|
}
|
||||||
|
|
||||||
toJSON(): ExamplePreferencesModel {
|
toJSON(): ExamplePreferencesModel {
|
||||||
return toJS({
|
return {
|
||||||
enabled: this.enabled
|
enabled: this.enabled
|
||||||
}, {
|
};
|
||||||
recurseEverything: true
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -73,7 +72,6 @@ The `enabled` field of the `ExamplePreferencesStore` is set to the value from th
|
|||||||
The `toJSON()` method is complementary to `fromStore()`.
|
The `toJSON()` method is complementary to `fromStore()`.
|
||||||
It is called when the store is being saved.
|
It is called when the store is being saved.
|
||||||
`toJSON()` must provide a JSON serializable object, facilitating its storage in JSON format.
|
`toJSON()` must provide a JSON serializable object, facilitating its storage in JSON format.
|
||||||
The `toJS()` function from [`mobx`](https://mobx.js.org/README.html) is convenient for this purpose, and is used here.
|
|
||||||
|
|
||||||
Finally, `ExamplePreferencesStore` is created by calling `ExamplePreferencesStore.getInstanceOrCreate()`, and exported for use by other parts of the extension.
|
Finally, `ExamplePreferencesStore` is created by calling `ExamplePreferencesStore.getInstanceOrCreate()`, and exported for use by other parts of the extension.
|
||||||
Note that `ExamplePreferencesStore` is a singleton.
|
Note that `ExamplePreferencesStore` is a singleton.
|
||||||
|
|||||||
@ -1661,6 +1661,12 @@
|
|||||||
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
|
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"js-tokens": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"json-parse-better-errors": {
|
"json-parse-better-errors": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
|
||||||
@ -1715,6 +1721,15 @@
|
|||||||
"path-exists": "^3.0.0"
|
"path-exists": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"loose-envify": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"lru-cache": {
|
"lru-cache": {
|
||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
||||||
@ -1881,6 +1896,27 @@
|
|||||||
"minimist": "^1.2.5"
|
"minimist": "^1.2.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"mobx": {
|
||||||
|
"version": "6.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/mobx/-/mobx-6.3.1.tgz",
|
||||||
|
"integrity": "sha512-by0VQNBltxLKcQ0uIz2h2mnVv1ZV0ief8mRRw+0k7mL2vSS3806rZg42bt8Vy78szaODtij/5iWIGvc46ZC3Cw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"mobx-react": {
|
||||||
|
"version": "7.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mobx-react/-/mobx-react-7.2.0.tgz",
|
||||||
|
"integrity": "sha512-KHUjZ3HBmZlNnPd1M82jcdVsQRDlfym38zJhZEs33VxyVQTvL77hODCArq6+C1P1k/6erEeo2R7rpE7ZeOL7dg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"mobx-react-lite": "^3.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mobx-react-lite": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mobx-react-lite/-/mobx-react-lite-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-q5+UHIqYCOpBoFm/PElDuOhbcatvTllgRp3M1s+Hp5j0Z6XNgDbgqxawJ0ZAUEyKM8X1zs70PCuhAIzX1f4Q/g==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"move-concurrently": {
|
"move-concurrently": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
|
||||||
@ -2290,6 +2326,16 @@
|
|||||||
"safe-buffer": "^5.1.0"
|
"safe-buffer": "^5.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react": {
|
||||||
|
"version": "17.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
|
||||||
|
"integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"loose-envify": "^1.1.0",
|
||||||
|
"object-assign": "^4.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"readable-stream": {
|
"readable-stream": {
|
||||||
"version": "2.3.7",
|
"version": "2.3.7",
|
||||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
|
"useDefineForClassFields": true,
|
||||||
"jsx": "react"
|
"jsx": "react"
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
|
|||||||
@ -14,7 +14,8 @@
|
|||||||
"clean": "rm -rf dist/ && rm *.tgz"
|
"clean": "rm -rf dist/ && rm *.tgz"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"dist/**/*"
|
"dist/**/*",
|
||||||
|
"resources/**/*"
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@k8slens/extensions": "file:../../src/extensions/npm/extensions",
|
"@k8slens/extensions": "file:../../src/extensions/npm/extensions",
|
||||||
@ -23,6 +24,5 @@
|
|||||||
"ts-loader": "^8.0.4",
|
"ts-loader": "^8.0.4",
|
||||||
"typescript": "^4.0.3",
|
"typescript": "^4.0.3",
|
||||||
"webpack": "^4.44.2"
|
"webpack": "^4.44.2"
|
||||||
},
|
}
|
||||||
"dependencies": {}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,7 +54,7 @@ spec:
|
|||||||
mountPath: /var/lib/prometheus
|
mountPath: /var/lib/prometheus
|
||||||
containers:
|
containers:
|
||||||
- name: prometheus
|
- name: prometheus
|
||||||
image: quay.io/prometheus/prometheus:v2.26.0
|
image: quay.io/prometheus/prometheus:v2.27.1
|
||||||
args:
|
args:
|
||||||
- --web.listen-address=0.0.0.0:9090
|
- --web.listen-address=0.0.0.0:9090
|
||||||
- --config.file=/etc/prometheus/prometheus.yaml
|
- --config.file=/etc/prometheus/prometheus.yaml
|
||||||
|
|||||||
@ -23,23 +23,15 @@ spec:
|
|||||||
operator: In
|
operator: In
|
||||||
values:
|
values:
|
||||||
- linux
|
- linux
|
||||||
- key: kubernetes.io/arch
|
|
||||||
operator: In
|
|
||||||
values:
|
|
||||||
- amd64
|
|
||||||
- matchExpressions:
|
- matchExpressions:
|
||||||
- key: beta.kubernetes.io/os
|
- key: beta.kubernetes.io/os
|
||||||
operator: In
|
operator: In
|
||||||
values:
|
values:
|
||||||
- linux
|
- linux
|
||||||
- key: beta.kubernetes.io/arch
|
|
||||||
operator: In
|
|
||||||
values:
|
|
||||||
- amd64
|
|
||||||
serviceAccountName: kube-state-metrics
|
serviceAccountName: kube-state-metrics
|
||||||
containers:
|
containers:
|
||||||
- name: kube-state-metrics
|
- name: kube-state-metrics
|
||||||
image: quay.io/coreos/kube-state-metrics:v1.9.8
|
image: k8s.gcr.io/kube-state-metrics/kube-state-metrics:v2.0.0
|
||||||
ports:
|
ports:
|
||||||
- name: metrics
|
- name: metrics
|
||||||
containerPort: 8080
|
containerPort: 8080
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Component, Catalog, K8sApi } from "@k8slens/extensions";
|
import { Component, Catalog, K8sApi } from "@k8slens/extensions";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { computed, observable } from "mobx";
|
import { computed, observable, makeObservable } from "mobx";
|
||||||
import { MetricsFeature, MetricsConfiguration } from "./metrics-feature";
|
import { MetricsFeature, MetricsConfiguration } from "./metrics-feature";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -30,6 +30,11 @@ interface Props {
|
|||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class MetricsSettings extends React.Component<Props> {
|
export class MetricsSettings extends React.Component<Props> {
|
||||||
|
constructor(props: Props) {
|
||||||
|
super(props);
|
||||||
|
makeObservable(this);
|
||||||
|
}
|
||||||
|
|
||||||
@observable featureStates = {
|
@observable featureStates = {
|
||||||
prometheus: false,
|
prometheus: false,
|
||||||
kubeStateMetrics: false,
|
kubeStateMetrics: false,
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
|
"useDefineForClassFields": true,
|
||||||
"jsx": "react"
|
"jsx": "react"
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
|
"useDefineForClassFields": true,
|
||||||
"jsx": "react"
|
"jsx": "react"
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
|
"useDefineForClassFields": true,
|
||||||
"jsx": "react"
|
"jsx": "react"
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
|
|||||||
@ -57,17 +57,17 @@ describe("Lens integration tests", () => {
|
|||||||
const appName: string = process.platform === "darwin" ? "OpenLens" : "File";
|
const appName: string = process.platform === "darwin" ? "OpenLens" : "File";
|
||||||
|
|
||||||
await app.electron.ipcRenderer.send("test-menu-item-click", appName, "Preferences");
|
await app.electron.ipcRenderer.send("test-menu-item-click", appName, "Preferences");
|
||||||
await app.client.waitUntilTextExists("[data-testid=application-header]", "APPLICATION");
|
await app.client.waitUntilTextExists("[data-testid=application-header]", "Application");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("shows all tabs and their contents", async () => {
|
it("shows all tabs and their contents", async () => {
|
||||||
await app.client.click("[data-testid=application-tab]");
|
await app.client.click("[data-testid=application-tab]");
|
||||||
await app.client.click("[data-testid=proxy-tab]");
|
await app.client.click("[data-testid=proxy-tab]");
|
||||||
await app.client.waitUntilTextExists("[data-testid=proxy-header]", "PROXY");
|
await app.client.waitUntilTextExists("[data-testid=proxy-header]", "Proxy");
|
||||||
await app.client.click("[data-testid=kube-tab]");
|
await app.client.click("[data-testid=kube-tab]");
|
||||||
await app.client.waitUntilTextExists("[data-testid=kubernetes-header]", "KUBERNETES");
|
await app.client.waitUntilTextExists("[data-testid=kubernetes-header]", "Kubernetes");
|
||||||
await app.client.click("[data-testid=telemetry-tab]");
|
await app.client.click("[data-testid=telemetry-tab]");
|
||||||
await app.client.waitUntilTextExists("[data-testid=telemetry-header]", "TELEMETRY");
|
await app.client.waitUntilTextExists("[data-testid=telemetry-header]", "Telemetry");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("ensures helm repos", async () => {
|
it("ensures helm repos", async () => {
|
||||||
|
|||||||
19
package.json
19
package.json
@ -2,7 +2,7 @@
|
|||||||
"name": "open-lens",
|
"name": "open-lens",
|
||||||
"productName": "OpenLens",
|
"productName": "OpenLens",
|
||||||
"description": "OpenLens - Open Source IDE for Kubernetes",
|
"description": "OpenLens - Open Source IDE for Kubernetes",
|
||||||
"version": "5.0.0-beta.5",
|
"version": "5.0.0-beta.6",
|
||||||
"main": "static/build/main.js",
|
"main": "static/build/main.js",
|
||||||
"copyright": "© 2021 OpenLens Authors",
|
"copyright": "© 2021 OpenLens Authors",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -183,6 +183,8 @@
|
|||||||
"@kubernetes/client-node": "^0.12.0",
|
"@kubernetes/client-node": "^0.12.0",
|
||||||
"abort-controller": "^3.0.0",
|
"abort-controller": "^3.0.0",
|
||||||
"array-move": "^3.0.0",
|
"array-move": "^3.0.0",
|
||||||
|
"auto-bind": "^4.0.0",
|
||||||
|
"autobind-decorator": "^2.4.0",
|
||||||
"await-lock": "^2.1.0",
|
"await-lock": "^2.1.0",
|
||||||
"byline": "^5.0.0",
|
"byline": "^5.0.0",
|
||||||
"chalk": "^4.1.0",
|
"chalk": "^4.1.0",
|
||||||
@ -207,9 +209,9 @@
|
|||||||
"mac-ca": "^1.0.4",
|
"mac-ca": "^1.0.4",
|
||||||
"marked": "^2.0.3",
|
"marked": "^2.0.3",
|
||||||
"md5-file": "^5.0.0",
|
"md5-file": "^5.0.0",
|
||||||
"mobx": "^5.15.7",
|
"mobx": "^6.3.0",
|
||||||
"mobx-observable-history": "^1.0.3",
|
"mobx-observable-history": "^2.0.1",
|
||||||
"mobx-react": "^6.2.2",
|
"mobx-react": "^7.1.0",
|
||||||
"mock-fs": "^4.12.0",
|
"mock-fs": "^4.12.0",
|
||||||
"moment": "^2.26.0",
|
"moment": "^2.26.0",
|
||||||
"moment-timezone": "^0.5.33",
|
"moment-timezone": "^0.5.33",
|
||||||
@ -241,7 +243,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@emeraldpay/hashicon-react": "^0.4.0",
|
"@emeraldpay/hashicon-react": "^0.4.0",
|
||||||
"@material-ui/core": "^4.10.1",
|
"@material-ui/core": "^4.11.4",
|
||||||
"@material-ui/icons": "^4.11.2",
|
"@material-ui/icons": "^4.11.2",
|
||||||
"@material-ui/lab": "^4.0.0-alpha.57",
|
"@material-ui/lab": "^4.0.0-alpha.57",
|
||||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.4.3",
|
"@pmmmwh/react-refresh-webpack-plugin": "^0.4.3",
|
||||||
@ -280,6 +282,7 @@
|
|||||||
"@types/react-dom": "^17.0.0",
|
"@types/react-dom": "^17.0.0",
|
||||||
"@types/react-router-dom": "^5.1.6",
|
"@types/react-router-dom": "^5.1.6",
|
||||||
"@types/react-select": "^3.0.13",
|
"@types/react-select": "^3.0.13",
|
||||||
|
"@types/react-table": "^7.7.0",
|
||||||
"@types/react-window": "^1.8.2",
|
"@types/react-window": "^1.8.2",
|
||||||
"@types/readable-stream": "^2.3.9",
|
"@types/readable-stream": "^2.3.9",
|
||||||
"@types/request": "^2.48.5",
|
"@types/request": "^2.48.5",
|
||||||
@ -336,8 +339,9 @@
|
|||||||
"nodemon": "^2.0.4",
|
"nodemon": "^2.0.4",
|
||||||
"open": "^7.3.1",
|
"open": "^7.3.1",
|
||||||
"patch-package": "^6.2.2",
|
"patch-package": "^6.2.2",
|
||||||
|
"postcss": "^8.2.14",
|
||||||
|
"postcss-loader": "~3.0.0",
|
||||||
"postinstall-postinstall": "^2.1.0",
|
"postinstall-postinstall": "^2.1.0",
|
||||||
"prettier": "^2.2.0",
|
|
||||||
"progress-bar-webpack-plugin": "^2.1.0",
|
"progress-bar-webpack-plugin": "^2.1.0",
|
||||||
"randomcolor": "^0.6.2",
|
"randomcolor": "^0.6.2",
|
||||||
"raw-loader": "^4.0.1",
|
"raw-loader": "^4.0.1",
|
||||||
@ -346,11 +350,13 @@
|
|||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.2.0",
|
||||||
"react-select": "^3.1.0",
|
"react-select": "^3.1.0",
|
||||||
"react-select-event": "^5.1.0",
|
"react-select-event": "^5.1.0",
|
||||||
|
"react-table": "^7.7.0",
|
||||||
"react-window": "^1.8.5",
|
"react-window": "^1.8.5",
|
||||||
"sass-loader": "^8.0.2",
|
"sass-loader": "^8.0.2",
|
||||||
"sharp": "^0.26.1",
|
"sharp": "^0.26.1",
|
||||||
"spectron": "11.0.0",
|
"spectron": "11.0.0",
|
||||||
"style-loader": "^1.2.1",
|
"style-loader": "^1.2.1",
|
||||||
|
"tailwindcss": "^2.1.2",
|
||||||
"ts-jest": "26.3.0",
|
"ts-jest": "26.3.0",
|
||||||
"ts-loader": "^7.0.5",
|
"ts-loader": "^7.0.5",
|
||||||
"ts-node": "^8.10.2",
|
"ts-node": "^8.10.2",
|
||||||
@ -360,6 +366,7 @@
|
|||||||
"typedoc-plugin-markdown": "^2.4.0",
|
"typedoc-plugin-markdown": "^2.4.0",
|
||||||
"typeface-roboto": "^0.0.75",
|
"typeface-roboto": "^0.0.75",
|
||||||
"typescript": "4.0.2",
|
"typescript": "4.0.2",
|
||||||
|
"typescript-plugin-css-modules": "^3.2.0",
|
||||||
"url-loader": "^4.1.0",
|
"url-loader": "^4.1.0",
|
||||||
"webpack": "^4.44.2",
|
"webpack": "^4.44.2",
|
||||||
"webpack-cli": "^3.3.11",
|
"webpack-cli": "^3.3.11",
|
||||||
|
|||||||
28
postcss.config.js
Normal file
28
postcss.config.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2021 OpenLens Authors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const tailwindcss = require("tailwindcss");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
plugins: [
|
||||||
|
tailwindcss("./tailwind.config.js")
|
||||||
|
],
|
||||||
|
};
|
||||||
@ -23,9 +23,8 @@ import path from "path";
|
|||||||
import Config from "conf";
|
import Config from "conf";
|
||||||
import type { Options as ConfOptions } from "conf/dist/source/types";
|
import type { Options as ConfOptions } from "conf/dist/source/types";
|
||||||
import { app, ipcMain, IpcMainEvent, ipcRenderer, IpcRendererEvent, remote } from "electron";
|
import { app, ipcMain, IpcMainEvent, ipcRenderer, IpcRendererEvent, remote } from "electron";
|
||||||
import { IReactionOptions, observable, reaction, runInAction, when } from "mobx";
|
import { IReactionOptions, makeObservable, observable, reaction, runInAction, when } from "mobx";
|
||||||
import Singleton from "./utils/singleton";
|
import { getAppVersion, Singleton, toJS, Disposer } from "./utils";
|
||||||
import { getAppVersion } from "./utils/app-version";
|
|
||||||
import logger from "../main/logger";
|
import logger from "../main/logger";
|
||||||
import { broadcastMessage, subscribeToBroadcast, unsubscribeFromBroadcast } from "./ipc";
|
import { broadcastMessage, subscribeToBroadcast, unsubscribeFromBroadcast } from "./ipc";
|
||||||
import isEqual from "lodash/isEqual";
|
import isEqual from "lodash/isEqual";
|
||||||
@ -41,13 +40,18 @@ export interface BaseStoreParams<T = any> extends ConfOptions<T> {
|
|||||||
*/
|
*/
|
||||||
export abstract class BaseStore<T = any> extends Singleton {
|
export abstract class BaseStore<T = any> extends Singleton {
|
||||||
protected storeConfig?: Config<T>;
|
protected storeConfig?: Config<T>;
|
||||||
protected syncDisposers: Function[] = [];
|
protected syncDisposers: Disposer[] = [];
|
||||||
|
|
||||||
whenLoaded = when(() => this.isLoaded);
|
|
||||||
@observable isLoaded = false;
|
@observable isLoaded = false;
|
||||||
|
|
||||||
|
get whenLoaded() {
|
||||||
|
return when(() => this.isLoaded);
|
||||||
|
}
|
||||||
|
|
||||||
protected constructor(protected params: BaseStoreParams) {
|
protected constructor(protected params: BaseStoreParams) {
|
||||||
super();
|
super();
|
||||||
|
makeObservable(this);
|
||||||
|
|
||||||
this.params = {
|
this.params = {
|
||||||
autoLoad: false,
|
autoLoad: false,
|
||||||
syncEnabled: true,
|
syncEnabled: true,
|
||||||
@ -114,7 +118,11 @@ export abstract class BaseStore<T = any> extends Singleton {
|
|||||||
|
|
||||||
enableSync() {
|
enableSync() {
|
||||||
this.syncDisposers.push(
|
this.syncDisposers.push(
|
||||||
reaction(() => this.toJSON(), model => this.onModelChange(model), this.params.syncOptions),
|
reaction(
|
||||||
|
() => toJS(this.toJSON()), // unwrap possible observables and react to everything
|
||||||
|
model => this.onModelChange(model),
|
||||||
|
this.params.syncOptions,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (ipcMain) {
|
if (ipcMain) {
|
||||||
|
|||||||
@ -19,7 +19,7 @@
|
|||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { action, computed, observable } from "mobx";
|
import { action, computed, observable, makeObservable } from "mobx";
|
||||||
import { Disposer, ExtendedMap } from "../utils";
|
import { Disposer, ExtendedMap } from "../utils";
|
||||||
import { CatalogCategory, CatalogEntityData, CatalogEntityKindData } from "./catalog-entity";
|
import { CatalogCategory, CatalogEntityData, CatalogEntityKindData } from "./catalog-entity";
|
||||||
|
|
||||||
@ -27,6 +27,10 @@ export class CatalogCategoryRegistry {
|
|||||||
protected categories = observable.set<CatalogCategory>();
|
protected categories = observable.set<CatalogCategory>();
|
||||||
protected groupKinds = new ExtendedMap<string, ExtendedMap<string, CatalogCategory>>();
|
protected groupKinds = new ExtendedMap<string, ExtendedMap<string, CatalogCategory>>();
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
makeObservable(this);
|
||||||
|
}
|
||||||
|
|
||||||
@action add(category: CatalogCategory): Disposer {
|
@action add(category: CatalogCategory): Disposer {
|
||||||
this.categories.add(category);
|
this.categories.add(category);
|
||||||
this.updateGroupKinds(category);
|
this.updateGroupKinds(category);
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
import EventEmitter from "events";
|
import EventEmitter from "events";
|
||||||
import type TypedEmitter from "typed-emitter";
|
import type TypedEmitter from "typed-emitter";
|
||||||
import { observable } from "mobx";
|
import { observable, makeObservable } from "mobx";
|
||||||
|
|
||||||
type ExtractEntityMetadataType<Entity> = Entity extends CatalogEntity<infer Metadata> ? Metadata : never;
|
type ExtractEntityMetadataType<Entity> = Entity extends CatalogEntity<infer Metadata> ? Metadata : never;
|
||||||
type ExtractEntityStatusType<Entity> = Entity extends CatalogEntity<any, infer Status> ? Status : never;
|
type ExtractEntityStatusType<Entity> = Entity extends CatalogEntity<any, infer Status> ? Status : never;
|
||||||
@ -63,6 +63,12 @@ export abstract class CatalogCategory extends (EventEmitter as new () => TypedEm
|
|||||||
};
|
};
|
||||||
abstract spec: CatalogCategorySpec;
|
abstract spec: CatalogCategorySpec;
|
||||||
|
|
||||||
|
static parseId(id = ""): { group?: string, kind?: string } {
|
||||||
|
const [group, kind] = id.split("/") ?? [];
|
||||||
|
|
||||||
|
return { group, kind };
|
||||||
|
}
|
||||||
|
|
||||||
public getId(): string {
|
public getId(): string {
|
||||||
return `${this.spec.group}/${this.spec.names.kind}`;
|
return `${this.spec.group}/${this.spec.names.kind}`;
|
||||||
}
|
}
|
||||||
@ -154,6 +160,7 @@ export abstract class CatalogEntity<
|
|||||||
@observable spec: Spec;
|
@observable spec: Spec;
|
||||||
|
|
||||||
constructor(data: CatalogEntityData<Metadata, Status, Spec>) {
|
constructor(data: CatalogEntityData<Metadata, Status, Spec>) {
|
||||||
|
makeObservable(this);
|
||||||
this.metadata = data.metadata;
|
this.metadata = data.metadata;
|
||||||
this.status = data.status;
|
this.status = data.status;
|
||||||
this.spec = data.spec;
|
this.spec = data.spec;
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
import { app, ipcMain, ipcRenderer, remote, webFrame } from "electron";
|
import { app, ipcMain, ipcRenderer, remote, webFrame } from "electron";
|
||||||
import { unlink } from "fs-extra";
|
import { unlink } from "fs-extra";
|
||||||
import { action, comparer, computed, observable, reaction, toJS } from "mobx";
|
import { action, comparer, computed, observable, reaction, makeObservable } from "mobx";
|
||||||
import { BaseStore } from "./base-store";
|
import { BaseStore } from "./base-store";
|
||||||
import { Cluster, ClusterState } from "../main/cluster";
|
import { Cluster, ClusterState } from "../main/cluster";
|
||||||
import migrations from "../migrations/cluster-store";
|
import migrations from "../migrations/cluster-store";
|
||||||
@ -33,7 +33,7 @@ import { saveToAppFiles } from "./utils/saveToAppFiles";
|
|||||||
import type { KubeConfig } from "@kubernetes/client-node";
|
import type { KubeConfig } from "@kubernetes/client-node";
|
||||||
import { handleRequest, requestMain, subscribeToBroadcast, unsubscribeAllFromBroadcast } from "./ipc";
|
import { handleRequest, requestMain, subscribeToBroadcast, unsubscribeAllFromBroadcast } from "./ipc";
|
||||||
import type { ResourceType } from "../renderer/components/cluster-settings/components/cluster-metrics-setting";
|
import type { ResourceType } from "../renderer/components/cluster-settings/components/cluster-metrics-setting";
|
||||||
import { disposer, noop } from "./utils";
|
import { disposer, noop, toJS } from "./utils";
|
||||||
|
|
||||||
export interface ClusterIconUpload {
|
export interface ClusterIconUpload {
|
||||||
clusterId: string;
|
clusterId: string;
|
||||||
@ -148,6 +148,8 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
|||||||
migrations,
|
migrations,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
makeObservable(this);
|
||||||
|
|
||||||
this.pushStateToViewsAutomatically();
|
this.pushStateToViewsAutomatically();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,16 +173,16 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
|||||||
});
|
});
|
||||||
} else if (ipcMain) {
|
} else if (ipcMain) {
|
||||||
handleRequest(ClusterStore.stateRequestChannel, (): clusterStateSync[] => {
|
handleRequest(ClusterStore.stateRequestChannel, (): clusterStateSync[] => {
|
||||||
const states: clusterStateSync[] = [];
|
const clusterStates: clusterStateSync[] = [];
|
||||||
|
|
||||||
this.clustersList.forEach((cluster) => {
|
this.clustersList.forEach((cluster) => {
|
||||||
states.push({
|
clusterStates.push({
|
||||||
state: cluster.getState(),
|
state: cluster.getState(),
|
||||||
id: cluster.id
|
id: cluster.id
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return states;
|
return clusterStates;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -309,7 +311,7 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
|||||||
|
|
||||||
@action
|
@action
|
||||||
protected fromStore({ activeCluster, clusters = [] }: ClusterStoreModel = {}) {
|
protected fromStore({ activeCluster, clusters = [] }: ClusterStoreModel = {}) {
|
||||||
const currentClusters = this.clusters.toJS();
|
const currentClusters = new Map(this.clusters);
|
||||||
const newClusters = new Map<ClusterId, Cluster>();
|
const newClusters = new Map<ClusterId, Cluster>();
|
||||||
const removedClusters = new Map<ClusterId, Cluster>();
|
const removedClusters = new Map<ClusterId, Cluster>();
|
||||||
|
|
||||||
@ -345,8 +347,6 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
|||||||
return toJS({
|
return toJS({
|
||||||
activeCluster: this.activeCluster,
|
activeCluster: this.activeCluster,
|
||||||
clusters: this.clustersList.map(cluster => cluster.toJSON()),
|
clusters: this.clustersList.map(cluster => cluster.toJSON()),
|
||||||
}, {
|
|
||||||
recurseEverything: true
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
44
src/common/configure-packages.ts
Normal file
44
src/common/configure-packages.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2021 OpenLens Authors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as Mobx from "mobx";
|
||||||
|
import * as Immer from "immer";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup default configuration for external npm-packages
|
||||||
|
*/
|
||||||
|
export default function configurePackages() {
|
||||||
|
// Docs: https://mobx.js.org/configuration.html
|
||||||
|
Mobx.configure({
|
||||||
|
enforceActions: "never",
|
||||||
|
isolateGlobalState: true,
|
||||||
|
|
||||||
|
// TODO: enable later (read more: https://mobx.js.org/migrating-from-4-or-5.html)
|
||||||
|
// computedRequiresReaction: true,
|
||||||
|
// reactionRequiresObservable: true,
|
||||||
|
// observableRequiresReaction: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Docs: https://immerjs.github.io/immer/
|
||||||
|
// Required in `utils/storage-helper.ts`
|
||||||
|
Immer.setAutoFreeze(false); // allow to merge mobx observables
|
||||||
|
Immer.enableMapSet(); // allow to merge maps and sets
|
||||||
|
}
|
||||||
@ -19,11 +19,12 @@
|
|||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { action, comparer, observable, toJS } from "mobx";
|
import { action, comparer, observable, makeObservable } from "mobx";
|
||||||
import { BaseStore } from "./base-store";
|
import { BaseStore } from "./base-store";
|
||||||
import migrations from "../migrations/hotbar-store";
|
import migrations from "../migrations/hotbar-store";
|
||||||
import * as uuid from "uuid";
|
import * as uuid from "uuid";
|
||||||
import isNull from "lodash/isNull";
|
import isNull from "lodash/isNull";
|
||||||
|
import { toJS } from "./utils";
|
||||||
import { CatalogEntity } from "./catalog";
|
import { CatalogEntity } from "./catalog";
|
||||||
|
|
||||||
export interface HotbarItem {
|
export interface HotbarItem {
|
||||||
@ -69,6 +70,7 @@ export class HotbarStore extends BaseStore<HotbarStoreModel> {
|
|||||||
},
|
},
|
||||||
migrations,
|
migrations,
|
||||||
});
|
});
|
||||||
|
makeObservable(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
get activeHotbarId() {
|
get activeHotbarId() {
|
||||||
@ -252,8 +254,6 @@ export class HotbarStore extends BaseStore<HotbarStoreModel> {
|
|||||||
activeHotbarId: this.activeHotbarId
|
activeHotbarId: this.activeHotbarId
|
||||||
};
|
};
|
||||||
|
|
||||||
return toJS(model, {
|
return toJS(model);
|
||||||
recurseEverything: true,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,29 +23,34 @@
|
|||||||
// https://www.electronjs.org/docs/api/ipc-main
|
// https://www.electronjs.org/docs/api/ipc-main
|
||||||
// https://www.electronjs.org/docs/api/ipc-renderer
|
// https://www.electronjs.org/docs/api/ipc-renderer
|
||||||
|
|
||||||
import { ipcMain, ipcRenderer, webContents, remote } from "electron";
|
import { ipcMain, ipcRenderer, remote, webContents } from "electron";
|
||||||
import { toJS } from "mobx";
|
import { toJS } from "../utils/toJS";
|
||||||
import logger from "../../main/logger";
|
import logger from "../../main/logger";
|
||||||
import { ClusterFrameInfo, clusterFrameMap } from "../cluster-frames";
|
import { ClusterFrameInfo, clusterFrameMap } from "../cluster-frames";
|
||||||
|
|
||||||
const subFramesChannel = "ipc:get-sub-frames";
|
const subFramesChannel = "ipc:get-sub-frames";
|
||||||
|
|
||||||
export function handleRequest(channel: string, listener: (event: Electron.IpcMainInvokeEvent, ...args: any[]) => any) {
|
export function handleRequest(channel: string, listener: (event: Electron.IpcMainInvokeEvent, ...args: any[]) => any) {
|
||||||
ipcMain.handle(channel, listener);
|
ipcMain.handle(channel, async (event, ...args) => {
|
||||||
|
const payload = await listener(event, ...args);
|
||||||
|
|
||||||
|
return sanitizePayload(payload);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function requestMain(channel: string, ...args: any[]) {
|
export async function requestMain(channel: string, ...args: any[]) {
|
||||||
return ipcRenderer.invoke(channel, ...args);
|
return ipcRenderer.invoke(channel, ...args.map(sanitizePayload));
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSubFrames(): ClusterFrameInfo[] {
|
function getSubFrames(): ClusterFrameInfo[] {
|
||||||
return toJS(Array.from(clusterFrameMap.values()), { recurseEverything: true });
|
return Array.from(clusterFrameMap.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
export function broadcastMessage(channel: string, ...args: any[]) {
|
export function broadcastMessage(channel: string, ...args: any[]) {
|
||||||
const views = (webContents || remote?.webContents)?.getAllWebContents();
|
const views = (webContents || remote?.webContents)?.getAllWebContents();
|
||||||
|
|
||||||
if (!views) return;
|
if (!views) return;
|
||||||
|
args = args.map(sanitizePayload);
|
||||||
|
|
||||||
ipcRenderer?.send(channel, ...args);
|
ipcRenderer?.send(channel, ...args);
|
||||||
ipcMain?.emit(channel, ...args);
|
ipcMain?.emit(channel, ...args);
|
||||||
@ -98,7 +103,13 @@ export function unsubscribeAllFromBroadcast(channel: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function bindBroadcastHandlers() {
|
export function bindBroadcastHandlers() {
|
||||||
handleRequest(subFramesChannel, () => {
|
handleRequest(subFramesChannel, () => getSubFrames());
|
||||||
return getSubFrames();
|
}
|
||||||
});
|
|
||||||
|
/**
|
||||||
|
* Sanitizing data for IPC-messaging before send.
|
||||||
|
* Removes possible observable values to avoid exceptions like "can't clone object".
|
||||||
|
*/
|
||||||
|
function sanitizePayload<T>(data: any): T {
|
||||||
|
return toJS(data);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,9 +19,9 @@
|
|||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { action, computed, observable,reaction } from "mobx";
|
import { action, computed, observable, reaction, makeObservable } from "mobx";
|
||||||
import { dockStore } from "../renderer/components/dock/dock.store";
|
import { dockStore } from "../renderer/components/dock/dock.store";
|
||||||
import { autobind } from "../renderer/utils";
|
import { boundMethod } from "../renderer/utils";
|
||||||
|
|
||||||
export class SearchStore {
|
export class SearchStore {
|
||||||
/**
|
/**
|
||||||
@ -54,6 +54,7 @@ export class SearchStore {
|
|||||||
@observable activeOverlayIndex = -1;
|
@observable activeOverlayIndex = -1;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
makeObservable(this);
|
||||||
reaction(() => dockStore.selectedTabId, () => {
|
reaction(() => dockStore.selectedTabId, () => {
|
||||||
searchStore.reset();
|
searchStore.reset();
|
||||||
});
|
});
|
||||||
@ -128,12 +129,12 @@ export class SearchStore {
|
|||||||
return prev;
|
return prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
@boundMethod
|
||||||
public setNextOverlayActive(): void {
|
public setNextOverlayActive(): void {
|
||||||
this.activeOverlayIndex = this.getNextOverlay(true);
|
this.activeOverlayIndex = this.getNextOverlay(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
@boundMethod
|
||||||
public setPrevOverlayActive(): void {
|
public setPrevOverlayActive(): void {
|
||||||
this.activeOverlayIndex = this.getPrevOverlay(true);
|
this.activeOverlayIndex = this.getPrevOverlay(true);
|
||||||
}
|
}
|
||||||
@ -159,7 +160,7 @@ export class SearchStore {
|
|||||||
* @param line Index of the line where overlay is located
|
* @param line Index of the line where overlay is located
|
||||||
* @param occurrence Number of the overlay within one line
|
* @param occurrence Number of the overlay within one line
|
||||||
*/
|
*/
|
||||||
@autobind()
|
@boundMethod
|
||||||
public isActiveOverlay(line: number, occurrence: number): boolean {
|
public isActiveOverlay(line: number, occurrence: number): boolean {
|
||||||
const firstLineIndex = this.occurrences.findIndex(item => item === line);
|
const firstLineIndex = this.occurrences.findIndex(item => item === line);
|
||||||
|
|
||||||
|
|||||||
@ -23,7 +23,7 @@ import type { ThemeId } from "../renderer/theme.store";
|
|||||||
import { app, remote } from "electron";
|
import { app, remote } from "electron";
|
||||||
import semver from "semver";
|
import semver from "semver";
|
||||||
import { readFile } from "fs-extra";
|
import { readFile } from "fs-extra";
|
||||||
import { action, computed, observable, reaction, toJS } from "mobx";
|
import { action, computed, observable, reaction, makeObservable } from "mobx";
|
||||||
import moment from "moment-timezone";
|
import moment from "moment-timezone";
|
||||||
import { BaseStore } from "./base-store";
|
import { BaseStore } from "./base-store";
|
||||||
import migrations from "../migrations/user-store";
|
import migrations from "../migrations/user-store";
|
||||||
@ -34,7 +34,7 @@ import logger from "../main/logger";
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
import os from "os";
|
import os from "os";
|
||||||
import { fileNameMigration } from "../migrations/user-store";
|
import { fileNameMigration } from "../migrations/user-store";
|
||||||
import { ObservableToggleSet } from "../renderer/utils";
|
import { ObservableToggleSet, toJS } from "../renderer/utils";
|
||||||
|
|
||||||
export interface UserStoreModel {
|
export interface UserStoreModel {
|
||||||
kubeConfigPath: string;
|
kubeConfigPath: string;
|
||||||
@ -73,6 +73,7 @@ export class UserStore extends BaseStore<UserStoreModel> {
|
|||||||
configName: "lens-user-store",
|
configName: "lens-user-store",
|
||||||
migrations,
|
migrations,
|
||||||
});
|
});
|
||||||
|
makeObservable(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@observable lastSeenAppVersion = "0.0.0";
|
@observable lastSeenAppVersion = "0.0.0";
|
||||||
@ -306,9 +307,7 @@ export class UserStore extends BaseStore<UserStoreModel> {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return toJS(model, {
|
return toJS(model);
|
||||||
recurseEverything: true,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
45
src/common/utils/__tests__/toJS.test.ts
Normal file
45
src/common/utils/__tests__/toJS.test.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2021 OpenLens Authors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
import { isObservable, observable } from "mobx";
|
||||||
|
import { toJS } from "../toJS";
|
||||||
|
|
||||||
|
describe("utils/toJS(data: any)", () => {
|
||||||
|
const y = { y: 2 };
|
||||||
|
|
||||||
|
const data = observable({ x: 1, y }, {}, {
|
||||||
|
deep: false, // this will keep ref to "y"
|
||||||
|
});
|
||||||
|
const data2 = {
|
||||||
|
x: 1, // partially observable
|
||||||
|
y: observable(y),
|
||||||
|
};
|
||||||
|
|
||||||
|
test("converts mobx-observable to corresponding js struct with links preserving", () => {
|
||||||
|
expect(toJS(data).y).toBe(y);
|
||||||
|
expect(isObservable(toJS(data).y)).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("converts partially observable js struct", () => {
|
||||||
|
expect(toJS(data2).y).not.toBe(y);
|
||||||
|
expect(toJS(data2).y).toEqual(y);
|
||||||
|
expect(isObservable(toJS(data2).y)).toBeFalsy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -19,48 +19,22 @@
|
|||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Decorator for binding class methods
|
import {boundMethod, boundClass} from "autobind-decorator";
|
||||||
// Can be applied to class or single method as @autobind()
|
import autoBindClass, { Options } from "auto-bind";
|
||||||
type Constructor<T = {}> = new (...args: any[]) => T;
|
import autoBindReactClass from "auto-bind/react";
|
||||||
|
|
||||||
export function autobind() {
|
// Automatically bind methods to their class instance
|
||||||
return function (target: Constructor | object, prop?: string, descriptor?: PropertyDescriptor) {
|
export function autoBind<T extends object>(obj: T, opts?: Options): T {
|
||||||
if (target instanceof Function) return bindClass(target);
|
if ("componentWillUnmount" in obj) {
|
||||||
else return bindMethod(target, prop, descriptor);
|
return autoBindReactClass(obj as any, opts);
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function bindClass<T extends Constructor>(constructor: T) {
|
|
||||||
const proto = constructor.prototype;
|
|
||||||
const descriptors = Object.getOwnPropertyDescriptors(proto);
|
|
||||||
const skipMethod = (methodName: string) => {
|
|
||||||
return methodName === "constructor"
|
|
||||||
|| typeof descriptors[methodName].value !== "function";
|
|
||||||
};
|
|
||||||
|
|
||||||
Object.keys(descriptors).forEach(prop => {
|
|
||||||
if (skipMethod(prop)) return;
|
|
||||||
const boundDescriptor = bindMethod(proto, prop, descriptors[prop]);
|
|
||||||
|
|
||||||
Object.defineProperty(proto, prop, boundDescriptor);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function bindMethod(target: object, prop?: string, descriptor?: PropertyDescriptor) {
|
|
||||||
if (!descriptor || typeof descriptor.value !== "function") {
|
|
||||||
throw new Error(`@autobind() must be used on class or method only`);
|
|
||||||
}
|
}
|
||||||
const { value: func, enumerable, configurable } = descriptor;
|
|
||||||
const boundFunc = new WeakMap<object, Function>();
|
|
||||||
|
|
||||||
return Object.defineProperty(target, prop, {
|
return autoBindClass(obj, opts);
|
||||||
enumerable,
|
|
||||||
configurable,
|
|
||||||
get() {
|
|
||||||
if (this === target) return func; // direct access from prototype
|
|
||||||
if (!boundFunc.has(this)) boundFunc.set(this, func.bind(this));
|
|
||||||
|
|
||||||
return boundFunc.get(this);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Class/method decorators
|
||||||
|
// Note: @boundClass doesn't work with mobx-6.x/@action decorator
|
||||||
|
export {
|
||||||
|
boundClass,
|
||||||
|
boundMethod,
|
||||||
|
};
|
||||||
|
|||||||
@ -19,7 +19,7 @@
|
|||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { action, IEnhancer, IObservableMapInitialValues, ObservableMap } from "mobx";
|
import { action, ObservableMap } from "mobx";
|
||||||
|
|
||||||
export class ExtendedMap<K, V> extends Map<K, V> {
|
export class ExtendedMap<K, V> extends Map<K, V> {
|
||||||
static new<K, V>(entries?: readonly (readonly [K, V])[] | null): ExtendedMap<K, V> {
|
static new<K, V>(entries?: readonly (readonly [K, V])[] | null): ExtendedMap<K, V> {
|
||||||
@ -67,34 +67,12 @@ export class ExtendedMap<K, V> extends Map<K, V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class ExtendedObservableMap<K, V> extends ObservableMap<K, V> {
|
export class ExtendedObservableMap<K, V> extends ObservableMap<K, V> {
|
||||||
constructor(protected getDefault: () => V, initialData?: IObservableMapInitialValues<K, V>, enhancer?: IEnhancer<V>, name?: string) {
|
|
||||||
super(initialData, enhancer, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
@action
|
||||||
getOrInsert(key: K, val: V): V {
|
getOrInsert(key: K, getVal: () => V): V {
|
||||||
if (this.has(key)) {
|
|
||||||
return this.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.set(key, val).get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
getOrInsertWith(key: K, getVal: () => V): V {
|
|
||||||
if (this.has(key)) {
|
if (this.has(key)) {
|
||||||
return this.get(key);
|
return this.get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.set(key, getVal()).get(key);
|
return this.set(key, getVal()).get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
|
||||||
getOrDefault(key: K): V {
|
|
||||||
if (this.has(key)) {
|
|
||||||
return this.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.set(key, this.getDefault()).get(key);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,6 +27,7 @@ export * from "./app-version";
|
|||||||
export * from "./autobind";
|
export * from "./autobind";
|
||||||
export * from "./base64";
|
export * from "./base64";
|
||||||
export * from "./camelCase";
|
export * from "./camelCase";
|
||||||
|
export * from "./toJS";
|
||||||
export * from "./cloneJson";
|
export * from "./cloneJson";
|
||||||
export * from "./debouncePromise";
|
export * from "./debouncePromise";
|
||||||
export * from "./defineGlobal";
|
export * from "./defineGlobal";
|
||||||
|
|||||||
39
src/common/utils/toJS.ts
Normal file
39
src/common/utils/toJS.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2021 OpenLens Authors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for mobx.toJS() to support partially observable objects as data-input (>= mobx6).
|
||||||
|
* Otherwise, output result won't be recursively converted to corresponding plain JS-structure.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* mobx.toJS({one: 1, two: observable.array([2])}); // "data.two" == ObservableArray<number>
|
||||||
|
*/
|
||||||
|
import * as mobx from "mobx";
|
||||||
|
import { isObservable, observable } from "mobx";
|
||||||
|
|
||||||
|
export function toJS<T>(data: T): T {
|
||||||
|
// make data observable for recursive toJS()-output
|
||||||
|
if (typeof data === "object" && !isObservable(data)) {
|
||||||
|
return mobx.toJS(observable.box(data).get());
|
||||||
|
}
|
||||||
|
|
||||||
|
return mobx.toJS(data);
|
||||||
|
}
|
||||||
@ -19,7 +19,7 @@
|
|||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { action, ObservableSet } from "mobx";
|
import { ObservableSet } from "mobx";
|
||||||
|
|
||||||
export class ToggleSet<T> extends Set<T> {
|
export class ToggleSet<T> extends Set<T> {
|
||||||
public toggle(value: T): void {
|
public toggle(value: T): void {
|
||||||
@ -31,7 +31,6 @@ export class ToggleSet<T> extends Set<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class ObservableToggleSet<T> extends ObservableSet<T> {
|
export class ObservableToggleSet<T> extends ObservableSet<T> {
|
||||||
@action
|
|
||||||
public toggle(value: T): void {
|
public toggle(value: T): void {
|
||||||
if (!this.delete(value)) {
|
if (!this.delete(value)) {
|
||||||
// Set.prototype.delete returns false if `value` was not in the set
|
// Set.prototype.delete returns false if `value` was not in the set
|
||||||
|
|||||||
@ -19,7 +19,8 @@
|
|||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Extension-api types generation bundle
|
// Extensions-api types bundle (main + renderer)
|
||||||
|
// Available for lens-extensions via NPM-package "@k8slens/extensions"
|
||||||
|
|
||||||
export * from "./core-api";
|
export * from "./core-api";
|
||||||
export * from "./renderer-api";
|
export * from "./renderer-api";
|
||||||
|
|||||||
@ -23,11 +23,11 @@ import { watch } from "chokidar";
|
|||||||
import { ipcRenderer } from "electron";
|
import { ipcRenderer } from "electron";
|
||||||
import { EventEmitter } from "events";
|
import { EventEmitter } from "events";
|
||||||
import fse from "fs-extra";
|
import fse from "fs-extra";
|
||||||
import { observable, reaction, toJS, when } from "mobx";
|
import { observable, reaction, when, makeObservable } from "mobx";
|
||||||
import os from "os";
|
import os from "os";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { broadcastMessage, handleRequest, requestMain, subscribeToBroadcast } from "../common/ipc";
|
import { broadcastMessage, handleRequest, requestMain, subscribeToBroadcast } from "../common/ipc";
|
||||||
import { Singleton } from "../common/utils";
|
import { Singleton, toJS } from "../common/utils";
|
||||||
import logger from "../main/logger";
|
import logger from "../main/logger";
|
||||||
import { ExtensionInstallationStateStore } from "../renderer/components/+extensions/extension-install.store";
|
import { ExtensionInstallationStateStore } from "../renderer/components/+extensions/extension-install.store";
|
||||||
import { extensionInstaller, PackageJson } from "./extension-installer";
|
import { extensionInstaller, PackageJson } from "./extension-installer";
|
||||||
@ -86,13 +86,22 @@ export class ExtensionDiscovery extends Singleton {
|
|||||||
|
|
||||||
// True if extensions have been loaded from the disk after app startup
|
// True if extensions have been loaded from the disk after app startup
|
||||||
@observable isLoaded = false;
|
@observable isLoaded = false;
|
||||||
whenLoaded = when(() => this.isLoaded);
|
|
||||||
|
get whenLoaded() {
|
||||||
|
return when(() => this.isLoaded);
|
||||||
|
}
|
||||||
|
|
||||||
// IPC channel to broadcast changes to extension-discovery from main
|
// IPC channel to broadcast changes to extension-discovery from main
|
||||||
protected static readonly extensionDiscoveryChannel = "extension-discovery:main";
|
protected static readonly extensionDiscoveryChannel = "extension-discovery:main";
|
||||||
|
|
||||||
public events = new EventEmitter();
|
public events = new EventEmitter();
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
makeObservable(this);
|
||||||
|
}
|
||||||
|
|
||||||
get localFolderPath(): string {
|
get localFolderPath(): string {
|
||||||
return path.join(os.homedir(), ".k8slens", "extensions");
|
return path.join(os.homedir(), ".k8slens", "extensions");
|
||||||
}
|
}
|
||||||
@ -374,7 +383,7 @@ export class ExtensionDiscovery extends Singleton {
|
|||||||
const userExtensions = await this.loadFromFolder(this.localFolderPath, bundledExtensions.map((extension) => extension.manifest.name));
|
const userExtensions = await this.loadFromFolder(this.localFolderPath, bundledExtensions.map((extension) => extension.manifest.name));
|
||||||
|
|
||||||
for (const extension of userExtensions) {
|
for (const extension of userExtensions) {
|
||||||
if (await fse.pathExists(extension.manifestPath) === false) {
|
if ((await fse.pathExists(extension.manifestPath)) === false) {
|
||||||
await this.installPackage(extension.absolutePath);
|
await this.installPackage(extension.absolutePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -468,8 +477,6 @@ export class ExtensionDiscovery extends Singleton {
|
|||||||
toJSON(): ExtensionDiscoveryChannelMessage {
|
toJSON(): ExtensionDiscoveryChannelMessage {
|
||||||
return toJS({
|
return toJS({
|
||||||
isLoaded: this.isLoaded
|
isLoaded: this.isLoaded
|
||||||
}, {
|
|
||||||
recurseEverything: true
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,11 +22,11 @@
|
|||||||
import { app, ipcRenderer, remote } from "electron";
|
import { app, ipcRenderer, remote } from "electron";
|
||||||
import { EventEmitter } from "events";
|
import { EventEmitter } from "events";
|
||||||
import { isEqual } from "lodash";
|
import { isEqual } from "lodash";
|
||||||
import { action, computed, observable, reaction, toJS, when } from "mobx";
|
import { action, computed, makeObservable, observable, reaction, when } from "mobx";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { getHostedCluster } from "../common/cluster-store";
|
import { getHostedCluster } from "../common/cluster-store";
|
||||||
import { broadcastMessage, handleRequest, requestMain, subscribeToBroadcast } from "../common/ipc";
|
import { broadcastMessage, handleRequest, requestMain, subscribeToBroadcast } from "../common/ipc";
|
||||||
import { Singleton } from "../common/utils";
|
import { Singleton, toJS } from "../common/utils";
|
||||||
import logger from "../main/logger";
|
import logger from "../main/logger";
|
||||||
import type { InstalledExtension } from "./extension-discovery";
|
import type { InstalledExtension } from "./extension-discovery";
|
||||||
import { ExtensionsStore } from "./extensions-store";
|
import { ExtensionsStore } from "./extensions-store";
|
||||||
@ -58,10 +58,19 @@ export class ExtensionLoader extends Singleton {
|
|||||||
private events = new EventEmitter();
|
private events = new EventEmitter();
|
||||||
|
|
||||||
@observable isLoaded = false;
|
@observable isLoaded = false;
|
||||||
whenLoaded = when(() => this.isLoaded);
|
|
||||||
|
get whenLoaded() {
|
||||||
|
return when(() => this.isLoaded);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
makeObservable(this);
|
||||||
|
}
|
||||||
|
|
||||||
@computed get userExtensions(): Map<LensExtensionId, InstalledExtension> {
|
@computed get userExtensions(): Map<LensExtensionId, InstalledExtension> {
|
||||||
const extensions = this.extensions.toJS();
|
const extensions = this.toJSON();
|
||||||
|
|
||||||
extensions.forEach((ext, extId) => {
|
extensions.forEach((ext, extId) => {
|
||||||
if (ext.isBundled) {
|
if (ext.isBundled) {
|
||||||
@ -75,7 +84,7 @@ export class ExtensionLoader extends Singleton {
|
|||||||
@computed get userExtensionsByName(): Map<string, LensExtension> {
|
@computed get userExtensionsByName(): Map<string, LensExtension> {
|
||||||
const extensions = new Map();
|
const extensions = new Map();
|
||||||
|
|
||||||
for (const [, val] of this.instances.toJS()) {
|
for (const [, val] of this.instances.toJSON()) {
|
||||||
if (val.isBundled) {
|
if (val.isBundled) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -117,6 +126,11 @@ export class ExtensionLoader extends Singleton {
|
|||||||
|
|
||||||
await Promise.all([this.whenLoaded, ExtensionsStore.getInstance().whenLoaded]);
|
await Promise.all([this.whenLoaded, ExtensionsStore.getInstance().whenLoaded]);
|
||||||
|
|
||||||
|
// broadcasting extensions between main/renderer processes
|
||||||
|
reaction(() => this.toJSON(), () => this.broadcastExtensions(), {
|
||||||
|
fireImmediately: true,
|
||||||
|
});
|
||||||
|
|
||||||
// save state on change `extension.isEnabled`
|
// save state on change `extension.isEnabled`
|
||||||
reaction(() => this.storeState, extensionsState => {
|
reaction(() => this.storeState, extensionsState => {
|
||||||
ExtensionsStore.getInstance().mergeState(extensionsState);
|
ExtensionsStore.getInstance().mergeState(extensionsState);
|
||||||
@ -156,14 +170,10 @@ export class ExtensionLoader extends Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async initMain() {
|
protected async initMain() {
|
||||||
this.isLoaded = true;
|
this.isLoaded = true;
|
||||||
this.loadOnMain();
|
this.loadOnMain();
|
||||||
|
|
||||||
reaction(() => this.toJSON(), () => {
|
|
||||||
this.broadcastExtensions();
|
|
||||||
});
|
|
||||||
|
|
||||||
handleRequest(ExtensionLoader.extensionsMainChannel, () => {
|
handleRequest(ExtensionLoader.extensionsMainChannel, () => {
|
||||||
return Array.from(this.toJSON());
|
return Array.from(this.toJSON());
|
||||||
});
|
});
|
||||||
@ -173,7 +183,7 @@ export class ExtensionLoader extends Singleton {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async initRenderer() {
|
protected async initRenderer() {
|
||||||
const extensionListHandler = (extensions: [LensExtensionId, InstalledExtension][]) => {
|
const extensionListHandler = (extensions: [LensExtensionId, InstalledExtension][]) => {
|
||||||
this.isLoaded = true;
|
this.isLoaded = true;
|
||||||
this.syncExtensions(extensions);
|
this.syncExtensions(extensions);
|
||||||
@ -188,16 +198,20 @@ export class ExtensionLoader extends Singleton {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
reaction(() => this.toJSON(), () => {
|
|
||||||
this.broadcastExtensions(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
requestMain(ExtensionLoader.extensionsMainChannel).then(extensionListHandler);
|
requestMain(ExtensionLoader.extensionsMainChannel).then(extensionListHandler);
|
||||||
subscribeToBroadcast(ExtensionLoader.extensionsMainChannel, (_event, extensions: [LensExtensionId, InstalledExtension][]) => {
|
subscribeToBroadcast(ExtensionLoader.extensionsMainChannel, (_event, extensions: [LensExtensionId, InstalledExtension][]) => {
|
||||||
extensionListHandler(extensions);
|
extensionListHandler(extensions);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
broadcastExtensions() {
|
||||||
|
const channel = ipcRenderer
|
||||||
|
? ExtensionLoader.extensionsRendererChannel
|
||||||
|
: ExtensionLoader.extensionsMainChannel;
|
||||||
|
|
||||||
|
broadcastMessage(channel, Array.from(this.extensions));
|
||||||
|
}
|
||||||
|
|
||||||
syncExtensions(extensions: [LensExtensionId, InstalledExtension][]) {
|
syncExtensions(extensions: [LensExtensionId, InstalledExtension][]) {
|
||||||
extensions.forEach(([lensExtensionId, extension]) => {
|
extensions.forEach(([lensExtensionId, extension]) => {
|
||||||
if (!isEqual(this.extensions.get(lensExtensionId), extension)) {
|
if (!isEqual(this.extensions.get(lensExtensionId), extension)) {
|
||||||
@ -255,7 +269,7 @@ export class ExtensionLoader extends Singleton {
|
|||||||
const cluster = getHostedCluster();
|
const cluster = getHostedCluster();
|
||||||
|
|
||||||
this.autoInitExtensions(async (extension: LensRendererExtension) => {
|
this.autoInitExtensions(async (extension: LensRendererExtension) => {
|
||||||
if (await extension.isEnabledForCluster(cluster) === false) {
|
if ((await extension.isEnabledForCluster(cluster)) === false) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,13 +348,6 @@ export class ExtensionLoader extends Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toJSON(): Map<LensExtensionId, InstalledExtension> {
|
toJSON(): Map<LensExtensionId, InstalledExtension> {
|
||||||
return toJS(this.extensions, {
|
return toJS(this.extensions);
|
||||||
exportMapsAsObjects: false,
|
|
||||||
recurseEverything: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
broadcastExtensions(main = true) {
|
|
||||||
broadcastMessage(main ? ExtensionLoader.extensionsMainChannel : ExtensionLoader.extensionsRendererChannel, Array.from(this.toJSON()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,7 +21,8 @@
|
|||||||
|
|
||||||
import type { LensExtensionId } from "./lens-extension";
|
import type { LensExtensionId } from "./lens-extension";
|
||||||
import { BaseStore } from "../common/base-store";
|
import { BaseStore } from "../common/base-store";
|
||||||
import { action, computed, observable, toJS } from "mobx";
|
import { action, computed, observable, makeObservable } from "mobx";
|
||||||
|
import { toJS } from "../common/utils";
|
||||||
|
|
||||||
export interface LensExtensionsStoreModel {
|
export interface LensExtensionsStoreModel {
|
||||||
extensions: Record<LensExtensionId, LensExtensionState>;
|
extensions: Record<LensExtensionId, LensExtensionState>;
|
||||||
@ -37,6 +38,7 @@ export class ExtensionsStore extends BaseStore<LensExtensionsStoreModel> {
|
|||||||
super({
|
super({
|
||||||
configName: "lens-extensions",
|
configName: "lens-extensions",
|
||||||
});
|
});
|
||||||
|
makeObservable(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
@ -68,9 +70,7 @@ export class ExtensionsStore extends BaseStore<LensExtensionsStoreModel> {
|
|||||||
|
|
||||||
toJSON(): LensExtensionsStoreModel {
|
toJSON(): LensExtensionsStoreModel {
|
||||||
return toJS({
|
return toJS({
|
||||||
extensions: this.state.toJSON(),
|
extensions: Object.fromEntries(this.state),
|
||||||
}, {
|
|
||||||
recurseEverything: true
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import type { InstalledExtension } from "./extension-discovery";
|
import type { InstalledExtension } from "./extension-discovery";
|
||||||
import { action, observable, reaction } from "mobx";
|
import { action, observable, reaction, makeObservable } from "mobx";
|
||||||
import { FilesystemProvisionerStore } from "../main/extension-filesystem";
|
import { FilesystemProvisionerStore } from "../main/extension-filesystem";
|
||||||
import logger from "../main/logger";
|
import logger from "../main/logger";
|
||||||
import type { ProtocolHandlerRegistration } from "./registries";
|
import type { ProtocolHandlerRegistration } from "./registries";
|
||||||
@ -52,6 +52,7 @@ export class LensExtension {
|
|||||||
[Disposers] = disposer();
|
[Disposers] = disposer();
|
||||||
|
|
||||||
constructor({ id, manifest, manifestPath, isBundled }: InstalledExtension) {
|
constructor({ id, manifest, manifestPath, isBundled }: InstalledExtension) {
|
||||||
|
makeObservable(this);
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.manifest = manifest;
|
this.manifest = manifest;
|
||||||
this.manifestPath = manifestPath;
|
this.manifestPath = manifestPath;
|
||||||
|
|||||||
@ -75,15 +75,22 @@ describe("getPageUrl", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("gets page url with custom params", () => {
|
it("gets page url with custom params", () => {
|
||||||
const params: PageParams<string> = { test1: "one", test2: "2" };
|
const params: PageParams = { test1: "one", test2: "2" };
|
||||||
const searchParams = new URLSearchParams(params);
|
const searchParams = new URLSearchParams(params);
|
||||||
const pageUrl = getExtensionPageUrl({ extensionId: ext.name, pageId: "page-with-params", params });
|
const pageUrl = getExtensionPageUrl({
|
||||||
|
extensionId: ext.name,
|
||||||
|
pageId: "page-with-params",
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
|
||||||
expect(pageUrl).toBe(`/extension/foo-bar/page-with-params?${searchParams}`);
|
expect(pageUrl).toBe(`/extension/foo-bar/page-with-params?${searchParams}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("gets page url with default custom params", () => {
|
it("gets page url with default custom params", () => {
|
||||||
const defaultPageUrl = getExtensionPageUrl({ extensionId: ext.name, pageId: "page-with-params", });
|
const defaultPageUrl = getExtensionPageUrl({
|
||||||
|
extensionId: ext.name,
|
||||||
|
pageId: "page-with-params",
|
||||||
|
});
|
||||||
|
|
||||||
expect(defaultPageUrl).toBe(`/extension/foo-bar/page-with-params?test1=test1-default`);
|
expect(defaultPageUrl).toBe(`/extension/foo-bar/page-with-params?test1=test1-default`);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -20,12 +20,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Base class for extensions-api registries
|
// Base class for extensions-api registries
|
||||||
import { action, observable } from "mobx";
|
import { action, observable, makeObservable } from "mobx";
|
||||||
import { LensExtension } from "../lens-extension";
|
import { LensExtension } from "../lens-extension";
|
||||||
|
|
||||||
export class BaseRegistry<T, I = T> {
|
export class BaseRegistry<T, I = T> {
|
||||||
private items = observable.map<T, I>();
|
private items = observable.map<T, I>();
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
makeObservable(this);
|
||||||
|
}
|
||||||
|
|
||||||
getItems(): I[] {
|
getItems(): I[] {
|
||||||
return Array.from(this.items.values());
|
return Array.from(this.items.values());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,9 +22,9 @@
|
|||||||
// Extensions API -> Commands
|
// Extensions API -> Commands
|
||||||
|
|
||||||
import { BaseRegistry } from "./base-registry";
|
import { BaseRegistry } from "./base-registry";
|
||||||
import { action, observable } from "mobx";
|
import { makeObservable, observable } from "mobx";
|
||||||
import { LensExtension } from "../lens-extension";
|
import type { LensExtension } from "../lens-extension";
|
||||||
import { CatalogEntity } from "../../common/catalog";
|
import type { CatalogEntity } from "../../common/catalog";
|
||||||
|
|
||||||
export type CommandContext = {
|
export type CommandContext = {
|
||||||
entity?: CatalogEntity;
|
entity?: CatalogEntity;
|
||||||
@ -39,9 +39,14 @@ export interface CommandRegistration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class CommandRegistry extends BaseRegistry<CommandRegistration> {
|
export class CommandRegistry extends BaseRegistry<CommandRegistration> {
|
||||||
@observable activeEntity: CatalogEntity;
|
@observable.ref activeEntity: CatalogEntity;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
makeObservable(this);
|
||||||
|
}
|
||||||
|
|
||||||
@action
|
|
||||||
add(items: CommandRegistration | CommandRegistration[], extension?: LensExtension) {
|
add(items: CommandRegistration | CommandRegistration[], extension?: LensExtension) {
|
||||||
const itemArray = [items].flat();
|
const itemArray = [items].flat();
|
||||||
|
|
||||||
|
|||||||
@ -23,9 +23,8 @@
|
|||||||
import type { IconProps } from "../../renderer/components/icon";
|
import type { IconProps } from "../../renderer/components/icon";
|
||||||
import type React from "react";
|
import type React from "react";
|
||||||
import type { PageTarget, RegisteredPage } from "./page-registry";
|
import type { PageTarget, RegisteredPage } from "./page-registry";
|
||||||
import { action } from "mobx";
|
import type { LensExtension } from "../lens-extension";
|
||||||
import { BaseRegistry } from "./base-registry";
|
import { BaseRegistry } from "./base-registry";
|
||||||
import { LensExtension } from "../lens-extension";
|
|
||||||
|
|
||||||
export interface PageMenuRegistration {
|
export interface PageMenuRegistration {
|
||||||
target?: PageTarget;
|
target?: PageTarget;
|
||||||
@ -43,7 +42,6 @@ export interface PageMenuComponents {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class PageMenuRegistry<T extends PageMenuRegistration> extends BaseRegistry<T> {
|
export class PageMenuRegistry<T extends PageMenuRegistration> extends BaseRegistry<T> {
|
||||||
@action
|
|
||||||
add(items: T[], ext: LensExtension) {
|
add(items: T[], ext: LensExtension) {
|
||||||
const normalizedItems = items.map(menuItem => {
|
const normalizedItems = items.map(menuItem => {
|
||||||
menuItem.target = {
|
menuItem.target = {
|
||||||
|
|||||||
@ -24,9 +24,8 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { BaseRegistry } from "./base-registry";
|
import { BaseRegistry } from "./base-registry";
|
||||||
import { LensExtension, sanitizeExtensionName } from "../lens-extension";
|
import { LensExtension, LensExtensionId, sanitizeExtensionName } from "../lens-extension";
|
||||||
import type { PageParam, PageParamInit } from "../../renderer/navigation/page-param";
|
import { createPageParam, PageParam, PageParamInit, searchParamsOptions } from "../../renderer/navigation";
|
||||||
import { createPageParam } from "../../renderer/navigation/helpers";
|
|
||||||
|
|
||||||
export interface PageRegistration {
|
export interface PageRegistration {
|
||||||
/**
|
/**
|
||||||
@ -34,21 +33,18 @@ export interface PageRegistration {
|
|||||||
* When not provided, first registered page without "id" would be used for page-menus without target.pageId for same extension
|
* When not provided, first registered page without "id" would be used for page-menus without target.pageId for same extension
|
||||||
*/
|
*/
|
||||||
id?: string;
|
id?: string;
|
||||||
params?: PageParams<string | ExtensionPageParamInit>;
|
params?: PageParams<string | Omit<PageParamInit<any>, "name" | "prefix">>;
|
||||||
components: PageComponents;
|
components: PageComponents;
|
||||||
}
|
}
|
||||||
|
|
||||||
// exclude "name" field since provided as key in page.params
|
|
||||||
export type ExtensionPageParamInit = Omit<PageParamInit, "name" | "isSystem">;
|
|
||||||
|
|
||||||
export interface PageComponents {
|
export interface PageComponents {
|
||||||
Page: React.ComponentType<any>;
|
Page: React.ComponentType<any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PageTarget<P = PageParams> {
|
export interface PageTarget {
|
||||||
extensionId?: string;
|
extensionId?: string;
|
||||||
pageId?: string;
|
pageId?: string;
|
||||||
params?: P;
|
params?: PageParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PageParams<V = any> {
|
export interface PageParams<V = any> {
|
||||||
@ -83,13 +79,12 @@ export function getExtensionPageUrl(target: PageTarget): string {
|
|||||||
|
|
||||||
if (registeredPage?.params) {
|
if (registeredPage?.params) {
|
||||||
Object.entries(registeredPage.params).forEach(([name, param]) => {
|
Object.entries(registeredPage.params).forEach(([name, param]) => {
|
||||||
const paramValue = param.stringify(targetParams[name]);
|
pageUrl.searchParams.delete(name); // first off, clear existing value(s)
|
||||||
|
|
||||||
if (param.init.skipEmpty && param.isEmpty(paramValue)) {
|
param.stringify(targetParams[name]).forEach(value => {
|
||||||
pageUrl.searchParams.delete(name);
|
if (searchParamsOptions.skipEmpty && !value) return;
|
||||||
} else {
|
pageUrl.searchParams.append(name, value);
|
||||||
pageUrl.searchParams.set(name, paramValue);
|
});
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +95,7 @@ export class PageRegistry extends BaseRegistry<PageRegistration, RegisteredPage>
|
|||||||
protected getRegisteredItem(page: PageRegistration, ext: LensExtension): RegisteredPage {
|
protected getRegisteredItem(page: PageRegistration, ext: LensExtension): RegisteredPage {
|
||||||
const { id: pageId } = page;
|
const { id: pageId } = page;
|
||||||
const extensionId = ext.name;
|
const extensionId = ext.name;
|
||||||
const params = this.normalizeParams(page.params);
|
const params = this.normalizeParams(extensionId, page.params);
|
||||||
const components = this.normalizeComponents(page.components, params);
|
const components = this.normalizeComponents(page.components, params);
|
||||||
const url = getExtensionPageUrl({ extensionId, pageId });
|
const url = getExtensionPageUrl({ extensionId, pageId });
|
||||||
|
|
||||||
@ -113,25 +108,48 @@ export class PageRegistry extends BaseRegistry<PageRegistration, RegisteredPage>
|
|||||||
if (params) {
|
if (params) {
|
||||||
const { Page } = components;
|
const { Page } = components;
|
||||||
|
|
||||||
|
// inject extension's page component props.params
|
||||||
components.Page = observer((props: object) => React.createElement(Page, { params, ...props }));
|
components.Page = observer((props: object) => React.createElement(Page, { params, ...props }));
|
||||||
}
|
}
|
||||||
|
|
||||||
return components;
|
return components;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected normalizeParams(params?: PageParams<string | ExtensionPageParamInit>): PageParams<PageParam> | undefined {
|
protected normalizeParams(extensionId: LensExtensionId, params?: PageParams<string | Partial<PageParamInit>>): PageParams<PageParam> {
|
||||||
if (!params) {
|
if (!params) return undefined;
|
||||||
return undefined;
|
const normalizedParams: PageParams<PageParam> = {};
|
||||||
}
|
|
||||||
Object.entries(params).forEach(([name, value]) => {
|
|
||||||
const paramInit: PageParamInit = typeof value === "object"
|
|
||||||
? { name, ...value }
|
|
||||||
: { name, defaultValue: value };
|
|
||||||
|
|
||||||
params[paramInit.name] = createPageParam(paramInit);
|
Object.entries(params).forEach(([paramName, paramValue]) => {
|
||||||
|
const paramInit: PageParamInit = {
|
||||||
|
name: paramName,
|
||||||
|
prefix: `${extensionId}:`,
|
||||||
|
defaultValue: paramValue,
|
||||||
|
};
|
||||||
|
|
||||||
|
// handle non-string params
|
||||||
|
if (typeof paramValue !== "string") {
|
||||||
|
const { defaultValue: value, parse, stringify } = paramValue;
|
||||||
|
|
||||||
|
const notAStringValue = typeof value !== "string" || (
|
||||||
|
Array.isArray(value) && !value.every(value => typeof value === "string")
|
||||||
|
);
|
||||||
|
|
||||||
|
if (notAStringValue && !(parse || stringify)) {
|
||||||
|
throw new Error(
|
||||||
|
`PageRegistry: param's "${paramName}" initialization has failed:
|
||||||
|
paramInit.parse() and paramInit.stringify() are required for non string | string[] "defaultValue"`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
paramInit.defaultValue = value;
|
||||||
|
paramInit.parse = parse;
|
||||||
|
paramInit.stringify = stringify;
|
||||||
|
}
|
||||||
|
|
||||||
|
normalizedParams[paramName] = createPageParam(paramInit);
|
||||||
});
|
});
|
||||||
|
|
||||||
return params as PageParams<PageParam>;
|
return normalizedParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
getByPageTarget(target: PageTarget): RegisteredPage | null {
|
getByPageTarget(target: PageTarget): RegisteredPage | null {
|
||||||
|
|||||||
@ -19,15 +19,13 @@
|
|||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { PageParam, PageParamInit } from "../../renderer/navigation/page-param";
|
import { navigation, PageParam, PageParamInit } from "../../renderer/navigation";
|
||||||
import { navigation } from "../../renderer/navigation";
|
|
||||||
|
|
||||||
export type { PageParamInit, PageParam } from "../../renderer/navigation/page-param";
|
export type { PageParamInit, PageParam } from "../../renderer/navigation/page-param";
|
||||||
export { navigate, isActiveRoute } from "../../renderer/navigation/helpers";
|
export { navigate, isActiveRoute } from "../../renderer/navigation/helpers";
|
||||||
export { hideDetails, showDetails, getDetailsUrl } from "../../renderer/components/kube-object/kube-object-details";
|
export { hideDetails, showDetails, getDetailsUrl } from "../../renderer/components/kube-object/kube-object-details";
|
||||||
export type { IURLParams } from "../../common/utils/buildUrl";
|
export type { IURLParams } from "../../common/utils/buildUrl";
|
||||||
|
|
||||||
// exporting to extensions-api version of helper without `isSystem` flag
|
export function createPageParam<V>(init: PageParamInit<V>) {
|
||||||
export function createPageParam<V = string>(init: PageParamInit<V>) {
|
|
||||||
return new PageParam<V>(init, navigation);
|
return new PageParam<V>(init, navigation);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,6 +20,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import fetchMock from "jest-fetch-mock";
|
import fetchMock from "jest-fetch-mock";
|
||||||
|
import configurePackages from "./common/configure-packages";
|
||||||
|
|
||||||
|
// setup default configuration for external npm-packages
|
||||||
|
configurePackages();
|
||||||
|
|
||||||
// rewire global.fetch to call 'fetchMock'
|
// rewire global.fetch to call 'fetchMock'
|
||||||
fetchMock.enableMocks();
|
fetchMock.enableMocks();
|
||||||
|
|
||||||
|
|||||||
@ -19,13 +19,14 @@
|
|||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { reaction, toJS } from "mobx";
|
import { reaction } from "mobx";
|
||||||
import { broadcastMessage } from "../common/ipc";
|
import { broadcastMessage } from "../common/ipc";
|
||||||
import type { CatalogEntityRegistry} from "./catalog";
|
import type { CatalogEntityRegistry } from "./catalog";
|
||||||
import "../common/catalog-entities/kubernetes-cluster";
|
import "../common/catalog-entities/kubernetes-cluster";
|
||||||
|
import { toJS } from "../common/utils";
|
||||||
|
|
||||||
export function pushCatalogToRenderer(catalog: CatalogEntityRegistry) {
|
export function pushCatalogToRenderer(catalog: CatalogEntityRegistry) {
|
||||||
return reaction(() => toJS(catalog.items, { recurseEverything: true }), (items) => {
|
return reaction(() => toJS(catalog.items), (items) => {
|
||||||
broadcastMessage("catalog:items", items);
|
broadcastMessage("catalog:items", items);
|
||||||
}, {
|
}, {
|
||||||
fireImmediately: true,
|
fireImmediately: true,
|
||||||
|
|||||||
@ -28,6 +28,12 @@ import mockFs from "mock-fs";
|
|||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import { ClusterStore } from "../../../common/cluster-store";
|
import { ClusterStore } from "../../../common/cluster-store";
|
||||||
|
|
||||||
|
jest.mock("electron", () => ({
|
||||||
|
app: {
|
||||||
|
getPath: () => "/foo",
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
describe("kubeconfig-sync.source tests", () => {
|
describe("kubeconfig-sync.source tests", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockFs();
|
mockFs();
|
||||||
|
|||||||
@ -19,7 +19,7 @@
|
|||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { action, observable, IComputedValue, computed, ObservableMap, runInAction } from "mobx";
|
import { action, observable, IComputedValue, computed, ObservableMap, runInAction, makeObservable, observe } from "mobx";
|
||||||
import type { CatalogEntity } from "../../common/catalog";
|
import type { CatalogEntity } from "../../common/catalog";
|
||||||
import { catalogEntityRegistry } from "../../main/catalog";
|
import { catalogEntityRegistry } from "../../main/catalog";
|
||||||
import { watch } from "chokidar";
|
import { watch } from "chokidar";
|
||||||
@ -35,6 +35,7 @@ import { catalogEntityFromCluster } from "../cluster-manager";
|
|||||||
import { UserStore } from "../../common/user-store";
|
import { UserStore } from "../../common/user-store";
|
||||||
import { ClusterStore, UpdateClusterModel } from "../../common/cluster-store";
|
import { ClusterStore, UpdateClusterModel } from "../../common/cluster-store";
|
||||||
import { createHash } from "crypto";
|
import { createHash } from "crypto";
|
||||||
|
import { homedir } from "os";
|
||||||
|
|
||||||
const logPrefix = "[KUBECONFIG-SYNC]:";
|
const logPrefix = "[KUBECONFIG-SYNC]:";
|
||||||
|
|
||||||
@ -45,6 +46,12 @@ export class KubeconfigSyncManager extends Singleton {
|
|||||||
|
|
||||||
protected static readonly syncName = "lens:kube-sync";
|
protected static readonly syncName = "lens:kube-sync";
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
makeObservable(this);
|
||||||
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
startSync(): void {
|
startSync(): void {
|
||||||
if (this.syncing) {
|
if (this.syncing) {
|
||||||
@ -69,7 +76,7 @@ export class KubeconfigSyncManager extends Singleton {
|
|||||||
this.startNewSync(filePath);
|
this.startNewSync(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.syncListDisposer = UserStore.getInstance().syncKubeconfigEntries.observe(change => {
|
this.syncListDisposer = observe(UserStore.getInstance().syncKubeconfigEntries, change => {
|
||||||
switch (change.type) {
|
switch (change.type) {
|
||||||
case "add":
|
case "add":
|
||||||
this.startNewSync(change.name);
|
this.startNewSync(change.name);
|
||||||
@ -187,7 +194,9 @@ export function computeDiff(contents: string, source: RootSource, filePath: stri
|
|||||||
|
|
||||||
const entity = catalogEntityFromCluster(cluster);
|
const entity = catalogEntityFromCluster(cluster);
|
||||||
|
|
||||||
entity.metadata.labels.file = filePath;
|
if (!filePath.startsWith(ClusterStore.storedKubeConfigFolder)) {
|
||||||
|
entity.metadata.labels.file = filePath.replace(homedir(), "~");
|
||||||
|
}
|
||||||
source.set(contextName, [cluster, entity]);
|
source.set(contextName, [cluster, entity]);
|
||||||
|
|
||||||
logger.debug(`${logPrefix} Added new cluster from sync`, { filePath, contextName });
|
logger.debug(`${logPrefix} Added new cluster from sync`, { filePath, contextName });
|
||||||
@ -249,17 +258,17 @@ async function watchFileChanges(filePath: string): Promise<[IComputedValue<Catal
|
|||||||
depth: stat.isDirectory() ? 0 : 1, // DIRs works with 0 but files need 1 (bug: https://github.com/paulmillr/chokidar/issues/1095)
|
depth: stat.isDirectory() ? 0 : 1, // DIRs works with 0 but files need 1 (bug: https://github.com/paulmillr/chokidar/issues/1095)
|
||||||
disableGlobbing: true,
|
disableGlobbing: true,
|
||||||
});
|
});
|
||||||
const rootSource = new ExtendedObservableMap<string, ObservableMap<string, RootSourceValue>>(observable.map);
|
const rootSource = new ExtendedObservableMap<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]))));
|
||||||
const stoppers = new Map<string, Disposer>();
|
const stoppers = new Map<string, Disposer>();
|
||||||
|
|
||||||
watcher
|
watcher
|
||||||
.on("change", (childFilePath) => {
|
.on("change", (childFilePath) => {
|
||||||
stoppers.get(childFilePath)();
|
stoppers.get(childFilePath)();
|
||||||
stoppers.set(childFilePath, diffChangedConfig(childFilePath, rootSource.getOrDefault(childFilePath)));
|
stoppers.set(childFilePath, diffChangedConfig(childFilePath, rootSource.getOrInsert(childFilePath, observable.map)));
|
||||||
})
|
})
|
||||||
.on("add", (childFilePath) => {
|
.on("add", (childFilePath) => {
|
||||||
stoppers.set(childFilePath, diffChangedConfig(childFilePath, rootSource.getOrDefault(childFilePath)));
|
stoppers.set(childFilePath, diffChangedConfig(childFilePath, rootSource.getOrInsert(childFilePath, observable.map)));
|
||||||
})
|
})
|
||||||
.on("unlink", (childFilePath) => {
|
.on("unlink", (childFilePath) => {
|
||||||
stoppers.get(childFilePath)();
|
stoppers.get(childFilePath)();
|
||||||
|
|||||||
@ -19,14 +19,16 @@
|
|||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { action, computed, observable, IComputedValue, IObservableArray } from "mobx";
|
import { action, computed, IComputedValue, IObservableArray, makeObservable, observable } from "mobx";
|
||||||
import { CatalogCategoryRegistry, catalogCategoryRegistry, CatalogEntity } from "../../common/catalog";
|
import { CatalogCategoryRegistry, catalogCategoryRegistry, CatalogEntity } from "../../common/catalog";
|
||||||
import { iter } from "../../common/utils";
|
import { iter } from "../../common/utils";
|
||||||
|
|
||||||
export class CatalogEntityRegistry {
|
export class CatalogEntityRegistry {
|
||||||
protected sources = observable.map<string, IComputedValue<CatalogEntity[]>>([], { deep: true });
|
protected sources = observable.map<string, IComputedValue<CatalogEntity[]>>();
|
||||||
|
|
||||||
constructor(private categoryRegistry: CatalogCategoryRegistry) {}
|
constructor(private categoryRegistry: CatalogCategoryRegistry) {
|
||||||
|
makeObservable(this);
|
||||||
|
}
|
||||||
|
|
||||||
@action addObservableSource(id: string, source: IObservableArray<CatalogEntity>) {
|
@action addObservableSource(id: string, source: IObservableArray<CatalogEntity>) {
|
||||||
this.sources.set(id, computed(() => source));
|
this.sources.set(id, computed(() => source));
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
import "../common/cluster-ipc";
|
import "../common/cluster-ipc";
|
||||||
import type http from "http";
|
import type http from "http";
|
||||||
import { ipcMain } from "electron";
|
import { ipcMain } from "electron";
|
||||||
import { action, autorun, reaction, toJS } from "mobx";
|
import { action, autorun, makeObservable, reaction } from "mobx";
|
||||||
import { ClusterStore, getClusterIdFromHost } from "../common/cluster-store";
|
import { ClusterStore, getClusterIdFromHost } from "../common/cluster-store";
|
||||||
import type { Cluster } from "./cluster";
|
import type { Cluster } from "./cluster";
|
||||||
import logger from "./logger";
|
import logger from "./logger";
|
||||||
@ -32,38 +32,47 @@ import { catalogEntityRegistry } from "./catalog";
|
|||||||
import { KubernetesCluster, KubernetesClusterPrometheusMetrics } from "../common/catalog-entities/kubernetes-cluster";
|
import { KubernetesCluster, KubernetesClusterPrometheusMetrics } from "../common/catalog-entities/kubernetes-cluster";
|
||||||
|
|
||||||
export class ClusterManager extends Singleton {
|
export class ClusterManager extends Singleton {
|
||||||
|
private store = ClusterStore.getInstance();
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
makeObservable(this);
|
||||||
|
this.bindEvents();
|
||||||
|
}
|
||||||
|
|
||||||
reaction(() => toJS(ClusterStore.getInstance().clustersList, { recurseEverything: true }), () => {
|
private bindEvents() {
|
||||||
this.updateCatalog(ClusterStore.getInstance().clustersList);
|
// reacting to every cluster's state change and total amount of items
|
||||||
}, { fireImmediately: true });
|
reaction(
|
||||||
|
() => this.store.clustersList.map(c => c.getState()),
|
||||||
|
() => this.updateCatalog(this.store.clustersList),
|
||||||
|
{ fireImmediately: true, }
|
||||||
|
);
|
||||||
|
|
||||||
reaction(() => catalogEntityRegistry.getItemsForApiKind<KubernetesCluster>("entity.k8slens.dev/v1alpha1", "KubernetesCluster"), (entities) => {
|
reaction(() => catalogEntityRegistry.getItemsForApiKind<KubernetesCluster>("entity.k8slens.dev/v1alpha1", "KubernetesCluster"), (entities) => {
|
||||||
this.syncClustersFromCatalog(entities);
|
this.syncClustersFromCatalog(entities);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// auto-stop removed clusters
|
// auto-stop removed clusters
|
||||||
autorun(() => {
|
autorun(() => {
|
||||||
const removedClusters = Array.from(ClusterStore.getInstance().removedClusters.values());
|
const removedClusters = Array.from(this.store.removedClusters.values());
|
||||||
|
|
||||||
if (removedClusters.length > 0) {
|
if (removedClusters.length > 0) {
|
||||||
const meta = removedClusters.map(cluster => cluster.getMeta());
|
const meta = removedClusters.map(cluster => cluster.getMeta());
|
||||||
|
|
||||||
logger.info(`[CLUSTER-MANAGER]: removing clusters`, meta);
|
logger.info(`[CLUSTER-MANAGER]: removing clusters`, meta);
|
||||||
removedClusters.forEach(cluster => cluster.disconnect());
|
removedClusters.forEach(cluster => cluster.disconnect());
|
||||||
ClusterStore.getInstance().removedClusters.clear();
|
this.store.removedClusters.clear();
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
delay: 250
|
delay: 250
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on("network:offline", () => { this.onNetworkOffline(); });
|
ipcMain.on("network:offline", this.onNetworkOffline);
|
||||||
ipcMain.on("network:online", () => { this.onNetworkOnline(); });
|
ipcMain.on("network:online", this.onNetworkOnline);
|
||||||
}
|
}
|
||||||
|
|
||||||
@action protected updateCatalog(clusters: Cluster[]) {
|
@action
|
||||||
|
protected updateCatalog(clusters: Cluster[]) {
|
||||||
for (const cluster of clusters) {
|
for (const cluster of clusters) {
|
||||||
const index = catalogEntityRegistry.items.findIndex((entity) => entity.metadata.uid === cluster.id);
|
const index = catalogEntityRegistry.items.findIndex((entity) => entity.metadata.uid === cluster.id);
|
||||||
|
|
||||||
@ -94,10 +103,10 @@ export class ClusterManager extends Singleton {
|
|||||||
|
|
||||||
@action syncClustersFromCatalog(entities: KubernetesCluster[]) {
|
@action syncClustersFromCatalog(entities: KubernetesCluster[]) {
|
||||||
for (const entity of entities) {
|
for (const entity of entities) {
|
||||||
const cluster = ClusterStore.getInstance().getById(entity.metadata.uid);
|
const cluster = this.store.getById(entity.metadata.uid);
|
||||||
|
|
||||||
if (!cluster) {
|
if (!cluster) {
|
||||||
ClusterStore.getInstance().addCluster({
|
this.store.addCluster({
|
||||||
id: entity.metadata.uid,
|
id: entity.metadata.uid,
|
||||||
preferences: {
|
preferences: {
|
||||||
clusterName: entity.metadata.name
|
clusterName: entity.metadata.name
|
||||||
@ -117,28 +126,28 @@ export class ClusterManager extends Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected onNetworkOffline() {
|
protected onNetworkOffline = () => {
|
||||||
logger.info("[CLUSTER-MANAGER]: network is offline");
|
logger.info("[CLUSTER-MANAGER]: network is offline");
|
||||||
ClusterStore.getInstance().clustersList.forEach((cluster) => {
|
this.store.clustersList.forEach((cluster) => {
|
||||||
if (!cluster.disconnected) {
|
if (!cluster.disconnected) {
|
||||||
cluster.online = false;
|
cluster.online = false;
|
||||||
cluster.accessible = false;
|
cluster.accessible = false;
|
||||||
cluster.refreshConnectionStatus().catch((e) => e);
|
cluster.refreshConnectionStatus().catch((e) => e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
protected onNetworkOnline() {
|
protected onNetworkOnline = () => {
|
||||||
logger.info("[CLUSTER-MANAGER]: network is online");
|
logger.info("[CLUSTER-MANAGER]: network is online");
|
||||||
ClusterStore.getInstance().clustersList.forEach((cluster) => {
|
this.store.clustersList.forEach((cluster) => {
|
||||||
if (!cluster.disconnected) {
|
if (!cluster.disconnected) {
|
||||||
cluster.refreshConnectionStatus().catch((e) => e);
|
cluster.refreshConnectionStatus().catch((e) => e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
stop() {
|
stop() {
|
||||||
ClusterStore.getInstance().clusters.forEach((cluster: Cluster) => {
|
this.store.clusters.forEach((cluster: Cluster) => {
|
||||||
cluster.disconnect();
|
cluster.disconnect();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -150,18 +159,18 @@ export class ClusterManager extends Singleton {
|
|||||||
if (req.headers.host.startsWith("127.0.0.1")) {
|
if (req.headers.host.startsWith("127.0.0.1")) {
|
||||||
const clusterId = req.url.split("/")[1];
|
const clusterId = req.url.split("/")[1];
|
||||||
|
|
||||||
cluster = ClusterStore.getInstance().getById(clusterId);
|
cluster = this.store.getById(clusterId);
|
||||||
|
|
||||||
if (cluster) {
|
if (cluster) {
|
||||||
// we need to swap path prefix so that request is proxied to kube api
|
// we need to swap path prefix so that request is proxied to kube api
|
||||||
req.url = req.url.replace(`/${clusterId}`, apiKubePrefix);
|
req.url = req.url.replace(`/${clusterId}`, apiKubePrefix);
|
||||||
}
|
}
|
||||||
} else if (req.headers["x-cluster-id"]) {
|
} else if (req.headers["x-cluster-id"]) {
|
||||||
cluster = ClusterStore.getInstance().getById(req.headers["x-cluster-id"].toString());
|
cluster = this.store.getById(req.headers["x-cluster-id"].toString());
|
||||||
} else {
|
} else {
|
||||||
const clusterId = getClusterIdFromHost(req.headers.host);
|
const clusterId = getClusterIdFromHost(req.headers.host);
|
||||||
|
|
||||||
cluster = ClusterStore.getInstance().getById(clusterId);
|
cluster = this.store.getById(clusterId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cluster;
|
return cluster;
|
||||||
@ -169,9 +178,7 @@ export class ClusterManager extends Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function catalogEntityFromCluster(cluster: Cluster) {
|
export function catalogEntityFromCluster(cluster: Cluster) {
|
||||||
return new KubernetesCluster(toJS({
|
return new KubernetesCluster({
|
||||||
apiVersion: "entity.k8slens.dev/v1alpha1",
|
|
||||||
kind: "KubernetesCluster",
|
|
||||||
metadata: {
|
metadata: {
|
||||||
uid: cluster.id,
|
uid: cluster.id,
|
||||||
name: cluster.name,
|
name: cluster.name,
|
||||||
@ -190,5 +197,5 @@ export function catalogEntityFromCluster(cluster: Cluster) {
|
|||||||
message: "",
|
message: "",
|
||||||
active: !cluster.disconnected
|
active: !cluster.disconnected
|
||||||
}
|
}
|
||||||
}));
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
import { ipcMain } from "electron";
|
import { ipcMain } from "electron";
|
||||||
import type { ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences, ClusterPrometheusPreferences, UpdateClusterModel } from "../common/cluster-store";
|
import type { ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences, ClusterPrometheusPreferences, UpdateClusterModel } from "../common/cluster-store";
|
||||||
import { action, comparer, computed, observable, reaction, toJS, when } from "mobx";
|
import { action, comparer, computed, makeObservable, observable, reaction, when } from "mobx";
|
||||||
import { broadcastMessage, ClusterListNamespaceForbiddenChannel } from "../common/ipc";
|
import { broadcastMessage, ClusterListNamespaceForbiddenChannel } from "../common/ipc";
|
||||||
import { ContextHandler } from "./context-handler";
|
import { ContextHandler } from "./context-handler";
|
||||||
import { AuthorizationV1Api, CoreV1Api, HttpError, KubeConfig, V1ResourceAttributes } from "@kubernetes/client-node";
|
import { AuthorizationV1Api, CoreV1Api, HttpError, KubeConfig, V1ResourceAttributes } from "@kubernetes/client-node";
|
||||||
@ -33,6 +33,7 @@ import logger from "./logger";
|
|||||||
import { VersionDetector } from "./cluster-detectors/version-detector";
|
import { VersionDetector } from "./cluster-detectors/version-detector";
|
||||||
import { detectorRegistry } from "./cluster-detectors/detector-registry";
|
import { detectorRegistry } from "./cluster-detectors/detector-registry";
|
||||||
import plimit from "p-limit";
|
import plimit from "p-limit";
|
||||||
|
import { toJS } from "../common/utils";
|
||||||
|
|
||||||
export enum ClusterStatus {
|
export enum ClusterStatus {
|
||||||
AccessGranted = 2,
|
AccessGranted = 2,
|
||||||
@ -91,7 +92,9 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
protected activated = false;
|
protected activated = false;
|
||||||
private resourceAccessStatuses: Map<KubeApiResource, boolean> = new Map();
|
private resourceAccessStatuses: Map<KubeApiResource, boolean> = new Map();
|
||||||
|
|
||||||
whenReady = when(() => this.ready);
|
get whenReady() {
|
||||||
|
return when(() => this.ready);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kubeconfig context name
|
* Kubeconfig context name
|
||||||
@ -227,9 +230,7 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
@computed get prometheusPreferences(): ClusterPrometheusPreferences {
|
@computed get prometheusPreferences(): ClusterPrometheusPreferences {
|
||||||
const { prometheus, prometheusProvider } = this.preferences;
|
const { prometheus, prometheusProvider } = this.preferences;
|
||||||
|
|
||||||
return toJS({ prometheus, prometheusProvider }, {
|
return toJS({ prometheus, prometheusProvider });
|
||||||
recurseEverything: true,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -240,6 +241,7 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constructor(model: ClusterModel) {
|
constructor(model: ClusterModel) {
|
||||||
|
makeObservable(this);
|
||||||
this.id = model.id;
|
this.id = model.id;
|
||||||
this.updateModel(model);
|
this.updateModel(model);
|
||||||
|
|
||||||
@ -570,9 +572,7 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
accessibleNamespaces: this.accessibleNamespaces,
|
accessibleNamespaces: this.accessibleNamespaces,
|
||||||
};
|
};
|
||||||
|
|
||||||
return toJS(model, {
|
return toJS(model);
|
||||||
recurseEverything: true
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -592,9 +592,7 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
isGlobalWatchEnabled: this.isGlobalWatchEnabled,
|
isGlobalWatchEnabled: this.isGlobalWatchEnabled,
|
||||||
};
|
};
|
||||||
|
|
||||||
return toJS(state, {
|
return toJS(state);
|
||||||
recurseEverything: true
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -23,23 +23,25 @@ import { randomBytes } from "crypto";
|
|||||||
import { SHA256 } from "crypto-js";
|
import { SHA256 } from "crypto-js";
|
||||||
import { app, remote } from "electron";
|
import { app, remote } from "electron";
|
||||||
import fse from "fs-extra";
|
import fse from "fs-extra";
|
||||||
import { action, observable, toJS } from "mobx";
|
import { action, makeObservable, observable } from "mobx";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { BaseStore } from "../common/base-store";
|
import { BaseStore } from "../common/base-store";
|
||||||
import type { LensExtensionId } from "../extensions/lens-extension";
|
import type { LensExtensionId } from "../extensions/lens-extension";
|
||||||
|
import { toJS } from "../common/utils";
|
||||||
|
|
||||||
interface FSProvisionModel {
|
interface FSProvisionModel {
|
||||||
extensions: Record<string, string>; // extension names to paths
|
extensions: Record<string, string>; // extension names to paths
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FilesystemProvisionerStore extends BaseStore<FSProvisionModel> {
|
export class FilesystemProvisionerStore extends BaseStore<FSProvisionModel> {
|
||||||
@observable registeredExtensions = observable.map<LensExtensionId, string>();
|
registeredExtensions = observable.map<LensExtensionId, string>();
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super({
|
super({
|
||||||
configName: "lens-filesystem-provisioner-store",
|
configName: "lens-filesystem-provisioner-store",
|
||||||
accessPropertiesByDotNotation: false, // To make dots safe in cluster context names
|
accessPropertiesByDotNotation: false, // To make dots safe in cluster context names
|
||||||
});
|
});
|
||||||
|
makeObservable(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -71,9 +73,7 @@ export class FilesystemProvisionerStore extends BaseStore<FSProvisionModel> {
|
|||||||
|
|
||||||
toJSON(): FSProvisionModel {
|
toJSON(): FSProvisionModel {
|
||||||
return toJS({
|
return toJS({
|
||||||
extensions: this.registeredExtensions.toJSON(),
|
extensions: Object.fromEntries(this.registeredExtensions),
|
||||||
}, {
|
|
||||||
recurseEverything: true
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,7 +24,7 @@
|
|||||||
import "../common/system-ca";
|
import "../common/system-ca";
|
||||||
import "../common/prometheus-providers";
|
import "../common/prometheus-providers";
|
||||||
import * as Mobx from "mobx";
|
import * as Mobx from "mobx";
|
||||||
import * as LensExtensions from "../extensions/core-api";
|
import * as LensExtensionsCoreApi from "../extensions/core-api";
|
||||||
import { app, autoUpdater, ipcMain, dialog, powerMonitor } from "electron";
|
import { app, autoUpdater, ipcMain, dialog, powerMonitor } from "electron";
|
||||||
import { appName, isMac, productName } from "../common/vars";
|
import { appName, isMac, productName } from "../common/vars";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
@ -55,6 +55,7 @@ import { HotbarStore } from "../common/hotbar-store";
|
|||||||
import { HelmRepoManager } from "./helm/helm-repo-manager";
|
import { HelmRepoManager } from "./helm/helm-repo-manager";
|
||||||
import { KubeconfigSyncManager } from "./catalog-sources";
|
import { KubeconfigSyncManager } from "./catalog-sources";
|
||||||
import { handleWsUpgrade } from "./proxy/ws-upgrade";
|
import { handleWsUpgrade } from "./proxy/ws-upgrade";
|
||||||
|
import configurePackages from "../common/configure-packages";
|
||||||
|
|
||||||
const workingDir = path.join(app.getPath("appData"), appName);
|
const workingDir = path.join(app.getPath("appData"), appName);
|
||||||
const cleanup = disposer();
|
const cleanup = disposer();
|
||||||
@ -77,6 +78,7 @@ if (process.env.LENS_DISABLE_GPU) {
|
|||||||
app.disableHardwareAcceleration();
|
app.disableHardwareAcceleration();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
configurePackages();
|
||||||
mangleProxyEnv();
|
mangleProxyEnv();
|
||||||
|
|
||||||
if (app.commandLine.getSwitchValue("proxy-server") !== "") {
|
if (app.commandLine.getSwitchValue("proxy-server") !== "") {
|
||||||
@ -191,15 +193,11 @@ app.on("ready", async () => {
|
|||||||
cleanup.push(pushCatalogToRenderer(catalogEntityRegistry));
|
cleanup.push(pushCatalogToRenderer(catalogEntityRegistry));
|
||||||
KubeconfigSyncManager.getInstance().startSync();
|
KubeconfigSyncManager.getInstance().startSync();
|
||||||
startUpdateChecking();
|
startUpdateChecking();
|
||||||
LensProtocolRouterMain
|
LensProtocolRouterMain.getInstance().rendererLoaded = true;
|
||||||
.getInstance()
|
|
||||||
.rendererLoaded = true;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ExtensionLoader.getInstance().whenLoaded.then(() => {
|
ExtensionLoader.getInstance().whenLoaded.then(() => {
|
||||||
LensProtocolRouterMain
|
LensProtocolRouterMain.getInstance().extensionsLoaded = true;
|
||||||
.getInstance()
|
|
||||||
.extensionsLoaded = true;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
logger.info("🧩 Initializing extensions");
|
logger.info("🧩 Initializing extensions");
|
||||||
@ -272,12 +270,16 @@ app.on("open-url", (event, rawUrl) => {
|
|||||||
.catch(error => logger.error(`${LensProtocolRouterMain.LoggingPrefix}: an error occured`, { error, rawUrl }));
|
.catch(error => logger.error(`${LensProtocolRouterMain.LoggingPrefix}: an error occured`, { error, rawUrl }));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Extensions-api runtime exports
|
/**
|
||||||
export const LensExtensionsApi = {
|
* Exports for virtual package "@k8slens/extensions" for main-process.
|
||||||
...LensExtensions,
|
* All exporting names available in global runtime scope:
|
||||||
|
* e.g. global.Mobx, global.LensExtensions
|
||||||
|
*/
|
||||||
|
const LensExtensions = {
|
||||||
|
...LensExtensionsCoreApi,
|
||||||
};
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Mobx,
|
Mobx,
|
||||||
LensExtensionsApi as LensExtensions,
|
LensExtensions,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -88,18 +88,18 @@ export class PrometheusLens implements PrometheusProvider {
|
|||||||
};
|
};
|
||||||
case "pvc":
|
case "pvc":
|
||||||
return {
|
return {
|
||||||
diskUsage: `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)`,
|
diskUsage: `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}",namespace="${opts.namespace}"}) by (persistentvolumeclaim, namespace)`,
|
||||||
diskCapacity: `sum(kubelet_volume_stats_capacity_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)`
|
diskCapacity: `sum(kubelet_volume_stats_capacity_bytes{persistentvolumeclaim="${opts.pvc}",namespace="${opts.namespace}"}) by (persistentvolumeclaim, namespace)`
|
||||||
};
|
};
|
||||||
case "ingress":
|
case "ingress":
|
||||||
const bytesSent = (ingress: string, statuses: string) =>
|
const bytesSent = (ingress: string, namespace: string, statuses: string) =>
|
||||||
`sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)`;
|
`sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}",namespace="${namespace}",status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress, namespace)`;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
bytesSentSuccess: bytesSent(opts.ingress, "^2\\\\d*"),
|
bytesSentSuccess: bytesSent(opts.ingress, opts.namespace, "^2\\\\d*"),
|
||||||
bytesSentFailure: bytesSent(opts.ingress, "^5\\\\d*"),
|
bytesSentFailure: bytesSent(opts.ingress, opts.namespace, "^5\\\\d*"),
|
||||||
requestDurationSeconds: `sum(rate(nginx_ingress_controller_request_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`,
|
requestDurationSeconds: `sum(rate(nginx_ingress_controller_request_duration_seconds_sum{ingress="${opts.ingress}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (ingress, namespace)`,
|
||||||
responseDurationSeconds: `sum(rate(nginx_ingress_controller_response_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`
|
responseDurationSeconds: `sum(rate(nginx_ingress_controller_response_duration_seconds_sum{ingress="${opts.ingress}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (ingress, namespace)`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -98,18 +98,18 @@ export class PrometheusOperator implements PrometheusProvider {
|
|||||||
};
|
};
|
||||||
case "pvc":
|
case "pvc":
|
||||||
return {
|
return {
|
||||||
diskUsage: `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)`,
|
diskUsage: `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}",namespace="${opts.namespace}"}) by (persistentvolumeclaim, namespace)`,
|
||||||
diskCapacity: `sum(kubelet_volume_stats_capacity_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)`
|
diskCapacity: `sum(kubelet_volume_stats_capacity_bytes{persistentvolumeclaim="${opts.pvc}",namespace="${opts.namespace}"}) by (persistentvolumeclaim, namespace)`
|
||||||
};
|
};
|
||||||
case "ingress":
|
case "ingress":
|
||||||
const bytesSent = (ingress: string, statuses: string) =>
|
const bytesSent = (ingress: string, namespace: string, statuses: string) =>
|
||||||
`sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)`;
|
`sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}",namespace="${namespace}",status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress, namespace)`;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
bytesSentSuccess: bytesSent(opts.ingress, "^2\\\\d*"),
|
bytesSentSuccess: bytesSent(opts.ingress, opts.namespace, "^2\\\\d*"),
|
||||||
bytesSentFailure: bytesSent(opts.ingress, "^5\\\\d*"),
|
bytesSentFailure: bytesSent(opts.ingress, opts.namespace, "^5\\\\d*"),
|
||||||
requestDurationSeconds: `sum(rate(nginx_ingress_controller_request_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`,
|
requestDurationSeconds: `sum(rate(nginx_ingress_controller_request_duration_seconds_sum{ingress="${opts.ingress}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (ingress, namespace)`,
|
||||||
responseDurationSeconds: `sum(rate(nginx_ingress_controller_response_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`
|
responseDurationSeconds: `sum(rate(nginx_ingress_controller_response_duration_seconds_sum{ingress="${opts.ingress}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (ingress, namespace)`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -88,18 +88,18 @@ export class PrometheusStacklight implements PrometheusProvider {
|
|||||||
};
|
};
|
||||||
case "pvc":
|
case "pvc":
|
||||||
return {
|
return {
|
||||||
diskUsage: `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)`,
|
diskUsage: `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}",namespace="${opts.namespace}"}) by (persistentvolumeclaim, namespace)`,
|
||||||
diskCapacity: `sum(kubelet_volume_stats_capacity_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)`
|
diskCapacity: `sum(kubelet_volume_stats_capacity_bytes{persistentvolumeclaim="${opts.pvc}",namespace="${opts.namespace}"}) by (persistentvolumeclaim, namespace)`
|
||||||
};
|
};
|
||||||
case "ingress":
|
case "ingress":
|
||||||
const bytesSent = (ingress: string, statuses: string) =>
|
const bytesSent = (ingress: string, namespace: string, statuses: string) =>
|
||||||
`sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)`;
|
`sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}",namespace="${namespace}",status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress, namespace)`;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
bytesSentSuccess: bytesSent(opts.ingress, "^2\\\\d*"),
|
bytesSentSuccess: bytesSent(opts.ingress, opts.namespace, "^2\\\\d*"),
|
||||||
bytesSentFailure: bytesSent(opts.ingress, "^5\\\\d*"),
|
bytesSentFailure: bytesSent(opts.ingress, opts.namespace, "^5\\\\d*"),
|
||||||
requestDurationSeconds: `sum(rate(nginx_ingress_controller_request_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`,
|
requestDurationSeconds: `sum(rate(nginx_ingress_controller_request_duration_seconds_sum{ingress="${opts.ingress}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (ingress, namespace)`,
|
||||||
responseDurationSeconds: `sum(rate(nginx_ingress_controller_response_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`
|
responseDurationSeconds: `sum(rate(nginx_ingress_controller_response_duration_seconds_sum{ingress="${opts.ingress}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (ingress, namespace)`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,7 +24,7 @@ import * as proto from "../../common/protocol-handler";
|
|||||||
import Url from "url-parse";
|
import Url from "url-parse";
|
||||||
import type { LensExtension } from "../../extensions/lens-extension";
|
import type { LensExtension } from "../../extensions/lens-extension";
|
||||||
import { broadcastMessage } from "../../common/ipc";
|
import { broadcastMessage } from "../../common/ipc";
|
||||||
import { observable, when } from "mobx";
|
import { observable, when, makeObservable } from "mobx";
|
||||||
|
|
||||||
export interface FallbackHandler {
|
export interface FallbackHandler {
|
||||||
(name: string): Promise<boolean>;
|
(name: string): Promise<boolean>;
|
||||||
@ -36,6 +36,12 @@ export class LensProtocolRouterMain extends proto.LensProtocolRouter {
|
|||||||
@observable rendererLoaded = false;
|
@observable rendererLoaded = false;
|
||||||
@observable extensionsLoaded = false;
|
@observable extensionsLoaded = false;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
makeObservable(this);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the most specific registered handler, if it exists, and invoke it.
|
* Find the most specific registered handler, if it exists, and invoke it.
|
||||||
*
|
*
|
||||||
|
|||||||
@ -38,7 +38,12 @@ export async function shellSync() {
|
|||||||
let envVars = {};
|
let envVars = {};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
envVars = await shellEnv(shell);
|
envVars = await Promise.race([
|
||||||
|
shellEnv(shell),
|
||||||
|
new Promise((_resolve, reject) => setTimeout(() => {
|
||||||
|
reject(new Error("Resolving shell environment is taking very long. Please review your shell configuration."));
|
||||||
|
}, 5_000))
|
||||||
|
]);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`shellEnv: ${error}`);
|
logger.error(`shellEnv: ${error}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import type { ClusterId } from "../common/cluster-store";
|
import type { ClusterId } from "../common/cluster-store";
|
||||||
import { observable } from "mobx";
|
import { makeObservable, observable } from "mobx";
|
||||||
import { app, BrowserWindow, dialog, shell, webContents } from "electron";
|
import { app, BrowserWindow, dialog, shell, webContents } from "electron";
|
||||||
import windowStateKeeper from "electron-window-state";
|
import windowStateKeeper from "electron-window-state";
|
||||||
import { appEventBus } from "../common/event-bus";
|
import { appEventBus } from "../common/event-bus";
|
||||||
@ -44,6 +44,7 @@ export class WindowManager extends Singleton {
|
|||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
makeObservable(this);
|
||||||
this.bindEvents();
|
this.bindEvents();
|
||||||
this.initMenu();
|
this.initMenu();
|
||||||
this.initTray();
|
this.initTray();
|
||||||
|
|||||||
@ -21,15 +21,19 @@
|
|||||||
|
|
||||||
import type { KubeObjectStore } from "../kube-object.store";
|
import type { KubeObjectStore } from "../kube-object.store";
|
||||||
|
|
||||||
import { action, observable } from "mobx";
|
import { action, observable, makeObservable } from "mobx";
|
||||||
import { autobind } from "../utils";
|
import { autoBind } from "../utils";
|
||||||
import { KubeApi, parseKubeApi } from "./kube-api";
|
import { KubeApi, parseKubeApi } from "./kube-api";
|
||||||
|
|
||||||
@autobind()
|
|
||||||
export class ApiManager {
|
export class ApiManager {
|
||||||
private apis = observable.map<string, KubeApi>();
|
private apis = observable.map<string, KubeApi>();
|
||||||
private stores = observable.map<string, KubeObjectStore>();
|
private stores = observable.map<string, KubeObjectStore>();
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
makeObservable(this);
|
||||||
|
autoBind(this);
|
||||||
|
}
|
||||||
|
|
||||||
getApi(pathOrCallback: string | ((api: KubeApi) => boolean)) {
|
getApi(pathOrCallback: string | ((api: KubeApi) => boolean)) {
|
||||||
if (typeof pathOrCallback === "string") {
|
if (typeof pathOrCallback === "string") {
|
||||||
return this.apis.get(pathOrCallback) || this.apis.get(parseKubeApi(pathOrCallback).apiBase);
|
return this.apis.get(pathOrCallback) || this.apis.get(parseKubeApi(pathOrCallback).apiBase);
|
||||||
|
|||||||
@ -19,7 +19,7 @@
|
|||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { computed, observable } from "mobx";
|
import { computed, observable, makeObservable } from "mobx";
|
||||||
import { subscribeToBroadcast } from "../../common/ipc";
|
import { subscribeToBroadcast } from "../../common/ipc";
|
||||||
import { CatalogCategory, CatalogEntity, CatalogEntityData, catalogCategoryRegistry, CatalogCategoryRegistry, CatalogEntityKindData } from "../../common/catalog";
|
import { CatalogCategory, CatalogEntity, CatalogEntityData, catalogCategoryRegistry, CatalogCategoryRegistry, CatalogEntityKindData } from "../../common/catalog";
|
||||||
import "../../common/catalog-entities";
|
import "../../common/catalog-entities";
|
||||||
@ -29,7 +29,9 @@ export class CatalogEntityRegistry {
|
|||||||
protected rawItems = observable.array<CatalogEntityData & CatalogEntityKindData>([], { deep: true });
|
protected rawItems = observable.array<CatalogEntityData & CatalogEntityKindData>([], { deep: true });
|
||||||
@observable protected _activeEntity: CatalogEntity;
|
@observable protected _activeEntity: CatalogEntity;
|
||||||
|
|
||||||
constructor(private categoryRegistry: CatalogCategoryRegistry) {}
|
constructor(private categoryRegistry: CatalogCategoryRegistry) {
|
||||||
|
makeObservable(this);
|
||||||
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
subscribeToBroadcast("catalog:items", (ev, items: (CatalogEntityData & CatalogEntityKindData)[]) => {
|
subscribeToBroadcast("catalog:items", (ev, items: (CatalogEntityData & CatalogEntityKindData)[]) => {
|
||||||
|
|||||||
@ -19,11 +19,9 @@
|
|||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { autobind } from "../../utils";
|
|
||||||
import { Role } from "./role.api";
|
import { Role } from "./role.api";
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
|
|
||||||
@autobind()
|
|
||||||
export class ClusterRole extends Role {
|
export class ClusterRole extends Role {
|
||||||
static kind = "ClusterRole";
|
static kind = "ClusterRole";
|
||||||
static namespaced = false;
|
static namespaced = false;
|
||||||
|
|||||||
@ -71,10 +71,7 @@ export interface IClusterMetrics<T = IMetrics> {
|
|||||||
fsUsage: T;
|
fsUsage: T;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Cluster extends KubeObject {
|
export interface Cluster {
|
||||||
static kind = "Cluster";
|
|
||||||
static apiBase = "/apis/cluster.k8s.io/v1alpha1/clusters";
|
|
||||||
|
|
||||||
spec: {
|
spec: {
|
||||||
clusterNetwork?: {
|
clusterNetwork?: {
|
||||||
serviceDomain?: string;
|
serviceDomain?: string;
|
||||||
@ -106,6 +103,11 @@ export class Cluster extends KubeObject {
|
|||||||
errorMessage?: string;
|
errorMessage?: string;
|
||||||
errorReason?: string;
|
errorReason?: string;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Cluster extends KubeObject {
|
||||||
|
static kind = "Cluster";
|
||||||
|
static apiBase = "/apis/cluster.k8s.io/v1alpha1/clusters";
|
||||||
|
|
||||||
getStatus() {
|
getStatus() {
|
||||||
if (this.metadata.deletionTimestamp) return ClusterStatus.REMOVING;
|
if (this.metadata.deletionTimestamp) return ClusterStatus.REMOVING;
|
||||||
|
|||||||
@ -28,13 +28,15 @@ export interface IComponentStatusCondition {
|
|||||||
message: string;
|
message: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ComponentStatus {
|
||||||
|
conditions: IComponentStatusCondition[];
|
||||||
|
}
|
||||||
|
|
||||||
export class ComponentStatus extends KubeObject {
|
export class ComponentStatus extends KubeObject {
|
||||||
static kind = "ComponentStatus";
|
static kind = "ComponentStatus";
|
||||||
static namespaced = false;
|
static namespaced = false;
|
||||||
static apiBase = "/api/v1/componentstatuses";
|
static apiBase = "/api/v1/componentstatuses";
|
||||||
|
|
||||||
conditions: IComponentStatusCondition[];
|
|
||||||
|
|
||||||
getTruthyConditions() {
|
getTruthyConditions() {
|
||||||
return this.conditions.filter(c => c.status === "True");
|
return this.conditions.filter(c => c.status === "True");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,10 +21,15 @@
|
|||||||
|
|
||||||
import { KubeObject } from "../kube-object";
|
import { KubeObject } from "../kube-object";
|
||||||
import type { KubeJsonApiData } from "../kube-json-api";
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
import { autobind } from "../../utils";
|
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
|
import { autoBind } from "../../../common/utils";
|
||||||
|
|
||||||
|
export interface ConfigMap {
|
||||||
|
data: {
|
||||||
|
[param: string]: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@autobind()
|
|
||||||
export class ConfigMap extends KubeObject {
|
export class ConfigMap extends KubeObject {
|
||||||
static kind = "ConfigMap";
|
static kind = "ConfigMap";
|
||||||
static namespaced = true;
|
static namespaced = true;
|
||||||
@ -32,12 +37,10 @@ export class ConfigMap extends KubeObject {
|
|||||||
|
|
||||||
constructor(data: KubeJsonApiData) {
|
constructor(data: KubeJsonApiData) {
|
||||||
super(data);
|
super(data);
|
||||||
this.data = this.data || {};
|
autoBind(this);
|
||||||
}
|
|
||||||
|
|
||||||
data: {
|
this.data ??= {};
|
||||||
[param: string]: string;
|
}
|
||||||
};
|
|
||||||
|
|
||||||
getKeys(): string[] {
|
getKeys(): string[] {
|
||||||
return Object.keys(this.data);
|
return Object.keys(this.data);
|
||||||
|
|||||||
@ -38,11 +38,7 @@ type AdditionalPrinterColumnsV1Beta = AdditionalPrinterColumnsCommon & {
|
|||||||
JSONPath: string;
|
JSONPath: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class CustomResourceDefinition extends KubeObject {
|
export interface CustomResourceDefinition {
|
||||||
static kind = "CustomResourceDefinition";
|
|
||||||
static namespaced = false;
|
|
||||||
static apiBase = "/apis/apiextensions.k8s.io/v1/customresourcedefinitions";
|
|
||||||
|
|
||||||
spec: {
|
spec: {
|
||||||
group: string;
|
group: string;
|
||||||
version?: string; // deprecated in v1 api
|
version?: string; // deprecated in v1 api
|
||||||
@ -84,6 +80,12 @@ export class CustomResourceDefinition extends KubeObject {
|
|||||||
};
|
};
|
||||||
storedVersions: string[];
|
storedVersions: string[];
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CustomResourceDefinition extends KubeObject {
|
||||||
|
static kind = "CustomResourceDefinition";
|
||||||
|
static namespaced = false;
|
||||||
|
static apiBase = "/apis/apiextensions.k8s.io/v1/customresourcedefinitions";
|
||||||
|
|
||||||
getResourceUrl() {
|
getResourceUrl() {
|
||||||
return crdResourcesURL({
|
return crdResourcesURL({
|
||||||
|
|||||||
@ -23,8 +23,9 @@ import moment from "moment";
|
|||||||
import { KubeObject } from "../kube-object";
|
import { KubeObject } from "../kube-object";
|
||||||
import type { IPodContainer } from "./pods.api";
|
import type { IPodContainer } from "./pods.api";
|
||||||
import { formatDuration } from "../../utils/formatDuration";
|
import { formatDuration } from "../../utils/formatDuration";
|
||||||
import { autobind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
|
||||||
export class CronJobApi extends KubeApi<CronJob> {
|
export class CronJobApi extends KubeApi<CronJob> {
|
||||||
suspend(params: { namespace: string; name: string }) {
|
suspend(params: { namespace: string; name: string }) {
|
||||||
@ -58,28 +59,7 @@ export class CronJobApi extends KubeApi<CronJob> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
export interface CronJob {
|
||||||
export class CronJob extends KubeObject {
|
|
||||||
static kind = "CronJob";
|
|
||||||
static namespaced = true;
|
|
||||||
static apiBase = "/apis/batch/v1beta1/cronjobs";
|
|
||||||
|
|
||||||
kind: string;
|
|
||||||
apiVersion: string;
|
|
||||||
metadata: {
|
|
||||||
name: string;
|
|
||||||
namespace: string;
|
|
||||||
selfLink: string;
|
|
||||||
uid: string;
|
|
||||||
resourceVersion: string;
|
|
||||||
creationTimestamp: string;
|
|
||||||
labels: {
|
|
||||||
[key: string]: string;
|
|
||||||
};
|
|
||||||
annotations: {
|
|
||||||
[key: string]: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
spec: {
|
spec: {
|
||||||
schedule: string;
|
schedule: string;
|
||||||
concurrencyPolicy: string;
|
concurrencyPolicy: string;
|
||||||
@ -116,6 +96,17 @@ export class CronJob extends KubeObject {
|
|||||||
status: {
|
status: {
|
||||||
lastScheduleTime?: string;
|
lastScheduleTime?: string;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CronJob extends KubeObject {
|
||||||
|
static kind = "CronJob";
|
||||||
|
static namespaced = true;
|
||||||
|
static apiBase = "/apis/batch/v1beta1/cronjobs";
|
||||||
|
|
||||||
|
constructor(data: KubeJsonApiData) {
|
||||||
|
super(data);
|
||||||
|
autoBind(this);
|
||||||
|
}
|
||||||
|
|
||||||
getSuspendFlag() {
|
getSuspendFlag() {
|
||||||
return this.spec.suspend.toString();
|
return this.spec.suspend.toString();
|
||||||
|
|||||||
@ -22,16 +22,21 @@
|
|||||||
import get from "lodash/get";
|
import get from "lodash/get";
|
||||||
import type { IPodContainer } from "./pods.api";
|
import type { IPodContainer } from "./pods.api";
|
||||||
import { IAffinity, WorkloadKubeObject } from "../workload-kube-object";
|
import { IAffinity, WorkloadKubeObject } from "../workload-kube-object";
|
||||||
import { autobind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
|
||||||
@autobind()
|
|
||||||
export class DaemonSet extends WorkloadKubeObject {
|
export class DaemonSet extends WorkloadKubeObject {
|
||||||
static kind = "DaemonSet";
|
static kind = "DaemonSet";
|
||||||
static namespaced = true;
|
static namespaced = true;
|
||||||
static apiBase = "/apis/apps/v1/daemonsets";
|
static apiBase = "/apis/apps/v1/daemonsets";
|
||||||
|
|
||||||
spec: {
|
constructor(data: KubeJsonApiData) {
|
||||||
|
super(data);
|
||||||
|
autoBind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
declare spec: {
|
||||||
selector: {
|
selector: {
|
||||||
matchLabels: {
|
matchLabels: {
|
||||||
[name: string]: string;
|
[name: string]: string;
|
||||||
@ -73,7 +78,7 @@ export class DaemonSet extends WorkloadKubeObject {
|
|||||||
};
|
};
|
||||||
revisionHistoryLimit: number;
|
revisionHistoryLimit: number;
|
||||||
};
|
};
|
||||||
status: {
|
declare status: {
|
||||||
currentNumberScheduled: number;
|
currentNumberScheduled: number;
|
||||||
numberMisscheduled: number;
|
numberMisscheduled: number;
|
||||||
desiredNumberScheduled: number;
|
desiredNumberScheduled: number;
|
||||||
|
|||||||
@ -22,8 +22,9 @@
|
|||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
|
|
||||||
import { IAffinity, WorkloadKubeObject } from "../workload-kube-object";
|
import { IAffinity, WorkloadKubeObject } from "../workload-kube-object";
|
||||||
import { autobind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
|
||||||
export class DeploymentApi extends KubeApi<Deployment> {
|
export class DeploymentApi extends KubeApi<Deployment> {
|
||||||
protected getScaleApiUrl(params: { namespace: string; name: string }) {
|
protected getScaleApiUrl(params: { namespace: string; name: string }) {
|
||||||
@ -87,13 +88,17 @@ interface IContainerProbe {
|
|||||||
failureThreshold?: number;
|
failureThreshold?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
|
||||||
export class Deployment extends WorkloadKubeObject {
|
export class Deployment extends WorkloadKubeObject {
|
||||||
static kind = "Deployment";
|
static kind = "Deployment";
|
||||||
static namespaced = true;
|
static namespaced = true;
|
||||||
static apiBase = "/apis/apps/v1/deployments";
|
static apiBase = "/apis/apps/v1/deployments";
|
||||||
|
|
||||||
spec: {
|
constructor(data: KubeJsonApiData) {
|
||||||
|
super(data);
|
||||||
|
autoBind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
declare spec: {
|
||||||
replicas: number;
|
replicas: number;
|
||||||
selector: { matchLabels: { [app: string]: string } };
|
selector: { matchLabels: { [app: string]: string } };
|
||||||
template: {
|
template: {
|
||||||
@ -172,7 +177,7 @@ export class Deployment extends WorkloadKubeObject {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
status: {
|
declare status: {
|
||||||
observedGeneration: number;
|
observedGeneration: number;
|
||||||
replicas: number;
|
replicas: number;
|
||||||
updatedReplicas: number;
|
updatedReplicas: number;
|
||||||
|
|||||||
@ -19,9 +19,10 @@
|
|||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { autobind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
import { KubeObject } from "../kube-object";
|
import { KubeObject } from "../kube-object";
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
|
||||||
export interface IEndpointPort {
|
export interface IEndpointPort {
|
||||||
name?: string;
|
name?: string;
|
||||||
@ -121,13 +122,19 @@ export class EndpointSubset implements IEndpointSubset {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
export interface Endpoint {
|
||||||
|
subsets: IEndpointSubset[];
|
||||||
|
}
|
||||||
|
|
||||||
export class Endpoint extends KubeObject {
|
export class Endpoint extends KubeObject {
|
||||||
static kind = "Endpoints";
|
static kind = "Endpoints";
|
||||||
static namespaced = true;
|
static namespaced = true;
|
||||||
static apiBase = "/api/v1/endpoints";
|
static apiBase = "/api/v1/endpoints";
|
||||||
|
|
||||||
subsets: IEndpointSubset[];
|
constructor(data: KubeJsonApiData) {
|
||||||
|
super(data);
|
||||||
|
autoBind(this);
|
||||||
|
}
|
||||||
|
|
||||||
getEndpointSubsets(): EndpointSubset[] {
|
getEndpointSubsets(): EndpointSubset[] {
|
||||||
const subsets = this.subsets || [];
|
const subsets = this.subsets || [];
|
||||||
|
|||||||
@ -22,15 +22,9 @@
|
|||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { KubeObject } from "../kube-object";
|
import { KubeObject } from "../kube-object";
|
||||||
import { formatDuration } from "../../utils/formatDuration";
|
import { formatDuration } from "../../utils/formatDuration";
|
||||||
import { autobind } from "../../utils";
|
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
|
|
||||||
@autobind()
|
export interface KubeEvent {
|
||||||
export class KubeEvent extends KubeObject {
|
|
||||||
static kind = "Event";
|
|
||||||
static namespaced = true;
|
|
||||||
static apiBase = "/api/v1/events";
|
|
||||||
|
|
||||||
involvedObject: {
|
involvedObject: {
|
||||||
kind: string;
|
kind: string;
|
||||||
namespace: string;
|
namespace: string;
|
||||||
@ -53,6 +47,12 @@ export class KubeEvent extends KubeObject {
|
|||||||
eventTime: null;
|
eventTime: null;
|
||||||
reportingComponent: string;
|
reportingComponent: string;
|
||||||
reportingInstance: string;
|
reportingInstance: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class KubeEvent extends KubeObject {
|
||||||
|
static kind = "Event";
|
||||||
|
static namespaced = true;
|
||||||
|
static apiBase = "/api/v1/events";
|
||||||
|
|
||||||
isWarning() {
|
isWarning() {
|
||||||
return this.type === "Warning";
|
return this.type === "Warning";
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
import { compile } from "path-to-regexp";
|
import { compile } from "path-to-regexp";
|
||||||
import { apiBase } from "../index";
|
import { apiBase } from "../index";
|
||||||
import { stringify } from "querystring";
|
import { stringify } from "querystring";
|
||||||
import { autobind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
|
|
||||||
export type RepoHelmChartList = Record<string, HelmChart[]>;
|
export type RepoHelmChartList = Record<string, HelmChart[]>;
|
||||||
export type HelmChartList = Record<string, RepoHelmChartList>;
|
export type HelmChartList = Record<string, RepoHelmChartList>;
|
||||||
@ -83,16 +83,7 @@ export async function getChartValues(repo: string, name: string, version: string
|
|||||||
return apiBase.get<string>(`/v2/charts/${repo}/${name}/values?${stringify({ version })}`);
|
return apiBase.get<string>(`/v2/charts/${repo}/${name}/values?${stringify({ version })}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
export interface HelmChart {
|
||||||
export class HelmChart {
|
|
||||||
constructor(data: any) {
|
|
||||||
Object.assign(this, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static create(data: any) {
|
|
||||||
return new HelmChart(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
apiVersion: string;
|
apiVersion: string;
|
||||||
name: string;
|
name: string;
|
||||||
version: string;
|
version: string;
|
||||||
@ -114,6 +105,17 @@ export class HelmChart {
|
|||||||
appVersion?: string;
|
appVersion?: string;
|
||||||
deprecated?: boolean;
|
deprecated?: boolean;
|
||||||
tillerVersion?: string;
|
tillerVersion?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class HelmChart {
|
||||||
|
constructor(data: HelmChart) {
|
||||||
|
Object.assign(this, data);
|
||||||
|
autoBind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
static create(data: any) {
|
||||||
|
return new HelmChart(data);
|
||||||
|
}
|
||||||
|
|
||||||
getId() {
|
getId() {
|
||||||
return `${this.repo}:${this.apiVersion}/${this.name}@${this.getAppVersion()}+${this.digest}`;
|
return `${this.repo}:${this.apiVersion}/${this.name}@${this.getAppVersion()}+${this.digest}`;
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
import jsYaml from "js-yaml";
|
import jsYaml from "js-yaml";
|
||||||
import { compile } from "path-to-regexp";
|
import { compile } from "path-to-regexp";
|
||||||
import { autobind, formatDuration } from "../../utils";
|
import { autoBind, formatDuration } from "../../utils";
|
||||||
import capitalize from "lodash/capitalize";
|
import capitalize from "lodash/capitalize";
|
||||||
import { apiBase } from "../index";
|
import { apiBase } from "../index";
|
||||||
import { helmChartStore } from "../../components/+apps-helm-charts/helm-chart.store";
|
import { helmChartStore } from "../../components/+apps-helm-charts/helm-chart.store";
|
||||||
@ -155,16 +155,7 @@ export async function rollbackRelease(name: string, namespace: string, revision:
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
export interface HelmRelease {
|
||||||
export class HelmRelease implements ItemObject {
|
|
||||||
constructor(data: any) {
|
|
||||||
Object.assign(this, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static create(data: any) {
|
|
||||||
return new HelmRelease(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
appVersion: string;
|
appVersion: string;
|
||||||
name: string;
|
name: string;
|
||||||
namespace: string;
|
namespace: string;
|
||||||
@ -172,6 +163,17 @@ export class HelmRelease implements ItemObject {
|
|||||||
status: string;
|
status: string;
|
||||||
updated: string;
|
updated: string;
|
||||||
revision: string;
|
revision: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class HelmRelease implements ItemObject {
|
||||||
|
constructor(data: any) {
|
||||||
|
Object.assign(this, data);
|
||||||
|
autoBind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
static create(data: any) {
|
||||||
|
return new HelmRelease(data);
|
||||||
|
}
|
||||||
|
|
||||||
getId() {
|
getId() {
|
||||||
return this.namespace + this.name;
|
return this.namespace + this.name;
|
||||||
|
|||||||
@ -59,11 +59,7 @@ export interface IHpaMetric {
|
|||||||
}>;
|
}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class HorizontalPodAutoscaler extends KubeObject {
|
export interface HorizontalPodAutoscaler {
|
||||||
static kind = "HorizontalPodAutoscaler";
|
|
||||||
static namespaced = true;
|
|
||||||
static apiBase = "/apis/autoscaling/v2beta1/horizontalpodautoscalers";
|
|
||||||
|
|
||||||
spec: {
|
spec: {
|
||||||
scaleTargetRef: {
|
scaleTargetRef: {
|
||||||
kind: string;
|
kind: string;
|
||||||
@ -86,6 +82,12 @@ export class HorizontalPodAutoscaler extends KubeObject {
|
|||||||
type: string;
|
type: string;
|
||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class HorizontalPodAutoscaler extends KubeObject {
|
||||||
|
static kind = "HorizontalPodAutoscaler";
|
||||||
|
static namespaced = true;
|
||||||
|
static apiBase = "/apis/autoscaling/v2beta1/horizontalpodautoscalers";
|
||||||
|
|
||||||
getMaxPods() {
|
getMaxPods() {
|
||||||
return this.spec.maxReplicas || 0;
|
return this.spec.maxReplicas || 0;
|
||||||
|
|||||||
@ -20,13 +20,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { KubeObject } from "../kube-object";
|
import { KubeObject } from "../kube-object";
|
||||||
import { autobind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
import { IMetrics, metricsApi } from "./metrics.api";
|
import { IMetrics, metricsApi } from "./metrics.api";
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
|
||||||
export class IngressApi extends KubeApi<Ingress> {
|
export class IngressApi extends KubeApi<Ingress> {
|
||||||
getMetrics(ingress: string, namespace: string): Promise<IIngressMetrics> {
|
getMetrics(ingress: string, namespace: string): Promise<IIngressMetrics> {
|
||||||
const opts = { category: "ingress", ingress };
|
const opts = { category: "ingress", ingress, namespace };
|
||||||
|
|
||||||
return metricsApi.getMetrics({
|
return metricsApi.getMetrics({
|
||||||
bytesSentSuccess: opts,
|
bytesSentSuccess: opts,
|
||||||
@ -82,12 +83,7 @@ export const getBackendServiceNamePort = (backend: IIngressBackend) => {
|
|||||||
return { serviceName, servicePort };
|
return { serviceName, servicePort };
|
||||||
};
|
};
|
||||||
|
|
||||||
@autobind()
|
export interface Ingress {
|
||||||
export class Ingress extends KubeObject {
|
|
||||||
static kind = "Ingress";
|
|
||||||
static namespaced = true;
|
|
||||||
static apiBase = "/apis/networking.k8s.io/v1/ingresses";
|
|
||||||
|
|
||||||
spec: {
|
spec: {
|
||||||
tls: {
|
tls: {
|
||||||
secretName: string;
|
secretName: string;
|
||||||
@ -117,6 +113,17 @@ export class Ingress extends KubeObject {
|
|||||||
ingress: ILoadBalancerIngress[];
|
ingress: ILoadBalancerIngress[];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Ingress extends KubeObject {
|
||||||
|
static kind = "Ingress";
|
||||||
|
static namespaced = true;
|
||||||
|
static apiBase = "/apis/networking.k8s.io/v1/ingresses";
|
||||||
|
|
||||||
|
constructor(data: KubeJsonApiData) {
|
||||||
|
super(data);
|
||||||
|
autoBind(this);
|
||||||
|
}
|
||||||
|
|
||||||
getRoutes() {
|
getRoutes() {
|
||||||
const { spec: { tls, rules } } = this;
|
const { spec: { tls, rules } } = this;
|
||||||
@ -188,7 +195,7 @@ export class Ingress extends KubeObject {
|
|||||||
|
|
||||||
getLoadBalancers() {
|
getLoadBalancers() {
|
||||||
const { status: { loadBalancer = { ingress: [] } } } = this;
|
const { status: { loadBalancer = { ingress: [] } } } = this;
|
||||||
|
|
||||||
return (loadBalancer.ingress ?? []).map(address => (
|
return (loadBalancer.ingress ?? []).map(address => (
|
||||||
address.hostname || address.ip
|
address.hostname || address.ip
|
||||||
));
|
));
|
||||||
|
|||||||
@ -20,19 +20,24 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import get from "lodash/get";
|
import get from "lodash/get";
|
||||||
import { autobind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
import { IAffinity, WorkloadKubeObject } from "../workload-kube-object";
|
import { IAffinity, WorkloadKubeObject } from "../workload-kube-object";
|
||||||
import type { IPodContainer } from "./pods.api";
|
import type { IPodContainer } from "./pods.api";
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
import type { JsonApiParams } from "../json-api";
|
import type { JsonApiParams } from "../json-api";
|
||||||
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
|
||||||
@autobind()
|
|
||||||
export class Job extends WorkloadKubeObject {
|
export class Job extends WorkloadKubeObject {
|
||||||
static kind = "Job";
|
static kind = "Job";
|
||||||
static namespaced = true;
|
static namespaced = true;
|
||||||
static apiBase = "/apis/batch/v1/jobs";
|
static apiBase = "/apis/batch/v1/jobs";
|
||||||
|
|
||||||
spec: {
|
constructor(data: KubeJsonApiData) {
|
||||||
|
super(data);
|
||||||
|
autoBind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
declare spec: {
|
||||||
parallelism?: number;
|
parallelism?: number;
|
||||||
completions?: number;
|
completions?: number;
|
||||||
backoffLimit?: number;
|
backoffLimit?: number;
|
||||||
@ -78,7 +83,7 @@ export class Job extends WorkloadKubeObject {
|
|||||||
serviceAccount?: string;
|
serviceAccount?: string;
|
||||||
schedulerName?: string;
|
schedulerName?: string;
|
||||||
};
|
};
|
||||||
status: {
|
declare status: {
|
||||||
conditions: {
|
conditions: {
|
||||||
type: string;
|
type: string;
|
||||||
status: string;
|
status: string;
|
||||||
|
|||||||
@ -21,7 +21,8 @@
|
|||||||
|
|
||||||
import { KubeObject } from "../kube-object";
|
import { KubeObject } from "../kube-object";
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
import { autobind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
|
||||||
export enum LimitType {
|
export enum LimitType {
|
||||||
CONTAINER = "Container",
|
CONTAINER = "Container",
|
||||||
@ -50,15 +51,21 @@ export interface LimitRangeItem extends LimitRangeParts {
|
|||||||
type: string
|
type: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
export interface LimitRange {
|
||||||
|
spec: {
|
||||||
|
limits: LimitRangeItem[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export class LimitRange extends KubeObject {
|
export class LimitRange extends KubeObject {
|
||||||
static kind = "LimitRange";
|
static kind = "LimitRange";
|
||||||
static namespaced = true;
|
static namespaced = true;
|
||||||
static apiBase = "/api/v1/limitranges";
|
static apiBase = "/api/v1/limitranges";
|
||||||
|
|
||||||
spec: {
|
constructor(data: KubeJsonApiData) {
|
||||||
limits: LimitRangeItem[];
|
super(data);
|
||||||
};
|
autoBind(this);
|
||||||
|
}
|
||||||
|
|
||||||
getContainerLimits() {
|
getContainerLimits() {
|
||||||
return this.spec.limits.filter(limit => limit.type === LimitType.CONTAINER);
|
return this.spec.limits.filter(limit => limit.type === LimitType.CONTAINER);
|
||||||
|
|||||||
@ -21,25 +21,32 @@
|
|||||||
|
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
import { KubeObject } from "../kube-object";
|
import { KubeObject } from "../kube-object";
|
||||||
import { autobind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
|
||||||
export enum NamespaceStatus {
|
export enum NamespaceStatus {
|
||||||
ACTIVE = "Active",
|
ACTIVE = "Active",
|
||||||
TERMINATING = "Terminating",
|
TERMINATING = "Terminating",
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
export interface Namespace {
|
||||||
|
status?: {
|
||||||
|
phase: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export class Namespace extends KubeObject {
|
export class Namespace extends KubeObject {
|
||||||
static kind = "Namespace";
|
static kind = "Namespace";
|
||||||
static namespaced = false;
|
static namespaced = false;
|
||||||
static apiBase = "/api/v1/namespaces";
|
static apiBase = "/api/v1/namespaces";
|
||||||
|
|
||||||
status?: {
|
constructor(data: KubeJsonApiData) {
|
||||||
phase: string;
|
super(data);
|
||||||
};
|
autoBind(this);
|
||||||
|
}
|
||||||
|
|
||||||
getStatus() {
|
getStatus() {
|
||||||
return this.status ? this.status.phase : "-";
|
return this.status?.phase ?? "-";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -20,8 +20,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { KubeObject } from "../kube-object";
|
import { KubeObject } from "../kube-object";
|
||||||
import { autobind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
|
||||||
export interface IPolicyIpBlock {
|
export interface IPolicyIpBlock {
|
||||||
cidr: string;
|
cidr: string;
|
||||||
@ -56,12 +57,7 @@ export interface IPolicyEgress {
|
|||||||
}[];
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
export interface NetworkPolicy {
|
||||||
export class NetworkPolicy extends KubeObject {
|
|
||||||
static kind = "NetworkPolicy";
|
|
||||||
static namespaced = true;
|
|
||||||
static apiBase = "/apis/networking.k8s.io/v1/networkpolicies";
|
|
||||||
|
|
||||||
spec: {
|
spec: {
|
||||||
podSelector: {
|
podSelector: {
|
||||||
matchLabels: {
|
matchLabels: {
|
||||||
@ -73,6 +69,17 @@ export class NetworkPolicy extends KubeObject {
|
|||||||
ingress: IPolicyIngress[];
|
ingress: IPolicyIngress[];
|
||||||
egress: IPolicyEgress[];
|
egress: IPolicyEgress[];
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class NetworkPolicy extends KubeObject {
|
||||||
|
static kind = "NetworkPolicy";
|
||||||
|
static namespaced = true;
|
||||||
|
static apiBase = "/apis/networking.k8s.io/v1/networkpolicies";
|
||||||
|
|
||||||
|
constructor(data: KubeJsonApiData) {
|
||||||
|
super(data);
|
||||||
|
autoBind(this);
|
||||||
|
}
|
||||||
|
|
||||||
getMatchLabels(): string[] {
|
getMatchLabels(): string[] {
|
||||||
if (!this.spec.podSelector || !this.spec.podSelector.matchLabels) return [];
|
if (!this.spec.podSelector || !this.spec.podSelector.matchLabels) return [];
|
||||||
|
|||||||
@ -20,13 +20,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { KubeObject } from "../kube-object";
|
import { KubeObject } from "../kube-object";
|
||||||
import { autobind, cpuUnitsToNumber, unitsToBytes } from "../../utils";
|
import { autoBind, cpuUnitsToNumber, unitsToBytes } from "../../utils";
|
||||||
import { IMetrics, metricsApi } from "./metrics.api";
|
import { IMetrics, metricsApi } from "./metrics.api";
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
|
||||||
export class NodesApi extends KubeApi<Node> {
|
export class NodesApi extends KubeApi<Node> {
|
||||||
getMetrics(): Promise<INodeMetrics> {
|
getMetrics(): Promise<INodeMetrics> {
|
||||||
const opts = { category: "nodes"};
|
const opts = { category: "nodes" };
|
||||||
|
|
||||||
return metricsApi.getMetrics({
|
return metricsApi.getMetrics({
|
||||||
memoryUsage: opts,
|
memoryUsage: opts,
|
||||||
@ -49,12 +50,7 @@ export interface INodeMetrics<T = IMetrics> {
|
|||||||
fsSize: T;
|
fsSize: T;
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
export interface Node {
|
||||||
export class Node extends KubeObject {
|
|
||||||
static kind = "Node";
|
|
||||||
static namespaced = false;
|
|
||||||
static apiBase = "/api/v1/nodes";
|
|
||||||
|
|
||||||
spec: {
|
spec: {
|
||||||
podCIDR: string;
|
podCIDR: string;
|
||||||
externalID: string;
|
externalID: string;
|
||||||
@ -105,6 +101,17 @@ export class Node extends KubeObject {
|
|||||||
sizeBytes: number;
|
sizeBytes: number;
|
||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Node extends KubeObject {
|
||||||
|
static kind = "Node";
|
||||||
|
static namespaced = false;
|
||||||
|
static apiBase = "/api/v1/nodes";
|
||||||
|
|
||||||
|
constructor(data: KubeJsonApiData) {
|
||||||
|
super(data);
|
||||||
|
autoBind(this);
|
||||||
|
}
|
||||||
|
|
||||||
getNodeConditionText() {
|
getNodeConditionText() {
|
||||||
const { conditions } = this.status;
|
const { conditions } = this.status;
|
||||||
|
|||||||
@ -20,16 +20,17 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { KubeObject } from "../kube-object";
|
import { KubeObject } from "../kube-object";
|
||||||
import { autobind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
import { IMetrics, metricsApi } from "./metrics.api";
|
import { IMetrics, metricsApi } from "./metrics.api";
|
||||||
import type { Pod } from "./pods.api";
|
import type { Pod } from "./pods.api";
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
|
||||||
export class PersistentVolumeClaimsApi extends KubeApi<PersistentVolumeClaim> {
|
export class PersistentVolumeClaimsApi extends KubeApi<PersistentVolumeClaim> {
|
||||||
getMetrics(pvcName: string, namespace: string): Promise<IPvcMetrics> {
|
getMetrics(pvcName: string, namespace: string): Promise<IPvcMetrics> {
|
||||||
return metricsApi.getMetrics({
|
return metricsApi.getMetrics({
|
||||||
diskUsage: { category: "pvc", pvc: pvcName },
|
diskUsage: { category: "pvc", pvc: pvcName, namespace },
|
||||||
diskCapacity: { category: "pvc", pvc: pvcName }
|
diskCapacity: { category: "pvc", pvc: pvcName, namespace }
|
||||||
}, {
|
}, {
|
||||||
namespace
|
namespace
|
||||||
});
|
});
|
||||||
@ -42,12 +43,7 @@ export interface IPvcMetrics<T = IMetrics> {
|
|||||||
diskCapacity: T;
|
diskCapacity: T;
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
export interface PersistentVolumeClaim {
|
||||||
export class PersistentVolumeClaim extends KubeObject {
|
|
||||||
static kind = "PersistentVolumeClaim";
|
|
||||||
static namespaced = true;
|
|
||||||
static apiBase = "/api/v1/persistentvolumeclaims";
|
|
||||||
|
|
||||||
spec: {
|
spec: {
|
||||||
accessModes: string[];
|
accessModes: string[];
|
||||||
storageClassName: string;
|
storageClassName: string;
|
||||||
@ -70,6 +66,17 @@ export class PersistentVolumeClaim extends KubeObject {
|
|||||||
status: {
|
status: {
|
||||||
phase: string; // Pending
|
phase: string; // Pending
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PersistentVolumeClaim extends KubeObject {
|
||||||
|
static kind = "PersistentVolumeClaim";
|
||||||
|
static namespaced = true;
|
||||||
|
static apiBase = "/api/v1/persistentvolumeclaims";
|
||||||
|
|
||||||
|
constructor(data: KubeJsonApiData) {
|
||||||
|
super(data);
|
||||||
|
autoBind(this);
|
||||||
|
}
|
||||||
|
|
||||||
getPods(allPods: Pod[]): Pod[] {
|
getPods(allPods: Pod[]): Pod[] {
|
||||||
const pods = allPods.filter(pod => pod.getNs() === this.getNs());
|
const pods = allPods.filter(pod => pod.getNs() === this.getNs());
|
||||||
|
|||||||
@ -21,15 +21,11 @@
|
|||||||
|
|
||||||
import { KubeObject } from "../kube-object";
|
import { KubeObject } from "../kube-object";
|
||||||
import { unitsToBytes } from "../../utils/convertMemory";
|
import { unitsToBytes } from "../../utils/convertMemory";
|
||||||
import { autobind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
|
||||||
@autobind()
|
export interface PersistentVolume {
|
||||||
export class PersistentVolume extends KubeObject {
|
|
||||||
static kind = "PersistentVolume";
|
|
||||||
static namespaced = false;
|
|
||||||
static apiBase = "/api/v1/persistentvolumes";
|
|
||||||
|
|
||||||
spec: {
|
spec: {
|
||||||
capacity: {
|
capacity: {
|
||||||
storage: string; // 8Gi
|
storage: string; // 8Gi
|
||||||
@ -65,6 +61,17 @@ export class PersistentVolume extends KubeObject {
|
|||||||
phase: string;
|
phase: string;
|
||||||
reason?: string;
|
reason?: string;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PersistentVolume extends KubeObject {
|
||||||
|
static kind = "PersistentVolume";
|
||||||
|
static namespaced = false;
|
||||||
|
static apiBase = "/api/v1/persistentvolumes";
|
||||||
|
|
||||||
|
constructor(data: KubeJsonApiData) {
|
||||||
|
super(data);
|
||||||
|
autoBind(this);
|
||||||
|
}
|
||||||
|
|
||||||
getCapacity(inBytes = false) {
|
getCapacity(inBytes = false) {
|
||||||
const capacity = this.spec.capacity;
|
const capacity = this.spec.capacity;
|
||||||
|
|||||||
@ -22,11 +22,7 @@
|
|||||||
import { KubeObject } from "../kube-object";
|
import { KubeObject } from "../kube-object";
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
|
|
||||||
export class PodMetrics extends KubeObject {
|
export interface PodMetrics {
|
||||||
static kind = "PodMetrics";
|
|
||||||
static namespaced = true;
|
|
||||||
static apiBase = "/apis/metrics.k8s.io/v1beta1/pods";
|
|
||||||
|
|
||||||
timestamp: string;
|
timestamp: string;
|
||||||
window: string;
|
window: string;
|
||||||
containers: {
|
containers: {
|
||||||
@ -38,6 +34,12 @@ export class PodMetrics extends KubeObject {
|
|||||||
}[];
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class PodMetrics extends KubeObject {
|
||||||
|
static kind = "PodMetrics";
|
||||||
|
static namespaced = true;
|
||||||
|
static apiBase = "/apis/metrics.k8s.io/v1beta1/pods";
|
||||||
|
}
|
||||||
|
|
||||||
export const podMetricsApi = new KubeApi({
|
export const podMetricsApi = new KubeApi({
|
||||||
objectConstructor: PodMetrics,
|
objectConstructor: PodMetrics,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -19,16 +19,12 @@
|
|||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { autobind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
import { KubeObject } from "../kube-object";
|
import { KubeObject } from "../kube-object";
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
|
||||||
@autobind()
|
export interface PodDisruptionBudget {
|
||||||
export class PodDisruptionBudget extends KubeObject {
|
|
||||||
static kind = "PodDisruptionBudget";
|
|
||||||
static namespaced = true;
|
|
||||||
static apiBase = "/apis/policy/v1beta1/poddisruptionbudgets";
|
|
||||||
|
|
||||||
spec: {
|
spec: {
|
||||||
minAvailable: string;
|
minAvailable: string;
|
||||||
maxUnavailable: string;
|
maxUnavailable: string;
|
||||||
@ -40,6 +36,17 @@ export class PodDisruptionBudget extends KubeObject {
|
|||||||
disruptionsAllowed: number
|
disruptionsAllowed: number
|
||||||
expectedPods: number
|
expectedPods: number
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PodDisruptionBudget extends KubeObject {
|
||||||
|
static kind = "PodDisruptionBudget";
|
||||||
|
static namespaced = true;
|
||||||
|
static apiBase = "/apis/policy/v1beta1/poddisruptionbudgets";
|
||||||
|
|
||||||
|
constructor(data: KubeJsonApiData) {
|
||||||
|
super(data);
|
||||||
|
autoBind(this);
|
||||||
|
}
|
||||||
|
|
||||||
getSelectors() {
|
getSelectors() {
|
||||||
const selector = this.spec.selector;
|
const selector = this.spec.selector;
|
||||||
|
|||||||
@ -20,9 +20,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { IAffinity, WorkloadKubeObject } from "../workload-kube-object";
|
import { IAffinity, WorkloadKubeObject } from "../workload-kube-object";
|
||||||
import { autobind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
import { IMetrics, metricsApi } from "./metrics.api";
|
import { IMetrics, metricsApi } from "./metrics.api";
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
|
||||||
export class PodsApi extends KubeApi<Pod> {
|
export class PodsApi extends KubeApi<Pod> {
|
||||||
async getLogs(params: { namespace: string; name: string }, query?: IPodLogsQuery): Promise<string> {
|
async getLogs(params: { namespace: string; name: string }, query?: IPodLogsQuery): Promise<string> {
|
||||||
@ -202,13 +203,17 @@ export interface IPodContainerStatus {
|
|||||||
started?: boolean;
|
started?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
|
||||||
export class Pod extends WorkloadKubeObject {
|
export class Pod extends WorkloadKubeObject {
|
||||||
static kind = "Pod";
|
static kind = "Pod";
|
||||||
static namespaced = true;
|
static namespaced = true;
|
||||||
static apiBase = "/api/v1/pods";
|
static apiBase = "/api/v1/pods";
|
||||||
|
|
||||||
spec: {
|
constructor(data: KubeJsonApiData) {
|
||||||
|
super(data);
|
||||||
|
autoBind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
declare spec: {
|
||||||
volumes?: {
|
volumes?: {
|
||||||
name: string;
|
name: string;
|
||||||
persistentVolumeClaim: {
|
persistentVolumeClaim: {
|
||||||
@ -265,7 +270,7 @@ export class Pod extends WorkloadKubeObject {
|
|||||||
};
|
};
|
||||||
affinity?: IAffinity;
|
affinity?: IAffinity;
|
||||||
};
|
};
|
||||||
status?: {
|
declare status?: {
|
||||||
phase: string;
|
phase: string;
|
||||||
conditions: {
|
conditions: {
|
||||||
type: string;
|
type: string;
|
||||||
|
|||||||
@ -19,16 +19,12 @@
|
|||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { autobind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
import { KubeObject } from "../kube-object";
|
import { KubeObject } from "../kube-object";
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
|
||||||
@autobind()
|
export interface PodSecurityPolicy {
|
||||||
export class PodSecurityPolicy extends KubeObject {
|
|
||||||
static kind = "PodSecurityPolicy";
|
|
||||||
static namespaced = false;
|
|
||||||
static apiBase = "/apis/policy/v1beta1/podsecuritypolicies";
|
|
||||||
|
|
||||||
spec: {
|
spec: {
|
||||||
allowPrivilegeEscalation?: boolean;
|
allowPrivilegeEscalation?: boolean;
|
||||||
allowedCSIDrivers?: {
|
allowedCSIDrivers?: {
|
||||||
@ -88,6 +84,17 @@ export class PodSecurityPolicy extends KubeObject {
|
|||||||
};
|
};
|
||||||
volumes?: string[];
|
volumes?: string[];
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PodSecurityPolicy extends KubeObject {
|
||||||
|
static kind = "PodSecurityPolicy";
|
||||||
|
static namespaced = false;
|
||||||
|
static apiBase = "/apis/policy/v1beta1/podsecuritypolicies";
|
||||||
|
|
||||||
|
constructor(data: KubeJsonApiData) {
|
||||||
|
super(data);
|
||||||
|
autoBind(this);
|
||||||
|
}
|
||||||
|
|
||||||
isPrivileged() {
|
isPrivileged() {
|
||||||
return !!this.spec.privileged;
|
return !!this.spec.privileged;
|
||||||
|
|||||||
@ -20,10 +20,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import get from "lodash/get";
|
import get from "lodash/get";
|
||||||
import { autobind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
import { WorkloadKubeObject } from "../workload-kube-object";
|
import { WorkloadKubeObject } from "../workload-kube-object";
|
||||||
import type { IPodContainer, Pod } from "./pods.api";
|
import type { IPodContainer, Pod } from "./pods.api";
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
|
||||||
export class ReplicaSetApi extends KubeApi<ReplicaSet> {
|
export class ReplicaSetApi extends KubeApi<ReplicaSet> {
|
||||||
protected getScaleApiUrl(params: { namespace: string; name: string }) {
|
protected getScaleApiUrl(params: { namespace: string; name: string }) {
|
||||||
@ -48,12 +49,17 @@ export class ReplicaSetApi extends KubeApi<ReplicaSet> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
|
||||||
export class ReplicaSet extends WorkloadKubeObject {
|
export class ReplicaSet extends WorkloadKubeObject {
|
||||||
static kind = "ReplicaSet";
|
static kind = "ReplicaSet";
|
||||||
static namespaced = true;
|
static namespaced = true;
|
||||||
static apiBase = "/apis/apps/v1/replicasets";
|
static apiBase = "/apis/apps/v1/replicasets";
|
||||||
spec: {
|
|
||||||
|
constructor(data: KubeJsonApiData) {
|
||||||
|
super(data);
|
||||||
|
autoBind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
declare spec: {
|
||||||
replicas?: number;
|
replicas?: number;
|
||||||
selector: { matchLabels: { [app: string]: string } };
|
selector: { matchLabels: { [app: string]: string } };
|
||||||
template?: {
|
template?: {
|
||||||
@ -66,7 +72,7 @@ export class ReplicaSet extends WorkloadKubeObject {
|
|||||||
};
|
};
|
||||||
minReadySeconds?: number;
|
minReadySeconds?: number;
|
||||||
};
|
};
|
||||||
status: {
|
declare status: {
|
||||||
replicas: number;
|
replicas: number;
|
||||||
fullyLabeledReplicas?: number;
|
fullyLabeledReplicas?: number;
|
||||||
readyReplicas?: number;
|
readyReplicas?: number;
|
||||||
|
|||||||
@ -21,7 +21,6 @@
|
|||||||
|
|
||||||
import { KubeObject } from "../kube-object";
|
import { KubeObject } from "../kube-object";
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
import type { KubeJsonApiData } from "../kube-json-api";
|
|
||||||
|
|
||||||
export interface IResourceQuotaValues {
|
export interface IResourceQuotaValues {
|
||||||
[quota: string]: string;
|
[quota: string]: string;
|
||||||
@ -51,16 +50,7 @@ export interface IResourceQuotaValues {
|
|||||||
"count/deployments.extensions"?: string;
|
"count/deployments.extensions"?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ResourceQuota extends KubeObject {
|
export interface ResourceQuota {
|
||||||
static kind = "ResourceQuota";
|
|
||||||
static namespaced = true;
|
|
||||||
static apiBase = "/api/v1/resourcequotas";
|
|
||||||
|
|
||||||
constructor(data: KubeJsonApiData) {
|
|
||||||
super(data);
|
|
||||||
this.spec = this.spec || {} as any;
|
|
||||||
}
|
|
||||||
|
|
||||||
spec: {
|
spec: {
|
||||||
hard: IResourceQuotaValues;
|
hard: IResourceQuotaValues;
|
||||||
scopeSelector?: {
|
scopeSelector?: {
|
||||||
@ -76,6 +66,12 @@ export class ResourceQuota extends KubeObject {
|
|||||||
hard: IResourceQuotaValues;
|
hard: IResourceQuotaValues;
|
||||||
used: IResourceQuotaValues;
|
used: IResourceQuotaValues;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ResourceQuota extends KubeObject {
|
||||||
|
static kind = "ResourceQuota";
|
||||||
|
static namespaced = true;
|
||||||
|
static apiBase = "/api/v1/resourcequotas";
|
||||||
|
|
||||||
getScopeSelector() {
|
getScopeSelector() {
|
||||||
const { matchExpressions = [] } = this.spec.scopeSelector || {};
|
const { matchExpressions = [] } = this.spec.scopeSelector || {};
|
||||||
|
|||||||
@ -19,9 +19,10 @@
|
|||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { autobind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
import { KubeObject } from "../kube-object";
|
import { KubeObject } from "../kube-object";
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
|
||||||
export interface IRoleBindingSubject {
|
export interface IRoleBindingSubject {
|
||||||
kind: string;
|
kind: string;
|
||||||
@ -30,18 +31,24 @@ export interface IRoleBindingSubject {
|
|||||||
apiGroup?: string;
|
apiGroup?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
export interface RoleBinding {
|
||||||
export class RoleBinding extends KubeObject {
|
|
||||||
static kind = "RoleBinding";
|
|
||||||
static namespaced = true;
|
|
||||||
static apiBase = "/apis/rbac.authorization.k8s.io/v1/rolebindings";
|
|
||||||
|
|
||||||
subjects?: IRoleBindingSubject[];
|
subjects?: IRoleBindingSubject[];
|
||||||
roleRef: {
|
roleRef: {
|
||||||
kind: string;
|
kind: string;
|
||||||
name: string;
|
name: string;
|
||||||
apiGroup?: string;
|
apiGroup?: string;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RoleBinding extends KubeObject {
|
||||||
|
static kind = "RoleBinding";
|
||||||
|
static namespaced = true;
|
||||||
|
static apiBase = "/apis/rbac.authorization.k8s.io/v1/rolebindings";
|
||||||
|
|
||||||
|
constructor(data: KubeJsonApiData) {
|
||||||
|
super(data);
|
||||||
|
autoBind(this);
|
||||||
|
}
|
||||||
|
|
||||||
getSubjects() {
|
getSubjects() {
|
||||||
return this.subjects || [];
|
return this.subjects || [];
|
||||||
|
|||||||
@ -22,17 +22,19 @@
|
|||||||
import { KubeObject } from "../kube-object";
|
import { KubeObject } from "../kube-object";
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
|
|
||||||
export class Role extends KubeObject {
|
export interface Role {
|
||||||
static kind = "Role";
|
|
||||||
static namespaced = true;
|
|
||||||
static apiBase = "/apis/rbac.authorization.k8s.io/v1/roles";
|
|
||||||
|
|
||||||
rules: {
|
rules: {
|
||||||
verbs: string[];
|
verbs: string[];
|
||||||
apiGroups: string[];
|
apiGroups: string[];
|
||||||
resources: string[];
|
resources: string[];
|
||||||
resourceNames?: string[];
|
resourceNames?: string[];
|
||||||
}[];
|
}[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Role extends KubeObject {
|
||||||
|
static kind = "Role";
|
||||||
|
static namespaced = true;
|
||||||
|
static apiBase = "/apis/rbac.authorization.k8s.io/v1/roles";
|
||||||
|
|
||||||
getRules() {
|
getRules() {
|
||||||
return this.rules || [];
|
return this.rules || [];
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
import { KubeObject } from "../kube-object";
|
import { KubeObject } from "../kube-object";
|
||||||
import type { KubeJsonApiData } from "../kube-json-api";
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
import { autobind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
|
|
||||||
export enum SecretType {
|
export enum SecretType {
|
||||||
@ -40,21 +40,24 @@ export interface ISecretRef {
|
|||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
export interface Secret {
|
||||||
export class Secret extends KubeObject {
|
|
||||||
static kind = "Secret";
|
|
||||||
static namespaced = true;
|
|
||||||
static apiBase = "/api/v1/secrets";
|
|
||||||
|
|
||||||
type: SecretType;
|
type: SecretType;
|
||||||
data: {
|
data: {
|
||||||
[prop: string]: string;
|
[prop: string]: string;
|
||||||
token?: string;
|
token?: string;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Secret extends KubeObject {
|
||||||
|
static kind = "Secret";
|
||||||
|
static namespaced = true;
|
||||||
|
static apiBase = "/api/v1/secrets";
|
||||||
|
|
||||||
constructor(data: KubeJsonApiData) {
|
constructor(data: KubeJsonApiData) {
|
||||||
super(data);
|
super(data);
|
||||||
this.data = this.data || {};
|
autoBind(this);
|
||||||
|
|
||||||
|
this.data ??= {};
|
||||||
}
|
}
|
||||||
|
|
||||||
getKeys(): string[] {
|
getKeys(): string[] {
|
||||||
|
|||||||
@ -28,8 +28,7 @@ export class SelfSubjectRulesReviewApi extends KubeApi<SelfSubjectRulesReview> {
|
|||||||
spec: {
|
spec: {
|
||||||
namespace
|
namespace
|
||||||
},
|
},
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,21 +40,21 @@ export interface ISelfSubjectReviewRule {
|
|||||||
nonResourceURLs?: string[];
|
nonResourceURLs?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SelfSubjectRulesReview extends KubeObject {
|
export interface SelfSubjectRulesReview {
|
||||||
static kind = "SelfSubjectRulesReview";
|
|
||||||
static namespaced = false;
|
|
||||||
static apiBase = "/apis/authorization.k8s.io/v1/selfsubjectrulesreviews";
|
|
||||||
|
|
||||||
spec: {
|
spec: {
|
||||||
// todo: add more types from api docs
|
|
||||||
namespace?: string;
|
namespace?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
status: {
|
status: {
|
||||||
resourceRules: ISelfSubjectReviewRule[];
|
resourceRules: ISelfSubjectReviewRule[];
|
||||||
nonResourceRules: ISelfSubjectReviewRule[];
|
nonResourceRules: ISelfSubjectReviewRule[];
|
||||||
incomplete: boolean;
|
incomplete: boolean;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SelfSubjectRulesReview extends KubeObject {
|
||||||
|
static kind = "SelfSubjectRulesReview";
|
||||||
|
static namespaced = false;
|
||||||
|
static apiBase = "/apis/authorization.k8s.io/v1/selfsubjectrulesreviews";
|
||||||
|
|
||||||
getResourceRules() {
|
getResourceRules() {
|
||||||
const rules = this.status && this.status.resourceRules || [];
|
const rules = this.status && this.status.resourceRules || [];
|
||||||
|
|||||||
@ -19,22 +19,29 @@
|
|||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { autobind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
import { KubeObject } from "../kube-object";
|
import { KubeObject } from "../kube-object";
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
|
||||||
@autobind()
|
export interface ServiceAccount {
|
||||||
export class ServiceAccount extends KubeObject {
|
|
||||||
static kind = "ServiceAccount";
|
|
||||||
static namespaced = true;
|
|
||||||
static apiBase = "/api/v1/serviceaccounts";
|
|
||||||
|
|
||||||
secrets?: {
|
secrets?: {
|
||||||
name: string;
|
name: string;
|
||||||
}[];
|
}[];
|
||||||
imagePullSecrets?: {
|
imagePullSecrets?: {
|
||||||
name: string;
|
name: string;
|
||||||
}[];
|
}[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ServiceAccount extends KubeObject {
|
||||||
|
static kind = "ServiceAccount";
|
||||||
|
static namespaced = true;
|
||||||
|
static apiBase = "/api/v1/serviceaccounts";
|
||||||
|
|
||||||
|
constructor(data: KubeJsonApiData) {
|
||||||
|
super(data);
|
||||||
|
autoBind(this);
|
||||||
|
}
|
||||||
|
|
||||||
getSecrets() {
|
getSecrets() {
|
||||||
return this.secrets || [];
|
return this.secrets || [];
|
||||||
|
|||||||
@ -19,25 +19,21 @@
|
|||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { autobind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
import { KubeObject } from "../kube-object";
|
import { KubeObject } from "../kube-object";
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
|
||||||
export interface IServicePort {
|
export interface ServicePort {
|
||||||
name?: string;
|
|
||||||
protocol: string;
|
|
||||||
port: number;
|
|
||||||
targetPort: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ServicePort implements IServicePort {
|
|
||||||
name?: string;
|
name?: string;
|
||||||
protocol: string;
|
protocol: string;
|
||||||
port: number;
|
port: number;
|
||||||
targetPort: number;
|
targetPort: number;
|
||||||
nodePort?: number;
|
nodePort?: number;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(data: IServicePort) {
|
export class ServicePort {
|
||||||
|
constructor(data: ServicePort) {
|
||||||
Object.assign(this, data);
|
Object.assign(this, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,12 +46,7 @@ export class ServicePort implements IServicePort {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
export interface Service {
|
||||||
export class Service extends KubeObject {
|
|
||||||
static kind = "Service";
|
|
||||||
static namespaced = true;
|
|
||||||
static apiBase = "/api/v1/services";
|
|
||||||
|
|
||||||
spec: {
|
spec: {
|
||||||
type: string;
|
type: string;
|
||||||
clusterIP: string;
|
clusterIP: string;
|
||||||
@ -75,6 +66,17 @@ export class Service extends KubeObject {
|
|||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Service extends KubeObject {
|
||||||
|
static kind = "Service";
|
||||||
|
static namespaced = true;
|
||||||
|
static apiBase = "/api/v1/services";
|
||||||
|
|
||||||
|
constructor(data: KubeJsonApiData) {
|
||||||
|
super(data);
|
||||||
|
autoBind(this);
|
||||||
|
}
|
||||||
|
|
||||||
getClusterIp() {
|
getClusterIp() {
|
||||||
return this.spec.clusterIP;
|
return this.spec.clusterIP;
|
||||||
|
|||||||
@ -22,8 +22,9 @@
|
|||||||
import get from "lodash/get";
|
import get from "lodash/get";
|
||||||
import type { IPodContainer } from "./pods.api";
|
import type { IPodContainer } from "./pods.api";
|
||||||
import { IAffinity, WorkloadKubeObject } from "../workload-kube-object";
|
import { IAffinity, WorkloadKubeObject } from "../workload-kube-object";
|
||||||
import { autobind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
|
||||||
export class StatefulSetApi extends KubeApi<StatefulSet> {
|
export class StatefulSetApi extends KubeApi<StatefulSet> {
|
||||||
protected getScaleApiUrl(params: { namespace: string; name: string }) {
|
protected getScaleApiUrl(params: { namespace: string; name: string }) {
|
||||||
@ -48,13 +49,17 @@ export class StatefulSetApi extends KubeApi<StatefulSet> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
|
||||||
export class StatefulSet extends WorkloadKubeObject {
|
export class StatefulSet extends WorkloadKubeObject {
|
||||||
static kind = "StatefulSet";
|
static kind = "StatefulSet";
|
||||||
static namespaced = true;
|
static namespaced = true;
|
||||||
static apiBase = "/apis/apps/v1/statefulsets";
|
static apiBase = "/apis/apps/v1/statefulsets";
|
||||||
|
|
||||||
spec: {
|
constructor(data: KubeJsonApiData) {
|
||||||
|
super(data);
|
||||||
|
autoBind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
declare spec: {
|
||||||
serviceName: string;
|
serviceName: string;
|
||||||
replicas: number;
|
replicas: number;
|
||||||
selector: {
|
selector: {
|
||||||
@ -107,7 +112,7 @@ export class StatefulSet extends WorkloadKubeObject {
|
|||||||
};
|
};
|
||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
status: {
|
declare status: {
|
||||||
observedGeneration: number;
|
observedGeneration: number;
|
||||||
replicas: number;
|
replicas: number;
|
||||||
currentReplicas: number;
|
currentReplicas: number;
|
||||||
|
|||||||
@ -19,16 +19,12 @@
|
|||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { autobind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
import { KubeObject } from "../kube-object";
|
import { KubeObject } from "../kube-object";
|
||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
|
import type { KubeJsonApiData } from "../kube-json-api";
|
||||||
|
|
||||||
@autobind()
|
export interface StorageClass {
|
||||||
export class StorageClass extends KubeObject {
|
|
||||||
static kind = "StorageClass";
|
|
||||||
static namespaced = false;
|
|
||||||
static apiBase = "/apis/storage.k8s.io/v1/storageclasses";
|
|
||||||
|
|
||||||
provisioner: string; // e.g. "storage.k8s.io/v1"
|
provisioner: string; // e.g. "storage.k8s.io/v1"
|
||||||
mountOptions?: string[];
|
mountOptions?: string[];
|
||||||
volumeBindingMode: string;
|
volumeBindingMode: string;
|
||||||
@ -36,6 +32,17 @@ export class StorageClass extends KubeObject {
|
|||||||
parameters: {
|
parameters: {
|
||||||
[param: string]: string; // every provisioner has own set of these parameters
|
[param: string]: string; // every provisioner has own set of these parameters
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class StorageClass extends KubeObject {
|
||||||
|
static kind = "StorageClass";
|
||||||
|
static namespaced = false;
|
||||||
|
static apiBase = "/apis/storage.k8s.io/v1/storageclasses";
|
||||||
|
|
||||||
|
constructor(data: KubeJsonApiData) {
|
||||||
|
super(data);
|
||||||
|
autoBind(this);
|
||||||
|
}
|
||||||
|
|
||||||
isDefault() {
|
isDefault() {
|
||||||
const annotations = this.metadata.annotations || {};
|
const annotations = this.metadata.annotations || {};
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import type { KubeJsonApiData, KubeJsonApiDataList, KubeJsonApiListMetadata, KubeJsonApiMetadata } from "./kube-json-api";
|
import type { KubeJsonApiData, KubeJsonApiDataList, KubeJsonApiListMetadata, KubeJsonApiMetadata } from "./kube-json-api";
|
||||||
import { autobind, formatDuration } from "../utils";
|
import { autoBind, formatDuration } from "../utils";
|
||||||
import type { ItemObject } from "../item.store";
|
import type { ItemObject } from "../item.store";
|
||||||
import { apiKube } from "./index";
|
import { apiKube } from "./index";
|
||||||
import type { JsonApiParams } from "./json-api";
|
import type { JsonApiParams } from "./json-api";
|
||||||
@ -87,11 +87,16 @@ export class KubeStatus {
|
|||||||
|
|
||||||
export type IKubeMetaField = keyof IKubeObjectMetadata;
|
export type IKubeMetaField = keyof IKubeObjectMetadata;
|
||||||
|
|
||||||
@autobind()
|
export class KubeObject<Metadata extends IKubeObjectMetadata = IKubeObjectMetadata, Status = any, Spec = any> implements ItemObject {
|
||||||
export class KubeObject implements ItemObject {
|
|
||||||
static readonly kind: string;
|
static readonly kind: string;
|
||||||
static readonly namespaced: boolean;
|
static readonly namespaced: boolean;
|
||||||
|
|
||||||
|
apiVersion: string;
|
||||||
|
kind: string;
|
||||||
|
metadata: Metadata;
|
||||||
|
status?: Status;
|
||||||
|
spec?: Spec;
|
||||||
|
|
||||||
static create(data: any) {
|
static create(data: any) {
|
||||||
return new KubeObject(data);
|
return new KubeObject(data);
|
||||||
}
|
}
|
||||||
@ -176,13 +181,9 @@ export class KubeObject implements ItemObject {
|
|||||||
|
|
||||||
constructor(data: KubeJsonApiData) {
|
constructor(data: KubeJsonApiData) {
|
||||||
Object.assign(this, data);
|
Object.assign(this, data);
|
||||||
|
autoBind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
apiVersion: string;
|
|
||||||
kind: string;
|
|
||||||
metadata: IKubeObjectMetadata;
|
|
||||||
status?: any; // todo: type-safety support
|
|
||||||
|
|
||||||
get selfLink() {
|
get selfLink() {
|
||||||
return this.metadata.selfLink;
|
return this.metadata.selfLink;
|
||||||
}
|
}
|
||||||
@ -265,7 +266,7 @@ export class KubeObject implements ItemObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// use unified resource-applier api for updating all k8s objects
|
// use unified resource-applier api for updating all k8s objects
|
||||||
async update<T extends KubeObject>(data: Partial<T>) {
|
async update<T extends KubeObject>(data: Partial<T>): Promise<T> {
|
||||||
return resourceApplierApi.update<T>({
|
return resourceApplierApi.update<T>({
|
||||||
...this.toPlainObject(),
|
...this.toPlainObject(),
|
||||||
...data,
|
...data,
|
||||||
|
|||||||
@ -26,8 +26,8 @@ import type { KubeObjectStore } from "../kube-object.store";
|
|||||||
import type { ClusterContext } from "../components/context";
|
import type { ClusterContext } from "../components/context";
|
||||||
|
|
||||||
import plimit from "p-limit";
|
import plimit from "p-limit";
|
||||||
import { comparer, IReactionDisposer, observable, reaction, when } from "mobx";
|
import { comparer, IReactionDisposer, observable, reaction, makeObservable } from "mobx";
|
||||||
import { autobind, noop } from "../utils";
|
import { autoBind, noop } from "../utils";
|
||||||
import type { KubeApi } from "./kube-api";
|
import type { KubeApi } from "./kube-api";
|
||||||
import type { KubeJsonApiData } from "./kube-json-api";
|
import type { KubeJsonApiData } from "./kube-json-api";
|
||||||
import { isDebugging, isProduction } from "../../common/vars";
|
import { isDebugging, isProduction } from "../../common/vars";
|
||||||
@ -50,11 +50,13 @@ export interface IKubeWatchLog {
|
|||||||
cssStyle?: string;
|
cssStyle?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
|
||||||
export class KubeWatchApi {
|
export class KubeWatchApi {
|
||||||
@observable context: ClusterContext = null;
|
@observable context: ClusterContext = null;
|
||||||
|
|
||||||
contextReady = when(() => Boolean(this.context));
|
constructor() {
|
||||||
|
makeObservable(this);
|
||||||
|
autoBind(this);
|
||||||
|
}
|
||||||
|
|
||||||
isAllowedApi(api: KubeApi): boolean {
|
isAllowedApi(api: KubeApi): boolean {
|
||||||
return Boolean(this.context?.cluster.isAllowedResource(api.kind));
|
return Boolean(this.context?.cluster.isAllowedResource(api.kind));
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { stringify } from "querystring";
|
import { stringify } from "querystring";
|
||||||
import { autobind, base64, EventEmitter } from "../utils";
|
import { boundMethod, base64, EventEmitter } from "../utils";
|
||||||
import { WebSocketApi } from "./websocket-api";
|
import { WebSocketApi } from "./websocket-api";
|
||||||
import isEqual from "lodash/isEqual";
|
import isEqual from "lodash/isEqual";
|
||||||
import { isDevelopment } from "../../common/vars";
|
import { isDevelopment } from "../../common/vars";
|
||||||
@ -106,7 +106,7 @@ export class TerminalApi extends WebSocketApi {
|
|||||||
this.onReady.removeAllListeners();
|
this.onReady.removeAllListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
@boundMethod
|
||||||
protected _onReady(data: string) {
|
protected _onReady(data: string) {
|
||||||
if (!data) return true;
|
if (!data) return true;
|
||||||
this.isReady = true;
|
this.isReady = true;
|
||||||
|
|||||||
@ -19,7 +19,7 @@
|
|||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { observable } from "mobx";
|
import { observable, makeObservable } from "mobx";
|
||||||
import { EventEmitter } from "../../common/event-emitter";
|
import { EventEmitter } from "../../common/event-emitter";
|
||||||
|
|
||||||
interface IParams {
|
interface IParams {
|
||||||
@ -66,6 +66,7 @@ export class WebSocketApi {
|
|||||||
};
|
};
|
||||||
|
|
||||||
constructor(protected params: IParams) {
|
constructor(protected params: IParams) {
|
||||||
|
makeObservable(this);
|
||||||
this.params = Object.assign({}, WebSocketApi.defaultParams, params);
|
this.params = Object.assign({}, WebSocketApi.defaultParams, params);
|
||||||
const { autoConnect, pingIntervalSeconds } = this.params;
|
const { autoConnect, pingIntervalSeconds } = this.params;
|
||||||
|
|
||||||
|
|||||||
@ -68,8 +68,6 @@ export interface IAffinity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class WorkloadKubeObject extends KubeObject {
|
export class WorkloadKubeObject extends KubeObject {
|
||||||
spec: any; // todo: add proper types
|
|
||||||
|
|
||||||
getSelectors(): string[] {
|
getSelectors(): string[] {
|
||||||
const selector = this.spec.selector;
|
const selector = this.spec.selector;
|
||||||
|
|
||||||
|
|||||||
@ -26,13 +26,14 @@ import * as Mobx from "mobx";
|
|||||||
import * as MobxReact from "mobx-react";
|
import * as MobxReact from "mobx-react";
|
||||||
import * as ReactRouter from "react-router";
|
import * as ReactRouter from "react-router";
|
||||||
import * as ReactRouterDom from "react-router-dom";
|
import * as ReactRouterDom from "react-router-dom";
|
||||||
|
import * as LensExtensionsCoreApi from "../extensions/core-api";
|
||||||
|
import * as LensExtensionsRendererApi from "../extensions/renderer-api";
|
||||||
import { render, unmountComponentAtNode } from "react-dom";
|
import { render, unmountComponentAtNode } from "react-dom";
|
||||||
import { delay } from "../common/utils";
|
import { delay } from "../common/utils";
|
||||||
import { isMac, isDevelopment } from "../common/vars";
|
import { isMac, isDevelopment } from "../common/vars";
|
||||||
import { HotbarStore } from "../common/hotbar-store";
|
import { HotbarStore } from "../common/hotbar-store";
|
||||||
import { ClusterStore } from "../common/cluster-store";
|
import { ClusterStore } from "../common/cluster-store";
|
||||||
import { UserStore } from "../common/user-store";
|
import { UserStore } from "../common/user-store";
|
||||||
import * as LensExtensions from "../extensions/extension-api";
|
|
||||||
import { ExtensionDiscovery } from "../extensions/extension-discovery";
|
import { ExtensionDiscovery } from "../extensions/extension-discovery";
|
||||||
import { ExtensionLoader } from "../extensions/extension-loader";
|
import { ExtensionLoader } from "../extensions/extension-loader";
|
||||||
import { ExtensionsStore } from "../extensions/extensions-store";
|
import { ExtensionsStore } from "../extensions/extensions-store";
|
||||||
@ -43,6 +44,9 @@ import { ThemeStore } from "./theme.store";
|
|||||||
import { HelmRepoManager } from "../main/helm/helm-repo-manager";
|
import { HelmRepoManager } from "../main/helm/helm-repo-manager";
|
||||||
import { ExtensionInstallationStateStore } from "./components/+extensions/extension-install.store";
|
import { ExtensionInstallationStateStore } from "./components/+extensions/extension-install.store";
|
||||||
import { DefaultProps } from "./mui-base-theme";
|
import { DefaultProps } from "./mui-base-theme";
|
||||||
|
import configurePackages from "../common/configure-packages";
|
||||||
|
|
||||||
|
configurePackages();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If this is a development buid, wait a second to attach
|
* If this is a development buid, wait a second to attach
|
||||||
@ -59,15 +63,6 @@ type AppComponent = React.ComponentType & {
|
|||||||
init?(): Promise<void>;
|
init?(): Promise<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export {
|
|
||||||
React,
|
|
||||||
ReactRouter,
|
|
||||||
ReactRouterDom,
|
|
||||||
Mobx,
|
|
||||||
MobxReact,
|
|
||||||
LensExtensions
|
|
||||||
};
|
|
||||||
|
|
||||||
export async function bootstrap(App: AppComponent) {
|
export async function bootstrap(App: AppComponent) {
|
||||||
const rootElem = document.getElementById("app");
|
const rootElem = document.getElementById("app");
|
||||||
|
|
||||||
@ -120,3 +115,23 @@ export async function bootstrap(App: AppComponent) {
|
|||||||
|
|
||||||
// run
|
// run
|
||||||
bootstrap(process.isMainFrame ? LensApp : App);
|
bootstrap(process.isMainFrame ? LensApp : App);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exports for virtual package "@k8slens/extensions" for renderer-process.
|
||||||
|
* All exporting names available in global runtime scope:
|
||||||
|
* e.g. Devtools -> Console -> window.LensExtensions (renderer)
|
||||||
|
*/
|
||||||
|
const LensExtensions = {
|
||||||
|
...LensExtensionsCoreApi,
|
||||||
|
...LensExtensionsRendererApi,
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
React,
|
||||||
|
ReactRouter,
|
||||||
|
ReactRouterDom,
|
||||||
|
Mobx,
|
||||||
|
MobxReact,
|
||||||
|
LensExtensions,
|
||||||
|
};
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
import "./add-cluster.scss";
|
import "./add-cluster.scss";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { action, observable, runInAction } from "mobx";
|
import { action, observable, runInAction, makeObservable } from "mobx";
|
||||||
import { KubeConfig } from "@kubernetes/client-node";
|
import { KubeConfig } from "@kubernetes/client-node";
|
||||||
import { AceEditor } from "../ace-editor";
|
import { AceEditor } from "../ace-editor";
|
||||||
import { Button } from "../button";
|
import { Button } from "../button";
|
||||||
@ -50,6 +50,11 @@ export class AddCluster extends React.Component {
|
|||||||
|
|
||||||
kubeContexts = observable.map<string, KubeConfig>();
|
kubeContexts = observable.map<string, KubeConfig>();
|
||||||
|
|
||||||
|
constructor(props: {}) {
|
||||||
|
super(props);
|
||||||
|
makeObservable(this);
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
appEventBus.emit({ name: "cluster-add", action: "start" });
|
appEventBus.emit({ name: "cluster-add", action: "start" });
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user