Skip to content

Commit

Permalink
chore: add Container providers using ProviderWidget (podman-desktop#1…
Browse files Browse the repository at this point in the history
…0625)

* chore: add Container providers using ProviderWidget
Signed-off-by: Sonia Sandler <[email protected]>
  • Loading branch information
SoniaSandler authored Jan 16, 2025
1 parent c48372d commit 0925949
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ export class StatusbarProvidersInit {
description: 'Show providers in statusbar',
type: 'boolean',
default: import.meta.env.DEV ? true : false,
hidden: true,
},
},
};
Expand Down
107 changes: 104 additions & 3 deletions packages/renderer/src/lib/statusbar/StatusBar.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,44 @@
* SPDX-License-Identifier: Apache-2.0
***********************************************************************/

import '@testing-library/jest-dom/vitest';

import type { ProviderStatus } from '@podman-desktop/api';
import { render } from '@testing-library/svelte';
import { tick } from 'svelte';
import { beforeEach, expect, test, vi } from 'vitest';

import StatusBar from '/@/lib/statusbar/StatusBar.svelte';
import { onDidChangeConfiguration } from '/@/stores/configurationProperties';
import { providerInfos } from '/@/stores/providers';
import { statusBarEntries } from '/@/stores/statusbar';
import { tasksInfo } from '/@/stores/tasks';
import type { ProviderInfo } from '/@api/provider-info';
import { ExperimentalTasksSettings } from '/@api/tasks-preferences';

const callbacks = new Map<string, (arg: unknown) => void>();

const providerMock1 = {
name: 'provider1',
containerConnections: [{}],
kubernetesConnections: [],
status: 'ready' as ProviderStatus,
images: {},
} as unknown as ProviderInfo;

const providerMock2 = {
name: 'provider2',
containerConnections: [],
kubernetesConnections: [{}],
status: 'ready' as ProviderStatus,
images: {},
} as unknown as ProviderInfo;

beforeEach(() => {
(window.getConfigurationValue as unknown) = vi.fn();
Object.defineProperty(window, 'getConfigurationValue', { value: vi.fn() });
onDidChangeConfiguration.addEventListener = vi.fn().mockImplementation((message: string, callback: () => void) => {
callbacks.set(message, callback);
});

// reset stores
statusBarEntries.set([]);
Expand All @@ -39,14 +67,21 @@ beforeEach(() => {
cancellable: false,
},
]);

providerInfos.set([providerMock1, providerMock2]);
});

