mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Merge branch 'master' into monorepo
Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
commit
e90d269abb
294 files changed
+3337
-2864
No files matched your search
@@ -43,7 +43,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
@@ -54,7 +54,7 @@ jobs:
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
@@ -68,4 +68,4 @@ jobs:
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
uses: github/codeql-action/analyze@v2
|
||||
@@ -30,6 +30,7 @@ jobs:
|
||||
commit: master
|
||||
tag: ${{ steps.tagger.outputs.tagname }}
|
||||
body: ${{ github.event.pull_request.body }}
|
||||
prerelease: ${{ endsWith(steps.tagger.outputs.tagname, '-alpha') || endsWith(steps.tagger.outputs.tagname, '-beta') }}
|
||||
publish-npm:
|
||||
uses: ./.github/workflows/publish-release-npm.yml
|
||||
needs: release
|
||||
|
||||
+11
-16
@@ -3,7 +3,7 @@
|
||||
"productName": "OpenLens",
|
||||
"description": "OpenLens - Open Source IDE for Kubernetes",
|
||||
"homepage": "https://github.com/lensapp/lens",
|
||||
"version": "6.4.0-alpha.2",
|
||||
"version": "6.4.0-alpha.4",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/lensapp/lens.git"
|
||||
@@ -133,12 +133,12 @@
|
||||
"history": "^4.10.1",
|
||||
"hpagent": "^1.2.0",
|
||||
"http-proxy": "^1.18.1",
|
||||
"immer": "^9.0.17",
|
||||
"immer": "^9.0.18",
|
||||
"joi": "^17.7.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"jsdom": "^16.7.0",
|
||||
"lodash": "^4.17.15",
|
||||
"marked": "^4.2.5",
|
||||
"marked": "^4.2.12",
|
||||
"md5-file": "^5.0.0",
|
||||
"mobx": "^6.7.0",
|
||||
"mobx-observable-history": "^2.0.3",
|
||||
@@ -158,8 +158,6 @@
|
||||
"react-router": "^5.3.4",
|
||||
"react-virtualized-auto-sizer": "^1.0.7",
|
||||
"readable-stream": "^3.6.0",
|
||||
"request": "^2.88.2",
|
||||
"request-promise-native": "^1.0.9",
|
||||
"rfc6902": "^5.0.1",
|
||||
"selfsigned": "^2.1.1",
|
||||
"semver": "^7.3.8",
|
||||
@@ -183,7 +181,7 @@
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.10",
|
||||
"@sentry/types": "^6.19.7",
|
||||
"@swc/cli": "^0.1.59",
|
||||
"@swc/core": "^1.3.26",
|
||||
"@swc/core": "^1.3.27",
|
||||
"@swc/jest": "^0.2.24",
|
||||
"@testing-library/dom": "^7.31.2",
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
@@ -226,8 +224,6 @@
|
||||
"@types/react-virtualized-auto-sizer": "^1.0.1",
|
||||
"@types/react-window": "^1.8.5",
|
||||
"@types/readable-stream": "^2.3.13",
|
||||
"@types/request": "^2.48.7",
|
||||
"@types/request-promise-native": "^1.0.18",
|
||||
"@types/semver": "^7.3.13",
|
||||
"@types/sharp": "^0.31.1",
|
||||
"@types/tar": "^6.1.3",
|
||||
@@ -241,8 +237,8 @@
|
||||
"@types/webpack-dev-server": "^4.7.2",
|
||||
"@types/webpack-env": "^1.18.0",
|
||||
"@types/webpack-node-externals": "^2.5.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.48.1",
|
||||
"@typescript-eslint/parser": "^5.48.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.48.2",
|
||||
"@typescript-eslint/parser": "^5.48.2",
|
||||
"adr": "^1.4.3",
|
||||
"ansi_up": "^5.1.0",
|
||||
"chalk": "^4.1.2",
|
||||
@@ -258,13 +254,13 @@
|
||||
"electron": "^19.1.9",
|
||||
"electron-builder": "^23.6.0",
|
||||
"electron-notarize": "^0.3.0",
|
||||
"esbuild": "^0.16.17",
|
||||
"esbuild-loader": "^2.20.0",
|
||||
"eslint": "^8.31.0",
|
||||
"esbuild": "^0.17.3",
|
||||
"esbuild-loader": "^2.21.0",
|
||||
"eslint": "^8.32.0",
|
||||
"eslint-import-resolver-typescript": "^3.5.3",
|
||||
"eslint-plugin-header": "^3.1.1",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-react": "7.32.0",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-react": "^7.32.1",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-unused-imports": "^2.0.0",
|
||||
"fork-ts-checker-webpack-plugin": "^6.5.2",
|
||||
@@ -332,7 +328,6 @@
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"@types/react-virtualized-auto-sizer": "^1.0.1",
|
||||
"@types/react-window": "^1.8.5",
|
||||
"@types/request-promise-native": "^1.0.18",
|
||||
"@types/tar": "^6.1.3",
|
||||
"@types/tcp-port-used": "^1.0.1",
|
||||
"@types/url-parse": "^1.4.8",
|
||||
|
||||
@@ -8,7 +8,7 @@ import { CatalogEntity, CatalogCategory, categoryVersion } from "../catalog/cata
|
||||
import { broadcastMessage } from "../ipc";
|
||||
import { app } from "electron";
|
||||
import type { CatalogEntityConstructor, CatalogEntitySpec } from "../catalog/catalog-entity";
|
||||
import { IpcRendererNavigationEvents } from "../../renderer/navigation/events";
|
||||
import { IpcRendererNavigationEvents } from "../ipc/navigation-events";
|
||||
import { requestClusterActivation, requestClusterDisconnection } from "../../renderer/ipc";
|
||||
import KubeClusterCategoryIcon from "./icons/kubernetes.svg";
|
||||
import getClusterByIdInjectable from "../cluster-store/get-by-id.injectable";
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { action, comparer, computed, makeObservable, observable, reaction, when } from "mobx";
|
||||
import { action, comparer, computed, makeObservable, observable, reaction, runInAction, when } from "mobx";
|
||||
import type { ClusterContextHandler } from "../../main/context-handler/context-handler";
|
||||
import type { KubeConfig } from "@kubernetes/client-node";
|
||||
import { HttpError } from "@kubernetes/client-node";
|
||||
@@ -11,13 +11,10 @@ import type { Kubectl } from "../../main/kubectl/kubectl";
|
||||
import type { KubeconfigManager } from "../../main/kubeconfig-manager/kubeconfig-manager";
|
||||
import type { KubeApiResource, KubeApiResourceDescriptor } from "../rbac";
|
||||
import { formatKubeApiResource } from "../rbac";
|
||||
import type { VersionDetector } from "../../main/cluster-detectors/version-detector";
|
||||
import type { DetectorRegistry } from "../../main/cluster-detectors/detector-registry";
|
||||
import plimit from "p-limit";
|
||||
import type { ClusterState, ClusterMetricsResourceType, ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences, ClusterPrometheusPreferences, UpdateClusterModel, KubeAuthUpdate, ClusterConfigData } from "../cluster-types";
|
||||
import { ClusterMetadataKey, initialNodeShellImage, ClusterStatus, clusterModelIdChecker, updateClusterModelChecker } from "../cluster-types";
|
||||
import { disposer, isDefined, isRequestError, toJS } from "../utils";
|
||||
import type { Response } from "request";
|
||||
import { clusterListNamespaceForbiddenChannel } from "../ipc/cluster";
|
||||
import type { CanI } from "./authorization-review.injectable";
|
||||
import type { ListNamespaces } from "./list-namespaces.injectable";
|
||||
@@ -27,11 +24,14 @@ import type { BroadcastMessage } from "../ipc/broadcast-message.injectable";
|
||||
import type { LoadConfigfromFile } from "../kube-helpers/load-config-from-file.injectable";
|
||||
import type { CanListResource, RequestNamespaceListPermissions, RequestNamespaceListPermissionsFor } from "./request-namespace-list-permissions.injectable";
|
||||
import type { RequestApiResources } from "../../main/cluster/request-api-resources.injectable";
|
||||
import type { DetectClusterMetadata } from "../../main/cluster-detectors/detect-cluster-metadata.injectable";
|
||||
import type { FalibleOnlyClusterMetadataDetector } from "../../main/cluster-detectors/token";
|
||||
|
||||
export interface ClusterDependencies {
|
||||
readonly directoryForKubeConfigs: string;
|
||||
readonly logger: Logger;
|
||||
readonly detectorRegistry: DetectorRegistry;
|
||||
readonly clusterVersionDetector: FalibleOnlyClusterMetadataDetector;
|
||||
detectClusterMetadata: DetectClusterMetadata;
|
||||
createKubeconfigManager: (cluster: Cluster) => KubeconfigManager;
|
||||
createContextHandler: (cluster: Cluster) => ClusterContextHandler;
|
||||
createKubectl: (clusterVersion: string) => Kubectl;
|
||||
@@ -39,7 +39,6 @@ export interface ClusterDependencies {
|
||||
requestApiResources: RequestApiResources;
|
||||
requestNamespaceListPermissionsFor: RequestNamespaceListPermissionsFor;
|
||||
createListNamespaces: (config: KubeConfig) => ListNamespaces;
|
||||
createVersionDetector: (cluster: Cluster) => VersionDetector;
|
||||
broadcastMessage: BroadcastMessage;
|
||||
loadConfigfromFile: LoadConfigfromFile;
|
||||
}
|
||||
@@ -455,10 +454,15 @@ export class Cluster implements ClusterModel {
|
||||
*/
|
||||
async refreshMetadata() {
|
||||
this.dependencies.logger.info(`[CLUSTER]: refreshMetadata`, this.getMeta());
|
||||
const metadata = await this.dependencies.detectorRegistry.detectForCluster(this);
|
||||
const existingMetadata = this.metadata;
|
||||
|
||||
this.metadata = Object.assign(existingMetadata, metadata);
|
||||
const newMetadata = await this.dependencies.detectClusterMetadata(this);
|
||||
|
||||
runInAction(() => {
|
||||
this.metadata = {
|
||||
...this.metadata,
|
||||
...newMetadata,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -521,8 +525,7 @@ export class Cluster implements ClusterModel {
|
||||
|
||||
protected async getConnectionStatus(): Promise<ClusterStatus> {
|
||||
try {
|
||||
const versionDetector = this.dependencies.createVersionDetector(this);
|
||||
const versionData = await versionDetector.detect();
|
||||
const versionData = await this.dependencies.clusterVersionDetector.detect(this);
|
||||
|
||||
this.metadata.version = versionData.value;
|
||||
|
||||
@@ -560,6 +563,8 @@ export class Cluster implements ClusterModel {
|
||||
const message = String(error.error || error.message) || String(error);
|
||||
|
||||
this.broadcastConnectUpdate(message, true);
|
||||
} else if (error instanceof Error || typeof error === "string") {
|
||||
this.broadcastConnectUpdate(`${error}`, true);
|
||||
} else {
|
||||
this.broadcastConnectUpdate("Unknown error has occurred", true);
|
||||
}
|
||||
@@ -652,7 +657,7 @@ export class Cluster implements ClusterModel {
|
||||
const namespaceList = [ctx?.namespace].filter(isDefined);
|
||||
|
||||
if (namespaceList.length === 0 && error instanceof HttpError && error.statusCode === 403) {
|
||||
const { response } = error as HttpError & { response: Response };
|
||||
const { response } = error as HttpError & { response: { body: unknown }};
|
||||
|
||||
this.dependencies.logger.info("[CLUSTER]: listing namespaces is forbidden, broadcasting", { clusterId: this.id, error: response.body });
|
||||
this.dependencies.broadcastMessage(clusterListNamespaceForbiddenChannel, this.id);
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getGlobalOverrideForFunction } from "../test-utils/get-global-override-for-function";
|
||||
import lensFetchInjectable from "./lens-fetch.injectable";
|
||||
|
||||
export default getGlobalOverrideForFunction(lensFetchInjectable);
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { Agent } from "https";
|
||||
import type { RequestInit, Response } from "node-fetch";
|
||||
import lensProxyPortInjectable from "../../main/lens-proxy/lens-proxy-port.injectable";
|
||||
import lensProxyCertificateInjectable from "../certificate/lens-proxy-certificate.injectable";
|
||||
import nodeFetchModuleInjectable from "./fetch-module.injectable";
|
||||
|
||||
export type LensRequestInit = Omit<RequestInit, "agent">;
|
||||
|
||||
export type LensFetch = (pathnameAndQuery: string, init?: LensRequestInit) => Promise<Response>;
|
||||
|
||||
const lensFetchInjectable = getInjectable({
|
||||
id: "lens-fetch",
|
||||
instantiate: (di): LensFetch => {
|
||||
const { default: fetch } = di.inject(nodeFetchModuleInjectable);
|
||||
const lensProxyPort = di.inject(lensProxyPortInjectable);
|
||||
const lensProxyCertificate = di.inject(lensProxyCertificateInjectable);
|
||||
|
||||
return async (pathnameAndQuery, init = {}) => {
|
||||
const agent = new Agent({
|
||||
ca: lensProxyCertificate.get().cert,
|
||||
});
|
||||
|
||||
return fetch(`https://127.0.0.1:${lensProxyPort.get()}${pathnameAndQuery}`, {
|
||||
...init,
|
||||
agent,
|
||||
});
|
||||
};
|
||||
},
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default lensFetchInjectable;
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { IpcRendererNavigationEvents } from "../../renderer/navigation/events";
|
||||
import { IpcRendererNavigationEvents } from "../ipc/navigation-events";
|
||||
import type { MessageChannel } from "../utils/channel/message-channel-listener-injection-token";
|
||||
|
||||
export type AppNavigationChannel = MessageChannel<string>;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { IpcRendererNavigationEvents } from "../../renderer/navigation/events";
|
||||
import { IpcRendererNavigationEvents } from "../ipc/navigation-events";
|
||||
import type { MessageChannel } from "../utils/channel/message-channel-listener-injection-token";
|
||||
|
||||
export type ClusterFrameNavigationChannel = MessageChannel<string>;
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||
import type { IpcMain } from "electron";
|
||||
|
||||
const ipcMainInjectionToken = getInjectionToken<IpcMain>({
|
||||
id: "ipc-main-injection-token",
|
||||
});
|
||||
|
||||
export default ipcMainInjectionToken;
|
||||
@@ -12,17 +12,17 @@ import { toJS } from "../utils/toJS";
|
||||
import type { ClusterFrameInfo } from "../cluster-frames";
|
||||
import { clusterFrameMap } from "../cluster-frames";
|
||||
import type { Disposer } from "../utils";
|
||||
import ipcMainInjectable from "../../main/utils/channel/ipc-main/ipc-main.injectable";
|
||||
import { getLegacyGlobalDiForExtensionApi } from "../../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
|
||||
import ipcRendererInjectable from "../../renderer/utils/channel/ipc-renderer.injectable";
|
||||
import loggerInjectable from "../logger.injectable";
|
||||
import ipcMainInjectionToken from "./ipc-main-injection-token";
|
||||
|
||||
export const broadcastMainChannel = "ipc:broadcast-main";
|
||||
|
||||
export function ipcMainHandle(channel: string, listener: (event: Electron.IpcMainInvokeEvent, ...args: any[]) => any) {
|
||||
const di = getLegacyGlobalDiForExtensionApi();
|
||||
|
||||
const ipcMain = di.inject(ipcMainInjectable);
|
||||
const ipcMain = di.inject(ipcMainInjectionToken);
|
||||
|
||||
ipcMain.handle(channel, async (event, ...args) => {
|
||||
return sanitizePayload(await listener(event, ...args));
|
||||
@@ -90,7 +90,7 @@ export async function broadcastMessage(channel: string, ...args: any[]): Promise
|
||||
export function ipcMainOn(channel: string, listener: (event: Electron.IpcMainEvent, ...args: any[]) => any): Disposer {
|
||||
const di = getLegacyGlobalDiForExtensionApi();
|
||||
|
||||
const ipcMain = di.inject(ipcMainInjectable);
|
||||
const ipcMain = di.inject(ipcMainInjectionToken);
|
||||
|
||||
ipcMain.on(channel, listener);
|
||||
|
||||
|
||||
File renamed without changes.
@@ -130,7 +130,7 @@ export function isFunction(val: unknown): val is (...args: unknown[]) => unknown
|
||||
/**
|
||||
* Checks if the value in the second position is non-nullable
|
||||
*/
|
||||
export function hasDefinedTupleValue<K, V>(pair: [K, V | undefined | null]): pair is [K, V] {
|
||||
export function hasDefinedTupleValue<K, V>(pair: readonly [K, V | undefined | null]): pair is [K, V] {
|
||||
return pair[1] != null;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getGlobalOverride } from "../test-utils/get-global-override";
|
||||
import extensionApiVersionInjectable from "./extension-api-version.injectable";
|
||||
|
||||
export default getGlobalOverride(extensionApiVersionInjectable, () => "6.0.0");
|
||||
@@ -4,15 +4,16 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { SemVer } from "semver";
|
||||
import applicationInformationToken from "./application-information-token";
|
||||
import packageJson from "../../../package.json";
|
||||
|
||||
const extensionApiVersionInjectable = getInjectable({
|
||||
id: "extension-api-version",
|
||||
instantiate: (di) => {
|
||||
const { major, minor, patch } = new SemVer(di.inject(applicationInformationToken).version);
|
||||
instantiate: () => {
|
||||
const { major, minor, patch } = new SemVer(packageJson.version);
|
||||
|
||||
return `${major}.${minor}.${patch}`;
|
||||
},
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default extensionApiVersionInjectable;
|
||||
@@ -27,6 +27,11 @@ import { getLegacyGlobalDiForExtensionApi } from "../as-legacy-globals-for-exten
|
||||
import maybeKubeApiInjectable from "../../common/k8s-api/maybe-kube-api.injectable";
|
||||
import { DeploymentApi as InternalDeploymentApi, IngressApi as InternalIngressApi, NodeApi, PersistentVolumeClaimApi, PodApi } from "../../common/k8s-api/endpoints";
|
||||
import { storesAndApisCanBeCreatedInjectionToken } from "../../common/k8s-api/stores-apis-can-be-created.token";
|
||||
import type { JsonApiConfig } from "../../common/k8s-api/json-api";
|
||||
import type { KubeJsonApi as InternalKubeJsonApi } from "../../common/k8s-api/kube-json-api";
|
||||
import createKubeJsonApiInjectable from "../../common/k8s-api/create-kube-json-api.injectable";
|
||||
import type { RequestInit } from "node-fetch";
|
||||
import createKubeJsonApiForClusterInjectable from "../../common/k8s-api/create-kube-json-api-for-cluster.injectable";
|
||||
|
||||
export const apiManager = asLegacyGlobalForExtensionApi(apiManagerInjectable);
|
||||
export const forCluster = asLegacyGlobalFunctionForExtensionApi(createKubeApiForClusterInjectable);
|
||||
@@ -59,6 +64,11 @@ function KubeApiCstr<
|
||||
return api;
|
||||
}
|
||||
|
||||
export type KubeApi<
|
||||
Object extends KubeObject = KubeObject,
|
||||
Data extends KubeJsonApiDataFor<Object> = KubeJsonApiDataFor<Object>,
|
||||
> = InternalKubeApi<Object, Data>;
|
||||
|
||||
export const KubeApi = KubeApiCstr as unknown as new<
|
||||
Object extends KubeObject = KubeObject,
|
||||
Data extends KubeJsonApiDataFor<Object> = KubeJsonApiDataFor<Object>,
|
||||
@@ -107,11 +117,26 @@ export {
|
||||
type KubeStatusData,
|
||||
} from "../../common/k8s-api/kube-object";
|
||||
|
||||
export {
|
||||
KubeJsonApi,
|
||||
type KubeJsonApiData,
|
||||
export type {
|
||||
KubeJsonApiData,
|
||||
} from "../../common/k8s-api/kube-json-api";
|
||||
|
||||
function KubeJsonApiCstr(config: JsonApiConfig, reqInit?: RequestInit) {
|
||||
const di = getLegacyGlobalDiForExtensionApi();
|
||||
const createKubeJsonApi = di.inject(createKubeJsonApiInjectable);
|
||||
|
||||
return createKubeJsonApi(config, reqInit);
|
||||
}
|
||||
|
||||
export type KubeJsonApi = InternalKubeJsonApi;
|
||||
|
||||
export const KubeJsonApi = Object.assign(
|
||||
KubeJsonApiCstr as unknown as new (config: JsonApiConfig, reqInit?: RequestInit) => InternalKubeJsonApi,
|
||||
{
|
||||
forCluster: asLegacyGlobalForExtensionApi(createKubeJsonApiForClusterInjectable),
|
||||
},
|
||||
);
|
||||
|
||||
export abstract class KubeObjectStore<
|
||||
K extends KubeObject = KubeObject,
|
||||
A extends InternalKubeApi<K, D> = InternalKubeApi<K, KubeJsonApiDataFor<K>>,
|
||||
@@ -186,30 +211,35 @@ function PodsApiConstructor(opts?: DerivedKubeApiOptions & IgnoredKubeApiOptions
|
||||
return new PodApi(getKubeApiDeps(), opts);
|
||||
}
|
||||
|
||||
export type PodsApi = PodApi;
|
||||
export const PodsApi = PodsApiConstructor as unknown as new (opts?: DerivedKubeApiOptions & IgnoredKubeApiOptions) => PodApi;
|
||||
|
||||
function NodesApiConstructor(opts?: DerivedKubeApiOptions & IgnoredKubeApiOptions) {
|
||||
return new NodeApi(getKubeApiDeps(), opts);
|
||||
}
|
||||
|
||||
export type NodesApi = NodeApi;
|
||||
export const NodesApi = NodesApiConstructor as unknown as new (opts?: DerivedKubeApiOptions & IgnoredKubeApiOptions) => NodeApi;
|
||||
|
||||
function DeploymentApiConstructor(opts?: DerivedKubeApiOptions) {
|
||||
return new InternalDeploymentApi(getKubeApiDeps(), opts);
|
||||
}
|
||||
|
||||
export type DeploymentApi = InternalDeploymentApi;
|
||||
export const DeploymentApi = DeploymentApiConstructor as unknown as new (opts?: DerivedKubeApiOptions) => InternalDeploymentApi;
|
||||
|
||||
function IngressApiConstructor(opts?: DerivedKubeApiOptions & IgnoredKubeApiOptions) {
|
||||
return new InternalIngressApi(getKubeApiDeps(), opts);
|
||||
}
|
||||
|
||||
export type IngressApi = InternalIngressApi;
|
||||
export const IngressApi = IngressApiConstructor as unknown as new (opts?: DerivedKubeApiOptions & IgnoredKubeApiOptions) => InternalIngressApi;
|
||||
|
||||
function PersistentVolumeClaimsApiConstructor(opts?: DerivedKubeApiOptions & IgnoredKubeApiOptions) {
|
||||
return new PersistentVolumeClaimApi(getKubeApiDeps(), opts);
|
||||
}
|
||||
|
||||
export type PersistentVolumeClaimsApi = PersistentVolumeClaimApi;
|
||||
export const PersistentVolumeClaimsApi = PersistentVolumeClaimsApiConstructor as unknown as new (opts?: DerivedKubeApiOptions & IgnoredKubeApiOptions) => PersistentVolumeClaimApi;
|
||||
|
||||
export {
|
||||
|
||||
@@ -73,14 +73,14 @@ export * from "../../renderer/components/dialog";
|
||||
export * from "../../renderer/components/line-progress";
|
||||
export * from "../../renderer/components/menu";
|
||||
|
||||
export type {
|
||||
CreateNotificationOptions,
|
||||
Notification,
|
||||
NotificationId,
|
||||
NotificationMessage,
|
||||
export {
|
||||
NotificationStatus,
|
||||
ShowNotification,
|
||||
NotificationsStore,
|
||||
type CreateNotificationOptions,
|
||||
type Notification,
|
||||
type NotificationId,
|
||||
type NotificationMessage,
|
||||
type ShowNotification,
|
||||
type NotificationsStore,
|
||||
} from "../../renderer/components/notifications";
|
||||
|
||||
export const Notifications = {
|
||||
|
||||
+18
-48
@@ -54,21 +54,6 @@ exports[`disable kube object detail items when cluster is not relevant given ext
|
||||
<div
|
||||
class="drawer-content flex column box grow"
|
||||
>
|
||||
<div
|
||||
class="DrawerItem"
|
||||
>
|
||||
<span
|
||||
class="name"
|
||||
>
|
||||
Created
|
||||
</span>
|
||||
<span
|
||||
class="value"
|
||||
>
|
||||
<unknown>
|
||||
ago
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="DrawerItem"
|
||||
>
|
||||
@@ -104,12 +89,17 @@ exports[`disable kube object detail items when cluster is not relevant given ext
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="DrawerTitle flex gaps align-center title"
|
||||
class="DrawerTitle title"
|
||||
>
|
||||
<span>
|
||||
Events
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="empty"
|
||||
>
|
||||
No events found
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -680,21 +670,6 @@ exports[`disable kube object detail items when cluster is not relevant given ext
|
||||
<div
|
||||
class="drawer-content flex column box grow"
|
||||
>
|
||||
<div
|
||||
class="DrawerItem"
|
||||
>
|
||||
<span
|
||||
class="name"
|
||||
>
|
||||
Created
|
||||
</span>
|
||||
<span
|
||||
class="value"
|
||||
>
|
||||
<unknown>
|
||||
ago
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="DrawerItem"
|
||||
>
|
||||
@@ -725,12 +700,17 @@ exports[`disable kube object detail items when cluster is not relevant given ext
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="DrawerTitle flex gaps align-center title"
|
||||
class="DrawerTitle title"
|
||||
>
|
||||
<span>
|
||||
Events
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="empty"
|
||||
>
|
||||
No events found
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1301,21 +1281,6 @@ exports[`disable kube object detail items when cluster is not relevant given not
|
||||
<div
|
||||
class="drawer-content flex column box grow"
|
||||
>
|
||||
<div
|
||||
class="DrawerItem"
|
||||
>
|
||||
<span
|
||||
class="name"
|
||||
>
|
||||
Created
|
||||
</span>
|
||||
<span
|
||||
class="value"
|
||||
>
|
||||
<unknown>
|
||||
ago
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="DrawerItem"
|
||||
>
|
||||
@@ -1346,12 +1311,17 @@ exports[`disable kube object detail items when cluster is not relevant given not
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="DrawerTitle flex gaps align-center title"
|
||||
class="DrawerTitle title"
|
||||
>
|
||||
<span>
|
||||
Events
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="empty"
|
||||
>
|
||||
No events found
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+12
-32
@@ -54,21 +54,6 @@ exports[`reactively hide kube object detail item renders 1`] = `
|
||||
<div
|
||||
class="drawer-content flex column box grow"
|
||||
>
|
||||
<div
|
||||
class="DrawerItem"
|
||||
>
|
||||
<span
|
||||
class="name"
|
||||
>
|
||||
Created
|
||||
</span>
|
||||
<span
|
||||
class="value"
|
||||
>
|
||||
<unknown>
|
||||
ago
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="DrawerItem"
|
||||
>
|
||||
@@ -99,12 +84,17 @@ exports[`reactively hide kube object detail item renders 1`] = `
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="DrawerTitle flex gaps align-center title"
|
||||
class="DrawerTitle title"
|
||||
>
|
||||
<span>
|
||||
Events
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="empty"
|
||||
>
|
||||
No events found
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -675,21 +665,6 @@ exports[`reactively hide kube object detail item when the item is shown renders
|
||||
<div
|
||||
class="drawer-content flex column box grow"
|
||||
>
|
||||
<div
|
||||
class="DrawerItem"
|
||||
>
|
||||
<span
|
||||
class="name"
|
||||
>
|
||||
Created
|
||||
</span>
|
||||
<span
|
||||
class="value"
|
||||
>
|
||||
<unknown>
|
||||
ago
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="DrawerItem"
|
||||
>
|
||||
@@ -725,12 +700,17 @@ exports[`reactively hide kube object detail item when the item is shown renders
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="DrawerTitle flex gaps align-center title"
|
||||
class="DrawerTitle title"
|
||||
>
|
||||
<span>
|
||||
Events
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="empty"
|
||||
>
|
||||
No events found
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+54
-18
@@ -1375,11 +1375,17 @@ exports[`New Upgrade Helm Chart Dock Tab given a namespace is selected when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
my-second-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
my-second-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
@@ -2172,11 +2178,17 @@ exports[`New Upgrade Helm Chart Dock Tab given a namespace is selected when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
my-second-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
my-second-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
@@ -2985,11 +2997,17 @@ exports[`New Upgrade Helm Chart Dock Tab given a namespace is selected when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
my-second-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
my-second-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
@@ -3834,11 +3852,17 @@ exports[`New Upgrade Helm Chart Dock Tab given a namespace is selected when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
my-second-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
my-second-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
@@ -4823,11 +4847,17 @@ exports[`New Upgrade Helm Chart Dock Tab given a namespace is selected when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
my-second-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
my-second-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
@@ -5814,11 +5844,17 @@ exports[`New Upgrade Helm Chart Dock Tab given a namespace is selected when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
my-second-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
my-second-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
|
||||
+216
-72
@@ -2242,11 +2242,17 @@ exports[`showing details for helm release given application is started when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
some-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
some-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
@@ -2328,11 +2334,17 @@ exports[`showing details for helm release given application is started when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
some-other-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
some-other-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
@@ -3206,11 +3218,17 @@ exports[`showing details for helm release given application is started when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
some-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
some-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
@@ -3292,11 +3310,17 @@ exports[`showing details for helm release given application is started when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
some-other-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
some-other-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
@@ -4231,11 +4255,17 @@ exports[`showing details for helm release given application is started when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
some-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
some-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
@@ -4317,11 +4347,17 @@ exports[`showing details for helm release given application is started when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
some-other-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
some-other-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
@@ -5256,11 +5292,17 @@ exports[`showing details for helm release given application is started when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
some-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
some-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
@@ -5342,11 +5384,17 @@ exports[`showing details for helm release given application is started when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
some-other-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
some-other-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
@@ -6526,11 +6574,17 @@ exports[`showing details for helm release given application is started when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
some-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
some-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
@@ -6612,11 +6666,17 @@ exports[`showing details for helm release given application is started when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
some-other-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
some-other-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
@@ -7796,11 +7856,17 @@ exports[`showing details for helm release given application is started when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
some-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
some-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
@@ -7882,11 +7948,17 @@ exports[`showing details for helm release given application is started when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
some-other-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
some-other-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
@@ -11242,11 +11314,17 @@ exports[`showing details for helm release given application is started when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
some-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
some-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
@@ -11328,11 +11406,17 @@ exports[`showing details for helm release given application is started when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
some-other-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
some-other-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
@@ -12512,11 +12596,17 @@ exports[`showing details for helm release given application is started when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
some-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
some-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
@@ -12598,11 +12688,17 @@ exports[`showing details for helm release given application is started when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
some-other-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
some-other-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
@@ -13537,11 +13633,17 @@ exports[`showing details for helm release given application is started when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
some-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
some-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
@@ -13623,11 +13725,17 @@ exports[`showing details for helm release given application is started when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
some-other-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
some-other-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
@@ -14565,11 +14673,17 @@ exports[`showing details for helm release given application is started when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
some-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
some-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
@@ -14651,11 +14765,17 @@ exports[`showing details for helm release given application is started when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
some-other-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
some-other-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
@@ -15529,11 +15649,17 @@ exports[`showing details for helm release given application is started when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
some-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
some-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
@@ -15615,11 +15741,17 @@ exports[`showing details for helm release given application is started when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
some-other-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
some-other-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
@@ -16554,11 +16686,17 @@ exports[`showing details for helm release given application is started when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
some-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
some-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
@@ -16640,11 +16778,17 @@ exports[`showing details for helm release given application is started when navi
|
||||
<div
|
||||
class="TableCell namespace"
|
||||
>
|
||||
<a
|
||||
class="filterNamespace"
|
||||
<div
|
||||
class="badge NamespaceSelectBadge flat clickable"
|
||||
>
|
||||
some-other-namespace
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
Set global namespace filter to:
|
||||
<b>
|
||||
some-other-namespace
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableCell chart"
|
||||
|
||||
+1
-1
@@ -1141,7 +1141,7 @@ exports[`preferences - navigation to terminal preferences given in preferences,
|
||||
class="Select__single-value css-1dimb5e-singleValue"
|
||||
>
|
||||
<span
|
||||
style="font-family: RobotoMono; font-size: 12px;"
|
||||
style="font-family: RobotoMono, var(--font-terminal); font-size: 12px;"
|
||||
>
|
||||
RobotoMono
|
||||
</span>
|
||||
|
||||
+11
-47
@@ -5,66 +5,30 @@
|
||||
import React from "react";
|
||||
import { SubTitle } from "../../../../../../renderer/components/layout/sub-title";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import type { UserStore } from "../../../../../../common/user-store";
|
||||
import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable";
|
||||
import { observer } from "mobx-react";
|
||||
import type { SelectOption } from "../../../../../../renderer/components/select";
|
||||
import { Select } from "../../../../../../renderer/components/select";
|
||||
import type { Logger } from "../../../../../../common/logger";
|
||||
import { action } from "mobx";
|
||||
import loggerInjectable from "../../../../../../common/logger.injectable";
|
||||
import type { TerminalFontPreferencePresenter } from "./terminal-font-options.injectable";
|
||||
import terminalFontPreferencePresenterInjectable from "./terminal-font-options.injectable";
|
||||
|
||||
interface Dependencies {
|
||||
userStore: UserStore;
|
||||
logger: Logger;
|
||||
model: TerminalFontPreferencePresenter;
|
||||
}
|
||||
|
||||
const NonInjectedTerminalFontFamily = observer(
|
||||
({ userStore, logger }: Dependencies) => {
|
||||
|
||||
// fonts must be declared in `fonts.scss` and at `template.html` (if early-preloading required)
|
||||
const supportedCustomFonts: SelectOption<string>[] = [
|
||||
"RobotoMono", "Anonymous Pro", "IBM Plex Mono", "JetBrains Mono", "Red Hat Mono",
|
||||
"Source Code Pro", "Space Mono", "Ubuntu Mono",
|
||||
].map(customFont => {
|
||||
const { fontFamily, fontSize } = userStore.terminalConfig;
|
||||
|
||||
return {
|
||||
label: <span style={{ fontFamily: customFont, fontSize }}>{customFont}</span>,
|
||||
value: customFont,
|
||||
isSelected: fontFamily === customFont,
|
||||
};
|
||||
});
|
||||
|
||||
const onFontFamilyChange = action(({ value: fontFamily }: SelectOption<string>) => {
|
||||
logger.info(`setting terminal font to ${fontFamily}`);
|
||||
|
||||
userStore.terminalConfig.fontFamily = fontFamily; // save to external storage
|
||||
});
|
||||
|
||||
|
||||
return (
|
||||
const NonInjectedTerminalFontFamily = observer(({ model }: Dependencies) => (
|
||||
<section>
|
||||
<SubTitle title="Font family" />
|
||||
<Select
|
||||
themeName="lens"
|
||||
controlShouldRenderValue
|
||||
value={userStore.terminalConfig.fontFamily}
|
||||
options={supportedCustomFonts}
|
||||
onChange={onFontFamilyChange as any}
|
||||
value={model.current.get()}
|
||||
options={model.options.get()}
|
||||
onChange={model.onSelection}
|
||||
/>
|
||||
</section>
|
||||
);
|
||||
},
|
||||
);
|
||||
));
|
||||
|
||||
export const TerminalFontFamily = withInjectables<Dependencies>(
|
||||
NonInjectedTerminalFontFamily,
|
||||
|
||||
{
|
||||
export const TerminalFontFamily = withInjectables<Dependencies>(NonInjectedTerminalFontFamily, {
|
||||
getProps: (di) => ({
|
||||
userStore: di.inject(userStoreInjectable),
|
||||
logger: di.inject(loggerInjectable),
|
||||
model: di.inject(terminalFontPreferencePresenterInjectable),
|
||||
}),
|
||||
},
|
||||
);
|
||||
});
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { IComputedValue } from "mobx";
|
||||
import { action, computed } from "mobx";
|
||||
import React from "react";
|
||||
import type { SingleValue } from "react-select";
|
||||
import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable";
|
||||
import { defaultTerminalFontFamily } from "../../../../../../common/vars";
|
||||
import type { SelectOption } from "../../../../../../renderer/components/select";
|
||||
import { terminalFontInjectionToken } from "../../../../../terminal/renderer/fonts/token";
|
||||
|
||||
export interface TerminalFontPreferencePresenter {
|
||||
readonly options: IComputedValue<SelectOption<string>[]>;
|
||||
readonly current: IComputedValue<string>;
|
||||
onSelection: (selection: SingleValue<SelectOption<string>>) => void;
|
||||
}
|
||||
|
||||
const terminalFontPreferencePresenterInjectable = getInjectable({
|
||||
id: "terminal-font-preference-presenter",
|
||||
instantiate: (di): TerminalFontPreferencePresenter => {
|
||||
const userStore = di.inject(userStoreInjectable);
|
||||
const terminalFonts = di.injectMany(terminalFontInjectionToken);
|
||||
|
||||
return {
|
||||
options: computed(() => terminalFonts.map(font => ({
|
||||
label: (
|
||||
<span
|
||||
style={{
|
||||
fontFamily: `${font.name}, var(--font-terminal)`,
|
||||
fontSize: userStore.terminalConfig.fontSize,
|
||||
}}
|
||||
>
|
||||
{font.name}
|
||||
</span>
|
||||
),
|
||||
value: font.name,
|
||||
isSelected: userStore.terminalConfig.fontFamily === font.name,
|
||||
}))),
|
||||
current: computed(() => userStore.terminalConfig.fontFamily),
|
||||
onSelection: action(selection => {
|
||||
userStore.terminalConfig.fontFamily = selection?.value ?? defaultTerminalFontFamily;
|
||||
}),
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default terminalFontPreferencePresenterInjectable;
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { terminalFontInjectionToken } from "./token";
|
||||
import AnonymousPro from "./AnonymousPro-Regular.ttf";
|
||||
|
||||
const anonymousProTerminalFontInjectable = getInjectable({
|
||||
id: "anonymous-pro-terminal-font",
|
||||
instantiate: () => ({
|
||||
name:"Anonymous Pro",
|
||||
url: AnonymousPro,
|
||||
}),
|
||||
injectionToken: terminalFontInjectionToken,
|
||||
});
|
||||
|
||||
export default anonymousProTerminalFontInjectable;
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { terminalFontInjectionToken } from "./token";
|
||||
|
||||
const terminalFontsInjectable = getInjectable({
|
||||
id: "terminal-fonts",
|
||||
instantiate: (di) => di.injectMany(terminalFontInjectionToken),
|
||||
});
|
||||
|
||||
export default terminalFontsInjectable;
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { terminalFontInjectionToken } from "./token";
|
||||
import IBMPlexMono from "./IBMPlexMono-Regular.ttf";
|
||||
|
||||
const ibmPlexMonoTerminalFontInjectable = getInjectable({
|
||||
id: "ibm-plex-mono-terminal-font",
|
||||
instantiate: () => ({
|
||||
name: "IBM Plex Mono",
|
||||
url: IBMPlexMono,
|
||||
}),
|
||||
injectionToken: terminalFontInjectionToken,
|
||||
});
|
||||
|
||||
export default ibmPlexMonoTerminalFontInjectable;
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { terminalFontInjectionToken } from "./token";
|
||||
import JetBrainsMono from "./JetBrainsMono-Regular.ttf";
|
||||
|
||||
const jetbrainsMonoTerminalFontInjectable = getInjectable({
|
||||
id: "jetbrains-mono-terminal-font",
|
||||
instantiate: () => ({
|
||||
name: "JetBrains Mono",
|
||||
url: JetBrainsMono,
|
||||
}),
|
||||
injectionToken: terminalFontInjectionToken,
|
||||
});
|
||||
|
||||
export default jetbrainsMonoTerminalFontInjectable;
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getGlobalOverride } from "../../../../common/test-utils/get-global-override";
|
||||
import loadTerminalFontInjectable from "./load-font.injectable";
|
||||
|
||||
export default getGlobalOverride(loadTerminalFontInjectable, () => async () => {});
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { TerminalFont } from "./token";
|
||||
|
||||
export type LoadTerminalFont = (font: TerminalFont) => Promise<void>;
|
||||
|
||||
const loadTerminalFontInjectable = getInjectable({
|
||||
id: "load-terminal-font",
|
||||
instantiate: (): LoadTerminalFont => async (font) => {
|
||||
const fontLoaded = document.fonts.check(`10px ${font.name}`);
|
||||
|
||||
if (fontLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fontFace = new FontFace(font.name, `url(${font.url})`);
|
||||
|
||||
document.fonts.add(fontFace);
|
||||
await fontFace.load();
|
||||
},
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default loadTerminalFontInjectable;
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { beforeFrameStartsFirstInjectionToken } from "../../../../renderer/before-frame-starts/tokens";
|
||||
import terminalFontsInjectable from "./fonts.injectable";
|
||||
import loadTerminalFontInjectable from "./load-font.injectable";
|
||||
|
||||
const preloadTerminalFontsInjectable = getInjectable({
|
||||
id: "preload-terminal-fonts",
|
||||
instantiate: (di) => ({
|
||||
id: "preload-terminal-fonts",
|
||||
run: async () => {
|
||||
const terminalFonts = di.inject(terminalFontsInjectable);
|
||||
const loadTerminalFont = di.inject(loadTerminalFontInjectable);
|
||||
|
||||
await Promise.allSettled(terminalFonts.map(loadTerminalFont));
|
||||
},
|
||||
}),
|
||||
injectionToken: beforeFrameStartsFirstInjectionToken,
|
||||
});
|
||||
|
||||
export default preloadTerminalFontsInjectable;
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { terminalFontInjectionToken } from "./token";
|
||||
import RedHatMono from "./RedHatMono-Regular.ttf";
|
||||
|
||||
const redHatMonoTerminalFontInjectable = getInjectable({
|
||||
id: "red-hat-mono-terminal-font",
|
||||
instantiate: () => ({
|
||||
name: "Red Hat Mono",
|
||||
url: RedHatMono,
|
||||
}),
|
||||
injectionToken: terminalFontInjectionToken,
|
||||
});
|
||||
|
||||
export default redHatMonoTerminalFontInjectable;
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { terminalFontInjectionToken } from "./token";
|
||||
import RobotoMono from "./Roboto-Mono.ttf"; // patched font with icons
|
||||
|
||||
const robotoMonoTerminalFontInjectable = getInjectable({
|
||||
id: "roboto-mono-terminal-font",
|
||||
instantiate: () => ({
|
||||
name: "RobotoMono",
|
||||
url: RobotoMono,
|
||||
}),
|
||||
injectionToken: terminalFontInjectionToken,
|
||||
});
|
||||
|
||||
export default robotoMonoTerminalFontInjectable;
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { terminalFontInjectionToken } from "./token";
|
||||
import SourceCodePro from "./SourceCodePro-Regular.ttf";
|
||||
|
||||
const sourceCodeProTerminalFontInjectable = getInjectable({
|
||||
id: "source-code-pro-terminal-font",
|
||||
instantiate: () => ({
|
||||
name: "Source Code Pro",
|
||||
url: SourceCodePro,
|
||||
}),
|
||||
injectionToken: terminalFontInjectionToken,
|
||||
});
|
||||
|
||||
export default sourceCodeProTerminalFontInjectable;
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { terminalFontInjectionToken } from "./token";
|
||||
import SpaceMono from "./SpaceMono-Regular.ttf";
|
||||
|
||||
const spaceMonoTerminalFontInjectable = getInjectable({
|
||||
id: "space-mono-terminal-font",
|
||||
instantiate: () => ({
|
||||
name: "Space Mono",
|
||||
url: SpaceMono,
|
||||
}),
|
||||
injectionToken: terminalFontInjectionToken,
|
||||
});
|
||||
|
||||
export default spaceMonoTerminalFontInjectable;
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||
|
||||
export interface TerminalFont {
|
||||
name: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export const terminalFontInjectionToken = getInjectionToken<TerminalFont>({
|
||||
id: "terminal-font-token",
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { terminalFontInjectionToken } from "./token";
|
||||
import UbuntuMono from "./UbuntuMono-Regular.ttf";
|
||||
|
||||
const ubunutuMonoTerminalFontInjectable = getInjectable({
|
||||
id: "ubunutu-mono-terminal-font",
|
||||
instantiate: () => ({
|
||||
name: "Ubuntu Mono",
|
||||
url: UbuntuMono,
|
||||
}),
|
||||
injectionToken: terminalFontInjectionToken,
|
||||
});
|
||||
|
||||
export default ubunutuMonoTerminalFontInjectable;
|
||||
+2
-2
@@ -4,11 +4,11 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { reaction } from "mobx";
|
||||
import ipcMainInjectionToken from "../../common/ipc/ipc-main-injection-token";
|
||||
import { catalogInitChannel } from "../../common/ipc/catalog";
|
||||
import { disposer, toJS } from "../../common/utils";
|
||||
import { getStartableStoppable } from "../../common/utils/get-startable-stoppable";
|
||||
import catalogEntityRegistryInjectable from "../catalog/entity-registry.injectable";
|
||||
import ipcMainInjectable from "../utils/channel/ipc-main/ipc-main.injectable";
|
||||
import catalogSyncBroadcasterInjectable from "./broadcaster.injectable";
|
||||
|
||||
const catalogSyncToRendererInjectable = getInjectable({
|
||||
@@ -16,7 +16,7 @@ const catalogSyncToRendererInjectable = getInjectable({
|
||||
|
||||
instantiate: (di) => {
|
||||
const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable);
|
||||
const ipcMain = di.inject(ipcMainInjectable);
|
||||
const ipcMain = di.inject(ipcMainInjectionToken);
|
||||
const catalogSyncBroadcaster = di.inject(catalogSyncBroadcasterInjectable);
|
||||
|
||||
return getStartableStoppable(
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { RequestPromiseOptions } from "request-promise-native";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
import type { K8sRequest } from "../k8s-request.injectable";
|
||||
|
||||
export interface ClusterDetectionResult {
|
||||
value: string | number | boolean;
|
||||
accuracy: number;
|
||||
}
|
||||
|
||||
export abstract class BaseClusterDetector {
|
||||
abstract readonly key: string;
|
||||
|
||||
constructor(public readonly cluster: Cluster, private _k8sRequest: K8sRequest) {}
|
||||
|
||||
abstract detect(): Promise<ClusterDetectionResult | null>;
|
||||
|
||||
protected async k8sRequest<T = any>(path: string, options: RequestPromiseOptions = {}): Promise<T> {
|
||||
return this._k8sRequest(this.cluster, path, options);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { clusterMetadataDetectorInjectionToken } from "./token";
|
||||
import { ClusterMetadataKey } from "../../common/cluster-types";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import k8SRequestInjectable from "../k8s-request.injectable";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
import requestClusterVersionInjectable from "./request-cluster-version.injectable";
|
||||
|
||||
const isGKE = (version: string) => version.includes("gke");
|
||||
const isEKS = (version: string) => version.includes("eks");
|
||||
const isIKS = (version: string) => version.includes("IKS");
|
||||
const isAKS = (cluster: Cluster) => cluster.apiUrl.includes("azmk8s.io");
|
||||
const isMirantis = (version: string) => version.includes("-mirantis-") || version.includes("-docker-");
|
||||
const isDigitalOcean = (cluster: Cluster) => cluster.apiUrl.endsWith("k8s.ondigitalocean.com");
|
||||
const isMinikube = (cluster: Cluster) => cluster.contextName.startsWith("minikube");
|
||||
const isMicrok8s = (cluster: Cluster) => cluster.contextName.startsWith("microk8s");
|
||||
const isKind = (cluster: Cluster) => cluster.contextName.startsWith("kubernetes-admin@kind-");
|
||||
const isDockerDesktop = (cluster: Cluster) => cluster.contextName === "docker-desktop";
|
||||
const isTke = (version: string) => version.includes("-tke.");
|
||||
const isCustom = (version: string) => version.includes("+");
|
||||
const isVMWare = (version: string) => version.includes("+vmware");
|
||||
const isRke = (version: string) => version.includes("-rancher");
|
||||
const isRancherDesktop = (cluster: Cluster) => cluster.contextName === "rancher-desktop";
|
||||
const isK3s = (version: string) => version.includes("+k3s");
|
||||
const isK0s = (version: string) => version.includes("-k0s") || version.includes("+k0s");
|
||||
const isAlibaba = (version: string) => version.includes("-aliyun");
|
||||
const isHuawei = (version: string) => version.includes("-CCE");
|
||||
|
||||
const clusterDistributionDetectorInjectable = getInjectable({
|
||||
id: "cluster-distribution-detector",
|
||||
instantiate: (di) => {
|
||||
const k8sRequest = di.inject(k8SRequestInjectable);
|
||||
const requestClusterVersion = di.inject(requestClusterVersionInjectable);
|
||||
const isOpenshift = async (cluster: Cluster) => {
|
||||
try {
|
||||
const { paths = [] } = await k8sRequest(cluster, "") as { paths?: string[] };
|
||||
|
||||
return paths.includes("/apis/project.openshift.io");
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
key: ClusterMetadataKey.DISTRIBUTION,
|
||||
detect: async (cluster) => {
|
||||
const version = await requestClusterVersion(cluster);
|
||||
|
||||
if (isRke(version)) {
|
||||
return { value: "rke", accuracy: 80 };
|
||||
}
|
||||
|
||||
if (isRancherDesktop(cluster)) {
|
||||
return { value: "rancher-desktop", accuracy: 80 };
|
||||
}
|
||||
|
||||
if (isK3s(version)) {
|
||||
return { value: "k3s", accuracy: 80 };
|
||||
}
|
||||
|
||||
if (isGKE(version)) {
|
||||
return { value: "gke", accuracy: 80 };
|
||||
}
|
||||
|
||||
if (isEKS(version)) {
|
||||
return { value: "eks", accuracy: 80 };
|
||||
}
|
||||
|
||||
if (isIKS(version)) {
|
||||
return { value: "iks", accuracy: 80 };
|
||||
}
|
||||
|
||||
if (isAKS(cluster)) {
|
||||
return { value: "aks", accuracy: 80 };
|
||||
}
|
||||
|
||||
if (isDigitalOcean(cluster)) {
|
||||
return { value: "digitalocean", accuracy: 90 };
|
||||
}
|
||||
|
||||
if (isK0s(version)) {
|
||||
return { value: "k0s", accuracy: 80 };
|
||||
}
|
||||
|
||||
if (isVMWare(version)) {
|
||||
return { value: "vmware", accuracy: 90 };
|
||||
}
|
||||
|
||||
if (isMirantis(version)) {
|
||||
return { value: "mirantis", accuracy: 90 };
|
||||
}
|
||||
|
||||
if (isAlibaba(version)) {
|
||||
return { value: "alibaba", accuracy: 90 };
|
||||
}
|
||||
|
||||
if (isHuawei(version)) {
|
||||
return { value: "huawei", accuracy: 90 };
|
||||
}
|
||||
|
||||
if (isTke(version)) {
|
||||
return { value: "tencent", accuracy: 90 };
|
||||
}
|
||||
|
||||
if (isMinikube(cluster)) {
|
||||
return { value: "minikube", accuracy: 80 };
|
||||
}
|
||||
|
||||
if (isMicrok8s(cluster)) {
|
||||
return { value: "microk8s", accuracy: 80 };
|
||||
}
|
||||
|
||||
if (isKind(cluster)) {
|
||||
return { value: "kind", accuracy: 70 };
|
||||
}
|
||||
|
||||
if (isDockerDesktop(cluster)) {
|
||||
return { value: "docker-desktop", accuracy: 80 };
|
||||
}
|
||||
|
||||
if (isCustom(version)) {
|
||||
if (await isOpenshift(cluster)) {
|
||||
return { value: "openshift", accuracy: 90 };
|
||||
}
|
||||
|
||||
return { value: "custom", accuracy: 10 };
|
||||
}
|
||||
|
||||
return { value: "unknown", accuracy: 10 };
|
||||
},
|
||||
};
|
||||
},
|
||||
injectionToken: clusterMetadataDetectorInjectionToken,
|
||||
});
|
||||
|
||||
export default clusterDistributionDetectorInjectable;
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { clusterMetadataDetectorInjectionToken } from "./token";
|
||||
import { createHash } from "crypto";
|
||||
import { ClusterMetadataKey } from "../../common/cluster-types";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import k8SRequestInjectable from "../k8s-request.injectable";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
|
||||
const clusterIdDetectorFactoryInjectable = getInjectable({
|
||||
id: "cluster-id-detector-factory",
|
||||
instantiate: (di) => {
|
||||
const k8sRequest = di.inject(k8SRequestInjectable);
|
||||
const getDefaultNamespaceId = async (cluster: Cluster) => {
|
||||
const { metadata } = await k8sRequest(cluster, "/api/v1/namespaces/default") as { metadata: { uid: string }};
|
||||
|
||||
return metadata.uid;
|
||||
};
|
||||
|
||||
return {
|
||||
key: ClusterMetadataKey.CLUSTER_ID,
|
||||
detect: async (cluster) => {
|
||||
let id: string;
|
||||
|
||||
try {
|
||||
id = await getDefaultNamespaceId(cluster);
|
||||
} catch(_) {
|
||||
id = cluster.apiUrl;
|
||||
}
|
||||
const value = createHash("sha256").update(id).digest("hex");
|
||||
|
||||
return { value, accuracy: 100 };
|
||||
},
|
||||
};
|
||||
},
|
||||
injectionToken: clusterMetadataDetectorInjectionToken,
|
||||
});
|
||||
|
||||
export default clusterIdDetectorFactoryInjectable;
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { BaseClusterDetector } from "./base-cluster-detector";
|
||||
import { createHash } from "crypto";
|
||||
import { ClusterMetadataKey } from "../../common/cluster-types";
|
||||
|
||||
export class ClusterIdDetector extends BaseClusterDetector {
|
||||
key = ClusterMetadataKey.CLUSTER_ID;
|
||||
|
||||
public async detect() {
|
||||
let id: string;
|
||||
|
||||
try {
|
||||
id = await this.getDefaultNamespaceId();
|
||||
} catch(_) {
|
||||
id = this.cluster.apiUrl;
|
||||
}
|
||||
const value = createHash("sha256").update(id).digest("hex");
|
||||
|
||||
return { value, accuracy: 100 };
|
||||
}
|
||||
|
||||
protected async getDefaultNamespaceId() {
|
||||
const response = await this.k8sRequest("/api/v1/namespaces/default");
|
||||
|
||||
return response.metadata.uid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { clusterMetadataDetectorInjectionToken } from "./token";
|
||||
import { ClusterMetadataKey } from "../../common/cluster-types";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import requestClusterVersionInjectable from "./request-cluster-version.injectable";
|
||||
|
||||
const clusterLastSeenDetectorInjectable = getInjectable({
|
||||
id: "cluster-last-seen-detector",
|
||||
instantiate: (di) => {
|
||||
const requestClusterVersion = di.inject(requestClusterVersionInjectable);
|
||||
|
||||
return {
|
||||
key: ClusterMetadataKey.LAST_SEEN,
|
||||
detect: async (cluster) => {
|
||||
try {
|
||||
await requestClusterVersion(cluster);
|
||||
|
||||
return { value: new Date().toJSON(), accuracy: 100 };
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
injectionToken: clusterMetadataDetectorInjectionToken,
|
||||
});
|
||||
|
||||
export default clusterLastSeenDetectorInjectable;
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { clusterMetadataDetectorInjectionToken } from "./token";
|
||||
import { ClusterMetadataKey } from "../../common/cluster-types";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import k8SRequestInjectable from "../k8s-request.injectable";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
|
||||
const clusterNodeCountDetectorInjectable = getInjectable({
|
||||
id: "cluster-node-count-detector",
|
||||
instantiate: (di) => {
|
||||
const k8sRequest = di.inject(k8SRequestInjectable);
|
||||
const requestNodeCount = async (cluster: Cluster) => {
|
||||
const { items } = await k8sRequest(cluster, "/api/v1/nodes") as { items: unknown[] };
|
||||
|
||||
return items.length;
|
||||
};
|
||||
|
||||
return {
|
||||
key: ClusterMetadataKey.NODES_COUNT,
|
||||
detect: async (cluster) => {
|
||||
try {
|
||||
return {
|
||||
value: await requestNodeCount(cluster),
|
||||
accuracy: 1000,
|
||||
};
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
injectionToken: clusterMetadataDetectorInjectionToken,
|
||||
});
|
||||
|
||||
export default clusterNodeCountDetectorInjectable;
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { clusterMetadataDetectorInjectionToken } from "./token";
|
||||
import { ClusterMetadataKey } from "../../common/cluster-types";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import requestClusterVersionInjectable from "./request-cluster-version.injectable";
|
||||
|
||||
const clusterVersionDetectorInjectable = getInjectable({
|
||||
id: "cluster-version-detector",
|
||||
instantiate: (di) => {
|
||||
const requestClusterVersion = di.inject(requestClusterVersionInjectable);
|
||||
|
||||
return {
|
||||
key: ClusterMetadataKey.VERSION,
|
||||
detect: async (cluster) => ({
|
||||
value: await requestClusterVersion(cluster),
|
||||
accuracy: 100,
|
||||
}),
|
||||
};
|
||||
},
|
||||
injectionToken: clusterMetadataDetectorInjectionToken,
|
||||
});
|
||||
|
||||
export default clusterVersionDetectorInjectable;
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { VersionDetector } from "./version-detector";
|
||||
import k8sRequestInjectable from "../k8s-request.injectable";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
|
||||
const createVersionDetectorInjectable = getInjectable({
|
||||
id: "create-version-detector",
|
||||
|
||||
instantiate: (di) => {
|
||||
const k8sRequest = di.inject(k8sRequestInjectable);
|
||||
|
||||
return (cluster: Cluster) =>
|
||||
new VersionDetector(cluster, k8sRequest);
|
||||
},
|
||||
});
|
||||
|
||||
export default createVersionDetectorInjectable;
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { pipeline } from "@ogre-tools/fp";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { groupBy, reduce } from "lodash";
|
||||
import { filter, map } from "lodash/fp";
|
||||
import type { ClusterMetadata } from "../../common/cluster-types";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
import { hasDefinedTupleValue, isDefined, object } from "../../common/utils";
|
||||
import type { ClusterDetectionResult, ClusterMetadataDetector } from "./token";
|
||||
import { clusterMetadataDetectorInjectionToken } from "./token";
|
||||
|
||||
export type DetectClusterMetadata = (cluster: Cluster) => Promise<ClusterMetadata>;
|
||||
|
||||
const pickHighestAccuracy = (prev: ClusterDetectionResult, curr: ClusterDetectionResult) => (
|
||||
prev.accuracy > curr.accuracy
|
||||
? prev
|
||||
: curr
|
||||
);
|
||||
|
||||
const detectMetadataWithFor = (cluster: Cluster) => async (clusterMetadataDetector: ClusterMetadataDetector) => {
|
||||
try {
|
||||
return await clusterMetadataDetector.detect(cluster);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const detectClusterMetadataInjectable = getInjectable({
|
||||
id: "detect-cluster-metadata",
|
||||
instantiate: (di): DetectClusterMetadata => {
|
||||
const clusterMetadataDetectors = di.injectMany(clusterMetadataDetectorInjectionToken);
|
||||
|
||||
return async (cluster) => {
|
||||
const entries = pipeline(
|
||||
await Promise.all(clusterMetadataDetectors.map(detectMetadataWithFor(cluster))),
|
||||
filter(isDefined),
|
||||
(arg) => groupBy(arg, "key"),
|
||||
(arg) => object.entries(arg),
|
||||
map(([ key, results ]) => [key, reduce(results, pickHighestAccuracy)] as const),
|
||||
filter(hasDefinedTupleValue),
|
||||
);
|
||||
|
||||
return object.fromEntries(entries);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default detectClusterMetadataInjectable;
|
||||
@@ -1,16 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { DetectorRegistry } from "./detector-registry";
|
||||
import k8sRequestInjectable from "../k8s-request.injectable";
|
||||
|
||||
const detectorRegistryInjectable = getInjectable({
|
||||
id: "detector-registry",
|
||||
|
||||
instantiate: (di) =>
|
||||
new DetectorRegistry({ k8sRequest: di.inject(k8sRequestInjectable) }),
|
||||
});
|
||||
|
||||
export default detectorRegistryInjectable;
|
||||
@@ -1,55 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { observable } from "mobx";
|
||||
import type { ClusterMetadata } from "../../common/cluster-types";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
import type { BaseClusterDetector, ClusterDetectionResult } from "./base-cluster-detector";
|
||||
import type { K8sRequest } from "../k8s-request.injectable";
|
||||
|
||||
interface Dependencies {
|
||||
k8sRequest: K8sRequest;
|
||||
}
|
||||
|
||||
export type DetectorConstructor = new (cluster: Cluster, k8sRequest: K8sRequest) => BaseClusterDetector;
|
||||
|
||||
export class DetectorRegistry {
|
||||
constructor(private dependencies: Dependencies) {}
|
||||
|
||||
registry = observable.array<DetectorConstructor>([], { deep: false });
|
||||
|
||||
add(detectorClass: DetectorConstructor): this {
|
||||
this.registry.push(detectorClass);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
async detectForCluster(cluster: Cluster): Promise<ClusterMetadata> {
|
||||
const results: { [key: string]: ClusterDetectionResult } = {};
|
||||
|
||||
for (const detectorClass of this.registry) {
|
||||
const detector = new detectorClass(cluster, this.dependencies.k8sRequest);
|
||||
|
||||
try {
|
||||
const data = await detector.detect();
|
||||
|
||||
if (!data) continue;
|
||||
const existingValue = results[detector.key];
|
||||
|
||||
if (existingValue && existingValue.accuracy > data.accuracy) continue; // previous value exists and is more accurate
|
||||
results[detector.key] = data;
|
||||
} catch (e) {
|
||||
// detector raised error, do nothing
|
||||
}
|
||||
}
|
||||
const metadata: ClusterMetadata = {};
|
||||
|
||||
for (const [key, result] of Object.entries(results)) {
|
||||
metadata[key] = result.value;
|
||||
}
|
||||
|
||||
return metadata;
|
||||
}
|
||||
}
|
||||
@@ -1,189 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { BaseClusterDetector } from "./base-cluster-detector";
|
||||
import { ClusterMetadataKey } from "../../common/cluster-types";
|
||||
|
||||
export class DistributionDetector extends BaseClusterDetector {
|
||||
key = ClusterMetadataKey.DISTRIBUTION;
|
||||
|
||||
public async detect() {
|
||||
const version = await this.getKubernetesVersion();
|
||||
|
||||
if (this.isRke(version)) {
|
||||
return { value: "rke", accuracy: 80 };
|
||||
}
|
||||
|
||||
if (this.isRancherDesktop()) {
|
||||
return { value: "rancher-desktop", accuracy: 80 };
|
||||
}
|
||||
|
||||
if (this.isK3s(version)) {
|
||||
return { value: "k3s", accuracy: 80 };
|
||||
}
|
||||
|
||||
if (this.isGKE(version)) {
|
||||
return { value: "gke", accuracy: 80 };
|
||||
}
|
||||
|
||||
if (this.isEKS(version)) {
|
||||
return { value: "eks", accuracy: 80 };
|
||||
}
|
||||
|
||||
if (this.isIKS(version)) {
|
||||
return { value: "iks", accuracy: 80 };
|
||||
}
|
||||
|
||||
if (this.isAKS()) {
|
||||
return { value: "aks", accuracy: 80 };
|
||||
}
|
||||
|
||||
if (this.isDigitalOcean()) {
|
||||
return { value: "digitalocean", accuracy: 90 };
|
||||
}
|
||||
|
||||
if (this.isK0s(version)) {
|
||||
return { value: "k0s", accuracy: 80 };
|
||||
}
|
||||
|
||||
if (this.isVMWare(version)) {
|
||||
return { value: "vmware", accuracy: 90 };
|
||||
}
|
||||
|
||||
if (this.isMirantis(version)) {
|
||||
return { value: "mirantis", accuracy: 90 };
|
||||
}
|
||||
|
||||
if (this.isAlibaba(version)) {
|
||||
return { value: "alibaba", accuracy: 90 };
|
||||
}
|
||||
|
||||
if (this.isHuawei(version)) {
|
||||
return { value: "huawei", accuracy: 90 };
|
||||
}
|
||||
|
||||
if (this.isTke(version)) {
|
||||
return { value: "tencent", accuracy: 90 };
|
||||
}
|
||||
|
||||
if (this.isMinikube()) {
|
||||
return { value: "minikube", accuracy: 80 };
|
||||
}
|
||||
|
||||
if (this.isMicrok8s()) {
|
||||
return { value: "microk8s", accuracy: 80 };
|
||||
}
|
||||
|
||||
if (this.isKind()) {
|
||||
return { value: "kind", accuracy: 70 };
|
||||
}
|
||||
|
||||
if (this.isDockerDesktop()) {
|
||||
return { value: "docker-desktop", accuracy: 80 };
|
||||
}
|
||||
|
||||
if (this.isCustom(version) && await this.isOpenshift()) {
|
||||
return { value: "openshift", accuracy: 90 };
|
||||
}
|
||||
|
||||
if (this.isCustom(version)) {
|
||||
return { value: "custom", accuracy: 10 };
|
||||
}
|
||||
|
||||
return { value: "unknown", accuracy: 10 };
|
||||
}
|
||||
|
||||
public async getKubernetesVersion() {
|
||||
const response = await this.k8sRequest("/version");
|
||||
|
||||
return response.gitVersion;
|
||||
}
|
||||
|
||||
protected isGKE(version: string) {
|
||||
return version.includes("gke");
|
||||
}
|
||||
|
||||
protected isEKS(version: string) {
|
||||
return version.includes("eks");
|
||||
}
|
||||
|
||||
protected isIKS(version: string) {
|
||||
return version.includes("IKS");
|
||||
}
|
||||
|
||||
protected isAKS() {
|
||||
return this.cluster.apiUrl.includes("azmk8s.io");
|
||||
}
|
||||
|
||||
protected isMirantis(version: string) {
|
||||
return version.includes("-mirantis-") || version.includes("-docker-");
|
||||
}
|
||||
|
||||
protected isDigitalOcean() {
|
||||
return this.cluster.apiUrl.endsWith("k8s.ondigitalocean.com");
|
||||
}
|
||||
|
||||
protected isMinikube() {
|
||||
return this.cluster.contextName.startsWith("minikube");
|
||||
}
|
||||
|
||||
protected isMicrok8s() {
|
||||
return this.cluster.contextName.startsWith("microk8s");
|
||||
}
|
||||
|
||||
protected isKind() {
|
||||
return this.cluster.contextName.startsWith("kubernetes-admin@kind-");
|
||||
}
|
||||
|
||||
protected isDockerDesktop() {
|
||||
return this.cluster.contextName === "docker-desktop";
|
||||
}
|
||||
|
||||
protected isTke(version: string) {
|
||||
return version.includes("-tke.");
|
||||
}
|
||||
|
||||
protected isCustom(version: string) {
|
||||
return version.includes("+");
|
||||
}
|
||||
|
||||
protected isVMWare(version: string) {
|
||||
return version.includes("+vmware");
|
||||
}
|
||||
|
||||
protected isRke(version: string) {
|
||||
return version.includes("-rancher");
|
||||
}
|
||||
|
||||
protected isRancherDesktop() {
|
||||
return this.cluster.contextName === "rancher-desktop";
|
||||
}
|
||||
|
||||
protected isK3s(version: string) {
|
||||
return version.includes("+k3s");
|
||||
}
|
||||
|
||||
protected isK0s(version: string) {
|
||||
return version.includes("-k0s") || version.includes("+k0s");
|
||||
}
|
||||
|
||||
protected isAlibaba(version: string) {
|
||||
return version.includes("-aliyun");
|
||||
}
|
||||
|
||||
protected isHuawei(version: string) {
|
||||
return version.includes("-CCE");
|
||||
}
|
||||
|
||||
protected async isOpenshift() {
|
||||
try {
|
||||
const response = await this.k8sRequest("");
|
||||
|
||||
return response.paths?.includes("/apis/project.openshift.io");
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { BaseClusterDetector } from "./base-cluster-detector";
|
||||
import { ClusterMetadataKey } from "../../common/cluster-types";
|
||||
|
||||
export class LastSeenDetector extends BaseClusterDetector {
|
||||
key = ClusterMetadataKey.LAST_SEEN;
|
||||
|
||||
public async detect() {
|
||||
if (!this.cluster.accessible) return null;
|
||||
|
||||
await this.k8sRequest("/version");
|
||||
|
||||
return { value: new Date().toJSON(), accuracy: 100 };
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { BaseClusterDetector } from "./base-cluster-detector";
|
||||
import { ClusterMetadataKey } from "../../common/cluster-types";
|
||||
|
||||
export class NodesCountDetector extends BaseClusterDetector {
|
||||
key = ClusterMetadataKey.NODES_COUNT;
|
||||
|
||||
public async detect() {
|
||||
if (!this.cluster.accessible) return null;
|
||||
const nodeCount = await this.getNodeCount();
|
||||
|
||||
return { value: nodeCount, accuracy: 100 };
|
||||
}
|
||||
|
||||
protected async getNodeCount(): Promise<number> {
|
||||
const response = await this.k8sRequest("/api/v1/nodes");
|
||||
|
||||
return response.items.length;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
import k8SRequestInjectable from "../k8s-request.injectable";
|
||||
|
||||
const requestClusterVersionInjectable = getInjectable({
|
||||
id: "request-cluster-version",
|
||||
instantiate: (di) => {
|
||||
const k8sRequest = di.inject(k8SRequestInjectable);
|
||||
|
||||
return async (cluster: Cluster) => {
|
||||
const { gitVersion } = await k8sRequest(cluster, "/version") as { gitVersion: string };
|
||||
|
||||
return gitVersion;
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default requestClusterVersionInjectable;
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
|
||||
export interface ClusterDetectionResult {
|
||||
value: string | number | boolean;
|
||||
accuracy: number;
|
||||
}
|
||||
|
||||
export interface FalibleOnlyClusterMetadataDetector {
|
||||
readonly key: string;
|
||||
detect(cluster: Cluster): Promise<ClusterDetectionResult>;
|
||||
}
|
||||
|
||||
export interface ClusterMetadataDetector {
|
||||
readonly key: string;
|
||||
detect(cluster: Cluster): Promise<ClusterDetectionResult | null>;
|
||||
}
|
||||
|
||||
export const clusterMetadataDetectorInjectionToken = getInjectionToken<ClusterMetadataDetector>({
|
||||
id: "cluster-metadata-detector-token",
|
||||
});
|
||||
@@ -1,23 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { BaseClusterDetector } from "./base-cluster-detector";
|
||||
import { ClusterMetadataKey } from "../../common/cluster-types";
|
||||
|
||||
export class VersionDetector extends BaseClusterDetector {
|
||||
key = ClusterMetadataKey.VERSION;
|
||||
|
||||
public async detect() {
|
||||
const version = await this.getKubernetesVersion();
|
||||
|
||||
return { value: version, accuracy: 100 };
|
||||
}
|
||||
|
||||
public async getKubernetesVersion() {
|
||||
const response = await this.k8sRequest("/version");
|
||||
|
||||
return response.gitVersion;
|
||||
}
|
||||
}
|
||||
@@ -14,11 +14,11 @@ import authorizationReviewInjectable from "../../common/cluster/authorization-re
|
||||
import listNamespacesInjectable from "../../common/cluster/list-namespaces.injectable";
|
||||
import createListApiResourcesInjectable from "../cluster/request-api-resources.injectable";
|
||||
import loggerInjectable from "../../common/logger.injectable";
|
||||
import detectorRegistryInjectable from "../cluster-detectors/detector-registry.injectable";
|
||||
import createVersionDetectorInjectable from "../cluster-detectors/create-version-detector.injectable";
|
||||
import broadcastMessageInjectable from "../../common/ipc/broadcast-message.injectable";
|
||||
import loadConfigfromFileInjectable from "../../common/kube-helpers/load-config-from-file.injectable";
|
||||
import requestNamespaceListPermissionsForInjectable from "../../common/cluster/request-namespace-list-permissions.injectable";
|
||||
import detectClusterMetadataInjectable from "../cluster-detectors/detect-cluster-metadata.injectable";
|
||||
import clusterVersionDetectorInjectable from "../cluster-detectors/cluster-version-detector.injectable";
|
||||
|
||||
const createClusterInjectable = getInjectable({
|
||||
id: "create-cluster",
|
||||
@@ -26,6 +26,8 @@ const createClusterInjectable = getInjectable({
|
||||
instantiate: (di) => {
|
||||
const dependencies: ClusterDependencies = {
|
||||
directoryForKubeConfigs: di.inject(directoryForKubeConfigsInjectable),
|
||||
logger: di.inject(loggerInjectable),
|
||||
clusterVersionDetector: di.inject(clusterVersionDetectorInjectable),
|
||||
createKubeconfigManager: di.inject(createKubeconfigManagerInjectable),
|
||||
createKubectl: di.inject(createKubectlInjectable),
|
||||
createContextHandler: di.inject(createContextHandlerInjectable),
|
||||
@@ -33,11 +35,9 @@ const createClusterInjectable = getInjectable({
|
||||
requestNamespaceListPermissionsFor: di.inject(requestNamespaceListPermissionsForInjectable),
|
||||
requestApiResources: di.inject(createListApiResourcesInjectable),
|
||||
createListNamespaces: di.inject(listNamespacesInjectable),
|
||||
logger: di.inject(loggerInjectable),
|
||||
detectorRegistry: di.inject(detectorRegistryInjectable),
|
||||
createVersionDetector: di.inject(createVersionDetectorInjectable),
|
||||
broadcastMessage: di.inject(broadcastMessageInjectable),
|
||||
loadConfigfromFile: di.inject(loadConfigfromFileInjectable),
|
||||
detectClusterMetadata: di.inject(detectClusterMetadataInjectable),
|
||||
};
|
||||
|
||||
return (model, configData) => new Cluster(dependencies, model, configData);
|
||||
|
||||
@@ -4,16 +4,19 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { Cluster } from "../common/cluster/cluster";
|
||||
import nodeFetchModuleInjectable from "../common/fetch/fetch-module.injectable";
|
||||
import type { RequestMetricsParams } from "../common/k8s-api/endpoints/metrics.api/request-metrics.injectable";
|
||||
import { object } from "../common/utils";
|
||||
import k8sRequestInjectable from "./k8s-request.injectable";
|
||||
|
||||
export type GetMetrics = (cluster: Cluster, prometheusPath: string, queryParams: RequestMetricsParams & { query: string }) => Promise<any>;
|
||||
export type GetMetrics = (cluster: Cluster, prometheusPath: string, queryParams: RequestMetricsParams & { query: string }) => Promise<unknown>;
|
||||
|
||||
const getMetricsInjectable = getInjectable({
|
||||
id: "get-metrics",
|
||||
|
||||
instantiate: (di): GetMetrics => {
|
||||
const k8sRequest = di.inject(k8sRequestInjectable);
|
||||
const { FormData } = di.inject(nodeFetchModuleInjectable);
|
||||
|
||||
return async (
|
||||
cluster,
|
||||
@@ -22,13 +25,16 @@ const getMetricsInjectable = getInjectable({
|
||||
) => {
|
||||
const prometheusPrefix = cluster.preferences.prometheus?.prefix || "";
|
||||
const metricsPath = `/api/v1/namespaces/${prometheusPath}/proxy${prometheusPrefix}/api/v1/query_range`;
|
||||
const body = new FormData();
|
||||
|
||||
for (const [key, value] of object.entries(queryParams)) {
|
||||
body.set(key, value.toString());
|
||||
}
|
||||
|
||||
return k8sRequest(cluster, metricsPath, {
|
||||
timeout: 0,
|
||||
resolveWithFullResponse: false,
|
||||
json: true,
|
||||
method: "POST",
|
||||
form: queryParams,
|
||||
body,
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
@@ -2,35 +2,49 @@
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { RequestPromiseOptions } from "request-promise-native";
|
||||
import request from "request-promise-native";
|
||||
import type { Cluster } from "../common/cluster/cluster";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import lensProxyPortInjectable from "./lens-proxy/lens-proxy-port.injectable";
|
||||
import lensProxyCertificateInjectable from "../common/certificate/lens-proxy-certificate.injectable";
|
||||
import type { LensRequestInit } from "../common/fetch/lens-fetch.injectable";
|
||||
import lensFetchInjectable from "../common/fetch/lens-fetch.injectable";
|
||||
import { withTimeout } from "../common/fetch/timeout-controller";
|
||||
|
||||
export type K8sRequest = (cluster: Cluster, path: string, options?: RequestPromiseOptions) => Promise<any>;
|
||||
export interface K8sRequestInit extends LensRequestInit {
|
||||
timeout?: number;
|
||||
}
|
||||
|
||||
export type K8sRequest = (cluster: Cluster, pathnameAndQuery: string, init?: K8sRequestInit) => Promise<unknown>;
|
||||
|
||||
const k8sRequestInjectable = getInjectable({
|
||||
id: "k8s-request",
|
||||
|
||||
instantiate: (di) => {
|
||||
const lensProxyPort = di.inject(lensProxyPortInjectable);
|
||||
const lensProxyCertificate = di.inject(lensProxyCertificateInjectable);
|
||||
instantiate: (di): K8sRequest => {
|
||||
const lensFetch = di.inject(lensFetchInjectable);
|
||||
|
||||
return async (
|
||||
cluster: Cluster,
|
||||
path: string,
|
||||
options: RequestPromiseOptions = {},
|
||||
cluster,
|
||||
pathnameAndQuery,
|
||||
{
|
||||
timeout = 30_000,
|
||||
signal,
|
||||
...init
|
||||
} = {},
|
||||
) => {
|
||||
const kubeProxyUrl = `https://127.0.0.1:${lensProxyPort.get()}/${cluster.id}`;
|
||||
const controller = timeout ? withTimeout(timeout) : undefined;
|
||||
|
||||
options.ca = lensProxyCertificate.get().cert;
|
||||
options.headers ??= {};
|
||||
options.json ??= true;
|
||||
options.timeout ??= 30000;
|
||||
if (controller) {
|
||||
signal?.addEventListener("abort", () => controller.abort());
|
||||
}
|
||||
|
||||
return request(kubeProxyUrl + path, options);
|
||||
const response = await lensFetch(`/${cluster.id}${pathnameAndQuery}`, {
|
||||
...init,
|
||||
signal: controller?.signal ?? signal,
|
||||
});
|
||||
|
||||
if (response.status < 200 || response.status >= 300) {
|
||||
throw new Error(`Failed to ${init.method ?? "get"} ${pathnameAndQuery} for clusterId=${cluster.id}: ${response.statusText}`, { cause: response });
|
||||
}
|
||||
|
||||
return response.json();
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
+2
-2
@@ -3,15 +3,15 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import ipcMainInjectionToken from "../../../../common/ipc/ipc-main-injection-token";
|
||||
import { bundledExtensionsLoaded } from "../../../../common/ipc/extension-handling";
|
||||
import { delay } from "../../../../common/utils";
|
||||
import ipcMainInjectable from "../../../utils/channel/ipc-main/ipc-main.injectable";
|
||||
|
||||
const waitUntilBundledExtensionsAreLoadedInjectable = getInjectable({
|
||||
id: "wait-until-bundled-extensions-are-loaded",
|
||||
|
||||
instantiate: (di) => {
|
||||
const ipcMain = di.inject(ipcMainInjectable);
|
||||
const ipcMain = di.inject(ipcMainInjectionToken);
|
||||
|
||||
return async () => {
|
||||
const viewHasLoaded = new Promise<void>((resolve) => {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { iter } from "../../../common/utils";
|
||||
import clusterFramesInjectable from "../../../common/cluster-frames.injectable";
|
||||
import { IpcRendererNavigationEvents } from "../../../renderer/navigation/events";
|
||||
import { IpcRendererNavigationEvents } from "../../../common/ipc/navigation-events";
|
||||
import showApplicationWindowInjectable from "./show-application-window.injectable";
|
||||
import getCurrentApplicationWindowInjectable from "./application-window/get-current-application-window.injectable";
|
||||
import assert from "assert";
|
||||
|
||||
-36
@@ -1,36 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { ClusterIdDetector } from "../../cluster-detectors/cluster-id-detector";
|
||||
import { LastSeenDetector } from "../../cluster-detectors/last-seen-detector";
|
||||
import { VersionDetector } from "../../cluster-detectors/version-detector";
|
||||
import { DistributionDetector } from "../../cluster-detectors/distribution-detector";
|
||||
import { NodesCountDetector } from "../../cluster-detectors/nodes-count-detector";
|
||||
import detectorRegistryInjectable from "../../cluster-detectors/detector-registry.injectable";
|
||||
import { onLoadOfApplicationInjectionToken } from "../runnable-tokens/on-load-of-application-injection-token";
|
||||
|
||||
const setupDetectorRegistryInjectable = getInjectable({
|
||||
id: "setup-detector-registry",
|
||||
|
||||
instantiate: (di) => {
|
||||
const detectorRegistry = di.inject(detectorRegistryInjectable);
|
||||
|
||||
return {
|
||||
id: "setup-detector-registry",
|
||||
run: () => {
|
||||
detectorRegistry
|
||||
.add(ClusterIdDetector)
|
||||
.add(LastSeenDetector)
|
||||
.add(VersionDetector)
|
||||
.add(DistributionDetector)
|
||||
.add(NodesCountDetector);
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: onLoadOfApplicationInjectionToken,
|
||||
});
|
||||
|
||||
export default setupDetectorRegistryInjectable;
|
||||
+2
-2
@@ -4,14 +4,14 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { IpcMainEvent } from "electron";
|
||||
import ipcMainInjectable from "../ipc-main/ipc-main.injectable";
|
||||
import { enlistMessageChannelListenerInjectionToken } from "../../../../common/utils/channel/enlist-message-channel-listener-injection-token";
|
||||
import ipcMainInjectionToken from "../../../../common/ipc/ipc-main-injection-token";
|
||||
|
||||
const enlistMessageChannelListenerInjectable = getInjectable({
|
||||
id: "enlist-message-channel-listener-for-main",
|
||||
|
||||
instantiate: (di) => {
|
||||
const ipcMain = di.inject(ipcMainInjectable);
|
||||
const ipcMain = di.inject(ipcMainInjectionToken);
|
||||
|
||||
return ({ channel, handler }) => {
|
||||
const nativeOnCallback = (_: IpcMainEvent, message: unknown) => {
|
||||
|
||||
+2
-2
@@ -4,10 +4,10 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { IpcMainInvokeEvent } from "electron";
|
||||
import ipcMainInjectable from "../ipc-main/ipc-main.injectable";
|
||||
import type { Disposer } from "../../../../common/utils";
|
||||
import type { RequestChannel } from "../../../../common/utils/channel/request-channel-listener-injection-token";
|
||||
import type { RequestChannelListener } from "./listener-tokens";
|
||||
import ipcMainInjectionToken from "../../../../common/ipc/ipc-main-injection-token";
|
||||
|
||||
export type EnlistRequestChannelListener = <TChannel extends RequestChannel<unknown, unknown>>(listener: RequestChannelListener<TChannel>) => Disposer;
|
||||
|
||||
@@ -15,7 +15,7 @@ const enlistRequestChannelListenerInjectable = getInjectable({
|
||||
id: "enlist-request-channel-listener-for-main",
|
||||
|
||||
instantiate: (di): EnlistRequestChannelListener => {
|
||||
const ipcMain = di.inject(ipcMainInjectable);
|
||||
const ipcMain = di.inject(ipcMainInjectionToken);
|
||||
|
||||
return ({ channel, handler }) => {
|
||||
const nativeHandleCallback = (_: IpcMainInvokeEvent, request: unknown) => handler(request);
|
||||
|
||||
@@ -4,11 +4,13 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { ipcMain } from "electron";
|
||||
import ipcMainInjectionToken from "../../../../common/ipc/ipc-main-injection-token";
|
||||
|
||||
const ipcMainInjectable = getInjectable({
|
||||
id: "ipc-main",
|
||||
instantiate: () => ipcMain,
|
||||
causesSideEffects: true,
|
||||
injectionToken: ipcMainInjectionToken,
|
||||
});
|
||||
|
||||
export default ipcMainInjectable;
|
||||
-1
@@ -16,7 +16,6 @@ const setupKubernetesClusterCatalogAddMenuListenerInjectable = getInjectable({
|
||||
instantiate: (di) => ({
|
||||
id: "setup-kubernetes-cluster-catalog-add-menu-listener",
|
||||
run: () => {
|
||||
// NOTE: these have to be here so that they are initialized only after the `runAfter` is ran
|
||||
const navigateToAddCluster = di.inject(navigateToAddClusterInjectable);
|
||||
const addSyncEntries = di.inject(addSyncEntriesInjectable);
|
||||
const kubernetesClusterCategory = di.inject(kubernetesClusterCategoryInjectable);
|
||||
|
||||
@@ -30,8 +30,11 @@ const createClusterInjectable = getInjectable({
|
||||
requestNamespaceListPermissionsFor: () => { throw new Error("Tried to access back-end feature in front-end."); },
|
||||
createListNamespaces: () => { throw new Error("Tried to access back-end feature in front-end."); },
|
||||
requestApiResources: () => { throw new Error("Tried to access back-end feature in front-end."); },
|
||||
detectorRegistry: undefined as never,
|
||||
createVersionDetector: () => { throw new Error("Tried to access back-end feature in front-end."); },
|
||||
detectClusterMetadata: () => { throw new Error("Tried to access back-end feature in front-end."); },
|
||||
clusterVersionDetector: {
|
||||
detect: () => { throw new Error("Tried to access back-end feature in front-end."); },
|
||||
key: "irrelavent",
|
||||
},
|
||||
};
|
||||
|
||||
return (model, configData) => new Cluster(dependencies, model, configData);
|
||||
|
||||
@@ -10,15 +10,14 @@ import { observer } from "mobx-react";
|
||||
import { KubeObjectListLayout } from "../kube-object-list-layout";
|
||||
import type { HorizontalPodAutoscaler } from "../../../common/k8s-api/endpoints/horizontal-pod-autoscaler.api";
|
||||
import { Badge } from "../badge";
|
||||
import { cssNames, prevDefault } from "../../utils";
|
||||
import { cssNames } from "../../utils";
|
||||
import { KubeObjectStatusIcon } from "../kube-object-status-icon";
|
||||
import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout";
|
||||
import { KubeObjectAge } from "../kube-object/age";
|
||||
import type { HorizontalPodAutoscalerStore } from "./store";
|
||||
import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable";
|
||||
import horizontalPodAutoscalerStoreInjectable from "./store.injectable";
|
||||
import { NamespaceSelectBadge } from "../+namespaces/namespace-select-badge";
|
||||
|
||||
enum columnId {
|
||||
name = "name",
|
||||
@@ -33,7 +32,6 @@ enum columnId {
|
||||
|
||||
interface Dependencies {
|
||||
horizontalPodAutoscalerStore: HorizontalPodAutoscalerStore;
|
||||
filterByNamespace: FilterByNamespace;
|
||||
}
|
||||
|
||||
@observer
|
||||
@@ -90,13 +88,10 @@ class NonInjectedHorizontalPodAutoscalers extends React.Component<Dependencies>
|
||||
renderTableContents={hpa => [
|
||||
hpa.getName(),
|
||||
<KubeObjectStatusIcon key="icon" object={hpa} />,
|
||||
<a
|
||||
<NamespaceSelectBadge
|
||||
key="namespace"
|
||||
className="filterNamespace"
|
||||
onClick={prevDefault(() => this.props.filterByNamespace(hpa.getNs()))}
|
||||
>
|
||||
{hpa.getNs()}
|
||||
</a>,
|
||||
namespace={hpa.getNs()}
|
||||
/>,
|
||||
this.getTargets(hpa),
|
||||
hpa.getMinPods(),
|
||||
hpa.getMaxPods(),
|
||||
@@ -124,7 +119,6 @@ class NonInjectedHorizontalPodAutoscalers extends React.Component<Dependencies>
|
||||
export const HorizontalPodAutoscalers = withInjectables<Dependencies>(NonInjectedHorizontalPodAutoscalers, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
filterByNamespace: di.inject(filterByNamespaceInjectable),
|
||||
horizontalPodAutoscalerStore: di.inject(horizontalPodAutoscalerStoreInjectable),
|
||||
}),
|
||||
});
|
||||
@@ -21,8 +21,6 @@
|
||||
flex: .5;
|
||||
}
|
||||
|
||||
a.filterNamespace {
|
||||
border-bottom: unset;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -16,9 +16,7 @@ import { KubeObjectAge } from "../kube-object/age";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import leaseStoreInjectable from "./store.injectable";
|
||||
import type { LeaseStore } from "./store";
|
||||
import { prevDefault } from "../../utils";
|
||||
import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable";
|
||||
import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable";
|
||||
import { NamespaceSelectBadge } from "../+namespaces/namespace-select-badge";
|
||||
|
||||
enum columnId {
|
||||
name = "name",
|
||||
@@ -32,7 +30,6 @@ export interface LeaseProps extends KubeObjectDetailsProps<Lease> {
|
||||
|
||||
interface Dependencies {
|
||||
leaseStore: LeaseStore;
|
||||
filterByNamespace: FilterByNamespace;
|
||||
}
|
||||
|
||||
@observer
|
||||
@@ -67,13 +64,10 @@ class NonInjectedLease extends React.Component<LeaseProps & Dependencies> {
|
||||
renderTableContents={lease => [
|
||||
lease.getName(),
|
||||
<KubeObjectStatusIcon key="icon" object={lease} />,
|
||||
<a
|
||||
<NamespaceSelectBadge
|
||||
key="namespace"
|
||||
className="filterNamespace"
|
||||
onClick={prevDefault(() => this.props.filterByNamespace(lease.getNs()))}
|
||||
>
|
||||
{lease.getNs()}
|
||||
</a>,
|
||||
namespace={lease.getNs()}
|
||||
/>,
|
||||
lease.getHolderIdentity(),
|
||||
<KubeObjectAge key="age" object={lease} />,
|
||||
]}
|
||||
@@ -87,6 +81,5 @@ export const Leases = withInjectables<Dependencies, LeaseProps>(NonInjectedLease
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
leaseStore: di.inject(leaseStoreInjectable),
|
||||
filterByNamespace: di.inject(filterByNamespaceInjectable),
|
||||
}),
|
||||
});
|
||||
@@ -11,12 +11,10 @@ import React from "react";
|
||||
import { KubeObjectStatusIcon } from "../kube-object-status-icon";
|
||||
import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout";
|
||||
import { KubeObjectAge } from "../kube-object/age";
|
||||
import { prevDefault } from "../../utils";
|
||||
import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable";
|
||||
import type { LimitRangeStore } from "./store";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable";
|
||||
import limitRangeStoreInjectable from "./store.injectable";
|
||||
import { NamespaceSelectBadge } from "../+namespaces/namespace-select-badge";
|
||||
|
||||
enum columnId {
|
||||
name = "name",
|
||||
@@ -25,7 +23,6 @@ enum columnId {
|
||||
}
|
||||
|
||||
interface Dependencies {
|
||||
filterByNamespace: FilterByNamespace;
|
||||
limitRangeStore: LimitRangeStore;
|
||||
}
|
||||
|
||||
@@ -58,13 +55,10 @@ class NonInjectedLimitRanges extends React.Component<Dependencies> {
|
||||
renderTableContents={limitRange => [
|
||||
limitRange.getName(),
|
||||
<KubeObjectStatusIcon key="icon" object={limitRange}/>,
|
||||
<a
|
||||
<NamespaceSelectBadge
|
||||
key="namespace"
|
||||
className="filterNamespace"
|
||||
onClick={prevDefault(() => this.props.filterByNamespace(limitRange.getNs()))}
|
||||
>
|
||||
{limitRange.getNs()}
|
||||
</a>,
|
||||
namespace={limitRange.getNs()}
|
||||
/>,
|
||||
<KubeObjectAge key="age" object={limitRange} />,
|
||||
]}
|
||||
/>
|
||||
@@ -76,7 +70,6 @@ class NonInjectedLimitRanges extends React.Component<Dependencies> {
|
||||
export const LimitRanges = withInjectables<Dependencies>(NonInjectedLimitRanges, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
filterByNamespace: di.inject(filterByNamespaceInjectable),
|
||||
limitRangeStore: di.inject(limitRangeStoreInjectable),
|
||||
}),
|
||||
});
|
||||
@@ -21,8 +21,6 @@
|
||||
flex: .5;
|
||||
}
|
||||
|
||||
a.filterNamespace {
|
||||
border-bottom: unset;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -11,12 +11,10 @@ import { KubeObjectListLayout } from "../kube-object-list-layout";
|
||||
import { KubeObjectStatusIcon } from "../kube-object-status-icon";
|
||||
import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout";
|
||||
import { KubeObjectAge } from "../kube-object/age";
|
||||
import { prevDefault } from "../../utils";
|
||||
import type { ConfigMapStore } from "./store";
|
||||
import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import configMapStoreInjectable from "./store.injectable";
|
||||
import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable";
|
||||
import { NamespaceSelectBadge } from "../+namespaces/namespace-select-badge";
|
||||
|
||||
enum columnId {
|
||||
name = "name",
|
||||
@@ -27,7 +25,6 @@ enum columnId {
|
||||
|
||||
interface Dependencies {
|
||||
configMapStore: ConfigMapStore;
|
||||
filterByNamespace: FilterByNamespace;
|
||||
}
|
||||
|
||||
@observer
|
||||
@@ -61,13 +58,10 @@ class NonInjectedConfigMaps extends React.Component<Dependencies> {
|
||||
renderTableContents={configMap => [
|
||||
configMap.getName(),
|
||||
<KubeObjectStatusIcon key="icon" object={configMap} />,
|
||||
<a
|
||||
<NamespaceSelectBadge
|
||||
key="namespace"
|
||||
className="filterNamespace"
|
||||
onClick={prevDefault(() => this.props.filterByNamespace(configMap.getNs()))}
|
||||
>
|
||||
{configMap.getNs()}
|
||||
</a>,
|
||||
namespace={configMap.getNs()}
|
||||
/>,
|
||||
configMap.getKeys().join(", "),
|
||||
<KubeObjectAge key="age" object={configMap} />,
|
||||
]}
|
||||
@@ -81,6 +75,5 @@ export const ConfigMaps = withInjectables<Dependencies>(NonInjectedConfigMaps, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
configMapStore: di.inject(configMapStoreInjectable),
|
||||
filterByNamespace: di.inject(filterByNamespaceInjectable),
|
||||
}),
|
||||
});
|
||||
+1
-3
@@ -21,8 +21,6 @@
|
||||
flex: .5;
|
||||
}
|
||||
|
||||
a.filterNamespace {
|
||||
border-bottom: unset;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+4
-11
@@ -13,12 +13,10 @@ import type { KubeObjectDetailsProps } from "../kube-object-details";
|
||||
import { KubeObjectListLayout } from "../kube-object-list-layout";
|
||||
import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout";
|
||||
import { KubeObjectAge } from "../kube-object/age";
|
||||
import { prevDefault } from "../../utils";
|
||||
import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable";
|
||||
import type { PodDisruptionBudgetStore } from "./store";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable";
|
||||
import podDisruptionBudgetStoreInjectable from "./store.injectable";
|
||||
import { NamespaceSelectBadge } from "../+namespaces/namespace-select-badge";
|
||||
|
||||
enum columnId {
|
||||
name = "name",
|
||||
@@ -34,7 +32,6 @@ export interface PodDisruptionBudgetsProps extends KubeObjectDetailsProps<PodDis
|
||||
}
|
||||
|
||||
interface Dependencies {
|
||||
filterByNamespace: FilterByNamespace;
|
||||
podDisruptionBudgetStore: PodDisruptionBudgetStore;
|
||||
}
|
||||
|
||||
@@ -74,13 +71,10 @@ class NonInjectedPodDisruptionBudgets extends React.Component<PodDisruptionBudge
|
||||
renderTableContents={pdb => [
|
||||
pdb.getName(),
|
||||
<KubeObjectStatusIcon key="icon" object={pdb} />,
|
||||
<a
|
||||
<NamespaceSelectBadge
|
||||
key="namespace"
|
||||
className="filterNamespace"
|
||||
onClick={prevDefault(() => this.props.filterByNamespace(pdb.getNs()))}
|
||||
>
|
||||
{pdb.getNs()}
|
||||
</a>,
|
||||
namespace={pdb.getNs()}
|
||||
/>,
|
||||
pdb.getMinAvailable(),
|
||||
pdb.getMaxUnavailable(),
|
||||
pdb.getCurrentHealthy(),
|
||||
@@ -96,7 +90,6 @@ class NonInjectedPodDisruptionBudgets extends React.Component<PodDisruptionBudge
|
||||
export const PodDisruptionBudgets = withInjectables<Dependencies, PodDisruptionBudgetsProps>(NonInjectedPodDisruptionBudgets, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
filterByNamespace: di.inject(filterByNamespaceInjectable),
|
||||
podDisruptionBudgetStore: di.inject(podDisruptionBudgetStoreInjectable),
|
||||
}),
|
||||
});
|
||||
@@ -9,8 +9,6 @@
|
||||
@include table-cell-warning;
|
||||
}
|
||||
|
||||
a.filterNamespace {
|
||||
border-bottom: unset;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -12,13 +12,11 @@ import { AddQuotaDialog } from "./add-dialog/view";
|
||||
import { KubeObjectStatusIcon } from "../kube-object-status-icon";
|
||||
import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout";
|
||||
import { KubeObjectAge } from "../kube-object/age";
|
||||
import { prevDefault } from "../../utils";
|
||||
import type { ResourceQuotaStore } from "./store";
|
||||
import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable";
|
||||
import resourceQuotaStoreInjectable from "./store.injectable";
|
||||
import openAddQuotaDialogInjectable from "./add-dialog/open.injectable";
|
||||
import { NamespaceSelectBadge } from "../+namespaces/namespace-select-badge";
|
||||
|
||||
enum columnId {
|
||||
name = "name",
|
||||
@@ -28,7 +26,6 @@ enum columnId {
|
||||
|
||||
interface Dependencies {
|
||||
resourceQuotaStore: ResourceQuotaStore;
|
||||
filterByNamespace: FilterByNamespace;
|
||||
openAddQuotaDialog: () => void;
|
||||
}
|
||||
|
||||
@@ -61,13 +58,10 @@ class NonInjectedResourceQuotas extends React.Component<Dependencies> {
|
||||
renderTableContents={resourceQuota => [
|
||||
resourceQuota.getName(),
|
||||
<KubeObjectStatusIcon key="icon" object={resourceQuota}/>,
|
||||
<a
|
||||
<NamespaceSelectBadge
|
||||
key="namespace"
|
||||
className="filterNamespace"
|
||||
onClick={prevDefault(() => this.props.filterByNamespace(resourceQuota.getNs()))}
|
||||
>
|
||||
{resourceQuota.getNs()}
|
||||
</a>,
|
||||
namespace={resourceQuota.getNs()}
|
||||
/>,
|
||||
<KubeObjectAge key="age" object={resourceQuota} />,
|
||||
]}
|
||||
addRemoveButtons={{
|
||||
@@ -84,7 +78,6 @@ class NonInjectedResourceQuotas extends React.Component<Dependencies> {
|
||||
export const ResourceQuotas = withInjectables<Dependencies>(NonInjectedResourceQuotas, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
filterByNamespace: di.inject(filterByNamespaceInjectable),
|
||||
resourceQuotaStore: di.inject(resourceQuotaStoreInjectable),
|
||||
openAddQuotaDialog: di.inject(openAddQuotaDialogInjectable),
|
||||
}),
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
@include table-cell-labels-offsets;
|
||||
}
|
||||
|
||||
a.filterNamespace {
|
||||
border-bottom: unset;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -13,13 +13,11 @@ import { Badge } from "../badge";
|
||||
import { KubeObjectStatusIcon } from "../kube-object-status-icon";
|
||||
import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout";
|
||||
import { KubeObjectAge } from "../kube-object/age";
|
||||
import { prevDefault } from "../../utils";
|
||||
import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable";
|
||||
import type { SecretStore } from "./store";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable";
|
||||
import secretStoreInjectable from "./store.injectable";
|
||||
import openAddSecretDialogInjectable from "./add-dialog/open.injectable";
|
||||
import { NamespaceSelectBadge } from "../+namespaces/namespace-select-badge";
|
||||
|
||||
enum columnId {
|
||||
name = "name",
|
||||
@@ -31,7 +29,6 @@ enum columnId {
|
||||
}
|
||||
|
||||
interface Dependencies {
|
||||
filterByNamespace: FilterByNamespace;
|
||||
secretStore: SecretStore;
|
||||
openAddSecretDialog: () => void;
|
||||
}
|
||||
@@ -71,13 +68,10 @@ class NonInjectedSecrets extends React.Component<Dependencies> {
|
||||
renderTableContents={secret => [
|
||||
secret.getName(),
|
||||
<KubeObjectStatusIcon key="icon" object={secret} />,
|
||||
<a
|
||||
<NamespaceSelectBadge
|
||||
key="namespace"
|
||||
className="filterNamespace"
|
||||
onClick={prevDefault(() => this.props.filterByNamespace(secret.getNs()))}
|
||||
>
|
||||
{secret.getNs()}
|
||||
</a>,
|
||||
namespace={secret.getNs()}
|
||||
/>,
|
||||
secret.getLabels().map(label => (
|
||||
<Badge
|
||||
scrollable
|
||||
@@ -104,7 +98,6 @@ class NonInjectedSecrets extends React.Component<Dependencies> {
|
||||
export const Secrets = withInjectables<Dependencies>(NonInjectedSecrets, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
filterByNamespace: di.inject(filterByNamespaceInjectable),
|
||||
secretStore: di.inject(secretStoreInjectable),
|
||||
openAddSecretDialog: di.inject(openAddSecretDialogInjectable),
|
||||
}),
|
||||
|
||||
@@ -4,7 +4,4 @@
|
||||
*/
|
||||
|
||||
.CrdResources {
|
||||
a.filterNamespace {
|
||||
border-bottom: unset;
|
||||
}
|
||||
}
|
||||
@@ -19,9 +19,7 @@ import { KubeObjectAge } from "../kube-object/age";
|
||||
import type { CustomResourceDefinitionStore } from "./definition.store";
|
||||
import apiManagerInjectable from "../../../common/k8s-api/api-manager/manager.injectable";
|
||||
import customResourceDefinitionStoreInjectable from "./definition.store.injectable";
|
||||
import { prevDefault } from "../../utils";
|
||||
import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable";
|
||||
import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable";
|
||||
import { NamespaceSelectBadge } from "../+namespaces/namespace-select-badge";
|
||||
|
||||
enum columnId {
|
||||
name = "name",
|
||||
@@ -34,7 +32,6 @@ interface Dependencies {
|
||||
name: IComputedValue<string>;
|
||||
apiManager: ApiManager;
|
||||
customResourceDefinitionStore: CustomResourceDefinitionStore;
|
||||
filterByNamespace: FilterByNamespace;
|
||||
}
|
||||
|
||||
@observer
|
||||
@@ -107,13 +104,7 @@ class NonInjectedCustomResources extends React.Component<Dependencies> {
|
||||
renderTableContents={customResource => [
|
||||
customResource.getName(),
|
||||
isNamespaced && (
|
||||
<a
|
||||
key="namespace"
|
||||
className="filterNamespace"
|
||||
onClick={prevDefault(() => this.props.filterByNamespace(customResource.getNs() as string))}
|
||||
>
|
||||
{customResource.getNs()}
|
||||
</a>
|
||||
<NamespaceSelectBadge namespace={customResource.getNs() as string} />
|
||||
),
|
||||
...extraColumns.map((column) => safeJSONPathValue(customResource, column.jsonPath)),
|
||||
<KubeObjectAge key="age" object={customResource} />,
|
||||
@@ -141,7 +132,6 @@ export const CustomResources = withInjectables<Dependencies>(NonInjectedCustomRe
|
||||
...di.inject(customResourcesRouteParametersInjectable),
|
||||
apiManager: di.inject(apiManagerInjectable),
|
||||
customResourceDefinitionStore: di.inject(customResourceDefinitionStoreInjectable),
|
||||
filterByNamespace: di.inject(filterByNamespaceInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -78,7 +78,7 @@ const NonInjectedEventDetails = observer(({
|
||||
|
||||
<DrawerTitle>Involved object</DrawerTitle>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableHead flat>
|
||||
<TableCell>Name</TableCell>
|
||||
<TableCell>Namespace</TableCell>
|
||||
<TableCell>Kind</TableCell>
|
||||
|
||||
@@ -19,7 +19,7 @@ import type { HeaderCustomizer } from "../item-object-list";
|
||||
import { Tooltip } from "../tooltip";
|
||||
import { Link } from "react-router-dom";
|
||||
import type { IClassName } from "../../utils";
|
||||
import { prevDefault, cssNames, stopPropagation } from "../../utils";
|
||||
import { cssNames, stopPropagation } from "../../utils";
|
||||
import { Icon } from "../icon";
|
||||
import type { ApiManager } from "../../../common/k8s-api/api-manager";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
@@ -28,10 +28,9 @@ import { KubeObjectAge } from "../kube-object/age";
|
||||
import { ReactiveDuration } from "../duration/reactive-duration";
|
||||
import apiManagerInjectable from "../../../common/k8s-api/api-manager/manager.injectable";
|
||||
import eventStoreInjectable from "./store.injectable";
|
||||
import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable";
|
||||
import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable";
|
||||
import type { GetDetailsUrl } from "../kube-detail-params/get-details-url.injectable";
|
||||
import getDetailsUrlInjectable from "../kube-detail-params/get-details-url.injectable";
|
||||
import { NamespaceSelectBadge } from "../+namespaces/namespace-select-badge";
|
||||
|
||||
enum columnId {
|
||||
message = "message",
|
||||
@@ -58,7 +57,6 @@ interface Dependencies {
|
||||
navigateToEvents: () => void;
|
||||
eventStore: EventStore;
|
||||
apiManager: ApiManager;
|
||||
filterByNamespace: FilterByNamespace;
|
||||
getDetailsUrl: GetDetailsUrl;
|
||||
}
|
||||
|
||||
@@ -202,15 +200,7 @@ class NonInjectedEvents extends React.Component<Dependencies & EventsProps> {
|
||||
),
|
||||
},
|
||||
compact
|
||||
? (
|
||||
<a
|
||||
key="namespace"
|
||||
className="filterNamespace"
|
||||
onClick={prevDefault(() => this.props.filterByNamespace(event.getNs()))}
|
||||
>
|
||||
{event.getNs()}
|
||||
</a>
|
||||
)
|
||||
? <NamespaceSelectBadge key="namespace" namespace={event.getNs()} />
|
||||
: event.getNs(),
|
||||
<Link
|
||||
key="link"
|
||||
@@ -246,7 +236,6 @@ export const Events = withInjectables<Dependencies, EventsProps>(NonInjectedEven
|
||||
navigateToEvents: di.inject(navigateToEventsInjectable),
|
||||
apiManager: di.inject(apiManagerInjectable),
|
||||
eventStore: di.inject(eventStoreInjectable),
|
||||
filterByNamespace: di.inject(filterByNamespaceInjectable),
|
||||
getDetailsUrl: di.inject(getDetailsUrlInjectable),
|
||||
}),
|
||||
});
|
||||
+3
-3
@@ -22,8 +22,8 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.no-items {
|
||||
text-align: center;
|
||||
}
|
||||
.empty {
|
||||
opacity: 0.6;
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import "./kube-event-details.scss";
|
||||
import styles from "./kube-event-details.module.scss";
|
||||
|
||||
import React from "react";
|
||||
import { disposeOnUnmount, observer } from "mobx-react";
|
||||
@@ -57,14 +57,14 @@ class NonInjectedKubeEventDetails extends React.Component<KubeEventDetailsProps
|
||||
|
||||
return (
|
||||
<div>
|
||||
<DrawerTitle className="flex gaps align-center">
|
||||
<DrawerTitle>
|
||||
<span>Events</span>
|
||||
</DrawerTitle>
|
||||
{events.length > 0 && (
|
||||
<div className="KubeEventDetails">
|
||||
<div className={styles.KubeEventDetails}>
|
||||
{events.map(event => (
|
||||
<div className="event" key={event.getId()}>
|
||||
<div className={cssNames("title", { warning: event.isWarning() })}>
|
||||
<div className={styles.event} key={event.getId()}>
|
||||
<div className={cssNames(styles.title, { [styles.warning]: event.isWarning() })}>
|
||||
{event.message}
|
||||
</div>
|
||||
<DrawerItem name="Source">
|
||||
@@ -85,6 +85,11 @@ class NonInjectedKubeEventDetails extends React.Component<KubeEventDetailsProps
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{events.length === 0 && (
|
||||
<div className={styles.empty}>
|
||||
No events found
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
a.filterNamespace {
|
||||
border-bottom: unset;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -23,9 +23,7 @@ import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout";
|
||||
import helmReleasesRouteParametersInjectable from "./helm-releases-route-parameters.injectable";
|
||||
import type { NavigateToHelmReleases } from "../../../common/front-end-routing/routes/cluster/helm/releases/navigate-to-helm-releases.injectable";
|
||||
import navigateToHelmReleasesInjectable from "../../../common/front-end-routing/routes/cluster/helm/releases/navigate-to-helm-releases.injectable";
|
||||
import { prevDefault } from "../../utils";
|
||||
import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable";
|
||||
import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable";
|
||||
import { NamespaceSelectBadge } from "../+namespaces/namespace-select-badge";
|
||||
|
||||
enum columnId {
|
||||
name = "name",
|
||||
@@ -43,19 +41,9 @@ interface Dependencies {
|
||||
releasesArePending: IComputedValue<boolean>;
|
||||
namespace: IComputedValue<string>;
|
||||
navigateToHelmReleases: NavigateToHelmReleases;
|
||||
filterByNamespace: FilterByNamespace;
|
||||
}
|
||||
|
||||
class NonInjectedHelmReleases extends Component<Dependencies> {
|
||||
// TODO: This side-effect in mount must go.
|
||||
componentDidMount() {
|
||||
const namespace = this.props.namespace.get();
|
||||
|
||||
if (namespace) {
|
||||
this.props.filterByNamespace(namespace);
|
||||
}
|
||||
}
|
||||
|
||||
onDetails = (item: HelmRelease) => {
|
||||
this.showDetails(item);
|
||||
};
|
||||
@@ -188,13 +176,10 @@ class NonInjectedHelmReleases extends Component<Dependencies> {
|
||||
]}
|
||||
renderTableContents={release => [
|
||||
release.getName(),
|
||||
<a
|
||||
<NamespaceSelectBadge
|
||||
key="namespace"
|
||||
className="filterNamespace"
|
||||
onClick={prevDefault(() => this.props.filterByNamespace(release.getNs()))}
|
||||
>
|
||||
{release.getNs()}
|
||||
</a>,
|
||||
namespace={release.getNs()}
|
||||
/>,
|
||||
release.getChart(),
|
||||
release.getRevision(),
|
||||
release.getVersion(),
|
||||
@@ -226,7 +211,6 @@ export const HelmReleases = withInjectables<Dependencies>(NonInjectedHelmRelease
|
||||
releases: di.inject(removableReleasesInjectable),
|
||||
releasesArePending: di.inject(releasesInjectable).pending,
|
||||
navigateToHelmReleases: di.inject(navigateToHelmReleasesInjectable),
|
||||
filterByNamespace: di.inject(filterByNamespaceInjectable),
|
||||
...di.inject(helmReleasesRouteParametersInjectable),
|
||||
}),
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
.NamespaceSelectBadge {
|
||||
@include pseudo-link;
|
||||
border-bottom: unset;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import styles from "./namespace-select-badge.module.scss";
|
||||
import React from "react";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import type { BadgeProps } from "../badge";
|
||||
import { Badge } from "../badge";
|
||||
import type {
|
||||
FilterByNamespace,
|
||||
} from "./namespace-select-filter-model/filter-by-namespace.injectable";
|
||||
import filterByNamespaceInjectable
|
||||
from "./namespace-select-filter-model/filter-by-namespace.injectable";
|
||||
import { prevDefault, cssNames } from "../../utils";
|
||||
|
||||
export interface NamespaceSelectBadgeProps extends BadgeProps {
|
||||
namespace: string;
|
||||
}
|
||||
|
||||
export interface Dependencies {
|
||||
filterByNamespace: FilterByNamespace;
|
||||
}
|
||||
|
||||
export function NamespaceSelectBadgeNonInjected(
|
||||
{
|
||||
namespace,
|
||||
label,
|
||||
filterByNamespace,
|
||||
...props
|
||||
}: NamespaceSelectBadgeProps & Dependencies) {
|
||||
return (
|
||||
<Badge
|
||||
flat={true}
|
||||
expandable={false}
|
||||
{...props}
|
||||
label={namespace ?? label}
|
||||
tooltip={(
|
||||
<>
|
||||
Set global namespace filter to:
|
||||
<b>{namespace}</b>
|
||||
</>
|
||||
)}
|
||||
className={cssNames(styles.NamespaceSelectBadge, props.className)}
|
||||
onClick={prevDefault(() => filterByNamespace(namespace))}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export const NamespaceSelectBadge = withInjectables<Dependencies, NamespaceSelectBadgeProps>(NamespaceSelectBadgeNonInjected, {
|
||||
getProps(di, props) {
|
||||
return {
|
||||
...props,
|
||||
filterByNamespace: di.inject(filterByNamespaceInjectable),
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -13,8 +13,6 @@
|
||||
@include table-cell-warning;
|
||||
}
|
||||
|
||||
a.filterNamespace {
|
||||
border-bottom: unset;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -11,12 +11,10 @@ import { KubeObjectListLayout } from "../kube-object-list-layout";
|
||||
import { KubeObjectStatusIcon } from "../kube-object-status-icon";
|
||||
import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout";
|
||||
import { KubeObjectAge } from "../kube-object/age";
|
||||
import { prevDefault } from "../../utils";
|
||||
import type { EndpointsStore } from "./store";
|
||||
import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import endpointsStoreInjectable from "./store.injectable";
|
||||
import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable";
|
||||
import { NamespaceSelectBadge } from "../+namespaces/namespace-select-badge";
|
||||
|
||||
enum columnId {
|
||||
name = "name",
|
||||
@@ -27,7 +25,6 @@ enum columnId {
|
||||
|
||||
interface Dependencies {
|
||||
endpointsStore: EndpointsStore;
|
||||
filterByNamespace: FilterByNamespace;
|
||||
}
|
||||
|
||||
@observer
|
||||
@@ -59,13 +56,10 @@ class NonInjectedEndpoints extends React.Component<Dependencies> {
|
||||
renderTableContents={endpoint => [
|
||||
endpoint.getName(),
|
||||
<KubeObjectStatusIcon key="icon" object={endpoint} />,
|
||||
<a
|
||||
<NamespaceSelectBadge
|
||||
key="namespace"
|
||||
className="filterNamespace"
|
||||
onClick={prevDefault(() => this.props.filterByNamespace(endpoint.getNs()))}
|
||||
>
|
||||
{endpoint.getNs()}
|
||||
</a>,
|
||||
namespace={endpoint.getNs()}
|
||||
/>,
|
||||
endpoint.toString(),
|
||||
<KubeObjectAge key="age" object={endpoint} />,
|
||||
]}
|
||||
@@ -86,6 +80,5 @@ export const Endpoints = withInjectables<Dependencies>(NonInjectedEndpoints, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
endpointsStore: di.inject(endpointsStoreInjectable),
|
||||
filterByNamespace: di.inject(filterByNamespaceInjectable),
|
||||
}),
|
||||
});
|
||||
@@ -37,7 +37,7 @@ class NonInjectedIngressDetails extends React.Component<IngressDetailsProps & De
|
||||
)}
|
||||
{rule.http && (
|
||||
<Table className="paths">
|
||||
<TableHead>
|
||||
<TableHead flat>
|
||||
<TableCell className="path">Path</TableCell>
|
||||
<TableCell className="link">Link</TableCell>
|
||||
<TableCell className="backends">Backends</TableCell>
|
||||
|
||||
@@ -32,8 +32,6 @@
|
||||
@include table-cell-warning;
|
||||
}
|
||||
|
||||
a.filterNamespace {
|
||||
border-bottom: unset;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Loaded 100 of 294 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user