From eaa415ae5246bf3c55c0a82f1b82cd1a92a149dc Mon Sep 17 00:00:00 2001 From: Ong Han Wei <66376253+rexong@users.noreply.github.com> Date: Mon, 14 Aug 2023 23:09:18 +0800 Subject: [PATCH 1/5] Fix loading issue (#12550) Co-authored-by: Dominic Lim <46486515+domlimm@users.noreply.github.com> --- .../instructor-home-page/instructor-home-page.component.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/web/app/pages-instructor/instructor-home-page/instructor-home-page.component.ts b/src/web/app/pages-instructor/instructor-home-page/instructor-home-page.component.ts index df44a64000e..59226d7d27f 100644 --- a/src/web/app/pages-instructor/instructor-home-page/instructor-home-page.component.ts +++ b/src/web/app/pages-instructor/instructor-home-page/instructor-home-page.component.ts @@ -499,7 +499,9 @@ export class InstructorHomePageComponent extends InstructorSessionModalPageCompo const requestList: Observable[] = this.createSessionCopyRequestsFromRowModel( this.courseTabModels[tabIndex].sessionsTableRowModels[result.sessionToCopyRowIndex], result); if (requestList.length === 1) { - this.copySingleSession(requestList[0], this.modifiedTimestampsModal); + this.copySingleSession(requestList[0].pipe(finalize(() => { + this.isCopyLoading = false; + })), this.modifiedTimestampsModal); } if (requestList.length > 1) { forkJoin(requestList).pipe(finalize(() => { From 6a89e1798d9c4a7731c55fcd8ca28759f2b00385 Mon Sep 17 00:00:00 2001 From: Ong Han Wei <66376253+rexong@users.noreply.github.com> Date: Thu, 17 Aug 2023 22:27:27 +0800 Subject: [PATCH 2/5] [#12535] Instructor Course Page: Make "Show" group tabbable (#12540) * Make 'Show' group tabbable and change cursor to pointer * Make use of tmRouterLink rather than using tabindex and enter key event * Change route to use relative route * Rerun CI * Change a tag to button tag * Remove background from button * Update E2E * Fix lint * Update snapshot * 12535-show-button-cannot-tabbed --------- Co-authored-by: Dominic Lim <46486515+domlimm@users.noreply.github.com> --- ...ructor-courses-page.component.spec.ts.snap | 46 ++++++++++++------- .../instructor-courses-page.component.html | 28 +++++------ .../instructor-courses-page.component.scss | 12 +++++ 3 files changed, 54 insertions(+), 32 deletions(-) diff --git a/src/web/app/pages-instructor/instructor-courses-page/__snapshots__/instructor-courses-page.component.spec.ts.snap b/src/web/app/pages-instructor/instructor-courses-page/__snapshots__/instructor-courses-page.component.spec.ts.snap index 8ee09ca2ebf..9e6adb100de 100644 --- a/src/web/app/pages-instructor/instructor-courses-page/__snapshots__/instructor-courses-page.component.spec.ts.snap +++ b/src/web/app/pages-instructor/instructor-courses-page/__snapshots__/instructor-courses-page.component.spec.ts.snap @@ -1843,32 +1843,39 @@ exports[`InstructorCoursesPageComponent should snap with no courses in course st - + - Show - + - + - + - + - Show - + - + - + Active courses - - Show - + {{ courseStats[course.course.courseId]['sections'] }} @@ -104,10 +103,9 @@

Active courses

- - Show - + {{ courseStats[course.course.courseId]['teams'] }} @@ -115,10 +113,9 @@

Active courses

- - Show - + {{ courseStats[course.course.courseId]['students'] }} @@ -126,10 +123,9 @@

Active courses

- - Show - + {{ courseStats[course.course.courseId]['unregistered'] }} diff --git a/src/web/app/pages-instructor/instructor-courses-page/instructor-courses-page.component.scss b/src/web/app/pages-instructor/instructor-courses-page/instructor-courses-page.component.scss index c17280ecff0..25440817a2e 100644 --- a/src/web/app/pages-instructor/instructor-courses-page/instructor-courses-page.component.scss +++ b/src/web/app/pages-instructor/instructor-courses-page/instructor-courses-page.component.scss @@ -106,3 +106,15 @@ .d-inline-block { position: inherit; } + +.link-button { + border: none; + text-decoration: underline; + color: var(--bs-link-color); + padding: 0; + background: none; +} + +.link-button:hover { + color: var(--bs-link-hover-color); +} From 325d066e948fe1d7d181102a4bc17d357d79d3a3 Mon Sep 17 00:00:00 2001 From: sgadkar2 <123888903+sgadkar2@users.noreply.github.com> Date: Sat, 19 Aug 2023 12:39:06 +0530 Subject: [PATCH 3/5] [#12313] Instructor sending submission reminders: missing space between checkbox and label (#12553) --- ...inders-to-respondents-modal.component.html | 32 ++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/web/app/components/sessions-table/send-reminders-to-respondents-modal/send-reminders-to-respondents-modal.component.html b/src/web/app/components/sessions-table/send-reminders-to-respondents-modal/send-reminders-to-respondents-modal.component.html index 3696b4acd3f..4c6942905a5 100644 --- a/src/web/app/components/sessions-table/send-reminders-to-respondents-modal/send-reminders-to-respondents-modal.component.html +++ b/src/web/app/components/sessions-table/send-reminders-to-respondents-modal/send-reminders-to-respondents-modal.component.html @@ -5,16 +5,32 @@
- - - - +
+
+
+ + +
+
+ + +
+
+
- - - - +
+
+
+ + +
+
+ + +
+
+
From b49359ec4a6d626a79de37bc5d68e97664d6844f Mon Sep 17 00:00:00 2001 From: Jason Qiu Date: Sat, 19 Aug 2023 15:56:07 +0800 Subject: [PATCH 4/5] [#12544] Rubric Question Statistics: Handle empty weights (#12545) * Use NO_VALUE to represent empty weights * Skip over null weights * Clean up calculations * Standardize naming * Fix null weight display * Add explanation for empty weights * Fix downloaded result empty weight display * Fix order of assertEquals * Handle null conversion to NO_VALUE when input out of focus * Revert back to using null value * Fix display when all chosen weights are empty * Standardize display for empty values * Fix failing tests --- .../InstructorFeedbackEditPage.java | 4 +- ...-question-edit-details-form.component.html | 5 +- .../rubric-question-statistics-calculation.ts | 108 +++++++++++++----- .../rubric-question-statistics.component.ts | 38 ++++-- .../test-data/rubricQuestionResponses.json | 2 + .../session-result-csv.service.spec.ts.snap | 18 +-- .../feedback-rubric-question-details.impl.ts | 28 +++-- 7 files changed, 144 insertions(+), 59 deletions(-) diff --git a/src/e2e/java/teammates/e2e/pageobjects/InstructorFeedbackEditPage.java b/src/e2e/java/teammates/e2e/pageobjects/InstructorFeedbackEditPage.java index 032e0fbc66f..4c0eda460ee 100644 --- a/src/e2e/java/teammates/e2e/pageobjects/InstructorFeedbackEditPage.java +++ b/src/e2e/java/teammates/e2e/pageobjects/InstructorFeedbackEditPage.java @@ -741,8 +741,8 @@ public void verifyRubricQuestionDetails(int questionNum, FeedbackRubricQuestionD for (int i = 0; i < numSubQn; i++) { List rubricWeights = getRubricWeights(questionNum, i + 2); for (int j = 0; j < numChoices; j++) { - assertEquals(rubricWeights.get(j).getAttribute("value"), - getDoubleString(weights.get(i).get(j))); + assertEquals(getDoubleString(weights.get(i).get(j)), + rubricWeights.get(j).getAttribute("value")); } } } else { diff --git a/src/web/app/components/question-types/question-edit-details-form/rubric-question-edit-details-form.component.html b/src/web/app/components/question-types/question-edit-details-form/rubric-question-edit-details-form.component.html index c6055bb8dce..5a7965a949f 100644 --- a/src/web/app/components/question-types/question-edit-details-form/rubric-question-edit-details-form.component.html +++ b/src/web/app/components/question-types/question-edit-details-form/rubric-question-edit-details-form.component.html @@ -2,7 +2,7 @@
@@ -49,7 +49,8 @@ (ngModelChange)="triggerRubricDescriptionChange($event, i, j)" rows="3" [disabled]="!isEditable"> + [ngModel]="model.rubricWeightsForEachCell[i][j]" + (ngModelChange)="triggerRubricWeightChange($event, i, j)"> diff --git a/src/web/app/components/question-types/question-statistics/question-statistics-calculation/rubric-question-statistics-calculation.ts b/src/web/app/components/question-types/question-statistics/question-statistics-calculation/rubric-question-statistics-calculation.ts index 9bc68fd288c..2a5e15dc865 100644 --- a/src/web/app/components/question-types/question-statistics/question-statistics-calculation/rubric-question-statistics-calculation.ts +++ b/src/web/app/components/question-types/question-statistics/question-statistics-calculation/rubric-question-statistics-calculation.ts @@ -3,7 +3,7 @@ import { FeedbackRubricQuestionDetails, FeedbackRubricResponseDetails, } from '../../../../../types/api-output'; -import { RUBRIC_ANSWER_NOT_CHOSEN } from '../../../../../types/feedback-response-details'; +import { NO_VALUE, RUBRIC_ANSWER_NOT_CHOSEN } from '../../../../../types/feedback-response-details'; import { QuestionStatistics } from '../question-statistics'; /** @@ -18,6 +18,7 @@ export interface PerRecipientStats { percentages: number[][]; percentagesAverage: number[]; weightsAverage: number[]; + areSubQuestionChosenWeightsAllNull: boolean[]; subQuestionTotalChosenWeight: number[]; subQuestionWeightAverage: number[]; overallWeightedSum: number; @@ -113,6 +114,7 @@ export class RubricQuestionStatisticsCalculation percentages: [], percentagesAverage: [], weightsAverage: [], + areSubQuestionChosenWeightsAllNull: this.subQuestions.map(() => true), subQuestionTotalChosenWeight: this.subQuestions.map(() => 0), subQuestionWeightAverage: [], }; @@ -122,8 +124,12 @@ export class RubricQuestionStatisticsCalculation continue; } this.perRecipientStatsMap[response.recipientEmail || response.recipient].answers[i][subAnswer] += 1; - this.perRecipientStatsMap[response.recipientEmail || response.recipient].subQuestionTotalChosenWeight[i] += - +this.weights[i][subAnswer].toFixed(5); + if (this.weights[i][subAnswer] !== null) { + this.perRecipientStatsMap[response.recipientEmail || response.recipient].subQuestionTotalChosenWeight[i] += + +this.weights[i][subAnswer].toFixed(5); + this.perRecipientStatsMap[ + response.recipientEmail || response.recipient].areSubQuestionChosenWeightsAllNull[i] = false; + } } } @@ -131,29 +137,54 @@ export class RubricQuestionStatisticsCalculation const perRecipientStats: PerRecipientStats = this.perRecipientStatsMap[recipient]; // Answers sum = number of answers in each column - perRecipientStats.answersSum = this.calculateAnswersSum(perRecipientStats.answers); + perRecipientStats.answersSum = this.sumValidValuesByColumn(perRecipientStats.answers); perRecipientStats.percentages = this.calculatePercentages(perRecipientStats.answers); perRecipientStats.percentagesAverage = this.calculatePercentagesAverage(perRecipientStats.answersSum); + perRecipientStats.subQuestionTotalChosenWeight = + perRecipientStats.subQuestionTotalChosenWeight.map((val: number, i: number) => + (perRecipientStats.areSubQuestionChosenWeightsAllNull[i] ? NO_VALUE : val)); perRecipientStats.subQuestionWeightAverage = this.calculateSubQuestionWeightAverage(perRecipientStats.answers); perRecipientStats.weightsAverage = this.calculateWeightsAverage(this.weights); - // Overall weighted sum = sum of total chosen weight for all sub questions - perRecipientStats.overallWeightedSum = - +(perRecipientStats.subQuestionTotalChosenWeight.reduce((a, b) => a + b)).toFixed(2); - // Overall weighted average = overall weighted sum / total number of responses - perRecipientStats.overallWeightAverage = +(perRecipientStats.overallWeightedSum - / this.calculateNumResponses(perRecipientStats.answersSum)).toFixed(2); + perRecipientStats.overallWeightedSum = this.calculateOverallWeightedSum( + perRecipientStats.areSubQuestionChosenWeightsAllNull, perRecipientStats.subQuestionTotalChosenWeight); + // Overall weighted average = overall weighted sum / total number of responses with non-null weights + perRecipientStats.overallWeightAverage = perRecipientStats.overallWeightedSum === NO_VALUE + ? NO_VALUE + : +(perRecipientStats.overallWeightedSum + / this.calculateNumResponses(this.countResponsesByRowWithValidWeight(perRecipientStats.answers))) + .toFixed(2); } } + // Number of responses for each sub question with non-null weights + private countResponsesByRowWithValidWeight(answers: number[][]): number[] { + const sums: number[] = []; + for (let r: number = 0; r < answers.length; r += 1) { + let sum: number = 0; + for (let c: number = 0; c < answers[0].length; c += 1) { + if (this.weights[r][c] === null) { + continue; + } + sum += answers[r][c]; + } + sums[r] = sum; + } + return sums; + } + private calculateSubQuestionWeightAverage(answers: number[][]): number[] { - const sums: number[] = answers.map((weightedAnswers: number[]) => - weightedAnswers.reduce((a: number, b: number) => a + b, 0)); + const sums: number[] = this.countResponsesByRowWithValidWeight(answers); return answers.map((subQuestionAnswer: number[], subQuestionIdx: number): number => { - const weightAverage: number = sums[subQuestionIdx] === 0 ? 0 - : subQuestionAnswer.reduce((prevValue: number, currValue: number, currentIndex: number): number => - prevValue + currValue * this.weights[subQuestionIdx][currentIndex], 0) / sums[subQuestionIdx]; + if (sums[subQuestionIdx] === 0) { + return NO_VALUE; + } + const weightAverage: number = + subQuestionAnswer.reduce((prevValue: number, currValue: number, currentIndex: number): number => + (this.weights[subQuestionIdx][currentIndex] === null + ? prevValue + : prevValue + currValue * this.weights[subQuestionIdx][currentIndex]), 0) / sums[subQuestionIdx]; return +weightAverage.toFixed(2); }); } @@ -176,27 +207,40 @@ export class RubricQuestionStatisticsCalculation return percentages; } - // Calculate sum of answers for each column - private calculateAnswersSum(answers: number[][]): number[] { + // Calculate sum of non-null values for each column + private sumValidValuesByColumn(matrix: number[][]): number[] { const sums: number[] = []; - for (let i: number = 0; i < answers[0].length; i += 1) { + for (let c: number = 0; c < matrix[0].length; c += 1) { let sum: number = 0; - for (let j: number = 0; j < answers.length; j += 1) { - sum += answers[j][i]; + for (let r: number = 0; r < matrix.length; r += 1) { + sum += matrix[r][c] === null ? 0 : matrix[r][c]; } - sums[i] = sum; + sums[c] = sum; } return sums; } - // Calculate weight average for each column + // Count number of non-null values for each column + private countValidValuesByColumn(matrix: number[][]): number[] { + const counts: number[] = []; + for (let c: number = 0; c < matrix[0].length; c += 1) { + let count: number = 0; + for (let r: number = 0; r < matrix.length; r += 1) { + count += matrix[r][c] === null ? 0 : 1; + } + counts[c] = count; + } + return counts; + } + + // Calculate non-null weight average for each column private calculateWeightsAverage(weights: number[][]): number[] { - // Calculate sum of weights for each column - const sums: number[] = this.calculateAnswersSum(weights); + const sums: number[] = this.sumValidValuesByColumn(weights); + const counts: number[] = this.countValidValuesByColumn(weights); const averages: number[] = []; - // Divide each weight sum by number of weights + // Divide each weight sum by number of non-null weights for (let i: number = 0; i < sums.length; i += 1) { - averages[i] = +(sums[i] / weights.length).toFixed(2); + averages[i] = counts[i] ? +(sums[i] / counts[i]).toFixed(2) : NO_VALUE; } return averages; } @@ -217,4 +261,16 @@ export class RubricQuestionStatisticsCalculation private calculateNumResponses(answersSum: number[]): number { return answersSum.reduce((a, b) => a + b); } + + // Overall weighted sum is sum of total chosen non-null weight for all sub questions + private calculateOverallWeightedSum(areChosenWeightsAllNull: boolean[], totalChosenWeights: number[]): number { + if (areChosenWeightsAllNull.every(Boolean)) { + return NO_VALUE; + } + let sum: number = 0; + for (const totalChosenWeight of totalChosenWeights) { + sum += totalChosenWeight === NO_VALUE ? 0 : totalChosenWeight; + } + return +(sum).toFixed(2); + } } diff --git a/src/web/app/components/question-types/question-statistics/rubric-question-statistics.component.ts b/src/web/app/components/question-types/question-statistics/rubric-question-statistics.component.ts index 852058648f4..e7fe3c03886 100644 --- a/src/web/app/components/question-types/question-statistics/rubric-question-statistics.component.ts +++ b/src/web/app/components/question-types/question-statistics/rubric-question-statistics.component.ts @@ -1,6 +1,7 @@ import { Component, OnChanges } from '@angular/core'; import { StringHelper } from '../../../../services/string-helper'; import { DEFAULT_RUBRIC_QUESTION_DETAILS } from '../../../../types/default-question-structs'; +import { NO_VALUE } from '../../../../types/feedback-response-details'; import { SortBy } from '../../../../types/sort-properties'; import { ColumnData, SortableTableCellData } from '../../sortable-table/sortable-table.component'; import { @@ -54,21 +55,29 @@ export class RubricQuestionStatisticsComponent extends RubricQuestionStatisticsC return { value: `${this.percentagesExcludeSelf[questionIndex][choiceIndex]}%` + ` (${this.answersExcludeSelf[questionIndex][choiceIndex]})` - + `${this.isWeightStatsVisible ? ` [${this.weights[questionIndex][choiceIndex]}]` : ''}`, + + `${this.isWeightStatsVisible + ? ` [${this.getDisplayWeight(this.weights[questionIndex][choiceIndex])}]` + : ''}`, }; } return { value: `${this.percentages[questionIndex][choiceIndex]}%` + ` (${this.answers[questionIndex][choiceIndex]})` - + `${this.isWeightStatsVisible ? ` [${this.weights[questionIndex][choiceIndex]}]` : ''}`, + + `${this.isWeightStatsVisible + ? ` [${this.getDisplayWeight(this.weights[questionIndex][choiceIndex])}]` + : ''}`, }; }), ]; if (this.isWeightStatsVisible) { if (this.excludeSelf) { - currRow.push({ value: this.subQuestionWeightAverageExcludeSelf[questionIndex] }); + currRow.push({ + value: this.getDisplayWeight(this.subQuestionWeightAverageExcludeSelf[questionIndex]), + }); } else { - currRow.push({ value: this.subQuestionWeightAverage[questionIndex] }); + currRow.push({ + value: this.getDisplayWeight(this.subQuestionWeightAverage[questionIndex]), + }); } } @@ -103,11 +112,11 @@ export class RubricQuestionStatisticsComponent extends RubricQuestionStatisticsC return { value: `${perRecipientStats.percentages[questionIndex][choiceIndex]}%` + ` (${perRecipientStats.answers[questionIndex][choiceIndex]})` - + ` [${this.weights[questionIndex][choiceIndex]}]`, + + ` [${this.getDisplayWeight(this.weights[questionIndex][choiceIndex])}]`, }; }), - { value: perRecipientStats.subQuestionTotalChosenWeight[questionIndex] }, - { value: perRecipientStats.subQuestionWeightAverage[questionIndex] }, + { value: this.getDisplayWeight(perRecipientStats.subQuestionTotalChosenWeight[questionIndex]) }, + { value: this.getDisplayWeight(perRecipientStats.subQuestionWeightAverage[questionIndex]) }, ]); }); }); @@ -124,6 +133,9 @@ export class RubricQuestionStatisticsComponent extends RubricQuestionStatisticsC this.perRecipientOverallRowsData = []; Object.values(this.perRecipientStatsMap).forEach((perRecipientStats: PerRecipientStats) => { + const perCriterionAverage: string = + perRecipientStats.subQuestionWeightAverage.map((val: number) => + this.getDisplayWeight(val)).toString(); this.perRecipientOverallRowsData.push([ { value: perRecipientStats.recipientTeam }, { value: perRecipientStats.recipientName }, @@ -132,13 +144,17 @@ export class RubricQuestionStatisticsComponent extends RubricQuestionStatisticsC return { value: `${perRecipientStats.percentagesAverage[choiceIndex]}%` + ` (${perRecipientStats.answersSum[choiceIndex]})` - + ` [${perRecipientStats.weightsAverage[choiceIndex]}]`, + + ` [${this.getDisplayWeight(perRecipientStats.weightsAverage[choiceIndex])}]`, }; }), - { value: perRecipientStats.overallWeightedSum }, - { value: perRecipientStats.overallWeightAverage }, - { value: perRecipientStats.subQuestionWeightAverage.toString() }, + { value: this.getDisplayWeight(perRecipientStats.overallWeightedSum) }, + { value: this.getDisplayWeight(perRecipientStats.overallWeightAverage) }, + { value: perCriterionAverage }, ]); }); } + + private getDisplayWeight(weight: number): any { + return weight === null || weight === NO_VALUE ? '-' : weight; + } } diff --git a/src/web/app/components/question-types/question-statistics/test-data/rubricQuestionResponses.json b/src/web/app/components/question-types/question-statistics/test-data/rubricQuestionResponses.json index e6623a372fc..e746e887694 100644 --- a/src/web/app/components/question-types/question-statistics/test-data/rubricQuestionResponses.json +++ b/src/web/app/components/question-types/question-statistics/test-data/rubricQuestionResponses.json @@ -70,6 +70,7 @@ "recipientEmail": "alice@gmail.com", "recipientName": "Alice", "recipientTeam": "Team 1", + "areSubQuestionChosenWeightsAllNull": [false, false, false], "subQuestionTotalChosenWeight": [1, 1, 0.8], "subQuestionWeightAverage": [0.5, 0.5, 0.4], "weightsAverage": [0.23, 0.77], @@ -88,6 +89,7 @@ "recipientEmail": "bob@gmail.com", "recipientName": "Bob", "recipientTeam": "Team 2", + "areSubQuestionChosenWeightsAllNull": [false, false, false], "subQuestionTotalChosenWeight": [0.4, 1, 0.8], "subQuestionWeightAverage": [0.2, 0.5, 0.4], "weightsAverage": [0.23, 0.77], diff --git a/src/web/services/__snapshots__/session-result-csv.service.spec.ts.snap b/src/web/services/__snapshots__/session-result-csv.service.spec.ts.snap index 88b9cf5793b..b6690556117 100644 --- a/src/web/services/__snapshots__/session-result-csv.service.spec.ts.snap +++ b/src/web/services/__snapshots__/session-result-csv.service.spec.ts.snap @@ -387,7 +387,7 @@ Team,Recipient Name,Recipient Email,Sub Question,Yes,No,Total,Average \\"Team 1.1
'\\"\\"\\",student2 In Course1,student2InCourse1@gmail.tmt,b) This student has tried his/her best.,100% (1) [1.25],0% (0) [-1.7],1.25,1.25 \\"Team 1.1'\\"\\"\\",student3 In Course1,student3InCourse1@gmail.tmt,a) This student has done a good job.,100% (1) [1.25],0% (0) [-1.7],1.25,1.25 \\"Team 1.1'\\"\\"\\",student3 In Course1,student3InCourse1@gmail.tmt,b) This student has tried his/her best.,100% (1) [1.25],0% (0) [-1.7],1.25,1.25 -\\"Team 1.1'\\"\\"\\",student4 In Course1,student4InCourse1@gmail.tmt,a) This student has done a good job.,0% (0) [1.25],0% (0) [-1.7],0,0 +\\"Team 1.1'\\"\\"\\",student4 In Course1,student4InCourse1@gmail.tmt,a) This student has done a good job.,0% (0) [1.25],0% (0) [-1.7],-,- \\"Team 1.1'\\"\\"\\",student4 In Course1,student4InCourse1@gmail.tmt,b) This student has tried his/her best.,100% (1) [1.25],0% (0) [-1.7],1.25,1.25 Per Recipient Statistics (Overall) @@ -395,7 +395,7 @@ Team,Recipient Name,Recipient Email,Yes,No,Total,Average,Per Criterion Average \\"Team 1.1'\\"\\"\\",\\"student1 In Course1'\\"\\"\\",student1InCourse1@gmail.tmt,50% (1) [1.25],50% (1) [-1.7],-0.45,-0.23,\\"1.25,-1.7\\" \\"Team 1.1'\\"\\"\\",student2 In Course1,student2InCourse1@gmail.tmt,50% (1) [1.25],50% (1) [-1.7],-0.45,-0.23,\\"-1.7,1.25\\" \\"Team 1.1'\\"\\"\\",student3 In Course1,student3InCourse1@gmail.tmt,100% (2) [1.25],0% (0) [-1.7],2.5,1.25,\\"1.25,1.25\\" -\\"Team 1.1'\\"\\"\\",student4 In Course1,student4InCourse1@gmail.tmt,100% (1) [1.25],0% (0) [-1.7],1.25,1.25,\\"0,1.25\\" +\\"Team 1.1'\\"\\"\\",student4 In Course1,student4InCourse1@gmail.tmt,100% (1) [1.25],0% (0) [-1.7],1.25,1.25,\\"-,1.25\\" Team,Giver's Name,Giver's Email,Recipient's Team,Recipient's Name,Recipient's Email,Sub Question,Choice Value,Choice Number,Giver's Comment @@ -427,22 +427,22 @@ Question 2,Please choose the best choice for the following sub-questions. Only f Summary Statistics ,Yes,No,Average a) This student has done a good job.,66.67% (2) [1.25],33.33% (1) [1],1.17 -b) This student has tried his/her best.,0% (0) [1.25],0% (0) [1],0 +b) This student has tried his/her best.,0% (0) [1.25],0% (0) [1],- Per Recipient Statistics (Per Criterion) Team,Recipient Name,Recipient Email,Sub Question,Yes,No,Total,Average \\"Team 1.1'\\"\\"\\",student2 In Course1,student2InCourse1@gmail.tmt,a) This student has done a good job.,100% (1) [1.25],0% (0) [1],1.25,1.25 -\\"Team 1.1'\\"\\"\\",student2 In Course1,student2InCourse1@gmail.tmt,b) This student has tried his/her best.,0% (0) [1.25],0% (0) [1],0,0 +\\"Team 1.1'\\"\\"\\",student2 In Course1,student2InCourse1@gmail.tmt,b) This student has tried his/her best.,0% (0) [1.25],0% (0) [1],-,- \\"Team 1.1'\\"\\"\\",student3 In Course1,student3InCourse1@gmail.tmt,a) This student has done a good job.,0% (0) [1.25],100% (1) [1],1,1 -\\"Team 1.1'\\"\\"\\",student3 In Course1,student3InCourse1@gmail.tmt,b) This student has tried his/her best.,0% (0) [1.25],0% (0) [1],0,0 +\\"Team 1.1'\\"\\"\\",student3 In Course1,student3InCourse1@gmail.tmt,b) This student has tried his/her best.,0% (0) [1.25],0% (0) [1],-,- \\"Team 1.1'\\"\\"\\",student4 In Course1,student4InCourse1@gmail.tmt,a) This student has done a good job.,100% (1) [1.25],0% (0) [1],1.25,1.25 -\\"Team 1.1'\\"\\"\\",student4 In Course1,student4InCourse1@gmail.tmt,b) This student has tried his/her best.,0% (0) [1.25],0% (0) [1],0,0 +\\"Team 1.1'\\"\\"\\",student4 In Course1,student4InCourse1@gmail.tmt,b) This student has tried his/her best.,0% (0) [1.25],0% (0) [1],-,- Per Recipient Statistics (Overall) Team,Recipient Name,Recipient Email,Yes,No,Total,Average,Per Criterion Average -\\"Team 1.1'\\"\\"\\",student2 In Course1,student2InCourse1@gmail.tmt,100% (1) [1.25],0% (0) [1],1.25,1.25,\\"1.25,0\\" -\\"Team 1.1'\\"\\"\\",student3 In Course1,student3InCourse1@gmail.tmt,0% (0) [1.25],100% (1) [1],1,1,\\"1,0\\" -\\"Team 1.1'\\"\\"\\",student4 In Course1,student4InCourse1@gmail.tmt,100% (1) [1.25],0% (0) [1],1.25,1.25,\\"1.25,0\\" +\\"Team 1.1'\\"\\"\\",student2 In Course1,student2InCourse1@gmail.tmt,100% (1) [1.25],0% (0) [1],1.25,1.25,\\"1.25,-\\" +\\"Team 1.1'\\"\\"\\",student3 In Course1,student3InCourse1@gmail.tmt,0% (0) [1.25],100% (1) [1],1,1,\\"1,-\\" +\\"Team 1.1'\\"\\"\\",student4 In Course1,student4InCourse1@gmail.tmt,100% (1) [1.25],0% (0) [1],1.25,1.25,\\"1.25,-\\" Team,Giver's Name,Giver's Email,Recipient's Team,Recipient's Name,Recipient's Email,Sub Question,Choice Value,Choice Number,Giver's Comment diff --git a/src/web/types/question-details-impl/feedback-rubric-question-details.impl.ts b/src/web/types/question-details-impl/feedback-rubric-question-details.impl.ts index 1049e57744d..7cb611879e5 100644 --- a/src/web/types/question-details-impl/feedback-rubric-question-details.impl.ts +++ b/src/web/types/question-details-impl/feedback-rubric-question-details.impl.ts @@ -7,6 +7,7 @@ import { FeedbackQuestionType, FeedbackRubricQuestionDetails, QuestionOutput, } from '../api-output'; +import { NO_VALUE } from '../feedback-response-details'; import { AbstractFeedbackQuestionDetails } from './abstract-feedback-question-details'; /** @@ -64,11 +65,13 @@ export class FeedbackRubricQuestionDetailsImpl extends AbstractFeedbackQuestionD ...statsCalculation.choices.map((_: string, choiceIndex: number) => { return `${statsCalculation.percentages[questionIndex][choiceIndex]}% \ (${statsCalculation.answers[questionIndex][choiceIndex]}) \ -${statsCalculation.hasWeights ? `[${statsCalculation.weights[questionIndex][choiceIndex]}]` : ''}`; +${statsCalculation.hasWeights + ? `[${this.getDisplayWeight(statsCalculation.weights[questionIndex][choiceIndex])}]` + : ''}`; }), ]; if (statsCalculation.hasWeights) { - currRow.push(String(statsCalculation.subQuestionWeightAverage[questionIndex])); + currRow.push(String(this.getDisplayWeight(statsCalculation.subQuestionWeightAverage[questionIndex]))); } statsRows.push(currRow); }); @@ -103,10 +106,10 @@ ${statsCalculation.hasWeights ? `[${statsCalculation.weights[questionIndex][choi ...statsCalculation.choices.map((_: string, choiceIndex: number) => { return `${perRecipientStats.percentages[questionIndex][choiceIndex]}% \ (${perRecipientStats.answers[questionIndex][choiceIndex]}) \ -[${statsCalculation.weights[questionIndex][choiceIndex]}]`; +[${this.getDisplayWeight(statsCalculation.weights[questionIndex][choiceIndex])}]`; }), - String(perRecipientStats.subQuestionTotalChosenWeight[questionIndex]), - String(perRecipientStats.subQuestionWeightAverage[questionIndex]), + String(this.getDisplayWeight(perRecipientStats.subQuestionTotalChosenWeight[questionIndex])), + String(this.getDisplayWeight(perRecipientStats.subQuestionWeightAverage[questionIndex])), ]); }); }); @@ -128,6 +131,9 @@ ${statsCalculation.hasWeights ? `[${statsCalculation.weights[questionIndex][choi .sort((a: PerRecipientStats, b: PerRecipientStats) => a.recipientTeam.localeCompare(b.recipientTeam) || a.recipientName.localeCompare(b.recipientName)) .forEach((perRecipientStats: PerRecipientStats) => { + const perCriterionAverage: string = + perRecipientStats.subQuestionWeightAverage.map((val: number) => + this.getDisplayWeight(val)).toString(); statsRows.push([ perRecipientStats.recipientTeam, perRecipientStats.recipientName, @@ -135,11 +141,11 @@ ${statsCalculation.hasWeights ? `[${statsCalculation.weights[questionIndex][choi ...statsCalculation.choices.map((_: string, choiceIndex: number) => { return `${perRecipientStats.percentagesAverage[choiceIndex]}% \ (${perRecipientStats.answersSum[choiceIndex]}) \ -[${perRecipientStats.weightsAverage[choiceIndex]}]`; +[${this.getDisplayWeight(perRecipientStats.weightsAverage[choiceIndex])}]`; }), - String(perRecipientStats.overallWeightedSum), - String(perRecipientStats.overallWeightAverage), - String(perRecipientStats.subQuestionWeightAverage.toString()), + String(this.getDisplayWeight(perRecipientStats.overallWeightedSum)), + String(this.getDisplayWeight(perRecipientStats.overallWeightAverage)), + String(perCriterionAverage), ]); }); @@ -153,4 +159,8 @@ ${statsCalculation.hasWeights ? `[${statsCalculation.weights[questionIndex][choi isInstructorCommentsOnResponsesAllowed(): boolean { return true; } + + private getDisplayWeight(weight: number): any { + return weight === null || weight === NO_VALUE ? '-' : weight; + } } From c6e3b18a38fc36b54d7374dd5a479e5f5856d112 Mon Sep 17 00:00:00 2001 From: Samuel Fang <60355570+samuelfangjw@users.noreply.github.com> Date: Mon, 21 Aug 2023 15:17:51 +0800 Subject: [PATCH 5/5] [#12565] Release V8.29.0 (#12566) --- src/web/data/developers.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/web/data/developers.json b/src/web/data/developers.json index ec8eef70336..4a486aaa848 100644 --- a/src/web/data/developers.json +++ b/src/web/data/developers.json @@ -1265,6 +1265,9 @@ "name": "Marianna Sternefeld", "username": "mesternefeld" }, + { + "username": "mariemllr" + }, { "name": "Marlon Calvo", "username": "marloncalvo" @@ -1489,6 +1492,11 @@ { "username": "Olle251" }, + { + "multiple": true, + "name": "Ong Han Wei", + "username": "rexong" + }, { "name": "Ong Jun Xiong", "username": "ong6" @@ -1650,6 +1658,10 @@ "name": "Rajat Saxena", "username": "srajat" }, + { + "name": "Rajdeep Pal", + "username": "Rajdeep1311" + }, { "name": "Rajiv Jha", "username": "rjrajivjha" @@ -1771,6 +1783,9 @@ { "username": "SetsunaS" }, + { + "username": "sgadkar2" + }, { "multiple": true, "name": "Shaharyar Shamshi", @@ -2089,6 +2104,9 @@ "multiple": true, "name": "Teo Yock Swee Terence" }, + { + "username": "theKelvincode" + }, { "multiple": true, "name": "Thikhina Bakmeedeniya",