diff --git a/packages/extension/src/dashboard-extension.ts b/packages/extension/src/dashboard-extension.ts index 7ae8c35e..35f24dfc 100644 --- a/packages/extension/src/dashboard-extension.ts +++ b/packages/extension/src/dashboard-extension.ts @@ -17,7 +17,7 @@ ***********************************************************************/ import type { WebviewPanel, ExtensionContext, KubeconfigUpdateEvent } from '@podman-desktop/api'; -import { kubernetes, Uri, window } from '@podman-desktop/api'; +import { env, kubernetes, Uri, window } from '@podman-desktop/api'; import { RpcExtension } from '/@common/rpc/rpc'; @@ -26,9 +26,15 @@ import { ContextsManager } from './manager/contexts-manager'; import { existsSync } from 'node:fs'; import { KubeConfig } from '@kubernetes/client-node'; import { ContextsStatesDispatcher } from './manager/contexts-states-dispatcher'; +import { InversifyBinding } from './inject/inversify-binding'; +import type { Container } from 'inversify'; export class DashboardExtension { + #container: Container | undefined; + #inversifyBinding: InversifyBinding | undefined; + #extensionContext: ExtensionContext; + #contextsManager: ContextsManager; #contextsStatesDispatcher: ContextsStatesDispatcher; @@ -37,6 +43,8 @@ export class DashboardExtension { } async activate(): Promise { + const telemetryLogger = env.createTelemetryLogger(); + const panel = await this.createWebview(); // Register webview communication for this webview @@ -44,10 +52,12 @@ export class DashboardExtension { rpcExtension.init(); this.#extensionContext.subscriptions.push(rpcExtension); - this.#contextsManager = new ContextsManager(); - this.#contextsStatesDispatcher = new ContextsStatesDispatcher(this.#contextsManager, rpcExtension); - const now = performance.now(); + this.#inversifyBinding = new InversifyBinding(rpcExtension, this.extensionContext, telemetryLogger); + this.#container = await this.#inversifyBinding.initBindings(); + + this.#contextsManager = await this.#container.getAsync(ContextsManager); + this.#contextsStatesDispatcher = await this.#container.getAsync(ContextsStatesDispatcher); const afterFirst = performance.now(); diff --git a/packages/extension/src/inject/inversify-binding.ts b/packages/extension/src/inject/inversify-binding.ts new file mode 100644 index 00000000..8366f637 --- /dev/null +++ b/packages/extension/src/inject/inversify-binding.ts @@ -0,0 +1,64 @@ +/********************************************************************** + * Copyright (C) 2025 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ***********************************************************************/ + +import 'reflect-metadata'; + +import type { ExtensionContext as PodmanDesktopExtensionContext, TelemetryLogger } from '@podman-desktop/api'; +import { Container } from 'inversify'; + +import { ExtensionContextSymbol, TelemetryLoggerSymbol } from '/@/inject/symbol'; +import { RpcExtension } from '/@common/rpc/rpc'; +import { managersModule } from '/@/manager/_manager-module'; + +export class InversifyBinding { + #container: Container | undefined; + + readonly #rpcExtension: RpcExtension; + + readonly #extensionContext: PodmanDesktopExtensionContext; + + readonly #telemetryLogger: TelemetryLogger; + + constructor( + rpcExtension: RpcExtension, + extensionContext: PodmanDesktopExtensionContext, + telemetryLogger: TelemetryLogger, + ) { + this.#rpcExtension = rpcExtension; + this.#extensionContext = extensionContext; + this.#telemetryLogger = telemetryLogger; + } + + public async initBindings(): Promise { + this.#container = new Container(); + + this.#container.bind(RpcExtension).toConstantValue(this.#rpcExtension); + this.#container.bind(ExtensionContextSymbol).toConstantValue(this.#extensionContext); + this.#container.bind(TelemetryLoggerSymbol).toConstantValue(this.#telemetryLogger); + + await this.#container.load(managersModule); + + return this.#container; + } + + async dispose(): Promise { + if (this.#container) { + await this.#container.unbindAll(); + } + } +} diff --git a/packages/extension/src/inject/symbol.ts b/packages/extension/src/inject/symbol.ts new file mode 100644 index 00000000..2dde73b0 --- /dev/null +++ b/packages/extension/src/inject/symbol.ts @@ -0,0 +1,21 @@ +/********************************************************************** + * Copyright (C) 2025 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ***********************************************************************/ + +export const ExtensionContextSymbol = Symbol.for('ExtensionContext'); + +export const TelemetryLoggerSymbol = Symbol.for('TelemetryLogger'); diff --git a/packages/extension/src/manager/_manager-module.ts b/packages/extension/src/manager/_manager-module.ts new file mode 100644 index 00000000..2dce1419 --- /dev/null +++ b/packages/extension/src/manager/_manager-module.ts @@ -0,0 +1,29 @@ +/********************************************************************** + * Copyright (C) 2025 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ***********************************************************************/ + +import { ContainerModule } from 'inversify'; + +import { ContextsManager } from './contexts-manager'; +import { ContextsStatesDispatcher } from './contexts-states-dispatcher'; + +const managersModule = new ContainerModule(options => { + options.bind(ContextsManager).toSelf().inSingletonScope(); + options.bind(ContextsStatesDispatcher).toSelf().inSingletonScope(); +}); + +export { managersModule }; diff --git a/packages/extension/src/manager/contexts-manager.ts b/packages/extension/src/manager/contexts-manager.ts index 8e124694..8eb835d6 100644 --- a/packages/extension/src/manager/contexts-manager.ts +++ b/packages/extension/src/manager/contexts-manager.ts @@ -48,6 +48,7 @@ import type { CacheUpdatedEvent, OfflineEvent, ResourceInformer } from '/@/types import { RoutesResourceFactory } from '/@/resources/routes-resource-factory.js'; import { SecretsResourceFactory } from '/@/resources/secrets-resource-factory.js'; import { ServicesResourceFactory } from '/@/resources/services-resource-factory.js'; +import { injectable } from 'inversify'; const HEALTH_CHECK_TIMEOUT_MS = 5_000; @@ -59,6 +60,7 @@ const HEALTH_CHECK_TIMEOUT_MS = 5_000; * * ContextsManager exposes the current state of the health checkers, permission checkers and informers. */ +@injectable() export class ContextsManager { #resourceFactoryHandler: ResourceFactoryHandler; #dispatcher: ContextsDispatcher; diff --git a/packages/extension/src/manager/contexts-states-dispatcher.spec.ts b/packages/extension/src/manager/contexts-states-dispatcher.spec.ts index 25405753..c40f4937 100644 --- a/packages/extension/src/manager/contexts-states-dispatcher.spec.ts +++ b/packages/extension/src/manager/contexts-states-dispatcher.spec.ts @@ -16,7 +16,7 @@ * SPDX-License-Identifier: Apache-2.0 ***********************************************************************/ -import { expect, test, vi } from 'vitest'; +import { beforeAll, beforeEach, expect, test, vi } from 'vitest'; import type { IDisposable } from '/@/types/disposable.js'; import type { ContextPermission } from '/@common/model/kubernetes-contexts-permissions.js'; @@ -24,57 +24,62 @@ import type { ContextPermission } from '/@common/model/kubernetes-contexts-permi import type { ContextHealthState } from './context-health-checker.js'; import type { ContextPermissionResult } from './context-permissions-checker.js'; import type { DispatcherEvent } from './contexts-dispatcher.js'; -import type { ContextsManager } from './contexts-manager.js'; +import { ContextsManager } from './contexts-manager.js'; import { ContextsStatesDispatcher } from './contexts-states-dispatcher.js'; import type { KubeConfigSingleContext } from '/@/types/kubeconfig-single-context.js'; import type { RpcExtension } from '/@common/rpc/rpc.js'; import { CONTEXTS_HEALTHS, CONTEXTS_PERMISSIONS, RESOURCES_COUNT, UPDATE_RESOURCE } from '/@common/channels.js'; +import type { ExtensionContext, TelemetryLogger } from '@podman-desktop/api'; +import type { Container } from 'inversify'; +import { InversifyBinding } from '../inject/inversify-binding.js'; + +let container: Container; +const contextsManagerMock: ContextsManager = { + onContextHealthStateChange: vi.fn(), + onOfflineChange: vi.fn(), + onContextPermissionResult: vi.fn(), + onContextDelete: vi.fn(), + getHealthCheckersStates: vi.fn(), + getPermissions: vi.fn(), + onResourceCountUpdated: vi.fn(), + onResourceUpdated: vi.fn(), + isContextOffline: vi.fn(), +} as unknown as ContextsManager; +const rpcExtension: RpcExtension = { + fire: vi.fn(), +} as unknown as RpcExtension; +const extensionContext = {} as ExtensionContext; +const telemetryLogger = {} as TelemetryLogger; +let dispatcher: ContextsStatesDispatcher; + +beforeAll(async () => { + const inversifyBinding = new InversifyBinding(rpcExtension, extensionContext, telemetryLogger); + container = await inversifyBinding.initBindings(); + (await container.rebind(ContextsManager)).toConstantValue(contextsManagerMock); +}); + +beforeEach(() => { + vi.resetAllMocks(); + dispatcher = container.get(ContextsStatesDispatcher); +}); -test('ContextsStatesDispatcher should call updateHealthStates when onContextHealthStateChange event is fired', () => { - const manager: ContextsManager = { - onContextHealthStateChange: vi.fn(), - onOfflineChange: vi.fn(), - onContextPermissionResult: vi.fn(), - onContextDelete: vi.fn(), - getHealthCheckersStates: vi.fn(), - getPermissions: vi.fn(), - onResourceCountUpdated: vi.fn(), - onResourceUpdated: vi.fn(), - isContextOffline: vi.fn(), - } as unknown as ContextsManager; - const rpcExtension: RpcExtension = { - fire: vi.fn(), - } as unknown as RpcExtension; - const dispatcher = new ContextsStatesDispatcher(manager, rpcExtension); +test('ContextsStatesDispatcher should call updateHealthStates when onContextHealthStateChange event is fired', async () => { const updateHealthStatesSpy = vi.spyOn(dispatcher, 'updateHealthStates').mockResolvedValue(); const updatePermissionsSpy = vi.spyOn(dispatcher, 'updatePermissions').mockResolvedValue(); dispatcher.init(); expect(updateHealthStatesSpy).not.toHaveBeenCalled(); expect(updatePermissionsSpy).not.toHaveBeenCalled(); - vi.mocked(manager.onContextHealthStateChange).mockImplementation(f => f({} as ContextHealthState) as IDisposable); - vi.mocked(manager.getHealthCheckersStates).mockReturnValue(new Map()); + vi.mocked(contextsManagerMock.onContextHealthStateChange).mockImplementation( + f => f({} as ContextHealthState) as IDisposable, + ); + vi.mocked(contextsManagerMock.getHealthCheckersStates).mockReturnValue(new Map()); dispatcher.init(); expect(updateHealthStatesSpy).toHaveBeenCalled(); expect(updatePermissionsSpy).not.toHaveBeenCalled(); }); test('ContextsStatesDispatcher should call updateHealthStates, updateResourcesCount and updateActiveResourcesCount when onOfflineChange event is fired', async () => { - const manager: ContextsManager = { - onContextHealthStateChange: vi.fn(), - onOfflineChange: vi.fn(), - onContextPermissionResult: vi.fn(), - onContextDelete: vi.fn(), - getHealthCheckersStates: vi.fn(), - getPermissions: vi.fn(), - onResourceCountUpdated: vi.fn(), - onResourceUpdated: vi.fn(), - isContextOffline: vi.fn(), - } as unknown as ContextsManager; - const rpcExtension: RpcExtension = { - fire: vi.fn(), - } as unknown as RpcExtension; - const dispatcher = new ContextsStatesDispatcher(manager, rpcExtension); const updateHealthStatesSpy = vi.spyOn(dispatcher, 'updateHealthStates').mockResolvedValue(); const updateResourcesCountSpy = vi.spyOn(dispatcher, 'updateResourcesCount').mockResolvedValue(); const updateActiveResourcesCountSpy = vi.spyOn(dispatcher, 'updateActiveResourcesCount').mockResolvedValue(); @@ -83,8 +88,8 @@ test('ContextsStatesDispatcher should call updateHealthStates, updateResourcesCo expect(updateResourcesCountSpy).not.toHaveBeenCalled(); expect(updateActiveResourcesCountSpy).not.toHaveBeenCalled(); - vi.mocked(manager.onOfflineChange).mockImplementation(f => f() as IDisposable); - vi.mocked(manager.getHealthCheckersStates).mockReturnValue(new Map()); + vi.mocked(contextsManagerMock.onOfflineChange).mockImplementation(f => f() as IDisposable); + vi.mocked(contextsManagerMock.getHealthCheckersStates).mockReturnValue(new Map()); dispatcher.init(); await vi.waitFor(() => { expect(updateHealthStatesSpy).toHaveBeenCalled(); @@ -94,59 +99,31 @@ test('ContextsStatesDispatcher should call updateHealthStates, updateResourcesCo }); test('ContextsStatesDispatcher should call updatePermissions when onContextPermissionResult event is fired', () => { - const manager: ContextsManager = { - onContextHealthStateChange: vi.fn(), - onOfflineChange: vi.fn(), - onContextPermissionResult: vi.fn(), - onContextDelete: vi.fn(), - getHealthCheckersStates: vi.fn(), - getPermissions: vi.fn(), - onResourceCountUpdated: vi.fn(), - onResourceUpdated: vi.fn(), - isContextOffline: vi.fn(), - } as unknown as ContextsManager; - const rpcExtension: RpcExtension = { - fire: vi.fn(), - } as unknown as RpcExtension; - const dispatcher = new ContextsStatesDispatcher(manager, rpcExtension); - vi.mocked(manager.getPermissions).mockReturnValue([]); + vi.mocked(contextsManagerMock.getPermissions).mockReturnValue([]); const updateHealthStatesSpy = vi.spyOn(dispatcher, 'updateHealthStates').mockResolvedValue(); const updatePermissionsSpy = vi.spyOn(dispatcher, 'updatePermissions').mockResolvedValue(); dispatcher.init(); expect(updateHealthStatesSpy).not.toHaveBeenCalled(); expect(updatePermissionsSpy).not.toHaveBeenCalled(); - vi.mocked(manager.onContextPermissionResult).mockImplementation(f => f({} as ContextPermissionResult) as IDisposable); + vi.mocked(contextsManagerMock.onContextPermissionResult).mockImplementation( + f => f({} as ContextPermissionResult) as IDisposable, + ); dispatcher.init(); expect(updateHealthStatesSpy).not.toHaveBeenCalled(); expect(updatePermissionsSpy).toHaveBeenCalled(); }); test('ContextsStatesDispatcher should call updateHealthStates and updatePermissions when onContextDelete event is fired', async () => { - const manager: ContextsManager = { - onContextHealthStateChange: vi.fn(), - onOfflineChange: vi.fn(), - onContextPermissionResult: vi.fn(), - onContextDelete: vi.fn(), - getHealthCheckersStates: vi.fn(), - getPermissions: vi.fn(), - onResourceCountUpdated: vi.fn(), - onResourceUpdated: vi.fn(), - isContextOffline: vi.fn(), - } as unknown as ContextsManager; - const rpcExtension: RpcExtension = { - fire: vi.fn(), - } as unknown as RpcExtension; - const dispatcher = new ContextsStatesDispatcher(manager, rpcExtension); - vi.mocked(manager.getPermissions).mockReturnValue([]); + vi.mocked(contextsManagerMock.getPermissions).mockReturnValue([]); const updateHealthStatesSpy = vi.spyOn(dispatcher, 'updateHealthStates').mockResolvedValue(); const updatePermissionsSpy = vi.spyOn(dispatcher, 'updatePermissions').mockResolvedValue(); - vi.mocked(manager.getHealthCheckersStates).mockReturnValue(new Map()); + vi.mocked(contextsManagerMock.getHealthCheckersStates).mockReturnValue(new Map()); dispatcher.init(); expect(updateHealthStatesSpy).not.toHaveBeenCalled(); expect(updatePermissionsSpy).not.toHaveBeenCalled(); - vi.mocked(manager.onContextDelete).mockImplementation(f => f({} as DispatcherEvent) as IDisposable); + vi.mocked(contextsManagerMock.onContextDelete).mockImplementation(f => f({} as DispatcherEvent) as IDisposable); dispatcher.init(); await vi.waitFor(() => { expect(updateHealthStatesSpy).toHaveBeenCalled(); @@ -155,30 +132,15 @@ test('ContextsStatesDispatcher should call updateHealthStates and updatePermissi }); test('ContextsStatesDispatcher should call updateResource and updateActiveResourcesCount when onResourceUpdated event is fired', async () => { - const manager: ContextsManager = { - onContextHealthStateChange: vi.fn(), - onOfflineChange: vi.fn(), - onContextPermissionResult: vi.fn(), - onContextDelete: vi.fn(), - getHealthCheckersStates: vi.fn(), - getPermissions: vi.fn(), - onResourceCountUpdated: vi.fn(), - onResourceUpdated: vi.fn(), - isContextOffline: vi.fn(), - } as unknown as ContextsManager; - const rpcExtension: RpcExtension = { - fire: vi.fn(), - } as unknown as RpcExtension; - const dispatcher = new ContextsStatesDispatcher(manager, rpcExtension); - vi.mocked(manager.getPermissions).mockReturnValue([]); + vi.mocked(contextsManagerMock.getPermissions).mockReturnValue([]); const updateResourceSpy = vi.spyOn(dispatcher, 'updateResource').mockResolvedValue(); const updateActiveResourcesCountSpy = vi.spyOn(dispatcher, 'updateActiveResourcesCount').mockResolvedValue(); - vi.mocked(manager.getHealthCheckersStates).mockReturnValue(new Map()); + vi.mocked(contextsManagerMock.getHealthCheckersStates).mockReturnValue(new Map()); dispatcher.init(); expect(updateResourceSpy).not.toHaveBeenCalled(); expect(updateActiveResourcesCountSpy).not.toHaveBeenCalled(); - vi.mocked(manager.onResourceUpdated).mockImplementation( + vi.mocked(contextsManagerMock.onResourceUpdated).mockImplementation( f => f({} as { contextName: string; resourceName: string }) as IDisposable, ); dispatcher.init(); @@ -189,19 +151,6 @@ test('ContextsStatesDispatcher should call updateResource and updateActiveResour }); test('getContextsHealths should return the values of the map returned by manager.getHealthCheckersStates without kubeConfig', () => { - const manager: ContextsManager = { - onContextHealthStateChange: vi.fn(), - onOfflineChange: vi.fn(), - onContextPermissionResult: vi.fn(), - onContextDelete: vi.fn(), - getHealthCheckersStates: vi.fn(), - getPermissions: vi.fn(), - isContextOffline: vi.fn(), - } as unknown as ContextsManager; - const rpcExtension: RpcExtension = { - fire: vi.fn(), - } as unknown as RpcExtension; - const dispatcher = new ContextsStatesDispatcher(manager, rpcExtension); const context1State = { contextName: 'context1', checking: true, @@ -223,36 +172,18 @@ test('getContextsHealths should return the values of the map returned by manager ['context2', { ...context2State, kubeConfig: {} as unknown as KubeConfigSingleContext }], ['context3', { ...context3State, kubeConfig: {} as unknown as KubeConfigSingleContext }], ]); - vi.mocked(manager.getHealthCheckersStates).mockReturnValue(value); + vi.mocked(contextsManagerMock.getHealthCheckersStates).mockReturnValue(value); const result = dispatcher.getContextsHealths(); expect(result).toEqual([context1State, context2State, context3State]); }); test('updateHealthStates should call rpcExtension.fire with CONTEXTS_HEALTHS and data', async () => { - const manager: ContextsManager = { - onContextHealthStateChange: vi.fn(), - onContextPermissionResult: vi.fn(), - onContextDelete: vi.fn(), - getHealthCheckersStates: vi.fn(), - getPermissions: vi.fn(), - } as unknown as ContextsManager; - const rpcExtension: RpcExtension = { - fire: vi.fn(), - } as unknown as RpcExtension; - const dispatcher = new ContextsStatesDispatcher(manager, rpcExtension); vi.spyOn(dispatcher, 'getContextsHealths').mockReturnValue([]); await dispatcher.updateHealthStates(); expect(rpcExtension.fire).toHaveBeenCalledWith(CONTEXTS_HEALTHS, { healths: [] }); }); test('getContextsPermissions should return the values as an array', () => { - const manager: ContextsManager = { - getPermissions: vi.fn(), - } as unknown as ContextsManager; - const rpcExtension: RpcExtension = { - fire: vi.fn(), - } as unknown as RpcExtension; - const dispatcher = new ContextsStatesDispatcher(manager, rpcExtension); const value: ContextPermission[] = [ { contextName: 'context1', @@ -279,45 +210,24 @@ test('getContextsPermissions should return the values as an array', () => { reason: 'ok', }, ]; - vi.mocked(manager.getPermissions).mockReturnValue(value); + vi.mocked(contextsManagerMock.getPermissions).mockReturnValue(value); const result = dispatcher.getContextsPermissions(); expect(result).toEqual(value); }); test('updatePermissions should call rpcExtension.fire with CONTEXTS_PERMISSIONS and data', async () => { - const manager: ContextsManager = { - getPermissions: vi.fn(), - } as unknown as ContextsManager; - const rpcExtension: RpcExtension = { - fire: vi.fn(), - } as unknown as RpcExtension; - const dispatcher = new ContextsStatesDispatcher(manager, rpcExtension); vi.spyOn(dispatcher, 'getContextsPermissions').mockReturnValue([]); await dispatcher.updatePermissions(); expect(rpcExtension.fire).toHaveBeenCalledWith(CONTEXTS_PERMISSIONS, { permissions: [] }); }); test('updateResourcesCount should call rpcExtension.fire with RESOURCES_COUNT and data', async () => { - const manager: ContextsManager = { - getResourcesCount: vi.fn(), - } as unknown as ContextsManager; - const rpcExtension: RpcExtension = { - fire: vi.fn(), - } as unknown as RpcExtension; - const dispatcher = new ContextsStatesDispatcher(manager, rpcExtension); vi.spyOn(dispatcher, 'getResourcesCount').mockReturnValue([]); await dispatcher.updateResourcesCount(); expect(rpcExtension.fire).toHaveBeenCalledWith(RESOURCES_COUNT, { counts: [] }); }); test('updateResource should call rpcExtension.fire with UPDATE_RESOURCE and data', async () => { - const manager: ContextsManager = { - getResources: vi.fn(), - } as unknown as ContextsManager; - const rpcExtension: RpcExtension = { - fire: vi.fn(), - } as unknown as RpcExtension; - const dispatcher = new ContextsStatesDispatcher(manager, rpcExtension); vi.spyOn(dispatcher, 'getResources').mockReturnValue([]); await dispatcher.updateResource('resource1', 'context1'); expect(rpcExtension.fire).toHaveBeenCalledWith(UPDATE_RESOURCE, { diff --git a/packages/extension/src/manager/contexts-states-dispatcher.ts b/packages/extension/src/manager/contexts-states-dispatcher.ts index 1c15fc34..008bcb8b 100644 --- a/packages/extension/src/manager/contexts-states-dispatcher.ts +++ b/packages/extension/src/manager/contexts-states-dispatcher.ts @@ -25,8 +25,8 @@ import type { KubernetesTroubleshootingInformation } from '/@common/model/kubern import type { ContextHealthState } from './context-health-checker.js'; import type { ContextPermissionResult } from './context-permissions-checker.js'; import type { DispatcherEvent } from './contexts-dispatcher.js'; -import type { ContextsManager } from './contexts-manager.js'; -import type { RpcExtension } from '/@common/rpc/rpc.js'; +import { ContextsManager } from './contexts-manager.js'; +import { RpcExtension } from '/@common/rpc/rpc.js'; import { ACTIVE_RESOURCES_COUNT, CONTEXTS_HEALTHS, @@ -34,12 +34,15 @@ import { RESOURCES_COUNT, UPDATE_RESOURCE, } from '/@common/channels.js'; +import { inject, injectable } from 'inversify'; +@injectable() export class ContextsStatesDispatcher { - constructor( - private manager: ContextsManager, - private rpcExtension: RpcExtension, - ) {} + @inject(ContextsManager) + private manager: ContextsManager; + + @inject(RpcExtension) + private rpcExtension: RpcExtension; init(): void { this.manager.onContextHealthStateChange((_state: ContextHealthState) => this.updateHealthStates());