Skip to content

Commit

Permalink
chore(Export): Convert export step visits (#906)
Browse files Browse the repository at this point in the history
  • Loading branch information
geoffreykwan authored Nov 18, 2022
1 parent ee226ad commit 42fd777
Show file tree
Hide file tree
Showing 12 changed files with 738 additions and 1,324 deletions.
25 changes: 19 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"drawing-tool": "^2.1.2",
"eventemitter2": "^5.0.1",
"fabric": "3.6.3",
"file-saver": "^2.0.5",
"highcharts": "^9.3.3",
"highcharts-angular": "^2.10.0",
"html2canvas": "^0.5.0-beta4",
Expand Down
2 changes: 2 additions & 0 deletions src/app/teacher/classroom-monitor.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ import { NodeProgressViewComponent } from '../../assets/wise5/classroomMonitor/c
import { TopBarComponent } from '../../assets/wise5/classroomMonitor/classroomMonitorComponents/shared/top-bar/top-bar.component';
import { NotebookGradingComponent } from '../../assets/wise5/classroomMonitor/notebook-grading/notebook-grading.component';
import { StudentGradingComponent } from '../../assets/wise5/classroomMonitor/student-grading/student-grading.component';
import { ExportStepVisitsComponent } from '../../assets/wise5/classroomMonitor/dataExport/export-step-visits/export-step-visits.component';

@NgModule({
declarations: [
Expand All @@ -72,6 +73,7 @@ import { StudentGradingComponent } from '../../assets/wise5/classroomMonitor/stu
EditComponentAnnotationsComponent,
EditComponentCommentComponent,
EditComponentScoreComponent,
ExportStepVisitsComponent,
GradingEditComponentMaxScoreComponent,
ManagePeriodComponent,
ManageShowStudentInfoComponent,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import { downgradeInjectable } from '@angular/upgrade/static';
import { downgradeComponent, downgradeInjectable } from '@angular/upgrade/static';
import * as angular from 'angular';
import { ComponentServiceLookupService } from '../../services/componentServiceLookupService';
import { DataExportService } from '../../services/dataExportService';
import DataExportController from './dataExportController';
import ExportController from './exportController';
import ExportVisitsController from './exportVisitsController';
import { ExportStepVisitsComponent } from './export-step-visits/export-step-visits.component';

export default angular
.module('dataExport', ['ngFileSaver'])
.factory('DataExportService', downgradeInjectable(DataExportService))
.factory('ComponentServiceLookupService', downgradeInjectable(ComponentServiceLookupService))
.controller('DataExportController', DataExportController)
.controller('ExportController', ExportController)
.controller('ExportVisitsController', ExportVisitsController)
.directive('exportStepVisits', downgradeComponent({ component: ExportStepVisitsComponent }))
.config([
'$stateProvider',
($stateProvider) => {
Expand All @@ -25,9 +23,7 @@ export default angular
})
.state('root.cm.exportVisits', {
url: '/export/visits',
templateUrl: '/assets/wise5/classroomMonitor/dataExport/exportVisits.html',
controller: 'ExportVisitsController',
controllerAs: 'exportVisitsController'
component: 'exportStepVisits'
});
}
]);
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<div class="view-content view-content--with-sidemenu top-content">
<div class="l-constrained">
<div class="main-div">
<button mat-raised-button
color="primary"
(click)="goBack()"
matToolip="Back"
matTooltipPosition="above"
i18n-matToolip>
<mat-icon>arrow_back</mat-icon>
</button>
<h5 i18n>Export Step Visit Events</h5>
<div class="top-explanations-buttons">
<button mat-raised-button
color="primary"
(click)="toggleColumnExplanations()">
<ng-container *ngIf="isShowColumnExplanations; else isHidingColumnExplanationsTop" i18n>
Hide Column Explanations
</ng-container>
<ng-template #isHidingColumnExplanationsTop i18n>
Show Column Explanations
</ng-template>
</button>
</div>
<div *ngIf="isShowColumnExplanations">
<table>
<tr>
<th class="explanation-column-name" i18n>Column Name</th>
<th i18n>Explanation</th>
</tr>
<tr *ngFor="let columnExplanation of columnExplanations">
<td>{{ columnExplanation.name }}</td>
<td>{{ columnExplanation.explanation }}</td>
</tr>
</table>
<div class="bottom-explanations-buttons">
<button mat-raised-button
color="primary"
(click)="toggleColumnExplanations()"
i18n>
Hide Column Explanations
</button>
</div>
</div>
<mat-checkbox *ngIf="canViewStudentNames"
color="primary"
class="include-student-names"
[(ngModel)]="includeStudentNames">
<h6 class="checkbox-label" i18n>Include Student Names</h6>
</mat-checkbox>
<h6 i18n>Choose Steps</h6>
<div class="select-all-buttons" fxLayoutGap="20px">
<button mat-raised-button color="primary" (click)="selectAll()" i18n>Select All</button>
<button mat-raised-button color="primary" (click)="deselectAll()" i18n>Deselect All</button>
<button mat-raised-button color="primary" (click)="export()" i18n>Export</button>
</div>
<ng-container *ngFor="let value of nodes; index as index">
<div *ngIf="index !== 0">
<mat-checkbox color="primary"
[ngClass]="{'md-primary': true, 'group-header': value.node.type === 'group', 'step-header': value.node.type === 'node'}"
[(ngModel)]="idToChecked[value.node.id]"
(ngModelChange)="nodeChecked(value.node)">
<h6 class="checkbox-label">{{ idToStepNumberAndTitle[value.node.id] }}</h6>
</mat-checkbox>
</div>
</ng-container>
<div>
<mat-checkbox color="primary"
[ngClass]="{'md-primary': true, 'group-header': 'group'}"
[(ngModel)]="includeDeletedSteps">
<h6 class="checkbox-label" i18n>Include Deleted Steps (If Any)</h6>
</mat-checkbox>
</div>
<div>
<button mat-raised-button color="primary" (click)="export()" i18n>Export</button>
<div fxFlex></div>
<button mat-raised-button
color="primary"
(click)="backToTop()"
matTooltip="Back To Top"
matTooltipPosition="above"
i18n-matTooltip>
<mat-icon>arrow_upward</mat-icon>
</button>
</div>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
.main-div {
margin-top: 20px;
margin-left: 20px;
}

.group-header {
margin-left: 20px;
margin-bottom: 16px;
}

.step-header {
margin-left: 40px;
margin-bottom: 16px;
}

table, tr, th, td {
border: 1px solid black;
}

th, td {
padding: 10px;
}

.top-explanations-buttons {
margin-bottom: 10px;
}

.bottom-explanations-buttons {
margin-top: 10px;
}

.explanation-column-name {
width: 200px;
}

.include-student-names {
margin-left: 10px;
margin-top: 10px;
}

.select-all-buttons {
margin-bottom: 20px;
}

.checkbox-label {
cursor: pointer;
display: inline;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FormsModule } from '@angular/forms';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatIconModule } from '@angular/material/icon';
import { ConfigService } from '../../../services/configService';
import { DataExportService } from '../../../services/dataExportService';
import { TeacherProjectService } from '../../../services/teacherProjectService';
import { ClassroomMonitorTestingModule } from '../../classroom-monitor-testing.module';
import { ExportStepVisitsComponent } from './export-step-visits.component';

let component: ExportStepVisitsComponent;
let fixture: ComponentFixture<ExportStepVisitsComponent>;
const group0Id = 'group0';
const group1Id = 'group1';
const node1Id = 'node1';
const node2Id = 'node2';
const node3Id = 'node3';
const allIds = [group0Id, group1Id, node1Id, node2Id, node3Id];

const group0 = createGroupNode(group0Id, [group1Id]);
const group1 = createGroupNode(group1Id, [node1Id, node2Id, node3Id]);
const node1 = createStepNode(node1Id);
const node2 = createStepNode(node2Id);
const node3 = createStepNode(node3Id);

describe('ExportStepVisitsComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ExportStepVisitsComponent],
imports: [ClassroomMonitorTestingModule, FormsModule, MatCheckboxModule, MatIconModule],
providers: [DataExportService]
}).compileComponents();
});

