mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Mobx-6 migration (#2718)
* mobx-6 migration -- part 1
Signed-off-by: Roman <ixrock@gmail.com>
* mobx-6 migration -- part 2 (npx mobx-undecorate --keepDecorators)
Signed-off-by: Roman <ixrock@gmail.com>
* mobx-6 migration -- part 3 (more fixes)
Signed-off-by: Roman <ixrock@gmail.com>
* unwrap possible observables from IPC-messaging
Signed-off-by: Roman <ixrock@gmail.com>
* mobx-6 migration -- remove @autobind as class-decorator
Signed-off-by: Roman <ixrock@gmail.com>
* mobx-6: replacing @autobind() as method-decorator to @boundMethod
Signed-off-by: Roman <ixrock@gmail.com>
* mobx-6: use toJS()-wrapper since monkey-patching require(mobx).toJS doesn't work
Signed-off-by: Roman <ixrock@gmail.com>
* removed `@observable static`
Signed-off-by: Roman <ixrock@gmail.com>
* use {useDefineForClassFields: true} in tsconfig.json
Signed-off-by: Roman <ixrock@gmail.com>
* remove ExtendedObservableMap
Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
* fix: removed makeObservable(this) from "terminal-tab.tsx"
Signed-off-by: Roman <ixrock@gmail.com>
* storage-helper refactoring
Signed-off-by: Roman <ixrock@gmail.com>
* normalize usages of #observable-value.toJSON() / attempt to catch the wind
Signed-off-by: Roman <ixrock@gmail.com>
* refactoring, more possible branch fixes + lint
Signed-off-by: Roman <ixrock@gmail.com>
* debugging cluster-view error -- part 1
Signed-off-by: Roman <ixrock@gmail.com>
* fix: refreshing cluster-view on ready
Signed-off-by: Roman <ixrock@gmail.com>
* fix: various app-crashes related to KubeObject.spec.* access from "undefined"
fix: config-map-details crash
Signed-off-by: Roman <ixrock@gmail.com>
* fix: namespace-store refactoring / saving selected-namespaces to external json-file
Signed-off-by: Roman <ixrock@gmail.com>
* fix: don't cache mobx.when(() => this.someObservable) cause might not work as expected due later call of makeObservable(this) in constructor
Signed-off-by: Roman <ixrock@gmail.com>
* fix: app-crash on editing k8s resource
Signed-off-by: Roman <ixrock@gmail.com>
* fix: restore "all namespaces" on page reload
Signed-off-by: Roman <ixrock@gmail.com>
* - fix: persist table-sort params and cluster-view's sidebar state to lens-local-storage
- new-feature: auto-open main-window's devtools in development-mode (yes/no/ugly?)
Signed-off-by: Roman <ixrock@gmail.com>
* fix: crd definition details -> crashing with <AceEditor mode="json"> (added missing mode-file in ace-editor.tsx)
Signed-off-by: Roman <ixrock@gmail.com>
* fix: crd definitions -> groups selector couldn't deselect last selected option
Signed-off-by: Roman <ixrock@gmail.com>
* refactoring: extensions-api exports clarification for "@k8slens/extensions"
Signed-off-by: Roman <ixrock@gmail.com>
* fix: various app-crashes related to kube-events (events page, some details page, overview, etc.)
Signed-off-by: Roman <ixrock@gmail.com>
* Reverted "use {useDefineForClassFields: true} in tsconfig.json" (various app-crash fixes)
This flag seems to be not possible to use with class-inheritance in some cases.
Example / demo:
`KubeObject` class has initial type definitions for the fields like: "metadata", "kind", etc.
and constructor() has Object.assign(this, data);
Meanwhile child class, e.g. KubeEvent inherited from KubeObject and has it's own extra type definitions for underlying resource, e.g. "involvedObject", "source", etc.
So calling super(data) doesn't work as expected for child class as it's own type definitions overwrites data from parent's constructor with `undefined` at later point.
Signed-off-by: Roman <ixrock@gmail.com>
* master-merge lint-fixes
Signed-off-by: Roman <ixrock@gmail.com>
* catalog.tsx / catalog-entities.store.ts refactoring & fixes
Signed-off-by: Roman <ixrock@gmail.com>
* fix: Catalog -> Browse all tab
Signed-off-by: Roman <ixrock@gmail.com>
* fix: CommandPalette doesn't appear from global menu by click/hotkey
Signed-off-by: Roman <ixrock@gmail.com>
* - Merging interfaces & classses to avoid overwriting fields from parent's super(data)-call with Object.assign(this, data). Otherwise use "declare" keyword at class field definition.
- Revamping {useDefineForClassFields: true} to avoid issues with non-observable class fields in some cases (from previous commit):
```
@observer
export class CommandContainer extends React.Component<CommandContainerProps> {
// without some defined initial value "commandComponent" is non-observable for some reasons
// when tsconfig.ts has {useDefineForClassFields:false}
@observable.ref commandComponent: React.ReactNode = null;
constructor(props: CommandContainerProps) {
super(props);
makeObservable(this);
}
```
Signed-off-by: Roman <ixrock@gmail.com>
* update KubeObject class type definition
Signed-off-by: Roman <ixrock@gmail.com>
* clean up / responding to comments
Signed-off-by: Roman <ixrock@gmail.com>
* fix: app-crash when navigating to catalog from active cluster-view, refactoring `catalog-entity-store`
Signed-off-by: Roman <ixrock@gmail.com>
* catalog-pusher clean up, replaced .observe_() to external observe() helper from "mobx"
Signed-off-by: Roman <ixrock@gmail.com>
* fix: catalog's items stale/non-observable (after connection to the cluster status still "disconnected"), lint-fixes
Signed-off-by: Roman <ixrock@gmail.com>
* fix: Catalog is empty after closing main-window and re-opening app from Tray
Signed-off-by: Roman <ixrock@gmail.com>
* fix: HotBar's icon context menu items non-observable (no "disconnect cluster", etc.)
Signed-off-by: Roman <ixrock@gmail.com>
* lint-fix/license check
Signed-off-by: Roman <ixrock@gmail.com>
* fix: redirect to catalog when disconnecting active cluster
Signed-off-by: Roman <ixrock@gmail.com>
* fix: refresh visibility of active cluster-view on switching from hotbar/catalog
Signed-off-by: Roman <ixrock@gmail.com>
* updated package.json for built-in extensions to use "*" version for packages served from main app
Signed-off-by: Roman <ixrock@gmail.com>
* - added missing makeObservable(this) to metrics-settings.tsx
- updated package-lock.json for built-in extensions
- lint fixes
Signed-off-by: Roman <ixrock@gmail.com>
* master-merge clean up fix, updated package-lock.json for built-in extensions after `make clean-extensions && make build-extensions`
Signed-off-by: Roman <ixrock@gmail.com>
* fix unit-tests
Signed-off-by: Roman <ixrock@gmail.com>
* master-merge fixes
Signed-off-by: Roman <ixrock@gmail.com>
* make lint happy
Signed-off-by: Roman <ixrock@gmail.com>
* reverted some changes, removed auto-opening devtools in dev-mode
Signed-off-by: Roman <ixrock@gmail.com>
* merge fixes
Signed-off-by: Roman <ixrock@gmail.com>
* master-merge conflict fixes:
- proper handling and navigating into catalog's active category via URL-builder
Signed-off-by: Roman <ixrock@gmail.com>
* reverting splitted params for catalog's page route to "/catalog/:group?/:kind?"
Signed-off-by: Roman <ixrock@gmail.com>
* clean-up: remove app's injecting dependencies from `extensions/kube-object-event-status/package.json`
Signed-off-by: Roman <ixrock@gmail.com>
* master-merge fix: added missing makeObservable(this) for extensions.tsx
Signed-off-by: Roman <ixrock@gmail.com>
* fix: catalog entity context menu stale/unobservable
Signed-off-by: Roman <ixrock@gmail.com>
Co-authored-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
parent
0c45dd807e
commit
2c3b510997
@ -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": [
|
||||||
|
|||||||
@ -23,6 +23,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": {}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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": [
|
||||||
|
|||||||
@ -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",
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { EventEmitter } from "events";
|
import { EventEmitter } from "events";
|
||||||
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;
|
||||||
@ -56,6 +56,12 @@ export abstract class CatalogCategory extends EventEmitter {
|
|||||||
};
|
};
|
||||||
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}`;
|
||||||
}
|
}
|
||||||
@ -147,6 +153,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,
|
||||||
|
};
|
||||||
|
|||||||
@ -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,7 +58,16 @@ 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.toJSON();
|
const extensions = this.toJSON();
|
||||||
@ -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,
|
||||||
|
|||||||
@ -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";
|
||||||
@ -45,6 +45,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 +75,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);
|
||||||
|
|||||||
@ -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,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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.
|
||||||
*
|
*
|
||||||
|
|||||||
@ -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,9 +20,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
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> {
|
||||||
@ -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;
|
||||||
|
|||||||
@ -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,10 +20,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
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> {
|
||||||
@ -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" });
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,10 +23,10 @@ import "./helm-chart-details.scss";
|
|||||||
|
|
||||||
import React, { Component } from "react";
|
import React, { Component } from "react";
|
||||||
import { getChartDetails, HelmChart } from "../../api/endpoints/helm-charts.api";
|
import { getChartDetails, HelmChart } from "../../api/endpoints/helm-charts.api";
|
||||||
import { observable, autorun } from "mobx";
|
import { observable, autorun, makeObservable } from "mobx";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { Drawer, DrawerItem } from "../drawer";
|
import { Drawer, DrawerItem } from "../drawer";
|
||||||
import { autobind, stopPropagation } from "../../utils";
|
import { boundMethod, stopPropagation } from "../../utils";
|
||||||
import { MarkdownViewer } from "../markdown-viewer";
|
import { MarkdownViewer } from "../markdown-viewer";
|
||||||
import { Spinner } from "../spinner";
|
import { Spinner } from "../spinner";
|
||||||
import { Button } from "../button";
|
import { Button } from "../button";
|
||||||
@ -48,6 +48,11 @@ export class HelmChartDetails extends Component<Props> {
|
|||||||
|
|
||||||
private abortController?: AbortController;
|
private abortController?: AbortController;
|
||||||
|
|
||||||
|
constructor(props: Props) {
|
||||||
|
super(props);
|
||||||
|
makeObservable(this);
|
||||||
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this.abortController?.abort();
|
this.abortController?.abort();
|
||||||
}
|
}
|
||||||
@ -67,7 +72,7 @@ export class HelmChartDetails extends Component<Props> {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@autobind()
|
@boundMethod
|
||||||
async onVersionChange({ value: version }: SelectOption<string>) {
|
async onVersionChange({ value: version }: SelectOption<string>) {
|
||||||
this.selectedChart = this.chartVersions.find(chart => chart.version === version);
|
this.selectedChart = this.chartVersions.find(chart => chart.version === version);
|
||||||
this.readme = null;
|
this.readme = null;
|
||||||
@ -84,7 +89,7 @@ export class HelmChartDetails extends Component<Props> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
@boundMethod
|
||||||
install() {
|
install() {
|
||||||
createInstallChartTab(this.selectedChart);
|
createInstallChartTab(this.selectedChart);
|
||||||
this.props.hideDetails();
|
this.props.hideDetails();
|
||||||
|
|||||||
@ -20,8 +20,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import semver from "semver";
|
import semver from "semver";
|
||||||
import { observable } from "mobx";
|
import { observable, makeObservable } from "mobx";
|
||||||
import { autobind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
import { getChartDetails, HelmChart, listCharts } from "../../api/endpoints/helm-charts.api";
|
import { getChartDetails, HelmChart, listCharts } from "../../api/endpoints/helm-charts.api";
|
||||||
import { ItemStore } from "../../item.store";
|
import { ItemStore } from "../../item.store";
|
||||||
import flatten from "lodash/flatten";
|
import flatten from "lodash/flatten";
|
||||||
@ -31,10 +31,16 @@ export interface IChartVersion {
|
|||||||
version: string;
|
version: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
|
||||||
export class HelmChartStore extends ItemStore<HelmChart> {
|
export class HelmChartStore extends ItemStore<HelmChart> {
|
||||||
@observable versions = observable.map<string, IChartVersion[]>();
|
@observable versions = observable.map<string, IChartVersion[]>();
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
makeObservable(this);
|
||||||
|
autoBind(this);
|
||||||
|
}
|
||||||
|
|
||||||
async loadAll() {
|
async loadAll() {
|
||||||
try {
|
try {
|
||||||
const res = await this.loadItems(() => listCharts());
|
const res = await this.loadItems(() => listCharts());
|
||||||
|
|||||||
@ -57,10 +57,10 @@ export class HelmCharts extends Component<Props> {
|
|||||||
|
|
||||||
showDetails = (chart: HelmChart) => {
|
showDetails = (chart: HelmChart) => {
|
||||||
if (!chart) {
|
if (!chart) {
|
||||||
navigation.merge(helmChartsURL());
|
navigation.push(helmChartsURL());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
navigation.merge(helmChartsURL({
|
navigation.push(helmChartsURL({
|
||||||
params: {
|
params: {
|
||||||
chartName: chart.getName(),
|
chartName: chart.getName(),
|
||||||
repo: chart.getRepository(),
|
repo: chart.getRepository(),
|
||||||
|
|||||||
@ -24,7 +24,7 @@ import "./release-details.scss";
|
|||||||
import React, { Component } from "react";
|
import React, { Component } from "react";
|
||||||
import groupBy from "lodash/groupBy";
|
import groupBy from "lodash/groupBy";
|
||||||
import isEqual from "lodash/isEqual";
|
import isEqual from "lodash/isEqual";
|
||||||
import { observable, reaction } from "mobx";
|
import { observable, reaction, makeObservable } from "mobx";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import kebabCase from "lodash/kebabCase";
|
import kebabCase from "lodash/kebabCase";
|
||||||
import { getRelease, getReleaseValues, HelmRelease, IReleaseDetails } from "../../api/endpoints/helm-releases.api";
|
import { getRelease, getReleaseValues, HelmRelease, IReleaseDetails } from "../../api/endpoints/helm-releases.api";
|
||||||
@ -72,7 +72,7 @@ export class ReleaseDetails extends Component<Props> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
@disposeOnUnmount
|
@disposeOnUnmount
|
||||||
secretWatcher = reaction(() => secretsStore.items.toJS(), () => {
|
secretWatcher = reaction(() => secretsStore.getItems(), () => {
|
||||||
if (!this.props.release) return;
|
if (!this.props.release) return;
|
||||||
const { getReleaseSecret } = releaseStore;
|
const { getReleaseSecret } = releaseStore;
|
||||||
const { release } = this.props;
|
const { release } = this.props;
|
||||||
@ -85,6 +85,11 @@ export class ReleaseDetails extends Component<Props> {
|
|||||||
this.releaseSecret = secret;
|
this.releaseSecret = secret;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
constructor(props: Props) {
|
||||||
|
super(props);
|
||||||
|
makeObservable(this);
|
||||||
|
}
|
||||||
|
|
||||||
async loadDetails() {
|
async loadDetails() {
|
||||||
const { release } = this.props;
|
const { release } = this.props;
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import type { HelmRelease } from "../../api/endpoints/helm-releases.api";
|
import type { HelmRelease } from "../../api/endpoints/helm-releases.api";
|
||||||
import { autobind, cssNames } from "../../utils";
|
import { boundMethod, cssNames } from "../../utils";
|
||||||
import { releaseStore } from "./release.store";
|
import { releaseStore } from "./release.store";
|
||||||
import { MenuActions, MenuActionsProps } from "../menu/menu-actions";
|
import { MenuActions, MenuActionsProps } from "../menu/menu-actions";
|
||||||
import { MenuItem } from "../menu";
|
import { MenuItem } from "../menu";
|
||||||
@ -35,12 +35,12 @@ interface Props extends MenuActionsProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class HelmReleaseMenu extends React.Component<Props> {
|
export class HelmReleaseMenu extends React.Component<Props> {
|
||||||
@autobind()
|
@boundMethod
|
||||||
remove() {
|
remove() {
|
||||||
return releaseStore.remove(this.props.release);
|
return releaseStore.remove(this.props.release);
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
@boundMethod
|
||||||
upgrade() {
|
upgrade() {
|
||||||
const { release, hideDetails } = this.props;
|
const { release, hideDetails } = this.props;
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ export class HelmReleaseMenu extends React.Component<Props> {
|
|||||||
hideDetails && hideDetails();
|
hideDetails && hideDetails();
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
@boundMethod
|
||||||
rollback() {
|
rollback() {
|
||||||
ReleaseRollbackDialog.open(this.props.release);
|
ReleaseRollbackDialog.open(this.props.release);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
import "./release-rollback-dialog.scss";
|
import "./release-rollback-dialog.scss";
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { observable } from "mobx";
|
import { observable, makeObservable } from "mobx";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { Dialog, DialogProps } from "../dialog";
|
import { Dialog, DialogProps } from "../dialog";
|
||||||
import { Wizard, WizardStep } from "../wizard";
|
import { Wizard, WizardStep } from "../wizard";
|
||||||
@ -35,26 +35,33 @@ import orderBy from "lodash/orderBy";
|
|||||||
interface Props extends DialogProps {
|
interface Props extends DialogProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const dialogState = observable.object({
|
||||||
|
isOpen: false,
|
||||||
|
release: null as HelmRelease,
|
||||||
|
});
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class ReleaseRollbackDialog extends React.Component<Props> {
|
export class ReleaseRollbackDialog extends React.Component<Props> {
|
||||||
@observable static isOpen = false;
|
|
||||||
@observable.ref static release: HelmRelease = null;
|
|
||||||
|
|
||||||
@observable isLoading = false;
|
@observable isLoading = false;
|
||||||
@observable revision: IReleaseRevision;
|
@observable revision: IReleaseRevision;
|
||||||
@observable revisions = observable.array<IReleaseRevision>();
|
@observable revisions = observable.array<IReleaseRevision>();
|
||||||
|
|
||||||
|
constructor(props: Props) {
|
||||||
|
super(props);
|
||||||
|
makeObservable(this);
|
||||||
|
}
|
||||||
|
|
||||||
static open(release: HelmRelease) {
|
static open(release: HelmRelease) {
|
||||||
ReleaseRollbackDialog.isOpen = true;
|
dialogState.isOpen = true;
|
||||||
ReleaseRollbackDialog.release = release;
|
dialogState.release = release;
|
||||||
}
|
}
|
||||||
|
|
||||||
static close() {
|
static close() {
|
||||||
ReleaseRollbackDialog.isOpen = false;
|
dialogState.isOpen = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
get release(): HelmRelease {
|
get release(): HelmRelease {
|
||||||
return ReleaseRollbackDialog.release;
|
return dialogState.release;
|
||||||
}
|
}
|
||||||
|
|
||||||
onOpen = async () => {
|
onOpen = async () => {
|
||||||
@ -115,7 +122,7 @@ export class ReleaseRollbackDialog extends React.Component<Props> {
|
|||||||
<Dialog
|
<Dialog
|
||||||
{...dialogProps}
|
{...dialogProps}
|
||||||
className="ReleaseRollbackDialog"
|
className="ReleaseRollbackDialog"
|
||||||
isOpen={ReleaseRollbackDialog.isOpen}
|
isOpen={dialogState.isOpen}
|
||||||
onOpen={this.onOpen}
|
onOpen={this.onOpen}
|
||||||
close={this.close}
|
close={this.close}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -20,8 +20,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import isEqual from "lodash/isEqual";
|
import isEqual from "lodash/isEqual";
|
||||||
import { action, observable, reaction, when } from "mobx";
|
import { action, observable, reaction, when, makeObservable } from "mobx";
|
||||||
import { autobind } from "../../utils";
|
import { autoBind } from "../../utils";
|
||||||
import { createRelease, deleteRelease, HelmRelease, IReleaseCreatePayload, IReleaseUpdatePayload, listReleases, rollbackRelease, updateRelease } from "../../api/endpoints/helm-releases.api";
|
import { createRelease, deleteRelease, HelmRelease, IReleaseCreatePayload, IReleaseUpdatePayload, listReleases, rollbackRelease, updateRelease } from "../../api/endpoints/helm-releases.api";
|
||||||
import { ItemStore } from "../../item.store";
|
import { ItemStore } from "../../item.store";
|
||||||
import type { Secret } from "../../api/endpoints";
|
import type { Secret } from "../../api/endpoints";
|
||||||
@ -29,19 +29,21 @@ import { secretsStore } from "../+config-secrets/secrets.store";
|
|||||||
import { namespaceStore } from "../+namespaces/namespace.store";
|
import { namespaceStore } from "../+namespaces/namespace.store";
|
||||||
import { Notifications } from "../notifications";
|
import { Notifications } from "../notifications";
|
||||||
|
|
||||||
@autobind()
|
|
||||||
export class ReleaseStore extends ItemStore<HelmRelease> {
|
export class ReleaseStore extends ItemStore<HelmRelease> {
|
||||||
releaseSecrets = observable.map<string, Secret>();
|
releaseSecrets = observable.map<string, Secret>();
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
makeObservable(this);
|
||||||
|
autoBind(this);
|
||||||
|
|
||||||
when(() => secretsStore.isLoaded, () => {
|
when(() => secretsStore.isLoaded, () => {
|
||||||
this.releaseSecrets.replace(this.getReleaseSecrets());
|
this.releaseSecrets.replace(this.getReleaseSecrets());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
watchAssociatedSecrets(): (() => void) {
|
watchAssociatedSecrets(): (() => void) {
|
||||||
return reaction(() => secretsStore.items.toJS(), () => {
|
return reaction(() => secretsStore.getItems(), () => {
|
||||||
if (this.isLoading) return;
|
if (this.isLoading) return;
|
||||||
const newSecrets = this.getReleaseSecrets();
|
const newSecrets = this.getReleaseSecrets();
|
||||||
const amountChanged = newSecrets.length !== this.releaseSecrets.size;
|
const amountChanged = newSecrets.length !== this.releaseSecrets.size;
|
||||||
|
|||||||
@ -67,7 +67,7 @@ export class HelmReleases extends Component<Props> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
showDetails = (item: HelmRelease) => {
|
showDetails = (item: HelmRelease) => {
|
||||||
navigation.merge(releaseURL({
|
navigation.push(releaseURL({
|
||||||
params: {
|
params: {
|
||||||
name: item.getName(),
|
name: item.getName(),
|
||||||
namespace: item.getNs()
|
namespace: item.getNs()
|
||||||
@ -76,7 +76,7 @@ export class HelmReleases extends Component<Props> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
hideDetails = () => {
|
hideDetails = () => {
|
||||||
navigation.merge(releaseURL());
|
navigation.push(releaseURL());
|
||||||
};
|
};
|
||||||
|
|
||||||
renderRemoveDialogMessage(selectedItems: HelmRelease[]) {
|
renderRemoveDialogMessage(selectedItems: HelmRelease[]) {
|
||||||
|
|||||||
@ -24,12 +24,10 @@ import { observer } from "mobx-react";
|
|||||||
import { TabLayout, TabLayoutRoute } from "../layout/tab-layout";
|
import { TabLayout, TabLayoutRoute } from "../layout/tab-layout";
|
||||||
import { HelmCharts, helmChartsRoute, helmChartsURL } from "../+apps-helm-charts";
|
import { HelmCharts, helmChartsRoute, helmChartsURL } from "../+apps-helm-charts";
|
||||||
import { HelmReleases, releaseRoute, releaseURL } from "../+apps-releases";
|
import { HelmReleases, releaseRoute, releaseURL } from "../+apps-releases";
|
||||||
import { namespaceUrlParam } from "../+namespaces/namespace.store";
|
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class Apps extends React.Component {
|
export class Apps extends React.Component {
|
||||||
static get tabRoutes(): TabLayoutRoute[] {
|
static get tabRoutes(): TabLayoutRoute[] {
|
||||||
const query = namespaceUrlParam.toObjectParam();
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@ -41,7 +39,7 @@ export class Apps extends React.Component {
|
|||||||
{
|
{
|
||||||
title: "Releases",
|
title: "Releases",
|
||||||
component: HelmReleases,
|
component: HelmReleases,
|
||||||
url: releaseURL({ query }),
|
url: releaseURL(),
|
||||||
routePath: releaseRoute.path.toString(),
|
routePath: releaseRoute.path.toString(),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@ -24,8 +24,8 @@ import React from "react";
|
|||||||
import { SpeedDial, SpeedDialAction } from "@material-ui/lab";
|
import { SpeedDial, SpeedDialAction } from "@material-ui/lab";
|
||||||
import { Icon } from "../icon";
|
import { Icon } from "../icon";
|
||||||
import { disposeOnUnmount, observer } from "mobx-react";
|
import { disposeOnUnmount, observer } from "mobx-react";
|
||||||
import { observable, reaction } from "mobx";
|
import { observable, reaction, makeObservable } from "mobx";
|
||||||
import { autobind } from "../../../common/utils";
|
import { boundMethod } from "../../../common/utils";
|
||||||
import type { CatalogCategory, CatalogEntityAddMenuContext, CatalogEntityAddMenu } from "../../api/catalog-entity";
|
import type { CatalogCategory, CatalogEntityAddMenuContext, CatalogEntityAddMenu } from "../../api/catalog-entity";
|
||||||
import { EventEmitter } from "events";
|
import { EventEmitter } from "events";
|
||||||
import { navigate } from "../../navigation";
|
import { navigate } from "../../navigation";
|
||||||
@ -39,6 +39,11 @@ export class CatalogAddButton extends React.Component<CatalogAddButtonProps> {
|
|||||||
@observable protected isOpen = false;
|
@observable protected isOpen = false;
|
||||||
protected menuItems = observable.array<CatalogEntityAddMenu>([]);
|
protected menuItems = observable.array<CatalogEntityAddMenu>([]);
|
||||||
|
|
||||||
|
constructor(props: CatalogAddButtonProps) {
|
||||||
|
super(props);
|
||||||
|
makeObservable(this);
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
disposeOnUnmount(this, [
|
disposeOnUnmount(this, [
|
||||||
reaction(() => this.props.category, (category) => {
|
reaction(() => this.props.category, (category) => {
|
||||||
@ -56,17 +61,17 @@ export class CatalogAddButton extends React.Component<CatalogAddButtonProps> {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
@boundMethod
|
||||||
onOpen() {
|
onOpen() {
|
||||||
this.isOpen = true;
|
this.isOpen = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
@boundMethod
|
||||||
onClose() {
|
onClose() {
|
||||||
this.isOpen = false;
|
this.isOpen = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
@boundMethod
|
||||||
onButtonClick() {
|
onButtonClick() {
|
||||||
if (this.menuItems.length == 1) {
|
if (this.menuItems.length == 1) {
|
||||||
this.menuItems[0].onClick();
|
this.menuItems[0].onClick();
|
||||||
|
|||||||
@ -19,12 +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, computed, IReactionDisposer, observable, reaction } from "mobx";
|
import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from "mobx";
|
||||||
import { catalogEntityRegistry } from "../../api/catalog-entity-registry";
|
import { catalogEntityRegistry } from "../../api/catalog-entity-registry";
|
||||||
import type { CatalogEntity, CatalogEntityActionContext } from "../../api/catalog-entity";
|
import type { CatalogEntity, CatalogEntityActionContext } from "../../api/catalog-entity";
|
||||||
import { ItemObject, ItemStore } from "../../item.store";
|
import { ItemObject, ItemStore } from "../../item.store";
|
||||||
import { autobind } from "../../utils";
|
|
||||||
import { CatalogCategory } from "../../../common/catalog";
|
import { CatalogCategory } from "../../../common/catalog";
|
||||||
|
import { autoBind } from "../../../common/utils";
|
||||||
|
|
||||||
export class CatalogEntityItem implements ItemObject {
|
export class CatalogEntityItem implements ItemObject {
|
||||||
constructor(public entity: CatalogEntity) {}
|
constructor(public entity: CatalogEntity) {}
|
||||||
@ -84,8 +84,13 @@ export class CatalogEntityItem implements ItemObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
|
||||||
export class CatalogEntityStore extends ItemStore<CatalogEntityItem> {
|
export class CatalogEntityStore extends ItemStore<CatalogEntityItem> {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
makeObservable(this);
|
||||||
|
autoBind(this);
|
||||||
|
}
|
||||||
|
|
||||||
@observable activeCategory?: CatalogCategory;
|
@observable activeCategory?: CatalogCategory;
|
||||||
|
|
||||||
@computed get entities() {
|
@computed get entities() {
|
||||||
|
|||||||
@ -23,7 +23,7 @@ import "./catalog.scss";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { disposeOnUnmount, observer } from "mobx-react";
|
import { disposeOnUnmount, observer } from "mobx-react";
|
||||||
import { ItemListLayout } from "../item-object-list";
|
import { ItemListLayout } from "../item-object-list";
|
||||||
import { action, observable, reaction, when } from "mobx";
|
import { action, makeObservable, observable, reaction, when } from "mobx";
|
||||||
import { CatalogEntityItem, CatalogEntityStore } from "./catalog-entity.store";
|
import { CatalogEntityItem, CatalogEntityStore } from "./catalog-entity.store";
|
||||||
import { navigate } from "../../navigation";
|
import { navigate } from "../../navigation";
|
||||||
import { kebabCase } from "lodash";
|
import { kebabCase } from "lodash";
|
||||||
@ -32,7 +32,6 @@ import { MenuItem, MenuActions } from "../menu";
|
|||||||
import { CatalogEntityContextMenu, CatalogEntityContextMenuContext, catalogEntityRunContext } from "../../api/catalog-entity";
|
import { CatalogEntityContextMenu, CatalogEntityContextMenuContext, catalogEntityRunContext } from "../../api/catalog-entity";
|
||||||
import { Badge } from "../badge";
|
import { Badge } from "../badge";
|
||||||
import { HotbarStore } from "../../../common/hotbar-store";
|
import { HotbarStore } from "../../../common/hotbar-store";
|
||||||
import { autobind } from "../../utils";
|
|
||||||
import { ConfirmDialog } from "../confirm-dialog";
|
import { ConfirmDialog } from "../confirm-dialog";
|
||||||
import { Tab, Tabs } from "../tabs";
|
import { Tab, Tabs } from "../tabs";
|
||||||
import { catalogCategoryRegistry } from "../../../common/catalog";
|
import { catalogCategoryRegistry } from "../../../common/catalog";
|
||||||
@ -49,12 +48,18 @@ enum sortBy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Props extends RouteComponentProps<ICatalogViewRouteParam> {}
|
interface Props extends RouteComponentProps<ICatalogViewRouteParam> {}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class Catalog extends React.Component<Props> {
|
export class Catalog extends React.Component<Props> {
|
||||||
@observable private catalogEntityStore?: CatalogEntityStore;
|
@observable private catalogEntityStore?: CatalogEntityStore;
|
||||||
@observable.deep private contextMenu: CatalogEntityContextMenuContext;
|
@observable private contextMenu: CatalogEntityContextMenuContext;
|
||||||
@observable activeTab?: string;
|
@observable activeTab?: string;
|
||||||
|
|
||||||
|
constructor(props: Props) {
|
||||||
|
super(props);
|
||||||
|
makeObservable(this);
|
||||||
|
}
|
||||||
|
|
||||||
get routeActiveTab(): string | undefined {
|
get routeActiveTab(): string | undefined {
|
||||||
const { group, kind } = this.props.match.params ?? {};
|
const { group, kind } = this.props.match.params ?? {};
|
||||||
|
|
||||||
@ -155,8 +160,7 @@ export class Catalog extends React.Component<Props> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
renderItemMenu = (item: CatalogEntityItem) => {
|
||||||
renderItemMenu(item: CatalogEntityItem) {
|
|
||||||
const menuItems = this.contextMenu.menuItems.filter((menuItem) => !menuItem.onlyVisibleForSource || menuItem.onlyVisibleForSource === item.entity.metadata.source);
|
const menuItems = this.contextMenu.menuItems.filter((menuItem) => !menuItem.onlyVisibleForSource || menuItem.onlyVisibleForSource === item.entity.metadata.source);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -173,7 +177,7 @@ export class Catalog extends React.Component<Props> {
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
</MenuActions>
|
</MenuActions>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
renderIcon(item: CatalogEntityItem) {
|
renderIcon(item: CatalogEntityItem) {
|
||||||
const category = catalogCategoryRegistry.getCategoryForEntity(item.entity);
|
const category = catalogCategoryRegistry.getCategoryForEntity(item.entity);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user