Skip to content

Commit

Permalink
Merge pull request #3699 from Tangerine-Community/release/v3.31.0
Browse files Browse the repository at this point in the history
Release/v3.31.0
  • Loading branch information
esurface authored Jul 26, 2024
2 parents 3009478 + 05f7974 commit 7e2cc5d
Show file tree
Hide file tree
Showing 74 changed files with 1,009 additions and 279 deletions.
42 changes: 42 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,47 @@
# What's new

## v3.31.0

__New Features__

- **Audio and Visual Feedback**: A new Prompt Box widget available in form authoring allows a form designer to add audio and visual feedback connected to Radio Block widgets. This feature provides a toolset for creating self-guided assessments. See the example in [tangy-forms](https://github.com/Tangerine-Community/tangy-form/blob/master/CHANGELOG.md#v4430). [#3473](https://github.com/Tangerine-Community/Tangerine/issues/3473)

- Client Login Screen Custom HTML: A new app-config.json setting, `customLoginMarkup`, allows for custom HTML to be added to the login screen. This feature is useful for adding custom branding or additional information to the login screen. As an example:
```json
"customLoginMarkup": "<div style='text-align: center;'><img src='assets/media/logo.png' alt='logo' style='max-width: 100%;'></div>"
```

- **Improved Data Management**:
* Data Managers now have access to a full workflow to review, edit, and verify data in the Tangerine web server. The Data Manager can click on a record and enter a new screen that allows them to perform actions align with a data collection supervision process.
* Searching has been improved to allow seaqrching for a specific ID in the imported data. This feature is useful for finding specific records synced to the server when reviewing or editing completed form responses. [#3681](https://github.com/Tangerine-Community/Tangerine/issues/3681)

__Fixes__
- Client Search Service: exclude archived cases from recent activity
- Media library cannot upload photos [#3583](https://github.com/Tangerine-Community/Tangerine/issues/3583)
- User Profile Import: The process of importing an existing device user now allows for retries and an asynchronous process to download existing records. This fixes an issue cause by timeouts when trying to import a user with a large number of records. [#3696](https://github.com/Tangerine-Community/Tangerine/issues/3696)
- When `T_ONLY_PROCESS_THESE_GROUPS` has a list of one or more groups, running `reporting-cache-clear` will only process the groups in the list

__Tangerine Teach__

- Add toggle in Attendence Check for 'late'. A teacher can click through the status of 'present', 'late', or 'absent' for each student.
- Use `studentRegistrationFields` to control showing name and surname of student in the student dashboard

__Libs and Dependencies__
- Bump version of `tangy-form` to v4.31.1 and `tangy-form-editor` to v7.18.0 for the new Prompt Box widget
- Bump version of `tangy-form` to v4.45.1 for disabling of `tangy-gps` in server edits

__Server upgrade instructions__

See the [Server Upgrade Insturctions](https://docs.tangerinecentral.org/system-administrator/upgrade-instructions).

*Special Instructions for this release:*

Once the Tangerine and CouchDB are running, run the upgrade script for v3.31.0:

`docker exec -it tangerine /tangerine/server/src/upgrade/v3.31.0.js`



## v3.30.2

__New Features__
Expand Down
2 changes: 1 addition & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
"rxjs-compat": "^6.5.5",
"sanitize-filename-ts": "^1.0.2",
"spark-md5": "^3.0.2",
"tangy-form": "4.42.0",
"tangy-form": "^4.43.2",
"translation-web-component": "1.1.1",
"tslib": "^1.10.0",
"underscore": "^1.9.1",
Expand Down
54 changes: 35 additions & 19 deletions client/src/app/class/_services/dashboard.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1043,17 +1043,47 @@ export class DashboardService {
return gradeInput?.value
}

async getAllStudentResults(students, studentsResponses, curriculumFormsList, curriculum) {
const allStudentResults = [];

const appConfig = await this.appConfigService.getAppConfig();
const studentRegistrationFields = appConfig.teachProperties?.studentRegistrationFields || []

students.forEach((student) => {
const studentResult = {};

studentResult['id'] = student.id;
studentRegistrationFields.forEach((field) => {
studentResult[field] = this.getValue(field, student.doc)
})
studentResult['forms'] = {};
curriculumFormsList.forEach((form) => {
const formResult = {};
formResult['formId'] = form.id;
formResult['curriculum'] = curriculum.name;
formResult['title'] = form.title;
formResult['src'] = form.src;
if (studentsResponses[student.id]) {
formResult['response'] = studentsResponses[student.id][form.id];
}
studentResult['forms'][form.id] = formResult;
});
allStudentResults.push(studentResult);
});

return allStudentResults;
}

/**
* Get the attendance list for the class, including any students who have not yet had attendance checked. If the savedAttendanceList is passed in, then
* populate the student from that doc by matching student.id.
* @param students
* @param savedList
*/
async getAttendanceList(students, savedList, curriculum) {
// const curriculumFormHtml = await this.getCurriculaForms(curriculum.name);
// const curriculumFormsList = await this.classUtils.createCurriculumFormsList(curriculumFormHtml);
const appConfig = await this.appConfigService.getAppConfig();
const studentRegistrationFields = appConfig.teachProperties?.studentRegistrationFields || []

const list = []
for (const student of students) {
let studentResult
Expand All @@ -1062,13 +1092,6 @@ export class DashboardService {
studentResult = savedList.find(studentDoc => studentDoc.id === studentId)
}
if (studentResult) {
// migration.
if (!studentResult.student_surname) {
studentResult.student_surname = studentResult.surname
}
if (!studentResult.student_name) {
studentResult.student_name = studentResult.name
}
list.push(studentResult)
} else {
studentResult = {}
Expand All @@ -1077,22 +1100,15 @@ export class DashboardService {
studentRegistrationFields.forEach((field) => {
studentResult[field] = this.getValue(field, student.doc)
})
// const student_name = this.getValue('student_name', student.doc)
// const student_surname = this.getValue('student_surname', student.doc)
// const phone = this.getValue('phone', student.doc);
// const classId = this.getValue('classId', student.doc)

// studentResult['name'] = student_name
// studentResult['surname'] = student_surname
// studentResult['phone'] = phone
// studentResult['classId'] = classId
studentResult['absent'] = null
if (appConfig.teachProperties?.showLateAttendanceOption) {
studentResult['late'] = null
}

list.push(studentResult)
}
}
return list
// await this.populateFeedback(curriculumId);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,28 @@
<td (click)="$event ? selectStudentName(element) : null" class="student-name"> {{element["student_name"]}} {{element["student_surname"]}} </td>
<td style="padding-right: 1em;">
<mat-chip-list class="absent">
<ng-container *ngIf="element['absent']; then absent; else present"></ng-container>
<ng-container *ngIf="!showLateAttendanceOption; then absentOnly; else withLate"></ng-container>
<ng-template #absentOnly>
<ng-container *ngIf="element['absent']; then absent; else present"></ng-container>
</ng-template>
<ng-template #withLate>
<ng-container *ngIf="element['absent']; then absent; else second"></ng-container>
<ng-template #second>
<ng-container *ngIf="element['late']; then late; else present"></ng-container>
</ng-template>
</ng-template>
<ng-template #absent>
<mat-chip color="primary" selected class="red" (click)="toggleAttendance(element)">
<mat-chip color="red" selected class="red" (click)="toggleAttendance('absent', element)">
<mat-icon>close</mat-icon>
</mat-chip>
</ng-template>
<ng-template #late>
<mat-chip color="orange" class="orange" (click)="toggleAttendance('late', element)">
<mat-icon>remove</mat-icon>
</mat-chip>
</ng-template>
<ng-template #present>
<mat-chip color="primary" class="green" (click)="toggleAttendance(element)">
<mat-chip color="primary" class="green" (click)="toggleAttendance('present', element)">
<mat-icon>check</mat-icon>
</mat-chip>
</ng-template>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {UserService} from "../../../shared/_services/user.service";
import {FormMetadata} from "../../form-metadata";
import {ClassFormService} from "../../_services/class-form.service";
import { TangySnackbarService } from 'src/app/shared/_services/tangy-snackbar.service';
import { AppConfigService } from 'src/app/shared/_services/app-config.service';

@Component({
selector: 'app-attendance-check',
Expand Down Expand Up @@ -40,16 +41,22 @@ export class AttendanceCheckComponent implements OnInit {
curriculum:any
ignoreCurriculumsForTracking: boolean = false
reportLocaltime: string;
showLateAttendanceOption: boolean = false;

constructor(
private dashboardService: DashboardService,
private variableService : VariableService,
private router: Router,
private classFormService: ClassFormService,
private tangySnackbarService: TangySnackbarService
private tangySnackbarService: TangySnackbarService,
private appConfigService: AppConfigService
) { }

async ngOnInit(): Promise<void> {

const appConfig = await this.appConfigService.getAppConfig()
this.showLateAttendanceOption = appConfig.teachProperties.showLateAttendanceOption || this.showLateAttendanceOption

let classIndex
await this.classFormService.initialize();
this.getValue = this.dashboardService.getValue
Expand Down Expand Up @@ -133,18 +140,33 @@ export class AttendanceCheckComponent implements OnInit {

}

async toggleAttendance(student) {
student.absent = !student.absent
await this.saveStudentAttendance()
}

async toggleMood(mood, student) {
student.mood = mood
if (!student.absent) {
await this.saveStudentAttendance()
async toggleAttendance(currentStatus, student) {
if (this.showLateAttendanceOption) {
if (currentStatus == 'present') {
// moving from present status to late status
student.absent = false
student.late = true
} else if (currentStatus == 'late') {
// moving from late status to absent status
student.absent = true
student.late = false
} else {
// moving from absent status to present status
student.absent = false
student.late = false
}
} else {
if (currentStatus == 'present') {
// moving from present status to absent status
student.absent = true
} else {
// moving from absent status to present status
student.absent = false
}
}
}

await this.saveStudentAttendance()
}

private async saveStudentAttendance() {
// save allStudentResults
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,9 @@ mat-card-title {
.mat-chip.mat-standard-chip.mat-chip-selected.mat-primary.red {
background-color: red;
}
.mat-chip.mat-standard-chip.mat-chip-selected.mat-primary.orange {
background-color: orange;
}

.gray {
background-color: gray;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export class AttendanceDashboardComponent implements OnInit {
for (let i = 0; i < this.currArray.length; i++) {
const curriculum = this.currArray[i];
let curriculumLabel = curriculum?.label
const reports = await this.dashboardService.searchDocs('scores', currentClass, null, null, curriculumLabel, randomId, true)
const reports = await this.dashboardService.searchDocs('scores', currentClass, '*', null, curriculumLabel, randomId, true)
reports.forEach((report) => {
report.doc.curriculum = curriculum
scoreReports.push(report.doc)
Expand Down
4 changes: 4 additions & 0 deletions client/src/app/class/dashboard/dashboard.component.css
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,10 @@ mat-card-title {
background-color: red;
}

.mat-chip.mat-standard-chip.mat-chip-selected.mat-primary.orange {
background-color: orange;
}

.gray {
background-color: gray;
}
Expand Down
2 changes: 1 addition & 1 deletion client/src/app/class/dashboard/dashboard.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
<th>{{'Completed?'|translate}}</th>
</tr>
<tr *ngFor="let element of allStudentResults">
<td (click)="$event ? selectStudentName(element) : null" class="student-name"> {{element["name"]}} </td>
<td (click)="$event ? selectStudentName(element) : null" class="student-name"> {{element["student_name"]}} {{element["student_surname"]}} </td>
<td class="checkbox-response" *ngIf="element.forms[currentItemId]?.response ; else elseBlock ">
<input type="checkbox"
(change)="$event ? selectCheckboxResult(element,currentItemId,$event) : null"
Expand Down
29 changes: 1 addition & 28 deletions client/src/app/class/dashboard/dashboard.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -317,34 +317,7 @@ export class DashboardComponent implements OnInit {
this.studentsResponses[studentId] = studentReponses;
}
}
const allStudentResults = [];
// for (const student of this.students) {
this.students.forEach((student) => {
const studentResults = {};
const student_name = this.getValue('student_name', student.doc)
const classId = this.getValue('classId', student.doc)
studentResults['id'] = student.id;
studentResults['name'] = student_name
studentResults['classId'] = classId
// studentResults["forms"] = [];
studentResults['forms'] = {};
// for (const form of this.curriculumForms) {
this.curriculumFormsList.forEach((form) => {
const formResult = {};
formResult['formId'] = form.id;
formResult['curriculum'] = this.curriculum.name;
formResult['title'] = form.title;
formResult['src'] = form.src;
if (this.studentsResponses[student.id]) {
formResult['response'] = this.studentsResponses[student.id][form.id];
}
// studentResults["forms"].push(formResult)
studentResults['forms'][form.id] = formResult;
});
allStudentResults.push(studentResults);
});
this.allStudentResults = allStudentResults;
// await this.populateFeedback(curriculumId);
this.allStudentResults = await this.dashboardService.getAllStudentResults(this.students, this.studentsResponses, this.curriculumFormsList, this.curriculum);
}

// Triggered by dropdown selection in UI.
Expand Down
1 change: 1 addition & 0 deletions client/src/app/class/feedback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export class Feedback {
skill:string;
assignment:string;
message:string;
customJSCode: string;
messageTruncated: string; // for listing
calculatedScore:string;
percentileRange: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@
.green {
background-color: green;
}

.orange {
background-color: orange;
}

.mat-chip.mat-standard-chip.mat-primary {
background-color: green;
}
Expand All @@ -76,6 +81,10 @@
background-color: red;
}

.mat-chip.mat-standard-chip.mat-chip-selected.mat-primary.orange {
background-color: orange;
}

.tangy-class-card-content-container {
margin-left: 3%;
/*width: 90%;*/
Expand Down
Loading

0 comments on commit 7e2cc5d

Please sign in to comment.