test('onMount should call getConfigurationValue', () => {
test('onMount should call getConfigurationValue', async () => {
render(StatusBar);

expect(window.getConfigurationValue).toHaveBeenCalledWith(
await vi.waitFor(() => expect(window.getConfigurationValue).toBeCalledTimes(2));

expect(window.getConfigurationValue).nthCalledWith(
1,
`${ExperimentalTasksSettings.SectionName}.${ExperimentalTasksSettings.StatusBar}`,
);

expect(window.getConfigurationValue).nthCalledWith(2, `statusbarProviders.showProviders`);
});

test('tasks should be visible when getConfigurationValue is true', async () => {
Expand All @@ -68,3 +103,69 @@ test('tasks should not be visible when getConfigurationValue is false', () => {
const status = queryByRole('status');
expect(status).toBeNull();
});

test('providers should be visible when getConfigurationValue is true', async () => {
vi.mocked(window.getConfigurationValue).mockResolvedValue(true);

const { queryByLabelText } = render(StatusBar);
await tick();

await vi.waitFor(() => {
const provider1 = queryByLabelText('provider1');
const provider2 = queryByLabelText('provider2');
expect(provider1).toBeInTheDocument();
expect(provider2).not.toBeInTheDocument();
});
});

test('providers should not be visible when getConfigurationValue is false', () => {
vi.mocked(window.getConfigurationValue).mockResolvedValue(false);

const { queryByLabelText } = render(StatusBar);
const provider1 = queryByLabelText('provider1');
expect(provider1).toBeNull();
});

test('providers should show up when configuration changes from false to true', async () => {
vi.mocked(window.getConfigurationValue).mockResolvedValue(false);
const { queryByLabelText } = render(StatusBar);
await tick();

const provider1 = queryByLabelText('provider1');
expect(provider1).toBeNull();

callbacks.get(`statusbarProviders.showProviders`)?.({
detail: { key: `statusbarProviders.showProviders`, value: true },
});

await tick();

await vi.waitFor(() => {
const provider1 = queryByLabelText('provider1');
const provider2 = queryByLabelText('provider2');
expect(provider1).toBeInTheDocument();
expect(provider2).not.toBeInTheDocument();
});
});

test('providers are hidden when configuration changes from true to false', async () => {
vi.mocked(window.getConfigurationValue).mockResolvedValueOnce(false);
vi.mocked(window.getConfigurationValue).mockResolvedValueOnce(true);
const { queryByLabelText } = render(StatusBar);

await vi.waitFor(() => {
const provider1 = queryByLabelText('provider1');
const provider2 = queryByLabelText('provider2');
expect(provider1).toBeInTheDocument();
expect(provider2).not.toBeInTheDocument();
});

callbacks.get(`statusbarProviders.showProviders`)?.({
detail: { key: `statusbarProviders.showProviders`, value: false },
});

await tick();

const provider1 = queryByLabelText('provider1');
expect(provider1).toBeNull();
});
36 changes: 34 additions & 2 deletions packages/renderer/src/lib/statusbar/StatusBar.svelte
Original file line number Diff line number Diff line change
@@ -1,17 +1,35 @@
<script lang="ts">
import { onMount } from 'svelte';
import { onDestroy, onMount } from 'svelte';
import TaskIndicator from '/@/lib/statusbar/TaskIndicator.svelte';
import { onDidChangeConfiguration } from '/@/stores/configurationProperties';
import { providerInfos } from '/@/stores/providers';
import { statusBarEntries } from '/@/stores/statusbar';
import { ExperimentalTasksSettings } from '/@api/tasks-preferences';
import type { StatusBarEntry } from '../../../../main/src/plugin/statusbar/statusbar-registry';
import ProviderWidget from './ProviderWidget.svelte';
import StatusBarItem from './StatusBarItem.svelte';
let leftEntries: StatusBarEntry[] = $state([]);
let rightEntries: StatusBarEntry[] = $state([]);
let containerProviders = $derived($providerInfos.filter(provider => provider.containerConnections.length > 0));
let experimentalTaskStatusBar: boolean = $state(false);
let experimentalProvidersStatusBar: boolean = $state(false);
function onDidChangeConfigurationCallback(e: Event): void {
if (!('detail' in e) || !e.detail || typeof e.detail !== 'object') {
return;
}
if ('key' in e.detail && 'value' in e.detail) {
const detail = e.detail as { key: string; value: boolean };
if ('statusbarProviders.showProviders' === detail.key) {
experimentalProvidersStatusBar = detail.value;
}
}
}
onMount(async () => {
statusBarEntries.subscribe(value => {
Expand Down Expand Up @@ -54,17 +72,31 @@ onMount(async () => {
(await window.getConfigurationValue<boolean>(
`${ExperimentalTasksSettings.SectionName}.${ExperimentalTasksSettings.StatusBar}`,
)) ?? false;
experimentalProvidersStatusBar =
(await window.getConfigurationValue<boolean>('statusbarProviders.showProviders')) ?? false;
onDidChangeConfiguration.addEventListener('statusbarProviders.showProviders', onDidChangeConfigurationCallback);
});
onDestroy(() => {
onDidChangeConfiguration.removeEventListener('statusbarProviders.showProviders', onDidChangeConfigurationCallback);
});
</script>

<div
class="flex justify-between px-1 bg-[var(--pd-statusbar-bg)] text-[var(--pd-statusbar-text)] text-sm space-x-2 z-40"
role="contentinfo"
aria-label="Status Bar">
<div class="flex flex-wrap gap-x-1.5 h-full">
<div class="flex flex-nowrap gap-x-1.5 h-full truncate">
{#each leftEntries as entry}
<StatusBarItem entry={entry} />
{/each}
{#if experimentalProvidersStatusBar}
{#each containerProviders as entry}
<ProviderWidget entry={entry}/>
{/each}
{/if}
</div>
<div class="flex flex-wrap flex-row-reverse gap-x-1.5 h-full place-self-end">
{#each rightEntries as entry}
Expand Down

0 comments on commit 0925949

Please sign in to comment.