-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(Authoring): Add JSON authoring view for when project is broken (#…
…964)
- Loading branch information
1 parent
cb30282
commit 9dbcfc9
Showing
9 changed files
with
521 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
export class NodeRecoveryAnalysis { | ||
hasTransitionToNull: boolean = false; | ||
nodeId: string; | ||
referencedIdsThatAreDuplicated: string[] = []; | ||
referencedIdsThatDoNotExist: string[] = []; | ||
|
||
constructor(nodeId: string) { | ||
this.nodeId = nodeId; | ||
} | ||
|
||
addReferencedIdThatIsDuplicated(nodeId: string): void { | ||
this.referencedIdsThatAreDuplicated.push(nodeId); | ||
} | ||
|
||
addReferencedIdThatDoesNotExist(nodeId: string): void { | ||
this.referencedIdsThatDoNotExist.push(nodeId); | ||
} | ||
|
||
setHasTransitionToNull(value: boolean): void { | ||
this.hasTransitionToNull = value; | ||
} | ||
|
||
hasProblem(): boolean { | ||
return ( | ||
this.referencedIdsThatAreDuplicated.length > 0 || | ||
this.referencedIdsThatDoNotExist.length > 0 || | ||
this.hasTransitionToNull | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
59 changes: 59 additions & 0 deletions
59
src/assets/wise5/authoringTool/recovery-authoring/recovery-authoring.component.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
<div id="top" class="view-content view-content--with-sidemenu"> | ||
<div class="l-constrained" layout="column"> | ||
<div class="node-content md-whiteframe-1dp main-box"> | ||
<div class="top-div"> | ||
<div class="save-bar" fxLayout="row" fxLayoutAlign="space-between center"> | ||
<div fxLayoutGap="20px"> | ||
<button mat-raised-button | ||
color="primary" | ||
(click)="save()" | ||
[disabled]="!saveButtonEnabled" | ||
i18n> | ||
Save | ||
</button> | ||
<button mat-raised-button | ||
color="primary" | ||
(click)="goToAuthoringView()" | ||
i18n> | ||
Go to Authoring View | ||
</button> | ||
</div> | ||
<div fxLayout="row"> | ||
<div *ngIf="jsonIsValid" class="valid" i18n>JSON Valid</div> | ||
<div *ngIf="!jsonIsValid" class="invalid" i18n>JSON Invalid</div> | ||
<div *ngIf="globalMessage != null"> | ||
<div class="component__actions__info md-caption global-message"> | ||
{{ globalMessage.text }} {{ globalMessage.time | date:'medium' }} | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
<div class="warning-div" i18n>Warning: Modifying the JSON may break the project. Please make a backup copy of the JSON before you modify it.</div> | ||
<div *ngIf="badNodes.length > 0" class="potential-problems-div"> | ||
<div class="potential-problems-header" i18n>Potential Problems</div> | ||
<div *ngFor="let badNode of badNodes" class="bad-node"> | ||
<div class="node-id">{{ badNode.nodeId }}</div> | ||
<div *ngIf="badNode.referencedIdsThatDoNotExist.length > 0" i18n> | ||
This group references the node ID but the node does not exist: {{ badNode.referencedIdsThatDoNotExist }} | ||
</div> | ||
<div *ngIf="badNode.referencedIdsThatAreDuplicated.length > 0" i18n> | ||
This group references the same node ID multiple times: {{ badNode.referencedIdsThatAreDuplicated }} | ||
</div> | ||
<div *ngIf="badNode.hasTransitionToNull" i18n>This node has a transition to null</div> | ||
</div> | ||
</div> | ||
</div> | ||
<div> | ||
<mat-form-field fxFlex appearance="outline"> | ||
<mat-label i18n>Edit Unit JSON</mat-label> | ||
<textarea class="mat-body-1" | ||
matInput | ||
cdkTextareaAutosize | ||
[(ngModel)]="projectJSONString" | ||
(ngModelChange)="projectJSONChanged()"> | ||
</textarea> | ||
</mat-form-field> | ||
</div> | ||
</div> | ||
</div> | ||
</div> |
50 changes: 50 additions & 0 deletions
50
src/assets/wise5/authoringTool/recovery-authoring/recovery-authoring.component.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
.main-box { | ||
position: relative; | ||
padding: 16px !important; | ||
} | ||
|
||
.top-div { | ||
background-color: white; | ||
position: sticky; | ||
top: 0px; | ||
z-index: 2; | ||
padding-top: 4px; | ||
padding-bottom: 4px; | ||
} | ||
|
||
.save-bar { | ||
margin-bottom: 20px; | ||
} | ||
|
||
.valid { | ||
color: green; | ||
} | ||
|
||
.invalid { | ||
color: red; | ||
} | ||
|
||
.warning-div { | ||
margin-bottom: 20px; | ||
color: red; | ||
} | ||
|
||
.potential-problems-div { | ||
color: red; | ||
} | ||
|
||
.potential-problems-header { | ||
text-decoration: underline; | ||
margin-bottom: 8px; | ||
} | ||
|
||
.bad-node { | ||
border: 1px solid red; | ||
border-radius: 8px; | ||
padding: 8px; | ||
margin-bottom: 4px; | ||
} | ||
|
||
.node-id { | ||
font-weight: bold; | ||
} |
136 changes: 136 additions & 0 deletions
136
src/assets/wise5/authoringTool/recovery-authoring/recovery-authoring.component.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
import { HttpClientTestingModule } from '@angular/common/http/testing'; | ||
import { ComponentFixture, TestBed } from '@angular/core/testing'; | ||
import { FormsModule } from '@angular/forms'; | ||
import { MatDialogModule } from '@angular/material/dialog'; | ||
import { MatInputModule } from '@angular/material/input'; | ||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; | ||
import { UpgradeModule } from '@angular/upgrade/static'; | ||
import { StudentTeacherCommonServicesModule } from '../../../../app/student-teacher-common-services.module'; | ||
import { TeacherProjectService } from '../../services/teacherProjectService'; | ||
import { RecoveryAuthoringComponent } from './recovery-authoring.component'; | ||
|
||
class MockTeacherProjectService { | ||
project = { | ||
nodes: [] | ||
}; | ||
|
||
saveProject() {} | ||
} | ||
|
||
class Node { | ||
id: string; | ||
ids: string[]; | ||
transitionLogic: any; | ||
|
||
constructor(id: string, ids: string[], transitions: any[]) { | ||
this.id = id; | ||
this.ids = ids; | ||
this.transitionLogic = { | ||
transitions: transitions | ||
}; | ||
} | ||
} | ||
|
||
let component: RecoveryAuthoringComponent; | ||
let fixture: ComponentFixture<RecoveryAuthoringComponent>; | ||
const groupId1 = 'group1'; | ||
const nodeId1 = 'node1'; | ||
const nodeId2 = 'node2'; | ||
|
||
describe('RecoveryAuthoringComponent', () => { | ||
beforeEach(async () => { | ||
await TestBed.configureTestingModule({ | ||
declarations: [RecoveryAuthoringComponent], | ||
imports: [ | ||
BrowserAnimationsModule, | ||
FormsModule, | ||
HttpClientTestingModule, | ||
MatDialogModule, | ||
MatInputModule, | ||
StudentTeacherCommonServicesModule, | ||
UpgradeModule | ||
], | ||
providers: [{ provide: TeacherProjectService, useClass: MockTeacherProjectService }] | ||
}).compileComponents(); | ||
}); | ||
|
||
beforeEach(() => { | ||
fixture = TestBed.createComponent(RecoveryAuthoringComponent); | ||
component = fixture.componentInstance; | ||
fixture.detectChanges(); | ||
}); | ||
|
||
projectJSONChanged(); | ||
save(); | ||
}); | ||
|
||
function projectJSONChanged() { | ||
describe('projectJSONChanged()', () => { | ||
detectJSONValidity(); | ||
detectPotentialProblems(); | ||
}); | ||
} | ||
|
||
function detectJSONValidity() { | ||
it('should detect json is invalid and disable save button', () => { | ||
setJSONAndExpect('abc', false, false); | ||
}); | ||
|
||
it('should detect json is valid and enable save button', () => { | ||
setJSONAndExpect('{ "nodes": [] }', true, true); | ||
}); | ||
} | ||
|
||
function setJSONAndExpect(json: string, jsonIsValid: boolean, saveButtonEnabled: boolean) { | ||
setProjectJSONStringAndTriggerChange(json); | ||
expect(component.jsonIsValid).toEqual(jsonIsValid); | ||
expect(component.saveButtonEnabled).toEqual(saveButtonEnabled); | ||
} | ||
|
||
function detectPotentialProblems() { | ||
it('should detect potential problem transition to null', () => { | ||
const projectJSON = { | ||
nodes: [new Node(nodeId1, null, [{ to: null }])] | ||
}; | ||
setProjectJSONStringAndTriggerChange(JSON.stringify(projectJSON)); | ||
expect(component.badNodes.length).toEqual(1); | ||
expect(component.badNodes[0].hasTransitionToNull).toEqual(true); | ||
}); | ||
|
||
it('should detect potential problem reference to node id that does not exist', () => { | ||
const projectJSON = { | ||
nodes: [new Node(groupId1, [nodeId1, nodeId2], []), new Node(nodeId1, null, [])] | ||
}; | ||
setProjectJSONStringAndTriggerChange(JSON.stringify(projectJSON)); | ||
expect(component.badNodes.length).toEqual(1); | ||
expect(component.badNodes[0].referencedIdsThatDoNotExist).toEqual([nodeId2]); | ||
}); | ||
|
||
it('should detect potential problem reference to node id duplicate', () => { | ||
const projectJSON = { | ||
nodes: [ | ||
new Node(groupId1, [nodeId1, nodeId1], []), | ||
new Node(nodeId1, null, [{ to: nodeId2 }]), | ||
new Node(nodeId2, null, []) | ||
] | ||
}; | ||
setProjectJSONStringAndTriggerChange(JSON.stringify(projectJSON)); | ||
expect(component.badNodes.length).toEqual(1); | ||
expect(component.badNodes[0].referencedIdsThatAreDuplicated).toEqual([nodeId1]); | ||
}); | ||
} | ||
|
||
function setProjectJSONStringAndTriggerChange(jsonString: string): void { | ||
component.projectJSONString = jsonString; | ||
component.projectJSONChanged(); | ||
} | ||
|
||
function save() { | ||
describe('save()', () => { | ||
it('should save and disable save button', () => { | ||
component.saveButtonEnabled = true; | ||
component.save(); | ||
expect(component.saveButtonEnabled).toBeFalsy(); | ||
}); | ||
}); | ||
} |
Oops, something went wrong.