Skip to content
Open
2 changes: 2 additions & 0 deletions src/app/student-teacher-common-services.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import { TeacherNodeService } from '../assets/wise5/services/teacherNodeService'
import { TeacherWebSocketService } from '../assets/wise5/services/teacherWebSocketService';
import { VLEProjectService } from '../assets/wise5/vle/vleProjectService';
import { WiseLinkService } from './services/wiseLinkService';
import { TimedNodeService } from '../assets/wise5/services/timedNodeService';

@NgModule({
providers: [
Expand Down Expand Up @@ -121,6 +122,7 @@ import { WiseLinkService } from './services/wiseLinkService';
TeacherDataService,
TeacherNodeService,
TeacherWebSocketService,
TimedNodeService,
StudentProjectTranslationService,
VLEProjectService,
WiseLinkService
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,9 @@
Show Submit Button
</mat-checkbox>
</div>
<div>
<mat-checkbox color="primary" [(ngModel)]="node.timed" (change)="saveProject()" i18n
>Timed Step</mat-checkbox
>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,20 @@
</div>
</div>
<mat-divider></mat-divider>
@if (isTimed()) {
<div class="time-limit">
<mat-form-field class="feedback-input" subscriptSizing="dynamic">
<mat-label i18n>Time Limit (seconds)</mat-label>
<input
matInput
type="number"
[(ngModel)]="component.timeLimit"
(ngModelChange)="saveProject()"
[required]="true"
/>
</mat-form-field>
</div>
}
<div>
<component-authoring
[nodeId]="nodeId"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,9 @@ component-authoring {
.mat-icon {
margin: 0;
}

.time-limit {
max-width: 200px;
margin: 16px;
margin-bottom: 0px;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import { TeacherNodeService } from '../../../services/teacherNodeService';
import { DeleteTranslationsService } from '../../../services/deleteTranslationsService';

@Component({
selector: 'node-authoring',
templateUrl: './node-authoring.component.html',
styleUrls: ['./node-authoring.component.scss'],
standalone: false
selector: 'node-authoring',
templateUrl: './node-authoring.component.html',
styleUrls: ['./node-authoring.component.scss'],
standalone: false
})
export class NodeAuthoringComponent implements OnInit {
components: ComponentContent[] = [];
Expand Down Expand Up @@ -119,7 +119,7 @@ export class NodeAuthoringComponent implements OnInit {
if (parseProject) {
this.projectService.parseProject();
}
return this.projectService.saveProject();
return this.saveProject();
}

protected deleteComponent(
Expand All @@ -139,7 +139,7 @@ export class NodeAuthoringComponent implements OnInit {

private deleteComponentsOnServer(components: ComponentContent[]): void {
this.checkIfNeedToShowNodeSaveOrNodeSubmitButtons();
this.projectService.saveProject().then(() => {
this.saveProject().then(() => {
this.deleteTranslationsService.tryDeleteComponents(components);
});
}
Expand Down Expand Up @@ -213,10 +213,19 @@ export class NodeAuthoringComponent implements OnInit {
if (scroll) {
this.highlightComponents([this.components[currentIndex]]);
}
this.projectService.saveProject();
this.saveProject();
}

protected editComponent(componentId: string): void {
this.editingComponentId = componentId;
}

protected isTimed(): boolean {
const node = this.projectService.getNodeById(this.node.id);
return node.timed !== null && node.timed;
Comment on lines +224 to +225
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplify?

Suggested change
const node = this.projectService.getNodeById(this.node.id);
return node.timed !== null && node.timed;
return this.projectService.getNodeById(this.node.id).timed;

}

protected saveProject(): Promise<any> {
return this.projectService.saveProject();
}
}
1 change: 1 addition & 0 deletions src/assets/wise5/common/ComponentContent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export interface ComponentContent {
showSaveButton?: boolean;
showSubmitButton?: boolean;
type: string;
timeLimit?: number;
}

export function hasConnectedComponent(
Expand Down
1 change: 1 addition & 0 deletions src/assets/wise5/common/Node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export class Node {
showSaveButton: boolean;
showSubmitButton: boolean;
title: string;
timed?: boolean;
transitionLogic?: TransitionLogic;
type: string;

Expand Down
11 changes: 11 additions & 0 deletions src/assets/wise5/services/timedNodeService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';

@Injectable()
export class TimedNodeService {
isNodeCompletedBroadcast: Subject<boolean> = new Subject<boolean>();

broadcastIsNodeCompleted(isCompleted: boolean): void {
this.isNodeCompletedBroadcast.next(isCompleted);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<button
mat-icon-button
(click)="goToPrevNode()"
[disabled]="!prevId"
[disabled]="isArrowDisabled('prev')"
aria-label="Previous Item"
i18n-aria-label
matTooltip="Previous Step"
Expand All @@ -25,6 +25,7 @@
[(ngModel)]="toNodeId"
hideSingleSelectionIndicator="true"
(ngModelChange)="toNodeIdChanged()"
[disabled]="isUnfinishedTimedStep()"
>
<mat-select-trigger>
{{ getNodePositionAndTitle(nodeId) }}
Expand Down Expand Up @@ -54,7 +55,7 @@
<button
mat-icon-button
(click)="goToNextNode()"
[disabled]="!nextId"
[disabled]="isArrowDisabled('next')"
aria-label="Next Item"
i18n-aria-label
matTooltip="Next Step"
Expand All @@ -63,16 +64,18 @@
<mat-icon>{{ icons.next }}</mat-icon>
</button>
</div>
<div>
<button
mat-icon-button
(click)="closeNode()"
aria-label="Project Plan"
i18n-aria-label
matTooltip="Project Plan"
i18n-matTooltip
>
<mat-icon class="unit-plan-icon">view_list</mat-icon>
</button>
</div>
@if (!isUnfinishedTimedStep()) {
<div>
<button
mat-icon-button
(click)="closeNode()"
aria-label="Project Plan"
i18n-aria-label
matTooltip="Project Plan"
i18n-matTooltip
>
<mat-icon class="unit-plan-icon">view_list</mat-icon>
</button>
</div>
}
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,16 @@ describe('StepToolsComponent', () => {
it('should create', () => {
expect(component).toBeTruthy();
});

it('should disable navigation on unfinished timed steps', () => {
let sections = fixture.nativeElement.querySelectorAll('.step-tools > div');
expect(sections.length).toEqual(2);

component['timedStep'] = true;
component['timedStepCompleted'] = false;
fixture.detectChanges();

sections = fixture.nativeElement.querySelectorAll('.step-tools > div');
expect(sections.length).toEqual(1); // isUnfinishedTimedStep() returned true
});
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CommonModule } from '@angular/common';
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { Component, Input, OnInit, ViewEncapsulation } from '@angular/core';
import { FlexLayoutModule } from '@angular/flex-layout';
import { FormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
Expand All @@ -14,6 +14,7 @@ import { NodeStatusService } from '../../../../services/nodeStatusService';
import { ProjectService } from '../../../../services/projectService';
import { StudentDataService } from '../../../../services/studentDataService';
import { Subscription } from 'rxjs';
import { TimedNodeService } from '../../../../services/timedNodeService';

@Component({
encapsulation: ViewEncapsulation.None,
Expand Down Expand Up @@ -43,14 +44,17 @@ export class StepToolsComponent implements OnInit {
protected nodeStatus: any;
protected nodeStatuses: any;
protected prevId: string;
@Input() private timedStep: boolean;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of making timedStep an input to this component, can we set this in updateModel()?

Suggested change
@Input() private timedStep: boolean;
private timedStep: boolean;

protected timedStepCompleted: boolean;
private subscriptions: Subscription = new Subscription();
protected toNodeId: string;

constructor(
private nodeService: NodeService,
private nodeStatusService: NodeStatusService,
private projectService: ProjectService,
private studentDataService: StudentDataService
private studentDataService: StudentDataService,
private timedNodeService: TimedNodeService
) {}

ngOnInit(): void {
Expand All @@ -76,6 +80,11 @@ export class StepToolsComponent implements OnInit {
this.updateModel();
})
);
this.subscriptions.add(
this.timedNodeService.isNodeCompletedBroadcast.subscribe(
(isStepCompleted) => (this.timedStepCompleted = isStepCompleted)
)
);
}

ngOnDestroy(): void {
Expand Down Expand Up @@ -124,4 +133,17 @@ export class StepToolsComponent implements OnInit {
protected closeNode(): void {
this.nodeService.closeNode();
}

protected isArrowDisabled(direction: 'prev' | 'next'): boolean {
const noNode = direction === 'prev' ? !this.prevId : !this.nextId;
return noNode || this.isUnfinishedTimedStep();
}

protected isUnfinishedTimedStep(): boolean {
if (this.timedStep) {
return !this.timedStepCompleted;
} else {
return false;
}
Comment on lines +143 to +147
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Write in one line?

}
}
28 changes: 16 additions & 12 deletions src/assets/wise5/vle/node/node.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ export class NodeComponent implements OnInit {
private autoSaveIntervalId: any;
protected components: any[];
protected componentToVisible = {};
protected dirtyComponentIds: any = [];
protected dirtySubmitComponentIds: any = [];
protected dirtyComponentIds: any[] = [];
protected dirtySubmitComponentIds: any[] = [];
protected disabled: boolean;
protected isBranchNode: boolean = false;
protected isLastNode: boolean = false;
Expand Down Expand Up @@ -74,14 +74,14 @@ export class NodeComponent implements OnInit {
protected workgroupId: number;

constructor(
private componentService: ComponentService,
private configService: ConfigService,
private constraintService: ConstraintService,
private nodeService: StudentNodeService,
private nodeStatusService: NodeStatusService,
private projectService: VLEProjectService,
private sessionService: SessionService,
private studentDataService: StudentDataService
protected componentService: ComponentService,
protected configService: ConfigService,
protected constraintService: ConstraintService,
protected nodeService: StudentNodeService,
protected nodeStatusService: NodeStatusService,
protected projectService: VLEProjectService,
protected sessionService: SessionService,
protected studentDataService: StudentDataService
) {}

ngOnChanges(): void {
Expand Down Expand Up @@ -191,7 +191,7 @@ export class NodeComponent implements OnInit {
this.latestComponentState = latestComponentState;
}

if (this.configService.isPreview()) {
if (this.isPreview()) {
this.showRubric = this.node.rubric != null && this.node.rubric != '';
}

Expand All @@ -204,7 +204,7 @@ export class NodeComponent implements OnInit {
}
}

private updateComponentVisibility(): void {
protected updateComponentVisibility(): void {
this.components.forEach((component) => {
const constraintResult = this.constraintService.evaluate(component.constraints);
this.componentToVisible[component.id] = constraintResult.isVisible;
Expand Down Expand Up @@ -475,4 +475,8 @@ export class NodeComponent implements OnInit {
this.createComponentStatesResponseHandler(true)
);
}

protected isPreview(): boolean {
return this.configService.isPreview();
}
}
Loading
Loading