Skip to content

Commit

Permalink
feat: making the page persistent
Browse files Browse the repository at this point in the history
Signed-off-by: axel7083 <[email protected]>
  • Loading branch information
axel7083 committed Jun 18, 2024
1 parent c5bc2cc commit 91295e7
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 2 deletions.
7 changes: 5 additions & 2 deletions packages/backend/src/managers/applicationManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import type { Recipe } from '@shared/src/models/IRecipe';
import type { GitCloneInfo, GitManager } from './gitManager';
import fs from 'fs';
import * as path from 'node:path';
import { containerEngine, Disposable } from '@podman-desktop/api';
import { containerEngine, Disposable, window, ProgressLocation } from '@podman-desktop/api';
import type {
PodCreatePortOptions,
TelemetryLogger,
Expand Down Expand Up @@ -106,7 +106,10 @@ export class ApplicationManager extends Publisher<ApplicationState[]> implements

const task = this.taskRegistry.createTask(`Pulling ${recipe.name} recipe`, 'loading', labels);

this.pullApplication(recipe, model, labels)
window
.withProgress({ location: ProgressLocation.TASK_WIDGET, title: `Pulling ${recipe.name}.` }, () =>
this.pullApplication(recipe, model, labels),
)
.then(() => {
task.state = 'success';
})
Expand Down
54 changes: 54 additions & 0 deletions packages/frontend/src/pages/StartRecipe.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import type { Recipe } from '@shared/src/models/IRecipe';
import { InferenceType } from '@shared/src/models/IInference';
import type { ModelInfo } from '@shared/src/models/IModelInfo';
import type { Task } from '@shared/src/models/ITask';
import { router } from 'tinro';

const mocks = vi.hoisted(() => {
return {
Expand Down Expand Up @@ -86,6 +87,9 @@ vi.mock('/@/stores/catalog', async () => {
vi.mock('tinro', () => ({
router: {
goto: vi.fn(),
location: {
query: new Map(),
},
},
}));

Expand Down Expand Up @@ -124,6 +128,9 @@ const fakeRemoteModel: ModelInfo = {
beforeEach(() => {
vi.resetAllMocks();

// reset all query between tests
router.location.query.clear();

mocks.getCatalogMock.mockReturnValue({
recipes: [fakeRecipe],
});
Expand Down Expand Up @@ -290,3 +297,50 @@ test('Loading task should make the submit button disabled', async () => {
expect(button).toBeDefined();
});
});

test('trackingId in router query should use it to display related tasks', () => {
mocks.getTasksMock.mockReturnValue([
{
id: 'dummy-task-id',
name: 'Dummy task',
state: 'loading',
labels: {
trackingId: 'fake-tracking-id',
},
} as Task,
]);

router.location.query.set('trackingId', 'fake-tracking-id');

render(StartRecipe, {
recipeId: 'dummy-recipe-id',
});
const button = screen.getByTitle(`Start ${fakeRecipe.name} recipe`);
expect(button).toBeDisabled();
});

test('restoring page should use model-id from tasks to restore the value in the select input', async () => {
mocks.getTasksMock.mockReturnValue([
{
id: 'dummy-task-id',
name: 'Dummy task',
state: 'loading',
labels: {
trackingId: 'fake-tracking-id',
'model-id': fakeRecommendedModel.id,
},
} as Task,
]);

router.location.query.set('trackingId', 'fake-tracking-id');

const { container } = render(StartRecipe, {
recipeId: 'dummy-recipe-id',
});

return await vi.waitFor(() => {
const input = container.querySelector('input[name="select-model"][type="hidden"]');
if (!input) throw new Error('input not found');
expect(JSON.parse((input as HTMLInputElement).value).label).toBe(fakeRecommendedModel.name);
});
});
28 changes: 28 additions & 0 deletions packages/frontend/src/pages/StartRecipe.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,35 @@ const processTasks = (tasks: Task[]) => {
// if all task are successful
completed = trackedTasks.every(task => task.state === 'success');
// if we re-open the page, we might need to restore the model selected
populateModelFromTasks();
};
// This method uses the trackedTasks to restore the selected value of model
// It is useful when the page has been restored
function populateModelFromTasks(): void {
// if we already have a value for the model keep it
if (value) return;
const task = trackedTasks.find(
task => task.labels && 'model-id' in task.labels && typeof task.labels['model-id'] === 'string',
);
const modelId = task?.labels?.['model-id'];
if (!modelId) return;
const model = models.find(model => model.id === modelId);
if (!model) return;
value = { ...model, label: model.name, value: model.id };
}
async function submit(): Promise<void> {
if (!recipe || !value) return;
loading = true;
trackingId = await studioClient.requestPullApplication(recipe.id, value.id);
router.location.query.set('trackingId', trackingId);
}
let connectionInfo: ContainerConnectionInfo | undefined;
Expand All @@ -93,6 +115,12 @@ $: if (value) {
}
onMount(() => {
// Fetch any trackingId we could recover from query
const query = router.location.query.get('trackingId');
if (typeof query === 'string' && query.length > 0) {
trackingId = query;
}
return tasks.subscribe(tasks => {
processTasks(tasks);
});
Expand Down

0 comments on commit 91295e7

Please sign in to comment.