update lms app runtime integration
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "lms",
|
||||
"version": "1.0.6",
|
||||
"version": "1.0.7",
|
||||
"description": "Autonomy Studio LMS Electron app",
|
||||
"main": "./out/main/index.js",
|
||||
"author": {
|
||||
|
||||
+24
-3
@@ -3185,6 +3185,22 @@ function createSplashWindow(): void {
|
||||
})
|
||||
}
|
||||
|
||||
function updateSplashStatus(message: string): void {
|
||||
if (!splashWindow || splashWindow.isDestroyed()) return
|
||||
const safeMessage = JSON.stringify(message)
|
||||
splashWindow.webContents.executeJavaScript(
|
||||
`window.setSplashStatus && window.setSplashStatus(${safeMessage})`
|
||||
).catch(() => undefined)
|
||||
}
|
||||
|
||||
function closeSplashAndShowMain(): void {
|
||||
if (mainWindow && !mainWindow.isDestroyed() && !mainWindow.isVisible()) {
|
||||
splashWindow?.close()
|
||||
splashWindow = null
|
||||
mainWindow.show()
|
||||
}
|
||||
}
|
||||
|
||||
function createWindow(): void {
|
||||
const { width, height } = screen.getPrimaryDisplay().workAreaSize
|
||||
|
||||
@@ -3210,10 +3226,9 @@ function createWindow(): void {
|
||||
suppressSystemContextMenu(mainWindow)
|
||||
mainWindow.once('ready-to-show', () => {
|
||||
setTimeout(() => {
|
||||
splashWindow?.close()
|
||||
splashWindow = null
|
||||
mainWindow?.show()
|
||||
updateSplashStatus('로그인 세션 확인 중...')
|
||||
}, 1100)
|
||||
setTimeout(closeSplashAndShowMain, 8000)
|
||||
})
|
||||
mainWindow.on('closed', () => {
|
||||
mainWindow = null
|
||||
@@ -3227,6 +3242,12 @@ function createWindow(): void {
|
||||
}
|
||||
|
||||
function registerLocalWorkspaceHandlers(): void {
|
||||
ipcMain.on('lms-boot-status', (_event, message: string) => {
|
||||
updateSplashStatus(message)
|
||||
})
|
||||
ipcMain.on('lms-boot-done', () => {
|
||||
closeSplashAndShowMain()
|
||||
})
|
||||
ipcMain.handle('local-workspace:modules:list', (_event, workspaceRoot?: string | null, courseModules?: CourseModuleInput[] | null) => collectAvailableModules(workspaceRoot, courseModules))
|
||||
ipcMain.handle('local-workspace:modules:install', (_event, moduleName: string, workspaceRoot?: string | null, folderName?: string | null, templateRepositoryUrl?: string | null, studentRepositoryUrl?: string | null, options?: ModuleInstallOptions | null) => installModuleFromCache(moduleName, workspaceRoot, folderName, templateRepositoryUrl, studentRepositoryUrl, options))
|
||||
ipcMain.handle('local-workspace:modules:delete', (_event, moduleName: string, workspaceRoot?: string | null, folderName?: string | null) => deleteWorkspaceModule(moduleName, workspaceRoot, folderName))
|
||||
|
||||
@@ -84,6 +84,10 @@ console.info('[lms-preload] launcher auth resolved', {
|
||||
|
||||
contextBridge.exposeInMainWorld('electron', electronAPI)
|
||||
contextBridge.exposeInMainWorld('launcherAuth', launcherAuth)
|
||||
contextBridge.exposeInMainWorld('lmsBootSplash', {
|
||||
status: (message: string) => ipcRenderer.send('lms-boot-status', message),
|
||||
done: () => ipcRenderer.send('lms-boot-done')
|
||||
})
|
||||
contextBridge.exposeInMainWorld('titlebar', {
|
||||
minimize: () => ipcRenderer.send('titlebar-minimize'),
|
||||
maximize: () => ipcRenderer.send('titlebar-maximize'),
|
||||
|
||||
@@ -77,14 +77,12 @@
|
||||
<script>
|
||||
document.getElementById('splash-image').src = './assets/splash.png'
|
||||
|
||||
const texts = ['학습 환경 준비 중...', '커리큘럼 불러오는 중...']
|
||||
const el = document.getElementById('loading-text')
|
||||
let index = 0
|
||||
|
||||
setInterval(() => {
|
||||
index = (index + 1) % texts.length
|
||||
el.textContent = texts[index]
|
||||
}, 1200)
|
||||
window.setSplashStatus = (message) => {
|
||||
if (typeof message === 'string' && message.trim()) {
|
||||
el.textContent = message
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -2662,6 +2662,18 @@ function LocalPcWorkspaceMockup({
|
||||
)
|
||||
}
|
||||
|
||||
function BootLoadingOverlay({ message }: { message: string }): React.JSX.Element {
|
||||
return (
|
||||
<div className="fixed inset-0 z-[200] grid place-items-center bg-black/24 backdrop-blur-[3px]">
|
||||
<section className="w-[324px] rounded-xl border border-white/14 bg-[rgba(18,24,36,0.78)] px-6 py-5 text-center shadow-[0_24px_80px_rgba(0,0,0,0.42),inset_0_1px_0_rgba(255,255,255,0.10)] backdrop-blur-2xl">
|
||||
<div className="mx-auto mb-4 h-9 w-9 animate-spin rounded-full border-2 border-white/12 border-t-[#4f8dff]" />
|
||||
<p className="text-[14px] font-bold text-white">Autonomy Studio LMS</p>
|
||||
<p className="mt-2 text-[12px] font-semibold text-white/58">{message}</p>
|
||||
</section>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default function App(): React.JSX.Element {
|
||||
const restoredStudioSessionRef = useRef<StudioRuntimeSessionState | null>(readStudioRuntimeSessionState())
|
||||
const previousWeekStateRef = useRef<Record<number, CurriculumWeek['state']>>({})
|
||||
@@ -2683,6 +2695,8 @@ export default function App(): React.JSX.Element {
|
||||
const [authSession, setAuthSession] = useState<LmsAuthSession | null>(null)
|
||||
const authSessionRef = useRef<LmsAuthSession | null>(null)
|
||||
const [authReady, setAuthReady] = useState(false)
|
||||
const [studentCoursesLoading, setStudentCoursesLoading] = useState(false)
|
||||
const [curriculumLoading, setCurriculumLoading] = useState(false)
|
||||
const [sidebarCollapsed, setSidebarCollapsed] = useState(false)
|
||||
const [userSidebarCollapsed, setUserSidebarCollapsed] = useState(false)
|
||||
const [platformModalOpen, setPlatformModalOpen] = useState(false)
|
||||
@@ -2939,6 +2953,7 @@ export default function App(): React.JSX.Element {
|
||||
const loadStudentCourses = useCallback(async (options: { autoSelectSingle?: boolean } = {}): Promise<void> => {
|
||||
if (!authReady || !authSession?.accessToken) return
|
||||
|
||||
setStudentCoursesLoading(true)
|
||||
try {
|
||||
const courses = await fetchStudentCourses(fetchWithFreshAuth)
|
||||
|
||||
@@ -2967,6 +2982,8 @@ export default function App(): React.JSX.Element {
|
||||
setStudentCourses([])
|
||||
setStudentCoursesLoaded(true)
|
||||
setCourseSelectionVisible(true)
|
||||
} finally {
|
||||
setStudentCoursesLoading(false)
|
||||
}
|
||||
}, [authReady, authSession?.accessToken, fetchWithFreshAuth])
|
||||
|
||||
@@ -2982,6 +2999,7 @@ export default function App(): React.JSX.Element {
|
||||
const loadCurriculum = useCallback(async (): Promise<void> => {
|
||||
if (!authReady || !studentCoursesLoaded || courseSelectionVisible || !selectedCourseId) return
|
||||
|
||||
setCurriculumLoading(true)
|
||||
try {
|
||||
const payload = await fetchCurriculum(fetchWithFreshAuth, selectedCourseId)
|
||||
const nextWeeks = payload?.weeks ?? []
|
||||
@@ -3023,6 +3041,8 @@ export default function App(): React.JSX.Element {
|
||||
setLearningStats([])
|
||||
setPlatformOptions([])
|
||||
setSelectedWeekState(null)
|
||||
} finally {
|
||||
setCurriculumLoading(false)
|
||||
}
|
||||
}, [authReady, authSession?.accessToken, courseSelectionVisible, fetchWithFreshAuth, selectedCourseId, selectedWeekState?.week, studentCoursesLoaded])
|
||||
|
||||
@@ -3924,6 +3944,22 @@ export default function App(): React.JSX.Element {
|
||||
setMaterialDownloadingResourceIds((current) => current.filter((id) => id !== resource.id))
|
||||
}
|
||||
}
|
||||
const bootLoadingMessage = !authReady
|
||||
? '로그인 세션 확인 중...'
|
||||
: authSession?.accessToken && (!studentCoursesLoaded || studentCoursesLoading)
|
||||
? '강좌 정보 불러오는 중...'
|
||||
: authSession?.accessToken && curriculumLoading
|
||||
? '커리큘럼 및 플랫폼 정보 가져오는 중...'
|
||||
: ''
|
||||
const bootLoadingVisible = Boolean(bootLoadingMessage)
|
||||
useEffect(() => {
|
||||
if (bootLoadingMessage) {
|
||||
window.lmsBootSplash?.status(bootLoadingMessage)
|
||||
return
|
||||
}
|
||||
|
||||
window.lmsBootSplash?.done()
|
||||
}, [bootLoadingMessage])
|
||||
|
||||
return (
|
||||
<div className="h-screen w-screen overflow-hidden bg-[#0a0b0e]">
|
||||
@@ -4219,6 +4255,7 @@ export default function App(): React.JSX.Element {
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
{bootLoadingVisible && <BootLoadingOverlay message={bootLoadingMessage} />}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Vendored
+4
@@ -37,6 +37,10 @@ interface Window {
|
||||
handoffToken: string | null
|
||||
audienceApp: string
|
||||
}
|
||||
lmsBootSplash?: {
|
||||
status: (message: string) => void
|
||||
done: () => void
|
||||
}
|
||||
titlebar: {
|
||||
minimize: () => void
|
||||
maximize: () => void
|
||||
|
||||
Reference in New Issue
Block a user