mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Merge remote-tracking branch 'origin/master' into fix/resource_details_panel_stale_data
This commit is contained in:
commit
980a9f510a
60 files changed
+33499
-36968
No files matched your search
@@ -1,3 +0,0 @@
|
||||
disturl "https://electronjs.org/headers"
|
||||
target "19.0.4"
|
||||
runtime "electron"
|
||||
+10
-10
@@ -50,14 +50,14 @@
|
||||
"license": "MIT",
|
||||
"author": "OpenLens Authors <info@k8slens.dev>",
|
||||
"scripts": {
|
||||
"build": "cross-env NODE_ENV=production yarn run webpack --config webpack/library-bundle.ts --progress",
|
||||
"build": "cross-env NODE_ENV=production webpack --config webpack/library-bundle.ts --progress",
|
||||
"clean": "rimraf dist static/build",
|
||||
"prepare:dev": "cross-env NODE_ENV=development yarn run webpack --config webpack/library-bundle.ts --progress",
|
||||
"dev": "cross-env NODE_ENV=development yarn run webpack --config webpack/library-bundle.ts --watch",
|
||||
"prepare:dev": "cross-env NODE_ENV=development webpack --config webpack/library-bundle.ts --progress",
|
||||
"dev": "cross-env NODE_ENV=development webpack --config webpack/library-bundle.ts --watch",
|
||||
"test:unit": "jest --testPathIgnorePatterns integration",
|
||||
"test:watch": "func() { jest ${1} --watch --testPathIgnorePatterns integration; }; func",
|
||||
"lint": "PROD=true yarn run eslint --ext js,ts,tsx --max-warnings=0 .",
|
||||
"lint:fix": "yarn run lint --fix"
|
||||
"lint": "PROD=true eslint --ext js,ts,tsx --max-warnings=0 .",
|
||||
"lint:fix": "npm run lint --fix"
|
||||
},
|
||||
"config": {
|
||||
"k8sProxyVersion": "0.3.0",
|
||||
@@ -192,7 +192,7 @@
|
||||
"win-ca": "^3.5.0",
|
||||
"winston": "^3.8.2",
|
||||
"winston-transport-browserconsole": "^1.0.5",
|
||||
"ws": "^8.12.0",
|
||||
"ws": "^8.12.1",
|
||||
"xterm-link-provider": "^1.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -242,7 +242,7 @@
|
||||
"@types/react-window": "^1.8.5",
|
||||
"@types/readable-stream": "^2.3.13",
|
||||
"@types/semver": "^7.3.13",
|
||||
"@types/tar": "^6.1.3",
|
||||
"@types/tar": "^6.1.4",
|
||||
"@types/tcp-port-used": "^1.0.1",
|
||||
"@types/tempy": "^0.3.0",
|
||||
"@types/triple-beam": "^1.3.2",
|
||||
@@ -310,7 +310,7 @@
|
||||
"react-table": "^7.8.0",
|
||||
"react-window": "^1.8.8",
|
||||
"rimraf": "^4.1.2",
|
||||
"sass": "^1.58.1",
|
||||
"sass": "^1.58.2",
|
||||
"sass-loader": "^12.6.0",
|
||||
"style-loader": "^3.3.1",
|
||||
"tailwindcss": "^3.2.4",
|
||||
@@ -318,7 +318,7 @@
|
||||
"ts-node": "^10.9.1",
|
||||
"type-fest": "^2.14.0",
|
||||
"typed-emitter": "^1.4.0",
|
||||
"typedoc": "0.23.24",
|
||||
"typedoc": "0.23.25",
|
||||
"typedoc-plugin-markdown": "^3.13.6",
|
||||
"typescript": "^4.9.5",
|
||||
"typescript-plugin-css-modules": "^3.4.0",
|
||||
@@ -340,7 +340,7 @@
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"@types/react-virtualized-auto-sizer": "^1.0.1",
|
||||
"@types/react-window": "^1.8.5",
|
||||
"@types/tar": "^6.1.3",
|
||||
"@types/tar": "^6.1.4",
|
||||
"@types/tcp-port-used": "^1.0.1",
|
||||
"@types/url-parse": "^1.4.8",
|
||||
"@types/uuid": "^8.3.4",
|
||||
|
||||
+8
-7
@@ -37,18 +37,17 @@ export interface RequestMetricsParams {
|
||||
namespace?: string;
|
||||
}
|
||||
|
||||
export interface RequestMetrics {
|
||||
(query: string, params?: RequestMetricsParams): Promise<MetricData>;
|
||||
(query: string[], params?: RequestMetricsParams): Promise<MetricData[]>;
|
||||
<Keys extends string>(query: Record<Keys, Partial<Record<string, string>>>, params?: RequestMetricsParams): Promise<Record<Keys, MetricData>>;
|
||||
}
|
||||
export type RequestMetrics = ReturnType<typeof requestMetricsInjectable["instantiate"]>;
|
||||
|
||||
const requestMetricsInjectable = getInjectable({
|
||||
id: "request-metrics",
|
||||
instantiate: (di) => {
|
||||
const apiBase = di.inject(apiBaseInjectable);
|
||||
|
||||
return (async (query: object, params: RequestMetricsParams = {}) => {
|
||||
function requestMetrics(query: string, params?: RequestMetricsParams): Promise<MetricData>;
|
||||
function requestMetrics(query: string[], params?: RequestMetricsParams): Promise<MetricData[]>;
|
||||
function requestMetrics<Keys extends string>(query: Record<Keys, Partial<Record<string, string>>>, params?: RequestMetricsParams): Promise<Record<Keys, MetricData>>;
|
||||
async function requestMetrics(query: string | string[] | Partial<Record<string, Partial<Record<string, string>>>>, params: RequestMetricsParams = {}): Promise<MetricData | MetricData[] | Partial<Record<string, MetricData>>> {
|
||||
const { range = 3600, step = 60, namespace } = params;
|
||||
let { start, end } = params;
|
||||
|
||||
@@ -66,7 +65,9 @@ const requestMetricsInjectable = getInjectable({
|
||||
"kubernetes_namespace": namespace,
|
||||
},
|
||||
});
|
||||
}) as RequestMetrics;
|
||||
}
|
||||
|
||||
return requestMetrics;
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { getGlobalOverride } from "../test-utils/get-global-override";
|
||||
import randomBytesInjectable from "./random-bytes.injectable";
|
||||
|
||||
export default getGlobalOverride(randomBytesInjectable, () => async (size) => {
|
||||
export default getGlobalOverride(randomBytesInjectable, () => (size) => {
|
||||
const res = Buffer.alloc(size);
|
||||
|
||||
for (let i = 0; i < size; i += 1) {
|
||||
|
||||
@@ -4,13 +4,12 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { randomBytes } from "crypto";
|
||||
import { promisify } from "util";
|
||||
|
||||
export type RandomBytes = (size: number) => Promise<Buffer>;
|
||||
export type RandomBytes = (size: number) => Buffer;
|
||||
|
||||
const randomBytesInjectable = getInjectable({
|
||||
id: "random-bytes",
|
||||
instantiate: (): RandomBytes => promisify(randomBytes),
|
||||
instantiate: (): RandomBytes => randomBytes,
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
|
||||
+22
-8
@@ -3,17 +3,18 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { ObservableMap } from "mobx";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
|
||||
import { getOrInsertWithAsync } from "../../../common/utils";
|
||||
import { getOrInsert } from "../../../common/utils";
|
||||
import randomBytesInjectable from "../../../common/utils/random-bytes.injectable";
|
||||
import joinPathsInjectable from "../../../common/path/join-paths.injectable";
|
||||
import directoryForExtensionDataInjectable from "./directory-for-extension-data.injectable";
|
||||
import ensureDirInjectable from "../../../common/fs/ensure-dir.injectable";
|
||||
import getHashInjectable from "./get-hash.injectable";
|
||||
import getPathToLegacyPackageJsonInjectable from "./get-path-to-legacy-package-json.injectable";
|
||||
import { registeredExtensionsInjectable } from "./registered-extensions.injectable";
|
||||
|
||||
export type EnsureHashedDirectoryForExtension = (extensionName: string, registeredExtensions: ObservableMap<string, string>) => Promise<string>;
|
||||
export type EnsureHashedDirectoryForExtension = (extensionName: string) => Promise<string>;
|
||||
|
||||
const ensureHashedDirectoryForExtensionInjectable = getInjectable({
|
||||
id: "ensure-hashed-directory-for-extension",
|
||||
@@ -24,14 +25,27 @@ const ensureHashedDirectoryForExtensionInjectable = getInjectable({
|
||||
const directoryForExtensionData = di.inject(directoryForExtensionDataInjectable);
|
||||
const ensureDirectory = di.inject(ensureDirInjectable);
|
||||
const getHash = di.inject(getHashInjectable);
|
||||
const getPathToLegacyPackageJson = di.inject(getPathToLegacyPackageJsonInjectable);
|
||||
const registeredExtensions = di.inject(registeredExtensionsInjectable);
|
||||
|
||||
return async (extensionName, registeredExtensions) => {
|
||||
const dirPath = await getOrInsertWithAsync(registeredExtensions, extensionName, async () => {
|
||||
const salt = (await randomBytes(32)).toString("hex");
|
||||
return async (extensionName) => {
|
||||
let dirPath: string;
|
||||
|
||||
const legacyDirPath = getPathToLegacyPackageJson(extensionName);
|
||||
const hashedDirectoryForLegacyDirPath = registeredExtensions.get(legacyDirPath);
|
||||
|
||||
if (hashedDirectoryForLegacyDirPath) {
|
||||
registeredExtensions.set(extensionName, hashedDirectoryForLegacyDirPath);
|
||||
registeredExtensions.delete(legacyDirPath);
|
||||
dirPath = hashedDirectoryForLegacyDirPath;
|
||||
} else {
|
||||
const salt = randomBytes(32).toString("hex");
|
||||
const hashedName = getHash(`${extensionName}/${salt}`);
|
||||
|
||||
return joinPaths(directoryForExtensionData, hashedName);
|
||||
});
|
||||
const hashedExtensionDirectory = joinPaths(directoryForExtensionData, hashedName);
|
||||
|
||||
dirPath = getOrInsert(registeredExtensions, extensionName, hashedExtensionDirectory);
|
||||
}
|
||||
|
||||
await ensureDirectory(dirPath);
|
||||
|
||||
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { ObservableMap } from "mobx";
|
||||
import { runInAction } from "mobx";
|
||||
import { getDiForUnitTesting } from "../../../main/getDiForUnitTesting";
|
||||
import type { EnsureHashedDirectoryForExtension } from "./ensure-hashed-directory-for-extension.injectable";
|
||||
import ensureHashedDirectoryForExtensionInjectable from "./ensure-hashed-directory-for-extension.injectable";
|
||||
import ensureDirInjectable from "../../../common/fs/ensure-dir.injectable";
|
||||
import directoryForExtensionDataInjectable from "./directory-for-extension-data.injectable";
|
||||
import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||
import { registeredExtensionsInjectable } from "./registered-extensions.injectable";
|
||||
|
||||
describe("ensure-hashed-directory-for-extension", () => {
|
||||
let ensureHashedDirectoryForExtension: EnsureHashedDirectoryForExtension;
|
||||
let ensureDirMock: jest.Mock;
|
||||
let registeredExtensions: ObservableMap<string, string>;
|
||||
|
||||
beforeEach(() => {
|
||||
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
ensureDirMock = jest.fn();
|
||||
|
||||
di.override(ensureDirInjectable, () => ensureDirMock);
|
||||
di.override(directoryForExtensionDataInjectable, () => "some-directory-for-extension-data");
|
||||
di.override(directoryForUserDataInjectable, () => "/some-directory-for-user-data");
|
||||
|
||||
ensureHashedDirectoryForExtension = di.inject(
|
||||
ensureHashedDirectoryForExtensionInjectable,
|
||||
);
|
||||
|
||||
registeredExtensions = di.inject(registeredExtensionsInjectable);
|
||||
});
|
||||
|
||||
it("given registered extension exists, returns existing directory", async () => {
|
||||
runInAction(() => {
|
||||
registeredExtensions.set("some-extension-name", "some-directory");
|
||||
});
|
||||
|
||||
const actual = await ensureHashedDirectoryForExtension(
|
||||
"some-extension-name",
|
||||
);
|
||||
|
||||
expect(actual).toBe("some-directory");
|
||||
});
|
||||
|
||||
it("given registered extension does not exist, returns random directory", async () => {
|
||||
const actual = await ensureHashedDirectoryForExtension(
|
||||
"some-extension-name",
|
||||
);
|
||||
|
||||
expect(actual).toBe("some-directory-for-extension-data/a37a1cfefc0391af3733f23cb6b29443f596a2b8ffe6d116c35df7bc3cd99ef6");
|
||||
});
|
||||
|
||||
describe("given extension directory was saved based on extension's package.json path", () => {
|
||||
beforeEach(() => {
|
||||
runInAction(() => {
|
||||
registeredExtensions.set("/some-directory-for-user-data/node_modules/some-extension-name/package.json", "some-directory");
|
||||
});
|
||||
ensureDirMock.mockClear();
|
||||
});
|
||||
|
||||
it("returns existing directory", async () => {
|
||||
const actual = await ensureHashedDirectoryForExtension(
|
||||
"some-extension-name",
|
||||
);
|
||||
|
||||
expect(actual).toBe("some-directory");
|
||||
});
|
||||
|
||||
it("ensure dir is called with some directory", async () => {
|
||||
await ensureHashedDirectoryForExtension(
|
||||
"some-extension-name",
|
||||
);
|
||||
|
||||
expect(ensureDirMock).toHaveBeenCalledWith("some-directory");
|
||||
});
|
||||
|
||||
it("is migrated to use the extension name as key", async () => {
|
||||
await ensureHashedDirectoryForExtension(
|
||||
"some-extension-name",
|
||||
);
|
||||
|
||||
expect(registeredExtensions.get("some-extension-name")).toEqual("some-directory");
|
||||
});
|
||||
|
||||
it("old key is removed", async () => {
|
||||
await ensureHashedDirectoryForExtension(
|
||||
"some-extension-name",
|
||||
);
|
||||
|
||||
expect(registeredExtensions.has("/some-directory-for-user-data/node_modules/some-extension-name/package.json")).toEqual(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* 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 { MigrationDeclaration } from "../../../common/base-store/migrations.injectable";
|
||||
|
||||
export const fileSystemProvisionerStoreInjectionToken = getInjectionToken<MigrationDeclaration>({
|
||||
id: "file-system-provisioner-store-injection-token",
|
||||
});
|
||||
+2
@@ -14,6 +14,7 @@ import { persistStateToConfigInjectionToken } from "../../../common/base-store/s
|
||||
import getBasenameOfPathInjectable from "../../../common/path/get-basename.injectable";
|
||||
import { enlistMessageChannelListenerInjectionToken } from "../../../common/utils/channel/enlist-message-channel-listener-injection-token";
|
||||
import ensureHashedDirectoryForExtensionInjectable from "./ensure-hashed-directory-for-extension.injectable";
|
||||
import { registeredExtensionsInjectable } from "./registered-extensions.injectable";
|
||||
|
||||
const fileSystemProvisionerStoreInjectable = getInjectable({
|
||||
id: "file-system-provisioner-store",
|
||||
@@ -30,6 +31,7 @@ const fileSystemProvisionerStoreInjectable = getInjectable({
|
||||
enlistMessageChannelListener: di.inject(enlistMessageChannelListenerInjectionToken),
|
||||
shouldDisableSyncInListener: di.inject(shouldBaseStoreDisableSyncInIpcListenerInjectionToken),
|
||||
ensureHashedDirectoryForExtension: di.inject(ensureHashedDirectoryForExtensionInjectable),
|
||||
registeredExtensions: di.inject(registeredExtensionsInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
+6
-6
@@ -3,7 +3,8 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { action, makeObservable, observable } from "mobx";
|
||||
import type { ObservableMap } from "mobx";
|
||||
import { action, makeObservable } from "mobx";
|
||||
import type { BaseStoreDependencies } from "../../../common/base-store/base-store";
|
||||
import { BaseStore } from "../../../common/base-store/base-store";
|
||||
import type { LensExtensionId } from "../../lens-extension";
|
||||
@@ -16,11 +17,10 @@ interface FSProvisionModel {
|
||||
|
||||
interface Dependencies extends BaseStoreDependencies {
|
||||
ensureHashedDirectoryForExtension: EnsureHashedDirectoryForExtension;
|
||||
registeredExtensions: ObservableMap<LensExtensionId, string>;
|
||||
}
|
||||
|
||||
export class FileSystemProvisionerStore extends BaseStore<FSProvisionModel> {
|
||||
readonly registeredExtensions = observable.map<LensExtensionId, string>();
|
||||
|
||||
constructor(protected readonly dependencies: Dependencies) {
|
||||
super(dependencies, {
|
||||
configName: "lens-filesystem-provisioner-store",
|
||||
@@ -37,17 +37,17 @@ export class FileSystemProvisionerStore extends BaseStore<FSProvisionModel> {
|
||||
* @returns path to the folder that the extension can safely write files to.
|
||||
*/
|
||||
async requestDirectory(extensionName: string): Promise<string> {
|
||||
return this.dependencies.ensureHashedDirectoryForExtension(extensionName, this.registeredExtensions);
|
||||
return this.dependencies.ensureHashedDirectoryForExtension(extensionName);
|
||||
}
|
||||
|
||||
@action
|
||||
protected fromStore({ extensions }: FSProvisionModel = { extensions: {}}): void {
|
||||
this.registeredExtensions.merge(extensions);
|
||||
this.dependencies.registeredExtensions.merge(extensions);
|
||||
}
|
||||
|
||||
toJSON(): FSProvisionModel {
|
||||
return toJS({
|
||||
extensions: Object.fromEntries(this.registeredExtensions),
|
||||
extensions: Object.fromEntries(this.dependencies.registeredExtensions),
|
||||
});
|
||||
}
|
||||
}
|
||||
+22
@@ -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 directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||
import joinPathsInjectable from "../../../common/path/join-paths.injectable";
|
||||
|
||||
export type GetPathToLegacyPackageJson = (extensionName: string) => string;
|
||||
|
||||
const getPathToLegacyPackageJson = getInjectable({
|
||||
id: "get-path-to-legacy-package-json",
|
||||
|
||||
instantiate: (di): GetPathToLegacyPackageJson => {
|
||||
const directoryForUserData = di.inject(directoryForUserDataInjectable);
|
||||
const joinPaths = di.inject(joinPathsInjectable);
|
||||
|
||||
return (extensionName: string) => joinPaths(directoryForUserData, "node_modules", extensionName, "package.json");
|
||||
},
|
||||
});
|
||||
|
||||
export default getPathToLegacyPackageJson;
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* 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 { observable } from "mobx";
|
||||
import type { LensExtensionId } from "../../lens-extension";
|
||||
|
||||
export const registeredExtensionsInjectable = getInjectable({
|
||||
id: "registered-extensions",
|
||||
instantiate: () => observable.map<LensExtensionId, string>(),
|
||||
});
|
||||
@@ -38,6 +38,8 @@ import kubeEventApiInjectable from "../../common/k8s-api/endpoints/events.api.in
|
||||
import roleBindingApiInjectable from "../../common/k8s-api/endpoints/role-binding.api.injectable";
|
||||
import customResourceDefinitionApiInjectable from "../../common/k8s-api/endpoints/custom-resource-definition.api.injectable";
|
||||
import { shouldShowResourceInjectionToken } from "../../common/cluster-store/allowed-resources-injection-token";
|
||||
import { asLegacyGlobalFunctionForExtensionApi } from "../as-legacy-globals-for-extension-api/as-legacy-global-function-for-extension-api";
|
||||
import requestMetricsInjectable from "../../common/k8s-api/endpoints/metrics.api/request-metrics.injectable";
|
||||
|
||||
export function isAllowedResource(resources: KubeResource | KubeResource[]) {
|
||||
const di = getLegacyGlobalDiForExtensionApi();
|
||||
@@ -93,6 +95,17 @@ export const crdApi = asLegacyGlobalForExtensionApi(customResourceDefinitionApiI
|
||||
|
||||
export * from "../common-api/k8s-api";
|
||||
|
||||
export const requestMetrics = asLegacyGlobalFunctionForExtensionApi(requestMetricsInjectable);
|
||||
|
||||
export type {
|
||||
RequestMetrics,
|
||||
RequestMetricsParams,
|
||||
} from "../../common/k8s-api/endpoints/metrics.api/request-metrics.injectable";
|
||||
export type {
|
||||
MetricData,
|
||||
MetricResult,
|
||||
} from "../../common/k8s-api/endpoints/metrics.api";
|
||||
|
||||
export {
|
||||
KubeObjectStatusLevel,
|
||||
type KubeObjectStatus,
|
||||
|
||||
+15
-3
@@ -79,7 +79,11 @@ exports[`disable kube object detail items when cluster is not relevant given ext
|
||||
<span
|
||||
class="value"
|
||||
>
|
||||
some-namespace
|
||||
<a
|
||||
href="/workloads?kube-details=%2Fapi%2Fv1%2Fnamespaces%2Fsome-namespace&kube-selected=%2Fapis%2Fsome-api-version%2Fnamespaces%2Fsome-namespace%2Fsome-kind%2Fsome-name"
|
||||
>
|
||||
some-namespace
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
@@ -695,7 +699,11 @@ exports[`disable kube object detail items when cluster is not relevant given ext
|
||||
<span
|
||||
class="value"
|
||||
>
|
||||
some-namespace
|
||||
<a
|
||||
href="/workloads?kube-details=%2Fapi%2Fv1%2Fnamespaces%2Fsome-namespace&kube-selected=%2Fapis%2Fsome-api-version%2Fnamespaces%2Fsome-namespace%2Fsome-kind%2Fsome-name"
|
||||
>
|
||||
some-namespace
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
@@ -1306,7 +1314,11 @@ exports[`disable kube object detail items when cluster is not relevant given not
|
||||
<span
|
||||
class="value"
|
||||
>
|
||||
some-namespace
|
||||
<a
|
||||
href="/workloads?kube-details=%2Fapi%2Fv1%2Fnamespaces%2Fsome-namespace&kube-selected=%2Fapis%2Fsome-api-version%2Fnamespaces%2Fsome-namespace%2Fsome-kind%2Fsome-name"
|
||||
>
|
||||
some-namespace
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
+10
-2
@@ -79,7 +79,11 @@ exports[`reactively hide kube object detail item renders 1`] = `
|
||||
<span
|
||||
class="value"
|
||||
>
|
||||
some-namespace
|
||||
<a
|
||||
href="/workloads?kube-details=%2Fapi%2Fv1%2Fnamespaces%2Fsome-namespace&kube-selected=%2Fapis%2Fsome-api-version%2Fnamespaces%2Fsome-namespace%2Fsome-kind%2Fsome-name"
|
||||
>
|
||||
some-namespace
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
@@ -690,7 +694,11 @@ exports[`reactively hide kube object detail item when the item is shown renders
|
||||
<span
|
||||
class="value"
|
||||
>
|
||||
some-namespace
|
||||
<a
|
||||
href="/workloads?kube-details=%2Fapi%2Fv1%2Fnamespaces%2Fsome-namespace&kube-selected=%2Fapis%2Fsome-api-version%2Fnamespaces%2Fsome-namespace%2Fsome-kind%2Fsome-name"
|
||||
>
|
||||
some-namespace
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
|
||||
@@ -29,17 +29,9 @@ export async function bootstrap(di: DiContainer) {
|
||||
|
||||
assert(rootElem, "#app MUST exist");
|
||||
|
||||
const extensionLoader = di.inject(extensionLoaderInjectable);
|
||||
|
||||
extensionLoader.init();
|
||||
|
||||
const extensionDiscovery = di.inject(extensionDiscoveryInjectable);
|
||||
|
||||
extensionDiscovery.init();
|
||||
|
||||
const extensionInstallationStateStore = di.inject(extensionInstallationStateStoreInjectable);
|
||||
|
||||
extensionInstallationStateStore.bindIpcListeners();
|
||||
await di.inject(extensionLoaderInjectable).init();
|
||||
await di.inject(extensionDiscoveryInjectable).init();
|
||||
di.inject(extensionInstallationStateStoreInjectable).bindIpcListeners();
|
||||
|
||||
let App;
|
||||
let initializeApp;
|
||||
|
||||
@@ -9,7 +9,7 @@ import React from "react";
|
||||
import upperFirst from "lodash/upperFirst";
|
||||
import kebabCase from "lodash/kebabCase";
|
||||
import { disposeOnUnmount, observer } from "mobx-react";
|
||||
import { DrawerItem, DrawerItemLabels } from "../drawer";
|
||||
import { DrawerItem } from "../drawer";
|
||||
import { Badge } from "../badge";
|
||||
import type { KubeObjectDetailsProps } from "../kube-object-details";
|
||||
import { formatNodeTaint, Node } from "../../../common/k8s-api/endpoints";
|
||||
@@ -23,7 +23,8 @@ import subscribeStoresInjectable from "../../kube-watch-api/subscribe-stores.inj
|
||||
import type { PodStore } from "../+workloads-pods/store";
|
||||
import podStoreInjectable from "../+workloads-pods/store.injectable";
|
||||
import loggerInjectable from "../../../common/logger.injectable";
|
||||
import loadPodsFromAllNamespacesInjectable from "../+workloads-pods/load-pods-from-all-namespaces.injectable";
|
||||
import loadPodsFromAllNamespacesInjectable
|
||||
from "../+workloads-pods/load-pods-from-all-namespaces.injectable";
|
||||
|
||||
export interface NodeDetailsProps extends KubeObjectDetailsProps<Node> {
|
||||
}
|
||||
@@ -97,14 +98,6 @@ class NonInjectedNodeDetails extends React.Component<NodeDetailsProps & Dependen
|
||||
</DrawerItem>
|
||||
</>
|
||||
)}
|
||||
<DrawerItemLabels
|
||||
name="Labels"
|
||||
labels={node.getLabels()}
|
||||
/>
|
||||
<DrawerItemLabels
|
||||
name="Annotations"
|
||||
labels={node.getAnnotations()}
|
||||
/>
|
||||
{taints.length > 0 && (
|
||||
<DrawerItem name="Taints" labelsOnly>
|
||||
{taints.map(taint => <Badge key={taint.key} label={formatNodeTaint(taint)} />)}
|
||||
|
||||
@@ -7,10 +7,6 @@
|
||||
--overlay-bg: #8cc474b8;
|
||||
--overlay-active-bg: orange;
|
||||
|
||||
// fix for `this.logsElement.scrollTop = this.logsElement.scrollHeight`
|
||||
// `overflow: overlay` don't allow scroll to the last line
|
||||
overflow: auto;
|
||||
|
||||
position: relative;
|
||||
color: var(--logsForeground);
|
||||
background: var(--logsBackground);
|
||||
@@ -21,6 +17,7 @@
|
||||
|
||||
.list {
|
||||
overflow-x: scroll!important;
|
||||
overflow-y: auto!important;
|
||||
|
||||
.LogRow {
|
||||
padding: 2px 16px;
|
||||
|
||||
@@ -28,7 +28,7 @@ export interface InstantiateArgs {
|
||||
const logsViewModelInjectable = getInjectable({
|
||||
id: "logs-view-model",
|
||||
|
||||
instantiate: (di, { tabId }: InstantiateArgs) => new LogTabViewModel(tabId, {
|
||||
instantiate: (di, tabId) => new LogTabViewModel(tabId, {
|
||||
getLogs: di.inject(getLogsInjectable),
|
||||
getLogsWithoutTimestamps: di.inject(getLogsWithoutTimestampsInjectable),
|
||||
getTimestampSplitLogs: di.inject(getTimestampSplitLogsInjectable),
|
||||
@@ -45,7 +45,10 @@ const logsViewModelInjectable = getInjectable({
|
||||
downloadAllLogs: di.inject(downloadAllLogsInjectable),
|
||||
searchStore: di.inject(searchStoreInjectable),
|
||||
}),
|
||||
lifecycle: lifecycleEnum.transient,
|
||||
|
||||
lifecycle: lifecycleEnum.keyedSingleton({
|
||||
getInstanceKey: (di, tabId: TabId) => `log-tab-view-model-${tabId}}`,
|
||||
}),
|
||||
});
|
||||
|
||||
export default logsViewModelInjectable;
|
||||
@@ -101,9 +101,7 @@ const NonInjectedLogsDockTab = observer(({
|
||||
export const LogsDockTab = withInjectables<Dependencies, LogsDockTabProps>(NonInjectedLogsDockTab, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
model: di.inject(logsViewModelInjectable, {
|
||||
tabId: props.tab.id,
|
||||
}),
|
||||
model: di.inject(logsViewModelInjectable, props.tab.id),
|
||||
subscribeStores: di.inject(subscribeStoresInjectable),
|
||||
podStore: di.inject(podStoreInjectable),
|
||||
}),
|
||||
|
||||
@@ -19,6 +19,8 @@ import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import getDetailsUrlInjectable from "../kube-detail-params/get-details-url.injectable";
|
||||
import apiManagerInjectable from "../../../common/k8s-api/api-manager/manager.injectable";
|
||||
import loggerInjectable from "../../../common/logger.injectable";
|
||||
import type { NamespaceApi } from "../../../common/k8s-api/endpoints";
|
||||
import namespaceApiInjectable from "../../../common/k8s-api/endpoints/namespace.api.injectable";
|
||||
|
||||
export interface KubeObjectMetaProps {
|
||||
object: KubeObject;
|
||||
@@ -28,20 +30,24 @@ export interface KubeObjectMetaProps {
|
||||
interface Dependencies {
|
||||
getDetailsUrl: GetDetailsUrl;
|
||||
apiManager: ApiManager;
|
||||
namespaceApi: NamespaceApi;
|
||||
logger: Logger;
|
||||
}
|
||||
|
||||
const NonInjectedKubeObjectMeta = observer(({
|
||||
apiManager,
|
||||
getDetailsUrl,
|
||||
object,
|
||||
hideFields = [
|
||||
"uid",
|
||||
"resourceVersion",
|
||||
"selfLink",
|
||||
],
|
||||
logger,
|
||||
}: Dependencies & KubeObjectMetaProps) => {
|
||||
const NonInjectedKubeObjectMeta = observer((
|
||||
{
|
||||
apiManager,
|
||||
getDetailsUrl,
|
||||
object,
|
||||
hideFields = [
|
||||
"uid",
|
||||
"resourceVersion",
|
||||
"selfLink",
|
||||
],
|
||||
logger,
|
||||
namespaceApi,
|
||||
}
|
||||
: Dependencies & KubeObjectMetaProps) => {
|
||||
if (!object) {
|
||||
return null;
|
||||
}
|
||||
@@ -59,6 +65,10 @@ const NonInjectedKubeObjectMeta = observer(({
|
||||
getFinalizers, getId, getName, metadata: { creationTimestamp },
|
||||
} = object;
|
||||
const ownerRefs = object.getOwnerRefs();
|
||||
const namespace = getNs();
|
||||
const namespaceDetailsUrl = namespace ? getDetailsUrl(
|
||||
namespaceApi.formatUrlForNotListing({ name: namespace }),
|
||||
) : "";
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -71,8 +81,8 @@ const NonInjectedKubeObjectMeta = observer(({
|
||||
{getName()}
|
||||
<KubeObjectStatusIcon key="icon" object={object} />
|
||||
</DrawerItem>
|
||||
<DrawerItem name="Namespace" hidden={isHidden("namespace") || !getNs()}>
|
||||
{getNs()}
|
||||
<DrawerItem name="Namespace" hidden={isHidden("namespace") || !namespace}>
|
||||
<Link to={namespaceDetailsUrl}>{namespace}</Link>
|
||||
</DrawerItem>
|
||||
<DrawerItem name="UID" hidden={isHidden("uid")}>
|
||||
{getId()}
|
||||
@@ -122,5 +132,6 @@ export const KubeObjectMeta = withInjectables<Dependencies, KubeObjectMetaProps>
|
||||
getDetailsUrl: di.inject(getDetailsUrlInjectable),
|
||||
apiManager: di.inject(apiManagerInjectable),
|
||||
logger: di.inject(loggerInjectable),
|
||||
namespaceApi: di.inject(namespaceApiInjectable),
|
||||
}),
|
||||
});
|
||||
@@ -36,7 +36,7 @@ const webpackLensMain = (): webpack.Configuration => {
|
||||
extensions: [".json", ".js", ".ts"],
|
||||
},
|
||||
externals: [
|
||||
nodeExternals(),
|
||||
nodeExternals({ modulesFromFile: true }),
|
||||
],
|
||||
module: {
|
||||
parser: {
|
||||
|
||||
@@ -46,7 +46,7 @@ export function webpackLensRenderer(): webpack.Configuration {
|
||||
],
|
||||
},
|
||||
externals: [
|
||||
nodeExternals(),
|
||||
nodeExternals({ modulesFromFile: true }),
|
||||
],
|
||||
optimization: {
|
||||
minimize: false,
|
||||
|
||||
-12948
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user