Skip to content

Commit

Permalink
feat: playground navigate to container (#192)
Browse files Browse the repository at this point in the history
* feat: playground navigate to container

* test: ensuring api is called when use container icon

Signed-off-by: axel7083 <[email protected]>

* fix: prettier

Signed-off-by: axel7083 <[email protected]>

* test: fix missing mockReturnValue

Signed-off-by: axel7083 <[email protected]>

---------

Signed-off-by: axel7083 <[email protected]>
  • Loading branch information
axel7083 authored Feb 1, 2024
1 parent dad6176 commit d927a74
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 2 deletions.
4 changes: 4 additions & 0 deletions packages/backend/src/studio-api-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,8 @@ export class StudioApiImpl implements StudioAPI {
async getModelsDirectory(): Promise<string> {
return this.modelsManager.getModelsDirectory();
}

navigateToContainer(containerId: string): Promise<void> {
return podmanDesktopApi.navigation.navigateToContainer(containerId);
}
}
2 changes: 1 addition & 1 deletion packages/frontend/src/lib/button/Button.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ $: {
{:else if iconType === 'fa'}
<Fa icon="{icon}" />
{:else if iconType === 'unknown'}
<svelte:component this="{icon}" />
<svelte:component size="1em" this="{icon}" />
{/if}
{#if $$slots.default}
<span><slot /></span>
Expand Down
45 changes: 45 additions & 0 deletions packages/frontend/src/lib/images/ContainerIcon.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<script lang="ts">
export let size = '40';
export let solid = false;
</script>

<svg
width="{size}"
height="{size}"
class="{$$props.class}"
style="{$$props.style}"
viewBox="0.926 0.926 4.498 4.498"
version="1.1"
xml:space="preserve"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
{#if solid}
<defs>
<mask id="containermask">
<rect x="-15" y="-15" width="100" height="100" fill="white"></rect>
<path
style="fill-rule:evenodd;stroke-width:0.264583;stroke-linejoin:round;stroke-miterlimit:10"
d="m -10.666282,15.93309 a 0.13230489,0.13230489 0 0 0 -0.02584,0.0052 l -2.116667,0.661458 a 0.13230489,0.13230489 0 0 0 -0.08888,0.151412 0.13230489,0.13230489 0 0 0 -0.0041,0.03256 v 2.390552 a 0.13230489,0.13230489 0 0 0 0.07028,0.116789 l 2.106332,1.123445 a 0.13230489,0.13230489 0 0 0 0.07235,0.01447 0.13230489,0.13230489 0 0 0 0.07235,-0.01447 l 2.1063312,-1.123445 a 0.13230489,0.13230489 0 0 0 0.07028,-0.116789 V 16.78372 a 0.13230489,0.13230489 0 0 0 -0.00362,-0.03152 0.13230489,0.13230489 0 0 0 -0.0894,-0.152445 l -2.1166662,-0.661458 a 0.13230489,0.13230489 0 0 0 -0.05271,-0.0052 z m 0.01344,0.269751 1.6737994,0.522965 -1.6737994,0.522966 -1.6738,-0.522966 z m -1.984375,0.762227 1.851566,0.595313 -0.0088,2.517159 -1.842781,-0.982886 z m 3.9687498,0 v 2.129586 l -1.8427818,0.982886 -0.0088,-2.517159 z"
></path>
</mask>
</defs>
<g transform="translate(21.210601,-15.062965)">
<g transform="translate(-7.3827548,0.05695021)">
<path
style="fill:currentColor;fill-rule:nonzero;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:10;stroke-dasharray:none"
mask="url(#containermask)"
d="m -10.652846,16.077316 -2.091065,0.619106 -0.0063,2.463792 2.065795,1.105548 2.1479213,-1.111865 0.012635,-2.369031 z"
></path>
</g>
</g>
{:else}
<g transform="translate(21.210601,-15.062965)">
<g transform="translate(-7.3827548,0.05695021)">
<path
style="fill:currentColor;fill-rule:evenodd;stroke-width:0.264583;stroke-linejoin:round;stroke-miterlimit:10"
d="m -10.666282,15.93309 a 0.13230489,0.13230489 0 0 0 -0.02584,0.0052 l -2.116667,0.661458 a 0.13230489,0.13230489 0 0 0 -0.08888,0.151412 0.13230489,0.13230489 0 0 0 -0.0041,0.03256 v 2.390552 a 0.13230489,0.13230489 0 0 0 0.07028,0.116789 l 2.106332,1.123445 a 0.13230489,0.13230489 0 0 0 0.07235,0.01447 0.13230489,0.13230489 0 0 0 0.07235,-0.01447 l 2.1063312,-1.123445 a 0.13230489,0.13230489 0 0 0 0.07028,-0.116789 V 16.78372 a 0.13230489,0.13230489 0 0 0 -0.00362,-0.03152 0.13230489,0.13230489 0 0 0 -0.0894,-0.152445 l -2.1166662,-0.661458 a 0.13230489,0.13230489 0 0 0 -0.05271,-0.0052 z m 0.01344,0.269751 1.6737994,0.522965 -1.6737994,0.522966 -1.6738,-0.522966 z m -1.984375,0.762227 1.851566,0.595313 -0.0088,2.517159 -1.842781,-0.982886 z m 3.9687498,0 v 2.129586 l -1.8427818,0.982886 -0.0088,-2.517159 z"
></path>
</g>
</g>
{/if}
</svg>
48 changes: 48 additions & 0 deletions packages/frontend/src/pages/ModelPlayground.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type { ModelInfo } from '@shared/src/models/IModelInfo';

const mocks = vi.hoisted(() => {
return {
navigateToContainerMock: vi.fn(),
startPlaygroundMock: vi.fn(),
askPlaygroundMock: vi.fn(),
getPlaygroundsStateMock: vi.fn().mockImplementation(() => Promise.resolve([])),
Expand All @@ -16,12 +17,20 @@ const mocks = vi.hoisted(() => {
return () => {};
},
},
playgroundStatesSubscribeMock: vi.fn().mockReturnValue([]),
playgroundStatesMock: {
subscribe: (f: (msg: any) => void) => {
f(mocks.playgroundStatesSubscribeMock());
return () => {};
},
},
};
});

vi.mock('../utils/client', async () => {
return {
studioClient: {
navigateToContainer: mocks.navigateToContainerMock,
getPlaygroundsState: mocks.getPlaygroundsStateMock,
startPlayground: mocks.startPlaygroundMock,
askPlayground: mocks.askPlaygroundMock,
Expand All @@ -43,6 +52,12 @@ vi.mock('../stores/playground-queries', async () => {
};
});

vi.mock('../stores/playground-states', async () => {
return {
playgroundStates: mocks.playgroundStatesMock,
};
});

beforeEach(() => {
vi.clearAllMocks();
});
Expand Down Expand Up @@ -168,3 +183,36 @@ test('should display error alert', async () => {
expect(alert).toBeDefined();
});
});

test('playground container icon should redirect', async () => {
mocks.playgroundQueriesSubscribeMock.mockReturnValue([]);
mocks.playgroundStatesSubscribeMock.mockReturnValue([
{
modelId: 'model1',
container: {
containerId: 'dummy-container-id',
},
},
]);
render(ModelPlayground, {
model: {
id: 'model1',
name: 'Model 1',
description: 'A description',
hw: 'CPU',
registry: 'Hugging Face',
popularity: 3,
license: '?',
url: 'https://huggingface.co/TheBloke/Llama-2-7B-Chat-GGUF/resolve/main/llama-2-7b-chat.Q5_K_S.gguf',
} as ModelInfo,
});

await waitFor(async () => {
const navigateTo = screen.getByTitle('navigate-to-container');
expect(navigateTo).toBeDefined();

await fireEvent.click(navigateTo);
});

expect(mocks.navigateToContainerMock).toHaveBeenNthCalledWith(1, 'dummy-container-id');
});
15 changes: 15 additions & 0 deletions packages/frontend/src/pages/ModelPlayground.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
export let model: ModelInfo | undefined;
import Fa from 'svelte-fa';
import { faPlay, faStop, faInfo, faWarning } from '@fortawesome/free-solid-svg-icons';
import ContainerIcon from '/@/lib/images/ContainerIcon.svelte';
import ErrorMessage from '/@/lib/ErrorMessage.svelte';
let prompt = '';
Expand Down Expand Up @@ -157,6 +158,17 @@
return true;
}
}
const navigateToContainer = () => {
if(playgroundState?.container?.containerId === undefined)
return;
try {
studioClient.navigateToContainer(playgroundState?.container?.containerId);
} catch(err) {
console.error(err);
}
}
</script>

<div class="m-4 w-full flew flex-col">
Expand All @@ -170,6 +182,9 @@
{#key playgroundState?.status}
<span class="flex-grow">Playground {playgroundState?.status}</span>
<Button title="playground-action" inProgress={isLoading()} on:click={onAction} icon="{getActionIcon()}"/>
{#if playgroundState?.container}
<Button class="ml-2" on:click={navigateToContainer} title="navigate-to-container" icon="{ContainerIcon}"/>
{/if}
{/key}
</div>
</Card>
Expand Down
2 changes: 1 addition & 1 deletion packages/shared/src/StudioAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ export abstract class StudioAPI {
abstract askPlayground(modelId: string, prompt: string): Promise<number>;
abstract getPlaygroundQueriesState(): Promise<QueryState[]>;
abstract getPlaygroundsState(): Promise<PlaygroundState[]>;

abstract getModelsDirectory(): Promise<string>;
abstract navigateToContainer(containerId: string): Promise<void>;
}

0 comments on commit d927a74

Please sign in to comment.