Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#12547] Empty weights for MCQ #13282

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ public List<String> validateQuestionDetails() {
// trigger this error.
if (hasAssignedWeights && !mcqWeights.isEmpty()) {
mcqWeights.stream()
.filter(weight -> weight < 0)
.filter(weight -> weight != null && weight < 0)
.forEach(weight -> errors.add(MCQ_ERROR_INVALID_WEIGHT));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ public List<String> validateQuestionDetails() {
// If weights are negative, trigger this error.
if (hasAssignedWeights && !msqWeights.isEmpty()) {
msqWeights.stream()
.filter(weight -> weight < 0)
.filter(weight -> weight != null && weight < 0)
.forEach(weight -> errors.add(MSQ_ERROR_INVALID_WEIGHT));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ exports[`McqQuestionEditDetailsFormComponent should snap when questionDropdownEn
<label
class="form-check-label ngb-tooltip-class fw-bold"
container="body"
ngbtooltip="Assign weights to the choices for calculating statistics."
ngbtooltip="Assign weights to the choices for calculating statistics. An empty weight (i.e. Not enough information to evaluate) can be assigned by leaving the input box empty."
>
<input
class="form-check-input ng-untouched ng-pristine ng-valid"
Expand Down Expand Up @@ -204,7 +204,7 @@ exports[`McqQuestionEditDetailsFormComponent should snap when questionDropdownEn
<label
class="form-check-label ngb-tooltip-class fw-bold"
container="body"
ngbtooltip="Assign weights to the choices for calculating statistics."
ngbtooltip="Assign weights to the choices for calculating statistics. An empty weight (i.e. Not enough information to evaluate) can be assigned by leaving the input box empty."
>
<input
class="form-check-input ng-untouched ng-pristine ng-valid"
Expand Down Expand Up @@ -366,7 +366,7 @@ exports[`McqQuestionEditDetailsFormComponent should snap with default view i.e.
<label
class="form-check-label ngb-tooltip-class fw-bold"
container="body"
ngbtooltip="Assign weights to the choices for calculating statistics."
ngbtooltip="Assign weights to the choices for calculating statistics. An empty weight (i.e. Not enough information to evaluate) can be assigned by leaving the input box empty."
>
<input
class="form-check-input ng-untouched ng-pristine ng-valid"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<div class="col-md-6">
<div class="col-md-12">
<div class="form-check form-check-inline" *ngIf="!isGeneratedOptionsEnabled">
<label class="form-check-label ngb-tooltip-class fw-bold" ngbTooltip="Assign weights to the choices for calculating statistics."
<label class="form-check-label ngb-tooltip-class fw-bold" ngbTooltip="Assign weights to the choices for calculating statistics. An empty weight (i.e. Not enough information to evaluate) can be assigned by leaving the input box empty."
container="body">
<input id="weights-checkbox" class="form-check-input" type="checkbox" [ngModel]="model.hasAssignedWeights"
[disabled]="!isEditable"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<div class="col-md-6">
<div class="col-md-12">
<div class="form-check form-check-inline" *ngIf="!isGeneratedOptionsEnabled">
<label class="form-check-label ngb-tooltip-class fw-bold" ngbTooltip="Assign weights to the choices for calculating statistics."
<label class="form-check-label ngb-tooltip-class fw-bold" ngbTooltip="Assign weights to the choices for calculating statistics. An empty weight (i.e. Not enough information to evaluate) can be assigned by leaving the input box empty."
container="body">
<input id="weights-checkbox" class="form-check-input" type="checkbox" [ngModel]="model.hasAssignedWeights"
[disabled]="!isEditable" (ngModelChange)="triggerWeightsColumn($event)">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
{ header: 'Recipient Name', sortBy: SortBy.MCQ_RECIPIENT_NAME },
...Object.keys(this.weightPerOption).map((key: string) => {
return {
header: `${key}[${(this.weightPerOption[key]).toFixed(2)}]`,
header: `${key}[${this.weightPerOption[key] !== null ? (this.weightPerOption[key]).toFixed(2) : '-'}]`,

Check failure on line 65 in src/web/app/components/question-types/question-statistics/mcq-question-statistics.component.ts

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

Unexpected negated condition

Check failure on line 65 in src/web/app/components/question-types/question-statistics/mcq-question-statistics.component.ts

View workflow job for this annotation

GitHub Actions / lint (windows-latest)

Unexpected negated condition
sortBy: SortBy.MCQ_OPTION_SELECTED_TIMES,
};
}),
Expand All @@ -83,8 +83,8 @@
value: this.perRecipientResponses[key].responses[option],
};
}),
{ value: (this.perRecipientResponses[key].total).toFixed(2) },
{ value: (this.perRecipientResponses[key].average).toFixed(2) },
{ value: this.perRecipientResponses[key].total !== null ? (this.perRecipientResponses[key].total).toFixed(2) : '-' },

Check failure on line 86 in src/web/app/components/question-types/question-statistics/mcq-question-statistics.component.ts

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

Unexpected negated condition

Check failure on line 86 in src/web/app/components/question-types/question-statistics/mcq-question-statistics.component.ts

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

This line has a length of 125. Maximum allowed is 120

Check failure on line 86 in src/web/app/components/question-types/question-statistics/mcq-question-statistics.component.ts

View workflow job for this annotation

GitHub Actions / lint (windows-latest)

Unexpected negated condition

Check failure on line 86 in src/web/app/components/question-types/question-statistics/mcq-question-statistics.component.ts

View workflow job for this annotation

GitHub Actions / lint (windows-latest)

This line has a length of 125. Maximum allowed is 120
{ value: this.perRecipientResponses[key].average !== null ? (this.perRecipientResponses[key].average).toFixed(2) : '-' },

Check failure on line 87 in src/web/app/components/question-types/question-statistics/mcq-question-statistics.component.ts

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

Unexpected negated condition

Check failure on line 87 in src/web/app/components/question-types/question-statistics/mcq-question-statistics.component.ts

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

This line has a length of 129. Maximum allowed is 120

Check failure on line 87 in src/web/app/components/question-types/question-statistics/mcq-question-statistics.component.ts

View workflow job for this annotation

GitHub Actions / lint (windows-latest)

Unexpected negated condition

Check failure on line 87 in src/web/app/components/question-types/question-statistics/mcq-question-statistics.component.ts

View workflow job for this annotation

GitHub Actions / lint (windows-latest)

This line has a length of 129. Maximum allowed is 120
];
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
{ header: 'Recipient Name', sortBy: SortBy.MSQ_RECIPIENT_NAME },
...Object.keys(this.weightPerOption).map((key: string) => {
return {
header: `${key} [${(this.weightPerOption[key]).toFixed(2)}]`,
header: `${key} [${this.weightPerOption[key] !== null ? (this.weightPerOption[key]).toFixed(2) : '-'}]`,

Check failure on line 65 in src/web/app/components/question-types/question-statistics/msq-question-statistics.component.ts

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

Unexpected negated condition

Check failure on line 65 in src/web/app/components/question-types/question-statistics/msq-question-statistics.component.ts

View workflow job for this annotation

GitHub Actions / lint (windows-latest)

Unexpected negated condition
sortBy: SortBy.MSQ_OPTION_SELECTED_TIMES,
};
}),
Expand All @@ -83,10 +83,9 @@
value: this.perRecipientResponses[key].responses[option],
};
}),
{ value: (this.perRecipientResponses[key].total).toFixed(2) },
{ value: (this.perRecipientResponses[key].average).toFixed(2) },
{ value: this.perRecipientResponses[key].total !== null ? (this.perRecipientResponses[key].total).toFixed(2) : '-' },

Check failure on line 86 in src/web/app/components/question-types/question-statistics/msq-question-statistics.component.ts

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

Unexpected negated condition

Check failure on line 86 in src/web/app/components/question-types/question-statistics/msq-question-statistics.component.ts

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

This line has a length of 125. Maximum allowed is 120

Check failure on line 86 in src/web/app/components/question-types/question-statistics/msq-question-statistics.component.ts

View workflow job for this annotation

GitHub Actions / lint (windows-latest)

Unexpected negated condition

Check failure on line 86 in src/web/app/components/question-types/question-statistics/msq-question-statistics.component.ts

View workflow job for this annotation

GitHub Actions / lint (windows-latest)

This line has a length of 125. Maximum allowed is 120
{ value: this.perRecipientResponses[key].average !== null ? (this.perRecipientResponses[key].average).toFixed(2) : '-' },

Check failure on line 87 in src/web/app/components/question-types/question-statistics/msq-question-statistics.component.ts

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

Unexpected negated condition

Check failure on line 87 in src/web/app/components/question-types/question-statistics/msq-question-statistics.component.ts

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

This line has a length of 129. Maximum allowed is 120

Check failure on line 87 in src/web/app/components/question-types/question-statistics/msq-question-statistics.component.ts

View workflow job for this annotation

GitHub Actions / lint (windows-latest)

Unexpected negated condition

Check failure on line 87 in src/web/app/components/question-types/question-statistics/msq-question-statistics.component.ts

View workflow job for this annotation

GitHub Actions / lint (windows-latest)

This line has a length of 129. Maximum allowed is 120
];
});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ export class McqQuestionStatisticsCalculation

for (const answer of Object.keys(this.weightPerOption)) {
const weight: number = this.weightPerOption[answer];
if (weight === null) {
continue;
}
Comment on lines 63 to +66
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is correct! but I was just initially puzzled by how we can set weight to be null when it's of number type. Turns out we can.. by doing const weight: number = null as any; to bypass the type checking, and i think that's what we're doing here.

I think we should follow TypeScript's type safety as best as we can for both type safety and readability. Thus, I think we need to change the following:

Line 17: weightPerOption: Record<string, number | null> = {};
Line 18: weightedPercentagePerOption: Record<string, number | null> = {};
Line 48: const weight: number | null = this.question.mcqWeights[i];
Line 57: const weight: number | null = this.weightPerOption[answer];
Line 58: Add a null check, similar to what you did here
Line 63: const weight: number | null = this.weightPerOption[answer];
... probably many more, please add as you see fit

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realized I did not do this in #12545 and set a bad example 🙏

const frequency: number = this.answerFrequency[answer];
const weightedPercentage: number = totalWeightedResponseCount === 0 ? 0
: 100 * ((frequency * weight) / totalWeightedResponseCount);
Expand Down Expand Up @@ -94,14 +97,31 @@ export class McqQuestionStatisticsCalculation
perRecipientResponse[response.recipient][answer] += 1;
}

const areAllOptionWeightsNull: boolean = this.question.mcqWeights.every(weight => weight === null);

for (const recipient of Object.keys(perRecipientResponse)) {
if (areAllOptionWeightsNull) {
this.perRecipientResponses[recipient] = {
recipient,
recipientEmail: recipientEmails[recipient],
total: null,
average: null,
recipientTeam: recipientToTeam[recipient],
responses: perRecipientResponse[recipient],
};
continue;
}

const responses: Record<string, number> = perRecipientResponse[recipient];
let total: number = 0;
let average: number = 0;
let numOfResponsesForRecipient: number = 0;
for (const answer of Object.keys(responses)) {
const responseCount: number = responses[answer];
const weight: number = this.weightPerOption[answer];
if (weight === null) {
continue;
}
total += responseCount * weight;
numOfResponsesForRecipient += responseCount;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ export class MsqQuestionStatisticsCalculation

for (const answer of Object.keys(this.weightPerOption)) {
const weight: number = this.weightPerOption[answer];
if (weight === null) {
continue;
}
const frequency: number = this.answerFrequency[answer];
const weightedPercentage: number = totalWeightedResponseCount === 0 ? 0
: 100 * ((frequency * weight) / totalWeightedResponseCount);
Expand Down Expand Up @@ -116,14 +119,31 @@ export class MsqQuestionStatisticsCalculation
this.updateResponseCountPerOptionForResponse(response.responseDetails, perRecipientResponse[email]);
}

const areAllOptionWeightsNull: boolean = this.question.msqWeights.every(weight => weight === null);

for (const recipient of Object.keys(perRecipientResponse)) {
if (areAllOptionWeightsNull) {
this.perRecipientResponses[recipient] = {
recipient,
recipientEmail: recipientEmails[recipient],
total: null,
average: null,
recipientTeam: recipientToTeam[recipient],
responses: perRecipientResponse[recipient],
};
continue;
}

const responses: Record<string, number> = perRecipientResponse[recipient];
let total: number = 0;
let average: number = 0;
let numOfResponsesForRecipient: number = 0;
for (const answer of Object.keys(responses)) {
const responseCount: number = responses[answer];
const weight: number = this.weightPerOption[answer];
if (weight === null) {
continue;
}
total += responseCount * weight;
numOfResponsesForRecipient += responseCount;
}
Expand Down
Loading