Skip to content

Commit

Permalink
Merge pull request #878 from doubtfire-lms/looks/visualisations
Browse files Browse the repository at this point in the history
Add in new burndown and task status count visualisations
  • Loading branch information
macite authored Nov 1, 2024
2 parents c583aa0 + bfecd08 commit 90bb12f
Show file tree
Hide file tree
Showing 17 changed files with 7,871 additions and 4,635 deletions.
12,016 changes: 7,466 additions & 4,550 deletions package-lock.json

Large diffs are not rendered by default.

34 changes: 17 additions & 17 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,24 @@
"keywords": [],
"author": "",
"dependencies": {
"@angular/animations": "^18.0.3",
"@angular/cdk": "^18.0.2",
"@angular/common": "^18.0.3",
"@angular/compiler": "^18.0.3",
"@angular/core": "^18.0.3",
"@angular/forms": "^18.0.3",
"@angular/material": "^18.0.2",
"@angular/material-moment-adapter": "^18.0.2",
"@angular/platform-browser": "^18.0.3",
"@angular/platform-browser-dynamic": "^18.0.3",
"@angular/router": "^18.0.3",
"@angular/service-worker": "^18.0.3",
"@angular/upgrade": "^18.0.3",
"@angular/animations": "^18.0",
"@angular/cdk": "^18.0",
"@angular/common": "^18.0",
"@angular/compiler": "^18.0",
"@angular/core": "^18.0",
"@angular/forms": "^18.0",
"@angular/material": "^18.0",
"@angular/material-moment-adapter": "^18.0",
"@angular/platform-browser": "^18.0",
"@angular/platform-browser-dynamic": "^18.0",
"@angular/router": "^18.0",
"@angular/service-worker": "^18.0",
"@angular/upgrade": "^18.0",
"@ctrl/ngx-emoji-mart": "^9.2.0",
"@ngneat/hotkeys": "^4.0.0",
"@uirouter/angular": "^14.0",
"@uirouter/angular-hybrid": "^18.0",
"@swimlane/ngx-charts": "^20.5.0",
"@uirouter/angular": "^13.0",
"@uirouter/angular-hybrid": "^17.1.0",
"@uirouter/angularjs": "^1.0.30",
"@uirouter/core": "^6.1.0",
"@uirouter/rx": "^1.0.0",
Expand Down Expand Up @@ -85,11 +85,12 @@
"ngx-bootstrap": "^6.1.0",
"ngx-entity-service": "^0.0.39",
"ngx-lottie": "^11.0.2",
"npm": "^10.4.0",
"nvd3": "1.8.6",
"rxjs": "~7.4.0",
"ts-md5": "^1.3.1",
"tslib": "^2.6.2",
"typescript-eslint": "^7.13.0",
"typescript-eslint": "^8.12.0",
"underscore.string": "2.3.3",
"zone.js": "~0.14"
},
Expand Down Expand Up @@ -118,7 +119,6 @@
"autoprefixer": "~6",
"canonical-path": "0.0.2",
"concurrently": "^3.2.0",
"eslint": "9",
"grunt": "^1.0.4",
"grunt-bump": "0.8.0",
"grunt-coffeelint": "0.0.16",
Expand Down
15 changes: 15 additions & 0 deletions src/app/api/models/task-status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,21 @@ export class TaskStatus {
['time_exceeded', 'Time Exceeded'],
]);

public static readonly STATUS_NAME_TO_KEY = new Map<string, TaskStatusEnum>([
['Ready for Feedback', 'ready_for_feedback'],
['Not Started', 'not_started'],
['Working On It', 'working_on_it'],
['Need Help', 'need_help'],
['Redo', 'redo'],
['Feedback Exceeded', 'feedback_exceeded'],
['Resubmit', 'fix_and_resubmit'],
['Discuss', 'discuss'],
['Demonstrate', 'demonstrate'],
['Complete', 'complete'],
['Fail', 'fail'],
['Time Exceeded', 'time_exceeded'],
]);

