mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
chore: Simplify extension dependency injection
- Has better typing
- Removes use of unnusual unique symbol
- Fix welcome banner tests
- Update associated snapshots
- Start converting custom column tests to use ApplicationBuilder
- Remove old and unnused RecursiveTreeView
- Introduce new TreeView for use in CatalogMenu to fix tests
Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
5db8fc1342
commit
82bf67cc9e
@ -201,7 +201,7 @@ export abstract class LensProtocolRouter {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
const extension = extensionLoader.getInstanceByName(name);
|
const extension = extensionLoader.getInstanceByName(name) as LensExtension | undefined;
|
||||||
|
|
||||||
if (!extension) {
|
if (!extension) {
|
||||||
this.dependencies.logger.info(`${LensProtocolRouter.LoggingPrefix}: Extension ${name} matched, but does not have a class for ${ipcRenderer ? "renderer" : "main"}`);
|
this.dependencies.logger.info(`${LensProtocolRouter.LoggingPrefix}: Extension ${name} matched, but does not have a class for ${ipcRenderer ? "renderer" : "main"}`);
|
||||||
|
|||||||
@ -3,17 +3,23 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { LensExtension } from "../lens-extension";
|
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||||
import { Console } from "console";
|
import { LensMainExtension } from "../lens-main-extension";
|
||||||
import { stdout, stderr } from "process";
|
|
||||||
|
|
||||||
console = new Console(stdout, stderr);
|
|
||||||
|
|
||||||
let ext: LensExtension;
|
|
||||||
|
|
||||||
describe("lens extension", () => {
|
describe("lens extension", () => {
|
||||||
|
let ext: LensMainExtension;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
ext = new LensExtension({
|
const builder = getApplicationBuilder();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is required because it sets up `AppPaths` which are required by LensMainExtension.
|
||||||
|
*
|
||||||
|
* That type isn't used internally so it needs to use "legacy global DI" to get its dependencies.
|
||||||
|
*/
|
||||||
|
await builder.render();
|
||||||
|
|
||||||
|
ext = new LensMainExtension({
|
||||||
manifest: {
|
manifest: {
|
||||||
name: "foo-bar",
|
name: "foo-bar",
|
||||||
version: "0.1.1",
|
version: "0.1.1",
|
||||||
|
|||||||
@ -1,17 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import type { LensExtensionConstructor, BundledInstalledExtension, ExternalInstalledExtension, BundledLensExtensionConstructor } from "@k8slens/legacy-extensions";
|
|
||||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
|
||||||
import type { LensExtension } from "../lens-extension";
|
|
||||||
|
|
||||||
export interface CreateExtensionInstance {
|
|
||||||
(ExtensionClass: LensExtensionConstructor, extension: ExternalInstalledExtension): LensExtension;
|
|
||||||
(ExtensionClass: BundledLensExtensionConstructor, extension: BundledInstalledExtension): LensExtension;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const createExtensionInstanceInjectionToken = getInjectionToken<CreateExtensionInstance>({
|
|
||||||
id: "create-extension-instance-token",
|
|
||||||
});
|
|
||||||
@ -2,14 +2,13 @@
|
|||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
import type { LensExtensionId } from "@k8slens/legacy-extensions";
|
import type { LegacyLensExtension, LensExtensionId } from "@k8slens/legacy-extensions";
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import { observable } from "mobx";
|
import { observable } from "mobx";
|
||||||
import type { LensExtension } from "../lens-extension";
|
|
||||||
|
|
||||||
const extensionInstancesInjectable = getInjectable({
|
const extensionInstancesInjectable = getInjectable({
|
||||||
id: "extension-instances",
|
id: "extension-instances",
|
||||||
instantiate: () => observable.map<LensExtensionId, LensExtension>(),
|
instantiate: () => observable.map<LensExtensionId, LegacyLensExtension>(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default extensionInstancesInjectable;
|
export default extensionInstancesInjectable;
|
||||||
|
|||||||
@ -4,9 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import { ExtensionLoader } from "./extension-loader";
|
import { ExtensionLoader } from "./extension-loader";
|
||||||
import { createExtensionInstanceInjectionToken } from "./create-extension-instance.token";
|
|
||||||
import extensionInstancesInjectable from "./extension-instances.injectable";
|
import extensionInstancesInjectable from "./extension-instances.injectable";
|
||||||
import type { LensExtension } from "../lens-extension";
|
|
||||||
import extensionInjectable from "./extension/extension.injectable";
|
import extensionInjectable from "./extension/extension.injectable";
|
||||||
import loggerInjectable from "../../common/logger.injectable";
|
import loggerInjectable from "../../common/logger.injectable";
|
||||||
import joinPathsInjectable from "../../common/path/join-paths.injectable";
|
import joinPathsInjectable from "../../common/path/join-paths.injectable";
|
||||||
@ -20,9 +18,8 @@ const extensionLoaderInjectable = getInjectable({
|
|||||||
|
|
||||||
instantiate: (di) => new ExtensionLoader({
|
instantiate: (di) => new ExtensionLoader({
|
||||||
updateExtensionsState: di.inject(updateExtensionsStateInjectable),
|
updateExtensionsState: di.inject(updateExtensionsStateInjectable),
|
||||||
createExtensionInstance: di.inject(createExtensionInstanceInjectionToken),
|
|
||||||
extensionInstances: di.inject(extensionInstancesInjectable),
|
extensionInstances: di.inject(extensionInstancesInjectable),
|
||||||
getExtension: (instance: LensExtension) => di.inject(extensionInjectable, instance),
|
getExtension: (instance) => di.inject(extensionInjectable, instance),
|
||||||
bundledExtensions: di.injectMany(bundledExtensionInjectionToken),
|
bundledExtensions: di.injectMany(bundledExtensionInjectionToken),
|
||||||
extensionEntryPointName: di.inject(extensionEntryPointNameInjectionToken),
|
extensionEntryPointName: di.inject(extensionEntryPointNameInjectionToken),
|
||||||
logger: di.inject(loggerInjectable),
|
logger: di.inject(loggerInjectable),
|
||||||
|
|||||||
@ -9,13 +9,12 @@ import type { ObservableMap } from "mobx";
|
|||||||
import { runInAction, action, computed, toJS, observable, reaction, when } from "mobx";
|
import { runInAction, action, computed, toJS, observable, reaction, when } from "mobx";
|
||||||
import { broadcastMessage, ipcMainOn, ipcRendererOn, ipcMainHandle } from "../../common/ipc";
|
import { broadcastMessage, ipcMainOn, ipcRendererOn, ipcMainHandle } from "../../common/ipc";
|
||||||
import { isDefined, iter } from "@k8slens/utilities";
|
import { isDefined, iter } from "@k8slens/utilities";
|
||||||
import type { ExternalInstalledExtension, InstalledExtension, LensExtensionConstructor, LensExtensionId, BundledExtension } from "@k8slens/legacy-extensions";
|
import type { ExternalInstalledExtension, InstalledExtension, LensExtensionConstructor, LensExtensionId, BundledExtension, BundledInstalledExtension, LegacyLensExtension } from "@k8slens/legacy-extensions";
|
||||||
import type { LensExtension } from "../lens-extension";
|
import type { LensExtension } from "../lens-extension";
|
||||||
import { extensionLoaderFromMainChannel, extensionLoaderFromRendererChannel } from "../../common/ipc/extension-handling";
|
import { extensionLoaderFromMainChannel, extensionLoaderFromRendererChannel } from "../../common/ipc/extension-handling";
|
||||||
import { requestExtensionLoaderInitialState } from "../../renderer/ipc";
|
import { requestExtensionLoaderInitialState } from "../../renderer/ipc";
|
||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { EventEmitter } from "../../common/event-emitter";
|
import { EventEmitter } from "../../common/event-emitter";
|
||||||
import type { CreateExtensionInstance } from "./create-extension-instance.token";
|
|
||||||
import type { Extension } from "./extension/extension.injectable";
|
import type { Extension } from "./extension/extension.injectable";
|
||||||
import type { Logger } from "../../common/logger";
|
import type { Logger } from "../../common/logger";
|
||||||
import type { JoinPaths } from "../../common/path/join-paths.injectable";
|
import type { JoinPaths } from "../../common/path/join-paths.injectable";
|
||||||
@ -25,13 +24,12 @@ import type { UpdateExtensionsState } from "../../features/extensions/enabled/co
|
|||||||
const logModule = "[EXTENSIONS-LOADER]";
|
const logModule = "[EXTENSIONS-LOADER]";
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
readonly extensionInstances: ObservableMap<LensExtensionId, LensExtension>;
|
readonly extensionInstances: ObservableMap<LensExtensionId, LegacyLensExtension>;
|
||||||
readonly bundledExtensions: BundledExtension[];
|
readonly bundledExtensions: BundledExtension[];
|
||||||
readonly logger: Logger;
|
readonly logger: Logger;
|
||||||
readonly extensionEntryPointName: "main" | "renderer";
|
readonly extensionEntryPointName: "main" | "renderer";
|
||||||
updateExtensionsState: UpdateExtensionsState;
|
updateExtensionsState: UpdateExtensionsState;
|
||||||
createExtensionInstance: CreateExtensionInstance;
|
getExtension: (instance: LegacyLensExtension) => Extension;
|
||||||
getExtension: (instance: LensExtension) => Extension;
|
|
||||||
joinPaths: JoinPaths;
|
joinPaths: JoinPaths;
|
||||||
getDirnameOfPath: GetDirnameOfPath;
|
getDirnameOfPath: GetDirnameOfPath;
|
||||||
}
|
}
|
||||||
@ -85,7 +83,7 @@ export class ExtensionLoader {
|
|||||||
* - `null` if no class definition is provided for the current process
|
* - `null` if no class definition is provided for the current process
|
||||||
* - `undefined` if the name is not known about
|
* - `undefined` if the name is not known about
|
||||||
*/
|
*/
|
||||||
getInstanceByName(name: string): LensExtension | null | undefined {
|
getInstanceByName(name: string): LegacyLensExtension | null | undefined {
|
||||||
if (this.nonInstancesByName.has(name)) {
|
if (this.nonInstancesByName.has(name)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -236,7 +234,7 @@ export class ExtensionLoader {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const installedExtension: InstalledExtension = {
|
const installedExtension: BundledInstalledExtension = {
|
||||||
absolutePath: "irrelevant",
|
absolutePath: "irrelevant",
|
||||||
id: extension.manifest.name,
|
id: extension.manifest.name,
|
||||||
isBundled: true,
|
isBundled: true,
|
||||||
@ -245,10 +243,7 @@ export class ExtensionLoader {
|
|||||||
manifest: extension.manifest,
|
manifest: extension.manifest,
|
||||||
manifestPath: "irrelevant",
|
manifestPath: "irrelevant",
|
||||||
};
|
};
|
||||||
const instance = this.dependencies.createExtensionInstance(
|
const instance = new LensExtensionClass(installedExtension);
|
||||||
LensExtensionClass,
|
|
||||||
installedExtension,
|
|
||||||
);
|
|
||||||
|
|
||||||
this.dependencies.extensionInstances.set(extension.manifest.name, instance);
|
this.dependencies.extensionInstances.set(extension.manifest.name, instance);
|
||||||
|
|
||||||
@ -307,35 +302,32 @@ export class ExtensionLoader {
|
|||||||
|
|
||||||
return [...installedExtensions.entries()]
|
return [...installedExtensions.entries()]
|
||||||
.filter((entry): entry is [string, ExternalInstalledExtension] => !entry[1].isBundled)
|
.filter((entry): entry is [string, ExternalInstalledExtension] => !entry[1].isBundled)
|
||||||
.map(([extId, extension]) => {
|
.map(([extId, installedExtension]) => {
|
||||||
const alreadyInit = this.dependencies.extensionInstances.has(extId) || this.nonInstancesByName.has(extension.manifest.name);
|
const alreadyInit = this.dependencies.extensionInstances.has(extId) || this.nonInstancesByName.has(installedExtension.manifest.name);
|
||||||
|
|
||||||
if (extension.isCompatible && extension.isEnabled && !alreadyInit) {
|
if (installedExtension.isCompatible && installedExtension.isEnabled && !alreadyInit) {
|
||||||
try {
|
try {
|
||||||
const LensExtensionClass = this.requireExtension(extension);
|
const LensExtensionClass = this.requireExtension(installedExtension);
|
||||||
|
|
||||||
if (!LensExtensionClass) {
|
if (!LensExtensionClass) {
|
||||||
this.nonInstancesByName.add(extension.manifest.name);
|
this.nonInstancesByName.add(installedExtension.manifest.name);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const instance = this.dependencies.createExtensionInstance(
|
const instance = new LensExtensionClass(installedExtension);
|
||||||
LensExtensionClass,
|
|
||||||
extension,
|
|
||||||
);
|
|
||||||
|
|
||||||
this.dependencies.extensionInstances.set(extId, instance);
|
this.dependencies.extensionInstances.set(extId, instance);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
instance,
|
instance,
|
||||||
installedExtension: extension,
|
installedExtension,
|
||||||
activated: instance.activate(),
|
activated: instance.activate(),
|
||||||
} as ExtensionBeingActivated;
|
} as ExtensionBeingActivated;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.dependencies.logger.error(`${logModule}: error loading extension`, { ext: extension, err });
|
this.dependencies.logger.error(`${logModule}: error loading extension`, { ext: installedExtension, err });
|
||||||
}
|
}
|
||||||
} else if (!extension.isEnabled && alreadyInit) {
|
} else if (!installedExtension.isEnabled && alreadyInit) {
|
||||||
this.removeInstance(extId);
|
this.removeInstance(extId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,13 +2,14 @@
|
|||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
import type { LegacyLensExtension } from "@k8slens/legacy-extensions";
|
||||||
import type { Injectable } from "@ogre-tools/injectable";
|
import type { Injectable } from "@ogre-tools/injectable";
|
||||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||||
import type { IComputedValue } from "mobx";
|
import type { IComputedValue } from "mobx";
|
||||||
import type { LensExtension } from "../lens-extension";
|
|
||||||
|
|
||||||
export type ExtensionRegistrator = (extension: LensExtension) =>
|
export type Injectables = Injectable<any, any, any>[];
|
||||||
Injectable<any, any, any>[] | IComputedValue<Injectable<any, any, any>[]>;
|
export type Registration = Injectables | IComputedValue<Injectables>;
|
||||||
|
export type ExtensionRegistrator = (extension: LegacyLensExtension) => Registration;
|
||||||
|
|
||||||
export const extensionRegistratorInjectionToken = getInjectionToken<ExtensionRegistrator>({
|
export const extensionRegistratorInjectionToken = getInjectionToken<ExtensionRegistrator>({
|
||||||
id: "extension-registrator-token",
|
id: "extension-registrator-token",
|
||||||
|
|||||||
@ -5,9 +5,9 @@
|
|||||||
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||||
import { reaction, runInAction } from "mobx";
|
import { reaction, runInAction } from "mobx";
|
||||||
import { disposer } from "@k8slens/utilities";
|
import { disposer } from "@k8slens/utilities";
|
||||||
import type { LensExtension } from "../../lens-extension";
|
|
||||||
import { extensionRegistratorInjectionToken } from "../extension-registrator-injection-token";
|
import { extensionRegistratorInjectionToken } from "../extension-registrator-injection-token";
|
||||||
import { injectableDifferencingRegistratorWith } from "../../../common/utils/registrator-helper";
|
import { injectableDifferencingRegistratorWith } from "../../../common/utils/registrator-helper";
|
||||||
|
import type { LegacyLensExtension } from "@k8slens/legacy-extensions";
|
||||||
|
|
||||||
export interface Extension {
|
export interface Extension {
|
||||||
register: () => void;
|
register: () => void;
|
||||||
@ -17,7 +17,7 @@ export interface Extension {
|
|||||||
const extensionInjectable = getInjectable({
|
const extensionInjectable = getInjectable({
|
||||||
id: "extension",
|
id: "extension",
|
||||||
|
|
||||||
instantiate: (parentDi, instance: LensExtension): Extension => {
|
instantiate: (parentDi, instance): Extension => {
|
||||||
const extensionInjectable = getInjectable({
|
const extensionInjectable = getInjectable({
|
||||||
id: `extension-${instance.sanitizedExtensionId}`,
|
id: `extension-${instance.sanitizedExtensionId}`,
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ const extensionInjectable = getInjectable({
|
|||||||
},
|
},
|
||||||
|
|
||||||
lifecycle: lifecycleEnum.keyedSingleton({
|
lifecycle: lifecycleEnum.keyedSingleton({
|
||||||
getInstanceKey: (di, instance: LensExtension) => instance,
|
getInstanceKey: (di, instance: LegacyLensExtension) => instance,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -2,16 +2,23 @@
|
|||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
import { iter } from "@k8slens/utilities";
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import { computed } from "mobx";
|
import { computed } from "mobx";
|
||||||
|
import isExtensionEnabledInjectable from "../features/extensions/enabled/common/is-enabled.injectable";
|
||||||
import extensionInstancesInjectable from "./extension-loader/extension-instances.injectable";
|
import extensionInstancesInjectable from "./extension-loader/extension-instances.injectable";
|
||||||
|
|
||||||
const extensionsInjectable = getInjectable({
|
const extensionsInjectable = getInjectable({
|
||||||
id: "extensions",
|
id: "extensions",
|
||||||
instantiate: (di) => {
|
instantiate: (di) => {
|
||||||
const extensionInstances = di.inject(extensionInstancesInjectable);
|
const extensionInstances = di.inject(extensionInstancesInjectable);
|
||||||
|
const isExtensionEnabled = di.inject(isExtensionEnabledInjectable);
|
||||||
|
|
||||||
return computed(() => [...extensionInstances.values()].filter(extension => extension.isEnabled));
|
return computed(() => (
|
||||||
|
iter.chain(extensionInstances.values())
|
||||||
|
.filter(extension => extension.isBundled || isExtensionEnabled(extension.id))
|
||||||
|
.toArray()
|
||||||
|
));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -4,16 +4,31 @@
|
|||||||
*/
|
*/
|
||||||
import { ipcMain } from "electron";
|
import { ipcMain } from "electron";
|
||||||
import { IpcPrefix, IpcRegistrar } from "./ipc-registrar";
|
import { IpcPrefix, IpcRegistrar } from "./ipc-registrar";
|
||||||
import { Disposers, lensExtensionDependencies } from "../lens-extension";
|
import { Disposers } from "../lens-extension";
|
||||||
import type { LensMainExtension } from "../lens-main-extension";
|
import type { LensMainExtension } from "../lens-main-extension";
|
||||||
import type { Disposer } from "@k8slens/utilities";
|
import type { Disposer } from "@k8slens/utilities";
|
||||||
import { once } from "lodash";
|
import { once } from "lodash";
|
||||||
import { ipcMainHandle } from "../../common/ipc";
|
import { ipcMainHandle } from "../../common/ipc";
|
||||||
|
import type { Logger } from "../common-api";
|
||||||
|
import { getEnvironmentSpecificLegacyGlobalDiForExtensionApi } from "../as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
|
||||||
|
import loggerInjectable from "../../common/logger.injectable";
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
readonly logger: Logger;
|
||||||
|
}
|
||||||
|
|
||||||
export abstract class IpcMain extends IpcRegistrar {
|
export abstract class IpcMain extends IpcRegistrar {
|
||||||
|
private readonly dependencies: Dependencies;
|
||||||
|
|
||||||
constructor(extension: LensMainExtension) {
|
constructor(extension: LensMainExtension) {
|
||||||
super(extension);
|
super(extension);
|
||||||
|
|
||||||
|
const di = getEnvironmentSpecificLegacyGlobalDiForExtensionApi("main");
|
||||||
|
|
||||||
|
this.dependencies = {
|
||||||
|
logger: di.inject(loggerInjectable),
|
||||||
|
};
|
||||||
|
|
||||||
// Call the static method on the bottom child class.
|
// Call the static method on the bottom child class.
|
||||||
extension[Disposers].push(() => (this.constructor as typeof IpcMain).resetInstance());
|
extension[Disposers].push(() => (this.constructor as typeof IpcMain).resetInstance());
|
||||||
}
|
}
|
||||||
@ -27,12 +42,12 @@ export abstract class IpcMain extends IpcRegistrar {
|
|||||||
listen(channel: string, listener: (event: Electron.IpcRendererEvent, ...args: any[]) => any): Disposer {
|
listen(channel: string, listener: (event: Electron.IpcRendererEvent, ...args: any[]) => any): Disposer {
|
||||||
const prefixedChannel = `extensions@${this[IpcPrefix]}:${channel}`;
|
const prefixedChannel = `extensions@${this[IpcPrefix]}:${channel}`;
|
||||||
const cleanup = once(() => {
|
const cleanup = once(() => {
|
||||||
this.extension[lensExtensionDependencies].logger.debug(`[IPC-RENDERER]: removing extension listener`, { channel, extension: { name: this.extension.name, version: this.extension.version }});
|
this.dependencies.logger.debug(`[IPC-RENDERER]: removing extension listener`, { channel, extension: { name: this.extension.name, version: this.extension.version }});
|
||||||
|
|
||||||
return ipcMain.removeListener(prefixedChannel, listener);
|
return ipcMain.removeListener(prefixedChannel, listener);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.extension[lensExtensionDependencies].logger.debug(`[IPC-RENDERER]: adding extension listener`, { channel, extension: { name: this.extension.name, version: this.extension.version }});
|
this.dependencies.logger.debug(`[IPC-RENDERER]: adding extension listener`, { channel, extension: { name: this.extension.name, version: this.extension.version }});
|
||||||
ipcMain.addListener(prefixedChannel, listener);
|
ipcMain.addListener(prefixedChannel, listener);
|
||||||
this.extension[Disposers].push(cleanup);
|
this.extension[Disposers].push(cleanup);
|
||||||
|
|
||||||
@ -47,10 +62,10 @@ export abstract class IpcMain extends IpcRegistrar {
|
|||||||
handle(channel: string, handler: (event: Electron.IpcMainInvokeEvent, ...args: any[]) => any): void {
|
handle(channel: string, handler: (event: Electron.IpcMainInvokeEvent, ...args: any[]) => any): void {
|
||||||
const prefixedChannel = `extensions@${this[IpcPrefix]}:${channel}`;
|
const prefixedChannel = `extensions@${this[IpcPrefix]}:${channel}`;
|
||||||
|
|
||||||
this.extension[lensExtensionDependencies].logger.debug(`[IPC-RENDERER]: adding extension handler`, { channel, extension: { name: this.extension.name, version: this.extension.version }});
|
this.dependencies.logger.debug(`[IPC-RENDERER]: adding extension handler`, { channel, extension: { name: this.extension.name, version: this.extension.version }});
|
||||||
ipcMainHandle(prefixedChannel, handler);
|
ipcMainHandle(prefixedChannel, handler);
|
||||||
this.extension[Disposers].push(() => {
|
this.extension[Disposers].push(() => {
|
||||||
this.extension[lensExtensionDependencies].logger.debug(`[IPC-RENDERER]: removing extension handler`, { channel, extension: { name: this.extension.name, version: this.extension.version }});
|
this.dependencies.logger.debug(`[IPC-RENDERER]: removing extension handler`, { channel, extension: { name: this.extension.name, version: this.extension.version }});
|
||||||
|
|
||||||
return ipcMain.removeHandler(prefixedChannel);
|
return ipcMain.removeHandler(prefixedChannel);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,33 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import type { IComputedValue } from "mobx";
|
|
||||||
import type { CatalogCategoryRegistry } from "../common/catalog";
|
|
||||||
import type { NavigateToRoute } from "../common/front-end-routing/navigate-to-route-injection-token";
|
|
||||||
import type { Route } from "../common/front-end-routing/front-end-route-injection-token";
|
|
||||||
import type { CatalogEntityRegistry as MainCatalogEntityRegistry } from "../main/catalog";
|
|
||||||
import type { CatalogEntityRegistry as RendererCatalogEntityRegistry } from "../renderer/api/catalog/entity/registry";
|
|
||||||
import type { GetExtensionPageParameters } from "../renderer/routes/get-extension-page-parameters.injectable";
|
|
||||||
import type { NavigateForExtension } from "../main/start-main-application/lens-window/navigate-for-extension.injectable";
|
|
||||||
import type { Logger } from "../common/logger";
|
|
||||||
import type { EnsureHashedDirectoryForExtension } from "./extension-loader/file-system-provisioner-store/ensure-hashed-directory-for-extension.injectable";
|
|
||||||
|
|
||||||
export interface LensExtensionDependencies {
|
|
||||||
readonly logger: Logger;
|
|
||||||
ensureHashedDirectoryForExtension: EnsureHashedDirectoryForExtension;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LensMainExtensionDependencies extends LensExtensionDependencies {
|
|
||||||
readonly entityRegistry: MainCatalogEntityRegistry;
|
|
||||||
readonly navigate: NavigateForExtension;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LensRendererExtensionDependencies extends LensExtensionDependencies {
|
|
||||||
navigateToRoute: NavigateToRoute;
|
|
||||||
getExtensionPageParameters: GetExtensionPageParameters;
|
|
||||||
readonly routes: IComputedValue<Route<unknown>[]>;
|
|
||||||
readonly entityRegistry: RendererCatalogEntityRegistry;
|
|
||||||
readonly categoryRegistry: CatalogCategoryRegistry;
|
|
||||||
}
|
|
||||||
@ -5,19 +5,19 @@
|
|||||||
|
|
||||||
import { action, computed, makeObservable, observable } from "mobx";
|
import { action, computed, makeObservable, observable } from "mobx";
|
||||||
import { disposer } from "@k8slens/utilities";
|
import { disposer } from "@k8slens/utilities";
|
||||||
import type { LensExtensionDependencies } from "./lens-extension-set-dependencies";
|
|
||||||
import type { ProtocolHandlerRegistration } from "../common/protocol-handler/registration";
|
import type { ProtocolHandlerRegistration } from "../common/protocol-handler/registration";
|
||||||
import type { InstalledExtension, LegacyLensExtension, LensExtensionId, LensExtensionManifest } from "@k8slens/legacy-extensions";
|
import type { InstalledExtension, LensExtensionId, LensExtensionManifest } from "@k8slens/legacy-extensions";
|
||||||
|
import type { Logger } from "./common-api";
|
||||||
|
import type { EnsureHashedDirectoryForExtension } from "./extension-loader/file-system-provisioner-store/ensure-hashed-directory-for-extension.injectable";
|
||||||
|
|
||||||
export const lensExtensionDependencies = Symbol("lens-extension-dependencies");
|
|
||||||
export const Disposers = Symbol("disposers");
|
export const Disposers = Symbol("disposers");
|
||||||
|
|
||||||
export class LensExtension<
|
export interface LensExtensionDependencies {
|
||||||
/**
|
readonly logger: Logger;
|
||||||
* @ignore
|
ensureHashedDirectoryForExtension: EnsureHashedDirectoryForExtension;
|
||||||
*/
|
}
|
||||||
Dependencies extends LensExtensionDependencies = LensExtensionDependencies,
|
|
||||||
> implements LegacyLensExtension {
|
export class LensExtension {
|
||||||
readonly id: LensExtensionId;
|
readonly id: LensExtensionId;
|
||||||
readonly manifest: LensExtensionManifest;
|
readonly manifest: LensExtensionManifest;
|
||||||
readonly manifestPath: string;
|
readonly manifestPath: string;
|
||||||
@ -27,6 +27,11 @@ export class LensExtension<
|
|||||||
return sanitizeExtensionName(this.name);
|
return sanitizeExtensionName(this.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
protected readonly dependencies: LensExtensionDependencies;
|
||||||
|
|
||||||
protocolHandlers: ProtocolHandlerRegistration[] = [];
|
protocolHandlers: ProtocolHandlerRegistration[] = [];
|
||||||
|
|
||||||
@observable private _isEnabled = false;
|
@observable private _isEnabled = false;
|
||||||
@ -40,12 +45,12 @@ export class LensExtension<
|
|||||||
*/
|
*/
|
||||||
[Disposers] = disposer();
|
[Disposers] = disposer();
|
||||||
|
|
||||||
constructor({ id, manifest, manifestPath, isBundled }: InstalledExtension) {
|
constructor(deps: LensExtensionDependencies, { id, manifest, manifestPath, isBundled }: InstalledExtension) {
|
||||||
// id is the name of the manifest
|
this.dependencies = deps;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.manifest = manifest as LensExtensionManifest;
|
this.manifest = manifest as LensExtensionManifest;
|
||||||
this.manifestPath = manifestPath;
|
this.manifestPath = manifestPath;
|
||||||
this.isBundled = !!isBundled;
|
this.isBundled = isBundled;
|
||||||
makeObservable(this);
|
makeObservable(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,11 +71,6 @@ export class LensExtension<
|
|||||||
return this.manifest.storeName || this.name;
|
return this.manifest.storeName || this.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @ignore
|
|
||||||
*/
|
|
||||||
readonly [lensExtensionDependencies]!: Dependencies;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* getExtensionFileFolder returns the path to an already created folder. This
|
* getExtensionFileFolder returns the path to an already created folder. This
|
||||||
* folder is for the sole use of this extension.
|
* folder is for the sole use of this extension.
|
||||||
@ -80,7 +80,7 @@ export class LensExtension<
|
|||||||
*/
|
*/
|
||||||
async getExtensionFileFolder(): Promise<string> {
|
async getExtensionFileFolder(): Promise<string> {
|
||||||
// storeName is read from the manifest and has a fallback to the manifest name, which equals id
|
// storeName is read from the manifest and has a fallback to the manifest name, which equals id
|
||||||
return this[lensExtensionDependencies].ensureHashedDirectoryForExtension(this.storeName);
|
return this.dependencies.ensureHashedDirectoryForExtension(this.storeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
@ -90,7 +90,7 @@ export class LensExtension<
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._isEnabled = true;
|
this._isEnabled = true;
|
||||||
this[lensExtensionDependencies].logger.info(`[EXTENSION]: enabled ${this.name}@${this.version}`);
|
this.dependencies.logger.info(`[EXTENSION]: enabled ${this.name}@${this.version}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
@ -104,9 +104,9 @@ export class LensExtension<
|
|||||||
try {
|
try {
|
||||||
await this.onDeactivate();
|
await this.onDeactivate();
|
||||||
this[Disposers]();
|
this[Disposers]();
|
||||||
this[lensExtensionDependencies].logger.info(`[EXTENSION]: disabled ${this.name}@${this.version}`);
|
this.dependencies.logger.info(`[EXTENSION]: disabled ${this.name}@${this.version}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this[lensExtensionDependencies].logger.error(`[EXTENSION]: disabling ${this.name}@${this.version} threw an error: ${error}`);
|
this.dependencies.logger.error(`[EXTENSION]: disabling ${this.name}@${this.version} threw an error: ${error}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,19 +3,49 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { LensExtension, lensExtensionDependencies } from "./lens-extension";
|
import type { LensExtensionDependencies } from "./lens-extension";
|
||||||
|
import { LensExtension } from "./lens-extension";
|
||||||
import type { CatalogEntity } from "../common/catalog";
|
import type { CatalogEntity } from "../common/catalog";
|
||||||
import type { IComputedValue, IObservableArray } from "mobx";
|
import type { IComputedValue, IObservableArray } from "mobx";
|
||||||
import { isObservableArray } from "mobx";
|
import { isObservableArray } from "mobx";
|
||||||
import type { MenuRegistration } from "../features/application-menu/main/menu-registration";
|
import type { MenuRegistration } from "../features/application-menu/main/menu-registration";
|
||||||
import type { TrayMenuRegistration } from "../main/tray/tray-menu-registration";
|
import type { TrayMenuRegistration } from "../main/tray/tray-menu-registration";
|
||||||
import type { ShellEnvModifier } from "../main/shell-session/shell-env-modifier/shell-env-modifier-registration";
|
import type { ShellEnvModifier } from "../main/shell-session/shell-env-modifier/shell-env-modifier-registration";
|
||||||
import type { LensMainExtensionDependencies } from "./lens-extension-set-dependencies";
|
import { getEnvironmentSpecificLegacyGlobalDiForExtensionApi } from "./as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
|
||||||
|
import type { InstalledExtension } from "./common-api";
|
||||||
|
import type { CatalogEntityRegistry } from "../main/catalog";
|
||||||
|
import type { NavigateForExtension } from "../main/start-main-application/lens-window/navigate-for-extension.injectable";
|
||||||
|
import catalogEntityRegistryInjectable from "../main/catalog/entity-registry.injectable";
|
||||||
|
import loggerInjectable from "../common/logger.injectable";
|
||||||
|
import navigateForExtensionInjectable from "../main/start-main-application/lens-window/navigate-for-extension.injectable";
|
||||||
|
import ensureHashedDirectoryForExtensionInjectable from "./extension-loader/file-system-provisioner-store/ensure-hashed-directory-for-extension.injectable";
|
||||||
|
|
||||||
export class LensMainExtension extends LensExtension<LensMainExtensionDependencies> {
|
interface LensMainExtensionDependencies extends LensExtensionDependencies {
|
||||||
|
readonly entityRegistry: CatalogEntityRegistry;
|
||||||
|
readonly navigate: NavigateForExtension;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class LensMainExtension extends LensExtension {
|
||||||
appMenus: MenuRegistration[] | IComputedValue<MenuRegistration[]> = [];
|
appMenus: MenuRegistration[] | IComputedValue<MenuRegistration[]> = [];
|
||||||
trayMenus: TrayMenuRegistration[] | IComputedValue<TrayMenuRegistration[]> = [];
|
trayMenus: TrayMenuRegistration[] | IComputedValue<TrayMenuRegistration[]> = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
declare readonly dependencies: LensMainExtensionDependencies;
|
||||||
|
|
||||||
|
constructor(extension: InstalledExtension) {
|
||||||
|
const di = getEnvironmentSpecificLegacyGlobalDiForExtensionApi("main");
|
||||||
|
const deps: LensMainExtensionDependencies = {
|
||||||
|
ensureHashedDirectoryForExtension: di.inject(ensureHashedDirectoryForExtensionInjectable),
|
||||||
|
navigate: di.inject(navigateForExtensionInjectable),
|
||||||
|
entityRegistry: di.inject(catalogEntityRegistryInjectable),
|
||||||
|
logger: di.inject(loggerInjectable),
|
||||||
|
};
|
||||||
|
|
||||||
|
super(deps, extension);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* implement this to modify the shell environment that Lens terminals are opened with. The ShellEnvModifier type has the signature
|
* implement this to modify the shell environment that Lens terminals are opened with. The ShellEnvModifier type has the signature
|
||||||
*
|
*
|
||||||
@ -32,18 +62,18 @@ export class LensMainExtension extends LensExtension<LensMainExtensionDependenci
|
|||||||
terminalShellEnvModifier?: ShellEnvModifier;
|
terminalShellEnvModifier?: ShellEnvModifier;
|
||||||
|
|
||||||
async navigate(pageId?: string, params?: Record<string, any>, frameId?: number) {
|
async navigate(pageId?: string, params?: Record<string, any>, frameId?: number) {
|
||||||
await this[lensExtensionDependencies].navigate(this.id, pageId, params, frameId);
|
await this.dependencies.navigate(this.id, pageId, params, frameId);
|
||||||
}
|
}
|
||||||
|
|
||||||
addCatalogSource(id: string, source: IObservableArray<CatalogEntity> | IComputedValue<CatalogEntity[]>) {
|
addCatalogSource(id: string, source: IObservableArray<CatalogEntity> | IComputedValue<CatalogEntity[]>) {
|
||||||
if (isObservableArray(source)) {
|
if (isObservableArray(source)) {
|
||||||
this[lensExtensionDependencies].entityRegistry.addObservableSource(`${this.name}:${id}`, source);
|
this.dependencies.entityRegistry.addObservableSource(`${this.name}:${id}`, source);
|
||||||
} else {
|
} else {
|
||||||
this[lensExtensionDependencies].entityRegistry.addComputedSource(`${this.name}:${id}`, source);
|
this.dependencies.entityRegistry.addComputedSource(`${this.name}:${id}`, source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removeCatalogSource(id: string) {
|
removeCatalogSource(id: string) {
|
||||||
this[lensExtensionDependencies].entityRegistry.removeSource(`${this.name}:${id}`);
|
this.dependencies.entityRegistry.removeSource(`${this.name}:${id}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,10 +3,11 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Disposers, LensExtension, lensExtensionDependencies } from "./lens-extension";
|
import { Disposers, LensExtension } from "./lens-extension";
|
||||||
import type { CatalogEntity, CategoryFilter } from "../common/catalog";
|
|
||||||
import type { Disposer } from "@k8slens/utilities";
|
import type { Disposer } from "@k8slens/utilities";
|
||||||
import type { EntityFilter } from "../renderer/api/catalog/entity/registry";
|
import type { LensExtensionDependencies } from "./lens-extension";
|
||||||
|
import type { CatalogEntity, CategoryFilter, CatalogCategoryRegistry } from "../common/catalog";
|
||||||
|
import type { EntityFilter, CatalogEntityRegistry } from "../renderer/api/catalog/entity/registry";
|
||||||
import type { TopBarRegistration } from "../renderer/components/layout/top-bar/top-bar-registration";
|
import type { TopBarRegistration } from "../renderer/components/layout/top-bar/top-bar-registration";
|
||||||
import type { KubernetesCluster } from "../common/catalog-entities";
|
import type { KubernetesCluster } from "../common/catalog-entities";
|
||||||
import type { WelcomeMenuRegistration } from "../renderer/components/+welcome/welcome-menu-items/welcome-menu-registration";
|
import type { WelcomeMenuRegistration } from "../renderer/components/+welcome/welcome-menu-items/welcome-menu-registration";
|
||||||
@ -22,7 +23,6 @@ import type { KubeObjectStatusRegistration } from "../renderer/components/kube-o
|
|||||||
import { fromPairs, map, matches, toPairs } from "lodash/fp";
|
import { fromPairs, map, matches, toPairs } from "lodash/fp";
|
||||||
import { pipeline } from "@ogre-tools/fp";
|
import { pipeline } from "@ogre-tools/fp";
|
||||||
import { getExtensionRoutePath } from "../renderer/routes/for-extension";
|
import { getExtensionRoutePath } from "../renderer/routes/for-extension";
|
||||||
import type { LensRendererExtensionDependencies } from "./lens-extension-set-dependencies";
|
|
||||||
import type { KubeObjectHandlerRegistration } from "../renderer/kube-object/handler";
|
import type { KubeObjectHandlerRegistration } from "../renderer/kube-object/handler";
|
||||||
import type { AppPreferenceTabRegistration } from "../features/preferences/renderer/compliance-for-legacy-extension-api/app-preference-tab-registration";
|
import type { AppPreferenceTabRegistration } from "../features/preferences/renderer/compliance-for-legacy-extension-api/app-preference-tab-registration";
|
||||||
import type { KubeObjectDetailRegistration } from "../renderer/components/kube-object-details/kube-object-detail-registration";
|
import type { KubeObjectDetailRegistration } from "../renderer/components/kube-object-details/kube-object-detail-registration";
|
||||||
@ -31,8 +31,29 @@ import type { EntitySettingRegistration } from "../renderer/components/+entity-s
|
|||||||
import type { CatalogEntityDetailRegistration } from "../renderer/components/+catalog/entity-details/token";
|
import type { CatalogEntityDetailRegistration } from "../renderer/components/+catalog/entity-details/token";
|
||||||
import type { PageRegistration } from "../renderer/routes/page-registration";
|
import type { PageRegistration } from "../renderer/routes/page-registration";
|
||||||
import type { ClusterPageMenuRegistration } from "../renderer/components/layout/cluster-page-menu";
|
import type { ClusterPageMenuRegistration } from "../renderer/components/layout/cluster-page-menu";
|
||||||
|
import type { IComputedValue } from "mobx";
|
||||||
|
import type { NavigateToRoute } from "../common/front-end-routing/navigate-to-route-injection-token";
|
||||||
|
import type { Route } from "../common/front-end-routing/front-end-route-injection-token";
|
||||||
|
import type { GetExtensionPageParameters } from "../renderer/routes/get-extension-page-parameters.injectable";
|
||||||
|
import type { InstalledExtension } from "./common-api";
|
||||||
|
import { getEnvironmentSpecificLegacyGlobalDiForExtensionApi } from "./as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
|
||||||
|
import catalogCategoryRegistryInjectable from "../common/catalog/category-registry.injectable";
|
||||||
|
import catalogEntityRegistryInjectable from "../renderer/api/catalog/entity/registry.injectable";
|
||||||
|
import loggerInjectable from "../common/logger.injectable";
|
||||||
|
import getExtensionPageParametersInjectable from "../renderer/routes/get-extension-page-parameters.injectable";
|
||||||
|
import navigateToRouteInjectable from "../renderer/routes/navigate-to-route.injectable";
|
||||||
|
import routesInjectable from "../renderer/routes/routes.injectable";
|
||||||
|
import ensureHashedDirectoryForExtensionInjectable from "./extension-loader/file-system-provisioner-store/ensure-hashed-directory-for-extension.injectable";
|
||||||
|
|
||||||
export class LensRendererExtension extends LensExtension<LensRendererExtensionDependencies> {
|
interface LensRendererExtensionDependencies extends LensExtensionDependencies {
|
||||||
|
navigateToRoute: NavigateToRoute;
|
||||||
|
getExtensionPageParameters: GetExtensionPageParameters;
|
||||||
|
readonly routes: IComputedValue<Route<unknown>[]>;
|
||||||
|
readonly entityRegistry: CatalogEntityRegistry;
|
||||||
|
readonly categoryRegistry: CatalogCategoryRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class LensRendererExtension extends LensExtension {
|
||||||
globalPages: PageRegistration[] = [];
|
globalPages: PageRegistration[] = [];
|
||||||
clusterPages: PageRegistration[] = [];
|
clusterPages: PageRegistration[] = [];
|
||||||
clusterPageMenus: ClusterPageMenuRegistration[] = [];
|
clusterPageMenus: ClusterPageMenuRegistration[] = [];
|
||||||
@ -54,8 +75,28 @@ export class LensRendererExtension extends LensExtension<LensRendererExtensionDe
|
|||||||
customCategoryViews: CustomCategoryViewRegistration[] = [];
|
customCategoryViews: CustomCategoryViewRegistration[] = [];
|
||||||
kubeObjectHandlers: KubeObjectHandlerRegistration[] = [];
|
kubeObjectHandlers: KubeObjectHandlerRegistration[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
declare protected readonly dependencies: LensRendererExtensionDependencies;
|
||||||
|
|
||||||
|
constructor(extension: InstalledExtension) {
|
||||||
|
const di = getEnvironmentSpecificLegacyGlobalDiForExtensionApi("renderer");
|
||||||
|
const deps: LensRendererExtensionDependencies = {
|
||||||
|
getExtensionPageParameters: di.inject(getExtensionPageParametersInjectable),
|
||||||
|
navigateToRoute: di.inject(navigateToRouteInjectable),
|
||||||
|
ensureHashedDirectoryForExtension: di.inject(ensureHashedDirectoryForExtensionInjectable),
|
||||||
|
categoryRegistry: di.inject(catalogCategoryRegistryInjectable),
|
||||||
|
entityRegistry: di.inject(catalogEntityRegistryInjectable),
|
||||||
|
routes: di.inject(routesInjectable),
|
||||||
|
logger: di.inject(loggerInjectable),
|
||||||
|
};
|
||||||
|
|
||||||
|
super(deps, extension);
|
||||||
|
}
|
||||||
|
|
||||||
async navigate(pageId?: string, params: object = {}) {
|
async navigate(pageId?: string, params: object = {}) {
|
||||||
const routes = this[lensExtensionDependencies].routes.get();
|
const routes = this.dependencies.routes.get();
|
||||||
const targetRegistration = [...this.globalPages, ...this.clusterPages]
|
const targetRegistration = [...this.globalPages, ...this.clusterPages]
|
||||||
.find(registration => registration.id === (pageId || undefined));
|
.find(registration => registration.id === (pageId || undefined));
|
||||||
|
|
||||||
@ -70,7 +111,7 @@ export class LensRendererExtension extends LensExtension<LensRendererExtensionDe
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const normalizedParams = this[lensExtensionDependencies].getExtensionPageParameters({
|
const normalizedParams = this.dependencies.getExtensionPageParameters({
|
||||||
extension: this,
|
extension: this,
|
||||||
registration: targetRegistration,
|
registration: targetRegistration,
|
||||||
});
|
});
|
||||||
@ -84,7 +125,7 @@ export class LensRendererExtension extends LensExtension<LensRendererExtensionDe
|
|||||||
fromPairs,
|
fromPairs,
|
||||||
);
|
);
|
||||||
|
|
||||||
this[lensExtensionDependencies].navigateToRoute(targetRoute, {
|
this.dependencies.navigateToRoute(targetRoute, {
|
||||||
query,
|
query,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -107,7 +148,7 @@ export class LensRendererExtension extends LensExtension<LensRendererExtensionDe
|
|||||||
* @returns A function to clean up the filter
|
* @returns A function to clean up the filter
|
||||||
*/
|
*/
|
||||||
addCatalogFilter(fn: EntityFilter): Disposer {
|
addCatalogFilter(fn: EntityFilter): Disposer {
|
||||||
const dispose = this[lensExtensionDependencies].entityRegistry.addCatalogFilter(fn);
|
const dispose = this.dependencies.entityRegistry.addCatalogFilter(fn);
|
||||||
|
|
||||||
this[Disposers].push(dispose);
|
this[Disposers].push(dispose);
|
||||||
|
|
||||||
@ -120,7 +161,7 @@ export class LensRendererExtension extends LensExtension<LensRendererExtensionDe
|
|||||||
* @returns A function to clean up the filter
|
* @returns A function to clean up the filter
|
||||||
*/
|
*/
|
||||||
addCatalogCategoryFilter(fn: CategoryFilter): Disposer {
|
addCatalogCategoryFilter(fn: CategoryFilter): Disposer {
|
||||||
const dispose = this[lensExtensionDependencies].categoryRegistry.addCatalogCategoryFilter(fn);
|
const dispose = this.dependencies.categoryRegistry.addCatalogCategoryFilter(fn);
|
||||||
|
|
||||||
this[Disposers].push(dispose);
|
this[Disposers].push(dispose);
|
||||||
|
|
||||||
|
|||||||
@ -81,6 +81,7 @@ exports[`extension special characters in page registrations renders 1`] = `
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
|
|||||||
@ -81,6 +81,7 @@ exports[`navigate to extension page renders 1`] = `
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
|
|||||||
@ -81,6 +81,7 @@ exports[`add-cluster - navigation using application menu renders 1`] = `
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import { computed } from "mobx";
|
|||||||
import type { Injectable } from "@ogre-tools/injectable";
|
import type { Injectable } from "@ogre-tools/injectable";
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import { extensionRegistratorInjectionToken } from "../../../extensions/extension-loader/extension-registrator-injection-token";
|
import { extensionRegistratorInjectionToken } from "../../../extensions/extension-loader/extension-registrator-injection-token";
|
||||||
import type { LensExtension } from "../../../extensions/lens-extension";
|
|
||||||
import type { LensMainExtension } from "../../../extensions/lens-main-extension";
|
import type { LensMainExtension } from "../../../extensions/lens-main-extension";
|
||||||
import type {
|
import type {
|
||||||
ApplicationMenuItemTypes,
|
ApplicationMenuItemTypes,
|
||||||
@ -25,7 +24,7 @@ const applicationMenuItemRegistratorInjectable = getInjectable({
|
|||||||
const logError = di.inject(logErrorInjectable);
|
const logError = di.inject(logErrorInjectable);
|
||||||
const toRecursedInjectables = toRecursedInjectablesFor(logError);
|
const toRecursedInjectables = toRecursedInjectablesFor(logError);
|
||||||
|
|
||||||
return (ext: LensExtension) => {
|
return (ext) => {
|
||||||
const mainExtension = ext as LensMainExtension;
|
const mainExtension = ext as LensMainExtension;
|
||||||
|
|
||||||
return computed(() => {
|
return computed(() => {
|
||||||
|
|||||||
@ -82,6 +82,7 @@ exports[`installing update when started renders 1`] = `
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
@ -367,6 +368,7 @@ exports[`installing update when started when user checks for updates renders 1`]
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
@ -652,6 +654,7 @@ exports[`installing update when started when user checks for updates when new up
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
@ -937,6 +940,7 @@ exports[`installing update when started when user checks for updates when new up
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
@ -1247,6 +1251,7 @@ exports[`installing update when started when user checks for updates when new up
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
@ -1557,6 +1562,7 @@ exports[`installing update when started when user checks for updates when new up
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
@ -1867,6 +1873,7 @@ exports[`installing update when started when user checks for updates when new up
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
@ -2152,6 +2159,7 @@ exports[`installing update when started when user checks for updates when no new
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
|
|||||||
@ -107,6 +107,7 @@ exports[`encourage user to update when sufficient time passed since update was d
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
@ -392,6 +393,7 @@ exports[`encourage user to update when sufficient time passed since update was d
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
|
|||||||
@ -82,6 +82,7 @@ exports[`installing update using tray when started renders 1`] = `
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
@ -367,6 +368,7 @@ exports[`installing update using tray when started when user checks for updates
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
@ -652,6 +654,7 @@ exports[`installing update using tray when started when user checks for updates
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
@ -937,6 +940,7 @@ exports[`installing update using tray when started when user checks for updates
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
@ -1247,6 +1251,7 @@ exports[`installing update using tray when started when user checks for updates
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
@ -1532,6 +1537,7 @@ exports[`installing update using tray when started when user checks for updates
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
|
|||||||
@ -107,6 +107,7 @@ exports[`force user to update when too long since update was downloaded when app
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
@ -417,6 +418,7 @@ exports[`force user to update when too long since update was downloaded when app
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
@ -774,6 +776,7 @@ exports[`force user to update when too long since update was downloaded when app
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
|
|||||||
@ -82,6 +82,7 @@ exports[`periodical checking of updates given updater is enabled and configurati
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
|
|||||||
@ -82,6 +82,7 @@ exports[`selection of update stability when started renders 1`] = `
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -89,41 +89,35 @@ exports[`entity running technical tests when navigated to catalog renders 1`] =
|
|||||||
Catalog
|
Catalog
|
||||||
</div>
|
</div>
|
||||||
<ul
|
<ul
|
||||||
aria-multiselectable="false"
|
class="treeView"
|
||||||
class="MuiTreeView-root"
|
|
||||||
role="tree"
|
role="tree"
|
||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
aria-selected="true"
|
class="root selected treeItem"
|
||||||
class="MuiTreeItem-root Mui-selected"
|
|
||||||
data-testid="*-tab"
|
data-testid="*-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="0"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
Browse
|
Browse
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
|
<div
|
||||||
|
class="HorizontalLine size-xxs"
|
||||||
|
/>
|
||||||
<li
|
<li
|
||||||
aria-expanded="true"
|
class="root treeGroup"
|
||||||
class="MuiTreeItem-root bordered Mui-expanded"
|
role="group"
|
||||||
role="treeitem"
|
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="group"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-iconContainer"
|
class="iconContainer"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon material focusable"
|
class="Icon material focusable"
|
||||||
@ -137,7 +131,7 @@ exports[`entity running technical tests when navigated to catalog renders 1`] =
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="parent"
|
class="parent"
|
||||||
@ -147,27 +141,15 @@ exports[`entity running technical tests when navigated to catalog renders 1`] =
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ul
|
<ul
|
||||||
class="MuiCollapse-root MuiTreeItem-group MuiCollapse-entered"
|
class="contents expanded"
|
||||||
role="group"
|
|
||||||
style="min-height: 0px;"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiCollapse-wrapper"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiCollapse-wrapperInner"
|
|
||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
class="MuiTreeItem-root"
|
class="root treeItem"
|
||||||
data-testid="entity.k8slens.dev/General-tab"
|
data-testid="entity.k8slens.dev/General-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon material focusable small"
|
class="Icon material focusable small"
|
||||||
@ -181,7 +163,7 @@ exports[`entity running technical tests when navigated to catalog renders 1`] =
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex"
|
class="flex"
|
||||||
@ -191,19 +173,14 @@ exports[`entity running technical tests when navigated to catalog renders 1`] =
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
class="MuiTreeItem-root"
|
class="root treeItem"
|
||||||
data-testid="entity.k8slens.dev/KubernetesCluster-tab"
|
data-testid="entity.k8slens.dev/KubernetesCluster-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon focusable small"
|
class="Icon focusable small"
|
||||||
@ -215,7 +192,7 @@ exports[`entity running technical tests when navigated to catalog renders 1`] =
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex"
|
class="flex"
|
||||||
@ -225,19 +202,14 @@ exports[`entity running technical tests when navigated to catalog renders 1`] =
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
class="MuiTreeItem-root"
|
class="root treeItem"
|
||||||
data-testid="entity.k8slens.dev/WebLink-tab"
|
data-testid="entity.k8slens.dev/WebLink-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon material focusable small"
|
class="Icon material focusable small"
|
||||||
@ -251,7 +223,7 @@ exports[`entity running technical tests when navigated to catalog renders 1`] =
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex"
|
class="flex"
|
||||||
@ -261,19 +233,14 @@ exports[`entity running technical tests when navigated to catalog renders 1`] =
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
class="MuiTreeItem-root"
|
class="root treeItem"
|
||||||
data-testid="entity.k8slens.dev/Mock-tab"
|
data-testid="entity.k8slens.dev/Mock-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon material focusable small"
|
class="Icon material focusable small"
|
||||||
@ -287,7 +254,7 @@ exports[`entity running technical tests when navigated to catalog renders 1`] =
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex"
|
class="flex"
|
||||||
@ -297,10 +264,7 @@ exports[`entity running technical tests when navigated to catalog renders 1`] =
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -392,6 +356,7 @@ exports[`entity running technical tests when navigated to catalog renders 1`] =
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="TableCell nowrap sorting"
|
class="TableCell nowrap sorting"
|
||||||
|
data-testid="catalog-kind-column"
|
||||||
id="kind"
|
id="kind"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -412,6 +377,7 @@ exports[`entity running technical tests when navigated to catalog renders 1`] =
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="TableCell sourceCell nowrap sorting"
|
class="TableCell sourceCell nowrap sorting"
|
||||||
|
data-testid="catalog-source-column"
|
||||||
id="source"
|
id="source"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -432,6 +398,7 @@ exports[`entity running technical tests when navigated to catalog renders 1`] =
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="TableCell labelsCell scrollable nowrap"
|
class="TableCell labelsCell scrollable nowrap"
|
||||||
|
data-testid="catalog-labels-column"
|
||||||
id="labels"
|
id="labels"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -442,6 +409,7 @@ exports[`entity running technical tests when navigated to catalog renders 1`] =
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="TableCell statusCell nowrap sorting"
|
class="TableCell statusCell nowrap sorting"
|
||||||
|
data-testid="catalog-status-column"
|
||||||
id="status"
|
id="status"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -805,41 +773,35 @@ exports[`entity running technical tests when navigated to catalog when details p
|
|||||||
Catalog
|
Catalog
|
||||||
</div>
|
</div>
|
||||||
<ul
|
<ul
|
||||||
aria-multiselectable="false"
|
class="treeView"
|
||||||
class="MuiTreeView-root"
|
|
||||||
role="tree"
|
role="tree"
|
||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
aria-selected="true"
|
class="root selected treeItem"
|
||||||
class="MuiTreeItem-root Mui-selected"
|
|
||||||
data-testid="*-tab"
|
data-testid="*-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="0"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
Browse
|
Browse
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
|
<div
|
||||||
|
class="HorizontalLine size-xxs"
|
||||||
|
/>
|
||||||
<li
|
<li
|
||||||
aria-expanded="true"
|
class="root treeGroup"
|
||||||
class="MuiTreeItem-root bordered Mui-expanded"
|
role="group"
|
||||||
role="treeitem"
|
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="group"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-iconContainer"
|
class="iconContainer"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon material focusable"
|
class="Icon material focusable"
|
||||||
@ -853,7 +815,7 @@ exports[`entity running technical tests when navigated to catalog when details p
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="parent"
|
class="parent"
|
||||||
@ -863,27 +825,15 @@ exports[`entity running technical tests when navigated to catalog when details p
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ul
|
<ul
|
||||||
class="MuiCollapse-root MuiTreeItem-group MuiCollapse-entered"
|
class="contents expanded"
|
||||||
role="group"
|
|
||||||
style="min-height: 0px;"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiCollapse-wrapper"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiCollapse-wrapperInner"
|
|
||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
class="MuiTreeItem-root"
|
class="root treeItem"
|
||||||
data-testid="entity.k8slens.dev/General-tab"
|
data-testid="entity.k8slens.dev/General-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon material focusable small"
|
class="Icon material focusable small"
|
||||||
@ -897,7 +847,7 @@ exports[`entity running technical tests when navigated to catalog when details p
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex"
|
class="flex"
|
||||||
@ -907,19 +857,14 @@ exports[`entity running technical tests when navigated to catalog when details p
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
class="MuiTreeItem-root"
|
class="root treeItem"
|
||||||
data-testid="entity.k8slens.dev/KubernetesCluster-tab"
|
data-testid="entity.k8slens.dev/KubernetesCluster-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon focusable small"
|
class="Icon focusable small"
|
||||||
@ -931,7 +876,7 @@ exports[`entity running technical tests when navigated to catalog when details p
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex"
|
class="flex"
|
||||||
@ -941,19 +886,14 @@ exports[`entity running technical tests when navigated to catalog when details p
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
class="MuiTreeItem-root"
|
class="root treeItem"
|
||||||
data-testid="entity.k8slens.dev/WebLink-tab"
|
data-testid="entity.k8slens.dev/WebLink-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon material focusable small"
|
class="Icon material focusable small"
|
||||||
@ -967,7 +907,7 @@ exports[`entity running technical tests when navigated to catalog when details p
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex"
|
class="flex"
|
||||||
@ -977,19 +917,14 @@ exports[`entity running technical tests when navigated to catalog when details p
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
class="MuiTreeItem-root"
|
class="root treeItem"
|
||||||
data-testid="entity.k8slens.dev/Mock-tab"
|
data-testid="entity.k8slens.dev/Mock-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon material focusable small"
|
class="Icon material focusable small"
|
||||||
@ -1003,7 +938,7 @@ exports[`entity running technical tests when navigated to catalog when details p
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex"
|
class="flex"
|
||||||
@ -1013,10 +948,7 @@ exports[`entity running technical tests when navigated to catalog when details p
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -1108,6 +1040,7 @@ exports[`entity running technical tests when navigated to catalog when details p
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="TableCell nowrap sorting"
|
class="TableCell nowrap sorting"
|
||||||
|
data-testid="catalog-kind-column"
|
||||||
id="kind"
|
id="kind"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -1128,6 +1061,7 @@ exports[`entity running technical tests when navigated to catalog when details p
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="TableCell sourceCell nowrap sorting"
|
class="TableCell sourceCell nowrap sorting"
|
||||||
|
data-testid="catalog-source-column"
|
||||||
id="source"
|
id="source"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -1148,6 +1082,7 @@ exports[`entity running technical tests when navigated to catalog when details p
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="TableCell labelsCell scrollable nowrap"
|
class="TableCell labelsCell scrollable nowrap"
|
||||||
|
data-testid="catalog-labels-column"
|
||||||
id="labels"
|
id="labels"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -1158,6 +1093,7 @@ exports[`entity running technical tests when navigated to catalog when details p
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="TableCell statusCell nowrap sorting"
|
class="TableCell statusCell nowrap sorting"
|
||||||
|
data-testid="catalog-status-column"
|
||||||
id="status"
|
id="status"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
314
packages/core/src/features/catalog/custom-columns.test.tsx
Normal file
314
packages/core/src/features/catalog/custom-columns.test.tsx
Normal file
@ -0,0 +1,314 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { RenderResult } from "@testing-library/react";
|
||||||
|
import { CatalogCategory, type CatalogCategorySpec, type CategoryColumnRegistration } from "../../common/catalog";
|
||||||
|
import catalogCategoryRegistryInjectable from "../../common/catalog/category-registry.injectable";
|
||||||
|
import navigateToCatalogInjectable from "../../common/front-end-routing/routes/catalog/navigate-to-catalog.injectable";
|
||||||
|
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||||
|
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||||
|
|
||||||
|
describe("custom category columns for catalog", () => {
|
||||||
|
let builder: ApplicationBuilder;
|
||||||
|
let renderResult: RenderResult;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
builder = getApplicationBuilder();
|
||||||
|
|
||||||
|
renderResult = await builder.render();
|
||||||
|
|
||||||
|
const navigateToCatalog = builder.applicationWindow.only.di.inject(navigateToCatalogInjectable);
|
||||||
|
|
||||||
|
navigateToCatalog();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders", () => {
|
||||||
|
expect(renderResult.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows 'Browse All' view", () => {
|
||||||
|
expect(renderResult.queryByTestId("catalog-list-for-browse-all")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show the 'Kind' column", () => {
|
||||||
|
expect(renderResult.queryByTestId("catalog-kind-column")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show the 'Status' column", () => {
|
||||||
|
expect(renderResult.queryByTestId("catalog-status-column")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show the 'Labels' column", () => {
|
||||||
|
expect(renderResult.queryByTestId("catalog-labels-column")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show the 'Source' column", () => {
|
||||||
|
expect(renderResult.queryByTestId("catalog-source-column")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when category is added using default colemns", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const catalogCategoryRegistry = builder.applicationWindow.only.di.inject(catalogCategoryRegistryInjectable);
|
||||||
|
|
||||||
|
catalogCategoryRegistry.add(new TestCategory());
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders", () => {
|
||||||
|
expect(renderResult.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows category in sidebar", () => {
|
||||||
|
expect(renderResult.queryByTestId("foo.bar.bat/Test-tab")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("still shows 'Browse All' view", () => {
|
||||||
|
expect(renderResult.queryByTestId("catalog-list-for-browse-all")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when the Test category tab is clicked", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
const testCategory = renderResult.getByTestId("foo.bar.bat/Test-tab");
|
||||||
|
|
||||||
|
testCategory.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders", () => {
|
||||||
|
expect(renderResult.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows view for category", () => {
|
||||||
|
expect(renderResult.queryByTestId("catalog-list-for-Test")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not show the 'Kind' column", () => {
|
||||||
|
expect(renderResult.queryByTestId("catalog-kind-column")).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show the 'Status' column", () => {
|
||||||
|
expect(renderResult.queryByTestId("catalog-status-column")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show the 'Labels' column", () => {
|
||||||
|
expect(renderResult.queryByTestId("catalog-labels-column")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show the 'Source' column", () => {
|
||||||
|
expect(renderResult.queryByTestId("catalog-source-column")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when an extension is registered with additional custom columns", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
builder.extensions.enable({
|
||||||
|
id: "some-id",
|
||||||
|
name: "some-name",
|
||||||
|
rendererOptions: {
|
||||||
|
additionalCategoryColumns: [
|
||||||
|
{
|
||||||
|
group: "foo.bar.bat",
|
||||||
|
id: "high",
|
||||||
|
kind: "Test",
|
||||||
|
renderCell: () => "",
|
||||||
|
titleProps: {
|
||||||
|
title: "High",
|
||||||
|
"data-testid": "my-high-column",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
group: "foo.bar",
|
||||||
|
id: "high",
|
||||||
|
kind: "Test",
|
||||||
|
renderCell: () => "",
|
||||||
|
titleProps: {
|
||||||
|
title: "High2",
|
||||||
|
"data-testid": "my-high2-column",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when the Test category tab is clicked", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
const testCategory = renderResult.getByTestId("foo.bar.bat/Test-tab");
|
||||||
|
|
||||||
|
testCategory.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders", () => {
|
||||||
|
expect(renderResult.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows view for category", () => {
|
||||||
|
expect(renderResult.queryByTestId("catalog-list-for-Test")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not show the 'Kind' column", () => {
|
||||||
|
expect(renderResult.queryByTestId("catalog-kind-column")).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show the 'Status' column", () => {
|
||||||
|
expect(renderResult.queryByTestId("catalog-status-column")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show the 'Labels' column", () => {
|
||||||
|
expect(renderResult.queryByTestId("catalog-labels-column")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show the 'Source' column", () => {
|
||||||
|
expect(renderResult.queryByTestId("catalog-source-column")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show the additional column that matches", () => {
|
||||||
|
expect(renderResult.queryByTestId("my-high-column")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not show the additional column that does not match", () => {
|
||||||
|
expect(renderResult.queryByTestId("my-high2-column")).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when category is added with custom columns", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const catalogCategoryRegistry = builder.applicationWindow.only.di.inject(catalogCategoryRegistryInjectable);
|
||||||
|
|
||||||
|
catalogCategoryRegistry.add(new TestCategory([{
|
||||||
|
id: "foo",
|
||||||
|
renderCell: () => null,
|
||||||
|
titleProps: {
|
||||||
|
title: "Foo",
|
||||||
|
"data-testid": "my-custom-column",
|
||||||
|
},
|
||||||
|
}]));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders", () => {
|
||||||
|
expect(renderResult.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows category in sidebar", () => {
|
||||||
|
expect(renderResult.queryByTestId("foo.bar.bat/Test-tab")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("still shows 'Browse All' view", () => {
|
||||||
|
expect(renderResult.queryByTestId("catalog-list-for-browse-all")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when the Test category tab is clicked", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
const testCategory = renderResult.getByTestId("foo.bar.bat/Test-tab");
|
||||||
|
|
||||||
|
testCategory.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders", () => {
|
||||||
|
expect(renderResult.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows view for category", () => {
|
||||||
|
expect(renderResult.queryByTestId("catalog-list-for-Test")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not show the 'Kind' column", () => {
|
||||||
|
expect(renderResult.queryByTestId("catalog-kind-column")).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not the 'Status' column", () => {
|
||||||
|
expect(renderResult.queryByTestId("catalog-status-column")).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not the 'Labels' column", () => {
|
||||||
|
expect(renderResult.queryByTestId("catalog-labels-column")).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not the 'Source' column", () => {
|
||||||
|
expect(renderResult.queryByTestId("catalog-source-column")).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show the custom column", () => {
|
||||||
|
expect(renderResult.queryByTestId("my-custom-column")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when category is added without default columns", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const catalogCategoryRegistry = builder.applicationWindow.only.di.inject(catalogCategoryRegistryInjectable);
|
||||||
|
|
||||||
|
catalogCategoryRegistry.add(new TestCategory([]));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders", () => {
|
||||||
|
expect(renderResult.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows category in sidebar", () => {
|
||||||
|
expect(renderResult.queryByTestId("foo.bar.bat/Test-tab")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("still shows 'Browse All' view", () => {
|
||||||
|
expect(renderResult.queryByTestId("catalog-list-for-browse-all")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when the Test category tab is clicked", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
const testCategory = renderResult.getByTestId("foo.bar.bat/Test-tab");
|
||||||
|
|
||||||
|
testCategory.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders", () => {
|
||||||
|
expect(renderResult.baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows view for category", () => {
|
||||||
|
expect(renderResult.queryByTestId("catalog-list-for-Test")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not show the 'Kind' column", () => {
|
||||||
|
expect(renderResult.queryByTestId("catalog-kind-column")).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not the 'Status' column", () => {
|
||||||
|
expect(renderResult.queryByTestId("catalog-status-column")).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not the 'Labels' column", () => {
|
||||||
|
expect(renderResult.queryByTestId("catalog-labels-column")).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not the 'Source' column", () => {
|
||||||
|
expect(renderResult.queryByTestId("catalog-source-column")).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
class TestCategory extends CatalogCategory {
|
||||||
|
apiVersion = "catalog.k8slens.dev/v1alpha1";
|
||||||
|
kind = "CatalogCategory";
|
||||||
|
metadata = {
|
||||||
|
name: "Test",
|
||||||
|
icon: "question_mark",
|
||||||
|
};
|
||||||
|
spec: CatalogCategorySpec = {
|
||||||
|
group: "foo.bar.bat",
|
||||||
|
names: {
|
||||||
|
kind: "Test",
|
||||||
|
},
|
||||||
|
versions: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(columns?: CategoryColumnRegistration[]) {
|
||||||
|
super();
|
||||||
|
this.spec = {
|
||||||
|
displayColumns: columns,
|
||||||
|
...this.spec,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -89,41 +89,35 @@ exports[`Deleting a cluster when an internal kubeconfig cluster is used when the
|
|||||||
Catalog
|
Catalog
|
||||||
</div>
|
</div>
|
||||||
<ul
|
<ul
|
||||||
aria-multiselectable="false"
|
class="treeView"
|
||||||
class="MuiTreeView-root"
|
|
||||||
role="tree"
|
role="tree"
|
||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
aria-selected="true"
|
class="root selected treeItem"
|
||||||
class="MuiTreeItem-root Mui-selected"
|
|
||||||
data-testid="*-tab"
|
data-testid="*-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="0"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
Browse
|
Browse
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
|
<div
|
||||||
|
class="HorizontalLine size-xxs"
|
||||||
|
/>
|
||||||
<li
|
<li
|
||||||
aria-expanded="true"
|
class="root treeGroup"
|
||||||
class="MuiTreeItem-root bordered Mui-expanded"
|
role="group"
|
||||||
role="treeitem"
|
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="group"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-iconContainer"
|
class="iconContainer"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon material focusable"
|
class="Icon material focusable"
|
||||||
@ -137,7 +131,7 @@ exports[`Deleting a cluster when an internal kubeconfig cluster is used when the
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="parent"
|
class="parent"
|
||||||
@ -147,27 +141,15 @@ exports[`Deleting a cluster when an internal kubeconfig cluster is used when the
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ul
|
<ul
|
||||||
class="MuiCollapse-root MuiTreeItem-group MuiCollapse-entered"
|
class="contents expanded"
|
||||||
role="group"
|
|
||||||
style="min-height: 0px;"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiCollapse-wrapper"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiCollapse-wrapperInner"
|
|
||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
class="MuiTreeItem-root"
|
class="root treeItem"
|
||||||
data-testid="entity.k8slens.dev/General-tab"
|
data-testid="entity.k8slens.dev/General-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon material focusable small"
|
class="Icon material focusable small"
|
||||||
@ -181,7 +163,7 @@ exports[`Deleting a cluster when an internal kubeconfig cluster is used when the
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex"
|
class="flex"
|
||||||
@ -191,19 +173,14 @@ exports[`Deleting a cluster when an internal kubeconfig cluster is used when the
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
class="MuiTreeItem-root"
|
class="root treeItem"
|
||||||
data-testid="entity.k8slens.dev/KubernetesCluster-tab"
|
data-testid="entity.k8slens.dev/KubernetesCluster-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon focusable small"
|
class="Icon focusable small"
|
||||||
@ -215,7 +192,7 @@ exports[`Deleting a cluster when an internal kubeconfig cluster is used when the
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex"
|
class="flex"
|
||||||
@ -225,19 +202,14 @@ exports[`Deleting a cluster when an internal kubeconfig cluster is used when the
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
class="MuiTreeItem-root"
|
class="root treeItem"
|
||||||
data-testid="entity.k8slens.dev/WebLink-tab"
|
data-testid="entity.k8slens.dev/WebLink-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon material focusable small"
|
class="Icon material focusable small"
|
||||||
@ -251,7 +223,7 @@ exports[`Deleting a cluster when an internal kubeconfig cluster is used when the
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex"
|
class="flex"
|
||||||
@ -261,10 +233,7 @@ exports[`Deleting a cluster when an internal kubeconfig cluster is used when the
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -356,6 +325,7 @@ exports[`Deleting a cluster when an internal kubeconfig cluster is used when the
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="TableCell nowrap sorting"
|
class="TableCell nowrap sorting"
|
||||||
|
data-testid="catalog-kind-column"
|
||||||
id="kind"
|
id="kind"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -376,6 +346,7 @@ exports[`Deleting a cluster when an internal kubeconfig cluster is used when the
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="TableCell sourceCell nowrap sorting"
|
class="TableCell sourceCell nowrap sorting"
|
||||||
|
data-testid="catalog-source-column"
|
||||||
id="source"
|
id="source"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -396,6 +367,7 @@ exports[`Deleting a cluster when an internal kubeconfig cluster is used when the
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="TableCell labelsCell scrollable nowrap"
|
class="TableCell labelsCell scrollable nowrap"
|
||||||
|
data-testid="catalog-labels-column"
|
||||||
id="labels"
|
id="labels"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -406,6 +378,7 @@ exports[`Deleting a cluster when an internal kubeconfig cluster is used when the
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="TableCell statusCell nowrap sorting"
|
class="TableCell statusCell nowrap sorting"
|
||||||
|
data-testid="catalog-status-column"
|
||||||
id="status"
|
id="status"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -741,41 +714,35 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
Catalog
|
Catalog
|
||||||
</div>
|
</div>
|
||||||
<ul
|
<ul
|
||||||
aria-multiselectable="false"
|
class="treeView"
|
||||||
class="MuiTreeView-root"
|
|
||||||
role="tree"
|
role="tree"
|
||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
aria-selected="true"
|
class="root selected treeItem"
|
||||||
class="MuiTreeItem-root Mui-selected"
|
|
||||||
data-testid="*-tab"
|
data-testid="*-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="0"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
Browse
|
Browse
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
|
<div
|
||||||
|
class="HorizontalLine size-xxs"
|
||||||
|
/>
|
||||||
<li
|
<li
|
||||||
aria-expanded="true"
|
class="root treeGroup"
|
||||||
class="MuiTreeItem-root bordered Mui-expanded"
|
role="group"
|
||||||
role="treeitem"
|
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="group"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-iconContainer"
|
class="iconContainer"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon material focusable"
|
class="Icon material focusable"
|
||||||
@ -789,7 +756,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="parent"
|
class="parent"
|
||||||
@ -799,27 +766,15 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ul
|
<ul
|
||||||
class="MuiCollapse-root MuiTreeItem-group MuiCollapse-entered"
|
class="contents expanded"
|
||||||
role="group"
|
|
||||||
style="min-height: 0px;"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiCollapse-wrapper"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiCollapse-wrapperInner"
|
|
||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
class="MuiTreeItem-root"
|
class="root treeItem"
|
||||||
data-testid="entity.k8slens.dev/General-tab"
|
data-testid="entity.k8slens.dev/General-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon material focusable small"
|
class="Icon material focusable small"
|
||||||
@ -833,7 +788,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex"
|
class="flex"
|
||||||
@ -843,19 +798,14 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
class="MuiTreeItem-root"
|
class="root treeItem"
|
||||||
data-testid="entity.k8slens.dev/KubernetesCluster-tab"
|
data-testid="entity.k8slens.dev/KubernetesCluster-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon focusable small"
|
class="Icon focusable small"
|
||||||
@ -867,7 +817,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex"
|
class="flex"
|
||||||
@ -877,19 +827,14 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
class="MuiTreeItem-root"
|
class="root treeItem"
|
||||||
data-testid="entity.k8slens.dev/WebLink-tab"
|
data-testid="entity.k8slens.dev/WebLink-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon material focusable small"
|
class="Icon material focusable small"
|
||||||
@ -903,7 +848,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex"
|
class="flex"
|
||||||
@ -913,10 +858,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -1008,6 +950,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="TableCell nowrap sorting"
|
class="TableCell nowrap sorting"
|
||||||
|
data-testid="catalog-kind-column"
|
||||||
id="kind"
|
id="kind"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -1028,6 +971,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="TableCell sourceCell nowrap sorting"
|
class="TableCell sourceCell nowrap sorting"
|
||||||
|
data-testid="catalog-source-column"
|
||||||
id="source"
|
id="source"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -1048,6 +992,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="TableCell labelsCell scrollable nowrap"
|
class="TableCell labelsCell scrollable nowrap"
|
||||||
|
data-testid="catalog-labels-column"
|
||||||
id="labels"
|
id="labels"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -1058,6 +1003,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="TableCell statusCell nowrap sorting"
|
class="TableCell statusCell nowrap sorting"
|
||||||
|
data-testid="catalog-status-column"
|
||||||
id="status"
|
id="status"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -1426,41 +1372,35 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
Catalog
|
Catalog
|
||||||
</div>
|
</div>
|
||||||
<ul
|
<ul
|
||||||
aria-multiselectable="false"
|
class="treeView"
|
||||||
class="MuiTreeView-root"
|
|
||||||
role="tree"
|
role="tree"
|
||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
aria-selected="true"
|
class="root selected treeItem"
|
||||||
class="MuiTreeItem-root Mui-selected"
|
|
||||||
data-testid="*-tab"
|
data-testid="*-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="0"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
Browse
|
Browse
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
|
<div
|
||||||
|
class="HorizontalLine size-xxs"
|
||||||
|
/>
|
||||||
<li
|
<li
|
||||||
aria-expanded="true"
|
class="root treeGroup"
|
||||||
class="MuiTreeItem-root bordered Mui-expanded"
|
role="group"
|
||||||
role="treeitem"
|
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="group"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-iconContainer"
|
class="iconContainer"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon material focusable"
|
class="Icon material focusable"
|
||||||
@ -1474,7 +1414,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="parent"
|
class="parent"
|
||||||
@ -1484,27 +1424,15 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ul
|
<ul
|
||||||
class="MuiCollapse-root MuiTreeItem-group MuiCollapse-entered"
|
class="contents expanded"
|
||||||
role="group"
|
|
||||||
style="min-height: 0px;"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiCollapse-wrapper"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiCollapse-wrapperInner"
|
|
||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
class="MuiTreeItem-root"
|
class="root treeItem"
|
||||||
data-testid="entity.k8slens.dev/General-tab"
|
data-testid="entity.k8slens.dev/General-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon material focusable small"
|
class="Icon material focusable small"
|
||||||
@ -1518,7 +1446,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex"
|
class="flex"
|
||||||
@ -1528,19 +1456,14 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
class="MuiTreeItem-root"
|
class="root treeItem"
|
||||||
data-testid="entity.k8slens.dev/KubernetesCluster-tab"
|
data-testid="entity.k8slens.dev/KubernetesCluster-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon focusable small"
|
class="Icon focusable small"
|
||||||
@ -1552,7 +1475,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex"
|
class="flex"
|
||||||
@ -1562,19 +1485,14 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
class="MuiTreeItem-root"
|
class="root treeItem"
|
||||||
data-testid="entity.k8slens.dev/WebLink-tab"
|
data-testid="entity.k8slens.dev/WebLink-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon material focusable small"
|
class="Icon material focusable small"
|
||||||
@ -1588,7 +1506,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex"
|
class="flex"
|
||||||
@ -1598,10 +1516,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -1693,6 +1608,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="TableCell nowrap sorting"
|
class="TableCell nowrap sorting"
|
||||||
|
data-testid="catalog-kind-column"
|
||||||
id="kind"
|
id="kind"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -1713,6 +1629,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="TableCell sourceCell nowrap sorting"
|
class="TableCell sourceCell nowrap sorting"
|
||||||
|
data-testid="catalog-source-column"
|
||||||
id="source"
|
id="source"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -1733,6 +1650,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="TableCell labelsCell scrollable nowrap"
|
class="TableCell labelsCell scrollable nowrap"
|
||||||
|
data-testid="catalog-labels-column"
|
||||||
id="labels"
|
id="labels"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -1743,6 +1661,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="TableCell statusCell nowrap sorting"
|
class="TableCell statusCell nowrap sorting"
|
||||||
|
data-testid="catalog-status-column"
|
||||||
id="status"
|
id="status"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -2190,41 +2109,35 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
Catalog
|
Catalog
|
||||||
</div>
|
</div>
|
||||||
<ul
|
<ul
|
||||||
aria-multiselectable="false"
|
class="treeView"
|
||||||
class="MuiTreeView-root"
|
|
||||||
role="tree"
|
role="tree"
|
||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
aria-selected="true"
|
class="root selected treeItem"
|
||||||
class="MuiTreeItem-root Mui-selected"
|
|
||||||
data-testid="*-tab"
|
data-testid="*-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="0"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
Browse
|
Browse
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
|
<div
|
||||||
|
class="HorizontalLine size-xxs"
|
||||||
|
/>
|
||||||
<li
|
<li
|
||||||
aria-expanded="true"
|
class="root treeGroup"
|
||||||
class="MuiTreeItem-root bordered Mui-expanded"
|
role="group"
|
||||||
role="treeitem"
|
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="group"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-iconContainer"
|
class="iconContainer"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon material focusable"
|
class="Icon material focusable"
|
||||||
@ -2238,7 +2151,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="parent"
|
class="parent"
|
||||||
@ -2248,27 +2161,15 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ul
|
<ul
|
||||||
class="MuiCollapse-root MuiTreeItem-group MuiCollapse-entered"
|
class="contents expanded"
|
||||||
role="group"
|
|
||||||
style="min-height: 0px;"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiCollapse-wrapper"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiCollapse-wrapperInner"
|
|
||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
class="MuiTreeItem-root"
|
class="root treeItem"
|
||||||
data-testid="entity.k8slens.dev/General-tab"
|
data-testid="entity.k8slens.dev/General-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon material focusable small"
|
class="Icon material focusable small"
|
||||||
@ -2282,7 +2183,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex"
|
class="flex"
|
||||||
@ -2292,19 +2193,14 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
class="MuiTreeItem-root"
|
class="root treeItem"
|
||||||
data-testid="entity.k8slens.dev/KubernetesCluster-tab"
|
data-testid="entity.k8slens.dev/KubernetesCluster-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon focusable small"
|
class="Icon focusable small"
|
||||||
@ -2316,7 +2212,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex"
|
class="flex"
|
||||||
@ -2326,19 +2222,14 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
class="MuiTreeItem-root"
|
class="root treeItem"
|
||||||
data-testid="entity.k8slens.dev/WebLink-tab"
|
data-testid="entity.k8slens.dev/WebLink-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon material focusable small"
|
class="Icon material focusable small"
|
||||||
@ -2352,7 +2243,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex"
|
class="flex"
|
||||||
@ -2362,10 +2253,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -2457,6 +2345,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="TableCell nowrap sorting"
|
class="TableCell nowrap sorting"
|
||||||
|
data-testid="catalog-kind-column"
|
||||||
id="kind"
|
id="kind"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -2477,6 +2366,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="TableCell sourceCell nowrap sorting"
|
class="TableCell sourceCell nowrap sorting"
|
||||||
|
data-testid="catalog-source-column"
|
||||||
id="source"
|
id="source"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -2497,6 +2387,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="TableCell labelsCell scrollable nowrap"
|
class="TableCell labelsCell scrollable nowrap"
|
||||||
|
data-testid="catalog-labels-column"
|
||||||
id="labels"
|
id="labels"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -2507,6 +2398,7 @@ exports[`Deleting a cluster when the kubeconfig has multiple clusters when the d
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="TableCell statusCell nowrap sorting"
|
class="TableCell statusCell nowrap sorting"
|
||||||
|
data-testid="catalog-status-column"
|
||||||
id="status"
|
id="status"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -2954,41 +2846,35 @@ exports[`Deleting a cluster when the kubeconfig has only one cluster when the di
|
|||||||
Catalog
|
Catalog
|
||||||
</div>
|
</div>
|
||||||
<ul
|
<ul
|
||||||
aria-multiselectable="false"
|
class="treeView"
|
||||||
class="MuiTreeView-root"
|
|
||||||
role="tree"
|
role="tree"
|
||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
aria-selected="true"
|
class="root selected treeItem"
|
||||||
class="MuiTreeItem-root Mui-selected"
|
|
||||||
data-testid="*-tab"
|
data-testid="*-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="0"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
Browse
|
Browse
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
|
<div
|
||||||
|
class="HorizontalLine size-xxs"
|
||||||
|
/>
|
||||||
<li
|
<li
|
||||||
aria-expanded="true"
|
class="root treeGroup"
|
||||||
class="MuiTreeItem-root bordered Mui-expanded"
|
role="group"
|
||||||
role="treeitem"
|
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="group"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-iconContainer"
|
class="iconContainer"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon material focusable"
|
class="Icon material focusable"
|
||||||
@ -3002,7 +2888,7 @@ exports[`Deleting a cluster when the kubeconfig has only one cluster when the di
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="parent"
|
class="parent"
|
||||||
@ -3012,27 +2898,15 @@ exports[`Deleting a cluster when the kubeconfig has only one cluster when the di
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ul
|
<ul
|
||||||
class="MuiCollapse-root MuiTreeItem-group MuiCollapse-entered"
|
class="contents expanded"
|
||||||
role="group"
|
|
||||||
style="min-height: 0px;"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiCollapse-wrapper"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiCollapse-wrapperInner"
|
|
||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
class="MuiTreeItem-root"
|
class="root treeItem"
|
||||||
data-testid="entity.k8slens.dev/General-tab"
|
data-testid="entity.k8slens.dev/General-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon material focusable small"
|
class="Icon material focusable small"
|
||||||
@ -3046,7 +2920,7 @@ exports[`Deleting a cluster when the kubeconfig has only one cluster when the di
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex"
|
class="flex"
|
||||||
@ -3056,19 +2930,14 @@ exports[`Deleting a cluster when the kubeconfig has only one cluster when the di
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
class="MuiTreeItem-root"
|
class="root treeItem"
|
||||||
data-testid="entity.k8slens.dev/KubernetesCluster-tab"
|
data-testid="entity.k8slens.dev/KubernetesCluster-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon focusable small"
|
class="Icon focusable small"
|
||||||
@ -3080,7 +2949,7 @@ exports[`Deleting a cluster when the kubeconfig has only one cluster when the di
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex"
|
class="flex"
|
||||||
@ -3090,19 +2959,14 @@ exports[`Deleting a cluster when the kubeconfig has only one cluster when the di
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
class="MuiTreeItem-root"
|
class="root treeItem"
|
||||||
data-testid="entity.k8slens.dev/WebLink-tab"
|
data-testid="entity.k8slens.dev/WebLink-tab"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTreeItem-content"
|
class="iconContainer"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTreeItem-iconContainer"
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon material focusable small"
|
class="Icon material focusable small"
|
||||||
@ -3116,7 +2980,7 @@ exports[`Deleting a cluster when the kubeconfig has only one cluster when the di
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root MuiTreeItem-label MuiTypography-body1"
|
class="label"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex"
|
class="flex"
|
||||||
@ -3126,10 +2990,7 @@ exports[`Deleting a cluster when the kubeconfig has only one cluster when the di
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -3221,6 +3082,7 @@ exports[`Deleting a cluster when the kubeconfig has only one cluster when the di
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="TableCell nowrap sorting"
|
class="TableCell nowrap sorting"
|
||||||
|
data-testid="catalog-kind-column"
|
||||||
id="kind"
|
id="kind"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -3241,6 +3103,7 @@ exports[`Deleting a cluster when the kubeconfig has only one cluster when the di
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="TableCell sourceCell nowrap sorting"
|
class="TableCell sourceCell nowrap sorting"
|
||||||
|
data-testid="catalog-source-column"
|
||||||
id="source"
|
id="source"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -3261,6 +3124,7 @@ exports[`Deleting a cluster when the kubeconfig has only one cluster when the di
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="TableCell labelsCell scrollable nowrap"
|
class="TableCell labelsCell scrollable nowrap"
|
||||||
|
data-testid="catalog-labels-column"
|
||||||
id="labels"
|
id="labels"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -3271,6 +3135,7 @@ exports[`Deleting a cluster when the kubeconfig has only one cluster when the di
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="TableCell statusCell nowrap sorting"
|
class="TableCell statusCell nowrap sorting"
|
||||||
|
data-testid="catalog-status-column"
|
||||||
id="status"
|
id="status"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|||||||
@ -173,6 +173,7 @@ exports[`Command Pallet: keyboard shortcut tests when on linux renders 1`] = `
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
@ -549,6 +550,7 @@ exports[`Command Pallet: keyboard shortcut tests when on linux when pressing ESC
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
@ -925,6 +927,7 @@ exports[`Command Pallet: keyboard shortcut tests when on linux when pressing SHI
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
@ -1313,6 +1316,7 @@ exports[`Command Pallet: keyboard shortcut tests when on linux when pressing SHI
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
@ -1598,6 +1602,7 @@ exports[`Command Pallet: keyboard shortcut tests when on macOS renders 1`] = `
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
@ -1883,6 +1888,7 @@ exports[`Command Pallet: keyboard shortcut tests when on macOS when pressing ESC
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
@ -2168,6 +2174,7 @@ exports[`Command Pallet: keyboard shortcut tests when on macOS when pressing SHI
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
@ -2465,6 +2472,7 @@ exports[`Command Pallet: keyboard shortcut tests when on macOS when pressing SHI
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
|
|||||||
@ -82,6 +82,7 @@ exports[`Showing correct entity settings renders 1`] = `
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
|
|||||||
@ -81,6 +81,7 @@ exports[`extensions - navigation using application menu renders 1`] = `
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
|
|||||||
@ -81,6 +81,7 @@ exports[`preferences - navigation using application menu renders 1`] = `
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
|
|||||||
@ -82,6 +82,7 @@ exports[`show-about-using-tray renders 1`] = `
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
|
|||||||
@ -82,6 +82,7 @@ exports[`status-bar-items-originating-from-extensions when application starts wh
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
|
|||||||
@ -82,6 +82,7 @@ exports[`extendability-using-extension-api given an extension with a weakly type
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
@ -376,6 +377,7 @@ exports[`extendability-using-extension-api given an extension with top-bar items
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
@ -661,6 +663,7 @@ exports[`extendability-using-extension-api given an extension with top-bar items
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
@ -946,6 +949,7 @@ exports[`extendability-using-extension-api renders 1`] = `
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
|
|||||||
@ -81,6 +81,7 @@ exports[`welcome - navigation using application menu renders 1`] = `
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
@ -1116,6 +1117,7 @@ exports[`welcome - navigation using application menu when navigated somewhere el
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="Icon logo svg focusable"
|
class="Icon logo svg focusable"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="icon"
|
class="icon"
|
||||||
|
|||||||
@ -0,0 +1,91 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import type { RenderResult } from "@testing-library/react";
|
||||||
|
import { screen } from "@testing-library/react";
|
||||||
|
import { defaultWidth } from "../../renderer/components/+welcome/welcome";
|
||||||
|
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||||
|
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||||
|
|
||||||
|
describe("Banners from extensions", () => {
|
||||||
|
let builder: ApplicationBuilder;
|
||||||
|
let renderResult: RenderResult;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
builder = getApplicationBuilder();
|
||||||
|
renderResult = await builder.render();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("initially renderes welcome page", () => {
|
||||||
|
expect(renderResult.queryByTestId("welcome-page")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows the empty welcome banner icon", () => {
|
||||||
|
expect(renderResult.queryByTestId("no-welcome-banners-icon")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when an extension is enabled with a single welcome banner", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
builder.extensions.enable({
|
||||||
|
id: "some-id",
|
||||||
|
name: "some-name",
|
||||||
|
rendererOptions: {
|
||||||
|
welcomeBanners: [
|
||||||
|
{
|
||||||
|
Banner: () => <div data-testid="some-test-id" />,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders the banner from the extension", () => {
|
||||||
|
expect(renderResult.queryByTestId("some-test-id")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("no longer shows the empty welcome banner icon", () => {
|
||||||
|
expect(renderResult.queryByTestId("no-welcome-banners-icon")).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when an extension is enabled with multiple banners with custom widths", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
builder.extensions.enable({
|
||||||
|
id: "some-id",
|
||||||
|
name: "some-name",
|
||||||
|
rendererOptions: {
|
||||||
|
welcomeBanners: [
|
||||||
|
{
|
||||||
|
width: 100,
|
||||||
|
Banner: () => <div />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
width: 800,
|
||||||
|
Banner: () => <div />,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("no longer shows the empty welcome banner icon", () => {
|
||||||
|
expect(renderResult.queryByTestId("no-welcome-banners-icon")).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("computes an opropriate width for the carosel", () => {
|
||||||
|
expect(screen.queryByTestId("welcome-banner-container")).toHaveStyle({
|
||||||
|
// should take the max width of the banners (if > defaultWidth)
|
||||||
|
width: `800px`,
|
||||||
|
});
|
||||||
|
expect(screen.queryByTestId("welcome-text-container")).toHaveStyle({
|
||||||
|
width: `${defaultWidth}px`,
|
||||||
|
});
|
||||||
|
expect(screen.queryByTestId("welcome-menu-container")).toHaveStyle({
|
||||||
|
width: `${defaultWidth}px`,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -1,37 +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 type { Writable } from "type-fest";
|
|
||||||
import loggerInjectable from "../../common/logger.injectable";
|
|
||||||
import { createExtensionInstanceInjectionToken } from "../../extensions/extension-loader/create-extension-instance.token";
|
|
||||||
import ensureHashedDirectoryForExtensionInjectable from "../../extensions/extension-loader/file-system-provisioner-store/ensure-hashed-directory-for-extension.injectable";
|
|
||||||
import { lensExtensionDependencies } from "../../extensions/lens-extension";
|
|
||||||
import type { LensMainExtensionDependencies } from "../../extensions/lens-extension-set-dependencies";
|
|
||||||
import type { LensMainExtension } from "../../extensions/lens-main-extension";
|
|
||||||
import catalogEntityRegistryInjectable from "../catalog/entity-registry.injectable";
|
|
||||||
import navigateForExtensionInjectable from "../start-main-application/lens-window/navigate-for-extension.injectable";
|
|
||||||
|
|
||||||
const createExtensionInstanceInjectable = getInjectable({
|
|
||||||
id: "create-extension-instance",
|
|
||||||
instantiate: (di) => {
|
|
||||||
const deps: LensMainExtensionDependencies = {
|
|
||||||
ensureHashedDirectoryForExtension: di.inject(ensureHashedDirectoryForExtensionInjectable),
|
|
||||||
entityRegistry: di.inject(catalogEntityRegistryInjectable),
|
|
||||||
navigate: di.inject(navigateForExtensionInjectable),
|
|
||||||
logger: di.inject(loggerInjectable),
|
|
||||||
};
|
|
||||||
|
|
||||||
return (ExtensionClass, extension) => {
|
|
||||||
const instance = new ExtensionClass(extension as any) as LensMainExtension;
|
|
||||||
|
|
||||||
(instance as Writable<LensMainExtension>)[lensExtensionDependencies] = deps;
|
|
||||||
|
|
||||||
return instance;
|
|
||||||
};
|
|
||||||
},
|
|
||||||
injectionToken: createExtensionInstanceInjectionToken,
|
|
||||||
});
|
|
||||||
|
|
||||||
export default createExtensionInstanceInjectable;
|
|
||||||
@ -10,15 +10,15 @@ import { noop } from "@k8slens/utilities";
|
|||||||
import type { LensProtocolRouterMain } from "../lens-protocol-router-main/lens-protocol-router-main";
|
import type { LensProtocolRouterMain } from "../lens-protocol-router-main/lens-protocol-router-main";
|
||||||
import { getDiForUnitTesting } from "../../getDiForUnitTesting";
|
import { getDiForUnitTesting } from "../../getDiForUnitTesting";
|
||||||
import lensProtocolRouterMainInjectable from "../lens-protocol-router-main/lens-protocol-router-main.injectable";
|
import lensProtocolRouterMainInjectable from "../lens-protocol-router-main/lens-protocol-router-main.injectable";
|
||||||
import { LensExtension } from "../../../extensions/lens-extension";
|
|
||||||
import type { ObservableMap } from "mobx";
|
import type { ObservableMap } from "mobx";
|
||||||
import { runInAction } from "mobx";
|
import { runInAction } from "mobx";
|
||||||
import extensionInstancesInjectable from "../../../extensions/extension-loader/extension-instances.injectable";
|
import extensionInstancesInjectable from "../../../extensions/extension-loader/extension-instances.injectable";
|
||||||
import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||||
import broadcastMessageInjectable from "../../../common/ipc/broadcast-message.injectable";
|
import broadcastMessageInjectable from "../../../common/ipc/broadcast-message.injectable";
|
||||||
import type { LensExtensionId } from "@k8slens/legacy-extensions";
|
|
||||||
import type { LensExtensionState } from "../../../features/extensions/enabled/common/state.injectable";
|
import type { LensExtensionState } from "../../../features/extensions/enabled/common/state.injectable";
|
||||||
import enabledExtensionsStateInjectable from "../../../features/extensions/enabled/common/state.injectable";
|
import enabledExtensionsStateInjectable from "../../../features/extensions/enabled/common/state.injectable";
|
||||||
|
import type { LegacyLensExtension, LensExtensionId } from "@k8slens/legacy-extensions";
|
||||||
|
import { LensMainExtension } from "../../../extensions/lens-main-extension";
|
||||||
|
|
||||||
function throwIfDefined(val: any): void {
|
function throwIfDefined(val: any): void {
|
||||||
if (val != null) {
|
if (val != null) {
|
||||||
@ -27,7 +27,7 @@ function throwIfDefined(val: any): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe("protocol router tests", () => {
|
describe("protocol router tests", () => {
|
||||||
let extensionInstances: ObservableMap<LensExtensionId, LensExtension>;
|
let extensionInstances: ObservableMap<LensExtensionId, LegacyLensExtension>;
|
||||||
let lpr: LensProtocolRouterMain;
|
let lpr: LensProtocolRouterMain;
|
||||||
let enabledExtensions: ObservableMap<LensExtensionId, LensExtensionState>;
|
let enabledExtensions: ObservableMap<LensExtensionId, LensExtensionState>;
|
||||||
let broadcastMessageMock: jest.Mock;
|
let broadcastMessageMock: jest.Mock;
|
||||||
@ -73,7 +73,7 @@ describe("protocol router tests", () => {
|
|||||||
|
|
||||||
it("should broadcast external route when called with valid host", async () => {
|
it("should broadcast external route when called with valid host", async () => {
|
||||||
const extId = uuid.v4();
|
const extId = uuid.v4();
|
||||||
const ext = new LensExtension({
|
const ext = new LensMainExtension({
|
||||||
id: extId,
|
id: extId,
|
||||||
manifestPath: "/foo/bar",
|
manifestPath: "/foo/bar",
|
||||||
manifest: {
|
manifest: {
|
||||||
@ -149,7 +149,7 @@ describe("protocol router tests", () => {
|
|||||||
let called: any = 0;
|
let called: any = 0;
|
||||||
|
|
||||||
const extId = uuid.v4();
|
const extId = uuid.v4();
|
||||||
const ext = new LensExtension({
|
const ext = new LensMainExtension({
|
||||||
id: extId,
|
id: extId,
|
||||||
manifestPath: "/foo/bar",
|
manifestPath: "/foo/bar",
|
||||||
manifest: {
|
manifest: {
|
||||||
@ -190,7 +190,7 @@ describe("protocol router tests", () => {
|
|||||||
|
|
||||||
{
|
{
|
||||||
const extId = uuid.v4();
|
const extId = uuid.v4();
|
||||||
const ext = new LensExtension({
|
const ext = new LensMainExtension({
|
||||||
id: extId,
|
id: extId,
|
||||||
manifestPath: "/foo/bar",
|
manifestPath: "/foo/bar",
|
||||||
manifest: {
|
manifest: {
|
||||||
@ -216,7 +216,7 @@ describe("protocol router tests", () => {
|
|||||||
|
|
||||||
{
|
{
|
||||||
const extId = uuid.v4();
|
const extId = uuid.v4();
|
||||||
const ext = new LensExtension({
|
const ext = new LensMainExtension({
|
||||||
id: extId,
|
id: extId,
|
||||||
manifestPath: "/foo/bar",
|
manifestPath: "/foo/bar",
|
||||||
manifest: {
|
manifest: {
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import { getDiForUnitTesting } from "../../../getDiForUnitTesting";
|
|||||||
import type { CatalogEntityStore } from "../catalog-entity-store.injectable";
|
import type { CatalogEntityStore } from "../catalog-entity-store.injectable";
|
||||||
import catalogEntityStoreInjectable from "../catalog-entity-store.injectable";
|
import catalogEntityStoreInjectable from "../catalog-entity-store.injectable";
|
||||||
import { noop } from "@k8slens/utilities";
|
import { noop } from "@k8slens/utilities";
|
||||||
|
import type { CatalogEntityRegistry } from "../../../api/catalog/entity/registry";
|
||||||
|
|
||||||
class TestEntityOne extends CatalogEntity {
|
class TestEntityOne extends CatalogEntity {
|
||||||
public static readonly apiVersion: string = "entity.k8slens.dev/v1alpha1";
|
public static readonly apiVersion: string = "entity.k8slens.dev/v1alpha1";
|
||||||
@ -152,7 +153,7 @@ describe("CatalogEntityStore", () => {
|
|||||||
getItemsForCategory: <T extends CatalogEntity>(category: CatalogCategory): T[] => {
|
getItemsForCategory: <T extends CatalogEntity>(category: CatalogCategory): T[] => {
|
||||||
return entityItems.filter(item => category.spec.versions.some(version => item instanceof version.entityClass)) as T[];
|
return entityItems.filter(item => category.spec.versions.some(version => item instanceof version.entityClass)) as T[];
|
||||||
},
|
},
|
||||||
} as any));
|
} as CatalogEntityRegistry));
|
||||||
|
|
||||||
store = di.inject(catalogEntityStoreInjectable);
|
store = di.inject(catalogEntityStoreInjectable);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,135 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import type { DiContainer } from "@ogre-tools/injectable";
|
|
||||||
import type { CatalogCategorySpec } from "../../../../common/catalog";
|
|
||||||
import { LensRendererExtension } from "../../../../extensions/lens-renderer-extension";
|
|
||||||
import { CatalogCategory } from "../../../api/catalog-entity";
|
|
||||||
import { getDiForUnitTesting } from "../../../getDiForUnitTesting";
|
|
||||||
import type { AdditionalCategoryColumnRegistration, CategoryColumnRegistration } from "../custom-category-columns";
|
|
||||||
import type { CategoryColumns, GetCategoryColumnsParams } from "../columns/get.injectable";
|
|
||||||
import getCategoryColumnsInjectable from "../columns/get.injectable";
|
|
||||||
import extensionInjectable from "../../../../extensions/extension-loader/extension/extension.injectable";
|
|
||||||
import currentlyInClusterFrameInjectable from "../../../routes/currently-in-cluster-frame.injectable";
|
|
||||||
|
|
||||||
class TestCategory extends CatalogCategory {
|
|
||||||
apiVersion = "catalog.k8slens.dev/v1alpha1";
|
|
||||||
kind = "CatalogCategory";
|
|
||||||
metadata = {
|
|
||||||
name: "Test",
|
|
||||||
icon: "question_mark",
|
|
||||||
};
|
|
||||||
spec: CatalogCategorySpec = {
|
|
||||||
group: "foo.bar.bat",
|
|
||||||
names: {
|
|
||||||
kind: "Test",
|
|
||||||
},
|
|
||||||
versions: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(columns?: CategoryColumnRegistration[]) {
|
|
||||||
super();
|
|
||||||
this.spec = {
|
|
||||||
displayColumns: columns,
|
|
||||||
...this.spec,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("Custom Category Columns", () => {
|
|
||||||
let di: DiContainer;
|
|
||||||
let getCategoryColumns: (params: GetCategoryColumnsParams) => CategoryColumns;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
di = getDiForUnitTesting();
|
|
||||||
|
|
||||||
di.override(currentlyInClusterFrameInjectable, () => false);
|
|
||||||
|
|
||||||
getCategoryColumns = di.inject(getCategoryColumnsInjectable);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("without extensions", () => {
|
|
||||||
it("should contain a kind column if activeCategory is falsy", () => {
|
|
||||||
expect(getCategoryColumns({ activeCategory: null }).renderTableHeader.find(elem => elem?.title === "Kind")).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not contain a kind column if activeCategory is truthy", () => {
|
|
||||||
expect(getCategoryColumns({ activeCategory: new TestCategory() }).renderTableHeader.find(elem => elem?.title === "Kind")).toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should include the default columns if the provided category doesn't provide any", () => {
|
|
||||||
expect(getCategoryColumns({ activeCategory: new TestCategory() }).renderTableHeader.find(elem => elem?.title === "Source")).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not include the default columns if the provided category provides any", () => {
|
|
||||||
expect(getCategoryColumns({ activeCategory: new TestCategory([]) }).renderTableHeader.find(elem => elem?.title === "Source")).toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should include the displayColumns from the provided category", () => {
|
|
||||||
const columns: CategoryColumnRegistration[] = [
|
|
||||||
{
|
|
||||||
id: "foo",
|
|
||||||
renderCell: () => null,
|
|
||||||
titleProps: {
|
|
||||||
title: "Foo",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
expect(getCategoryColumns({ activeCategory: new TestCategory(columns) }).renderTableHeader.find(elem => elem?.title === "Foo")).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("with extensions", () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
const ext = di.inject(extensionInjectable, new (class extends LensRendererExtension {
|
|
||||||
additionalCategoryColumns = [
|
|
||||||
{
|
|
||||||
group: "foo.bar.bat",
|
|
||||||
id: "high",
|
|
||||||
kind: "Test",
|
|
||||||
renderCell: () => "",
|
|
||||||
titleProps: {
|
|
||||||
title: "High",
|
|
||||||
},
|
|
||||||
} as AdditionalCategoryColumnRegistration,
|
|
||||||
{
|
|
||||||
group: "foo.bar",
|
|
||||||
id: "high",
|
|
||||||
kind: "Test",
|
|
||||||
renderCell: () => "",
|
|
||||||
titleProps: {
|
|
||||||
title: "High2",
|
|
||||||
},
|
|
||||||
} as AdditionalCategoryColumnRegistration,
|
|
||||||
];
|
|
||||||
})({
|
|
||||||
absolutePath: "/some-absolute-path",
|
|
||||||
id: "some-id",
|
|
||||||
isBundled: false,
|
|
||||||
isCompatible: true,
|
|
||||||
isEnabled: true,
|
|
||||||
manifest: {
|
|
||||||
engines: {
|
|
||||||
lens: "",
|
|
||||||
},
|
|
||||||
name: "some-extension-name",
|
|
||||||
version: "1.0.0",
|
|
||||||
},
|
|
||||||
manifestPath: "/some-manifest-path",
|
|
||||||
}));
|
|
||||||
|
|
||||||
ext.register();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should include columns from extensions that match", () => {
|
|
||||||
expect(getCategoryColumns({ activeCategory: new TestCategory() }).renderTableHeader.find(elem => elem?.title === "High")).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not include columns from extensions that don't match", () => {
|
|
||||||
expect(getCategoryColumns({ activeCategory: new TestCategory() }).renderTableHeader.find(elem => elem?.title === "High2")).toBeFalsy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -30,7 +30,7 @@ const catalogEntityStoreInjectable = getInjectable({
|
|||||||
const catalogCategoryRegistry = di.inject(catalogCategoryRegistryInjectable);
|
const catalogCategoryRegistry = di.inject(catalogCategoryRegistryInjectable);
|
||||||
const selectedCatalogEntityParam = di.inject(selectedCatalogEntityParamInjectable);
|
const selectedCatalogEntityParam = di.inject(selectedCatalogEntityParamInjectable);
|
||||||
|
|
||||||
const activeCategory = observable.box<CatalogCategory | undefined>(undefined);
|
const activeCategory = observable.box<CatalogCategory>();
|
||||||
const entities = computed(() => {
|
const entities = computed(() => {
|
||||||
const category = activeCategory.get();
|
const category = activeCategory.get();
|
||||||
|
|
||||||
|
|||||||
@ -7,25 +7,24 @@ import treeStyles from "./catalog-tree.module.scss";
|
|||||||
import styles from "./catalog-menu.module.scss";
|
import styles from "./catalog-menu.module.scss";
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import type { TreeItemProps } from "@material-ui/lab";
|
|
||||||
import { TreeItem, TreeView } from "@material-ui/lab";
|
|
||||||
import { Icon } from "../icon";
|
import { Icon } from "../icon";
|
||||||
import { StylesProvider } from "@material-ui/core";
|
|
||||||
import { cssNames } from "@k8slens/utilities";
|
|
||||||
import type { CatalogCategory } from "../../api/catalog-entity";
|
import type { CatalogCategory } from "../../api/catalog-entity";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { CatalogCategoryLabel } from "./catalog-category-label";
|
import { CatalogCategoryLabel } from "./catalog-category-label";
|
||||||
import type { IComputedValue } from "mobx";
|
import type { IComputedValue } from "mobx";
|
||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
import filteredCategoriesInjectable from "../../../common/catalog/filtered-categories.injectable";
|
import filteredCategoriesInjectable from "../../../common/catalog/filtered-categories.injectable";
|
||||||
|
import { TreeGroup, TreeItem, TreeView } from "../tree-view/tree-view";
|
||||||
|
import { browseCatalogTab } from "./catalog-browse-tab";
|
||||||
|
import { HorizontalLine } from "../horizontal-line/horizontal-line";
|
||||||
|
|
||||||
export interface CatalogMenuProps {
|
export interface CatalogMenuProps {
|
||||||
activeTab: string | undefined;
|
activeTab: string | undefined;
|
||||||
onItemClick: (id: string) => void;
|
onItemClick: (id: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCategoryIcon(category: CatalogCategory) {
|
function CategoryIcon(props: { category: CatalogCategory }) {
|
||||||
const { icon } = category.metadata ?? {};
|
const { icon } = props.category.metadata ?? {};
|
||||||
|
|
||||||
if (typeof icon === "string") {
|
if (typeof icon === "string") {
|
||||||
return Icon.isSvg(icon)
|
return Icon.isSvg(icon)
|
||||||
@ -36,12 +35,6 @@ function getCategoryIcon(category: CatalogCategory) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Item(props: TreeItemProps) {
|
|
||||||
return (
|
|
||||||
<TreeItem classes={treeStyles} {...props}/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
filteredCategories: IComputedValue<CatalogCategory[]>;
|
filteredCategories: IComputedValue<CatalogCategory[]>;
|
||||||
}
|
}
|
||||||
@ -51,42 +44,36 @@ const NonInjectedCatalogMenu = observer(({
|
|||||||
filteredCategories,
|
filteredCategories,
|
||||||
onItemClick,
|
onItemClick,
|
||||||
}: CatalogMenuProps & Dependencies) => (
|
}: CatalogMenuProps & Dependencies) => (
|
||||||
// Overwrite Material UI styles with injectFirst https://material-ui.com/guides/interoperability/#controlling-priority-4
|
|
||||||
<StylesProvider injectFirst>
|
|
||||||
<div className="flex flex-col w-full">
|
<div className="flex flex-col w-full">
|
||||||
<div className={styles.catalog}>Catalog</div>
|
<div className={styles.catalog}>Catalog</div>
|
||||||
<TreeView
|
<TreeView>
|
||||||
defaultExpanded={["catalog"]}
|
<TreeItem
|
||||||
defaultCollapseIcon={<Icon material="expand_more" />}
|
classes={treeStyles}
|
||||||
defaultExpandIcon={<Icon material="chevron_right" />}
|
|
||||||
selected={activeTab || "browse"}
|
|
||||||
>
|
|
||||||
<Item
|
|
||||||
nodeId="browse"
|
|
||||||
label="Browse"
|
label="Browse"
|
||||||
data-testid="*-tab"
|
data-testid="*-tab"
|
||||||
onClick={() => onItemClick("*")} />
|
onClick={() => onItemClick("*")}
|
||||||
<Item
|
selected={activeTab === browseCatalogTab}
|
||||||
nodeId="catalog"
|
/>
|
||||||
|
<HorizontalLine size="xxs" />
|
||||||
|
<TreeGroup
|
||||||
|
classes={treeStyles}
|
||||||
label={<div className={styles.parent}>Categories</div>}
|
label={<div className={styles.parent}>Categories</div>}
|
||||||
className={cssNames(styles.bordered)}
|
|
||||||
>
|
>
|
||||||
{
|
{filteredCategories.get()
|
||||||
filteredCategories.get()
|
|
||||||
.map(category => (
|
.map(category => (
|
||||||
<Item
|
<TreeItem
|
||||||
icon={getCategoryIcon(category)}
|
classes={treeStyles}
|
||||||
key={category.getId()}
|
key={category.getId()}
|
||||||
nodeId={category.getId()}
|
icon={<CategoryIcon category={category} />}
|
||||||
label={<CatalogCategoryLabel category={category} />}
|
label={<CatalogCategoryLabel category={category} />}
|
||||||
|
selected={activeTab === category.getId()}
|
||||||
data-testid={`${category.getId()}-tab`}
|
data-testid={`${category.getId()}-tab`}
|
||||||
onClick={() => onItemClick(category.getId())} />
|
onClick={() => onItemClick(category.getId())}
|
||||||
))
|
/>
|
||||||
}
|
))}
|
||||||
</Item>
|
</TreeGroup>
|
||||||
</TreeView>
|
</TreeView>
|
||||||
</div>
|
</div>
|
||||||
</StylesProvider>
|
|
||||||
));
|
));
|
||||||
|
|
||||||
export const CatalogMenu = withInjectables<Dependencies, CatalogMenuProps>(NonInjectedCatalogMenu, {
|
export const CatalogMenu = withInjectables<Dependencies, CatalogMenuProps>(NonInjectedCatalogMenu, {
|
||||||
|
|||||||
@ -23,39 +23,8 @@
|
|||||||
.content {
|
.content {
|
||||||
min-height: 26px;
|
min-height: 26px;
|
||||||
line-height: 1.3;
|
line-height: 1.3;
|
||||||
padding: 2px var(--padding) 2px 0;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: var(--sidebarItemHoverBackground);
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
color: white;
|
|
||||||
background-color: var(--blue);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.group {
|
.group {
|
||||||
margin-left: 0px;
|
margin-left: 0px;
|
||||||
|
|
||||||
.iconContainer {
|
|
||||||
margin-left: 28px;
|
|
||||||
margin-top: 2px;
|
|
||||||
align-self: flex-start;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.selected {
|
|
||||||
& > *:first-child {
|
|
||||||
background-color: var(--blue);
|
|
||||||
color: white;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.iconContainer {
|
|
||||||
width: 21px;
|
|
||||||
margin-left: 5px;
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -135,16 +135,19 @@ class NonInjectedCatalog extends React.Component<Dependencies> {
|
|||||||
}
|
}
|
||||||
}, { fireImmediately: true }),
|
}, { fireImmediately: true }),
|
||||||
// If active category is filtered out, automatically switch to the first category
|
// If active category is filtered out, automatically switch to the first category
|
||||||
reaction(() => catalogCategoryRegistry.filteredItems, () => {
|
reaction(() => [...catalogCategoryRegistry.filteredItems], (categories) => {
|
||||||
if (!catalogCategoryRegistry.filteredItems.find(item => item.getId() === catalogEntityStore.activeCategory.get()?.getId())) {
|
const currentCategory = catalogEntityStore.activeCategory.get();
|
||||||
const item = catalogCategoryRegistry.filteredItems[0];
|
const someCategory = categories[0];
|
||||||
|
|
||||||
runInAction(() => {
|
if (this.routeActiveTab === browseCatalogTab || !someCategory) {
|
||||||
if (item) {
|
return;
|
||||||
this.activeTab = item.getId();
|
|
||||||
this.props.catalogEntityStore.activeCategory.set(item);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
const currentCategoryShouldBeShown = Boolean(categories.find(item => item.getId() === someCategory.getId()));
|
||||||
|
|
||||||
|
if (!currentCategory || !currentCategoryShouldBeShown) {
|
||||||
|
this.activeTab = someCategory.getId();
|
||||||
|
this.props.catalogEntityStore.activeCategory.set(someCategory);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
|||||||
@ -17,6 +17,7 @@ const defaultBrowseAllColumns: RegisteredAdditionalCategoryColumn[] = [
|
|||||||
id: "kind",
|
id: "kind",
|
||||||
sortBy: "kind",
|
sortBy: "kind",
|
||||||
title: "Kind",
|
title: "Kind",
|
||||||
|
"data-testid": "catalog-kind-column",
|
||||||
},
|
},
|
||||||
sortCallback: entity => entity.kind,
|
sortCallback: entity => entity.kind,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -25,6 +25,7 @@ const defaultCategoryColumnsInjectable = getInjectable({
|
|||||||
className: styles.sourceCell,
|
className: styles.sourceCell,
|
||||||
id: "source",
|
id: "source",
|
||||||
sortBy: "source",
|
sortBy: "source",
|
||||||
|
"data-testid": "catalog-source-column",
|
||||||
},
|
},
|
||||||
sortCallback: entity => entity.getSource(),
|
sortCallback: entity => entity.getSource(),
|
||||||
searchFilter: entity => `source=${entity.getSource()}`,
|
searchFilter: entity => `source=${entity.getSource()}`,
|
||||||
@ -37,6 +38,7 @@ const defaultCategoryColumnsInjectable = getInjectable({
|
|||||||
id: "labels",
|
id: "labels",
|
||||||
title: "Labels",
|
title: "Labels",
|
||||||
className: `${styles.labelsCell} scrollable`,
|
className: `${styles.labelsCell} scrollable`,
|
||||||
|
"data-testid": "catalog-labels-column",
|
||||||
},
|
},
|
||||||
searchFilter: entity => KubeObject.stringifyLabels(entity.metadata.labels),
|
searchFilter: entity => KubeObject.stringifyLabels(entity.metadata.labels),
|
||||||
},
|
},
|
||||||
@ -53,6 +55,7 @@ const defaultCategoryColumnsInjectable = getInjectable({
|
|||||||
className: styles.statusCell,
|
className: styles.statusCell,
|
||||||
id: "status",
|
id: "status",
|
||||||
sortBy: "status",
|
sortBy: "status",
|
||||||
|
"data-testid": "catalog-status-column",
|
||||||
},
|
},
|
||||||
searchFilter: entity => entity.status.phase,
|
searchFilter: entity => entity.status.phase,
|
||||||
sortCallback: entity => entity.status.phase,
|
sortCallback: entity => entity.status.phase,
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import type { TableCellProps } from "../table";
|
|||||||
export interface TitleCellProps {
|
export interface TitleCellProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
title: string;
|
title: string;
|
||||||
|
"data-testid"?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CategoryColumnRegistration {
|
export interface CategoryColumnRegistration {
|
||||||
|
|||||||
@ -1,102 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from "react";
|
|
||||||
import { screen } from "@testing-library/react";
|
|
||||||
import "@testing-library/jest-dom/extend-expect";
|
|
||||||
import { defaultWidth, Welcome } from "../welcome";
|
|
||||||
import { computed } from "mobx";
|
|
||||||
import { getDiForUnitTesting } from "../../../getDiForUnitTesting";
|
|
||||||
import type { DiRender } from "../../test-utils/renderFor";
|
|
||||||
import { renderFor } from "../../test-utils/renderFor";
|
|
||||||
import type { DiContainer } from "@ogre-tools/injectable";
|
|
||||||
import rendererExtensionsInjectable from "../../../../extensions/renderer-extensions.injectable";
|
|
||||||
import { LensRendererExtension } from "../../../../extensions/lens-renderer-extension";
|
|
||||||
import type { WelcomeBannerRegistration } from "../welcome-banner-items/welcome-banner-registration";
|
|
||||||
import currentlyInClusterFrameInjectable from "../../../routes/currently-in-cluster-frame.injectable";
|
|
||||||
|
|
||||||
describe("<Welcome/>", () => {
|
|
||||||
let render: DiRender;
|
|
||||||
let di: DiContainer;
|
|
||||||
let welcomeBannersStub: WelcomeBannerRegistration[];
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
di = getDiForUnitTesting();
|
|
||||||
|
|
||||||
di.override(currentlyInClusterFrameInjectable, () => false);
|
|
||||||
|
|
||||||
render = renderFor(di);
|
|
||||||
welcomeBannersStub = [];
|
|
||||||
|
|
||||||
di.override(rendererExtensionsInjectable, () =>
|
|
||||||
computed(() => [
|
|
||||||
new TestExtension({
|
|
||||||
id: "some-id",
|
|
||||||
welcomeBanners: welcomeBannersStub,
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("renders <Banner /> registered in WelcomeBannerRegistry and hide logo", async () => {
|
|
||||||
const testId = "testId";
|
|
||||||
|
|
||||||
welcomeBannersStub.push({
|
|
||||||
Banner: () => <div data-testid={testId} />,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { container } = render(<Welcome />);
|
|
||||||
|
|
||||||
expect(screen.queryByTestId(testId)).toBeInTheDocument();
|
|
||||||
expect(container.getElementsByClassName("logo").length).toBe(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("calculates max width from WelcomeBanner.width registered in WelcomeBannerRegistry", async () => {
|
|
||||||
welcomeBannersStub.push({
|
|
||||||
width: 100,
|
|
||||||
Banner: () => <div />,
|
|
||||||
});
|
|
||||||
|
|
||||||
welcomeBannersStub.push({
|
|
||||||
width: 800,
|
|
||||||
Banner: () => <div />,
|
|
||||||
});
|
|
||||||
|
|
||||||
render(<Welcome />);
|
|
||||||
|
|
||||||
expect(screen.queryByTestId("welcome-banner-container")).toHaveStyle({
|
|
||||||
// should take the max width of the banners (if > defaultWidth)
|
|
||||||
width: `800px`,
|
|
||||||
});
|
|
||||||
expect(screen.queryByTestId("welcome-text-container")).toHaveStyle({
|
|
||||||
width: `${defaultWidth}px`,
|
|
||||||
});
|
|
||||||
expect(screen.queryByTestId("welcome-menu-container")).toHaveStyle({
|
|
||||||
width: `${defaultWidth}px`,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
class TestExtension extends LensRendererExtension {
|
|
||||||
constructor({
|
|
||||||
id,
|
|
||||||
welcomeBanners,
|
|
||||||
}: {
|
|
||||||
id: string;
|
|
||||||
welcomeBanners: WelcomeBannerRegistration[];
|
|
||||||
}) {
|
|
||||||
super({
|
|
||||||
id,
|
|
||||||
absolutePath: "irrelevant",
|
|
||||||
isBundled: false,
|
|
||||||
isCompatible: false,
|
|
||||||
isEnabled: false,
|
|
||||||
manifest: { name: id, version: "some-version", engines: { lens: "^5.5.0" }},
|
|
||||||
manifestPath: "irrelevant",
|
|
||||||
});
|
|
||||||
|
|
||||||
this.welcomeBanners = welcomeBanners;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -71,7 +71,11 @@ const NonInjectedWelcome = observer(({
|
|||||||
))}
|
))}
|
||||||
</Carousel>
|
</Carousel>
|
||||||
) : (
|
) : (
|
||||||
<Icon svg="logo-lens" className="logo" />
|
<Icon
|
||||||
|
svg="logo-lens"
|
||||||
|
className="logo"
|
||||||
|
data-testid="no-welcome-banners-icon"
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import { getInjectionToken } from "@ogre-tools/injectable";
|
|||||||
import type { IComputedValue } from "mobx";
|
import type { IComputedValue } from "mobx";
|
||||||
import type React from "react";
|
import type React from "react";
|
||||||
|
|
||||||
interface WorkloadOverviewDetail {
|
export interface WorkloadOverviewDetail {
|
||||||
orderNumber: number;
|
orderNumber: number;
|
||||||
Component: React.ElementType<{}>;
|
Component: React.ElementType<{}>;
|
||||||
enabled: IComputedValue<boolean>;
|
enabled: IComputedValue<boolean>;
|
||||||
|
|||||||
@ -16,24 +16,12 @@ const workloadOverviewDetailRegistratorInjectable = getInjectable({
|
|||||||
instantiate: (di) => {
|
instantiate: (di) => {
|
||||||
const getRandomId = di.inject(getRandomIdInjectable);
|
const getRandomId = di.inject(getRandomIdInjectable);
|
||||||
|
|
||||||
const getExtensionShouldBeEnabledForClusterFrame = (
|
|
||||||
extension: LensRendererExtension,
|
|
||||||
) =>
|
|
||||||
di.inject(extensionShouldBeEnabledForClusterFrameInjectable, extension);
|
|
||||||
|
|
||||||
return (ext) => {
|
return (ext) => {
|
||||||
const extension = ext as LensRendererExtension;
|
const extension = ext as LensRendererExtension;
|
||||||
|
const extensionShouldBeEnabledForClusterFrame = di.inject(extensionShouldBeEnabledForClusterFrameInjectable, extension);
|
||||||
|
|
||||||
const extensionShouldBeEnabledForClusterFrame =
|
return extension.kubeWorkloadsOverviewItems.map((registration) => getInjectable({
|
||||||
getExtensionShouldBeEnabledForClusterFrame(extension);
|
id: `workload-overview-detail-from-${extension.sanitizedExtensionId}-${getRandomId()}`,
|
||||||
|
|
||||||
return extension.kubeWorkloadsOverviewItems.map((registration) => {
|
|
||||||
const id = `workload-overview-detail-from-${
|
|
||||||
extension.sanitizedExtensionId
|
|
||||||
}-${getRandomId()}`;
|
|
||||||
|
|
||||||
return getInjectable({
|
|
||||||
id,
|
|
||||||
|
|
||||||
instantiate: () => ({
|
instantiate: () => ({
|
||||||
Component: registration.components.Details,
|
Component: registration.components.Details,
|
||||||
@ -46,13 +34,11 @@ const workloadOverviewDetailRegistratorInjectable = getInjectable({
|
|||||||
return registration.visible ? registration.visible.get() : true;
|
return registration.visible ? registration.visible.get() : true;
|
||||||
}),
|
}),
|
||||||
|
|
||||||
orderNumber:
|
orderNumber: 0.5 + (registration.priority ? 100 - registration.priority : 50),
|
||||||
0.5 + (registration.priority ? 100 - registration.priority : 50),
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
injectionToken: workloadOverviewDetailInjectionToken,
|
injectionToken: workloadOverviewDetailInjectionToken,
|
||||||
});
|
}));
|
||||||
});
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,6 @@ import { HotbarMenu } from "../hotbar/hotbar-menu";
|
|||||||
import { DeleteClusterDialog } from "../delete-cluster-dialog";
|
import { DeleteClusterDialog } from "../delete-cluster-dialog";
|
||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
import { TopBar } from "../layout/top-bar/top-bar";
|
import { TopBar } from "../layout/top-bar/top-bar";
|
||||||
import catalogPreviousActiveTabStorageInjectable from "../+catalog/catalog-previous-active-tab-storage/catalog-previous-active-tab-storage.injectable";
|
|
||||||
import type { IComputedValue } from "mobx";
|
import type { IComputedValue } from "mobx";
|
||||||
import currentRouteComponentInjectable from "../../routes/current-route-component.injectable";
|
import currentRouteComponentInjectable from "../../routes/current-route-component.injectable";
|
||||||
import welcomeRouteInjectable from "../../../common/front-end-routing/routes/welcome/welcome-route.injectable";
|
import welcomeRouteInjectable from "../../../common/front-end-routing/routes/welcome/welcome-route.injectable";
|
||||||
@ -21,10 +20,8 @@ import { buildURL } from "@k8slens/utilities";
|
|||||||
import type { WatchForGeneralEntityNavigation } from "../../api/helpers/watch-for-general-entity-navigation.injectable";
|
import type { WatchForGeneralEntityNavigation } from "../../api/helpers/watch-for-general-entity-navigation.injectable";
|
||||||
import watchForGeneralEntityNavigationInjectable from "../../api/helpers/watch-for-general-entity-navigation.injectable";
|
import watchForGeneralEntityNavigationInjectable from "../../api/helpers/watch-for-general-entity-navigation.injectable";
|
||||||
import currentPathInjectable from "../../routes/current-path.injectable";
|
import currentPathInjectable from "../../routes/current-path.injectable";
|
||||||
import type { StorageLayer } from "../../utils/storage-helper";
|
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
catalogPreviousActiveTabStorage: StorageLayer<string | null>;
|
|
||||||
currentRouteComponent: IComputedValue<React.ElementType | undefined>;
|
currentRouteComponent: IComputedValue<React.ElementType | undefined>;
|
||||||
welcomeUrl: string;
|
welcomeUrl: string;
|
||||||
watchForGeneralEntityNavigation: WatchForGeneralEntityNavigation;
|
watchForGeneralEntityNavigation: WatchForGeneralEntityNavigation;
|
||||||
@ -84,7 +81,6 @@ class NonInjectedClusterManager extends React.Component<Dependencies> {
|
|||||||
|
|
||||||
export const ClusterManager = withInjectables<Dependencies>(NonInjectedClusterManager, {
|
export const ClusterManager = withInjectables<Dependencies>(NonInjectedClusterManager, {
|
||||||
getProps: (di) => ({
|
getProps: (di) => ({
|
||||||
catalogPreviousActiveTabStorage: di.inject(catalogPreviousActiveTabStorageInjectable),
|
|
||||||
currentRouteComponent: di.inject(currentRouteComponentInjectable),
|
currentRouteComponent: di.inject(currentRouteComponentInjectable),
|
||||||
welcomeUrl: buildURL(di.inject(welcomeRouteInjectable).path),
|
welcomeUrl: buildURL(di.inject(welcomeRouteInjectable).path),
|
||||||
watchForGeneralEntityNavigation: di.inject(watchForGeneralEntityNavigationInjectable),
|
watchForGeneralEntityNavigation: di.inject(watchForGeneralEntityNavigationInjectable),
|
||||||
|
|||||||
@ -20,6 +20,9 @@
|
|||||||
|
|
||||||
$baseline: 8px;
|
$baseline: 8px;
|
||||||
|
|
||||||
|
@include horizontalLineSize('xxs', 0.5 * $baseline);
|
||||||
|
@include horizontalLineSize('xs', 1 * $baseline);
|
||||||
@include horizontalLineSize('sm', 2 * $baseline);
|
@include horizontalLineSize('sm', 2 * $baseline);
|
||||||
@include horizontalLineSize('md', 3 * $baseline);
|
@include horizontalLineSize('md', 3 * $baseline);
|
||||||
|
@include horizontalLineSize('lg', 4 * $baseline);
|
||||||
@include horizontalLineSize('xl', 5 * $baseline);
|
@include horizontalLineSize('xl', 5 * $baseline);
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import styles from "./horizontal-line.module.scss";
|
|||||||
import { cssNames } from "@k8slens/utilities";
|
import { cssNames } from "@k8slens/utilities";
|
||||||
|
|
||||||
interface HorizontalLineProps {
|
interface HorizontalLineProps {
|
||||||
size?: "sm" | "md" | "xl";
|
size?: "xxs" | "xs" | "sm" | "md" | "lg" | "xl";
|
||||||
}
|
}
|
||||||
|
|
||||||
export const HorizontalLine = ({ size = "xl" }: HorizontalLineProps = { size: "xl" }) => {
|
export const HorizontalLine = ({ size = "xl" }: HorizontalLineProps = { size: "xl" }) => {
|
||||||
|
|||||||
@ -25,6 +25,8 @@ import createEditResourceTabInjectable from "../dock/edit-resource/edit-resource
|
|||||||
import hideDetailsInjectable from "../kube-detail-params/hide-details.injectable";
|
import hideDetailsInjectable from "../kube-detail-params/hide-details.injectable";
|
||||||
import { kubeObjectMenuItemInjectionToken } from "./kube-object-menu-item-injection-token";
|
import { kubeObjectMenuItemInjectionToken } from "./kube-object-menu-item-injection-token";
|
||||||
import activeEntityInternalClusterInjectable from "../../api/catalog/entity/get-active-cluster-entity.injectable";
|
import activeEntityInternalClusterInjectable from "../../api/catalog/entity/get-active-cluster-entity.injectable";
|
||||||
|
import directoryForTempInjectable from "../../../common/app-paths/directory-for-temp/directory-for-temp.injectable";
|
||||||
|
import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||||
|
|
||||||
// TODO: make `animated={false}` not required to make tests deterministic
|
// TODO: make `animated={false}` not required to make tests deterministic
|
||||||
describe("kube-object-menu", () => {
|
describe("kube-object-menu", () => {
|
||||||
@ -34,6 +36,9 @@ describe("kube-object-menu", () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
di = getDiForUnitTesting();
|
di = getDiForUnitTesting();
|
||||||
|
|
||||||
|
di.override(directoryForUserDataInjectable, () => "/some-directory-for-user-data");
|
||||||
|
di.override(directoryForTempInjectable, () => "/some-directory-for-temp");
|
||||||
|
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
di.register(
|
di.register(
|
||||||
someMenuItemInjectable,
|
someMenuItemInjectable,
|
||||||
|
|||||||
@ -1,235 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from "react";
|
|
||||||
import "@testing-library/jest-dom/extend-expect";
|
|
||||||
import { screen, waitFor } from "@testing-library/react";
|
|
||||||
import { ScrollSpy } from "../scroll-spy";
|
|
||||||
import { RecursiveTreeView } from "../../tree-view";
|
|
||||||
import { getDiForUnitTesting } from "../../../getDiForUnitTesting";
|
|
||||||
import { type DiRender, renderFor } from "../../test-utils/renderFor";
|
|
||||||
|
|
||||||
const observe = jest.fn();
|
|
||||||
|
|
||||||
Object.defineProperty(window, "IntersectionObserver", {
|
|
||||||
writable: true,
|
|
||||||
value: jest.fn().mockImplementation(() => ({
|
|
||||||
observe,
|
|
||||||
unobserve: jest.fn(),
|
|
||||||
})),
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("<ScrollSpy/>", () => {
|
|
||||||
let render: DiRender;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
const di = getDiForUnitTesting();
|
|
||||||
|
|
||||||
render = renderFor(di);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("renders w/o errors", () => {
|
|
||||||
const { container } = render((
|
|
||||||
<ScrollSpy
|
|
||||||
render={() => (
|
|
||||||
<div>
|
|
||||||
<section id="application">
|
|
||||||
<h1>Application</h1>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
));
|
|
||||||
|
|
||||||
expect(container).toBeInstanceOf(HTMLElement);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("calls intersection observer", () => {
|
|
||||||
render((
|
|
||||||
<ScrollSpy
|
|
||||||
render={() => (
|
|
||||||
<div>
|
|
||||||
<section id="application">
|
|
||||||
<h1>Application</h1>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
));
|
|
||||||
|
|
||||||
expect(observe).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("renders dataTree component", async () => {
|
|
||||||
render((
|
|
||||||
<ScrollSpy
|
|
||||||
render={dataTree => (
|
|
||||||
<div>
|
|
||||||
<nav>
|
|
||||||
<RecursiveTreeView data={dataTree}/>
|
|
||||||
</nav>
|
|
||||||
<section id="application">
|
|
||||||
<h1>Application</h1>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
));
|
|
||||||
|
|
||||||
expect(await screen.findByTestId("TreeView")).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("throws if no sections founded", () => {
|
|
||||||
// Prevent writing to stderr during this render.
|
|
||||||
const err = console.error;
|
|
||||||
|
|
||||||
console.error = jest.fn();
|
|
||||||
|
|
||||||
expect(() => render((
|
|
||||||
<ScrollSpy
|
|
||||||
render={() => (
|
|
||||||
<div>
|
|
||||||
Content
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
))).toThrow();
|
|
||||||
|
|
||||||
// Restore writing to stderr.
|
|
||||||
console.error = err;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
describe("<TreeView/> dataTree inside <ScrollSpy/>", () => {
|
|
||||||
let render: DiRender;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
const di = getDiForUnitTesting();
|
|
||||||
|
|
||||||
render = renderFor(di);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("contains links to all sections", async () => {
|
|
||||||
render((
|
|
||||||
<ScrollSpy
|
|
||||||
render={dataTree => (
|
|
||||||
<div>
|
|
||||||
<nav>
|
|
||||||
<RecursiveTreeView data={dataTree}/>
|
|
||||||
</nav>
|
|
||||||
<section id="application">
|
|
||||||
<h1>Application</h1>
|
|
||||||
<section id="appearance">
|
|
||||||
<h2>Appearance</h2>
|
|
||||||
</section>
|
|
||||||
<section id="theme">
|
|
||||||
<h2>Theme</h2>
|
|
||||||
<div>description</div>
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
));
|
|
||||||
|
|
||||||
expect(await screen.findByTitle("Application")).toBeInTheDocument();
|
|
||||||
expect(await screen.findByTitle("Appearance")).toBeInTheDocument();
|
|
||||||
expect(await screen.findByTitle("Theme")).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("not showing links to sections without id", async () => {
|
|
||||||
const { queryByTitle } = render((
|
|
||||||
<ScrollSpy
|
|
||||||
render={dataTree => (
|
|
||||||
<div>
|
|
||||||
<nav>
|
|
||||||
<RecursiveTreeView data={dataTree}/>
|
|
||||||
</nav>
|
|
||||||
<section id="application">
|
|
||||||
<h1>Application</h1>
|
|
||||||
<section>
|
|
||||||
<h2>Kubectl</h2>
|
|
||||||
</section>
|
|
||||||
<section id="appearance">
|
|
||||||
<h2>Appearance</h2>
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
));
|
|
||||||
|
|
||||||
expect(await screen.findByTitle("Application")).toBeInTheDocument();
|
|
||||||
expect(await screen.findByTitle("Appearance")).toBeInTheDocument();
|
|
||||||
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(queryByTitle("Kubectl")).not.toBeInTheDocument();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("expands parent sections", async () => {
|
|
||||||
render((
|
|
||||||
<ScrollSpy
|
|
||||||
render={dataTree => (
|
|
||||||
<div>
|
|
||||||
<nav>
|
|
||||||
<RecursiveTreeView data={dataTree}/>
|
|
||||||
</nav>
|
|
||||||
<section id="application">
|
|
||||||
<h1>Application</h1>
|
|
||||||
<section id="appearance">
|
|
||||||
<h2>Appearance</h2>
|
|
||||||
</section>
|
|
||||||
<section id="theme">
|
|
||||||
<h2>Theme</h2>
|
|
||||||
<div>description</div>
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
<section id="Kubernetes">
|
|
||||||
<h1>Kubernetes</h1>
|
|
||||||
<section id="kubectl">
|
|
||||||
<h2>Kubectl</h2>
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
));
|
|
||||||
|
|
||||||
expect(await screen.findByTitle("Application")).toHaveAttribute("aria-expanded");
|
|
||||||
expect(await screen.findByTitle("Kubernetes")).toHaveAttribute("aria-expanded");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("skips sections without headings", async () => {
|
|
||||||
render((
|
|
||||||
<ScrollSpy
|
|
||||||
render={dataTree => (
|
|
||||||
<div>
|
|
||||||
<nav>
|
|
||||||
<RecursiveTreeView data={dataTree}/>
|
|
||||||
</nav>
|
|
||||||
<section id="application">
|
|
||||||
<h1>Application</h1>
|
|
||||||
<section id="appearance">
|
|
||||||
<p>Appearance</p>
|
|
||||||
</section>
|
|
||||||
<section id="theme">
|
|
||||||
<h2>Theme</h2>
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
));
|
|
||||||
|
|
||||||
expect(await screen.findByTitle("Application")).toBeInTheDocument();
|
|
||||||
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(screen.queryByTitle("appearance")).not.toBeInTheDocument();
|
|
||||||
expect(screen.queryByTitle("Appearance")).not.toBeInTheDocument();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -6,7 +6,14 @@
|
|||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import React, { useEffect, useRef, useState } from "react";
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
import { useMutationObserver } from "../../hooks";
|
import { useMutationObserver } from "../../hooks";
|
||||||
import type { NavigationTree } from "../tree-view";
|
|
||||||
|
export interface NavigationTree {
|
||||||
|
id: string;
|
||||||
|
parentId?: string;
|
||||||
|
name: string;
|
||||||
|
selected?: boolean;
|
||||||
|
children?: NavigationTree[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface ScrollSpyProps extends React.DOMAttributes<HTMLElement> {
|
export interface ScrollSpyProps extends React.DOMAttributes<HTMLElement> {
|
||||||
render: (data: NavigationTree[]) => JSX.Element;
|
render: (data: NavigationTree[]) => JSX.Element;
|
||||||
|
|||||||
@ -71,6 +71,11 @@ export interface TableCellProps extends React.DOMAttributes<HTMLDivElement> {
|
|||||||
* indicator, might come from parent <TableHead>, don't use this prop outside (!)
|
* indicator, might come from parent <TableHead>, don't use this prop outside (!)
|
||||||
*/
|
*/
|
||||||
_nowrap?: boolean;
|
_nowrap?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For passing in the testid
|
||||||
|
*/
|
||||||
|
"data-testid"?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TableCell extends React.Component<TableCellProps> {
|
export class TableCell extends React.Component<TableCellProps> {
|
||||||
|
|||||||
@ -55,7 +55,7 @@ export interface TabProps<D> extends DOMAttributes<HTMLElement> {
|
|||||||
className?: string;
|
className?: string;
|
||||||
active?: boolean;
|
active?: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
icon?: React.ReactNode | string; // material-ui name or custom icon
|
icon?: React.ReactNode | string; // material-io name or custom icon
|
||||||
label?: React.ReactNode;
|
label?: React.ReactNode;
|
||||||
value: D;
|
value: D;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -53,7 +53,7 @@ import { applicationWindowInjectionToken } from "../../../main/start-main-applic
|
|||||||
import closeAllWindowsInjectable from "../../../main/start-main-application/lens-window/hide-all-windows/close-all-windows.injectable";
|
import closeAllWindowsInjectable from "../../../main/start-main-application/lens-window/hide-all-windows/close-all-windows.injectable";
|
||||||
import type { LensWindow } from "../../../main/start-main-application/lens-window/application-window/create-lens-window.injectable";
|
import type { LensWindow } from "../../../main/start-main-application/lens-window/application-window/create-lens-window.injectable";
|
||||||
import type { FakeExtensionOptions } from "./get-extension-fake";
|
import type { FakeExtensionOptions } from "./get-extension-fake";
|
||||||
import { getMainExtensionFakeWith, getRendererExtensionFakeWith } from "./get-extension-fake";
|
import { getExtensionFakeForMain, getExtensionFakeForRenderer } from "./get-extension-fake";
|
||||||
import namespaceApiInjectable from "../../../common/k8s-api/endpoints/namespace.api.injectable";
|
import namespaceApiInjectable from "../../../common/k8s-api/endpoints/namespace.api.injectable";
|
||||||
import { Namespace } from "../../../common/k8s-api/endpoints";
|
import { Namespace } from "../../../common/k8s-api/endpoints";
|
||||||
import { getOverrideFsWithFakes } from "../../../test-utils/override-fs-with-fakes";
|
import { getOverrideFsWithFakes } from "../../../test-utils/override-fs-with-fakes";
|
||||||
@ -594,13 +594,13 @@ export const getApplicationBuilder = () => {
|
|||||||
enable: (...extensions) => {
|
enable: (...extensions) => {
|
||||||
builder.afterWindowStart(action(({ windowDi }) => {
|
builder.afterWindowStart(action(({ windowDi }) => {
|
||||||
extensions
|
extensions
|
||||||
.map(getRendererExtensionFakeWith(windowDi))
|
.map(getExtensionFakeForRenderer)
|
||||||
.forEach(enableExtensionFor(windowDi, rendererExtensionsStateInjectable));
|
.forEach(enableExtensionFor(windowDi, rendererExtensionsStateInjectable));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
builder.afterApplicationStart(action(({ mainDi }) => {
|
builder.afterApplicationStart(action(({ mainDi }) => {
|
||||||
extensions
|
extensions
|
||||||
.map(getMainExtensionFakeWith(mainDi))
|
.map(getExtensionFakeForMain)
|
||||||
.forEach(enableExtensionFor(mainDi, mainExtensionsStateInjectable));
|
.forEach(enableExtensionFor(mainDi, mainExtensionsStateInjectable));
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|||||||
@ -2,20 +2,8 @@
|
|||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
import type { Writable } from "type-fest";
|
|
||||||
import { lensExtensionDependencies } from "../../../extensions/lens-extension";
|
|
||||||
import { LensMainExtension } from "../../../extensions/lens-main-extension";
|
import { LensMainExtension } from "../../../extensions/lens-main-extension";
|
||||||
import navigateForExtensionInjectable from "../../../main/start-main-application/lens-window/navigate-for-extension.injectable";
|
|
||||||
import { LensRendererExtension } from "../../../extensions/lens-renderer-extension";
|
import { LensRendererExtension } from "../../../extensions/lens-renderer-extension";
|
||||||
import catalogCategoryRegistryInjectable from "../../../common/catalog/category-registry.injectable";
|
|
||||||
import getExtensionPageParametersInjectable from "../../routes/get-extension-page-parameters.injectable";
|
|
||||||
import navigateToRouteInjectable from "../../routes/navigate-to-route.injectable";
|
|
||||||
import routesInjectable from "../../routes/routes.injectable";
|
|
||||||
import catalogEntityRegistryForMainInjectable from "../../../main/catalog/entity-registry.injectable";
|
|
||||||
import catalogEntityRegistryForRendererInjectable from "../../api/catalog/entity/registry.injectable";
|
|
||||||
import type { DiContainer } from "@ogre-tools/injectable";
|
|
||||||
import loggerInjectable from "../../../common/logger.injectable";
|
|
||||||
import ensureHashedDirectoryForExtensionInjectable from "../../../extensions/extension-loader/file-system-provisioner-store/ensure-hashed-directory-for-extension.injectable";
|
|
||||||
|
|
||||||
export class TestExtensionMain extends LensMainExtension {}
|
export class TestExtensionMain extends LensMainExtension {}
|
||||||
export class TestExtensionRenderer extends LensRendererExtension {}
|
export class TestExtensionRenderer extends LensRendererExtension {}
|
||||||
@ -27,8 +15,9 @@ export interface FakeExtensionOptions {
|
|||||||
mainOptions?: Partial<LensMainExtension>;
|
mainOptions?: Partial<LensMainExtension>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getMainExtensionFakeWith = (di: DiContainer) => ({ id, name, mainOptions = {}}: FakeExtensionOptions) => {
|
export const getExtensionFakeForMain = ({ id, name, mainOptions = {}}: FakeExtensionOptions) => (
|
||||||
const instance = new TestExtensionMain({
|
Object.assign(
|
||||||
|
new TestExtensionMain({
|
||||||
id,
|
id,
|
||||||
absolutePath: "irrelevant",
|
absolutePath: "irrelevant",
|
||||||
isBundled: false,
|
isBundled: false,
|
||||||
@ -42,22 +31,14 @@ export const getMainExtensionFakeWith = (di: DiContainer) => ({ id, name, mainOp
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
manifestPath: "irrelevant",
|
manifestPath: "irrelevant",
|
||||||
});
|
}),
|
||||||
|
mainOptions,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
Object.assign(instance, mainOptions);
|
export const getExtensionFakeForRenderer = ({ id, name, rendererOptions = {}}: FakeExtensionOptions) => (
|
||||||
|
Object.assign(
|
||||||
(instance as Writable<LensMainExtension>)[lensExtensionDependencies] = {
|
new TestExtensionRenderer({
|
||||||
ensureHashedDirectoryForExtension: di.inject(ensureHashedDirectoryForExtensionInjectable),
|
|
||||||
entityRegistry: di.inject(catalogEntityRegistryForMainInjectable),
|
|
||||||
navigate: di.inject(navigateForExtensionInjectable),
|
|
||||||
logger: di.inject(loggerInjectable),
|
|
||||||
};
|
|
||||||
|
|
||||||
return instance;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getRendererExtensionFakeWith = (di: DiContainer) => ({ id, name, rendererOptions = {}}: FakeExtensionOptions) => {
|
|
||||||
const instance = new TestExtensionRenderer({
|
|
||||||
id,
|
id,
|
||||||
absolutePath: "irrelevant",
|
absolutePath: "irrelevant",
|
||||||
isBundled: false,
|
isBundled: false,
|
||||||
@ -71,19 +52,7 @@ export const getRendererExtensionFakeWith = (di: DiContainer) => ({ id, name, re
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
manifestPath: "irrelevant",
|
manifestPath: "irrelevant",
|
||||||
});
|
}),
|
||||||
|
rendererOptions,
|
||||||
Object.assign(instance, rendererOptions);
|
)
|
||||||
|
);
|
||||||
(instance as Writable<LensRendererExtension>)[lensExtensionDependencies] = {
|
|
||||||
categoryRegistry: di.inject(catalogCategoryRegistryInjectable),
|
|
||||||
entityRegistry: di.inject(catalogEntityRegistryForRendererInjectable),
|
|
||||||
ensureHashedDirectoryForExtension: di.inject(ensureHashedDirectoryForExtensionInjectable),
|
|
||||||
getExtensionPageParameters: di.inject(getExtensionPageParametersInjectable),
|
|
||||||
navigateToRoute: di.inject(navigateToRouteInjectable),
|
|
||||||
routes: di.inject(routesInjectable),
|
|
||||||
logger: di.inject(loggerInjectable),
|
|
||||||
};
|
|
||||||
|
|
||||||
return instance;
|
|
||||||
};
|
|
||||||
|
|||||||
@ -1,6 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export * from "./tree-view";
|
|
||||||
@ -0,0 +1,63 @@
|
|||||||
|
.treeItem {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
padding: 2px var(--padding) 2px 0;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--sidebarItemHoverBackground);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selected:hover {
|
||||||
|
background-color: var(--blue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected {
|
||||||
|
background-color: var(--blue);
|
||||||
|
color: white;
|
||||||
|
border-radius: 2px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.treeGroup {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contents {
|
||||||
|
padding-left: 25px;
|
||||||
|
transition: all 300ms ease;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&.expanded {
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.expanded) {
|
||||||
|
max-height: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected {
|
||||||
|
color: white;
|
||||||
|
background-color: var(--blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconContainer {
|
||||||
|
align-self: flex-start;
|
||||||
|
width: 21px;
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.treeView {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
@ -1,32 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
.TreeView {
|
|
||||||
.MuiTypography-body1 {
|
|
||||||
font-size: var(--font-size);
|
|
||||||
color: var(--textColorAccent);
|
|
||||||
}
|
|
||||||
|
|
||||||
.MuiTreeItem-root {
|
|
||||||
> .MuiTreeItem-content .MuiTreeItem-label {
|
|
||||||
border-radius: 4px;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.selected {
|
|
||||||
> .MuiTreeItem-content .MuiTreeItem-label {
|
|
||||||
border-color: var(--blue);
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make inner component selected state invisible
|
|
||||||
&.Mui-selected, &.Mui-selected:focus {
|
|
||||||
> .MuiTreeItem-content .MuiTreeItem-label {
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -3,103 +3,153 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import "./tree-view.scss";
|
import styles from "./tree-view.module.scss";
|
||||||
|
import type { MouseEventHandler } from "react";
|
||||||
import React, { useEffect, useRef } from "react";
|
import React, { useState } from "react";
|
||||||
import { Icon } from "../icon";
|
|
||||||
import TreeView from "@material-ui/lab/TreeView";
|
|
||||||
import TreeItem from "@material-ui/lab/TreeItem";
|
|
||||||
import { cssNames } from "@k8slens/utilities";
|
import { cssNames } from "@k8slens/utilities";
|
||||||
|
import { Icon } from "../icon";
|
||||||
|
|
||||||
import _ from "lodash";
|
export interface TreeViewClasses {
|
||||||
import getDeepDash from "deepdash";
|
root?: string;
|
||||||
|
|
||||||
const deepDash = getDeepDash(_);
|
|
||||||
|
|
||||||
export interface NavigationTree {
|
|
||||||
id: string;
|
|
||||||
parentId?: string;
|
|
||||||
name: string;
|
|
||||||
selected?: boolean;
|
|
||||||
children?: NavigationTree[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RecursiveTreeViewProps {
|
export interface TreeViewProps {
|
||||||
data: NavigationTree[];
|
classes?: TreeViewClasses;
|
||||||
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
function scrollToItem(id: string) {
|
export function TreeView(props: TreeViewProps) {
|
||||||
document.getElementById(id)?.scrollIntoView();
|
const {
|
||||||
}
|
children,
|
||||||
|
classes = {},
|
||||||
|
} = props;
|
||||||
|
|
||||||
function getSelectedNode(data: NavigationTree[]) {
|
return (
|
||||||
return deepDash.findDeep(data, (value, key) => key === "selected" && value === true)?.parent;
|
<ul
|
||||||
}
|
className={cssNames(classes.root, styles.treeView)}
|
||||||
|
role="tree"
|
||||||
export function RecursiveTreeView({ data }: RecursiveTreeViewProps) {
|
|
||||||
const [expanded, setExpanded] = React.useState<string[]>([]);
|
|
||||||
const prevData = useRef<NavigationTree[]>(data);
|
|
||||||
|
|
||||||
const handleToggle = (event: React.ChangeEvent<{}>, nodeIds: string[]) => {
|
|
||||||
setExpanded(nodeIds);
|
|
||||||
};
|
|
||||||
|
|
||||||
const expandTopLevelNodes = () => {
|
|
||||||
setExpanded(data.map(node => node.id));
|
|
||||||
};
|
|
||||||
|
|
||||||
const expandParentNode = () => {
|
|
||||||
const node = getSelectedNode(data) as any as NavigationTree;
|
|
||||||
const id = node?.parentId;
|
|
||||||
|
|
||||||
if (id && !expanded.includes(id)) {
|
|
||||||
setExpanded([...expanded, id]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onLabelClick = (event: React.MouseEvent, nodeId: string) => {
|
|
||||||
event.preventDefault();
|
|
||||||
scrollToItem(nodeId);
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderTree = (nodes: NavigationTree[]) => {
|
|
||||||
return nodes.map(node => (
|
|
||||||
<TreeItem
|
|
||||||
key={node.id}
|
|
||||||
nodeId={node.id}
|
|
||||||
label={node.name}
|
|
||||||
onLabelClick={(event) => onLabelClick(event, node.id)}
|
|
||||||
className={cssNames({ selected: node.selected })}
|
|
||||||
title={node.name}
|
|
||||||
>
|
>
|
||||||
{Array.isArray(node.children) ? node.children.map((node) => renderTree([node])) : null}
|
{children}
|
||||||
</TreeItem>
|
</ul>
|
||||||
));
|
);
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!prevData.current.length) {
|
|
||||||
expandTopLevelNodes();
|
|
||||||
} else {
|
|
||||||
expandParentNode();
|
|
||||||
}
|
}
|
||||||
prevData.current = data;
|
|
||||||
}, [data]);
|
|
||||||
|
|
||||||
if (!data.length) {
|
export interface TreeItemClasses {
|
||||||
return null;
|
root?: string;
|
||||||
|
label?: string;
|
||||||
|
selected?: string;
|
||||||
|
hover?: string;
|
||||||
|
iconContainer?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TreeItemProps {
|
||||||
|
classes?: TreeItemClasses;
|
||||||
|
icon?: JSX.Element;
|
||||||
|
label: JSX.Element | string;
|
||||||
|
"data-testid"?: string;
|
||||||
|
selected?: boolean;
|
||||||
|
onClick?: MouseEventHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function TreeItem(props: TreeItemProps) {
|
||||||
|
const {
|
||||||
|
label,
|
||||||
|
"data-testid": dataTestId,
|
||||||
|
classes = {},
|
||||||
|
icon,
|
||||||
|
onClick,
|
||||||
|
selected = false,
|
||||||
|
} = props;
|
||||||
|
const [hovering, setHovering] = useState(false);
|
||||||
|
const optionalCssNames: Partial<Record<string, any>> = {};
|
||||||
|
|
||||||
|
if (classes.selected) {
|
||||||
|
optionalCssNames[classes.selected] = selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (classes.hover) {
|
||||||
|
optionalCssNames[classes.hover] = hovering;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TreeView
|
<li
|
||||||
data-testid="TreeView"
|
className={cssNames(classes.root, optionalCssNames, styles.treeItem, {
|
||||||
className="TreeView"
|
[styles.selected]: selected,
|
||||||
expanded={expanded}
|
})}
|
||||||
onNodeToggle={handleToggle}
|
role="treeitem"
|
||||||
defaultCollapseIcon={<Icon material="expand_more"/>}
|
data-testid={dataTestId}
|
||||||
defaultExpandIcon={<Icon material="chevron_right" />}
|
onClick={onClick}
|
||||||
|
onMouseOver={() => setHovering(true)}
|
||||||
|
onMouseLeave={() => setHovering(false)}
|
||||||
>
|
>
|
||||||
{renderTree(data)}
|
<div className={cssNames(classes.iconContainer, styles.iconContainer)}>
|
||||||
</TreeView>
|
{icon}
|
||||||
|
</div>
|
||||||
|
<div className={classes.label}>
|
||||||
|
{label}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TreeGroupClasses {
|
||||||
|
root?: string;
|
||||||
|
group?: string;
|
||||||
|
iconContainer?: string;
|
||||||
|
label?: string;
|
||||||
|
contents?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TreeGroupProps {
|
||||||
|
classes?: TreeGroupClasses;
|
||||||
|
children?: JSX.Element[] | JSX.Element;
|
||||||
|
defaultExpanded?: boolean;
|
||||||
|
label: JSX.Element | string;
|
||||||
|
"data-testid"?: string;
|
||||||
|
collapseIcon?: JSX.Element;
|
||||||
|
expandIcon?: JSX.Element;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function TreeGroup(props: TreeGroupProps) {
|
||||||
|
const {
|
||||||
|
label,
|
||||||
|
"data-testid": dataTestId,
|
||||||
|
children,
|
||||||
|
classes = {},
|
||||||
|
collapseIcon,
|
||||||
|
defaultExpanded = true,
|
||||||
|
expandIcon,
|
||||||
|
} = props;
|
||||||
|
const [expanded, setExpanded] = useState(defaultExpanded);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
className={cssNames(classes.root, styles.treeGroup)}
|
||||||
|
role="group"
|
||||||
|
data-testid={dataTestId}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={cssNames(classes.group, styles.group)}
|
||||||
|
onClick={() => setExpanded(!expanded)}
|
||||||
|
>
|
||||||
|
<div className={cssNames(classes.iconContainer, styles.iconContainer)}>
|
||||||
|
{
|
||||||
|
expanded
|
||||||
|
? collapseIcon ?? <Icon material="expand_more" />
|
||||||
|
: expandIcon ?? <Icon material="chevron_right" />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div className={classes.label}>
|
||||||
|
{label}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ul
|
||||||
|
className={cssNames(classes.contents, styles.contents, {
|
||||||
|
[styles.expanded]: expanded,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,43 +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 type { Writable } from "type-fest";
|
|
||||||
import catalogCategoryRegistryInjectable from "../../common/catalog/category-registry.injectable";
|
|
||||||
import loggerInjectable from "../../common/logger.injectable";
|
|
||||||
import { createExtensionInstanceInjectionToken } from "../../extensions/extension-loader/create-extension-instance.token";
|
|
||||||
import ensureHashedDirectoryForExtensionInjectable from "../../extensions/extension-loader/file-system-provisioner-store/ensure-hashed-directory-for-extension.injectable";
|
|
||||||
import { lensExtensionDependencies } from "../../extensions/lens-extension";
|
|
||||||
import type { LensRendererExtensionDependencies } from "../../extensions/lens-extension-set-dependencies";
|
|
||||||
import type { LensRendererExtension } from "../../extensions/lens-renderer-extension";
|
|
||||||
import catalogEntityRegistryInjectable from "../api/catalog/entity/registry.injectable";
|
|
||||||
import getExtensionPageParametersInjectable from "../routes/get-extension-page-parameters.injectable";
|
|
||||||
import navigateToRouteInjectable from "../routes/navigate-to-route.injectable";
|
|
||||||
import routesInjectable from "../routes/routes.injectable";
|
|
||||||
|
|
||||||
const createExtensionInstanceInjectable = getInjectable({
|
|
||||||
id: "create-extension-instance",
|
|
||||||
instantiate: (di) => {
|
|
||||||
const deps: LensRendererExtensionDependencies = {
|
|
||||||
categoryRegistry: di.inject(catalogCategoryRegistryInjectable),
|
|
||||||
entityRegistry: di.inject(catalogEntityRegistryInjectable),
|
|
||||||
ensureHashedDirectoryForExtension: di.inject(ensureHashedDirectoryForExtensionInjectable),
|
|
||||||
getExtensionPageParameters: di.inject(getExtensionPageParametersInjectable),
|
|
||||||
navigateToRoute: di.inject(navigateToRouteInjectable),
|
|
||||||
routes: di.inject(routesInjectable),
|
|
||||||
logger: di.inject(loggerInjectable),
|
|
||||||
};
|
|
||||||
|
|
||||||
return (ExtensionClass, extension) => {
|
|
||||||
const instance = new ExtensionClass(extension as any) as LensRendererExtension;
|
|
||||||
|
|
||||||
(instance as Writable<LensRendererExtension>)[lensExtensionDependencies] = deps;
|
|
||||||
|
|
||||||
return instance;
|
|
||||||
};
|
|
||||||
},
|
|
||||||
injectionToken: createExtensionInstanceInjectionToken,
|
|
||||||
});
|
|
||||||
|
|
||||||
export default createExtensionInstanceInjectable;
|
|
||||||
@ -4,10 +4,12 @@ import type {
|
|||||||
BundledLensExtensionManifest,
|
BundledLensExtensionManifest,
|
||||||
} from "./lens-extension";
|
} from "./lens-extension";
|
||||||
|
|
||||||
|
export type BundledExtensionResult = BundledLensExtensionConstructor | null;
|
||||||
|
|
||||||
export interface BundledExtension {
|
export interface BundledExtension {
|
||||||
readonly manifest: BundledLensExtensionManifest;
|
readonly manifest: BundledLensExtensionManifest;
|
||||||
main: () => Promise<BundledLensExtensionConstructor | null>;
|
main: () => BundledExtensionResult | Promise<BundledExtensionResult>;
|
||||||
renderer: () => Promise<BundledLensExtensionConstructor | null>;
|
renderer: () => BundledExtensionResult | Promise<BundledExtensionResult>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const bundledExtensionInjectionToken =
|
export const bundledExtensionInjectionToken =
|
||||||
|
|||||||
@ -21,7 +21,6 @@
|
|||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"allowJs": false,
|
"allowJs": false,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
|
||||||
"importsNotUsedAsValues": "error",
|
"importsNotUsedAsValues": "error",
|
||||||
"traceResolution": false,
|
"traceResolution": false,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user