From f57ffeb428f9c7b5708ebb7e64a316e40d13090f Mon Sep 17 00:00:00 2001 From: Labibatanjim Date: Thu, 7 May 2026 21:02:48 +1000 Subject: [PATCH 1/4] feat: add dashboard list item component --- .../dashboard-list-item.component.html | 8 +++++++ .../dashboard-list-item.component.scss | 22 +++++++++++++++++ .../dashboard-list-item.component.ts | 24 +++++++++++++++++++ src/app/doubtfire-angular.module.ts | 3 ++- 4 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 src/app/dashboard/dashboard-list-item.component.html create mode 100644 src/app/dashboard/dashboard-list-item.component.scss create mode 100644 src/app/dashboard/dashboard-list-item.component.ts diff --git a/src/app/dashboard/dashboard-list-item.component.html b/src/app/dashboard/dashboard-list-item.component.html new file mode 100644 index 000000000..ef5bd52e5 --- /dev/null +++ b/src/app/dashboard/dashboard-list-item.component.html @@ -0,0 +1,8 @@ +
+

{{ task?.title }}

+ +
+ Task {{ task?.number }} + {{ task?.type }} +
+
\ No newline at end of file diff --git a/src/app/dashboard/dashboard-list-item.component.scss b/src/app/dashboard/dashboard-list-item.component.scss new file mode 100644 index 000000000..463fb3471 --- /dev/null +++ b/src/app/dashboard/dashboard-list-item.component.scss @@ -0,0 +1,22 @@ +.task-item { + padding: 12px; + border-radius: 8px; + background: white; + cursor: pointer; + margin-bottom: 10px; + box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); + + &:hover { + background: #f5f5f5; + } +} + +.task-details { + display: flex; + justify-content: space-between; + font-size: 12px; +} + +.task-type { + font-weight: bold; +} \ No newline at end of file diff --git a/src/app/dashboard/dashboard-list-item.component.ts b/src/app/dashboard/dashboard-list-item.component.ts new file mode 100644 index 000000000..8c3dd6171 --- /dev/null +++ b/src/app/dashboard/dashboard-list-item.component.ts @@ -0,0 +1,24 @@ +import { Component, Input } from '@angular/core'; +import { Router } from '@angular/router'; + +@Component({ + selector: 'dashboard-list-item', + templateUrl: './dashboard-list-item.component.html', + styleUrls: ['./dashboard-list-item.component.scss'] +}) +export class DashboardListItemComponent { + @Input() task: any; + + constructor(private router: Router) {} + + goToTask() { + if (!this.task) return; + + this.router.navigate([ + '/units', + this.task.unitId, + 'tasks', + this.task.id + ]); + } +} \ No newline at end of file diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 879db426d..78ddb71d2 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -44,7 +44,7 @@ import {MatDialogModule as MatDialogModuleNew} from '@angular/material/dialog'; import {AlertService} from 'src/app/common/services/alert.service'; import {AlertComponent} from 'src/app/common/services/alert.service'; import {MatSidenavModule} from '@angular/material/sidenav'; - +import { DashboardListItemComponent } from './dashboard/dashboard-list-item.component'; import {setTheme} from 'ngx-bootstrap/utils'; import {CodeEditorModule} from '@ngstack/code-editor'; @@ -366,6 +366,7 @@ const GANTT_CHART_CONFIG = { @NgModule({ // Components we declare declarations: [ + DashboardListItemComponent, AlertComponent, AboutDoubtfireModalContent, D2lUnitDetailsFormComponent, From 88a866ea7ff2e17be331ec2c09b7c2d67f4c667c Mon Sep 17 00:00:00 2001 From: Cilly Leang Date: Tue, 12 May 2026 22:33:08 +1000 Subject: [PATCH 2/4] feat(dashboard): create dashboard list item --- .../dashboard-list-item.component.html | 19 +++++++----- .../dashboard-list-item.component.scss | 22 ------------- .../dashboard-list-item.component.ts | 31 +++++++------------ 3 files changed, 24 insertions(+), 48 deletions(-) delete mode 100644 src/app/dashboard/dashboard-list-item.component.scss diff --git a/src/app/dashboard/dashboard-list-item.component.html b/src/app/dashboard/dashboard-list-item.component.html index ef5bd52e5..f4d34fdcc 100644 --- a/src/app/dashboard/dashboard-list-item.component.html +++ b/src/app/dashboard/dashboard-list-item.component.html @@ -1,8 +1,13 @@ -
-

{{ task?.title }}

- -
- Task {{ task?.number }} - {{ task?.type }} +
+
+
+

{{ task.title }}

+

{{ task.subtitle }}

-
\ No newline at end of file +
+
+ {{ task.comments }} +
+ keyboard_arrow_down +
+
diff --git a/src/app/dashboard/dashboard-list-item.component.scss b/src/app/dashboard/dashboard-list-item.component.scss deleted file mode 100644 index 463fb3471..000000000 --- a/src/app/dashboard/dashboard-list-item.component.scss +++ /dev/null @@ -1,22 +0,0 @@ -.task-item { - padding: 12px; - border-radius: 8px; - background: white; - cursor: pointer; - margin-bottom: 10px; - box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); - - &:hover { - background: #f5f5f5; - } -} - -.task-details { - display: flex; - justify-content: space-between; - font-size: 12px; -} - -.task-type { - font-weight: bold; -} \ No newline at end of file diff --git a/src/app/dashboard/dashboard-list-item.component.ts b/src/app/dashboard/dashboard-list-item.component.ts index 8c3dd6171..b201cfcad 100644 --- a/src/app/dashboard/dashboard-list-item.component.ts +++ b/src/app/dashboard/dashboard-list-item.component.ts @@ -1,24 +1,17 @@ -import { Component, Input } from '@angular/core'; -import { Router } from '@angular/router'; +import {Component, Input} from '@angular/core'; + +export type DashboardTask = { + title: string; + subtitle: string; + abbreviation: string; + color: string; + comments: number; +}; @Component({ - selector: 'dashboard-list-item', + selector: 'f-dashboard-list-item', templateUrl: './dashboard-list-item.component.html', - styleUrls: ['./dashboard-list-item.component.scss'] }) export class DashboardListItemComponent { - @Input() task: any; - - constructor(private router: Router) {} - - goToTask() { - if (!this.task) return; - - this.router.navigate([ - '/units', - this.task.unitId, - 'tasks', - this.task.id - ]); - } -} \ No newline at end of file + @Input() task: DashboardTask; +} From d19717cd5c2dea3bfca37e8645a93205155b82ee Mon Sep 17 00:00:00 2001 From: Cilly Leang Date: Tue, 12 May 2026 22:33:44 +1000 Subject: [PATCH 3/4] feat(dashboard): link up items to main dashboard page --- .../f-cross-dashboard.component.html | 17 +++++-- .../f-cross-dashboard.component.scss | 0 .../dashboard/f-cross-dashboard.component.ts | 48 ++++++++++++------- 3 files changed, 45 insertions(+), 20 deletions(-) delete mode 100644 src/app/dashboard/f-cross-dashboard.component.scss diff --git a/src/app/dashboard/f-cross-dashboard.component.html b/src/app/dashboard/f-cross-dashboard.component.html index dc1a456d7..978148aa1 100644 --- a/src/app/dashboard/f-cross-dashboard.component.html +++ b/src/app/dashboard/f-cross-dashboard.component.html @@ -1,7 +1,7 @@
-
-
+
+

{{ unit.code }}

{{ unit.code }} filter_list_alt
- +
+
+
+ +
+
+
diff --git a/src/app/dashboard/f-cross-dashboard.component.scss b/src/app/dashboard/f-cross-dashboard.component.scss deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/app/dashboard/f-cross-dashboard.component.ts b/src/app/dashboard/f-cross-dashboard.component.ts index 2f1bfcdb6..bd4bbc072 100644 --- a/src/app/dashboard/f-cross-dashboard.component.ts +++ b/src/app/dashboard/f-cross-dashboard.component.ts @@ -1,41 +1,57 @@ import {Component, OnInit} from '@angular/core'; -import {Unit} from 'src/app/api/models/unit'; import {GlobalStateService} from 'src/app/projects/states/index/global-state.service'; +import {Project} from '../api/models/project'; +import {TaskStatus} from '../api/models/task-status'; +import {DashboardTask} from './dashboard-list-item.component'; +import {Task} from '../api/models/task'; +import {TaskDefinition} from '../api/models/task-definition'; -type IUnits = { - id: number; +type DashboardUnit = { + projectId: number; code: string; name: string; - // tasks: ITask[]; + tasks: DashboardTask[]; }; @Component({ selector: 'f-cross-dashboard', templateUrl: './f-cross-dashboard.component.html', - styleUrls: ['./f-cross-dashboard.component.scss'], }) export class CrossDashboardComponent implements OnInit { constructor(private globalStateService: GlobalStateService) {} - units: IUnits[] = []; + units: DashboardUnit[] = []; ngOnInit(): void { this.globalStateService.onLoad(() => { - this.globalStateService.loadedUnits.values.subscribe((units) => { - this.units = this.mapUnits(units); + this.globalStateService.currentUserProjects.values.subscribe((projects) => { + this.units = this.mapProjects(projects); }); }); } - mapUnit(unit: Unit): IUnits { - return { - id: unit.id, - code: unit.code, - name: unit.name, - }; + mapProjects(projects: readonly Project[]): DashboardUnit[] { + return projects.map((project) => { + const unit = project.unit; + return { + projectId: project.id, + code: unit.code, + name: unit.name, + tasks: this.mapTasks(project.tasks, unit.taskDefinitions), + }; + }); } - mapUnits(units: readonly Unit[]) { - return units.map((unit) => this.mapUnit(unit)); + mapTasks(tasks: readonly Task[], taskDefs: readonly TaskDefinition[]): DashboardTask[] { + return taskDefs.map((def) => { + const task = tasks.find((t) => t.taskDefId == def.id); + return { + title: def.name, + subtitle: `${def.abbreviation} - ${def.targetGradeText} Task`, + abbreviation: def.abbreviation, + color: TaskStatus.STATUS_COLORS.get(task?.status ?? 'not_started'), + comments: task?.numNewComments ?? 0, + }; + }); } } From d50d77ab7d48af17b42dd20abebfe5e150f95410 Mon Sep 17 00:00:00 2001 From: Cilly Leang Date: Tue, 12 May 2026 22:34:35 +1000 Subject: [PATCH 4/4] feat(dashboard): include task definitions on initial projects load --- .../states/index/global-state.service.ts | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/app/projects/states/index/global-state.service.ts b/src/app/projects/states/index/global-state.service.ts index 6d3cdb12d..1837e240e 100644 --- a/src/app/projects/states/index/global-state.service.ts +++ b/src/app/projects/states/index/global-state.service.ts @@ -292,18 +292,24 @@ export class GlobalStateService implements OnDestroy { next: (_unitRoles: UnitRole[]) => { // unit roles are now in the cache - this.projectService.query(undefined, {params: {include_in_active: false}}).subscribe({ - next: (_projects: Project[]) => { - // projects updated in cache - - setTimeout(() => { - this.isLoadingSubject.next(false); - }, 800); - }, - error: (_response) => { - this.alerts.error('Unable to access the units you study.', 6000); - }, - }); + this.projectService + .query(undefined, { + params: { + include_inactive: false, + include_task_definitions: true, + }, + }) + .subscribe({ + next: (_projects: Project[]) => { + // projects updated in cache + setTimeout(() => { + this.isLoadingSubject.next(false); + }, 800); + }, + error: (_response) => { + this.alerts.error('Unable to access the units you study.', 6000); + }, + }); }, error: (_response) => { this.alerts.error('Unable to access your units.', 6000);