public static readonly STATUS_ICONS = new Map<TaskStatusEnum, string>([
['ready_for_feedback', 'fa fa-thumbs-o-up'],
['not_started', 'fa fa-pause'],
Expand Down
11 changes: 11 additions & 0 deletions src/app/api/services/mapping-fn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,15 @@ export class MappingFunctions {
const diff = this.daysBetween(date1, date2);
return Math.ceil(diff / 7);
}

/**
* Calculate the date that is a number of days after a given date
*
* @param date start date
* @param days number of days to add
* @returns the date that is that many days after the start date
*/
public static daysAfter(date: Date, days: number): Date {
return new Date(date.getTime() + this.dayMs(days));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Component, ViewContainerRef } from '@angular/core';
import { TooltipService } from '@swimlane/ngx-charts';
import { AppInjector } from "src/app/app-injector";

/**
* @title chart-base-component
* @desc This is a base class to be used with the ngx-charts library. It is used to set the root view container for the tooltip service, to avoid issues with the tooltip not displaying correctly.
*
* Child classes need to extend this class and call super() in the constructor, passing in the ViewContainerRef.
*/
@Component({
template: `<p>chart-base-component works!</p>`,
})
export class ChartBaseComponent {
constructor(public viewContainerRef: ViewContainerRef) {
const chartToolTipService = AppInjector.get(TooltipService);
chartToolTipService.injectionService.setRootViewContainer(this.viewContainerRef);
}
}
49 changes: 29 additions & 20 deletions src/app/doubtfire-angular.module.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import {interval} from 'rxjs';
import {take} from 'rxjs/operators';

import {NgModule, Injector, DoBootstrap} from '@angular/core';
import {BrowserModule, DomSanitizer, Title} from '@angular/platform-browser';
import {UpgradeModule} from '@angular/upgrade/static';
import {AppInjector, setAppInjector} from './app-injector';
import {HTTP_INTERCEPTORS, HttpClientModule} from '@angular/common/http';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import { NgModule, Injector, DoBootstrap } from '@angular/core';
import { BrowserModule, DomSanitizer, Title } from '@angular/platform-browser';
import { UpgradeModule } from '@angular/upgrade/static';
import { AppInjector, setAppInjector } from './app-injector';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgxChartsModule } from '@swimlane/ngx-charts';

// Lottie animation module
// import {LottieModule, LottieCacheModule} from 'ngx-lottie';
Expand Down Expand Up @@ -112,7 +113,6 @@ import {StudentTutorialSelectComponent} from './units/states/edit/directives/uni
import {StudentCampusSelectComponent} from './units/states/edit/directives/unit-students-editor/student-campus-select/student-campus-select.component';
import {ServiceWorkerModule} from '@angular/service-worker';
import {environment} from 'src/environments/environment';
import {NgxChartsModule} from '@swimlane/ngx-charts';
import {PickerModule} from '@ctrl/ngx-emoji-mart';
import {EmojiModule} from '@ctrl/ngx-emoji-mart/ngx-emoji';
import {EmojiService} from './common/services/emoji.service';
Expand Down Expand Up @@ -217,19 +217,23 @@ import {
TeachingPeriodUnitImportDialogComponent,
TeachingPeriodUnitImportService,
} from './admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog';
import {AcceptEulaComponent} from './eula/accept-eula/accept-eula.component';
import {TiiActionLogComponent} from './admin/tii-action-log/tii-action-log.component';
import {TiiActionService} from './api/services/tii-action.service';
import {FUnitsComponent} from './admin/states/units/units.component';
import {FUnitTaskListComponent} from './units/task-viewer/directives/unit-task-list/unit-task-list.component';
import {FTaskDetailsViewComponent} from './units/task-viewer/directives/task-details-view/task-details-view.component';
import {FTaskSheetViewComponent} from './units/task-viewer/directives/task-sheet-view/task-sheet-view.component';
import {UnitCodeComponent} from './common/unit-code/unit-code.component';
import {GradeService} from './common/services/grade.service';
import {UnitRootStateComponent} from './units/unit-root-state.component';
import {TaskViewerStateComponent} from './units/task-viewer/task-viewer-state.component';
import {ProjectRootStateComponent} from './projects/states/project-root-state.component';
import {ProjectProgressDashboardComponent} from './projects/project-progress-dashboard/project-progress-dashboard.component';

import { AcceptEulaComponent } from './eula/accept-eula/accept-eula.component';
import { TiiActionLogComponent } from './admin/tii-action-log/tii-action-log.component';
import { TiiActionService } from './api/services/tii-action.service';
import { FUnitsComponent } from './admin/states/units/units.component';
import { FUnitTaskListComponent } from './units/task-viewer/directives/unit-task-list/unit-task-list.component';
import { FTaskDetailsViewComponent } from './units/task-viewer/directives/task-details-view/task-details-view.component';
import { FTaskSheetViewComponent } from './units/task-viewer/directives/task-sheet-view/task-sheet-view.component';
import { UnitCodeComponent } from './common/unit-code/unit-code.component';
import { GradeService } from './common/services/grade.service';
import { UnitRootStateComponent } from './units/unit-root-state.component';
import { TaskViewerStateComponent } from './units/task-viewer/task-viewer-state.component';
import { ProjectRootStateComponent } from './projects/states/project-root-state.component';
import { ProjectProgressDashboardComponent } from './projects/project-progress-dashboard/project-progress-dashboard.component';
import { ProgressBurndownChartComponent } from './visualisations/progress-burndown-chart/progressburndownchart.component';
import { TaskVisualisationComponent } from './visualisations/task-visualisation/taskvisualisation.component';
import { ChartBaseComponent } from './common/chart-base/chart-base-component/chart-base-component.component';

@NgModule({
// Components we declare
Expand Down Expand Up @@ -336,6 +340,10 @@ import {ProjectProgressDashboardComponent} from './projects/project-progress-das
ProjectProgressGaugeComponent,
FTaskBadgeComponent,
FUnitsComponent,
ChartBaseComponent,
ProgressBurndownChartComponent,
TaskVisualisationComponent

],
// Services we provide
providers: [
Expand Down Expand Up @@ -472,6 +480,7 @@ import {ProjectProgressDashboardComponent} from './projects/project-progress-das
MatDatepickerModule,
MatNativeDateModule,
MatDialogModuleNew,
NgxChartsModule
],
})

