feat: add LMS web client
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
import { useCallback, useEffect } from 'react'
|
||||
import { LMS_API_BASE_URL } from '../../config/appConfig'
|
||||
import type { CurriculumWeek } from '../curriculum/types'
|
||||
import type { ModulePrebuiltArtifact, ModuleRow, RuntimeImageArtifact } from './types'
|
||||
|
||||
type UseRemoteWorkspaceRuntimeOptions = {
|
||||
availableModules: ModuleRow[]
|
||||
curriculumModules: CurriculumWeek['modules']
|
||||
courseKey: string
|
||||
weekNumber: number
|
||||
clonePathPreview: string
|
||||
remoteWorkspace: boolean
|
||||
remoteWorkspaceTargetKey: string
|
||||
activeRuntimeImages: RuntimeImageArtifact[]
|
||||
getFreshAccessToken: () => Promise<string>
|
||||
getRemoteWorkspaceTarget: () => RemoteWorkspaceTarget
|
||||
saveDirtyFilesForModule: (module: ModuleRow) => Promise<void>
|
||||
onRegisterStopRunningModules?: (handler: (() => Promise<void>) | null) => void
|
||||
}
|
||||
|
||||
type UseRemoteWorkspaceRuntimeResult = {
|
||||
prepareRemoteRuntimeModule: (module: ModuleRow) => Promise<void>
|
||||
}
|
||||
|
||||
export function useRemoteWorkspaceRuntime({
|
||||
availableModules,
|
||||
curriculumModules,
|
||||
courseKey,
|
||||
weekNumber,
|
||||
clonePathPreview,
|
||||
remoteWorkspace,
|
||||
remoteWorkspaceTargetKey,
|
||||
activeRuntimeImages,
|
||||
getFreshAccessToken,
|
||||
getRemoteWorkspaceTarget,
|
||||
saveDirtyFilesForModule,
|
||||
onRegisterStopRunningModules
|
||||
}: UseRemoteWorkspaceRuntimeOptions): UseRemoteWorkspaceRuntimeResult {
|
||||
const prepareRemoteRuntimeModule = useCallback(async (module: ModuleRow): Promise<void> => {
|
||||
const requestAccessToken = await getFreshAccessToken()
|
||||
await saveDirtyFilesForModule(module)
|
||||
|
||||
const response = await fetch(`${LMS_API_BASE_URL}/studio/repositories/prepare`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `Bearer ${requestAccessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
courseId: courseKey,
|
||||
week: weekNumber,
|
||||
moduleName: module.name,
|
||||
folderName: module.folderName,
|
||||
templateRepositoryUrl: module.templateRepositoryUrl
|
||||
})
|
||||
})
|
||||
if (!response.ok) throw new Error(await response.text())
|
||||
const prepared = await response.json() as {
|
||||
repositoryUrlWithToken?: string
|
||||
templateRepositoryUrlWithToken?: string
|
||||
templateRepositoryUrl?: string
|
||||
prebuiltArtifacts?: ModulePrebuiltArtifact[] | null
|
||||
}
|
||||
|
||||
const submitResult = await window.localWorkspace.git.submit(
|
||||
module.name,
|
||||
clonePathPreview,
|
||||
module.folderName,
|
||||
`Run: ${weekNumber}주차 ${module.name}`,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined
|
||||
)
|
||||
if (!submitResult.ok && !submitResult.message.includes('제출할 변경사항이 없습니다')) {
|
||||
throw new Error(`[${module.name}] ${submitResult.message}`)
|
||||
}
|
||||
|
||||
const templateRepositoryUrl = prepared.templateRepositoryUrlWithToken ?? prepared.templateRepositoryUrl ?? module.templateRepositoryUrl
|
||||
await window.remoteWorkspace.modules.install(
|
||||
getRemoteWorkspaceTarget(),
|
||||
module.name,
|
||||
module.folderName,
|
||||
templateRepositoryUrl,
|
||||
prepared.repositoryUrlWithToken,
|
||||
{
|
||||
prebuiltArtifacts: prepared.prebuiltArtifacts ?? module.prebuiltArtifacts ?? null,
|
||||
runtimeImages: activeRuntimeImages
|
||||
}
|
||||
)
|
||||
}, [
|
||||
activeRuntimeImages,
|
||||
clonePathPreview,
|
||||
courseKey,
|
||||
getFreshAccessToken,
|
||||
getRemoteWorkspaceTarget,
|
||||
saveDirtyFilesForModule,
|
||||
weekNumber
|
||||
])
|
||||
|
||||
const stopRunningWorkspaceModules = useCallback(async (): Promise<void> => {
|
||||
if (remoteWorkspace) {
|
||||
const moduleMap = new Map<string, { moduleName: string; folderName?: string | null; sortOrder?: number | null }>()
|
||||
for (const module of availableModules) {
|
||||
moduleMap.set(module.name, {
|
||||
moduleName: module.name,
|
||||
folderName: module.folderName,
|
||||
sortOrder: module.sortOrder
|
||||
})
|
||||
}
|
||||
for (const module of curriculumModules ?? []) {
|
||||
if (!moduleMap.has(module.name)) {
|
||||
moduleMap.set(module.name, {
|
||||
moduleName: module.name,
|
||||
folderName: module.folderName,
|
||||
sortOrder: module.sortOrder
|
||||
})
|
||||
}
|
||||
}
|
||||
const modules = Array.from(moduleMap.values())
|
||||
.sort((left, right) => (right.sortOrder ?? 0) - (left.sortOrder ?? 0))
|
||||
.map(({ moduleName, folderName }) => ({ moduleName, folderName }))
|
||||
if (!modules.length) return
|
||||
await window.remoteWorkspace.modules.resetSession(getRemoteWorkspaceTarget(), modules).catch(() => ({ ok: false, message: '플랫폼 초기화 실패' }))
|
||||
return
|
||||
}
|
||||
await window.localWorkspace.modules.stopRunning().catch(() => ({ ok: false, message: '모듈 중지 실패' }))
|
||||
}, [availableModules, curriculumModules, getRemoteWorkspaceTarget, remoteWorkspace, remoteWorkspaceTargetKey])
|
||||
|
||||
useEffect(() => {
|
||||
onRegisterStopRunningModules?.(stopRunningWorkspaceModules)
|
||||
return () => onRegisterStopRunningModules?.(null)
|
||||
}, [onRegisterStopRunningModules, stopRunningWorkspaceModules])
|
||||
|
||||
return {
|
||||
prepareRemoteRuntimeModule
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user