openlearn-next 0.7.12 → 0.7.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/cli-data.mjs +2 -2
- package/cli-doctor.mjs +2 -1
- package/dist/assets/{AcademicYearFilter-Dm3no4Nb.js → AcademicYearFilter-pCzZgimU.js} +1 -1
- package/dist/assets/ActivityWorkspaceWidget-KJQdLnvf.js +1 -0
- package/dist/assets/AdminDirectoryView-DDxX8RO2.js +5 -0
- package/dist/assets/AssessmentCenter-D5cVUqvy.js +1 -0
- package/dist/assets/{AssignmentFilePreview-dVhnTYmq.js → AssignmentFilePreview-DK29gdpQ.js} +2 -2
- package/dist/assets/BatchPickerModal-Cw4OZqOJ.js +1 -0
- package/dist/assets/ClassesView-Czx7hU2V.js +32 -0
- package/dist/assets/ClassroomCountdownWidget-BeAM37Cq.js +2 -0
- package/dist/assets/CloudDriveModal-GNZzWVCP.js +1 -0
- package/dist/assets/ComputerLabView-C_0c7sjz.js +1 -0
- package/dist/assets/CourseManagement-DzLB0Xmp.js +1 -0
- package/dist/assets/CourseWizardModal-DmQu237c.js +3 -0
- package/dist/assets/CoursewareHubPanel-Xn5WbXg9.js +1 -0
- package/dist/assets/Dashboard-CX83FUeF.js +8 -0
- package/dist/assets/ExportWeightModal-C0SuUhHM.js +1 -0
- package/dist/assets/HelpTour-D8hVFA6N.js +1 -0
- package/dist/assets/HelpView-C0PP_51D.js +204 -0
- package/dist/assets/ImportLessonsModal-p8Uc1U_h.js +1 -0
- package/dist/assets/{ImportModal-Ct0I5cAL.js → ImportModal-DNaPHV0I.js} +2 -2
- package/dist/assets/InteractiveCoursewareViewer-D9YTgasv.js +1 -0
- package/dist/assets/InteractiveWhiteboard-CHYQfRjR.js +19 -0
- package/dist/assets/LazyCourseware-dtuOSiyR.js +2 -0
- package/dist/assets/LazyWhiteboard-DuBKAh4-.js +2 -0
- package/dist/assets/LessonEditorView-BgI7C_FK.js +1 -0
- package/dist/assets/LiveClassroomView-CJK_WMqD.js +67 -0
- package/dist/assets/NotificationDetailModal-BVYuS4uR.js +1 -0
- package/dist/assets/PluginView-CpWjy0Xf.js +66 -0
- package/dist/assets/ProcessLogsModal-D-Ez_YZA.js +1 -0
- package/dist/assets/QuizGeneratorModal-Lf5QMvkq.js +1 -0
- package/dist/assets/RevealPresentationWrapper-Dnf4v72i.js +48 -0
- package/dist/assets/StudentAssignmentEvalPanel-C-7YSfEQ.js +1 -0
- package/dist/assets/StudentAssignmentView-LuMaNpq8.js +1 -0
- package/dist/assets/StudentLessonView-DUG8I1Zy.js +1 -0
- package/dist/assets/StudentView-mMwGPiiF.js +2 -0
- package/dist/assets/SystemResourceLibraryModal-LUDNOwgW.js +1 -0
- package/dist/assets/TeacherView-ofB-3SEJ.js +2 -0
- package/dist/assets/TimetableView-DrZbyCOQ.js +6 -0
- package/dist/assets/{UTIF-BtQhea94.js → UTIF-DbcUtUKZ.js} +1 -1
- package/dist/assets/index-CG-g_9my.css +1 -0
- package/dist/assets/index-CLtQGl25.js +169 -0
- package/dist/assets/{index.es-CijVATXs.js → index.es-D1mLdmCj.js} +1 -1
- package/dist/assets/keyboard-Rs007iOv.js +1 -0
- package/dist/assets/{pluginParsers-DD3QL1Xl.js → pluginParsers-C46aCYkl.js} +1 -1
- package/dist/assets/student-workspace-BFPfR77J.js +1 -0
- package/dist/assets/{vendor-charts-skggaP9D.js → vendor-charts-CK-CU_m7.js} +1 -1
- package/dist/assets/{vendor-icons-CaXLq01o.js → vendor-icons-__JLt-CP.js} +2 -2
- package/dist/assets/{vendor-konva-BOuJWFuE.js → vendor-konva-DGELdczq.js} +1 -1
- package/dist/assets/{vendor-motion-BFAPOs-b.js → vendor-motion-DtyD8eRQ.js} +1 -1
- package/dist/assets/{vendor-pdf-DVWGghIL.js → vendor-pdf-DNexfcCO.js} +3 -3
- package/dist/assets/{vendor-pptx-BqU7v5zS.js → vendor-pptx-ByQkJ0Xi.js} +178 -178
- package/dist/assets/{vendor-react-DHoBZpn2.js → vendor-react-lfWn1oGs.js} +1 -1
- package/dist/assets/{vendor-utils-BxOuk3id.js → vendor-utils-CsoI4M9x.js} +1 -1
- package/dist/cli-migrator.cjs +23 -7
- package/dist/index.html +10 -6
- package/dist/server.cjs +16125 -9457
- package/docs_plugin_guide.md +1023 -0
- package/migrations/046_logout_clear_site_data.sql +9 -0
- package/migrations/047_third_party_theme_system.sql +55 -0
- package/migrations/048_file_storage_extension.sql +63 -0
- package/migrations/049_ai_personas.sql +25 -0
- package/migrations/050_ai_persona_governance.sql +11 -0
- package/migrations/051_community_registry_url.sql +9 -0
- package/migrations/052_community_install_enabled.sql +12 -0
- package/migrations/053_runtime_admin_policies.sql +28 -0
- package/migrations/054_user_onboarding_tour_status.sql +10 -0
- package/migrations/055_classroom_collab_whiteboard.sql +27 -0
- package/migrations/056_public_student_lookup.sql +9 -0
- package/migrations/README.md +59 -48
- package/migrations/schema-golden.json +98 -2
- package/package.json +8 -6
- package/scripts/assert-node-runtime.mjs +4 -3
- package/dist/assets/ActivityWorkspaceWidget-TtBuNORs.js +0 -1
- package/dist/assets/AdminDirectoryView-D03WOMc-.js +0 -5
- package/dist/assets/AssessmentCenter-MUvoJySb.js +0 -1
- package/dist/assets/BatchPickerModal-QALdhrX6.js +0 -1
- package/dist/assets/ClassesView-CKwlRz-A.js +0 -32
- package/dist/assets/ClassroomCountdownWidget-DyWyForY.js +0 -2
- package/dist/assets/CloudDriveModal-C8UAn3MO.js +0 -1
- package/dist/assets/ComputerLabView-E5b3XTkk.js +0 -1
- package/dist/assets/CourseManagement-3jSlq7lV.js +0 -1
- package/dist/assets/CourseWizardModal-BAkW5VJX.js +0 -3
- package/dist/assets/CoursewareHubPanel-BkjcusjZ.js +0 -1
- package/dist/assets/Dashboard-Ha2fZAqD.js +0 -8
- package/dist/assets/ExportWeightModal-D2Y13384.js +0 -1
- package/dist/assets/HelpTour-DBq2otcV.js +0 -1
- package/dist/assets/HelpView-BVLRnMxl.js +0 -204
- package/dist/assets/ImportLessonsModal-CQlq4b81.js +0 -1
- package/dist/assets/InteractiveCoursewareViewer-DGKh1gO8.js +0 -1
- package/dist/assets/InteractiveWhiteboard-BbZlYpRu.js +0 -65
- package/dist/assets/LazyCourseware-zONqinCM.js +0 -2
- package/dist/assets/LazyWhiteboard-BV98LEZ8.js +0 -2
- package/dist/assets/LessonEditorView-LXRkKxdY.js +0 -1
- package/dist/assets/LiveClassroomView-TaHtHWkY.js +0 -63
- package/dist/assets/NotificationDetailModal-BF_-pn0c.js +0 -1
- package/dist/assets/PluginView-sVMPXae9.js +0 -77
- package/dist/assets/ProcessLogsModal-D97xLgnL.js +0 -1
- package/dist/assets/QuizGeneratorModal-CNY8ISjR.js +0 -1
- package/dist/assets/StudentAssignmentEvalPanel-CUmM5DbT.js +0 -1
- package/dist/assets/StudentAssignmentView-B-1MtwKj.js +0 -1
- package/dist/assets/StudentLessonView-CqrcvVND.js +0 -1
- package/dist/assets/StudentView-Bi9kgSrN.js +0 -2
- package/dist/assets/SystemResourceLibraryModal-DDALKrJC.js +0 -1
- package/dist/assets/TeacherView-C5JmoKHk.js +0 -2
- package/dist/assets/TimetableView-BOLB-kZC.js +0 -6
- package/dist/assets/index-Bc9003lB.js +0 -131
- package/dist/assets/index-D4aq9poS.css +0 -1
- package/dist/assets/student-workspace-C4UgD58C.js +0 -1
- package/dist/assets/vendor-reveal-DcQQzuI9.css +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as d,j as r,R as x}from"./vendor-react-DHoBZpn2.js";import{E as I,i as M}from"./index-Bc9003lB.js";import{L as A}from"./LazyWhiteboard-BV98LEZ8.js";import{S as W}from"./StudentAssignmentEvalPanel-CUmM5DbT.js";import{aq as C,h as z}from"./vendor-icons-CaXLq01o.js";import{ActivityWorkspaceWidget as P}from"./ActivityWorkspaceWidget-TtBuNORs.js";import"./vendor-utils-BxOuk3id.js";import"./vendor-pdf-DVWGghIL.js";import"./vendor-motion-BFAPOs-b.js";import"./vendor-charts-skggaP9D.js";import"./AssignmentFilePreview-dVhnTYmq.js";class w{constructor(){this.providers=new Map}register(e){if(!e||!e.id)throw new Error("WorkspaceSlotRegistry Error: WorkspaceSlotProvider must have a valid ID.");this.providers.set(e.id,e)}unregister(e){return this.providers.delete(e)}getProviders(e){const t=Array.from(this.providers.values()).filter(s=>s.slot===e);return t.sort((s,i)=>(i.priority??0)-(s.priority??0)),Object.freeze(t)}listAll(){return Object.freeze(Array.from(this.providers.values()))}clear(){this.providers.clear()}}const k=d.createContext(null),N=({registry:n,children:e})=>{const[t]=d.useState(()=>n??new w),[,s]=d.useState(0),i=d.useCallback(()=>{s(l=>l+1)},[]),a=d.useCallback(l=>{t.register(l),i()},[t,i]),c=d.useCallback(l=>{t.unregister(l)&&i()},[t,i]),o=d.useCallback(l=>t.getProviders(l),[t]),g=d.useMemo(()=>({registry:t,registerSlotProvider:a,unregisterSlotProvider:c,getSlotProviders:o}),[t,a,c,o]);return r.jsx(k.Provider,{value:g,children:e})},_=()=>{const n=d.useContext(k);if(!n)throw new Error("useWorkspace must be used within a WorkspaceProvider");return n},D=n=>{const{getSlotProviders:e}=_();return e(n)},f=({slot:n,className:e})=>{const t=D(n);return t.length===0?null:r.jsx("div",{className:`workspace-slot workspace-slot-${n.toLowerCase()} ${e??""}`,children:t.map(s=>r.jsx(x.Fragment,{children:s.render()},s.id))})},L=({className:n,children:e})=>r.jsxs("div",{className:`workspace-shell flex flex-col h-screen w-screen overflow-hidden bg-slate-900 text-slate-100 ${n??""}`,children:[r.jsx(f,{slot:"TopBar",className:"w-full flex-none z-30"}),r.jsxs("div",{className:"flex flex-1 overflow-hidden relative",children:[r.jsx(f,{slot:"LeftSidebar",className:"flex-none z-20"}),r.jsxs("main",{className:"flex-1 relative overflow-hidden flex flex-col",children:[r.jsx(f,{slot:"MainCanvas",className:"flex-1 w-full h-full relative"}),e,r.jsx(f,{slot:"BottomPanel",className:"flex-none z-20"})]}),r.jsx(f,{slot:"RightSidebar",className:"flex-none z-20"})]}),r.jsx(f,{slot:"StatusBar",className:"w-full flex-none z-30"}),r.jsx(f,{slot:"FloatingArea",className:"absolute inset-0 pointer-events-none z-40"}),r.jsx(f,{slot:"DialogArea",className:"absolute inset-0 pointer-events-none z-50"})]});var b=(n=>(n[n.Immediate=0]="Immediate",n[n.High=1]="High",n[n.Normal=2]="Normal",n[n.Low=3]="Low",n[n.Idle=4]="Idle",n))(b||{});class E{constructor(){this.subscribers=new Map}subscribe(e,t){const s=String(e);this.subscribers.has(s)||this.subscribers.set(s,new Set);const i=this.subscribers.get(s);return i.add(t),()=>{i.delete(t)}}async publish(e,t,s="runtime.system"){const i={id:`evt_${globalThis.crypto.randomUUID()}`,type:e,payload:t,source:s,timestamp:Date.now()},a=this.subscribers.get(String(e))||new Set,c=this.subscribers.get("*")||new Set,o=[...Array.from(a),...Array.from(c)];return await Promise.all(o.map(g=>Promise.resolve(g(i)).catch(l=>{console.error(`[RuntimeEventBus] Error in subscriber for ${String(e)}:`,l)}))),i}clear(){this.subscribers.clear()}}class O{constructor(e=`rt_${globalThis.crypto.randomUUID()}`){this.listeners=new Set,this.currentState={runtime:{id:e,lifecycle:"Create",startTime:Date.now(),elapsedTime:0},lesson:{},stage:{index:0},activity:{},whiteboard:{objectCount:0,isLocked:!1},teachingObjects:[],students:[],plugin:[],ai:{isGenerating:!1},analytics:{totalInteractions:0,activeStudentCount:0,averageScore:0}}}getState(){return this.currentState}setState(e){this.currentState=Object.freeze(e),this.notify()}updateState(e){this.currentState=Object.freeze({...this.currentState,...e,runtime:e.runtime?{...this.currentState.runtime,...e.runtime}:this.currentState.runtime,lesson:e.lesson?{...this.currentState.lesson,...e.lesson}:this.currentState.lesson,stage:e.stage?{...this.currentState.stage,...e.stage}:this.currentState.stage,activity:e.activity?{...this.currentState.activity,...e.activity}:this.currentState.activity,whiteboard:e.whiteboard?{...this.currentState.whiteboard,...e.whiteboard}:this.currentState.whiteboard,ai:e.ai?{...this.currentState.ai,...e.ai}:this.currentState.ai,analytics:e.analytics?{...this.currentState.analytics,...e.analytics}:this.currentState.analytics}),this.notify()}setLifecycle(e){this.updateState({runtime:{...this.currentState.runtime,lifecycle:e}})}addStudent(e){this.currentState.students.some(s=>s.id===e.id)||this.updateState({students:Object.freeze([...this.currentState.students,e])})}removeStudent(e){this.updateState({students:Object.freeze(this.currentState.students.filter(t=>t.id!==e))})}subscribe(e){return this.listeners.add(e),e(this.getState()),()=>{this.listeners.delete(e)}}notify(){const e=this.getState();for(const t of this.listeners)try{t(e)}catch(s){console.error("[RuntimeStateManager] Listener error:",s)}}}class ${constructor(){this.services=new Map}registerService(e){if(!e.serviceId)throw new Error("[RuntimeServiceRegistry] Service must provide a non-empty serviceId.");this.services.set(e.serviceId,e)}async unregisterService(e){const t=this.services.get(e);return t?(await t.dispose(),this.services.delete(e)):!1}getService(e){return this.services.get(e)}listServices(){return Object.freeze(Array.from(this.services.keys()))}async initializeAll(e){for(const t of this.services.values())await t.initialize(e)}async disposeAll(){for(const e of this.services.values())try{await e.dispose()}catch(t){console.error(`[RuntimeServiceRegistry] Error disposing service ${e.serviceId}:`,t)}this.services.clear()}}class B{constructor(){this.modules=new Map,this.activeModuleIds=new Set}registerModule(e){if(!e.id)throw new Error("[RuntimeModuleRegistry] Module must specify a valid id.");this.modules.set(e.id,e)}async unregisterModule(e,t){const s=this.modules.get(e);return s?(this.activeModuleIds.has(e)&&t&&(await s.stop(t),this.activeModuleIds.delete(e)),await s.dispose(),this.modules.delete(e)):!1}getModule(e){return this.modules.get(e)}listModules(){return Object.freeze(Array.from(this.modules.values()))}async startAll(e){for(const t of this.modules.values())await t.initialize(e),await t.start(e),this.activeModuleIds.add(t.id)}async stopAll(e){for(const t of this.activeModuleIds){const s=this.modules.get(t);if(s)try{await s.stop(e)}catch(i){console.error(`[RuntimeModuleRegistry] Error stopping module ${t}:`,i)}}this.activeModuleIds.clear()}}class U{constructor(){this.taskQueue=[],this.isProcessing=!1,this.timer=null}schedule(e,t,s=b.Normal,i=0,a=3){return new Promise((c,o)=>{const g={id:`tsk_${globalThis.crypto.randomUUID()}`,name:e,priority:s,taskFn:async()=>{i>0&&await new Promise(l=>setTimeout(l,i));try{const l=await t();return c(l),l}catch(l){throw o(l),l}},delayMs:i,maxRetries:a,createdAt:Date.now()};this.taskQueue.push(g),this.sortQueue(),queueMicrotask(()=>{this.processQueue()})})}start(){this.timer||(this.timer=setInterval(()=>{this.processQueue()},50))}stop(){this.timer&&(clearInterval(this.timer),this.timer=null)}getPendingTaskCount(){return this.taskQueue.length}sortQueue(){this.taskQueue.sort((e,t)=>e.priority-t.priority||e.createdAt-t.createdAt)}async processQueue(){if(this.isProcessing||this.taskQueue.length===0)return;this.isProcessing=!0;const e=this.taskQueue.shift();if(e){let t=0;const s=e.maxRetries??1;for(;t<s;)try{await e.taskFn();break}catch(i){t+=1,t>=s&&console.error(`[RuntimeScheduler] Task ${e.name} (${e.id}) failed after ${t} attempts:`,i)}}this.isProcessing=!1}}class T{constructor(){this.rolePermissions=new Map([["Teacher",new Set(["lesson:control","stage:navigate","whiteboard:draw","quiz:submit","plugin:execute","ai:invoke","session:manage"])],["Assistant",new Set(["stage:navigate","whiteboard:draw","quiz:submit","plugin:execute","ai:invoke"])],["Student",new Set(["whiteboard:draw","quiz:submit","ai:invoke","plugin:execute"])],["Observer",new Set([])],["Plugin",new Set(["whiteboard:draw","plugin:execute","ai:invoke"])],["AI",new Set(["stage:navigate","whiteboard:draw","ai:invoke"])]])}hasPermission(e,t){const s=this.rolePermissions.get(e);return s?s.has(t):!1}grantPermission(e,t){this.rolePermissions.has(e)||this.rolePermissions.set(e,new Set),this.rolePermissions.get(e).add(t)}revokePermission(e,t){const s=this.rolePermissions.get(e);s&&s.delete(t)}getRolePermissions(e){const t=this.rolePermissions.get(e);return Object.freeze(t?Array.from(t):[])}}class F{constructor(){this.resources=new Map}registerResource(e,t,s){const i=Array.from(this.resources.values()).find(c=>c.url===e);if(i)return i;const a={id:`res_${globalThis.crypto.randomUUID()}`,type:t,url:e,sizeBytes:s,status:"loaded",cachedAt:Date.now()};return this.resources.set(a.id,a),a}getResource(e){return this.resources.get(e)}listResources(e){const t=Array.from(this.resources.values());return Object.freeze(e?t.filter(s=>s.type===e):t)}removeResource(e){return this.resources.delete(e)}clear(){this.resources.clear()}}class H{constructor(){this.snapshots=new Map}takeSnapshot(e,t,s,i){const a={snapshotId:`snap_${globalThis.crypto.randomUUID()}`,timestamp:Date.now(),stateTree:JSON.parse(JSON.stringify(e)),activeServices:[...t],loadedModules:[...s],resources:[...i]};return this.snapshots.set(a.snapshotId,a),this.lastAutoSnapshot=a,a}getLatestSnapshot(){return this.lastAutoSnapshot}getSnapshot(e){return this.snapshots.get(e)}clear(){this.snapshots.clear(),this.lastAutoSnapshot=void 0}}class Q{constructor(){this.hooks=new Map}registerHook(e,t){this.hooks.has(e)||this.hooks.set(e,new Set);const s=this.hooks.get(e);return s.add(t),()=>{s.delete(t)}}async executeHook(e,t,s){const i=this.hooks.get(e);if(!(!i||i.size===0))for(const a of i)try{await a(t,s)}catch(c){console.error(`[RuntimeHooksManager] Error executing hook "${e}":`,c)}}clear(){this.hooks.clear()}}class q{constructor(e,t){this.activeSession=null,this.eventBus=e,this.stateManager=t}async createSession(e,t,s,i){this.activeSession&&this.activeSession.status==="active"&&await this.destroySession();const a={sessionId:e,courseId:s,lessonId:i,teacher:t,students:Object.freeze([]),createdAt:Date.now(),status:"active"};return this.activeSession=a,this.stateManager.updateState({lesson:{activeLessonId:i,status:"ready"}}),await this.eventBus.publish("SessionCreated",{sessionId:e,teacherId:t.id,timestamp:Date.now()}),a}async joinSession(e){if(!this.activeSession||this.activeSession.status!=="active")return!1;const t=[...this.activeSession.students.filter(s=>s.id!==e.id),{...e,isOnline:!0}];return this.activeSession={...this.activeSession,students:Object.freeze(t)},this.stateManager.addStudent(e),await this.eventBus.publish("StudentJoined",{student:e,timestamp:Date.now()}),!0}async leaveSession(e){if(!this.activeSession||this.activeSession.status!=="active")return!1;const t=this.activeSession.students.map(s=>s.id===e?{...s,isOnline:!1}:s);return this.activeSession={...this.activeSession,students:Object.freeze(t)},this.stateManager.removeStudent(e),await this.eventBus.publish("StudentLeft",{studentId:e,timestamp:Date.now()}),!0}async reconnectSession(e){if(!this.activeSession||this.activeSession.status!=="active")return!1;const t=this.activeSession.students.find(i=>i.id===e);if(!t)return!1;const s={...t,isOnline:!0};return this.joinSession(s)}async destroySession(){this.activeSession&&(this.activeSession={...this.activeSession,status:"destroyed"},this.activeSession=null)}getActiveSession(){return this.activeSession}}class J{constructor(){this.eventCount=0}incrementEventCount(){this.eventCount+=1}getDiagnostics(e,t,s,i){const a=process.memoryUsage?process.memoryUsage().heapUsed/1048576:0;return{runtimeId:e.runtime.id,lifecycleState:e.runtime.lifecycle,activeServicesCount:t,registeredModulesCount:s,pendingSchedulerTasksCount:i,activeStudentsCount:e.students.length,totalInteractionsCount:e.analytics.totalInteractions,memoryUsageMB:Math.round(a*100)/100,timestamp:Date.now()}}}class K{constructor(e=`rt_${globalThis.crypto.randomUUID()}`){this.currentRole="Teacher",this.runtimeId=e,this.eventBus=new E,this.stateManager=new O(e),this.serviceRegistry=new $,this.moduleRegistry=new B,this.scheduler=new U,this.permissionManager=new T,this.resourceManager=new F,this.snapshotManager=new H,this.hooksManager=new Q,this.sessionManager=new q(this.eventBus,this.stateManager),this.monitor=new J,this.stateManager.setLifecycle("Create")}getContext(){const e=this.sessionManager.getActiveSession();return{runtimeId:this.runtimeId,sessionId:e?.sessionId||"sess_default",courseId:e?.courseId,lessonId:e?.lessonId,teacher:e?.teacher,currentUser:this.currentUser||e?.teacher,role:this.currentRole,permissions:this.permissionManager.getRolePermissions(this.currentRole),lifecycleState:this.stateManager.getState().runtime.lifecycle}}async initialize(){this.transitionState("Initialize"),this.scheduler.start();const e=this.getContext();await this.serviceRegistry.initializeAll(e),this.transitionState("Prepare")}async start(){const e=this.getContext();await this.hooksManager.executeHook("beforeLessonStart",{},e),this.transitionState("Running"),await this.moduleRegistry.startAll(e),await this.hooksManager.executeHook("afterLessonStart",{},e),await this.eventBus.publish("LessonStarted",{lessonId:e.lessonId||"les_active",timestamp:Date.now()}),this.takeSnapshot()}async pause(){this.transitionState("Pause"),this.scheduler.stop(),await this.eventBus.publish("RuntimePaused",{elapsedTime:this.stateManager.getState().runtime.elapsedTime,timestamp:Date.now()})}async resume(){this.transitionState("Resume"),this.scheduler.start(),this.transitionState("Running")}async stop(){const e=this.getContext();this.transitionState("Stop"),await this.moduleRegistry.stopAll(e),this.scheduler.stop(),this.takeSnapshot()}async dispose(){await this.stop(),this.transitionState("Dispose"),await this.serviceRegistry.disposeAll(),this.hooksManager.clear(),this.resourceManager.clear(),this.eventBus.clear()}transitionState(e){const t=this.stateManager.getState().runtime.lifecycle;this.stateManager.setLifecycle(e),this.eventBus.publish("LifecycleChanged",{from:t,to:e,timestamp:Date.now()})}registerModule(e){this.moduleRegistry.registerModule(e)}registerService(e){this.serviceRegistry.registerService(e)}registerRuntimeHook(e,t){return this.hooksManager.registerHook(e,t)}scheduleTask(e,t,s=b.Normal,i=0){return this.scheduler.schedule(e,t,s,i)}setUser(e){this.currentUser=e,this.currentRole=e.role}hasPermission(e){return this.permissionManager.hasPermission(this.currentRole,e)}takeSnapshot(){return this.snapshotManager.takeSnapshot(this.stateManager.getState(),this.serviceRegistry.listServices(),this.moduleRegistry.listModules().map(e=>e.id),this.resourceManager.listResources())}restoreLatestSnapshot(){const e=this.snapshotManager.getLatestSnapshot();return e?(this.stateManager.setState(e.stateTree),!0):!1}getDiagnostics(){return this.monitor.getDiagnostics(this.stateManager.getState(),this.serviceRegistry.listServices().length,this.moduleRegistry.listModules().length,this.scheduler.getPendingTaskCount())}}class V{constructor(e){this.init=e,this.kernel=new K,this.kernel.setUser({id:e.student.id,name:e.student.name,role:"Student",avatar:e.student.avatar,isOnline:!0,joinedAt:Date.now()})}getView(){const e=this.kernel.getContext();return{studentId:this.init.student.id,studentName:this.init.student.name,role:"Student",lessonId:this.init.lessonId??e.lessonId,courseId:this.init.courseId??e.courseId,permissions:e.permissions}}get permissions(){return this.kernel.getContext().permissions}hasPermission(e){return this.kernel.hasPermission(e)}subscribe(e,t){return this.kernel.eventBus.subscribe(e,s=>t(s.payload))}takeSnapshot(){return this.kernel.takeSnapshot()}restoreSnapshot(){return this.kernel.restoreLatestSnapshot()}get runtimeKernel(){return this.kernel}dispose(){return this.kernel.dispose()}}function G({isOpen:n,lang:e,activeStudentId:t,studentNotifications:s,readNotifications:i,setReadNotifications:a,studentDashboardData:c,setIsNotificationsOpen:o,setSelectedNotificationForModal:g}){if(!n)return null;const l=s.filter(u=>!i.has(u.id));return r.jsxs("div",{className:"absolute right-0 mt-2 w-80 bg-white border border-gray-200 shadow-lg rounded-xl z-50 overflow-hidden",children:[r.jsxs("div",{className:"p-3 border-b border-gray-100 flex justify-between items-center bg-gray-50",children:[r.jsx("h3",{className:"font-semibold text-gray-800",children:"Notifications"}),l.length>0&&r.jsx("button",{onClick:async()=>{if(!t)return;try{const h=s.filter(m=>!i.has(m.id)).map(m=>fetch(`/api/students/${t}/read_notifications`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({notificationId:m.id})}));await Promise.all(h)}catch(h){console.error(h)}const u=new Set(i);s.forEach(h=>u.add(h.id)),a(u)},className:"text-xs text-indigo-600 hover:text-indigo-800 font-medium",children:"Mark all as read"})]}),r.jsx("div",{className:"max-h-96 overflow-y-auto",children:s.length===0?r.jsx("div",{className:"p-4 text-center text-sm text-gray-500 italic",children:"No notifications."}):r.jsx("div",{className:"divide-y divide-gray-100",children:s.map(u=>{const h=!i.has(u.id);return r.jsx("div",{className:`p-3 hover:bg-gray-50 cursor-pointer ${h?"bg-indigo-50/30":""}`,onClick:()=>{if(h){t&&fetch(`/api/students/${t}/read_notifications`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({notificationId:u.id})}).catch(console.error);const S=new Set(i);S.add(u.id),a(S)}const m=c?.assignments?.find(S=>S.id===u.relatedId);g({...u,assignment:m}),o(!1)},children:r.jsxs("div",{className:"flex gap-3",children:[r.jsx("div",{className:"mt-0.5",children:u.type==="new_assignment"?r.jsx(C,{size:16,className:"text-indigo-500"}):r.jsx(z,{size:16,className:"text-green-500"})}),r.jsxs("div",{className:"flex-1",children:[r.jsx("div",{className:`text-sm ${h?"font-semibold text-gray-900":"font-medium text-gray-700"}`,children:u.title}),r.jsx("div",{className:`text-xs mt-0.5 ${h?"text-gray-600":"text-gray-500"}`,children:u.message})]}),h&&r.jsx("div",{className:"w-2 h-2 rounded-full bg-indigo-500 mt-1"})]})},u.id)})})})]})}const X=({widgetId:n="widget_ai_teacher_workspace",initialSection:e="Lesson Assistant",onActionExecute:t})=>{const[s,i]=d.useState({widgetId:n,visible:!0,pinned:!0,collapsed:!1,fullscreen:!1,dockPosition:"right",activeSection:e});if(!s.visible)return null;const a=["Lesson Assistant","Whiteboard Assistant","Resource Assistant","Activity Assistant","Student Assistant","Assessment Assistant","Summary Assistant","Plugin Assistant"],c=o=>{t&&t(o,{section:s.activeSection})};return r.jsxs("div",{"data-testid":"ai-teacher-workspace-widget",className:`ai-teacher-workspace-panel ${s.dockPosition} ${s.collapsed?"collapsed":""} ${s.fullscreen?"fullscreen":""}`,style:{border:"1px solid #e2e8f0",borderRadius:"8px",background:"#ffffff",padding:"12px",boxShadow:"0 4px 6px -1px rgba(0, 0, 0, 0.1)"},children:[r.jsxs("div",{className:"ai-widget-header",style:{display:"flex",justifyContent:"space-between",alignItems:"center",borderBottom:"1px solid #f1f5f9",paddingBottom:"8px",marginBottom:"8px"},children:[r.jsx("span",{style:{fontWeight:600,fontSize:"14px",color:"#1e293b"},children:"🤖 AI Teacher Assistant"}),r.jsxs("div",{className:"ai-widget-controls",style:{display:"flex",gap:"4px"},children:[r.jsx("button",{"data-testid":"btn-pin",onClick:()=>i(o=>({...o,pinned:!o.pinned})),style:{fontSize:"12px",cursor:"pointer"},children:s.pinned?"📌 Unpin":"📍 Pin"}),r.jsx("button",{"data-testid":"btn-dock",onClick:()=>i(o=>({...o,dockPosition:o.dockPosition==="right"?"float":"right"})),style:{fontSize:"12px",cursor:"pointer"},children:s.dockPosition==="right"?"🌊 Float":"📥 Dock"}),r.jsx("button",{"data-testid":"btn-fullscreen",onClick:()=>i(o=>({...o,fullscreen:!o.fullscreen})),style:{fontSize:"12px",cursor:"pointer"},children:s.fullscreen?"🗗 Restore":"⛶ Fullscreen"}),r.jsx("button",{"data-testid":"btn-collapse",onClick:()=>i(o=>({...o,collapsed:!o.collapsed})),style:{fontSize:"12px",cursor:"pointer"},children:s.collapsed?"➕ Expand":"➖ Collapse"})]})]}),!s.collapsed&&r.jsxs(r.Fragment,{children:[r.jsx("div",{className:"ai-section-tabs",style:{display:"flex",flexWrap:"wrap",gap:"4px",marginBottom:"12px"},children:a.map(o=>r.jsx("button",{"data-testid":`tab-${o.toLowerCase().replace(/\s+/g,"-")}`,onClick:()=>i(g=>({...g,activeSection:o})),style:{padding:"4px 8px",fontSize:"12px",borderRadius:"4px",border:"1px solid #cbd5e1",background:s.activeSection===o?"#3b82f6":"#f8fafc",color:s.activeSection===o?"#ffffff":"#334155",cursor:"pointer"},children:o},o))}),r.jsxs("div",{className:"ai-section-body",style:{minHeight:"100px"},children:[r.jsxs("div",{style:{fontSize:"13px",color:"#475569",marginBottom:"8px"},children:["Active Assistant: ",r.jsx("strong",{children:s.activeSection})]}),r.jsxs("div",{style:{display:"flex",gap:"8px",flexWrap:"wrap"},children:[r.jsx("button",{"data-testid":"btn-summarize",onClick:()=>c("ai_summarize_lesson"),style:{padding:"6px 12px",fontSize:"12px",background:"#eff6ff",border:"1px solid #bfdbfe",borderRadius:"4px",cursor:"pointer"},children:"📝 Summarize Content"}),r.jsx("button",{"data-testid":"btn-explain",onClick:()=>c("ai_explain_whiteboard"),style:{padding:"6px 12px",fontSize:"12px",background:"#f0fdf4",border:"1px solid #bbf7d0",borderRadius:"4px",cursor:"pointer"},children:"🎨 Explain Visuals"}),r.jsx("button",{"data-testid":"btn-quiz",onClick:()=>c("ai_generate_quiz"),style:{padding:"6px 12px",fontSize:"12px",background:"#fefce8",border:"1px solid #fef08a",borderRadius:"4px",cursor:"pointer"},children:"⚡ Generate Quiz"})]})]})]})]})};class Y{constructor(){this.resources=new Map,this.providers=new Map}registerProvider(e){if(!e||!e.id||!e.type)throw new Error("ResourceRegistry Error: ResourceProvider must have a valid ID and Type.");this.providers.set(e.type,e)}unregisterProvider(e){for(const[t,s]of this.providers.entries())if(s.id===e)return this.providers.delete(t);return!1}getProvider(e){return this.providers.get(e)}registerResource(e){if(!e||!e.id)throw new Error("ResourceRegistry Error: ResourceDescriptor must have a valid ID.");this.resources.set(e.id,{...e})}unregisterResource(e){return this.resources.delete(e)}getResource(e){return this.resources.get(e)}listResources(e){const t=Array.from(this.resources.values());return Object.freeze(e?t.filter(s=>s.type===e):t)}executeAction(e,t,s){const i=this.resources.get(e);if(!i)throw new Error(`ResourceRegistry Error: Resource '${e}' not found.`);const a=this.providers.get(i.type);switch(t){case"preview":return a?.preview?a.preview(i):{previewUrl:i.url};case"open":return a?.open?a.open(i):{openUrl:i.url};case"pin":return i.pinned=!i.pinned,{pinned:i.pinned};case"favorite":return i.favorited=!i.favorited,{favorited:i.favorited};case"annotate":return{annotate:!0,resourceId:e,params:s};case"share":return{shareUrl:i.url??`resource://${i.id}`};case"fullscreen":return{fullscreen:!0,resourceId:e};default:throw new Error(`ResourceRegistry Error: Unknown action '${t}'.`)}}clear(){this.resources.clear(),this.providers.clear()}}const y={padding:"12px",color:"#e2e8f0",fontSize:"13px"},Z=()=>r.jsx("div",{style:{width:"100%",height:"100%"},children:r.jsx(A,{})}),ee=({context:n})=>{const e=n.getView();return r.jsxs("div",{style:y,children:[r.jsx("div",{style:{fontWeight:600,marginBottom:6},children:"📘 Lesson"}),r.jsxs("div",{children:["Lesson ID: ",e.lessonId??"—"]}),r.jsxs("div",{children:["Course ID: ",e.courseId??"—"]})]})},te=()=>{const[n]=d.useState(()=>new Y().listResources());return r.jsxs("div",{style:y,children:[r.jsx("div",{style:{fontWeight:600,marginBottom:6},children:"📂 Resources"}),n.length===0?r.jsx("div",{style:{opacity:.7},children:"No resources shared yet."}):r.jsx("ul",{children:n.map(e=>r.jsxs("li",{children:[e.type,": ",e.url]},e.id))})]})},se=({studentId:n,lang:e="en"})=>r.jsx(P,{role:"student",actorId:n,lang:e}),ie=({studentId:n,lessonId:e,lang:t="en"})=>e?r.jsx(W,{lessonId:e,studentId:n,lang:t,addToast:()=>{}}):r.jsx("div",{style:y,children:"No active lesson — assignments unavailable."}),re=({context:n})=>{const[e,t]=d.useState([]);return d.useEffect(()=>{const s=n.subscribe("LessonStarted",a=>{t(c=>[...c,{id:`ls_${a.timestamp}`,text:`Lesson started (${a.lessonId})`}])}),i=n.subscribe("StageChanged",a=>{t(c=>[...c,{id:`sc_${a.timestamp}`,text:`Stage changed → ${a.toStageId}`}])});return()=>{s(),i()}},[n]),r.jsxs("div",{style:y,children:[r.jsx("div",{style:{fontWeight:600,marginBottom:6},children:"📣 Teacher Broadcast"}),e.length===0?r.jsx("div",{style:{opacity:.7},children:"No announcements yet."}):r.jsx("ul",{children:e.map(s=>r.jsx("li",{children:s.text},s.id))})]})},ne=()=>r.jsx(X,{}),ae=({studentId:n,lang:e="en"})=>{const[t,s]=d.useState(!0),[i,a]=d.useState(new Set),[c]=d.useState([]);return r.jsx(G,{isOpen:t,lang:e,activeStudentId:n,studentNotifications:c,readNotifications:i,setReadNotifications:a,studentDashboardData:null,setIsNotificationsOpen:s,setSelectedNotificationForModal:()=>{}})},oe=()=>r.jsx(I,{slot:"student.view"});class ce{constructor(e){this.registeredWidgets=new Map,this.slotRegistry=e??new w}get slotRegistryRef(){return this.slotRegistry}registerWidget(e){if(!e||!e.id)throw new Error("StudentWidgetRegistry Error: StudentWidgetDescriptor must have a valid ID.");this.registeredWidgets.set(e.id,e);const t=e.component;this.slotRegistry.register({id:e.id,slot:e.slot,priority:e.priority??10,render:s=>x.createElement(t,s)})}unregisterWidget(e){const t=this.registeredWidgets.delete(e);return t&&this.slotRegistry.unregister(e),t}registerDefaultWidgets(e){const{studentId:t,lessonId:s,lang:i="en",context:a,pluginHost:c}=e;this.mountWidget("widget_student_whiteboard","Whiteboard","MainCanvas",Z,{},"official"),this.mountWidget("widget_student_lesson","Lesson","LeftSidebar",ee,{context:a},"official"),this.mountWidget("widget_student_resources","Resources","LeftSidebar",te,{},"official"),this.mountWidget("widget_student_activities","Activities","BottomPanel",se,{},"official"),this.mountWidget("widget_student_assignments","Assignments","RightSidebar",ie,{studentId:t,lessonId:s,lang:i},"official",20),this.mountWidget("widget_student_ai_assistant","AI Learning Assistant","RightSidebar",ne,{},"official",10),this.mountWidget("widget_student_broadcast","Teacher Broadcast","BottomPanel",re,{context:a},"official"),this.mountWidget("widget_student_notifications","Notifications","FloatingArea",ae,{studentId:t,lang:i},"official"),c&&this.mountWidget("widget_student_plugins","Plugin Widgets","FloatingArea",oe,{},"plugin")}getWidget(e){return this.registeredWidgets.get(e)}listWidgets(){return Object.freeze(Array.from(this.registeredWidgets.values()))}clear(){for(const e of this.registeredWidgets.keys())this.slotRegistry.unregister(e);this.registeredWidgets.clear()}mountWidget(e,t,s,i,a,c,o=10){this.registeredWidgets.set(e,{id:e,name:t,slot:s,component:i,provider:c,priority:o}),this.slotRegistry.register({id:e,slot:s,priority:o,render:()=>x.createElement(i,a)})}}const R="openlearn_student_workspace_";function le(n){return{studentId:n,openedWidgets:[],layout:{},selectedResourceIds:[],activityState:{},aiConversation:[],updatedAt:Date.now()}}class de{constructor(e){this.key=`${R}${e}`}load(){try{if(typeof localStorage>"u")return null;const e=localStorage.getItem(this.key);if(!e)return null;const t=JSON.parse(e);return t.studentId!==this.studentIdFromKey()?null:t}catch{return null}}save(e){try{if(typeof localStorage>"u")return;localStorage.setItem(this.key,JSON.stringify({...e,updatedAt:Date.now()}))}catch{}}update(e){const s={...this.load()??le(this.studentIdFromKey()),...e,updatedAt:Date.now()};return this.save(s),s}clear(){try{if(typeof localStorage>"u")return;localStorage.removeItem(this.key)}catch{}}studentIdFromKey(){return this.key.slice(R.length)}}const be=n=>{const{student:e,lessonId:t,courseId:s,teacherId:i,teacherName:a,lang:c="en",autoRestore:o=!0,pluginHost:g}=n,[l]=d.useState(()=>new V({student:e,lessonId:t,courseId:s,teacherId:i,teacherName:a,lang:c})),[u]=d.useState(()=>new w),[h]=d.useState(()=>{const p=new ce(u);return p.registerDefaultWidgets({studentId:e.id,lessonId:t,lang:c,context:l,pluginHost:g}),p}),[m]=d.useState(()=>new de(e.id));d.useEffect(()=>{if(!o)return;l.restoreSnapshot();const p=m.load();p?.currentLessonId&&p.currentLessonId},[o,l,m]),d.useEffect(()=>{const p=l.subscribe("LessonStarted",v=>{m.update({currentLessonId:v.lessonId})});return()=>{p()}},[l,m]),d.useEffect(()=>()=>{l.takeSnapshot();const p=h.listWidgets().map(j=>j.id),v=m.load();m.save({studentId:e.id,openedWidgets:p,layout:v?.layout??{},currentLessonId:v?.currentLessonId??t,selectedResourceIds:v?.selectedResourceIds??[],activityState:v?.activityState??{},aiConversation:v?.aiConversation??[],updatedAt:Date.now()}),l.dispose()},[l,m,h,e.id,t]);const S=r.jsx(N,{registry:u,children:r.jsx(L,{})});return g?r.jsx(M,{host:g,children:S}):S};export{be as StudentWorkspace,be as default};
|