Expand Down
75 changes: 44 additions & 31 deletions src/app/doubtfire-angularjs.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,37 +186,39 @@ import {
UnitService,
UserService,
} from './api/models/doubtfire-model';
import {FileDownloaderService} from './common/file-downloader/file-downloader.service';
import {CheckForUpdateService} from './sessions/service-worker-updater/check-for-update.service';
import {TaskSubmissionService} from './common/services/task-submission.service';
import {TaskAssessmentModalService} from './common/modals/task-assessment-modal/task-assessment-modal.service';
import {TaskSubmissionHistoryComponent} from './tasks/task-submission-history/task-submission-history.component';
import {HeaderComponent} from './common/header/header.component';
import {SplashScreenComponent} from './home/splash-screen/splash-screen.component';
import {GlobalStateService} from './projects/states/index/global-state.service';
import {TransitionHooksService} from './sessions/transition-hooks.service';
import {AuthenticationService} from './api/services/authentication.service';
import {ProjectService} from './api/services/project.service';
import {ObjectSelectComponent} from './common/obect-select/object-select.component';
import {TaskDefinitionService} from './api/services/task-definition.service';
import {EditProfileDialogService} from './common/modals/edit-profile-dialog/edit-profile-dialog.service';
import {GroupService} from './api/services/group.service';
import {UserBadgeComponent} from './common/user-badge/user-badge.component';
import {TaskStatusCardComponent} from './projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component';
import {TaskDueCardComponent} from './projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component';
import {FooterComponent} from './common/footer/footer.component';
import {TaskAssessmentCardComponent} from './projects/states/dashboard/directives/task-dashboard/directives/task-assessment-card/task-assessment-card.component';
import {TaskSubmissionCardComponent} from './projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.component';
import {InboxComponent} from './units/states/tasks/inbox/inbox.component';
import {TaskDefinitionEditorComponent} from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component';
import {UnitAnalyticsComponent} from './units/states/analytics/unit-analytics-route.component';
import {UnitTaskEditorComponent} from './units/states/edit/directives/unit-tasks-editor/unit-task-editor.component';
import {TeachingPeriodUnitImportService} from './admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog';
import {CreateNewUnitModal} from './admin/modals/create-new-unit-modal/create-new-unit-modal.component';
import {FUsersComponent} from './admin/states/users/users.component';
import {FUnitTaskListComponent} from './units/task-viewer/directives/unit-task-list/unit-task-list.component';
import {FTaskDetailsViewComponent} from './units/task-viewer/directives/task-details-view/task-details-view.component';
import {FTaskSheetViewComponent} from './units/task-viewer/directives/task-sheet-view/task-sheet-view.component';
import { FileDownloaderService } from './common/file-downloader/file-downloader.service';
import { CheckForUpdateService } from './sessions/service-worker-updater/check-for-update.service';
import { TaskSubmissionService } from './common/services/task-submission.service';
import { TaskAssessmentModalService } from './common/modals/task-assessment-modal/task-assessment-modal.service';
import { TaskSubmissionHistoryComponent } from './tasks/task-submission-history/task-submission-history.component';
import { HeaderComponent } from './common/header/header.component';
import { SplashScreenComponent } from './home/splash-screen/splash-screen.component';
import { GlobalStateService } from './projects/states/index/global-state.service';
import { TransitionHooksService } from './sessions/transition-hooks.service';
import { AuthenticationService } from './api/services/authentication.service';
import { ProjectService } from './api/services/project.service';
import { ObjectSelectComponent } from './common/obect-select/object-select.component';
import { TaskDefinitionService } from './api/services/task-definition.service';
import { EditProfileDialogService } from './common/modals/edit-profile-dialog/edit-profile-dialog.service';
import { GroupService } from './api/services/group.service';
import { UserBadgeComponent } from './common/user-badge/user-badge.component';
import { TaskStatusCardComponent } from './projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component';
import { TaskDueCardComponent } from './projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component';
import { FooterComponent } from './common/footer/footer.component';
import { TaskAssessmentCardComponent } from './projects/states/dashboard/directives/task-dashboard/directives/task-assessment-card/task-assessment-card.component';
import { TaskSubmissionCardComponent } from './projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.component';
import { InboxComponent } from './units/states/tasks/inbox/inbox.component';
import { TaskDefinitionEditorComponent } from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component';
import { UnitAnalyticsComponent } from './units/states/analytics/unit-analytics-route.component';
import { UnitTaskEditorComponent } from './units/states/edit/directives/unit-tasks-editor/unit-task-editor.component';
import { TeachingPeriodUnitImportService } from './admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog';
import { CreateNewUnitModal } from './admin/modals/create-new-unit-modal/create-new-unit-modal.component';
import { FUsersComponent } from './admin/states/users/users.component';
import { FUnitTaskListComponent } from './units/task-viewer/directives/unit-task-list/unit-task-list.component';
import { FTaskDetailsViewComponent } from './units/task-viewer/directives/task-details-view/task-details-view.component';
import { FTaskSheetViewComponent } from './units/task-viewer/directives/task-sheet-view/task-sheet-view.component';
import { ProgressBurndownChartComponent } from './visualisations/progress-burndown-chart/progressburndownchart.component';
import { TaskVisualisationComponent } from './visualisations/task-visualisation/taskvisualisation.component';

