Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…into 7.0.x
  • Loading branch information
macite committed Jun 20, 2023
2 parents 48ab807 + 24d4cdb commit 17050f9
Show file tree
Hide file tree
Showing 12 changed files with 179 additions and 57 deletions.
29 changes: 29 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,35 @@

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

### [7.0.14](https://github.com/macite/doubtfire-deploy/compare/v7.0.13...v7.0.14) (2023-06-18)


### Features

* sort staff in unit import ([5399627](https://github.com/macite/doubtfire-deploy/commit/539962715916a1c5a8ca6314095d841305492a8a))
* unit import staff autocomplete ([b489620](https://github.com/macite/doubtfire-deploy/commit/b489620e8eb2f20379d18fcf27a3ecc951c924a5))

### [7.0.13](https://github.com/macite/doubtfire-deploy/compare/v7.0.12...v7.0.13) (2023-06-17)


### Bug Fixes

* correct location of gtag ([a681622](https://github.com/macite/doubtfire-deploy/commit/a681622bd707acf40612136e2af10e85f3fa4bad))
* update google analytics ([c0b913a](https://github.com/macite/doubtfire-deploy/commit/c0b913aa3187abbe31e743390bb68c6daba48bf0))

### [7.0.12](https://github.com/macite/doubtfire-deploy/compare/v7.0.9...v7.0.12) (2023-06-17)


### Features

* streamline unit import ([4e6827c](https://github.com/macite/doubtfire-deploy/commit/4e6827c1a57dd22ffda38329d7ecc5cf56097c40))


### Bug Fixes

* grade should not updated on assessment fail ([6e065e6](https://github.com/macite/doubtfire-deploy/commit/6e065e61702be5bde11a05675346dbdea8f1843d))
* tasks inclusion in portfolio creation ([f86a8c5](https://github.com/macite/doubtfire-deploy/commit/f86a8c5571059bb1d2606d90cb3902bfb6f30b4b))

### [7.0.11](https://github.com/macite/doubtfire-deploy/compare/v7.0.10...v7.0.11) (2023-06-02)


Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "doubtfire",
"version": "7.0.11",
"version": "7.0.14",
"homepage": "http://github.com/doubtfire-lms/",
"description": "Learning and feedback tool.",
"license": "AGPL-3.0",
Expand Down
6 changes: 2 additions & 4 deletions src/app/account/edit-profile/edit-profile.component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { EditProfileComponent } from './edit-profile.component';

describe('EditProfileComponent', () => {
Expand All @@ -8,9 +7,8 @@ describe('EditProfileComponent', () => {

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ EditProfileComponent ]
})
.compileComponents();
declarations: [EditProfileComponent]
}).compileComponents();

fixture = TestBed.createComponent(EditProfileComponent);
component = fixture.componentInstance;
Expand Down
7 changes: 2 additions & 5 deletions src/app/account/edit-profile/edit-profile.component.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import { Component, OnInit } from '@angular/core';
import { Component } from '@angular/core';

@Component({
selector: 'f-edit-profile',
templateUrl: './edit-profile.component.html',
styleUrls: ['./edit-profile.component.scss'],
})
export class EditProfileComponent implements OnInit {
constructor() {}

ngOnInit(): void {}
export class EditProfileComponent {
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,16 @@ <h3>Activities</h3>
</div>
</div>
<table mat-table [dataSource]="dataSource" matSort (matSortChange)="sortTableData($event)" class="mat-elevation-z3">

<!-- Name Column -->
<ng-container [formGroup]="formData" matColumnDef="name">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Name </th>
<th mat-header-cell *matHeaderCellDef mat-sort-header>Name</th>
<td mat-cell *matCellDef="let activityType">
<div *ngIf="!editing(activityType) else edit">
{{activityType.name}}
<div *ngIf="!editing(activityType); else edit">
{{ activityType.name }}
</div>
<ng-template #edit>
<mat-form-field class="data-entry">
<input matInput required formControlName="name" placeholder="Name">
<input matInput required formControlName="name" placeholder="Name" />
</mat-form-field>
</ng-template>
</td>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,41 @@ <h1 mat-dialog-title>Import Units Into {{ data.teachingPeriod.name() }}</h1>
<ng-container matColumnDef="unitCode">
<th mat-header-cell *matHeaderCellDef> Unit Code </th>
<td mat-cell *matCellDef="let unitToImport">
{{ unitToImport.unitCode }}
<mat-form-field appearance="outline">
<input matInput [(ngModel)]="unitToImport.unitCode" (input)="codeChange($event.target.value, unitToImport)">
</mat-form-field>
</td>
</ng-container>

<ng-container matColumnDef="sourceUnit">
<th mat-header-cell *matHeaderCellDef> Source Unit </th>
<td mat-cell *matCellDef="let unitToImport">
<object-select placeholder="New Unit" [source]="unitToImport.relatedUnits" [(target)]="unitToImport.sourceUnit"></object-select>
<object-select placeholder="New Unit" [source]="unitToImport.relatedUnits" [target]="unitToImport.sourceUnit" (targetChange)="changeSourceUnit(unitToImport, $event)"></object-select>
</td>
</ng-container>

<ng-container matColumnDef="unitName">
<th mat-header-cell *matHeaderCellDef> Unit Name </th>
<td mat-cell *matCellDef="let unitToImport">
<span *ngIf="unitToImport.sourceUnit">{{ unitToImport.sourceUnit.name }}</span>
<mat-form-field appearance="outline" *ngIf="!unitToImport.sourceUnit">
<mat-label>Unit Name</mat-label>
<input matInput [(ngModel)]="unitToImport.unitName">
</mat-form-field>
</td>
</ng-container>

<ng-container matColumnDef="convenor">
<th mat-header-cell *matHeaderCellDef> Main Convenor </th>
<td mat-cell *matCellDef="let unitToImport">
<object-select placeholder="No Staff Selected" [source]="teachingStaff" [(target)]="unitToImport.convenor"></object-select>
<mat-form-field appearance="outline">
<input type="text" matInput [formControl]="unitToImport.convenorFormControl" [matAutocomplete]="auto" [(ngModel)]="unitToImport.convenor">
<mat-autocomplete #auto="matAutocomplete" [displayWith]="displayFn">
<mat-option *ngFor="let staff of unitToImport.filteredStaff | async" [value]="staff">
{{staff.name}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</td>
</ng-container>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ td.mat-column-sourceUnit {
width: 15em;
}

th.mat-column-unitName,
td.mat-column-unitName {
width: 15em;
}

th.mat-column-convenor,
td.mat-column-convenor {
width: 15em;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
import { Component, Inject, Injectable, OnInit, ViewChild } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef, MatDialogModule, MatDialog } from '@angular/material/dialog';
import { MatButtonModule } from '@angular/material/button';
import { FormControl, FormsModule } from '@angular/forms';
import { MatInputModule } from '@angular/material/input';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatStepperModule } from '@angular/material/stepper';
import { MAT_DIALOG_DATA, MatDialogRef, MatDialog } from '@angular/material/dialog';
import { FormControl } from '@angular/forms';
import { Unit, TeachingPeriod, User, UserService, UnitService } from 'src/app/api/models/doubtfire-model';
import { Observable, filter, map, startWith } from 'rxjs';
import { MatTable, MatTableDataSource } from '@angular/material/table';
import { GlobalStateService } from 'src/app/projects/states/index/global-state.service';
import { Observable, map, startWith } from 'rxjs';

export interface TeachingPeriodUnitImportData {
teachingPeriod: TeachingPeriod;
}

interface UnitImportData {
unitCode: string;
unitName?: string;
sourceUnit: Unit;
convenor: User;
relatedUnits?: { value: Unit; text: string }[];
done?: boolean;
convenorFormControl: FormControl<User>;
filteredStaff: Observable<User[]>;
}

@Injectable()
Expand Down Expand Up @@ -56,7 +55,8 @@ export class TeachingPeriodUnitImportDialogComponent implements OnInit {

public dataSource = new MatTableDataSource(this.unitsToImport);

public teachingStaff: { value: User; text: string }[];
public teachingStaff: User[];
public filteredOptions: Observable<User[]>;

public allUnits: Unit[];

Expand All @@ -65,7 +65,7 @@ export class TeachingPeriodUnitImportDialogComponent implements OnInit {
*/
public codesToAdd: string = '';

public displayedColumns: string[] = ['unitCode', 'sourceUnit', 'convenor', 'status', 'actions'];
public displayedColumns: string[] = ['unitCode', 'sourceUnit', 'unitName', 'convenor', 'status', 'actions'];

constructor(
public dialogRef: MatDialogRef<TeachingPeriodUnitImportData>,
Expand All @@ -85,14 +85,23 @@ export class TeachingPeriodUnitImportDialogComponent implements OnInit {
this.userService.getTutors().subscribe((staff) => {
// Load all units now we have the staff
this.loadAllUnits();

this.teachingStaff = staff
.filter((s) => ['Convenor', 'Admin'].includes(s.systemRole))
.map((s) => {
return { value: s, text: s.name };
});
.sort((a, b) => a.name.localeCompare(b.name));
});
}

displayFn(user: User): string {
return user && user.name ? user.name : '';
}

private _filter(name: string): User[] {
const filterValue = name.toLowerCase();

return this.teachingStaff.filter(option => option.name.toLowerCase().includes(filterValue));
}

private loadAllUnits() {
// Load all units
this.unitService.query(undefined, { params: { include_in_active: true } }).subscribe({
Expand All @@ -110,6 +119,16 @@ export class TeachingPeriodUnitImportDialogComponent implements OnInit {
this.dialogRef.close();
}

public changeSourceUnit(value: UnitImportData, unit: Unit) {
value.sourceUnit = unit;
value.convenor = unit.mainConvenorUser;
}

public codeChange(code: string, value: UnitImportData) {
value.relatedUnits = this.relatedUnits(code);
value.sourceUnit = value.relatedUnits.length > 0 ? value.relatedUnits[0].value : null;
}

public relatedUnits(code: string): { value: Unit; text: string }[] {
return this.allUnits
.filter((u) => u.code.includes(code) || code.includes(u.code))
Expand Down Expand Up @@ -155,23 +174,29 @@ export class TeachingPeriodUnitImportDialogComponent implements OnInit {

const relatedUnits = this.relatedUnits(code);
const sourceUnit = relatedUnits.length > 0 ? relatedUnits[0].value : null;
const formControl = new FormControl<User>(sourceUnit?.mainConvenor?.user || sourceUnit?.mainConvenorUser);

this.unitsToImport.push({
unitCode: code,
sourceUnit: sourceUnit,
convenor: sourceUnit?.mainConvenor?.user || sourceUnit?.mainConvenorUser,
relatedUnits: relatedUnits,
convenorFormControl: formControl,
filteredStaff: formControl.valueChanges.pipe(
startWith(''),
map(value => {
const name = typeof value === 'string' ? value : value?.name;
return name ? this._filter(name as string) : this.teachingStaff;
})
)
});
}

this.codesToAdd = '';
this.table.renderRows();
}

private importUnit(idx: number) {
// Stop when past last unit to import
if (idx >= this.unitsToImport.length) return;
const unitToImport = this.unitsToImport[idx];
private importExistingUnit(unitToImport: UnitImportData, idx: number) {
unitToImport.sourceUnit.rolloverTo({ teaching_period_id: this.data.teachingPeriod.id }).subscribe({
next: (newUnit: Unit) => {
unitToImport.done = true;
Expand Down Expand Up @@ -204,6 +229,48 @@ export class TeachingPeriodUnitImportDialogComponent implements OnInit {
});
}

private createNewUnit(unitToImport: UnitImportData, idx: number) {
this.unitService.create({
unit: {
code: unitToImport.unitCode,
name: unitToImport.unitName,
main_convenor_user_id: unitToImport.convenor?.id,
teaching_period_id: this.data.teachingPeriod.id,
}
}).subscribe({
next: (newUnit: Unit) => {
unitToImport.done = true;
this.importUnit(idx + 1);
},
error: (failure) => {
unitToImport.done = false;
console.log(failure);
this.importUnit(idx + 1);
}
});
}

private importUnit(idx: number) {
// Stop when past last unit to import
if (idx >= this.unitsToImport.length) return;
const unitToImport = this.unitsToImport[idx];

const code = unitToImport.sourceUnit ? unitToImport.sourceUnit.code : unitToImport.unitCode;

if (unitToImport.done !== undefined || this.teachigPeriod.hasUnitWithCode(code)){
// Skip units already done
this.importUnit(idx + 1);
} else {
if (unitToImport.sourceUnit) {
// Import existing units - if there was a source unit
this.importExistingUnit(unitToImport, idx);
} else {
// Create a new unit
this.createNewUnit(unitToImport, idx);
}
}
}

public doImport() {
this.importUnit(0);
}
Expand Down
4 changes: 4 additions & 0 deletions src/app/api/models/teaching-period.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ export class TeachingPeriod extends Entity {
return unit && this.unitsCache.has(unit?.id);
}

public hasUnitWithCode(code: string): boolean {
return this.unitsCache.currentValues.some((u) => u.code === code);
}

/**
* Check if a unit with a matching code exists in this teaching period.
*
Expand Down
14 changes: 12 additions & 2 deletions src/app/api/services/unit.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,18 +66,28 @@ export class UnitService extends CachedEntityService<Unit> {
{
keys: ['mainConvenor', 'main_convenor_id'],
toEntityFn: (data, key, entity) => {
entity.mainConvenorUser = AppInjector.get(UserService).cache.get(data[key]);
return entity.staffCache.get(data[key]);
},
toJsonFn: (unit: Unit, key: string) => {
return unit.mainConvenor?.id;
}
},
{
keys: ['mainConvenorUser', 'main_convenor_user_id'],
toEntityFn: (data, key, entity) => {
return AppInjector.get(UserService).cache.get(data[key]);
},
toJsonFn: (unit: Unit, key: string) => {
return unit.mainConvenor?.user.id;
}
},
{
keys: ['teachingPeriod', 'teaching_period_id'],
toEntityFn: (data, key, entity) => {
if ( data['teaching_period_id'] ) {
return this.teachingPeriodService.cache.get(data['teaching_period_id']);
const teachingPeriod = this.teachingPeriodService.cache.get(data['teaching_period_id']);
teachingPeriod?.unitsCache.add(entity);
return teachingPeriod;
} else { return undefined; }
},
toJsonFn: (entity: Unit, key: string) => {
Expand Down
Loading

0 comments on commit 17050f9

Please sign in to comment.