Skip to content

Commit ae8b02b

Browse files
authored
feat: broadcast events (#17)
Signed-off-by: Philippe Martin <[email protected]>
1 parent 94e8a3c commit ae8b02b

11 files changed

+274
-139
lines changed

packages/common/src/channels.ts

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,32 @@
1-
import { type DashboardApi } from './interface/dashboard-api';
1+
/**********************************************************************
2+
* Copyright (C) 2025 Red Hat, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-License-Identifier: Apache-2.0
17+
***********************************************************************/
18+
19+
import type { ActiveResourcesCountInfo } from './model/active-resources-count-info';
20+
import type { ContextsHealthsInfo } from './model/contexts-healths-info';
21+
import type { ContextsPermissionsInfo } from './model/contexts-permissions-info';
22+
import type { ResourcesCountInfo } from './model/resources-count-info';
23+
import type { UpdateResourceInfo } from './model/update-resource-info';
24+
225
import { createRpcChannel } from './rpc';
326

4-
// RPC channels (used by the webview to send requests to the extension)
5-
export const API_DASHBOARD = createRpcChannel<DashboardApi>('DashboardApi');
27+
// Broadcast events (sent by extension and received by the webview)
28+
export const RESOURCES_COUNT = createRpcChannel<ResourcesCountInfo>('ResourcesCount');
29+
export const ACTIVE_RESOURCES_COUNT = createRpcChannel<ActiveResourcesCountInfo>('ActiveResourcesCount');
30+
export const CONTEXTS_HEALTHS = createRpcChannel<ContextsHealthsInfo>('ContextsHealths');
31+
export const CONTEXTS_PERMISSIONS = createRpcChannel<ContextsPermissionsInfo>('ContextsPermissions');
32+
export const UPDATE_RESOURCE = createRpcChannel<UpdateResourceInfo>('UpdateResource');
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**********************************************************************
2+
* Copyright (C) 2025 Red Hat, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-License-Identifier: Apache-2.0
17+
***********************************************************************/
18+
19+
import type { ResourceCount } from './kubernetes-resource-count';
20+
21+
export interface ActiveResourcesCountInfo {
22+
counts: ResourceCount[];
23+
}

packages/common/src/model/api-sender.ts renamed to packages/common/src/model/contexts-healths-info.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**********************************************************************
2-
* Copyright (C) 2022-2024 Red Hat, Inc.
2+
* Copyright (C) 2025 Red Hat, Inc.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,8 @@
1616
* SPDX-License-Identifier: Apache-2.0
1717
***********************************************************************/
1818

19-
export type ApiSenderType = {
20-
send: (channel: string, data?: unknown) => void;
21-
};
19+
import type { ContextHealth } from './kubernetes-contexts-healths';
20+
21+
export interface ContextsHealthsInfo {
22+
healths: ContextHealth[];
23+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**********************************************************************
2+
* Copyright (C) 2025 Red Hat, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-License-Identifier: Apache-2.0
17+
***********************************************************************/
18+
19+
import type { ContextPermission } from './kubernetes-contexts-permissions';
20+
21+
export interface ContextsPermissionsInfo {
22+
permissions: ContextPermission[];
23+
}

packages/common/src/interface/dashboard-api.ts renamed to packages/common/src/model/resources-count-info.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
* SPDX-License-Identifier: Apache-2.0
1717
***********************************************************************/
1818

19-
export const DashboardApi = Symbol.for('DashboardApi');
20-
export interface DashboardApi {
21-
ping(): Promise<string>;
19+
import type { ResourceCount } from './kubernetes-resource-count';
20+
21+
export interface ResourcesCountInfo {
22+
counts: ResourceCount[];
2223
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**********************************************************************
2+
* Copyright (C) 2025 Red Hat, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-License-Identifier: Apache-2.0
17+
***********************************************************************/
18+
19+
import type { KubernetesContextResources } from './kubernetes-resources';
20+
21+
export interface UpdateResourceInfo {
22+
contextName: string;
23+
resourceName: string;
24+
resources: KubernetesContextResources[];
25+
}

packages/extension/src/dashboard-extension.spec.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,19 @@ import { assert, beforeEach, describe, expect, test, vi } from 'vitest';
2222
import { DashboardExtension } from './dashboard-extension';
2323
import { vol } from 'memfs';
2424

25-
import type { ContextsManager } from './manager/contexts-manager';
26-
import type { ContextsStatesDispatcher } from './manager/contexts-states-dispatcher';
25+
import { ContextsManager } from './manager/contexts-manager';
26+
import { ContextsStatesDispatcher } from './manager/contexts-states-dispatcher';
2727

2828
let extensionContextMock: ExtensionContext;
2929
let dashboardExtension: DashboardExtension;
3030
let contextsManagerMock: ContextsManager;
31-
let contextsStatesDispatcher: ContextsStatesDispatcher;
31+
let contextsStatesDispatcherMock: ContextsStatesDispatcher;
3232

3333
vi.mock(import('node:fs'));
3434
vi.mock(import('node:fs/promises'));
3535
vi.mock(import('@kubernetes/client-node'));
36+
vi.mock(import('./manager/contexts-manager'));
37+
vi.mock(import('./manager/contexts-states-dispatcher'));
3638

3739
beforeEach(() => {
3840
vi.restoreAllMocks();
@@ -50,14 +52,19 @@ beforeEach(() => {
5052
extensionContextMock = {
5153
subscriptions: [],
5254
} as unknown as ExtensionContext;
55+
5356
// Create a mock for the contextsManager
5457
contextsManagerMock = {
5558
update: vi.fn(),
5659
} as unknown as ContextsManager;
57-
contextsStatesDispatcher = {
60+
vi.mocked(ContextsManager).mockReturnValue(contextsManagerMock);
61+
62+
contextsStatesDispatcherMock = {
5863
init: vi.fn(),
5964
} as unknown as ContextsStatesDispatcher;
60-
dashboardExtension = new DashboardExtension(extensionContextMock, contextsManagerMock, contextsStatesDispatcher);
65+
vi.mocked(ContextsStatesDispatcher).mockReturnValue(contextsStatesDispatcherMock);
66+
67+
dashboardExtension = new DashboardExtension(extensionContextMock);
6168
vi.mocked(kubernetes.getKubeconfig).mockReturnValue({
6269
path: '/path/to/kube/config',
6370
} as Uri);
@@ -80,7 +87,7 @@ describe('a kubeconfig file is not present', () => {
8087
callback({ type: 'UPDATE', location: { path: '/path/to/kube/config' } as Uri });
8188
expect(contextsManagerMock.update).toHaveBeenCalledOnce();
8289

83-
expect(contextsStatesDispatcher.init).toHaveBeenCalledOnce();
90+
expect(contextsStatesDispatcherMock.init).toHaveBeenCalledOnce();
8491
});
8592

8693
test('should deactivate correctly', async () => {
@@ -107,7 +114,7 @@ describe('a kubeconfig file is present', () => {
107114
callback({ type: 'UPDATE', location: { path: '/path/to/kube/config' } as Uri });
108115
expect(contextsManagerMock.update).toHaveBeenCalledOnce();
109116

110-
expect(contextsStatesDispatcher.init).toHaveBeenCalledOnce();
117+
expect(contextsStatesDispatcherMock.init).toHaveBeenCalledOnce();
111118
});
112119

113120
test('should deactivate correctly', async () => {

packages/extension/src/dashboard-extension.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,24 +22,18 @@ import { kubernetes, Uri, window } from '@podman-desktop/api';
2222
import { RpcExtension } from '/@common/rpc/rpc';
2323

2424
import { readFile } from 'node:fs/promises';
25-
import type { ContextsManager } from './manager/contexts-manager';
25+
import { ContextsManager } from './manager/contexts-manager';
2626
import { existsSync } from 'node:fs';
2727
import { KubeConfig } from '@kubernetes/client-node';
28-
import type { ContextsStatesDispatcher } from './manager/contexts-states-dispatcher';
28+
import { ContextsStatesDispatcher } from './manager/contexts-states-dispatcher';
2929

3030
export class DashboardExtension {
3131
#extensionContext: ExtensionContext;
3232
#contextsManager: ContextsManager;
3333
#contextsStatesDispatcher: ContextsStatesDispatcher;
3434

35-
constructor(
36-
readonly extensionContext: ExtensionContext,
37-
readonly contextManager: ContextsManager,
38-
readonly contextsStatesDispatcher: ContextsStatesDispatcher,
39-
) {
35+
constructor(readonly extensionContext: ExtensionContext) {
4036
this.#extensionContext = extensionContext;
41-
this.#contextsManager = contextManager;
42-
this.#contextsStatesDispatcher = contextsStatesDispatcher;
4337
}
4438

4539
async activate(): Promise<void> {
@@ -50,6 +44,9 @@ export class DashboardExtension {
5044
rpcExtension.init();
5145
this.#extensionContext.subscriptions.push(rpcExtension);
5246

47+
this.#contextsManager = new ContextsManager();
48+
this.#contextsStatesDispatcher = new ContextsStatesDispatcher(this.#contextsManager, rpcExtension);
49+
5350
const now = performance.now();
5451

5552
const afterFirst = performance.now();

packages/extension/src/main.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,12 @@
1919
import type { ExtensionContext } from '@podman-desktop/api';
2020

2121
import { DashboardExtension } from './dashboard-extension';
22-
import { ContextsManager } from './manager/contexts-manager';
23-
import { ContextsStatesDispatcher } from './manager/contexts-states-dispatcher';
2422

2523
let dashboardExtension: DashboardExtension | undefined;
2624

2725
// Initialize the activation of the extension.
2826
export async function activate(extensionContext: ExtensionContext): Promise<void> {
29-
const contextsManager = new ContextsManager();
30-
const apiSender = {
31-
send: (channel: string, data?: unknown): void => {
32-
console.log(`==> recv data "${data}" on channel ${channel}`);
33-
},
34-
};
35-
const contextsStatesDispatcher = new ContextsStatesDispatcher(contextsManager, apiSender);
36-
dashboardExtension ??= new DashboardExtension(extensionContext, contextsManager, contextsStatesDispatcher);
27+
dashboardExtension ??= new DashboardExtension(extensionContext);
3728

3829
await dashboardExtension.activate();
3930
}

0 commit comments

Comments
 (0)