Skip to content

Commit

Permalink
fix: rebase + prettier + lint
Browse files Browse the repository at this point in the history
Signed-off-by: axel7083 <[email protected]>
  • Loading branch information
axel7083 committed Jan 19, 2024
1 parent 558aaba commit 1d715be
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 86 deletions.
72 changes: 60 additions & 12 deletions packages/backend/src/managers/catalogManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,17 @@ import defaultCatalog from '../ai.json';
import type { Category } from '@shared/src/models/ICategory';
import type { Recipe } from '@shared/src/models/IRecipe';
import type { ModelInfo } from '@shared/src/models/IModelInfo';
import { MSG_NEW_CATALOG_STATE } from '@shared/Messages';
import { fs } from '@podman-desktop/api';
import type { Webview } from '@podman-desktop/api';

export class CatalogManager {
private catalog: Catalog;

constructor(private appUserDirectory: string) {
constructor(
private appUserDirectory: string,
private webview: Webview,
) {
// We start with an empty catalog, for the methods to work before the catalog is loaded
this.catalog = {
categories: [],
Expand All @@ -18,6 +24,10 @@ export class CatalogManager {
};
}

public getCatalog(): Catalog {
return this.catalog;
}

public getCategories(): Category[] {
return this.catalog.categories;
}
Expand All @@ -31,23 +41,61 @@ export class CatalogManager {

async loadCatalog() {
const catalogPath = path.resolve(this.appUserDirectory, 'catalog.json');
if (!existsSync(catalogPath)) {
return this.setCatalog(defaultCatalog);
}

try {
if (!existsSync(catalogPath)) {
this.setCatalog(defaultCatalog);
return;
}
// TODO(feloy): watch catalog file and update catalog with new content
const data = await promises.readFile(catalogPath, 'utf-8');
const cat = JSON.parse(data) as Catalog;
this.setCatalog(cat);
this.watchCatalogFile(catalogPath); // do not await, we want to do this async
} catch (err: unknown) {
console.error('unable to watch catalog file, changes to the catalog file won\'t be reflected to the UI', err);
}

try {
const cat = await this.readAndAnalyzeCatalog(catalogPath);
return this.setCatalog(cat);
} catch (err: unknown) {
console.error('unable to read catalog file, reverting to default catalog', err);
this.setCatalog(defaultCatalog);
}
// If something went wrong we load the default catalog
return this.setCatalog(defaultCatalog);
}

watchCatalogFile(path: string) {
const watcher = fs.createFileSystemWatcher(path);
watcher.onDidCreate(async () => {
try {
const cat = await this.readAndAnalyzeCatalog(path);
await this.setCatalog(cat);
} catch (err: unknown) {
console.error('unable to read created catalog file, continue using default catalog', err);
}
});
watcher.onDidDelete(async () => {
console.log('user catalog file deleted, reverting to default catalog');
await this.setCatalog(defaultCatalog);
});
watcher.onDidChange(async () => {
try {
const cat = await this.readAndAnalyzeCatalog(path);
await this.setCatalog(cat);
} catch (err: unknown) {
console.error('unable to read modified catalog file, reverting to default catalog', err);
}
});
}

async readAndAnalyzeCatalog(path: string): Promise<Catalog> {
const data = await promises.readFile(path, 'utf-8');
return JSON.parse(data) as Catalog;
// TODO(feloy): check version, ...
}

setCatalog(newCatalog: Catalog) {
// TODO(feloy): send message to frontend with new catalog
async setCatalog(newCatalog: Catalog) {
this.catalog = newCatalog;
await this.webview.postMessage({
id: MSG_NEW_CATALOG_STATE,
body: this.catalog,
});
}
}
29 changes: 22 additions & 7 deletions packages/backend/src/studio-api-impl.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import type { TaskRegistry } from './registries/TaskRegistry';
import type { Webview } from '@podman-desktop/api';

import * as fs from 'node:fs';
import { CatalogManager } from './managers/catalogManager';

vi.mock('./ai.json', () => {
return {
Expand All @@ -41,17 +42,34 @@ vi.mock('node:fs', () => {
existsSync: vi.fn(),
promises: {
readFile: vi.fn(),
}
},
};
});

vi.mock('@podman-desktop/api', () => {
return {
fs: {
createFileSystemWatcher: () => ({
onDidCreate: vi.fn(),
onDidDelete: vi.fn(),
onDidChange: vi.fn(),
}),
},
};
});

let studioApiImpl: StudioApiImpl;
let catalogManager;

beforeEach(async () => {
const appUserDirectory = '.';
catalogManager = new CatalogManager(appUserDirectory);

// Creating CatalogManager
catalogManager = new CatalogManager(appUserDirectory, {
postMessage: vi.fn(),
} as unknown as Webview);

// Creating StudioApiImpl
studioApiImpl = new StudioApiImpl(
{
appUserDirectory,
Expand All @@ -60,9 +78,6 @@ beforeEach(async () => {
{} as unknown as TaskRegistry,
{} as unknown as PlayGroundManager,
catalogManager,
{
postMessage: vi.fn(),
} as unknown as Webview,
);
vi.resetAllMocks();
vi.mock('node:fs');
Expand All @@ -84,8 +99,8 @@ describe('invalid user catalog', () => {
);
});

test('expect error if id does not correspond to any model', () => {
expect(() => studioApiImpl.getModelById('unknown')).toThrowError('No model found having id unknown');
test('expect error if id does not correspond to any model', async () => {
await expect(() => studioApiImpl.getModelById('unknown')).rejects.toThrowError('No model found having id unknown');
});
});

Expand Down
72 changes: 7 additions & 65 deletions packages/backend/src/studio-api-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,10 @@ import type { Task } from '@shared/src/models/ITask';
import type { PlayGroundManager } from './managers/playground';
import * as podmanDesktopApi from '@podman-desktop/api';
import type { QueryState } from '@shared/src/models/IPlaygroundQueryState';
import type { Catalog } from '@shared/src/models/ICatalog';
import { MSG_NEW_CATALOG_STATE } from '@shared/Messages';

import * as path from 'node:path';
import type { CatalogManager } from './managers/catalogManager';
import type { Catalog } from '@shared/src/models/ICatalog';

export const RECENT_CATEGORY_ID = 'recent-category';

Expand All @@ -25,67 +24,10 @@ export class StudioApiImpl implements StudioAPI {
private taskRegistry: TaskRegistry,
private playgroundManager: PlayGroundManager,
private catalogManager: CatalogManager,
private webview: podmanDesktopApi.Webview,
) {}

async loadCatalog() {
const catalogPath = path.resolve(this.applicationManager.appUserDirectory, 'catalog.json');

try {
this.watchCatalogFile(catalogPath); // do not await, we want to do this async
} catch (err: unknown) {
console.error("unable to watch catalog file, changes to the catalog file won't be reflected to the UI", err);
}

try {
if (!fs.existsSync(catalogPath)) {
await this.setCatalog(defaultCatalog);
return;
}
const cat = await this.readAndAnalyzeCatalog(catalogPath);
await this.setCatalog(cat);
} catch (err: unknown) {
console.error('unable to read catalog file, reverting to default catalog', err);
await this.setCatalog(defaultCatalog);
}
}

watchCatalogFile(path: string) {
const watcher = podmanDesktopApi.fs.createFileSystemWatcher(path);
watcher.onDidCreate(async () => {
try {
const cat = await this.readAndAnalyzeCatalog(path);
await this.setCatalog(cat);
} catch (err: unknown) {
console.error('unable to read created catalog file, continue using default catalog', err);
}
});
watcher.onDidDelete(async () => {
console.log('user catalog file deleted, reverting to default catalog');
await this.setCatalog(defaultCatalog);
});
watcher.onDidChange(async () => {
try {
const cat = await this.readAndAnalyzeCatalog(path);
await this.setCatalog(cat);
} catch (err: unknown) {
console.error('unable to read modified catalog file, reverting to default catalog', err);
}
});
}

async readAndAnalyzeCatalog(path: string): Promise<Catalog> {
const data = await fs.promises.readFile(path, 'utf-8');
return JSON.parse(data) as Catalog;
// TODO(feloy): check version, ...
}

async setCatalog(newCatalog: Catalog) {
this.catalog = newCatalog;
await this.webview.postMessage({
id: MSG_NEW_CATALOG_STATE,
body: this.catalog,
});
async ping(): Promise<string> {
return 'pong';
}

async openURL(url: string): Promise<boolean> {
Expand All @@ -96,10 +38,6 @@ export class StudioApiImpl implements StudioAPI {
return this.recipeStatusRegistry.getStatus(recipeId);
}

async ping(): Promise<string> {
return 'pong';
}

async getRecentRecipes(): Promise<Recipe[]> {
return []; // no recent implementation for now
}
Expand Down Expand Up @@ -187,4 +125,8 @@ export class StudioApiImpl implements StudioAPI {
async getPlaygroundStates(): Promise<QueryState[]> {
return this.playgroundManager.getState();
}

async getCatalog(): Promise<Catalog> {
return this.catalogManager.getCatalog();
}
}
7 changes: 5 additions & 2 deletions packages/backend/src/studio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,11 @@ export class Studio {
const recipeStatusRegistry = new RecipeStatusRegistry(taskRegistry);
const applicationManager = new ApplicationManager(gitManager, recipeStatusRegistry, this.#extensionContext);
this.playgroundManager = new PlayGroundManager(this.#panel.webview);
this.catalogManager = new CatalogManager(applicationManager.appUserDirectory);
// Create catalog manager, responsible for loading the catalog files and watching for changes
this.catalogManager = new CatalogManager(
applicationManager.appUserDirectory,
this.#panel.webview,
);

// Creating StudioApiImpl
this.studioApi = new StudioApiImpl(
Expand All @@ -104,7 +108,6 @@ export class Studio {
taskRegistry,
this.playgroundManager,
this.catalogManager,
this.#panel.webview,
);

await this.catalogManager.loadCatalog();
Expand Down

0 comments on commit 1d715be

Please sign in to comment.