diff --git a/src/app/classroom-monitor/workgroup-node-status/workgroup-node-status.component.ts b/src/app/classroom-monitor/workgroup-node-status/workgroup-node-status.component.ts index bc53c22ae7b..dc3d47ce4c1 100644 --- a/src/app/classroom-monitor/workgroup-node-status/workgroup-node-status.component.ts +++ b/src/app/classroom-monitor/workgroup-node-status/workgroup-node-status.component.ts @@ -2,12 +2,10 @@ import { Component, Input } from '@angular/core'; @Component({ selector: 'workgroup-node-status', + standalone: true, template: `{{ statusText }}` }) export class WorkgroupNodeStatusComponent { - @Input() - statusClass: string = 'text-secondary'; - - @Input() - statusText: string; + @Input() statusClass: string = 'text-secondary'; + @Input() statusText: string; } diff --git a/src/app/teacher/grading-common.module.ts b/src/app/teacher/grading-common.module.ts index 39b2c01db38..e9327561d28 100644 --- a/src/app/teacher/grading-common.module.ts +++ b/src/app/teacher/grading-common.module.ts @@ -20,7 +20,8 @@ import { NavItemProgressComponent } from '../classroom-monitor/nav-item-progress ComponentGradingModule, IntersectionObserverModule, StatusIconComponent, - StudentTeacherCommonModule + StudentTeacherCommonModule, + WorkgroupNodeStatusComponent ], declarations: [ EditComponentAnnotationsComponent, @@ -32,7 +33,6 @@ import { NavItemProgressComponent } from '../classroom-monitor/nav-item-progress WorkgroupInfoComponent, WorkgroupItemComponent, WorkgroupNodeScoreComponent, - WorkgroupNodeStatusComponent, WorkgroupSelectAutocompleteComponent ], exports: [ diff --git a/src/assets/wise5/classroomMonitor/classroomMonitorComponents/milestones/milestone-workgroup-item/milestone-workgroup-item.component.html b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/milestones/milestone-workgroup-item/milestone-workgroup-item.component.html index 12010f382bc..c017d0a1952 100644 --- a/src/assets/wise5/classroomMonitor/classroomMonitorComponents/milestones/milestone-workgroup-item/milestone-workgroup-item.component.html +++ b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/milestones/milestone-workgroup-item/milestone-workgroup-item.component.html @@ -25,8 +25,7 @@ >
- - +
- - +
diff --git a/src/assets/wise5/classroomMonitor/classroomMonitorComponents/studentGrading/step-item/step-item.component.html b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/studentGrading/step-item/step-item.component.html index 43a1328f6f3..aaa8a272dc4 100644 --- a/src/assets/wise5/classroomMonitor/classroomMonitorComponents/studentGrading/step-item/step-item.component.html +++ b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/studentGrading/step-item/step-item.component.html @@ -24,8 +24,7 @@ />
- - +
diff --git a/src/assets/wise5/services/studentDataService.ts b/src/assets/wise5/services/studentDataService.ts index 45c73c52230..db576cca5e2 100644 --- a/src/assets/wise5/services/studentDataService.ts +++ b/src/assets/wise5/services/studentDataService.ts @@ -26,17 +26,20 @@ export class StudentDataService extends DataService { private componentDirtySource: Subject = new Subject(); public componentDirty$: Observable = this.componentDirtySource.asObservable(); private componentSaveTriggeredSource: Subject = new Subject(); - public componentSaveTriggered$: Observable = this.componentSaveTriggeredSource.asObservable(); + public componentSaveTriggered$: Observable = + this.componentSaveTriggeredSource.asObservable(); private componentSubmitDirtySource: Subject = new Subject(); public componentSubmitDirty$: Observable = this.componentSubmitDirtySource.asObservable(); private componentSubmitTriggeredSource: Subject = new Subject(); - public componentSubmitTriggered$: Observable = this.componentSubmitTriggeredSource.asObservable(); + public componentSubmitTriggered$: Observable = + this.componentSubmitTriggeredSource.asObservable(); private componentStudentDataSource: Subject = new Subject(); public componentStudentData$: Observable = this.componentStudentDataSource.asObservable(); private dataRetrievedSource: Subject = new Subject(); public dataRetrieved$: Observable = this.dataRetrievedSource.asObservable(); private studentWorkSavedToServerSource: Subject = new Subject(); - public studentWorkSavedToServer$: Observable = this.studentWorkSavedToServerSource.asObservable(); + public studentWorkSavedToServer$: Observable = + this.studentWorkSavedToServerSource.asObservable(); private navItemIsExpandedSource: Subject = new Subject(); public navItemIsExpanded$: Observable = this.navItemIsExpandedSource.asObservable(); private nodeStatusesChangedSource: Subject = new Subject(); @@ -281,6 +284,12 @@ export class StudentDataService extends DataService { return this.saveToServer(componentStates, events, annotations); } + saveEvents(events: any): Promise { + const componentStates = undefined; + const annotations = undefined; + return this.saveToServer(componentStates, events, annotations); + } + createNewEvent(nodeId, componentId, context, componentType, category, event, data) { return { nodeId: nodeId, diff --git a/src/assets/wise5/vle/node/node.component.ts b/src/assets/wise5/vle/node/node.component.ts index f289b308f99..73527ab00df 100644 --- a/src/assets/wise5/vle/node/node.component.ts +++ b/src/assets/wise5/vle/node/node.component.ts @@ -138,17 +138,21 @@ export class NodeComponent implements OnInit { }) ); - this.studentDataService.currentNodeChanged$.subscribe(({ currentNode }) => { - this.node = this.projectService.getNode(currentNode.id); - this.nodeUnloaded(this.node.id); - if (this.node.isEvaluateTransitionLogicOn('exitNode')) { - this.nodeService.evaluateTransitionLogic(); - } - this.initializeNode(); - }); - this.studentDataService.nodeStatusesChanged$.subscribe(() => { - this.updateComponentVisibility(); - }); + this.subscriptions.add( + this.studentDataService.currentNodeChanged$.subscribe(({ currentNode }) => { + this.node = this.projectService.getNode(currentNode.id); + if (this.node.isEvaluateTransitionLogicOn('exitNode')) { + this.nodeService.evaluateTransitionLogic(); + } + this.initializeNode(); + }) + ); + + this.subscriptions.add( + this.studentDataService.nodeStatusesChanged$.subscribe(() => { + this.updateComponentVisibility(); + }) + ); } initializeNode(): void { @@ -164,29 +168,12 @@ export class NodeComponent implements OnInit { this.nodeService.evaluateTransitionLogic(); } - const latestComponentState = this.studentDataService.getLatestComponentStateByNodeIdAndComponentId( - this.node.id - ); + const latestComponentState = + this.studentDataService.getLatestComponentStateByNodeIdAndComponentId(this.node.id); if (latestComponentState) { this.latestComponentState = latestComponentState; } - const componentId = null; - const componentType = null; - const category = 'Navigation'; - const event = 'nodeEntered'; - const eventData = { - nodeId: this.node.id - }; - this.studentDataService.saveVLEEvent( - this.node.id, - componentId, - componentType, - category, - event, - eventData - ); - if (this.configService.isPreview()) { this.showRubric = this.node.rubric != null && this.node.rubric != ''; } @@ -449,29 +436,10 @@ export class NodeComponent implements OnInit { ); } - private nodeUnloaded(nodeId: string): void { - const componentId = null; - const componentType = null; - const category = 'Navigation'; - const event = 'nodeExited'; - const eventData = { - nodeId: nodeId - }; - this.studentDataService.saveVLEEvent( - nodeId, - componentId, - componentType, - category, - event, - eventData - ); - } - private registerExitListener(): void { this.subscriptions.add( this.sessionService.exit$.subscribe(() => { this.stopAutoSaveInterval(); - this.nodeUnloaded(this.node.id); }) ); } diff --git a/src/assets/wise5/vle/vle.component.ts b/src/assets/wise5/vle/vle.component.ts index 05d446db63c..6ab4638d3e9 100644 --- a/src/assets/wise5/vle/vle.component.ts +++ b/src/assets/wise5/vle/vle.component.ts @@ -58,6 +58,11 @@ export class VLEComponent implements AfterViewInit { private wiseLinkService: WiseLinkService ) {} + @HostListener('window:beforeunload') + beforeUnload(): void { + this.saveNodeExitedEvent(); + } + ngAfterViewInit(): void { this.initializeVLEService.initialized$.subscribe((initialized: boolean) => { if (initialized) { @@ -106,6 +111,7 @@ export class VLEComponent implements AfterViewInit { this.notebookConfig = this.notebookService.getNotebookConfig(); this.setLayoutState(); this.initializeSubscriptions(); + this.saveNodeEnteredEvent(); } ngOnDestroy() { @@ -179,49 +185,17 @@ export class VLEComponent implements AfterViewInit { this.subscriptions.add( this.studentDataService.currentNodeChanged$.subscribe(({ previousNode }) => { this.setCurrentNode(); - let currentNodeId = this.currentNode.id; - + const currentNodeId = this.currentNode.id; this.studentDataService.updateStackHistory(currentNodeId); this.nodeStatusService.setNodeIsVisited(currentNodeId); - - let componentId, componentType, category, eventName, eventData, eventNodeId; - if (previousNode != null && this.projectService.isGroupNode(previousNode.id)) { - // going from group to node or group to group - componentId = null; - componentType = null; - category = 'Navigation'; - eventName = 'nodeExited'; - eventData = { - nodeId: previousNode.id - }; - eventNodeId = previousNode.id; - this.studentDataService.saveVLEEvent( - eventNodeId, - componentId, - componentType, - category, - eventName, - eventData - ); + const events = []; + if (previousNode != null) { + events.push(this.createNodeExitedEvent(previousNode.id)); } + events.push(this.createNodeEnteredEvent()); + this.studentDataService.saveEvents(events); if (this.projectService.isGroupNode(currentNodeId)) { - componentId = null; - componentType = null; - category = 'Navigation'; - eventName = 'nodeEntered'; - eventData = { - nodeId: currentNodeId - }; - eventNodeId = currentNodeId; - this.studentDataService.saveVLEEvent( - eventNodeId, - componentId, - componentType, - category, - eventName, - eventData - ); } else { this.scrollToTop(); } @@ -401,4 +375,34 @@ export class VLEComponent implements AfterViewInit { } }; } + + private saveNodeEnteredEvent(): void { + this.studentDataService.saveEvents([this.createNodeEnteredEvent()]); + } + + private saveNodeExitedEvent(): void { + this.studentDataService.saveEvents([this.createNodeExitedEvent()]); + } + + private createNodeEnteredEvent(): any { + return this.createNodeEvent('nodeEntered'); + } + + private createNodeExitedEvent(nodeId: string = this.currentNode.id): any { + return this.createNodeEvent('nodeExited', nodeId); + } + + private createNodeEvent(eventName: string, nodeId: string = this.currentNode.id): any { + return this.studentDataService.createNewEvent( + nodeId, + null, + 'VLE', + null, + 'Navigation', + eventName, + { + nodeId: nodeId + } + ); + } } diff --git a/src/messages.xlf b/src/messages.xlf index 37f9ce50f73..61193615f46 100644 --- a/src/messages.xlf +++ b/src/messages.xlf @@ -9977,7 +9977,7 @@ Click "Cancel" to keep the invalid JSON open so you can fix it. src/assets/wise5/vle/vle.component.ts - 162 + 168 @@ -9992,7 +9992,7 @@ Click "Cancel" to keep the invalid JSON open so you can fix it. src/assets/wise5/vle/vle.component.ts - 163 + 169 @@ -13815,14 +13815,14 @@ Click "Cancel" to keep the invalid JSON open so you can fix it.Step src/assets/wise5/classroomMonitor/classroomMonitorComponents/milestones/milestone-workgroup-item/milestone-workgroup-item.component.html - 73 + 72 Step src/assets/wise5/classroomMonitor/classroomMonitorComponents/milestones/milestone-workgroup-item/milestone-workgroup-item.component.html - 95 + 94 @@ -21796,28 +21796,28 @@ If this problem continues, let your teacher know and move on to the next activit Preview Student src/assets/wise5/services/studentDataService.ts - 74 + 77 StudentDataService.saveComponentEvent: component, category, event args must not be null src/assets/wise5/services/studentDataService.ts - 241 + 244 StudentDataService.saveComponentEvent: nodeId, componentId, componentType must not be null src/assets/wise5/services/studentDataService.ts - 251 + 254 StudentDataService.saveVLEEvent: category and event args must not be null src/assets/wise5/services/studentDataService.ts - 260 + 263