beforeEach(() => {
fixture = TestBed.createComponent(ExportStepVisitsComponent);
component = fixture.componentInstance;
spyOn(TestBed.inject(ConfigService), 'getPermissions').and.returnValue({
canAuthorProject: true,
canGradeStudentWork: true,
canViewStudentNames: true
});
spyOn(TestBed.inject(TeacherProjectService), 'getNodeOrderOfProject').and.returnValue({
nodes: [{ node: group0 }, { node: group1 }, { node: node1 }, { node: node2 }, { node: node3 }]
});
fixture.detectChanges();
});

selectAll();
deselectAll();
nodeChecked();
});

function createGroupNode(id: string, ids: string[]) {
return { id: id, type: 'group', ids: ids };
}

function createStepNode(id: string) {
return { id: id, type: 'node' };
}

function selectAll() {
describe('selectAll', () => {
it('should select all', () => {
setIdToCheckedForAll(component.idToChecked, false);
component.selectAll();
expectIdToCheckedForAll(component.idToChecked, true);
});
});
}

function setIdToCheckedForAll(idToChecked: any, value: boolean) {
for (const id of allIds) {
idToChecked[id] = value;
}
}

function expectIdToCheckedForAll(idToChecked: any, value: boolean) {
for (const id of allIds) {
expect(idToChecked[id]).toEqual(value);
}
}

function deselectAll() {
describe('deselectAll', () => {
it('should deselect all', () => {
setIdToCheckedForAll(component.idToChecked, true);
component.deselectAll();
expectIdToCheckedForAll(component.idToChecked, false);
});
});
}

function nodeChecked() {
describe('nodeChecked', () => {
it('should check a group node', () => {
setIdToCheckedForAll(component.idToChecked, false);
component.idToChecked[group1Id] = true;
component.nodeChecked(group1);
expect(component.idToChecked[group0Id]).toEqual(false);
expect(component.idToChecked[group1Id]).toEqual(true);
expect(component.idToChecked[node1Id]).toEqual(true);
expect(component.idToChecked[node2Id]).toEqual(true);
expect(component.idToChecked[node3Id]).toEqual(true);
});
it('should check a step node', () => {
setIdToCheckedForAll(component.idToChecked, false);
component.idToChecked[node1Id] = true;
component.nodeChecked(node1);
expect(component.idToChecked[group0Id]).toEqual(false);
expect(component.idToChecked[group1Id]).toEqual(false);
expect(component.idToChecked[node1Id]).toEqual(true);
expect(component.idToChecked[node2Id]).toEqual(false);
expect(component.idToChecked[node3Id]).toEqual(false);
});
});
}
Loading

0 comments on commit 42fd777

Please sign in to comment.