import {FUnitsComponent} from './admin/states/units/units.component';
import {MarkedPipe} from './common/pipes/marked.pipe';
Expand Down Expand Up @@ -469,3 +471,14 @@ const otherwiseConfigBlock = [
},
];
DoubtfireAngularJSModule.config(otherwiseConfigBlock);


DoubtfireAngularJSModule.directive(
'fProgressBurndownChart',
downgradeComponent({ component: ProgressBurndownChartComponent })
);

DoubtfireAngularJSModule.directive(
'fTaskVisualisation',
downgradeComponent({ component: TaskVisualisationComponent })
);
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,12 @@ <h1 class="text-5xl mb-0 mr-2">Targetting</h1>
</mat-card-header>
<mat-card-content>
<div class="w-full h-full flex items-center justify-center">
<f-project-progress-gauge [project]="project"></f-project-progress-gauge>
<!-- <f-project-progress-gauge [project]="project"></f-project-progress-gauge> -->
<f-progress-burndown-chart [project]="project" [unit]="project.unit" [grade]="project.targetGrade"></f-progress-burndown-chart>
<f-task-visualisation
[project]="project"
[grade]="project.targetGrade">
</f-task-visualisation>
</div>
</mat-card-content>
</mat-card>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ <h4>Progress Burndown</h4>
</div>
</div><!--/burndown-heading-->
<div class="card-body">
<progress-burndown-chart project="project" unit="project.unit"></progress-burndown-chart>
<f-progress-burndown-chart [project]="project" [unit]="project.unit" [grade]="project.targetGrade"></f-progress-burndown-chart>
</div><!--/burndown-body-->
<div class="card-footer">
Aim to keep your
Expand All @@ -47,10 +47,10 @@ <h4>Task Statuses</h4>
</div>
</div><!--/pie-chart-heading-->
<div class="card-body">
<student-task-status-pie-chart
project="project"
update-data="renderTaskStatusPieChart">
</student-task-status-pie-chart>
<f-task-visualisation
[project]="project"
[grade]="project.targetGrade">
</f-task-visualisation>
</div><!--/pie-chart-body-->
</div><!--/pie-chart-card-->
</div><!--/pie-chart-column-->
Expand Down
28 changes: 17 additions & 11 deletions src/app/projects/states/project-root-state.component.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import {Component, Input} from '@angular/core';
import {Observable, first} from 'rxjs';
import {AsyncSubject, Observable, Subscriber, first} from 'rxjs';
import {Project, ProjectService} from 'src/app/api/models/doubtfire-model';
import {AppInjector} from 'src/app/app-injector';
import {NgHybridStateDeclaration} from '@uirouter/angular-hybrid';
Expand Down Expand Up @@ -32,19 +32,25 @@ export const ProjectRootState: NgHybridStateDeclaration = {
project$: function ($stateParams) {
const projectService = AppInjector.get(ProjectService);
const globalState = AppInjector.get(GlobalStateService);
const projectId = parseInt($stateParams.projectId);

return new Observable<Project>((observer) => {
const projectId = parseInt($stateParams.projectId);
const result = new AsyncSubject<Project>();

globalState.onLoad(() => {
projectService.get({id: projectId}, {cacheBehaviourOnGet: 'cacheQuery'}).subscribe({
next: (project: Project) => {
observer.next(project);
observer.complete();
},
});
const mappingCompleteCallback = (entity: Project) => {
result.next(entity);
result.complete();
}

// Async call to load the project
globalState.onLoad(() => {
projectService.get({id: projectId}, {cacheBehaviourOnGet: 'cacheQuery', mappingCompleteCallback: mappingCompleteCallback}).subscribe({
next: (_project: Project) => {
// Do nothing - the mappingCompleteCallback will be called when complete
},
});
}).pipe(first());
});

return result;
},
},
};
3 changes: 3 additions & 0 deletions src/app/units/task-viewer/task-viewer-state.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
width: 10px
}

// HACK - issue access this from the main style.scss
$main-view-max-height: calc((var(--vh, 1vh) * (100)) - 85px);

f-task-viewer-state {
height: calc($main-view-max-height + 70px); // temporary fix to reclaim the footer region for this specific page
display: flex;
Expand Down
Loading

0 comments on commit 90bb12f

Please sign in to comment.