diff --git a/src/lms-renderer/env.d.ts b/src/lms-renderer/env.d.ts index 9cdbe5b..b33e123 100644 --- a/src/lms-renderer/env.d.ts +++ b/src/lms-renderer/env.d.ts @@ -65,7 +65,7 @@ interface Window { delete: (moduleName: string, path: string, workspaceRoot?: string, folderName?: string) => Promise<{ ok: boolean }> } modules: { - list: (workspaceRoot?: string, modules?: Array<{ sortOrder?: number | null; category: string; name: string; folderName: string; templateRepositoryUrl?: string | null; sourceType?: string | null; prebuiltArtifacts?: ModulePrebuiltArtifact[] | null }>) => Promise<{ + list: (workspaceRoot?: string, modules?: Array<{ sortOrder?: number | null; category: string; name: string; folderName: string; templateRepositoryUrl?: string | null; sourceType?: string | null; prebuiltArtifacts?: ModulePrebuiltArtifact[] | null; dockerImage?: string | null }>) => Promise<{ cacheRoot: string workspaceRoot: string | null modules: Array<{ @@ -77,6 +77,7 @@ interface Window { sourcePath: string workspacePath: string | null templateRepositoryUrl?: string | null + dockerImage?: string | null parameters: string[] cpu: number | null memory: number | null @@ -101,12 +102,12 @@ interface Window { } }> delete: (moduleName: string, workspaceRoot?: string, folderName?: string) => Promise<{ ok: boolean }> - start: (moduleName: string, workspaceRoot?: string, folderName?: string, rosParams?: string, gpuEnabled?: boolean, rosDomainId?: string, runtimeImages?: RuntimeImageArtifact[] | null) => Promise<{ ok: boolean; message: string }> - build: (moduleName: string, workspaceRoot?: string, folderName?: string, gpuEnabled?: boolean, rosDomainId?: string, runtimeImages?: RuntimeImageArtifact[] | null) => Promise<{ ok: boolean; message: string }> + start: (moduleName: string, workspaceRoot?: string, folderName?: string, rosParams?: string, gpuEnabled?: boolean, rosDomainId?: string, runtimeImages?: RuntimeImageArtifact[] | null, dockerImage?: string | null) => Promise<{ ok: boolean; message: string }> + build: (moduleName: string, workspaceRoot?: string, folderName?: string, gpuEnabled?: boolean, rosDomainId?: string, runtimeImages?: RuntimeImageArtifact[] | null, dockerImage?: string | null, rosParams?: string) => Promise<{ ok: boolean; message: string }> stop: (moduleName: string, workspaceRoot?: string, folderName?: string) => Promise<{ ok: boolean; message: string }> stopMany: (modules: Array<{ moduleName: string; folderName?: string | null }>, workspaceRoot?: string) => Promise<{ ok: boolean; message: string }> stopRunning: () => Promise<{ ok: boolean; message: string }> - restart: (moduleName: string, workspaceRoot?: string, folderName?: string, rosParams?: string, gpuEnabled?: boolean, rosDomainId?: string, runtimeImages?: RuntimeImageArtifact[] | null) => Promise<{ ok: boolean; message: string }> + restart: (moduleName: string, workspaceRoot?: string, folderName?: string, rosParams?: string, gpuEnabled?: boolean, rosDomainId?: string, runtimeImages?: RuntimeImageArtifact[] | null, dockerImage?: string | null) => Promise<{ ok: boolean; message: string }> logs: (moduleName: string, workspaceRoot?: string, folderName?: string) => Promise<{ ok: boolean; logs: string; message?: string }> updateParameters: (moduleName: string, workspaceRoot?: string, folderName?: string, rosParams?: string) => Promise<{ ok: boolean; parameters: string[] }> } diff --git a/src/lms-renderer/features/workspace/useWorkspaceModuleControl.ts b/src/lms-renderer/features/workspace/useWorkspaceModuleControl.ts index d8083f0..afb3d8a 100644 --- a/src/lms-renderer/features/workspace/useWorkspaceModuleControl.ts +++ b/src/lms-renderer/features/workspace/useWorkspaceModuleControl.ts @@ -180,7 +180,7 @@ export function useWorkspaceModuleControl({ for (const module of targets) { const result = remoteWorkspace ? await remoteModuleStart(module) - : await window.localWorkspace.modules.start(module.name, clonePathPreview, module.folderName, getModuleRosParams(module), sourceSettings.gpuEnabled, sourceSettings.rosDomainId, activeRuntimeImages) + : await window.localWorkspace.modules.start(module.name, clonePathPreview, module.folderName, getModuleRosParams(module), sourceSettings.gpuEnabled, sourceSettings.rosDomainId, activeRuntimeImages, module.dockerImage) if (!result.ok) throw new Error(result.message) } await loadAvailableModules({ silent: true }) @@ -256,14 +256,14 @@ export function useWorkspaceModuleControl({ : action === 'build' ? remoteWorkspace ? await window.remoteWorkspace.modules.build(getRemoteWorkspaceTarget(), module.name, module.folderName, sourceSettings.gpuEnabled, sourceSettings.rosDomainId, activeRuntimeImages) - : await window.localWorkspace.modules.build(module.name, clonePathPreview, module.folderName, sourceSettings.gpuEnabled, sourceSettings.rosDomainId, activeRuntimeImages) + : await window.localWorkspace.modules.build(module.name, clonePathPreview, module.folderName, sourceSettings.gpuEnabled, sourceSettings.rosDomainId, activeRuntimeImages, module.dockerImage, getModuleRosParams(module)) : action === 'restart' ? remoteWorkspace ? await remoteModuleRestart(module) - : await window.localWorkspace.modules.restart(module.name, clonePathPreview, module.folderName, getModuleRosParams(module), sourceSettings.gpuEnabled, sourceSettings.rosDomainId, activeRuntimeImages) + : await window.localWorkspace.modules.restart(module.name, clonePathPreview, module.folderName, getModuleRosParams(module), sourceSettings.gpuEnabled, sourceSettings.rosDomainId, activeRuntimeImages, module.dockerImage) : remoteWorkspace ? await remoteModuleStart(module) - : await window.localWorkspace.modules.start(module.name, clonePathPreview, module.folderName, getModuleRosParams(module), sourceSettings.gpuEnabled, sourceSettings.rosDomainId, activeRuntimeImages) + : await window.localWorkspace.modules.start(module.name, clonePathPreview, module.folderName, getModuleRosParams(module), sourceSettings.gpuEnabled, sourceSettings.rosDomainId, activeRuntimeImages, module.dockerImage) if (!result.ok) throw new Error(result.message) await loadAvailableModules({ silent: true }) const actionLabel = action === 'stop' diff --git a/src/lmsElectronAdapter.ts b/src/lmsElectronAdapter.ts index b8b5448..33fb0a9 100644 --- a/src/lmsElectronAdapter.ts +++ b/src/lmsElectronAdapter.ts @@ -159,6 +159,7 @@ const localModules = { sourcePath: module.sourcePath ?? module.workspacePath ?? '', workspacePath: module.workspacePath ?? null, templateRepositoryUrl: module.templateRepositoryUrl ?? null, + dockerImage: module.dockerImage ?? null, parameters: Array.isArray(module.parameters) ? module.parameters : [], cpu: running ? cpu : null, memory: running ? memory : null, @@ -173,10 +174,12 @@ const localModules = { folderName?: string, templateRepositoryUrl?: string | null, studentRepositoryUrl?: string | null, + options?: { runtimeImages?: unknown }, ) { const result = await bridgeRequest<{ ok: boolean; workspacePath?: string }>('/api/modules/install', { workspaceRoot, module: moduleInput(name, folderName, { templateRepositoryUrl, studentRepositoryUrl }), + runtimeImages: options?.runtimeImages, }) return { ok: result.ok, @@ -195,21 +198,24 @@ const localModules = { }, } }, - async start(name: string, workspaceRoot?: string, folderName?: string, rosParams?: string, gpuEnabled?: boolean, rosDomainId?: string) { + async start(name: string, workspaceRoot?: string, folderName?: string, rosParams?: string, gpuEnabled?: boolean, rosDomainId?: string, runtimeImages?: unknown, dockerImage?: string | null) { return bridgeRequest<{ ok: boolean; message: string }>('/api/modules/start', { workspaceRoot, - module: moduleInput(name, folderName), + module: moduleInput(name, folderName, { dockerImage }), rosParams, gpuEnabled, rosDomainId, + runtimeImages, }) }, - async build(name: string, workspaceRoot?: string, folderName?: string, gpuEnabled?: boolean, rosDomainId?: string) { + async build(name: string, workspaceRoot?: string, folderName?: string, gpuEnabled?: boolean, rosDomainId?: string, runtimeImages?: unknown, dockerImage?: string | null, rosParams?: string) { return bridgeRequest<{ ok: boolean; message: string }>('/api/modules/build', { workspaceRoot, - module: moduleInput(name, folderName), + module: moduleInput(name, folderName, { dockerImage }), gpuEnabled, rosDomainId, + runtimeImages, + rosParams, }) }, async stop(name: string, workspaceRoot?: string, folderName?: string) { @@ -225,9 +231,9 @@ const localModules = { async stopRunning() { return bridgeRequest<{ ok: boolean; message: string }>('/api/modules/stop-running', {}) }, - async restart(name: string, workspaceRoot?: string, folderName?: string, rosParams?: string, gpuEnabled?: boolean, rosDomainId?: string) { + async restart(name: string, workspaceRoot?: string, folderName?: string, rosParams?: string, gpuEnabled?: boolean, rosDomainId?: string, runtimeImages?: unknown, dockerImage?: string | null) { await localModules.stop(name, workspaceRoot, folderName) - return localModules.start(name, workspaceRoot, folderName, rosParams, gpuEnabled, rosDomainId) + return localModules.start(name, workspaceRoot, folderName, rosParams, gpuEnabled, rosDomainId, runtimeImages, dockerImage) }, async logs(name: string, workspaceRoot?: string, folderName?: string) { return bridgeRequest<{ ok: boolean; logs: string; message?: string }>('/api/modules/logs', {