mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Merge branch 'master' into typesafe-catalog-category-events
This commit is contained in:
commit
048394222b
@ -50,6 +50,7 @@ module.exports = {
|
|||||||
plugins: [
|
plugins: [
|
||||||
"header",
|
"header",
|
||||||
"unused-imports",
|
"unused-imports",
|
||||||
|
"react-hooks"
|
||||||
],
|
],
|
||||||
rules: {
|
rules: {
|
||||||
"header/header": [2, "./license-header"],
|
"header/header": [2, "./license-header"],
|
||||||
@ -210,7 +211,9 @@ module.exports = {
|
|||||||
{ "blankLine": "always", "prev": "*", "next": "class" },
|
{ "blankLine": "always", "prev": "*", "next": "class" },
|
||||||
{ "blankLine": "always", "prev": ["const", "let", "var"], "next": "*" },
|
{ "blankLine": "always", "prev": ["const", "let", "var"], "next": "*" },
|
||||||
{ "blankLine": "any", "prev": ["const", "let", "var"], "next": ["const", "let", "var"]},
|
{ "blankLine": "any", "prev": ["const", "let", "var"], "next": ["const", "let", "var"]},
|
||||||
]
|
],
|
||||||
|
"react-hooks/rules-of-hooks": "error",
|
||||||
|
"react-hooks/exhaustive-deps": "off"
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -18,7 +18,7 @@
|
|||||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
* 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.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
module.exports = {
|
export default {
|
||||||
Trans: ({ children }: { children: React.ReactNode }) => children,
|
Trans: ({ children }: { children: React.ReactNode }) => children,
|
||||||
t: (message: string) => message
|
t: (message: string) => message
|
||||||
};
|
};
|
||||||
|
|||||||
@ -18,7 +18,7 @@
|
|||||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
* 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.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
module.exports = {
|
export default {
|
||||||
require: jest.fn(),
|
require: jest.fn(),
|
||||||
match: jest.fn(),
|
match: jest.fn(),
|
||||||
app: {
|
app: {
|
||||||
|
|||||||
@ -18,4 +18,5 @@
|
|||||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
* 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.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
module.exports = {};
|
|
||||||
|
export default {};
|
||||||
|
|||||||
@ -18,4 +18,4 @@
|
|||||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
* 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.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
module.exports = {};
|
export default {};
|
||||||
|
|||||||
@ -25,7 +25,7 @@
|
|||||||
TEST_NAMESPACE namespace. This is done to minimize destructive impact of the cluster tests on an existing minikube
|
TEST_NAMESPACE namespace. This is done to minimize destructive impact of the cluster tests on an existing minikube
|
||||||
cluster and vice versa.
|
cluster and vice versa.
|
||||||
*/
|
*/
|
||||||
import { Application } from "spectron";
|
import type { Application } from "spectron";
|
||||||
import * as utils from "../helpers/utils";
|
import * as utils from "../helpers/utils";
|
||||||
import { listHelmRepositories } from "../helpers/utils";
|
import { listHelmRepositories } from "../helpers/utils";
|
||||||
import { fail } from "assert";
|
import { fail } from "assert";
|
||||||
|
|||||||
@ -18,7 +18,14 @@
|
|||||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
* 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.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
import { Application } from "spectron";
|
|
||||||
|
/*
|
||||||
|
Cluster tests are run if there is a pre-existing minikube cluster. Before running cluster tests the TEST_NAMESPACE
|
||||||
|
namespace is removed, if it exists, from the minikube cluster. Resources are created as part of the cluster tests in the
|
||||||
|
TEST_NAMESPACE namespace. This is done to minimize destructive impact of the cluster tests on an existing minikube
|
||||||
|
cluster and vice versa.
|
||||||
|
*/
|
||||||
|
import type { Application } from "spectron";
|
||||||
import * as utils from "../helpers/utils";
|
import * as utils from "../helpers/utils";
|
||||||
import { minikubeReady, waitForMinikubeDashboard } from "../helpers/minikube";
|
import { minikubeReady, waitForMinikubeDashboard } from "../helpers/minikube";
|
||||||
import { exec } from "child_process";
|
import { exec } from "child_process";
|
||||||
|
|||||||
@ -18,7 +18,8 @@
|
|||||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
* 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.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
import { Application } from "spectron";
|
|
||||||
|
import type { Application } from "spectron";
|
||||||
import * as utils from "../helpers/utils";
|
import * as utils from "../helpers/utils";
|
||||||
|
|
||||||
jest.setTimeout(60000);
|
jest.setTimeout(60000);
|
||||||
|
|||||||
@ -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 { spawnSync } from "child_process";
|
import { spawnSync } from "child_process";
|
||||||
import { Application } from "spectron";
|
import type { Application } from "spectron";
|
||||||
|
|
||||||
export function minikubeReady(testNamespace: string): boolean {
|
export function minikubeReady(testNamespace: string): boolean {
|
||||||
// determine if minikube is running
|
// determine if minikube is running
|
||||||
|
|||||||
@ -62,11 +62,11 @@ theme:
|
|||||||
- scheme: slate
|
- scheme: slate
|
||||||
toggle:
|
toggle:
|
||||||
icon: material/toggle-switch-off-outline
|
icon: material/toggle-switch-off-outline
|
||||||
name: Switch to light mode
|
name: Switch to dark mode
|
||||||
- scheme: default
|
- scheme: default
|
||||||
toggle:
|
toggle:
|
||||||
icon: material/toggle-switch
|
icon: material/toggle-switch
|
||||||
name: Switch to dark mode
|
name: Switch to light mode
|
||||||
features:
|
features:
|
||||||
- toc.autohide
|
- toc.autohide
|
||||||
- search.suggest
|
- search.suggest
|
||||||
|
|||||||
@ -316,6 +316,7 @@
|
|||||||
"eslint": "^7.7.0",
|
"eslint": "^7.7.0",
|
||||||
"eslint-plugin-header": "^3.1.1",
|
"eslint-plugin-header": "^3.1.1",
|
||||||
"eslint-plugin-react": "^7.21.5",
|
"eslint-plugin-react": "^7.21.5",
|
||||||
|
"eslint-plugin-react-hooks": "^4.2.0",
|
||||||
"eslint-plugin-unused-imports": "^1.0.1",
|
"eslint-plugin-unused-imports": "^1.0.1",
|
||||||
"file-loader": "^6.0.0",
|
"file-loader": "^6.0.0",
|
||||||
"flex.box": "^3.4.4",
|
"flex.box": "^3.4.4",
|
||||||
|
|||||||
@ -23,6 +23,12 @@ import { SearchStore } from "../search-store";
|
|||||||
import { Console } from "console";
|
import { Console } from "console";
|
||||||
import { stdout, stderr } from "process";
|
import { stdout, stderr } from "process";
|
||||||
|
|
||||||
|
jest.mock("electron", () => ({
|
||||||
|
app: {
|
||||||
|
getPath: () => "/foo",
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
console = new Console(stdout, stderr);
|
console = new Console(stdout, stderr);
|
||||||
|
|
||||||
let searchStore: SearchStore = null;
|
let searchStore: SearchStore = null;
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import Config from "conf";
|
import Config from "conf";
|
||||||
import { 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, observable, reaction, runInAction, when } from "mobx";
|
||||||
import Singleton from "./utils/singleton";
|
import Singleton from "./utils/singleton";
|
||||||
|
|||||||
@ -19,26 +19,36 @@
|
|||||||
* 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, toJS } from "mobx";
|
import { action, computed, observable } from "mobx";
|
||||||
|
import { Disposer, ExtendedMap } from "../utils";
|
||||||
import { CatalogCategory, CatalogEntityData, CatalogEntityKindData } from "./catalog-entity";
|
import { CatalogCategory, CatalogEntityData, CatalogEntityKindData } from "./catalog-entity";
|
||||||
|
|
||||||
export class CatalogCategoryRegistry {
|
export class CatalogCategoryRegistry {
|
||||||
@observable protected categories: CatalogCategory[] = [];
|
protected categories = observable.set<CatalogCategory>();
|
||||||
|
protected groupKinds = new ExtendedMap<string, ExtendedMap<string, CatalogCategory>>();
|
||||||
|
|
||||||
@action add(category: CatalogCategory) {
|
@action add(category: CatalogCategory): Disposer {
|
||||||
this.categories.push(category);
|
this.categories.add(category);
|
||||||
|
this.updateGroupKinds(category);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
this.categories.delete(category);
|
||||||
|
this.groupKinds.clear();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@action remove(category: CatalogCategory) {
|
private updateGroupKinds(category: CatalogCategory) {
|
||||||
this.categories = this.categories.filter((cat) => cat.apiVersion !== category.apiVersion && cat.kind !== category.kind);
|
this.groupKinds
|
||||||
|
.getOrInsert(category.spec.group, ExtendedMap.new)
|
||||||
|
.strictSet(category.spec.names.kind, category);
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed get items() {
|
@computed get items() {
|
||||||
return toJS(this.categories);
|
return Array.from(this.categories);
|
||||||
}
|
}
|
||||||
|
|
||||||
getForGroupKind<T extends CatalogCategory>(group: string, kind: string) {
|
getForGroupKind<T extends CatalogCategory>(group: string, kind: string): T | undefined {
|
||||||
return this.categories.find((c) => c.spec.group === group && c.spec.names.kind === kind) as T;
|
return this.groupKinds.get(group)?.get(kind) as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
getEntityForData(data: CatalogEntityData & CatalogEntityKindData) {
|
getEntityForData(data: CatalogEntityData & CatalogEntityKindData) {
|
||||||
@ -60,17 +70,11 @@ export class CatalogCategoryRegistry {
|
|||||||
return new specVersion.entityClass(data);
|
return new specVersion.entityClass(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
getCategoryForEntity<T extends CatalogCategory>(data: CatalogEntityData & CatalogEntityKindData) {
|
getCategoryForEntity<T extends CatalogCategory>(data: CatalogEntityData & CatalogEntityKindData): T | undefined {
|
||||||
const splitApiVersion = data.apiVersion.split("/");
|
const splitApiVersion = data.apiVersion.split("/");
|
||||||
const group = splitApiVersion[0];
|
const group = splitApiVersion[0];
|
||||||
|
|
||||||
const category = this.categories.find((category) => {
|
return this.getForGroupKind(group, data.kind);
|
||||||
return category.spec.group === group && category.spec.names.kind === data.kind;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!category) return null;
|
|
||||||
|
|
||||||
return category as T;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,4 +21,3 @@
|
|||||||
|
|
||||||
export * from "./catalog-category-registry";
|
export * from "./catalog-category-registry";
|
||||||
export * from "./catalog-entity";
|
export * from "./catalog-entity";
|
||||||
export * from "./catalog-entity-registry";
|
|
||||||
|
|||||||
@ -35,11 +35,9 @@ export const clusterKubectlDeleteAllHandler = "cluster:kubectl-delete-all";
|
|||||||
|
|
||||||
if (ipcMain) {
|
if (ipcMain) {
|
||||||
handleRequest(clusterActivateHandler, (event, clusterId: ClusterId, force = false) => {
|
handleRequest(clusterActivateHandler, (event, clusterId: ClusterId, force = false) => {
|
||||||
const cluster = ClusterStore.getInstance().getById(clusterId);
|
return ClusterStore.getInstance()
|
||||||
|
.getById(clusterId)
|
||||||
if (cluster) {
|
?.activate(force);
|
||||||
return cluster.activate(force);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
handleRequest(clusterSetFrameIdHandler, (event: IpcMainInvokeEvent, clusterId: ClusterId) => {
|
handleRequest(clusterSetFrameIdHandler, (event: IpcMainInvokeEvent, clusterId: ClusterId) => {
|
||||||
@ -47,15 +45,14 @@ if (ipcMain) {
|
|||||||
|
|
||||||
if (cluster) {
|
if (cluster) {
|
||||||
clusterFrameMap.set(cluster.id, { frameId: event.frameId, processId: event.processId });
|
clusterFrameMap.set(cluster.id, { frameId: event.frameId, processId: event.processId });
|
||||||
|
cluster.pushState();
|
||||||
return cluster.pushState();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
handleRequest(clusterRefreshHandler, (event, clusterId: ClusterId) => {
|
handleRequest(clusterRefreshHandler, (event, clusterId: ClusterId) => {
|
||||||
const cluster = ClusterStore.getInstance().getById(clusterId);
|
return ClusterStore.getInstance()
|
||||||
|
.getById(clusterId)
|
||||||
if (cluster) return cluster.refresh({ refreshMetadata: true });
|
?.refresh({ refreshMetadata: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
handleRequest(clusterDisconnectHandler, (event, clusterId: ClusterId) => {
|
handleRequest(clusterDisconnectHandler, (event, clusterId: ClusterId) => {
|
||||||
|
|||||||
@ -30,9 +30,9 @@ import logger from "../main/logger";
|
|||||||
import { appEventBus } from "./event-bus";
|
import { appEventBus } from "./event-bus";
|
||||||
import { dumpConfigYaml } from "./kube-helpers";
|
import { dumpConfigYaml } from "./kube-helpers";
|
||||||
import { saveToAppFiles } from "./utils/saveToAppFiles";
|
import { saveToAppFiles } from "./utils/saveToAppFiles";
|
||||||
import { 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 { 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 } from "./utils";
|
||||||
|
|
||||||
export interface ClusterIconUpload {
|
export interface ClusterIconUpload {
|
||||||
|
|||||||
@ -53,12 +53,11 @@ export class EventEmitter<D extends [...any[]]> {
|
|||||||
|
|
||||||
emit(...data: D) {
|
emit(...data: D) {
|
||||||
[...this.listeners].every(([callback, options]) => {
|
[...this.listeners].every(([callback, options]) => {
|
||||||
if (options.once) this.removeListener(callback);
|
if (options.once) {
|
||||||
const result = callback(...data);
|
this.removeListener(callback);
|
||||||
|
}
|
||||||
|
|
||||||
if (result === false) return; // break cycle
|
return callback(...data) !== false;
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,10 +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 type { EventEmitter } from "events";
|
||||||
import { ipcMain } from "electron";
|
import { ipcMain } from "electron";
|
||||||
import { EventEmitter } from "events";
|
|
||||||
import logger from "../../main/logger";
|
import logger from "../../main/logger";
|
||||||
import { Disposer } from "../utils";
|
import type { Disposer } from "../utils";
|
||||||
|
|
||||||
export type ListenerEvent<EM extends EventEmitter> = Parameters<Parameters<EM["on"]>[1]>[0];
|
export type ListenerEvent<EM extends EventEmitter> = Parameters<Parameters<EM["on"]>[1]>[0];
|
||||||
export type ListVerifier<T extends any[]> = (args: unknown[]) => args is T;
|
export type ListVerifier<T extends any[]> = (args: unknown[]) => args is T;
|
||||||
|
|||||||
@ -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 { UpdateInfo } from "electron-updater";
|
import type { UpdateInfo } from "electron-updater";
|
||||||
|
|
||||||
export const UpdateAvailableChannel = "update-available";
|
export const UpdateAvailableChannel = "update-available";
|
||||||
export const AutoUpdateLogPrefix = "[UPDATE-CHECKER]";
|
export const AutoUpdateLogPrefix = "[UPDATE-CHECKER]";
|
||||||
|
|||||||
@ -22,7 +22,7 @@ import fse from "fs-extra";
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
import hb from "handlebars";
|
import hb from "handlebars";
|
||||||
import { ResourceApplier } from "../../main/resource-applier";
|
import { ResourceApplier } from "../../main/resource-applier";
|
||||||
import { KubernetesCluster } from "../catalog-entities";
|
import type { KubernetesCluster } from "../catalog-entities";
|
||||||
import logger from "../../main/logger";
|
import logger from "../../main/logger";
|
||||||
import { app } from "electron";
|
import { app } from "electron";
|
||||||
import { requestMain } from "../ipc";
|
import { requestMain } from "../ipc";
|
||||||
|
|||||||
@ -230,7 +230,7 @@ export function getNodeWarningConditions(node: V1Node) {
|
|||||||
*
|
*
|
||||||
* Note: This function returns an error instead of throwing it, returning `undefined` if the validation passes
|
* Note: This function returns an error instead of throwing it, returning `undefined` if the validation passes
|
||||||
*/
|
*/
|
||||||
export function validateKubeConfig(config: KubeConfig, contextName: string, validationOpts: KubeConfigValidationOpts = {}): Error | undefined {
|
export function validateKubeConfig(config: KubeConfig, contextName: string, validationOpts: KubeConfigValidationOpts = {}): Error | void {
|
||||||
try {
|
try {
|
||||||
// we only receive a single context, cluster & user object here so lets validate them as this
|
// we only receive a single context, cluster & user object here so lets validate them as this
|
||||||
// will be called when we add a new cluster to Lens
|
// will be called when we add a new cluster to Lens
|
||||||
|
|||||||
@ -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 Url from "url-parse";
|
import type Url from "url-parse";
|
||||||
|
|
||||||
export enum RoutingErrorType {
|
export enum RoutingErrorType {
|
||||||
INVALID_PROTOCOL = "invalid-protocol",
|
INVALID_PROTOCOL = "invalid-protocol",
|
||||||
@ -52,6 +52,8 @@ export class RoutingError extends Error {
|
|||||||
return "no extension ID";
|
return "no extension ID";
|
||||||
case RoutingErrorType.MISSING_EXTENSION:
|
case RoutingErrorType.MISSING_EXTENSION:
|
||||||
return "extension not found";
|
return "extension not found";
|
||||||
|
default:
|
||||||
|
return `unknown error: ${this.type}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,12 +24,12 @@ import { countBy } from "lodash";
|
|||||||
import { Singleton } from "../utils";
|
import { Singleton } from "../utils";
|
||||||
import { pathToRegexp } from "path-to-regexp";
|
import { pathToRegexp } from "path-to-regexp";
|
||||||
import logger from "../../main/logger";
|
import logger from "../../main/logger";
|
||||||
import Url from "url-parse";
|
import type Url from "url-parse";
|
||||||
import { RoutingError, RoutingErrorType } from "./error";
|
import { RoutingError, RoutingErrorType } from "./error";
|
||||||
import { ExtensionsStore } from "../../extensions/extensions-store";
|
import { ExtensionsStore } from "../../extensions/extensions-store";
|
||||||
import { ExtensionLoader } from "../../extensions/extension-loader";
|
import { ExtensionLoader } from "../../extensions/extension-loader";
|
||||||
import { LensExtension } from "../../extensions/lens-extension";
|
import type { LensExtension } from "../../extensions/lens-extension";
|
||||||
import { RouteHandler, RouteParams } from "../../extensions/registries/protocol-handler-registry";
|
import type { RouteHandler, RouteParams } from "../../extensions/registries/protocol-handler-registry";
|
||||||
|
|
||||||
// IPC channel for protocol actions. Main broadcasts the open-url events to this channel.
|
// IPC channel for protocol actions. Main broadcasts the open-url events to this channel.
|
||||||
export const ProtocolHandlerIpcPrefix = "protocol-handler";
|
export const ProtocolHandlerIpcPrefix = "protocol-handler";
|
||||||
|
|||||||
@ -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 { AbortController } from "abort-controller";
|
import type { AbortController } from "abort-controller";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a promise that will be resolved after at least `timeout` ms have
|
* Return a promise that will be resolved after at least `timeout` ms have
|
||||||
|
|||||||
@ -22,19 +22,17 @@
|
|||||||
import { action, IEnhancer, IObservableMapInitialValues, ObservableMap } from "mobx";
|
import { action, IEnhancer, IObservableMapInitialValues, ObservableMap } from "mobx";
|
||||||
|
|
||||||
export class ExtendedMap<K, V> extends Map<K, V> {
|
export class ExtendedMap<K, V> extends Map<K, V> {
|
||||||
constructor(protected getDefault: () => V, entries?: readonly (readonly [K, V])[] | null) {
|
static new<K, V>(entries?: readonly (readonly [K, V])[] | null): ExtendedMap<K, V> {
|
||||||
super(entries);
|
return new ExtendedMap<K, V>(entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
getOrInsert(key: K, val: V): V {
|
/**
|
||||||
if (this.has(key)) {
|
* Get the value behind `key`. If it was not pressent, first insert the value returned by `getVal`
|
||||||
return this.get(key);
|
* @param key The key to insert into the map with
|
||||||
}
|
* @param getVal A function that returns a new instance of `V`.
|
||||||
|
* @returns The value in the map
|
||||||
return this.set(key, val).get(key);
|
*/
|
||||||
}
|
getOrInsert(key: K, getVal: () => V): V {
|
||||||
|
|
||||||
getOrInsertWith(key: K, getVal: () => V): V {
|
|
||||||
if (this.has(key)) {
|
if (this.has(key)) {
|
||||||
return this.get(key);
|
return this.get(key);
|
||||||
}
|
}
|
||||||
@ -42,12 +40,29 @@ export class ExtendedMap<K, V> extends Map<K, V> {
|
|||||||
return this.set(key, getVal()).get(key);
|
return this.set(key, getVal()).get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
getOrDefault(key: K): V {
|
/**
|
||||||
|
* Set the value associated with `key` iff there was not a previous value
|
||||||
|
* @throws if `key` already in map
|
||||||
|
* @returns `this` so that `strictSet` can be chained
|
||||||
|
*/
|
||||||
|
strictSet(key: K, val: V): this {
|
||||||
if (this.has(key)) {
|
if (this.has(key)) {
|
||||||
return this.get(key);
|
throw new TypeError("Duplicate key in map");
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.set(key, this.getDefault()).get(key);
|
return this.set(key, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value associated with `key`
|
||||||
|
* @throws if `key` did not a value associated with it
|
||||||
|
*/
|
||||||
|
strictGet(key: K): V {
|
||||||
|
if (!this.has(key)) {
|
||||||
|
throw new TypeError("key not in map");
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.get(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -19,6 +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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
export type Falsey = false | 0 | "" | null | undefined;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new type safe empty Iterable
|
* Create a new type safe empty Iterable
|
||||||
* @returns An `Iterable` that yields 0 items
|
* @returns An `Iterable` that yields 0 items
|
||||||
@ -57,6 +59,36 @@ export function* map<T, U>(src: Iterable<T>, fn: (from: T) => U): Iterable<U> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The single layer flattening of an iterator, discarding `Falsey` values.
|
||||||
|
* @param src A type that can be iterated over
|
||||||
|
* @param fn The function that returns either an iterable over items that should be filtered out or a `Falsey` value indicating that it should be ignored
|
||||||
|
*/
|
||||||
|
export function* filterFlatMap<T, U>(src: Iterable<T>, fn: (from: T) => Iterable<U | Falsey> | Falsey): Iterable<U> {
|
||||||
|
for (const from of src) {
|
||||||
|
if (!from) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapping = fn(from);
|
||||||
|
|
||||||
|
if (!mapping) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const mapped of mapping) {
|
||||||
|
if (mapped) {
|
||||||
|
yield mapped;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new iterator that yields the items that each call to `fn` would produce
|
||||||
|
* @param src A type that can be iterated over
|
||||||
|
* @param fn A function that returns an iterator
|
||||||
|
*/
|
||||||
export function* flatMap<T, U>(src: Iterable<T>, fn: (from: T) => Iterable<U>): Iterable<U> {
|
export function* flatMap<T, U>(src: Iterable<T>, fn: (from: T) => Iterable<U>): Iterable<U> {
|
||||||
for (const from of src) {
|
for (const from of src) {
|
||||||
yield* fn(from);
|
yield* fn(from);
|
||||||
@ -83,7 +115,7 @@ export function* filter<T>(src: Iterable<T>, fn: (from: T) => any): Iterable<T>
|
|||||||
* @param src A type that can be iterated over
|
* @param src A type that can be iterated over
|
||||||
* @param fn The function that is called for each value
|
* @param fn The function that is called for each value
|
||||||
*/
|
*/
|
||||||
export function* filterMap<T, U>(src: Iterable<T>, fn: (from: T) => U): Iterable<U> {
|
export function* filterMap<T, U>(src: Iterable<T>, fn: (from: T) => U | Falsey): Iterable<U> {
|
||||||
for (const from of src) {
|
for (const from of src) {
|
||||||
const res = fn(from);
|
const res = fn(from);
|
||||||
|
|
||||||
@ -99,7 +131,7 @@ export function* filterMap<T, U>(src: Iterable<T>, fn: (from: T) => U): Iterable
|
|||||||
* @param src A type that can be iterated over
|
* @param src A type that can be iterated over
|
||||||
* @param fn The function that is called for each value
|
* @param fn The function that is called for each value
|
||||||
*/
|
*/
|
||||||
export function* filterMapStrict<T, U>(src: Iterable<T>, fn: (from: T) => U): Iterable<U> {
|
export function* filterMapStrict<T, U>(src: Iterable<T>, fn: (from: T) => U | null | undefined): Iterable<U> {
|
||||||
for (const from of src) {
|
for (const from of src) {
|
||||||
const res = fn(from);
|
const res = fn(from);
|
||||||
|
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
import { app, remote } from "electron";
|
import { app, remote } from "electron";
|
||||||
import { ensureDirSync, writeFileSync } from "fs-extra";
|
import { ensureDirSync, writeFileSync } from "fs-extra";
|
||||||
import { WriteFileOptions } from "fs";
|
import type { WriteFileOptions } from "fs";
|
||||||
|
|
||||||
export function saveToAppFiles(filePath: string, contents: any, options?: WriteFileOptions): string {
|
export function saveToAppFiles(filePath: string, contents: any, options?: WriteFileOptions): string {
|
||||||
const absPath = path.resolve((app || remote.app).getPath("userData"), filePath);
|
const absPath = path.resolve((app || remote.app).getPath("userData"), filePath);
|
||||||
|
|||||||
@ -77,6 +77,8 @@ jest.mock(
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
}),
|
}),
|
||||||
on: jest.fn(
|
on: jest.fn(
|
||||||
(channel: string, listener: (event: any, ...args: any[]) => void) => {
|
(channel: string, listener: (event: any, ...args: any[]) => void) => {
|
||||||
|
|||||||
@ -20,7 +20,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
import { CatalogEntity, catalogEntityRegistry as registry } from "../../common/catalog";
|
import type { CatalogEntity } from "../../common/catalog";
|
||||||
|
import { catalogEntityRegistry as registry } from "../../main/catalog";
|
||||||
|
|
||||||
export { catalogCategoryRegistry as catalogCategories } from "../../common/catalog/catalog-category-registry";
|
export { catalogCategoryRegistry as catalogCategories } from "../../common/catalog/catalog-category-registry";
|
||||||
export * from "../../common/catalog-entities";
|
export * from "../../common/catalog-entities";
|
||||||
|
|||||||
@ -325,6 +325,8 @@ export class ExtensionLoader extends Singleton {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`${logModule}: can't load extension main at ${extAbsolutePath}: ${error}`, { extension, error });
|
logger.error(`${logModule}: can't load extension main at ${extAbsolutePath}: ${error}`, { extension, error });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
getExtension(extId: LensExtensionId): InstalledExtension {
|
getExtension(extId: LensExtensionId): InstalledExtension {
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
import { BaseStore } from "../common/base-store";
|
import { BaseStore } from "../common/base-store";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import { LensExtension } from "./lens-extension";
|
import type { LensExtension } from "./lens-extension";
|
||||||
|
|
||||||
export abstract class ExtensionStore<T> extends BaseStore<T> {
|
export abstract class ExtensionStore<T> extends BaseStore<T> {
|
||||||
protected extension: LensExtension;
|
protected extension: LensExtension;
|
||||||
|
|||||||
@ -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 { Singleton } from "../common/utils";
|
import { Singleton } from "../common/utils";
|
||||||
import { LensExtension } from "./lens-extension";
|
import type { LensExtension } from "./lens-extension";
|
||||||
import { createHash } from "crypto";
|
import { createHash } from "crypto";
|
||||||
import { broadcastMessage } from "../common/ipc";
|
import { broadcastMessage } from "../common/ipc";
|
||||||
|
|
||||||
|
|||||||
@ -23,7 +23,7 @@ import type { InstalledExtension } from "./extension-discovery";
|
|||||||
import { action, observable, reaction } from "mobx";
|
import { action, observable, reaction } 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 { ProtocolHandlerRegistration } from "./registries";
|
import type { ProtocolHandlerRegistration } from "./registries";
|
||||||
import { disposer } from "../common/utils";
|
import { disposer } from "../common/utils";
|
||||||
|
|
||||||
export type LensExtensionId = string; // path to manifest (package.json)
|
export type LensExtensionId = string; // path to manifest (package.json)
|
||||||
|
|||||||
@ -22,9 +22,10 @@
|
|||||||
import { LensExtension } from "./lens-extension";
|
import { LensExtension } from "./lens-extension";
|
||||||
import { WindowManager } from "../main/window-manager";
|
import { WindowManager } from "../main/window-manager";
|
||||||
import { getExtensionPageUrl } from "./registries/page-registry";
|
import { getExtensionPageUrl } from "./registries/page-registry";
|
||||||
import { CatalogEntity, catalogEntityRegistry } from "../common/catalog";
|
import { catalogEntityRegistry } from "../main/catalog";
|
||||||
import { IObservableArray } from "mobx";
|
import type { CatalogEntity } from "../common/catalog";
|
||||||
import { MenuRegistration } from "./registries";
|
import type { IObservableArray } from "mobx";
|
||||||
|
import type { MenuRegistration } from "./registries";
|
||||||
|
|
||||||
export class LensMainExtension extends LensExtension {
|
export class LensMainExtension extends LensExtension {
|
||||||
appMenus: MenuRegistration[] = [];
|
appMenus: MenuRegistration[] = [];
|
||||||
|
|||||||
@ -26,8 +26,8 @@ import type {
|
|||||||
import type { Cluster } from "../main/cluster";
|
import type { Cluster } from "../main/cluster";
|
||||||
import { LensExtension } from "./lens-extension";
|
import { LensExtension } from "./lens-extension";
|
||||||
import { getExtensionPageUrl } from "./registries/page-registry";
|
import { getExtensionPageUrl } from "./registries/page-registry";
|
||||||
import { CommandRegistration } from "./registries/command-registry";
|
import type { CommandRegistration } from "./registries/command-registry";
|
||||||
import { EntitySettingRegistration } from "./registries/entity-setting-registry";
|
import type { EntitySettingRegistration } from "./registries/entity-setting-registry";
|
||||||
|
|
||||||
export class LensRendererExtension extends LensExtension {
|
export class LensRendererExtension extends LensExtension {
|
||||||
globalPages: PageRegistration[] = [];
|
globalPages: PageRegistration[] = [];
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
import { ipcMain } from "electron";
|
import { ipcMain } from "electron";
|
||||||
import { IpcPrefix, IpcStore } from "./ipc-store";
|
import { IpcPrefix, IpcStore } from "./ipc-store";
|
||||||
import { Disposers } from "./lens-extension";
|
import { Disposers } from "./lens-extension";
|
||||||
import { LensMainExtension } from "./lens-main-extension";
|
import type { LensMainExtension } from "./lens-main-extension";
|
||||||
|
|
||||||
export abstract class MainIpcStore extends IpcStore {
|
export abstract class MainIpcStore extends IpcStore {
|
||||||
constructor(extension: LensMainExtension) {
|
constructor(extension: LensMainExtension) {
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import type React from "react";
|
import type React from "react";
|
||||||
import { CatalogEntity } from "../../common/catalog";
|
import type { CatalogEntity } from "../../common/catalog";
|
||||||
import { BaseRegistry } from "./base-registry";
|
import { BaseRegistry } from "./base-registry";
|
||||||
|
|
||||||
export interface EntitySettingViewProps {
|
export interface EntitySettingViewProps {
|
||||||
|
|||||||
@ -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 React from "react";
|
import type React from "react";
|
||||||
import { BaseRegistry } from "./base-registry";
|
import { BaseRegistry } from "./base-registry";
|
||||||
|
|
||||||
export interface KubeObjectDetailComponents {
|
export interface KubeObjectDetailComponents {
|
||||||
|
|||||||
@ -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 React from "react";
|
import type React from "react";
|
||||||
import { BaseRegistry } from "./base-registry";
|
import { BaseRegistry } from "./base-registry";
|
||||||
|
|
||||||
export interface KubeObjectMenuComponents {
|
export interface KubeObjectMenuComponents {
|
||||||
|
|||||||
@ -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 { KubeObject, KubeObjectStatus } from "../renderer-api/k8s-api";
|
import type { KubeObject, KubeObjectStatus } from "../renderer-api/k8s-api";
|
||||||
import { BaseRegistry } from "./base-registry";
|
import { BaseRegistry } from "./base-registry";
|
||||||
|
|
||||||
export interface KubeObjectStatusRegistration {
|
export interface KubeObjectStatusRegistration {
|
||||||
|
|||||||
@ -25,7 +25,7 @@ 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, sanitizeExtensionName } from "../lens-extension";
|
||||||
import { PageParam, PageParamInit } from "../../renderer/navigation/page-param";
|
import type { PageParam, PageParamInit } from "../../renderer/navigation/page-param";
|
||||||
import { createPageParam } from "../../renderer/navigation/helpers";
|
import { createPageParam } from "../../renderer/navigation/helpers";
|
||||||
|
|
||||||
export interface PageRegistration {
|
export interface PageRegistration {
|
||||||
@ -119,9 +119,9 @@ export class PageRegistry extends BaseRegistry<PageRegistration, RegisteredPage>
|
|||||||
return components;
|
return components;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected normalizeParams(params?: PageParams<string | ExtensionPageParamInit>): PageParams<PageParam> {
|
protected normalizeParams(params?: PageParams<string | ExtensionPageParamInit>): PageParams<PageParam> | undefined {
|
||||||
if (!params) {
|
if (!params) {
|
||||||
return;
|
return undefined;
|
||||||
}
|
}
|
||||||
Object.entries(params).forEach(([name, value]) => {
|
Object.entries(params).forEach(([name, value]) => {
|
||||||
const paramInit: PageParamInit = typeof value === "object"
|
const paramInit: PageParamInit = typeof value === "object"
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
// Extensions API -> Status bar customizations
|
// Extensions API -> Status bar customizations
|
||||||
|
|
||||||
import React from "react";
|
import type React from "react";
|
||||||
import { BaseRegistry } from "./base-registry";
|
import { BaseRegistry } from "./base-registry";
|
||||||
|
|
||||||
interface StatusBarComponents {
|
interface StatusBarComponents {
|
||||||
|
|||||||
@ -23,9 +23,9 @@ export { isAllowedResource } from "../../common/rbac";
|
|||||||
export { ResourceStack } from "../../common/k8s/resource-stack";
|
export { ResourceStack } from "../../common/k8s/resource-stack";
|
||||||
export { apiManager } from "../../renderer/api/api-manager";
|
export { apiManager } from "../../renderer/api/api-manager";
|
||||||
export { KubeObjectStore } from "../../renderer/kube-object.store";
|
export { KubeObjectStore } from "../../renderer/kube-object.store";
|
||||||
export { KubeApi, forCluster, IKubeApiCluster } from "../../renderer/api/kube-api";
|
export { KubeApi, forCluster } from "../../renderer/api/kube-api";
|
||||||
export { KubeObject } from "../../renderer/api/kube-object";
|
export { KubeObject } from "../../renderer/api/kube-object";
|
||||||
export { Pod, podsApi, PodsApi, IPodContainer, IPodContainerStatus } from "../../renderer/api/endpoints";
|
export { Pod, podsApi, PodsApi } from "../../renderer/api/endpoints";
|
||||||
export { Node, nodesApi, NodesApi } from "../../renderer/api/endpoints";
|
export { Node, nodesApi, NodesApi } from "../../renderer/api/endpoints";
|
||||||
export { Deployment, deploymentApi, DeploymentApi } from "../../renderer/api/endpoints";
|
export { Deployment, deploymentApi, DeploymentApi } from "../../renderer/api/endpoints";
|
||||||
export { DaemonSet, daemonSetApi } from "../../renderer/api/endpoints";
|
export { DaemonSet, daemonSetApi } from "../../renderer/api/endpoints";
|
||||||
@ -33,7 +33,7 @@ export { StatefulSet, statefulSetApi } from "../../renderer/api/endpoints";
|
|||||||
export { Job, jobApi } from "../../renderer/api/endpoints";
|
export { Job, jobApi } from "../../renderer/api/endpoints";
|
||||||
export { CronJob, cronJobApi } from "../../renderer/api/endpoints";
|
export { CronJob, cronJobApi } from "../../renderer/api/endpoints";
|
||||||
export { ConfigMap, configMapApi } from "../../renderer/api/endpoints";
|
export { ConfigMap, configMapApi } from "../../renderer/api/endpoints";
|
||||||
export { Secret, secretsApi, ISecretRef } from "../../renderer/api/endpoints";
|
export { Secret, secretsApi } from "../../renderer/api/endpoints";
|
||||||
export { ReplicaSet, replicaSetApi } from "../../renderer/api/endpoints";
|
export { ReplicaSet, replicaSetApi } from "../../renderer/api/endpoints";
|
||||||
export { ResourceQuota, resourceQuotaApi } from "../../renderer/api/endpoints";
|
export { ResourceQuota, resourceQuotaApi } from "../../renderer/api/endpoints";
|
||||||
export { LimitRange, limitRangeApi } from "../../renderer/api/endpoints";
|
export { LimitRange, limitRangeApi } from "../../renderer/api/endpoints";
|
||||||
@ -54,7 +54,13 @@ export { RoleBinding, roleBindingApi } from "../../renderer/api/endpoints";
|
|||||||
export { ClusterRole, clusterRoleApi } from "../../renderer/api/endpoints";
|
export { ClusterRole, clusterRoleApi } from "../../renderer/api/endpoints";
|
||||||
export { ClusterRoleBinding, clusterRoleBindingApi } from "../../renderer/api/endpoints";
|
export { ClusterRoleBinding, clusterRoleBindingApi } from "../../renderer/api/endpoints";
|
||||||
export { CustomResourceDefinition, crdApi } from "../../renderer/api/endpoints";
|
export { CustomResourceDefinition, crdApi } from "../../renderer/api/endpoints";
|
||||||
export { KubeObjectStatus, KubeObjectStatusLevel } from "./kube-object-status";
|
export { KubeObjectStatusLevel } from "./kube-object-status";
|
||||||
|
|
||||||
|
// types
|
||||||
|
export type { IKubeApiCluster } from "../../renderer/api/kube-api";
|
||||||
|
export type { IPodContainer, IPodContainerStatus } from "../../renderer/api/endpoints";
|
||||||
|
export type { ISecretRef } from "../../renderer/api/endpoints";
|
||||||
|
export type { KubeObjectStatus } from "./kube-object-status";
|
||||||
|
|
||||||
// stores
|
// stores
|
||||||
export type { EventStore } from "../../renderer/components/+events/event.store";
|
export type { EventStore } from "../../renderer/components/+events/event.store";
|
||||||
|
|||||||
@ -25,7 +25,7 @@ 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 { IURLParams } from "../../common/utils/buildUrl";
|
export type { IURLParams } from "../../common/utils/buildUrl";
|
||||||
|
|
||||||
// exporting to extensions-api version of helper without `isSystem` flag
|
// exporting to extensions-api version of helper without `isSystem` flag
|
||||||
export function createPageParam<V = string>(init: PageParamInit<V>) {
|
export function createPageParam<V = string>(init: PageParamInit<V>) {
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
import { ipcRenderer } from "electron";
|
import { ipcRenderer } from "electron";
|
||||||
import { IpcPrefix, IpcStore } from "./ipc-store";
|
import { IpcPrefix, IpcStore } from "./ipc-store";
|
||||||
import { Disposers } from "./lens-extension";
|
import { Disposers } from "./lens-extension";
|
||||||
import { LensRendererExtension } from "./lens-renderer-extension";
|
import type { LensRendererExtension } from "./lens-renderer-extension";
|
||||||
|
|
||||||
export abstract class RendererIpcStore extends IpcStore {
|
export abstract class RendererIpcStore extends IpcStore {
|
||||||
constructor(extension: LensRendererExtension) {
|
constructor(extension: LensRendererExtension) {
|
||||||
|
|||||||
@ -44,6 +44,12 @@ jest.mock("winston", () => ({
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
jest.mock("electron", () => ({
|
||||||
|
app: {
|
||||||
|
getPath: () => "/foo",
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
jest.mock("../../common/ipc");
|
jest.mock("../../common/ipc");
|
||||||
jest.mock("child_process");
|
jest.mock("child_process");
|
||||||
jest.mock("tcp-port-used");
|
jest.mock("tcp-port-used");
|
||||||
@ -56,7 +62,7 @@ import { ChildProcess, spawn } from "child_process";
|
|||||||
import { bundledKubectlPath, Kubectl } from "../kubectl";
|
import { bundledKubectlPath, Kubectl } from "../kubectl";
|
||||||
import { mock, MockProxy } from "jest-mock-extended";
|
import { mock, MockProxy } from "jest-mock-extended";
|
||||||
import { waitUntilUsed } from "tcp-port-used";
|
import { waitUntilUsed } from "tcp-port-used";
|
||||||
import { Readable } from "stream";
|
import type { Readable } from "stream";
|
||||||
import { UserStore } from "../../common/user-store";
|
import { UserStore } from "../../common/user-store";
|
||||||
import { Console } from "console";
|
import { Console } from "console";
|
||||||
import { stdout, stderr } from "process";
|
import { stdout, stderr } from "process";
|
||||||
|
|||||||
@ -28,6 +28,12 @@ const logger = {
|
|||||||
crit: jest.fn(),
|
crit: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
jest.mock("electron", () => ({
|
||||||
|
app: {
|
||||||
|
getPath: () => `/tmp`,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
jest.mock("winston", () => ({
|
jest.mock("winston", () => ({
|
||||||
format: {
|
format: {
|
||||||
colorize: jest.fn(),
|
colorize: jest.fn(),
|
||||||
@ -47,7 +53,7 @@ jest.mock("winston", () => ({
|
|||||||
import { KubeconfigManager } from "../kubeconfig-manager";
|
import { KubeconfigManager } from "../kubeconfig-manager";
|
||||||
import mockFs from "mock-fs";
|
import mockFs from "mock-fs";
|
||||||
import { Cluster } from "../cluster";
|
import { Cluster } from "../cluster";
|
||||||
import { ContextHandler } from "../context-handler";
|
import type { ContextHandler } from "../context-handler";
|
||||||
import fse from "fs-extra";
|
import fse from "fs-extra";
|
||||||
import { loadYaml } from "@kubernetes/client-node";
|
import { loadYaml } from "@kubernetes/client-node";
|
||||||
import { Console } from "console";
|
import { Console } from "console";
|
||||||
@ -91,7 +97,9 @@ describe("kubeconfig manager tests", () => {
|
|||||||
contextName: "minikube",
|
contextName: "minikube",
|
||||||
kubeConfigPath: "minikube-config.yml",
|
kubeConfigPath: "minikube-config.yml",
|
||||||
});
|
});
|
||||||
contextHandler = jest.fn() as any;
|
contextHandler = {
|
||||||
|
ensureServer: () => Promise.resolve(),
|
||||||
|
} as any;
|
||||||
jest.spyOn(KubeconfigManager.prototype, "resolveProxyUrl", "get").mockReturnValue("http://127.0.0.1:9191/foo");
|
jest.spyOn(KubeconfigManager.prototype, "resolveProxyUrl", "get").mockReturnValue("http://127.0.0.1:9191/foo");
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -103,7 +111,7 @@ describe("kubeconfig manager tests", () => {
|
|||||||
const kubeConfManager = new KubeconfigManager(cluster, contextHandler);
|
const kubeConfManager = new KubeconfigManager(cluster, contextHandler);
|
||||||
|
|
||||||
expect(logger.error).not.toBeCalled();
|
expect(logger.error).not.toBeCalled();
|
||||||
expect(await kubeConfManager.getPath()).toBe(`tmp${path.sep}kubeconfig-foo`);
|
expect(await kubeConfManager.getPath()).toBe(`${path.sep}tmp${path.sep}kubeconfig-foo`);
|
||||||
// this causes an intermittent "ENXIO: no such device or address, read" error
|
// this causes an intermittent "ENXIO: no such device or address, read" error
|
||||||
// const file = await fse.readFile(await kubeConfManager.getPath());
|
// const file = await fse.readFile(await kubeConfManager.getPath());
|
||||||
const file = fse.readFileSync(await kubeConfManager.getPath());
|
const file = fse.readFileSync(await kubeConfManager.getPath());
|
||||||
|
|||||||
@ -20,33 +20,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { reaction, toJS } from "mobx";
|
import { reaction, toJS } from "mobx";
|
||||||
import { broadcastMessage, subscribeToBroadcast, unsubscribeFromBroadcast } from "../common/ipc";
|
import { broadcastMessage } from "../common/ipc";
|
||||||
import { CatalogEntityRegistry} from "../common/catalog";
|
import type { CatalogEntityRegistry} from "./catalog";
|
||||||
import "../common/catalog-entities/kubernetes-cluster";
|
import "../common/catalog-entities/kubernetes-cluster";
|
||||||
import { Disposer } from "../common/utils";
|
|
||||||
|
|
||||||
export class CatalogPusher {
|
export function pushCatalogToRenderer(catalog: CatalogEntityRegistry) {
|
||||||
static init(catalog: CatalogEntityRegistry) {
|
return reaction(() => toJS(catalog.items, { recurseEverything: true }), (items) => {
|
||||||
new CatalogPusher(catalog).init();
|
broadcastMessage("catalog:items", items);
|
||||||
}
|
}, {
|
||||||
|
fireImmediately: true,
|
||||||
private constructor(private catalog: CatalogEntityRegistry) {}
|
});
|
||||||
|
|
||||||
init() {
|
|
||||||
const disposers: Disposer[] = [];
|
|
||||||
|
|
||||||
disposers.push(reaction(() => toJS(this.catalog.items, { recurseEverything: true }), (items) => {
|
|
||||||
broadcastMessage("catalog:items", items);
|
|
||||||
}, {
|
|
||||||
fireImmediately: true,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const listener = subscribeToBroadcast("catalog:broadcast", () => {
|
|
||||||
broadcastMessage("catalog:items", toJS(this.catalog.items, { recurseEverything: true }));
|
|
||||||
});
|
|
||||||
|
|
||||||
disposers.push(() => unsubscribeFromBroadcast("catalog:broadcast", listener));
|
|
||||||
|
|
||||||
return disposers;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,9 +20,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { ObservableMap } from "mobx";
|
import { ObservableMap } from "mobx";
|
||||||
import { CatalogEntity } from "../../../common/catalog";
|
import type { CatalogEntity } from "../../../common/catalog";
|
||||||
import { loadFromOptions } from "../../../common/kube-helpers";
|
import { loadFromOptions } from "../../../common/kube-helpers";
|
||||||
import { Cluster } from "../../cluster";
|
import type { Cluster } from "../../cluster";
|
||||||
import { computeDiff, configToModels } from "../kubeconfig-sync";
|
import { computeDiff, configToModels } from "../kubeconfig-sync";
|
||||||
import mockFs from "mock-fs";
|
import mockFs from "mock-fs";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
|
|||||||
@ -20,14 +20,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { action, observable, IComputedValue, computed, ObservableMap, runInAction } from "mobx";
|
import { action, observable, IComputedValue, computed, ObservableMap, runInAction } from "mobx";
|
||||||
import { CatalogEntity, catalogEntityRegistry } from "../../common/catalog";
|
import type { CatalogEntity } from "../../common/catalog";
|
||||||
|
import { catalogEntityRegistry } from "../../main/catalog";
|
||||||
import { watch } from "chokidar";
|
import { watch } from "chokidar";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import fse from "fs-extra";
|
import fse from "fs-extra";
|
||||||
import stream from "stream";
|
import type stream from "stream";
|
||||||
import { Disposer, ExtendedObservableMap, iter, Singleton } from "../../common/utils";
|
import { Disposer, ExtendedObservableMap, iter, Singleton } from "../../common/utils";
|
||||||
import logger from "../logger";
|
import logger from "../logger";
|
||||||
import { KubeConfig } from "@kubernetes/client-node";
|
import type { KubeConfig } from "@kubernetes/client-node";
|
||||||
import { loadConfigFromString, splitConfig, validateKubeConfig } from "../../common/kube-helpers";
|
import { loadConfigFromString, splitConfig, validateKubeConfig } from "../../common/kube-helpers";
|
||||||
import { Cluster } from "../cluster";
|
import { Cluster } from "../cluster";
|
||||||
import { catalogEntityFromCluster } from "../cluster-manager";
|
import { catalogEntityFromCluster } from "../cluster-manager";
|
||||||
|
|||||||
@ -20,8 +20,30 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { observable, reaction } from "mobx";
|
import { observable, reaction } from "mobx";
|
||||||
import { WebLink } from "../catalog-entities";
|
import { WebLink, WebLinkSpec, WebLinkStatus } from "../../../common/catalog-entities";
|
||||||
import { CatalogEntityRegistry } from "../catalog";
|
import { catalogCategoryRegistry, CatalogEntity, CatalogEntityMetadata } from "../../../common/catalog";
|
||||||
|
import { CatalogEntityRegistry } from "../catalog-entity-registry";
|
||||||
|
|
||||||
|
class InvalidEntity extends CatalogEntity<CatalogEntityMetadata, WebLinkStatus, WebLinkSpec> {
|
||||||
|
public readonly apiVersion = "entity.k8slens.dev/v1alpha1";
|
||||||
|
public readonly kind = "Invalid";
|
||||||
|
|
||||||
|
async onRun() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public onSettingsOpen(): void {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public onDetailsOpen(): void {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public onContextMenuOpen(): void {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
describe("CatalogEntityRegistry", () => {
|
describe("CatalogEntityRegistry", () => {
|
||||||
let registry: CatalogEntityRegistry;
|
let registry: CatalogEntityRegistry;
|
||||||
@ -39,9 +61,23 @@ describe("CatalogEntityRegistry", () => {
|
|||||||
phase: "valid"
|
phase: "valid"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
const invalidEntity = new InvalidEntity({
|
||||||
|
metadata: {
|
||||||
|
uid: "invalid",
|
||||||
|
name: "test-link",
|
||||||
|
source: "test",
|
||||||
|
labels: {}
|
||||||
|
},
|
||||||
|
spec: {
|
||||||
|
url: "https://k8slens.dev"
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
phase: "valid"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
registry = new CatalogEntityRegistry();
|
registry = new CatalogEntityRegistry(catalogCategoryRegistry);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("addSource", () => {
|
describe("addSource", () => {
|
||||||
@ -79,4 +115,22 @@ describe("CatalogEntityRegistry", () => {
|
|||||||
expect(registry.items.length).toEqual(0);
|
expect(registry.items.length).toEqual(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("items", () => {
|
||||||
|
it("returns added items", () => {
|
||||||
|
expect(registry.items.length).toBe(0);
|
||||||
|
|
||||||
|
const source = observable.array([entity]);
|
||||||
|
|
||||||
|
registry.addObservableSource("test", source);
|
||||||
|
expect(registry.items.length).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not return items without matching category", () => {
|
||||||
|
const source = observable.array([invalidEntity]);
|
||||||
|
|
||||||
|
registry.addObservableSource("test", source);
|
||||||
|
expect(registry.items.length).toBe(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
@ -20,12 +20,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { action, computed, observable, IComputedValue, IObservableArray } from "mobx";
|
import { action, computed, observable, IComputedValue, IObservableArray } from "mobx";
|
||||||
import { CatalogEntity } from "./catalog-entity";
|
import { CatalogCategoryRegistry, catalogCategoryRegistry, CatalogEntity } from "../../common/catalog";
|
||||||
import { iter } from "../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[]>>([], { deep: true });
|
||||||
|
|
||||||
|
constructor(private categoryRegistry: CatalogCategoryRegistry) {}
|
||||||
|
|
||||||
@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));
|
||||||
}
|
}
|
||||||
@ -39,7 +41,9 @@ export class CatalogEntityRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@computed get items(): CatalogEntity[] {
|
@computed get items(): CatalogEntity[] {
|
||||||
return Array.from(iter.flatMap(this.sources.values(), source => source.get()));
|
const allItems = Array.from(iter.flatMap(this.sources.values(), source => source.get()));
|
||||||
|
|
||||||
|
return allItems.filter((entity) => this.categoryRegistry.getCategoryForEntity(entity) !== undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
getItemsForApiKind<T extends CatalogEntity>(apiVersion: string, kind: string): T[] {
|
getItemsForApiKind<T extends CatalogEntity>(apiVersion: string, kind: string): T[] {
|
||||||
@ -49,4 +53,4 @@ export class CatalogEntityRegistry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const catalogEntityRegistry = new CatalogEntityRegistry();
|
export const catalogEntityRegistry = new CatalogEntityRegistry(catalogCategoryRegistry);
|
||||||
22
src/main/catalog/index.ts
Normal file
22
src/main/catalog/index.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from "./catalog-entity-registry";
|
||||||
@ -19,8 +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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { RequestPromiseOptions } from "request-promise-native";
|
import type { RequestPromiseOptions } from "request-promise-native";
|
||||||
import { Cluster } from "../cluster";
|
import type { Cluster } from "../cluster";
|
||||||
import { k8sRequest } from "../k8s-request";
|
import { k8sRequest } from "../k8s-request";
|
||||||
|
|
||||||
export type ClusterDetectionResult = {
|
export type ClusterDetectionResult = {
|
||||||
|
|||||||
@ -20,9 +20,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { observable } from "mobx";
|
import { observable } from "mobx";
|
||||||
import { ClusterMetadata } from "../../common/cluster-store";
|
import type { ClusterMetadata } from "../../common/cluster-store";
|
||||||
import { Cluster } from "../cluster";
|
import type { Cluster } from "../cluster";
|
||||||
import { BaseClusterDetector, ClusterDetectionResult } from "./base-cluster-detector";
|
import type { BaseClusterDetector, ClusterDetectionResult } from "./base-cluster-detector";
|
||||||
import { ClusterIdDetector } from "./cluster-id-detector";
|
import { ClusterIdDetector } from "./cluster-id-detector";
|
||||||
import { DistributionDetector } from "./distribution-detector";
|
import { DistributionDetector } from "./distribution-detector";
|
||||||
import { LastSeenDetector } from "./last-seen-detector";
|
import { LastSeenDetector } from "./last-seen-detector";
|
||||||
|
|||||||
@ -24,11 +24,11 @@ import type http from "http";
|
|||||||
import { ipcMain } from "electron";
|
import { ipcMain } from "electron";
|
||||||
import { action, autorun, reaction, toJS } from "mobx";
|
import { action, autorun, reaction, toJS } from "mobx";
|
||||||
import { ClusterStore, getClusterIdFromHost } from "../common/cluster-store";
|
import { ClusterStore, getClusterIdFromHost } from "../common/cluster-store";
|
||||||
import { Cluster } from "./cluster";
|
import type { Cluster } from "./cluster";
|
||||||
import logger from "./logger";
|
import logger from "./logger";
|
||||||
import { apiKubePrefix } from "../common/vars";
|
import { apiKubePrefix } from "../common/vars";
|
||||||
import { Singleton } from "../common/utils";
|
import { Singleton } from "../common/utils";
|
||||||
import { catalogEntityRegistry } from "../common/catalog";
|
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 {
|
||||||
|
|||||||
@ -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 type { PrometheusProvider, PrometheusService } from "./prometheus/provider-registry";
|
import type { PrometheusService } from "./prometheus/provider-registry";
|
||||||
import type { ClusterPrometheusPreferences } from "../common/cluster-store";
|
import type { ClusterPrometheusPreferences } from "../common/cluster-store";
|
||||||
import type { Cluster } from "./cluster";
|
import type { Cluster } from "./cluster";
|
||||||
import type httpProxy from "http-proxy";
|
import type httpProxy from "http-proxy";
|
||||||
@ -75,16 +75,15 @@ export class ContextHandler {
|
|||||||
return prometheusProviders.find(p => p.id === this.prometheusProvider);
|
return prometheusProviders.find(p => p.id === this.prometheusProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPrometheusService(): Promise<PrometheusService> {
|
async getPrometheusService(): Promise<PrometheusService | void> {
|
||||||
const providers = this.prometheusProvider ? prometheusProviders.filter(provider => provider.id == this.prometheusProvider) : prometheusProviders;
|
const providers = this.prometheusProvider ? prometheusProviders.filter(provider => provider.id == this.prometheusProvider) : prometheusProviders;
|
||||||
const prometheusPromises: Promise<PrometheusService>[] = providers.map(async (provider: PrometheusProvider): Promise<PrometheusService> => {
|
const prometheusPromises: Promise<PrometheusService | void>[] = providers.map(async provider => {
|
||||||
const apiClient = (await this.cluster.getProxyKubeconfig()).makeApiClient(CoreV1Api);
|
const apiClient = (await this.cluster.getProxyKubeconfig()).makeApiClient(CoreV1Api);
|
||||||
|
|
||||||
return await provider.getPrometheusService(apiClient);
|
return provider.getPrometheusService(apiClient);
|
||||||
});
|
});
|
||||||
const resolvedPrometheusServices = await Promise.all(prometheusPromises);
|
|
||||||
|
|
||||||
return resolvedPrometheusServices.filter(n => n)[0];
|
return (await Promise.all(prometheusPromises)).find(Boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPrometheusPath(): Promise<string> {
|
async getPrometheusPath(): Promise<string> {
|
||||||
|
|||||||
@ -26,7 +26,7 @@ import fse from "fs-extra";
|
|||||||
import { action, observable, toJS } from "mobx";
|
import { action, observable, toJS } from "mobx";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { BaseStore } from "../common/base-store";
|
import { BaseStore } from "../common/base-store";
|
||||||
import { LensExtensionId } from "../extensions/lens-extension";
|
import type { LensExtensionId } from "../extensions/lens-extension";
|
||||||
|
|
||||||
interface FSProvisionModel {
|
interface FSProvisionModel {
|
||||||
extensions: Record<string, string>; // extension names to paths
|
extensions: Record<string, string>; // extension names to paths
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
import { HelmRepo, HelmRepoManager } from "../helm-repo-manager";
|
import { HelmRepo, HelmRepoManager } from "../helm-repo-manager";
|
||||||
|
|
||||||
export class HelmChartManager {
|
export class HelmChartManager {
|
||||||
private cache: any = {};
|
cache: any = {};
|
||||||
private repo: HelmRepo;
|
private repo: HelmRepo;
|
||||||
|
|
||||||
constructor(repo: HelmRepo){
|
constructor(repo: HelmRepo){
|
||||||
|
|||||||
@ -24,7 +24,7 @@ import fse from "fs-extra";
|
|||||||
import * as yaml from "js-yaml";
|
import * as yaml from "js-yaml";
|
||||||
import { promiseExec} from "../promise-exec";
|
import { promiseExec} from "../promise-exec";
|
||||||
import { helmCli } from "./helm-cli";
|
import { helmCli } from "./helm-cli";
|
||||||
import { Cluster } from "../cluster";
|
import type { Cluster } from "../cluster";
|
||||||
import { toCamelCase } from "../../common/utils/camelCase";
|
import { toCamelCase } from "../../common/utils/camelCase";
|
||||||
|
|
||||||
export async function listReleases(pathToKubeconfig: string, namespace?: string) {
|
export async function listReleases(pathToKubeconfig: string, namespace?: string) {
|
||||||
|
|||||||
@ -20,11 +20,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import semver from "semver";
|
import semver from "semver";
|
||||||
import { Cluster } from "../cluster";
|
import type { Cluster } from "../cluster";
|
||||||
import logger from "../logger";
|
import logger from "../logger";
|
||||||
import { HelmRepoManager } from "./helm-repo-manager";
|
import { HelmRepoManager } from "./helm-repo-manager";
|
||||||
import { HelmChartManager } from "./helm-chart-manager";
|
import { HelmChartManager } from "./helm-chart-manager";
|
||||||
import { HelmChartList, RepoHelmChartList } from "../../renderer/api/endpoints/helm-charts.api";
|
import type { HelmChartList, RepoHelmChartList } from "../../renderer/api/endpoints/helm-charts.api";
|
||||||
import { deleteRelease, getHistory, getRelease, getValues, installChart, listReleases, rollback, upgradeRelease } from "./helm-release-manager";
|
import { deleteRelease, getHistory, getRelease, getValues, installChart, listReleases, rollback, upgradeRelease } from "./helm-release-manager";
|
||||||
|
|
||||||
class HelmService {
|
class HelmService {
|
||||||
|
|||||||
@ -45,18 +45,19 @@ import type { LensExtensionId } from "../extensions/lens-extension";
|
|||||||
import { FilesystemProvisionerStore } from "./extension-filesystem";
|
import { FilesystemProvisionerStore } from "./extension-filesystem";
|
||||||
import { installDeveloperTools } from "./developer-tools";
|
import { installDeveloperTools } from "./developer-tools";
|
||||||
import { LensProtocolRouterMain } from "./protocol-handler";
|
import { LensProtocolRouterMain } from "./protocol-handler";
|
||||||
import { getAppVersion, getAppVersionFromProxyServer } from "../common/utils";
|
import { disposer, getAppVersion, getAppVersionFromProxyServer } from "../common/utils";
|
||||||
import { bindBroadcastHandlers } from "../common/ipc";
|
import { bindBroadcastHandlers } from "../common/ipc";
|
||||||
import { startUpdateChecking } from "./app-updater";
|
import { startUpdateChecking } from "./app-updater";
|
||||||
import { IpcRendererNavigationEvents } from "../renderer/navigation/events";
|
import { IpcRendererNavigationEvents } from "../renderer/navigation/events";
|
||||||
import { CatalogPusher } from "./catalog-pusher";
|
import { pushCatalogToRenderer } from "./catalog-pusher";
|
||||||
import { catalogEntityRegistry } from "../common/catalog";
|
import { catalogEntityRegistry } from "./catalog";
|
||||||
import { HotbarStore } from "../common/hotbar-store";
|
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";
|
||||||
|
|
||||||
const workingDir = path.join(app.getPath("appData"), appName);
|
const workingDir = path.join(app.getPath("appData"), appName);
|
||||||
|
const cleanup = disposer();
|
||||||
|
|
||||||
app.setName(appName);
|
app.setName(appName);
|
||||||
|
|
||||||
@ -142,7 +143,7 @@ app.on("ready", async () => {
|
|||||||
const lensProxy = LensProxy.createInstance(handleWsUpgrade);
|
const lensProxy = LensProxy.createInstance(handleWsUpgrade);
|
||||||
|
|
||||||
ClusterManager.createInstance();
|
ClusterManager.createInstance();
|
||||||
KubeconfigSyncManager.createInstance().startSync();
|
KubeconfigSyncManager.createInstance();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
logger.info("🔌 Starting LensProxy");
|
logger.info("🔌 Starting LensProxy");
|
||||||
@ -187,7 +188,8 @@ app.on("ready", async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ipcMain.on(IpcRendererNavigationEvents.LOADED, () => {
|
ipcMain.on(IpcRendererNavigationEvents.LOADED, () => {
|
||||||
CatalogPusher.init(catalogEntityRegistry);
|
cleanup.push(pushCatalogToRenderer(catalogEntityRegistry));
|
||||||
|
KubeconfigSyncManager.getInstance().startSync();
|
||||||
startUpdateChecking();
|
startUpdateChecking();
|
||||||
LensProtocolRouterMain
|
LensProtocolRouterMain
|
||||||
.getInstance()
|
.getInstance()
|
||||||
@ -251,6 +253,7 @@ app.on("will-quit", (event) => {
|
|||||||
appEventBus.emit({name: "app", action: "close"});
|
appEventBus.emit({name: "app", action: "close"});
|
||||||
ClusterManager.getInstance(false)?.stop(); // close cluster connections
|
ClusterManager.getInstance(false)?.stop(); // close cluster connections
|
||||||
KubeconfigSyncManager.getInstance(false)?.stopSync();
|
KubeconfigSyncManager.getInstance(false)?.stopSync();
|
||||||
|
cleanup();
|
||||||
|
|
||||||
if (blockQuit) {
|
if (blockQuit) {
|
||||||
event.preventDefault(); // prevent app's default shutdown (e.g. required for telemetry, etc.)
|
event.preventDefault(); // prevent app's default shutdown (e.g. required for telemetry, etc.)
|
||||||
|
|||||||
@ -21,9 +21,9 @@
|
|||||||
|
|
||||||
import request, { RequestPromiseOptions } from "request-promise-native";
|
import request, { RequestPromiseOptions } from "request-promise-native";
|
||||||
import { apiKubePrefix } from "../common/vars";
|
import { apiKubePrefix } from "../common/vars";
|
||||||
import { IMetricsReqParams } from "../renderer/api/endpoints/metrics.api";
|
import type { IMetricsReqParams } from "../renderer/api/endpoints/metrics.api";
|
||||||
import { LensProxy } from "./proxy/lens-proxy";
|
import { LensProxy } from "./proxy/lens-proxy";
|
||||||
import { Cluster } from "./cluster";
|
import type { Cluster } from "./cluster";
|
||||||
|
|
||||||
export async function k8sRequest<T = any>(cluster: Cluster, path: string, options: RequestPromiseOptions = {}): Promise<T> {
|
export async function k8sRequest<T = any>(cluster: Cluster, path: string, options: RequestPromiseOptions = {}): Promise<T> {
|
||||||
const kubeProxyUrl = `http://localhost:${LensProxy.getInstance().port}${apiKubePrefix}`;
|
const kubeProxyUrl = `http://localhost:${LensProxy.getInstance().port}${apiKubePrefix}`;
|
||||||
|
|||||||
@ -71,6 +71,7 @@ export class KubeconfigManager {
|
|||||||
await this.contextHandler.ensureServer();
|
await this.contextHandler.ensureServer();
|
||||||
this.tempFile = await this.createProxyKubeconfig();
|
this.tempFile = await this.createProxyKubeconfig();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
logger.error(`Failed to created temp config for auth-proxy`, { err });
|
logger.error(`Failed to created temp config for auth-proxy`, { err });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,7 +87,7 @@ export class KubeconfigManager {
|
|||||||
protected async createProxyKubeconfig(): Promise<string> {
|
protected async createProxyKubeconfig(): Promise<string> {
|
||||||
const { configDir, cluster } = this;
|
const { configDir, cluster } = this;
|
||||||
const { contextName, kubeConfigPath, id } = cluster;
|
const { contextName, kubeConfigPath, id } = cluster;
|
||||||
const tempFile = path.join(configDir, `kubeconfig-${id}`);
|
const tempFile = path.normalize(path.join(configDir, `kubeconfig-${id}`));
|
||||||
const kubeConfig = loadConfig(kubeConfigPath);
|
const kubeConfig = loadConfig(kubeConfigPath);
|
||||||
const proxyConfig: Partial<KubeConfig> = {
|
const proxyConfig: Partial<KubeConfig> = {
|
||||||
currentContext: contextName,
|
currentContext: contextName,
|
||||||
|
|||||||
@ -25,7 +25,7 @@ import request from "request";
|
|||||||
import { ensureDir, pathExists } from "fs-extra";
|
import { ensureDir, pathExists } from "fs-extra";
|
||||||
import * as tar from "tar";
|
import * as tar from "tar";
|
||||||
import { isWindows } from "../common/vars";
|
import { isWindows } from "../common/vars";
|
||||||
import winston from "winston";
|
import type winston from "winston";
|
||||||
|
|
||||||
export type LensBinaryOpts = {
|
export type LensBinaryOpts = {
|
||||||
version: string;
|
version: string;
|
||||||
@ -204,7 +204,7 @@ export class LensBinary {
|
|||||||
throw(error);
|
throw(error);
|
||||||
});
|
});
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
file.on("close", () => {
|
file.on("close", () => {
|
||||||
this.logger.debug(`${this.originalBinaryName} binary download closed`);
|
this.logger.debug(`${this.originalBinaryName} binary download closed`);
|
||||||
if (!this.tarPath) fs.chmod(binaryPath, 0o755, (err) => {
|
if (!this.tarPath) fs.chmod(binaryPath, 0o755, (err) => {
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
import { app, BrowserWindow, dialog, ipcMain, IpcMainEvent, Menu, MenuItem, MenuItemConstructorOptions, webContents, shell } from "electron";
|
import { app, BrowserWindow, dialog, ipcMain, IpcMainEvent, Menu, MenuItem, MenuItemConstructorOptions, webContents, shell } from "electron";
|
||||||
import { autorun } from "mobx";
|
import { autorun } from "mobx";
|
||||||
import { WindowManager } from "./window-manager";
|
import type { WindowManager } from "./window-manager";
|
||||||
import { appName, isMac, isWindows, isTestEnv, docsUrl, supportUrl, productName } from "../common/vars";
|
import { appName, isMac, isWindows, isTestEnv, docsUrl, supportUrl, productName } from "../common/vars";
|
||||||
import { addClusterURL } from "../renderer/components/+add-cluster/add-cluster.route";
|
import { addClusterURL } from "../renderer/components/+add-cluster/add-cluster.route";
|
||||||
import { preferencesURL } from "../renderer/components/+preferences/preferences.route";
|
import { preferencesURL } from "../renderer/components/+preferences/preferences.route";
|
||||||
|
|||||||
@ -20,8 +20,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { PrometheusLens } from "./lens";
|
import { PrometheusLens } from "./lens";
|
||||||
import { CoreV1Api } from "@kubernetes/client-node";
|
import type { CoreV1Api } from "@kubernetes/client-node";
|
||||||
import { PrometheusService } from "./provider-registry";
|
import type { PrometheusService } from "./provider-registry";
|
||||||
import logger from "../logger";
|
import logger from "../logger";
|
||||||
|
|
||||||
export class PrometheusHelm extends PrometheusLens {
|
export class PrometheusHelm extends PrometheusLens {
|
||||||
@ -29,7 +29,7 @@ export class PrometheusHelm extends PrometheusLens {
|
|||||||
name = "Helm";
|
name = "Helm";
|
||||||
rateAccuracy = "5m";
|
rateAccuracy = "5m";
|
||||||
|
|
||||||
public async getPrometheusService(client: CoreV1Api): Promise<PrometheusService> {
|
public async getPrometheusService(client: CoreV1Api): Promise<PrometheusService | void> {
|
||||||
const labelSelector = "app=prometheus,component=server,heritage=Helm";
|
const labelSelector = "app=prometheus,component=server,heritage=Helm";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -19,8 +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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { PrometheusProvider, PrometheusQueryOpts, PrometheusQuery, PrometheusService } from "./provider-registry";
|
import type { PrometheusProvider, PrometheusQueryOpts, PrometheusQuery, PrometheusService } from "./provider-registry";
|
||||||
import { CoreV1Api } from "@kubernetes/client-node";
|
import type { CoreV1Api } from "@kubernetes/client-node";
|
||||||
import logger from "../logger";
|
import logger from "../logger";
|
||||||
|
|
||||||
export class PrometheusLens implements PrometheusProvider {
|
export class PrometheusLens implements PrometheusProvider {
|
||||||
@ -28,7 +28,7 @@ export class PrometheusLens implements PrometheusProvider {
|
|||||||
name = "Lens";
|
name = "Lens";
|
||||||
rateAccuracy = "1m";
|
rateAccuracy = "1m";
|
||||||
|
|
||||||
public async getPrometheusService(client: CoreV1Api): Promise<PrometheusService> {
|
public async getPrometheusService(client: CoreV1Api): Promise<PrometheusService | void> {
|
||||||
try {
|
try {
|
||||||
const resp = await client.readNamespacedService("prometheus", "lens-metrics");
|
const resp = await client.readNamespacedService("prometheus", "lens-metrics");
|
||||||
const service = resp.body;
|
const service = resp.body;
|
||||||
@ -44,7 +44,7 @@ export class PrometheusLens implements PrometheusProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public getQueries(opts: PrometheusQueryOpts): PrometheusQuery {
|
public getQueries(opts: PrometheusQueryOpts): PrometheusQuery | void {
|
||||||
switch(opts.category) {
|
switch(opts.category) {
|
||||||
case "cluster":
|
case "cluster":
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -19,8 +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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { PrometheusProvider, PrometheusQueryOpts, PrometheusQuery, PrometheusService } from "./provider-registry";
|
import type { PrometheusProvider, PrometheusQueryOpts, PrometheusQuery, PrometheusService } from "./provider-registry";
|
||||||
import { CoreV1Api, V1Service } from "@kubernetes/client-node";
|
import type { CoreV1Api, V1Service } from "@kubernetes/client-node";
|
||||||
import logger from "../logger";
|
import logger from "../logger";
|
||||||
|
|
||||||
export class PrometheusOperator implements PrometheusProvider {
|
export class PrometheusOperator implements PrometheusProvider {
|
||||||
@ -28,7 +28,7 @@ export class PrometheusOperator implements PrometheusProvider {
|
|||||||
id = "operator";
|
id = "operator";
|
||||||
name = "Prometheus Operator";
|
name = "Prometheus Operator";
|
||||||
|
|
||||||
public async getPrometheusService(client: CoreV1Api): Promise<PrometheusService> {
|
public async getPrometheusService(client: CoreV1Api): Promise<PrometheusService | void> {
|
||||||
try {
|
try {
|
||||||
let service: V1Service;
|
let service: V1Service;
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ export class PrometheusOperator implements PrometheusProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public getQueries(opts: PrometheusQueryOpts): PrometheusQuery {
|
public getQueries(opts: PrometheusQueryOpts): PrometheusQuery | void {
|
||||||
switch(opts.category) {
|
switch(opts.category) {
|
||||||
case "cluster":
|
case "cluster":
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -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 { CoreV1Api } from "@kubernetes/client-node";
|
import type { CoreV1Api } from "@kubernetes/client-node";
|
||||||
|
|
||||||
export type PrometheusClusterQuery = {
|
export type PrometheusClusterQuery = {
|
||||||
memoryUsage: string;
|
memoryUsage: string;
|
||||||
@ -83,8 +83,8 @@ export type PrometheusService = {
|
|||||||
export interface PrometheusProvider {
|
export interface PrometheusProvider {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
getQueries(opts: PrometheusQueryOpts): PrometheusQuery;
|
getQueries(opts: PrometheusQueryOpts): PrometheusQuery | void;
|
||||||
getPrometheusService(client: CoreV1Api): Promise<PrometheusService>;
|
getPrometheusService(client: CoreV1Api): Promise<PrometheusService | void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PrometheusProviderList = {
|
export type PrometheusProviderList = {
|
||||||
|
|||||||
@ -19,8 +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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { PrometheusProvider, PrometheusQueryOpts, PrometheusQuery, PrometheusService } from "./provider-registry";
|
import type { PrometheusProvider, PrometheusQueryOpts, PrometheusQuery, PrometheusService } from "./provider-registry";
|
||||||
import { CoreV1Api } from "@kubernetes/client-node";
|
import type { CoreV1Api } from "@kubernetes/client-node";
|
||||||
import logger from "../logger";
|
import logger from "../logger";
|
||||||
|
|
||||||
export class PrometheusStacklight implements PrometheusProvider {
|
export class PrometheusStacklight implements PrometheusProvider {
|
||||||
@ -28,7 +28,7 @@ export class PrometheusStacklight implements PrometheusProvider {
|
|||||||
name = "Stacklight";
|
name = "Stacklight";
|
||||||
rateAccuracy = "1m";
|
rateAccuracy = "1m";
|
||||||
|
|
||||||
public async getPrometheusService(client: CoreV1Api): Promise<PrometheusService> {
|
public async getPrometheusService(client: CoreV1Api): Promise<PrometheusService | void> {
|
||||||
try {
|
try {
|
||||||
const resp = await client.readNamespacedService("prometheus-server", "stacklight");
|
const resp = await client.readNamespacedService("prometheus-server", "stacklight");
|
||||||
const service = resp.body;
|
const service = resp.body;
|
||||||
@ -44,7 +44,7 @@ export class PrometheusStacklight implements PrometheusProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public getQueries(opts: PrometheusQueryOpts): PrometheusQuery {
|
public getQueries(opts: PrometheusQueryOpts): PrometheusQuery | void {
|
||||||
switch(opts.category) {
|
switch(opts.category) {
|
||||||
case "cluster":
|
case "cluster":
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
import logger from "../logger";
|
import logger from "../logger";
|
||||||
import * as proto from "../../common/protocol-handler";
|
import * as proto from "../../common/protocol-handler";
|
||||||
import Url from "url-parse";
|
import Url from "url-parse";
|
||||||
import { 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 } from "mobx";
|
||||||
|
|
||||||
|
|||||||
@ -21,3 +21,5 @@
|
|||||||
|
|
||||||
// Don't export the contents here
|
// Don't export the contents here
|
||||||
// It will break the extension webpack
|
// It will break the extension webpack
|
||||||
|
|
||||||
|
export default {};
|
||||||
|
|||||||
@ -20,13 +20,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import net from "net";
|
import net from "net";
|
||||||
import http from "http";
|
import type http from "http";
|
||||||
import spdy from "spdy";
|
import spdy from "spdy";
|
||||||
import httpProxy from "http-proxy";
|
import httpProxy from "http-proxy";
|
||||||
import url from "url";
|
import url from "url";
|
||||||
import { apiPrefix, apiKubePrefix } from "../../common/vars";
|
import { apiPrefix, apiKubePrefix } from "../../common/vars";
|
||||||
import { Router } from "../router";
|
import { Router } from "../router";
|
||||||
import { ContextHandler } from "../context-handler";
|
import type { ContextHandler } from "../context-handler";
|
||||||
import logger from "../logger";
|
import logger from "../logger";
|
||||||
import { Singleton } from "../../common/utils";
|
import { Singleton } from "../../common/utils";
|
||||||
import { ClusterManager } from "../cluster-manager";
|
import { ClusterManager } from "../cluster-manager";
|
||||||
@ -205,13 +205,13 @@ export class LensProxy extends Singleton {
|
|||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async getProxyTarget(req: http.IncomingMessage, contextHandler: ContextHandler): Promise<httpProxy.ServerOptions> {
|
protected async getProxyTarget(req: http.IncomingMessage, contextHandler: ContextHandler): Promise<httpProxy.ServerOptions | void> {
|
||||||
if (req.url.startsWith(apiKubePrefix)) {
|
if (req.url.startsWith(apiKubePrefix)) {
|
||||||
delete req.headers.authorization;
|
delete req.headers.authorization;
|
||||||
req.url = req.url.replace(apiKubePrefix, "");
|
req.url = req.url.replace(apiKubePrefix, "");
|
||||||
const isWatchRequest = req.url.includes("watch=");
|
const isWatchRequest = req.url.includes("watch=");
|
||||||
|
|
||||||
return await contextHandler.getApiTarget(isWatchRequest);
|
return contextHandler.getApiTarget(isWatchRequest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -26,8 +26,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import * as WebSocket from "ws";
|
import * as WebSocket from "ws";
|
||||||
import http from "http";
|
import type http from "http";
|
||||||
import net from "net";
|
import type net from "net";
|
||||||
import url from "url";
|
import url from "url";
|
||||||
import { NodeShellSession, LocalShellSession } from "../shell-session";
|
import { NodeShellSession, LocalShellSession } from "../shell-session";
|
||||||
import { ClusterManager } from "../cluster-manager";
|
import { ClusterManager } from "../cluster-manager";
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import type { Cluster } from "./cluster";
|
import type { Cluster } from "./cluster";
|
||||||
import { KubernetesObject } from "@kubernetes/client-node";
|
import type { KubernetesObject } from "@kubernetes/client-node";
|
||||||
import { exec } from "child_process";
|
import { exec } from "child_process";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import * as yaml from "js-yaml";
|
import * as yaml from "js-yaml";
|
||||||
|
|||||||
@ -21,10 +21,10 @@
|
|||||||
|
|
||||||
import Call from "@hapi/call";
|
import Call from "@hapi/call";
|
||||||
import Subtext from "@hapi/subtext";
|
import Subtext from "@hapi/subtext";
|
||||||
import http from "http";
|
import type http from "http";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { readFile } from "fs-extra";
|
import { readFile } from "fs-extra";
|
||||||
import { Cluster } from "./cluster";
|
import type { Cluster } from "./cluster";
|
||||||
import { apiPrefix, appName, publicPath, isDevelopment, webpackDevServerPort } from "../common/vars";
|
import { apiPrefix, appName, publicPath, isDevelopment, webpackDevServerPort } from "../common/vars";
|
||||||
import { HelmApiRoute, KubeconfigRoute, MetricsRoute, PortForwardRoute, ResourceApplierApiRoute, VersionRoute } from "./routes";
|
import { HelmApiRoute, KubeconfigRoute, MetricsRoute, PortForwardRoute, ResourceApplierApiRoute, VersionRoute } from "./routes";
|
||||||
import logger from "./logger";
|
import logger from "./logger";
|
||||||
|
|||||||
@ -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 { LensApiRequest } from "../router";
|
import type { LensApiRequest } from "../router";
|
||||||
import { helmService } from "../helm/helm-service";
|
import { helmService } from "../helm/helm-service";
|
||||||
import { respondJson, respondText } from "../utils/http-responses";
|
import { respondJson, respondText } from "../utils/http-responses";
|
||||||
import logger from "../logger";
|
import logger from "../logger";
|
||||||
|
|||||||
@ -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 { LensApiRequest } from "../router";
|
import type { LensApiRequest } from "../router";
|
||||||
import { respondJson } from "../utils/http-responses";
|
import { respondJson } from "../utils/http-responses";
|
||||||
import { Cluster } from "../cluster";
|
import type { Cluster } from "../cluster";
|
||||||
import { CoreV1Api, V1Secret } from "@kubernetes/client-node";
|
import { CoreV1Api, V1Secret } from "@kubernetes/client-node";
|
||||||
|
|
||||||
function generateKubeConfig(username: string, secret: V1Secret, cluster: Cluster) {
|
function generateKubeConfig(username: string, secret: V1Secret, cluster: Cluster) {
|
||||||
|
|||||||
@ -20,10 +20,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import { LensApiRequest } from "../router";
|
import type { LensApiRequest } from "../router";
|
||||||
import { respondJson } from "../utils/http-responses";
|
import { respondJson } from "../utils/http-responses";
|
||||||
import { Cluster, ClusterMetadataKey } from "../cluster";
|
import { Cluster, ClusterMetadataKey } from "../cluster";
|
||||||
import { ClusterPrometheusMetadata } from "../../common/cluster-store";
|
import type { ClusterPrometheusMetadata } from "../../common/cluster-store";
|
||||||
import logger from "../logger";
|
import logger from "../logger";
|
||||||
import { getMetrics } from "../k8s-request";
|
import { getMetrics } from "../k8s-request";
|
||||||
|
|
||||||
|
|||||||
@ -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 { LensApiRequest } from "../router";
|
import type { LensApiRequest } from "../router";
|
||||||
import { spawn, ChildProcessWithoutNullStreams } from "child_process";
|
import { spawn, ChildProcessWithoutNullStreams } from "child_process";
|
||||||
import { Kubectl } from "../kubectl";
|
import { Kubectl } from "../kubectl";
|
||||||
import { shell } from "electron";
|
import { shell } from "electron";
|
||||||
|
|||||||
@ -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 { LensApiRequest } from "../router";
|
import type { LensApiRequest } from "../router";
|
||||||
import { respondJson, respondText } from "../utils/http-responses";
|
import { respondJson, respondText } from "../utils/http-responses";
|
||||||
import { ResourceApplier } from "../resource-applier";
|
import { ResourceApplier } from "../resource-applier";
|
||||||
|
|
||||||
|
|||||||
@ -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 { LensApiRequest } from "../router";
|
import type { LensApiRequest } from "../router";
|
||||||
import { respondJson } from "../utils/http-responses";
|
import { respondJson } from "../utils/http-responses";
|
||||||
import { getAppVersion } from "../../common/utils";
|
import { getAppVersion } from "../../common/utils";
|
||||||
|
|
||||||
|
|||||||
@ -19,11 +19,11 @@
|
|||||||
* 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 * as WebSocket from "ws";
|
import type * as WebSocket from "ws";
|
||||||
import { v4 as uuid } from "uuid";
|
import { v4 as uuid } from "uuid";
|
||||||
import * as k8s from "@kubernetes/client-node";
|
import * as k8s from "@kubernetes/client-node";
|
||||||
import { KubeConfig } from "@kubernetes/client-node";
|
import type { KubeConfig } from "@kubernetes/client-node";
|
||||||
import { Cluster } from "../cluster";
|
import type { Cluster } from "../cluster";
|
||||||
import { ShellOpenError, ShellSession } from "./shell-session";
|
import { ShellOpenError, ShellSession } from "./shell-session";
|
||||||
|
|
||||||
export class NodeShellSession extends ShellSession {
|
export class NodeShellSession extends ShellSession {
|
||||||
|
|||||||
@ -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 { Cluster } from "../cluster";
|
import type { Cluster } from "../cluster";
|
||||||
import { Kubectl } from "../kubectl";
|
import { Kubectl } from "../kubectl";
|
||||||
import * as WebSocket from "ws";
|
import type * as WebSocket from "ws";
|
||||||
import shellEnv from "shell-env";
|
import shellEnv from "shell-env";
|
||||||
import { app } from "electron";
|
import { app } from "electron";
|
||||||
import { clearKubeconfigEnvVars } from "../utils/clear-kube-env-vars";
|
import { clearKubeconfigEnvVars } from "../utils/clear-kube-env-vars";
|
||||||
|
|||||||
@ -25,7 +25,7 @@ import { Menu, Tray } from "electron";
|
|||||||
import { autorun } from "mobx";
|
import { autorun } from "mobx";
|
||||||
import { showAbout } from "./menu";
|
import { showAbout } from "./menu";
|
||||||
import { checkForUpdates, isAutoUpdateEnabled } from "./app-updater";
|
import { checkForUpdates, isAutoUpdateEnabled } from "./app-updater";
|
||||||
import { WindowManager } from "./window-manager";
|
import type { WindowManager } from "./window-manager";
|
||||||
import { preferencesURL } from "../renderer/components/+preferences/preferences.route";
|
import { preferencesURL } from "../renderer/components/+preferences/preferences.route";
|
||||||
import logger from "./logger";
|
import logger from "./logger";
|
||||||
import { isDevelopment, isWindows, productName } from "../common/vars";
|
import { isDevelopment, isWindows, productName } from "../common/vars";
|
||||||
|
|||||||
@ -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 { Readable } from "stream";
|
import type { Readable } from "stream";
|
||||||
import URLParse from "url-parse";
|
import URLParse from "url-parse";
|
||||||
|
|
||||||
interface GetPortArgs {
|
interface GetPortArgs {
|
||||||
|
|||||||
@ -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 http from "http";
|
import type http from "http";
|
||||||
|
|
||||||
export function respondJson(res: http.ServerResponse, content: any, status = 200) {
|
export function respondJson(res: http.ServerResponse, content: any, status = 200) {
|
||||||
respond(res, JSON.stringify(content), "application/json", status);
|
respond(res, JSON.stringify(content), "application/json", status);
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
// Fix embedded kubeconfig paths under snap config
|
// Fix embedded kubeconfig paths under snap config
|
||||||
|
|
||||||
import { migration } from "../migration-wrapper";
|
import { migration } from "../migration-wrapper";
|
||||||
import { ClusterModel } from "../../common/cluster-store";
|
import type { ClusterModel } from "../../common/cluster-store";
|
||||||
import { getAppVersion } from "../../common/utils/app-version";
|
import { getAppVersion } from "../../common/utils/app-version";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Cleans up a store that had the state related data stored
|
// Cleans up a store that had the state related data stored
|
||||||
import { Hotbar } from "../../common/hotbar-store";
|
import type { Hotbar } from "../../common/hotbar-store";
|
||||||
import { ClusterStore } from "../../common/cluster-store";
|
import { ClusterStore } from "../../common/cluster-store";
|
||||||
import { migration } from "../migration-wrapper";
|
import { migration } from "../migration-wrapper";
|
||||||
import { v4 as uuid } from "uuid";
|
import { v4 as uuid } from "uuid";
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Cleans up a store that had the state related data stored
|
// Cleans up a store that had the state related data stored
|
||||||
import { Hotbar } from "../../common/hotbar-store";
|
import type { Hotbar } from "../../common/hotbar-store";
|
||||||
import { migration } from "../migration-wrapper";
|
import { migration } from "../migration-wrapper";
|
||||||
import * as uuid from "uuid";
|
import * as uuid from "uuid";
|
||||||
|
|
||||||
|
|||||||
@ -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 Config from "conf";
|
import type Config from "conf";
|
||||||
import { isTestEnv } from "../common/vars";
|
import { isTestEnv } from "../common/vars";
|
||||||
|
|
||||||
export interface MigrationOpts {
|
export interface MigrationOpts {
|
||||||
|
|||||||
@ -22,11 +22,18 @@
|
|||||||
import { CatalogEntityRegistry } from "../catalog-entity-registry";
|
import { CatalogEntityRegistry } from "../catalog-entity-registry";
|
||||||
import "../../../common/catalog-entities";
|
import "../../../common/catalog-entities";
|
||||||
import { catalogCategoryRegistry } from "../../../common/catalog/catalog-category-registry";
|
import { catalogCategoryRegistry } from "../../../common/catalog/catalog-category-registry";
|
||||||
|
import type { CatalogEntityData, CatalogEntityKindData } from "../catalog-entity";
|
||||||
|
|
||||||
|
class TestCatalogEntityRegistry extends CatalogEntityRegistry {
|
||||||
|
replaceItems(items: Array<CatalogEntityData & CatalogEntityKindData>) {
|
||||||
|
this.rawItems.replace(items);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
describe("CatalogEntityRegistry", () => {
|
describe("CatalogEntityRegistry", () => {
|
||||||
describe("updateItems", () => {
|
describe("updateItems", () => {
|
||||||
it("adds new catalog item", () => {
|
it("adds new catalog item", () => {
|
||||||
const catalog = new CatalogEntityRegistry(catalogCategoryRegistry);
|
const catalog = new TestCatalogEntityRegistry(catalogCategoryRegistry);
|
||||||
const items = [{
|
const items = [{
|
||||||
apiVersion: "entity.k8slens.dev/v1alpha1",
|
apiVersion: "entity.k8slens.dev/v1alpha1",
|
||||||
kind: "KubernetesCluster",
|
kind: "KubernetesCluster",
|
||||||
@ -42,7 +49,7 @@ describe("CatalogEntityRegistry", () => {
|
|||||||
spec: {}
|
spec: {}
|
||||||
}];
|
}];
|
||||||
|
|
||||||
catalog.updateItems(items);
|
catalog.replaceItems(items);
|
||||||
expect(catalog.items.length).toEqual(1);
|
expect(catalog.items.length).toEqual(1);
|
||||||
|
|
||||||
items.push({
|
items.push({
|
||||||
@ -60,12 +67,12 @@ describe("CatalogEntityRegistry", () => {
|
|||||||
spec: {}
|
spec: {}
|
||||||
});
|
});
|
||||||
|
|
||||||
catalog.updateItems(items);
|
catalog.replaceItems(items);
|
||||||
expect(catalog.items.length).toEqual(2);
|
expect(catalog.items.length).toEqual(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("updates existing items", () => {
|
it("updates existing items", () => {
|
||||||
const catalog = new CatalogEntityRegistry(catalogCategoryRegistry);
|
const catalog = new TestCatalogEntityRegistry(catalogCategoryRegistry);
|
||||||
const items = [{
|
const items = [{
|
||||||
apiVersion: "entity.k8slens.dev/v1alpha1",
|
apiVersion: "entity.k8slens.dev/v1alpha1",
|
||||||
kind: "KubernetesCluster",
|
kind: "KubernetesCluster",
|
||||||
@ -81,19 +88,19 @@ describe("CatalogEntityRegistry", () => {
|
|||||||
spec: {}
|
spec: {}
|
||||||
}];
|
}];
|
||||||
|
|
||||||
catalog.updateItems(items);
|
catalog.replaceItems(items);
|
||||||
expect(catalog.items.length).toEqual(1);
|
expect(catalog.items.length).toEqual(1);
|
||||||
expect(catalog.items[0].status.phase).toEqual("disconnected");
|
expect(catalog.items[0].status.phase).toEqual("disconnected");
|
||||||
|
|
||||||
items[0].status.phase = "connected";
|
items[0].status.phase = "connected";
|
||||||
|
|
||||||
catalog.updateItems(items);
|
catalog.replaceItems(items);
|
||||||
expect(catalog.items.length).toEqual(1);
|
expect(catalog.items.length).toEqual(1);
|
||||||
expect(catalog.items[0].status.phase).toEqual("connected");
|
expect(catalog.items[0].status.phase).toEqual("connected");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("removes deleted items", () => {
|
it("removes deleted items", () => {
|
||||||
const catalog = new CatalogEntityRegistry(catalogCategoryRegistry);
|
const catalog = new TestCatalogEntityRegistry(catalogCategoryRegistry);
|
||||||
const items = [
|
const items = [
|
||||||
{
|
{
|
||||||
apiVersion: "entity.k8slens.dev/v1alpha1",
|
apiVersion: "entity.k8slens.dev/v1alpha1",
|
||||||
@ -125,11 +132,51 @@ describe("CatalogEntityRegistry", () => {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
catalog.updateItems(items);
|
catalog.replaceItems(items);
|
||||||
items.splice(0, 1);
|
items.splice(0, 1);
|
||||||
catalog.updateItems(items);
|
catalog.replaceItems(items);
|
||||||
expect(catalog.items.length).toEqual(1);
|
expect(catalog.items.length).toEqual(1);
|
||||||
expect(catalog.items[0].metadata.uid).toEqual("456");
|
expect(catalog.items[0].metadata.uid).toEqual("456");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("items", () => {
|
||||||
|
it("does not return items without matching category", () => {
|
||||||
|
const catalog = new TestCatalogEntityRegistry(catalogCategoryRegistry);
|
||||||
|
const items = [
|
||||||
|
{
|
||||||
|
apiVersion: "entity.k8slens.dev/v1alpha1",
|
||||||
|
kind: "KubernetesCluster",
|
||||||
|
metadata: {
|
||||||
|
uid: "123",
|
||||||
|
name: "foobar",
|
||||||
|
source: "test",
|
||||||
|
labels: {}
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
phase: "disconnected"
|
||||||
|
},
|
||||||
|
spec: {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
apiVersion: "entity.k8slens.dev/v1alpha1",
|
||||||
|
kind: "FooBar",
|
||||||
|
metadata: {
|
||||||
|
uid: "456",
|
||||||
|
name: "barbaz",
|
||||||
|
source: "test",
|
||||||
|
labels: {}
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
phase: "disconnected"
|
||||||
|
},
|
||||||
|
spec: {}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
catalog.replaceItems(items);
|
||||||
|
|
||||||
|
expect(catalog.items.length).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { CustomResourceDefinition } from "../endpoints";
|
import { CustomResourceDefinition } from "../endpoints";
|
||||||
import { IKubeObjectMetadata } from "../kube-object";
|
import type { IKubeObjectMetadata } from "../kube-object";
|
||||||
|
|
||||||
describe("Crds", () => {
|
describe("Crds", () => {
|
||||||
describe("getVersion", () => {
|
describe("getVersion", () => {
|
||||||
|
|||||||
@ -19,26 +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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { action, observable } from "mobx";
|
import { computed, observable } from "mobx";
|
||||||
import { broadcastMessage, 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";
|
||||||
|
import { iter } from "../utils";
|
||||||
|
|
||||||
export class CatalogEntityRegistry {
|
export class CatalogEntityRegistry {
|
||||||
@observable protected _items: CatalogEntity[] = observable.array([], { 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) {}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
subscribeToBroadcast("catalog:items", (ev, items: (CatalogEntityData & CatalogEntityKindData)[]) => {
|
subscribeToBroadcast("catalog:items", (ev, items: (CatalogEntityData & CatalogEntityKindData)[]) => {
|
||||||
this.updateItems(items);
|
this.rawItems.replace(items);
|
||||||
});
|
});
|
||||||
broadcastMessage("catalog:broadcast");
|
|
||||||
}
|
|
||||||
|
|
||||||
@action updateItems(items: (CatalogEntityData & CatalogEntityKindData)[]) {
|
|
||||||
this._items = items.map(data => this.categoryRegistry.getEntityForData(data));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
set activeEntity(entity: CatalogEntity) {
|
set activeEntity(entity: CatalogEntity) {
|
||||||
@ -49,23 +45,27 @@ export class CatalogEntityRegistry {
|
|||||||
return this._activeEntity;
|
return this._activeEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
get items() {
|
@computed get items() {
|
||||||
return this._items;
|
return Array.from(iter.filterMap(this.rawItems, rawItem => this.categoryRegistry.getEntityForData(rawItem)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@computed get entities(): Map<string, CatalogEntity> {
|
||||||
|
return new Map(this.items.map(item => [item.metadata.uid, item]));
|
||||||
}
|
}
|
||||||
|
|
||||||
getById(id: string) {
|
getById(id: string) {
|
||||||
return this._items.find((entity) => entity.metadata.uid === id);
|
return this.entities.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
getItemsForApiKind<T extends CatalogEntity>(apiVersion: string, kind: string): T[] {
|
getItemsForApiKind<T extends CatalogEntity>(apiVersion: string, kind: string): T[] {
|
||||||
const items = this._items.filter((item) => item.apiVersion === apiVersion && item.kind === kind);
|
const items = this.items.filter((item) => item.apiVersion === apiVersion && item.kind === kind);
|
||||||
|
|
||||||
return items as T[];
|
return items as T[];
|
||||||
}
|
}
|
||||||
|
|
||||||
getItemsForCategory<T extends CatalogEntity>(category: CatalogCategory): T[] {
|
getItemsForCategory<T extends CatalogEntity>(category: CatalogCategory): T[] {
|
||||||
const supportedVersions = category.spec.versions.map((v) => `${category.spec.group}/${v.name}`);
|
const supportedVersions = category.spec.versions.map((v) => `${category.spec.group}/${v.name}`);
|
||||||
const items = this._items.filter((item) => supportedVersions.includes(item.apiVersion) && item.kind === category.spec.names.kind);
|
const items = this.items.filter((item) => supportedVersions.includes(item.apiVersion) && item.kind === category.spec.names.kind);
|
||||||
|
|
||||||
return items as T[];
|
return items as T[];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,18 +21,17 @@
|
|||||||
|
|
||||||
import { navigate } from "../navigation";
|
import { navigate } from "../navigation";
|
||||||
import { commandRegistry } from "../../extensions/registries";
|
import { commandRegistry } from "../../extensions/registries";
|
||||||
import { CatalogEntity } from "../../common/catalog";
|
import type { CatalogEntity } from "../../common/catalog";
|
||||||
|
|
||||||
export {
|
export { CatalogCategory, CatalogEntity } from "../../common/catalog";
|
||||||
CatalogCategory,
|
export type {
|
||||||
CatalogEntity,
|
|
||||||
CatalogEntityData,
|
CatalogEntityData,
|
||||||
CatalogEntityKindData,
|
CatalogEntityKindData,
|
||||||
CatalogEntityActionContext,
|
CatalogEntityActionContext,
|
||||||
CatalogEntityAddMenuContext,
|
CatalogEntityAddMenuContext,
|
||||||
CatalogEntityAddMenu,
|
CatalogEntityAddMenu,
|
||||||
CatalogEntityContextMenu,
|
CatalogEntityContextMenu,
|
||||||
CatalogEntityContextMenuContext
|
CatalogEntityContextMenuContext,
|
||||||
} from "../../common/catalog";
|
} from "../../common/catalog";
|
||||||
|
|
||||||
export const catalogEntityRunContext = {
|
export const catalogEntityRunContext = {
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { KubeObject } from "../kube-object";
|
import { KubeObject } from "../kube-object";
|
||||||
import { 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";
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { KubeObject } from "../kube-object";
|
import { KubeObject } from "../kube-object";
|
||||||
import { 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";
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import get from "lodash/get";
|
import get from "lodash/get";
|
||||||
import { 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";
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user