From c226806486c0972d6bae3c2e9974b1d9c987b539 Mon Sep 17 00:00:00 2001 From: Hiroki Terashima Date: Wed, 20 Sep 2023 13:18:15 -0700 Subject: [PATCH] feat(FeedbackRule): isLowestWorkgroupIdInPeerGroup token (#1420) Also add BooleanTermEvaluator to evaluate "true" and "false" tokens that are added on the stack after evaluating other tokens --- .../FeedbackRuleEvaluator.spec.ts | 5 +- .../feedbackRule/FeedbackRuleEvaluator.ts | 10 +++- ...dbackRuleEvaluatorMultipleStudents.spec.ts | 3 ++ .../FeedbackRuleEvaluatorMultipleStudents.ts | 1 + .../BooleanTermEvaluator.spec.ts | 21 +++++++++ .../TermEvaluator/BooleanTermEvaluator.ts | 20 ++++++++ .../TermEvaluator/IdeaTermEvaluator.spec.ts | 29 +++++++----- .../TermEvaluator/IdeaTermEvaluator.ts | 10 +--- ...orkgroupIdInPeerGroupTermEvaluator.spec.ts | 46 +++++++++++++++++++ ...westWorkgroupIdInPeerGroupTermEvaluator.ts | 8 ++++ .../TermEvaluator/TermEvaluator.ts | 22 ++++++++- .../TermEvaluatorFactory.spec.ts | 45 +++++++++++------- .../TermEvaluator/TermEvaluatorFactory.ts | 12 ++++- .../dialog-guidance-student.component.ts | 1 + .../open-response-student.component.ts | 1 + .../peer-chat-question-bank.component.ts | 18 ++++++-- .../dynamic-prompt/DynamicPromptEvaluator.ts | 14 +++++- .../DynamicPromptMultipleChoiceEvaluator.ts | 1 + .../DynamicPromptOpenResponseEvaluator.ts | 1 + .../dynamic-prompt.component.ts | 4 +- src/messages.xlf | 2 +- 21 files changed, 224 insertions(+), 50 deletions(-) create mode 100644 src/assets/wise5/components/common/feedbackRule/TermEvaluator/BooleanTermEvaluator.spec.ts create mode 100644 src/assets/wise5/components/common/feedbackRule/TermEvaluator/BooleanTermEvaluator.ts create mode 100644 src/assets/wise5/components/common/feedbackRule/TermEvaluator/IsLowestWorkgroupIdInPeerGroupTermEvaluator.spec.ts create mode 100644 src/assets/wise5/components/common/feedbackRule/TermEvaluator/IsLowestWorkgroupIdInPeerGroupTermEvaluator.ts diff --git a/src/assets/wise5/components/common/feedbackRule/FeedbackRuleEvaluator.spec.ts b/src/assets/wise5/components/common/feedbackRule/FeedbackRuleEvaluator.spec.ts index f3b7a7cfcb..1151733856 100644 --- a/src/assets/wise5/components/common/feedbackRule/FeedbackRuleEvaluator.spec.ts +++ b/src/assets/wise5/components/common/feedbackRule/FeedbackRuleEvaluator.spec.ts @@ -19,6 +19,7 @@ describe('FeedbackRuleEvaluator', () => { beforeEach(() => { evaluator = new FeedbackRuleEvaluator( new FeedbackRuleComponent(DEFAULT_FEEDBACK_RULES, 5, true), + null, null ); }); @@ -78,6 +79,7 @@ function matchRule_hasKIScore() { beforeEach(() => { evaluator = new FeedbackRuleEvaluator( new FeedbackRuleComponent(HAS_KI_SCORE_FEEDBACK_RULES, 5, true), + null, null ); }); @@ -123,6 +125,7 @@ function matchRule_ideaCount() { ]; evaluator = new FeedbackRuleEvaluator( new FeedbackRuleComponent(feedbackRules, 5, true), + null, null ); }); @@ -147,7 +150,7 @@ function matchNoRule_ReturnDefault() { function matchNoRule_NoDefaultFeedbackAuthored_ReturnApplicationDefault() { it(`should return application default rule when no rule is matched and no default is authored`, () => { - evaluator = new FeedbackRuleEvaluator(new FeedbackRuleComponent([], 5, true), null); + evaluator = new FeedbackRuleEvaluator(new FeedbackRuleComponent([], 5, true), null, null); expectFeedback(['idea10', 'idea11'], [KI_SCORE_1], 1, evaluator.defaultFeedback); }); } diff --git a/src/assets/wise5/components/common/feedbackRule/FeedbackRuleEvaluator.ts b/src/assets/wise5/components/common/feedbackRule/FeedbackRuleEvaluator.ts index eea5678964..4b3aa8730d 100644 --- a/src/assets/wise5/components/common/feedbackRule/FeedbackRuleEvaluator.ts +++ b/src/assets/wise5/components/common/feedbackRule/FeedbackRuleEvaluator.ts @@ -1,6 +1,8 @@ import { Component } from '../../../common/Component'; +import { ConfigService } from '../../../services/configService'; import { ConstraintService } from '../../../services/constraintService'; import { FeedbackRuleComponent } from '../../feedbackRule/FeedbackRuleComponent'; +import { PeerGroup } from '../../peerChat/PeerGroup'; import { CRaterResponse } from '../cRater/CRaterResponse'; import { FeedbackRule } from './FeedbackRule'; import { FeedbackRuleExpression } from './FeedbackRuleExpression'; @@ -12,12 +14,14 @@ export class FeedbackRuleEvaluator { defaultFeedback = $localize`Thanks for submitting your response.`; protected factory; protected referenceComponent: Component; + protected peerGroup: PeerGroup; constructor( protected component: FeedbackRuleComponent, + protected configService: ConfigService, protected constraintService: ConstraintService ) { - this.factory = new TermEvaluatorFactory(constraintService); + this.factory = new TermEvaluatorFactory(configService, constraintService); } getFeedbackRule(responses: T): FeedbackRule { @@ -142,6 +146,10 @@ export class FeedbackRuleEvaluator { ); } + setPeerGroup(peerGroup: PeerGroup): void { + this.peerGroup = peerGroup; + } + setReferenceComponent(referenceComponent: Component): void { this.referenceComponent = referenceComponent; } diff --git a/src/assets/wise5/components/common/feedbackRule/FeedbackRuleEvaluatorMultipleStudents.spec.ts b/src/assets/wise5/components/common/feedbackRule/FeedbackRuleEvaluatorMultipleStudents.spec.ts index 3791399ffc..99b8854f33 100644 --- a/src/assets/wise5/components/common/feedbackRule/FeedbackRuleEvaluatorMultipleStudents.spec.ts +++ b/src/assets/wise5/components/common/feedbackRule/FeedbackRuleEvaluatorMultipleStudents.spec.ts @@ -16,6 +16,7 @@ describe('FeedbackRuleEvaluatorMultipleStudents', () => { beforeEach(() => { evaluator = new FeedbackRuleEvaluatorMultipleStudents( new FeedbackRuleComponent(DEFAULT_FEEDBACK_RULES, 5, true), + null, null ); }); @@ -40,6 +41,7 @@ function matchRules_HasKIScore() { beforeEach(() => { evaluator = new FeedbackRuleEvaluatorMultipleStudents( new FeedbackRuleComponent(HAS_KI_SCORE_FEEDBACK_RULES, 5, true), + null, null ); }); @@ -73,6 +75,7 @@ function matchNoRule_NoDefaultFeedbackAuthored_ReturnApplicationDefault() { authored`, () => { evaluator = new FeedbackRuleEvaluatorMultipleStudents( new FeedbackRuleComponent([], 5, true), + null, null ); expectRules([createCRaterResponse(['idea10', 'idea11'], [KI_SCORE_1], 1)], ['default']); diff --git a/src/assets/wise5/components/common/feedbackRule/FeedbackRuleEvaluatorMultipleStudents.ts b/src/assets/wise5/components/common/feedbackRule/FeedbackRuleEvaluatorMultipleStudents.ts index fc43424c16..c82c6d27a3 100644 --- a/src/assets/wise5/components/common/feedbackRule/FeedbackRuleEvaluatorMultipleStudents.ts +++ b/src/assets/wise5/components/common/feedbackRule/FeedbackRuleEvaluatorMultipleStudents.ts @@ -49,6 +49,7 @@ export class FeedbackRuleEvaluatorMultipleStudents extends FeedbackRuleEvaluator protected evaluateTerm(term: string, responses: Response[]): boolean { const evaluator: TermEvaluator = this.factory.getTermEvaluator(term); + evaluator.setPeerGroup(this.peerGroup); evaluator.setReferenceComponent(this.referenceComponent); return responses.some((response: Response) => { return evaluator.evaluate(response); diff --git a/src/assets/wise5/components/common/feedbackRule/TermEvaluator/BooleanTermEvaluator.spec.ts b/src/assets/wise5/components/common/feedbackRule/TermEvaluator/BooleanTermEvaluator.spec.ts new file mode 100644 index 0000000000..4a1a7ed2a9 --- /dev/null +++ b/src/assets/wise5/components/common/feedbackRule/TermEvaluator/BooleanTermEvaluator.spec.ts @@ -0,0 +1,21 @@ +import { Response } from '../Response'; +import { BooleanTermEvaluator } from './BooleanTermEvaluator'; + +describe('BooleanTermEvaluator', () => { + describe('evaluate()', () => { + testEvaluate('true', true); + testEvaluate('false', false); + }); +}); + +function testEvaluate(term: string, expectedResult: boolean) { + describe(`term is "${term}"`, () => { + let evaluator: BooleanTermEvaluator; + beforeEach(() => { + evaluator = new BooleanTermEvaluator(term); + }); + it(`returns ${expectedResult}`, () => { + expect(evaluator.evaluate(new Response())).toBe(expectedResult); + }); + }); +} diff --git a/src/assets/wise5/components/common/feedbackRule/TermEvaluator/BooleanTermEvaluator.ts b/src/assets/wise5/components/common/feedbackRule/TermEvaluator/BooleanTermEvaluator.ts new file mode 100644 index 0000000000..32f397eea6 --- /dev/null +++ b/src/assets/wise5/components/common/feedbackRule/TermEvaluator/BooleanTermEvaluator.ts @@ -0,0 +1,20 @@ +import { Response } from '../Response'; +import { TermEvaluator } from './TermEvaluator'; + +export class BooleanTermEvaluator extends TermEvaluator { + constructor(protected term: string) { + super(term); + } + + evaluate(response: Response): boolean { + /** + * The term 'true' or 'false' is usually not authored, but is created and added to the termStack + * by the application as it processes operator expressions like "&&", "||", and "!" + * (see FeedbackRuleEvaluator.evaluateOperator()). + * For example, if the student had ideas 1, 2 and 3, evaluating the postfix expression + * ["1", "2", "&&", "3", "&&"] goes like this: + * ["1", "2", "&&", "3", "&&"] => ["true", "3", "&&"] => ["true"] => true. + */ + return this.term === 'true'; + } +} diff --git a/src/assets/wise5/components/common/feedbackRule/TermEvaluator/IdeaTermEvaluator.spec.ts b/src/assets/wise5/components/common/feedbackRule/TermEvaluator/IdeaTermEvaluator.spec.ts index 052cd9386b..7aa400ac7f 100644 --- a/src/assets/wise5/components/common/feedbackRule/TermEvaluator/IdeaTermEvaluator.spec.ts +++ b/src/assets/wise5/components/common/feedbackRule/TermEvaluator/IdeaTermEvaluator.spec.ts @@ -3,19 +3,24 @@ import { CRaterResponse } from '../../cRater/CRaterResponse'; import { IdeaTermEvaluator } from './IdeaTermEvaluator'; describe('IdeaTermEvaluator', () => { - describe('evaluate()', () => { - const response_with_no_ideas = new CRaterResponse(); - const response_with_2_ideas = new CRaterResponse(); - response_with_2_ideas.ideas = [new CRaterIdea('1', true), new CRaterIdea('2', true)]; - it("should always return true if term is 'true'", () => { - const evaluator_true = new IdeaTermEvaluator('true'); - expect(evaluator_true.evaluate(response_with_no_ideas)).toBeTrue(); - expect(evaluator_true.evaluate(response_with_2_ideas)).toBeTrue(); + const evaluator = new IdeaTermEvaluator('1'); + describe('evaluate(response)', () => { + let response: CRaterResponse; + beforeEach(() => { + response = new CRaterResponse(); }); - it('should return true iff idea term is found in the response', () => { - const evaluator_idea1 = new IdeaTermEvaluator('1'); - expect(evaluator_idea1.evaluate(response_with_no_ideas)).toBeFalse(); - expect(evaluator_idea1.evaluate(response_with_2_ideas)).toBeTrue(); + describe('response does not contain the idea', () => { + it('returns false', () => { + expect(evaluator.evaluate(response)).toBeFalse(); + }); + }); + describe('response contains the idea', () => { + beforeEach(() => { + response.ideas = [new CRaterIdea('1', true), new CRaterIdea('2', true)]; + }); + it('returns true', () => { + expect(evaluator.evaluate(response)).toBeTrue(); + }); }); }); }); diff --git a/src/assets/wise5/components/common/feedbackRule/TermEvaluator/IdeaTermEvaluator.ts b/src/assets/wise5/components/common/feedbackRule/TermEvaluator/IdeaTermEvaluator.ts index 032b6ea9b3..f59d62ee20 100644 --- a/src/assets/wise5/components/common/feedbackRule/TermEvaluator/IdeaTermEvaluator.ts +++ b/src/assets/wise5/components/common/feedbackRule/TermEvaluator/IdeaTermEvaluator.ts @@ -7,14 +7,6 @@ export class IdeaTermEvaluator extends TermEvaluator { } evaluate(response: CRaterResponse): boolean { - /** - * The term 'true' or 'false' is usually not authored, but is created and added to the termStack - * by the application as it processes operator expressions like "&&", "||", and "!" - * (see FeedbackRuleEvaluator.evaluateOperator()). - * For example, if the student had ideas 1, 2 and 3, evaluating the postfix expression - * ["1", "2", "&&", "3", "&&"] goes like this: - * ["1", "2", "&&", "3", "&&"] => ["true", "3", "&&"] => ["true"] => true. - */ - return this.term === 'true' || response.getDetectedIdeaNames().includes(this.term); + return response.getDetectedIdeaNames().includes(this.term); } } diff --git a/src/assets/wise5/components/common/feedbackRule/TermEvaluator/IsLowestWorkgroupIdInPeerGroupTermEvaluator.spec.ts b/src/assets/wise5/components/common/feedbackRule/TermEvaluator/IsLowestWorkgroupIdInPeerGroupTermEvaluator.spec.ts new file mode 100644 index 0000000000..f7c3553e23 --- /dev/null +++ b/src/assets/wise5/components/common/feedbackRule/TermEvaluator/IsLowestWorkgroupIdInPeerGroupTermEvaluator.spec.ts @@ -0,0 +1,46 @@ +import { PeerGrouping } from '../../../../../../app/domain/peerGrouping'; +import { PeerGroup } from '../../../peerChat/PeerGroup'; +import { PeerGroupMember } from '../../../peerChat/PeerGroupMember'; +import { CRaterResponse } from '../../cRater/CRaterResponse'; +import { IsLowestWorkgroupIdInPeerGroupTermEvaluator } from './IsLowestWorkgroupIdInPeerGroupTermEvaluator'; + +class ConfigService { + getWorkgroupId() { + return 1; + } +} + +describe('IsLowestWorkgroupIdInPeerGroupTermEvaluator', () => { + let evaluator, mockConfigService; + beforeEach(() => { + evaluator = new IsLowestWorkgroupIdInPeerGroupTermEvaluator('isLowestWorkgroupIdInPeerGroup'); + mockConfigService = new ConfigService(); + evaluator.setConfigService(mockConfigService); + evaluator.setPeerGroup( + new PeerGroup(1, [{ id: 1 }, { id: 2 }] as PeerGroupMember[], new PeerGrouping()) + ); + }); + describe('evaluate()', () => { + [ + { + description: 'your workgroup id is the lowest', + myWorkgroupId: 1, + expected: true + }, + { + description: 'your workgroup id is not the lowest', + myWorkgroupId: 2, + expected: false + } + ].forEach(({ description, myWorkgroupId, expected }) => { + describe(description, () => { + beforeEach(() => { + spyOn(mockConfigService, 'getWorkgroupId').and.returnValue(myWorkgroupId); + }); + it(`returns ${expected}`, () => { + expect(evaluator.evaluate(new CRaterResponse())).toEqual(expected); + }); + }); + }); + }); +}); diff --git a/src/assets/wise5/components/common/feedbackRule/TermEvaluator/IsLowestWorkgroupIdInPeerGroupTermEvaluator.ts b/src/assets/wise5/components/common/feedbackRule/TermEvaluator/IsLowestWorkgroupIdInPeerGroupTermEvaluator.ts new file mode 100644 index 0000000000..b8dd81b17a --- /dev/null +++ b/src/assets/wise5/components/common/feedbackRule/TermEvaluator/IsLowestWorkgroupIdInPeerGroupTermEvaluator.ts @@ -0,0 +1,8 @@ +import { Response } from '../Response'; +import { TermEvaluator } from './TermEvaluator'; + +export class IsLowestWorkgroupIdInPeerGroupTermEvaluator extends TermEvaluator { + evaluate(response: Response | Response[]): boolean { + return this.peerGroup.getWorkgroupIds().sort().at(0) === this.configService.getWorkgroupId(); + } +} diff --git a/src/assets/wise5/components/common/feedbackRule/TermEvaluator/TermEvaluator.ts b/src/assets/wise5/components/common/feedbackRule/TermEvaluator/TermEvaluator.ts index ae7134e62e..ea07524a63 100644 --- a/src/assets/wise5/components/common/feedbackRule/TermEvaluator/TermEvaluator.ts +++ b/src/assets/wise5/components/common/feedbackRule/TermEvaluator/TermEvaluator.ts @@ -1,10 +1,14 @@ import { Component } from '../../../../common/Component'; +import { ConfigService } from '../../../../services/configService'; import { ConstraintService } from '../../../../services/constraintService'; +import { PeerGroup } from '../../../peerChat/PeerGroup'; import { Response } from '../Response'; export abstract class TermEvaluator { - protected referenceComponent: Component; + protected configService: ConfigService; protected constraintService: ConstraintService; + protected peerGroup: PeerGroup; + protected referenceComponent: Component; constructor(protected term: string) {} abstract evaluate(response: Response | Response[]): boolean; @@ -13,6 +17,14 @@ export abstract class TermEvaluator { return /accumulatedIdeaCount(MoreThan|Equals|LessThan)\([\d+]\)/.test(term); } + static isBooleanTerm(term: string): boolean { + return ['true', 'false'].includes(term); + } + + static isLowestWorkgroupIdInPeerGroupTerm(term: string): boolean { + return term === 'isLowestWorkgroupIdInPeerGroup'; + } + static isMyChoiceChosenTerm(term: string): boolean { return /myChoiceChosen\("\w+"\)/.test(term); } @@ -40,10 +52,18 @@ export abstract class TermEvaluator { ); } + setConfigService(service: ConfigService): void { + this.configService = service; + } + setConstraintService(service: ConstraintService): void { this.constraintService = service; } + setPeerGroup(peerGroup: PeerGroup): void { + this.peerGroup = peerGroup; + } + setReferenceComponent(referenceComponent: Component): void { this.referenceComponent = referenceComponent; } diff --git a/src/assets/wise5/components/common/feedbackRule/TermEvaluator/TermEvaluatorFactory.spec.ts b/src/assets/wise5/components/common/feedbackRule/TermEvaluator/TermEvaluatorFactory.spec.ts index 3fdec1e21c..f7047576a9 100644 --- a/src/assets/wise5/components/common/feedbackRule/TermEvaluator/TermEvaluatorFactory.spec.ts +++ b/src/assets/wise5/components/common/feedbackRule/TermEvaluator/TermEvaluatorFactory.spec.ts @@ -4,25 +4,36 @@ import { IdeaCountTermEvaluator } from './IdeaCountTermEvaluator'; import { IdeaTermEvaluator } from './IdeaTermEvaluator'; import { IsSubmitNumberEvaluator } from './IsSubmitNumberEvaluator'; import { TermEvaluatorFactory } from './TermEvaluatorFactory'; +import { AccumulatedIdeaCountTermEvaluator } from './AccumulatedIdeaCountTermEvaluator'; +import { IsLowestWorkgroupIdInPeerGroupTermEvaluator } from './IsLowestWorkgroupIdInPeerGroupTermEvaluator'; +import { BooleanTermEvaluator } from './BooleanTermEvaluator'; describe('TermEvaluatorFactory', () => { - const factory = new TermEvaluatorFactory(null); - describe('getTermEvaluator()', () => { - it('should return correct evaluator', () => { - [ - { - term: 'myChoiceChosen("choice1")', - instanceType: MyChoiceChosenTermEvaluator - }, - { term: 'hasKIScore(3)', instanceType: HasKIScoreTermEvaluator }, - { term: 'ideaCountMoreThan(1)', instanceType: IdeaCountTermEvaluator }, - { term: 'ideaCountEquals(3)', instanceType: IdeaCountTermEvaluator }, - { term: 'ideaCountLessThan(2)', instanceType: IdeaCountTermEvaluator }, - { term: 'isSubmitNumber(2)', instanceType: IsSubmitNumberEvaluator }, - { term: 'isSubmitNumber(23)', instanceType: IsSubmitNumberEvaluator }, - { term: '2', instanceType: IdeaTermEvaluator } - ].forEach(({ term, instanceType }) => { - expect(factory.getTermEvaluator(term) instanceof instanceType).toBeTrue(); + const factory = new TermEvaluatorFactory(null, null); + describe('getTermEvaluator(term)', () => { + [ + { term: 'true', evaluator: BooleanTermEvaluator }, + { term: 'false', evaluator: BooleanTermEvaluator }, + { term: 'hasKIScore(3)', evaluator: HasKIScoreTermEvaluator }, + { term: 'ideaCountMoreThan(1)', evaluator: IdeaCountTermEvaluator }, + { term: 'ideaCountEquals(3)', evaluator: IdeaCountTermEvaluator }, + { term: 'ideaCountLessThan(2)', evaluator: IdeaCountTermEvaluator }, + { term: 'isSubmitNumber(2)', evaluator: IsSubmitNumberEvaluator }, + { term: 'isSubmitNumber(23)', evaluator: IsSubmitNumberEvaluator }, + { term: 'accumulatedIdeaCountMoreThan(1)', evaluator: AccumulatedIdeaCountTermEvaluator }, + { term: 'accumulatedIdeaCountEquals(3)', evaluator: AccumulatedIdeaCountTermEvaluator }, + { term: 'accumulatedIdeaCountLessThan(2)', evaluator: AccumulatedIdeaCountTermEvaluator }, + { term: 'myChoiceChosen("1")', evaluator: MyChoiceChosenTermEvaluator }, + { + term: 'isLowestWorkgroupIdInPeerGroup', + evaluator: IsLowestWorkgroupIdInPeerGroupTermEvaluator + }, + { term: '2', evaluator: IdeaTermEvaluator } + ].forEach(({ term, evaluator }) => { + describe(`term is ${term}`, () => { + it(`returns ${evaluator.name}`, () => { + expect(factory.getTermEvaluator(term) instanceof evaluator).toBeTrue(); + }); }); }); }); diff --git a/src/assets/wise5/components/common/feedbackRule/TermEvaluator/TermEvaluatorFactory.ts b/src/assets/wise5/components/common/feedbackRule/TermEvaluator/TermEvaluatorFactory.ts index c633508a14..07ad875236 100644 --- a/src/assets/wise5/components/common/feedbackRule/TermEvaluator/TermEvaluatorFactory.ts +++ b/src/assets/wise5/components/common/feedbackRule/TermEvaluator/TermEvaluatorFactory.ts @@ -7,13 +7,18 @@ import { IdeaCountWithResponseIndexTermEvaluator } from './IdeaCountWithResponse import { IdeaTermEvaluator } from './IdeaTermEvaluator'; import { IsSubmitNumberEvaluator } from './IsSubmitNumberEvaluator'; import { TermEvaluator } from './TermEvaluator'; +import { ConfigService } from '../../../../services/configService'; +import { IsLowestWorkgroupIdInPeerGroupTermEvaluator } from './IsLowestWorkgroupIdInPeerGroupTermEvaluator'; +import { BooleanTermEvaluator } from './BooleanTermEvaluator'; export class TermEvaluatorFactory { - constructor(private constraintService: ConstraintService) {} + constructor(private configService: ConfigService, private constraintService: ConstraintService) {} getTermEvaluator(term: string): TermEvaluator { let evaluator: TermEvaluator; - if (TermEvaluator.isHasKIScoreTerm(term)) { + if (TermEvaluator.isBooleanTerm(term)) { + evaluator = new BooleanTermEvaluator(term); + } else if (TermEvaluator.isHasKIScoreTerm(term)) { evaluator = new HasKIScoreTermEvaluator(term); } else if (TermEvaluator.isIdeaCountTerm(term)) { evaluator = new IdeaCountTermEvaluator(term); @@ -25,9 +30,12 @@ export class TermEvaluatorFactory { evaluator = new AccumulatedIdeaCountTermEvaluator(term); } else if (TermEvaluator.isMyChoiceChosenTerm(term)) { evaluator = new MyChoiceChosenTermEvaluator(term); + } else if (TermEvaluator.isLowestWorkgroupIdInPeerGroupTerm(term)) { + evaluator = new IsLowestWorkgroupIdInPeerGroupTermEvaluator(term); } else { evaluator = new IdeaTermEvaluator(term); } + evaluator.setConfigService(this.configService); evaluator.setConstraintService(this.constraintService); return evaluator; } diff --git a/src/assets/wise5/components/dialogGuidance/dialog-guidance-student/dialog-guidance-student.component.ts b/src/assets/wise5/components/dialogGuidance/dialog-guidance-student/dialog-guidance-student.component.ts index d1d2253caa..7ba31c49ca 100644 --- a/src/assets/wise5/components/dialogGuidance/dialog-guidance-student/dialog-guidance-student.component.ts +++ b/src/assets/wise5/components/dialogGuidance/dialog-guidance-student/dialog-guidance-student.component.ts @@ -89,6 +89,7 @@ export class DialogGuidanceStudentComponent extends ComponentStudent { this.getMaxSubmitCount(), this.component.isMultipleFeedbackTextsForSameRuleAllowed() ), + this.configService, this.constraintService ); if (this.component.isComputerAvatarEnabled()) { diff --git a/src/assets/wise5/components/openResponse/open-response-student/open-response-student.component.ts b/src/assets/wise5/components/openResponse/open-response-student/open-response-student.component.ts index b458105b29..a9c47a7a84 100644 --- a/src/assets/wise5/components/openResponse/open-response-student/open-response-student.component.ts +++ b/src/assets/wise5/components/openResponse/open-response-student/open-response-student.component.ts @@ -402,6 +402,7 @@ export class OpenResponseStudent extends ComponentStudent { this.getMaxSubmitCount(), this.isMultipleFeedbackTextsForSameRuleAllowed() ), + this.ConfigService, this.constraintService ); const rule: FeedbackRule = feedbackRuleEvaluator.getFeedbackRule([response]); diff --git a/src/assets/wise5/components/peerChat/peer-chat-question-bank/peer-chat-question-bank.component.ts b/src/assets/wise5/components/peerChat/peer-chat-question-bank/peer-chat-question-bank.component.ts index 0a502bc9a6..61cd826776 100644 --- a/src/assets/wise5/components/peerChat/peer-chat-question-bank/peer-chat-question-bank.component.ts +++ b/src/assets/wise5/components/peerChat/peer-chat-question-bank/peer-chat-question-bank.component.ts @@ -1,5 +1,5 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { Observable } from 'rxjs'; +import { Observable, forkJoin } from 'rxjs'; import { PeerGroupService } from '../../../services/peerGroupService'; import { ProjectService } from '../../../services/projectService'; import { OpenResponseContent } from '../../openResponse/OpenResponseContent'; @@ -16,6 +16,7 @@ import { copy } from '../../../common/object/object'; import { Question } from './Question'; import { QuestionBankService } from './questionBank.service'; import { ConstraintService } from '../../../services/constraintService'; +import { ConfigService } from '../../../services/configService'; @Component({ selector: 'peer-chat-question-bank', @@ -31,6 +32,7 @@ export class PeerChatQuestionBankComponent implements OnInit { @Output() useQuestionEvent = new EventEmitter(); constructor( + private configService: ConfigService, private constraintService: ConstraintService, private peerGroupService: PeerGroupService, private projectService: ProjectService, @@ -61,13 +63,20 @@ export class PeerChatQuestionBankComponent implements OnInit { } private evaluatePeerGroup(referenceComponent: WISEComponent): void { - this.getPeerGroupData( + const peerGroupRequest = this.peerGroupService.retrievePeerGroup( + this.content.questionBank.getPeerGroupingTag() + ); + const peerGroupDataRequest = this.getPeerGroupData( this.content.questionBank.getPeerGroupingTag(), this.content.nodeId, this.content.componentId - ).subscribe((peerGroupStudentData: PeerGroupStudentData[]) => { + ); + forkJoin([peerGroupRequest, peerGroupDataRequest]).subscribe((response) => { + const peerGroup = response[0]; + const peerGroupStudentData = response[1]; const questionBankRules = this.chooseQuestionBankRulesToDisplay( referenceComponent, + peerGroup, peerGroupStudentData ); this.displayedQuestionBankRules = questionBankRules; @@ -78,6 +87,7 @@ export class PeerChatQuestionBankComponent implements OnInit { private chooseQuestionBankRulesToDisplay( referenceComponent: WISEComponent, + peerGroup: PeerGroup, peerGroupStudentData: PeerGroupStudentData[] ): QuestionBankRule[] { const responses = peerGroupStudentData.map((peerMemberData: PeerGroupStudentData) => { @@ -93,9 +103,11 @@ export class PeerChatQuestionBankComponent implements OnInit { (referenceComponent.content as OpenResponseContent).maxSubmitCount, false ), + this.configService, this.constraintService ); feedbackRuleEvaluator.setReferenceComponent(referenceComponent); + feedbackRuleEvaluator.setPeerGroup(peerGroup); return this.filterQuestions( feedbackRuleEvaluator.getFeedbackRules(responses) as QuestionBankRule[], this.content.questionBank.maxQuestionsToShow diff --git a/src/assets/wise5/directives/dynamic-prompt/DynamicPromptEvaluator.ts b/src/assets/wise5/directives/dynamic-prompt/DynamicPromptEvaluator.ts index 444dc03c55..f824c637a6 100644 --- a/src/assets/wise5/directives/dynamic-prompt/DynamicPromptEvaluator.ts +++ b/src/assets/wise5/directives/dynamic-prompt/DynamicPromptEvaluator.ts @@ -14,7 +14,12 @@ export abstract class DynamicPromptEvaluator { evaluate(referenceComponent: Component): void { if (this.component.dynamicPrompt.isPeerGroupingTagSpecified()) { - this.evaluatePeerGroup(referenceComponent); + this.component.peerGroupService + .retrievePeerGroup(this.component.dynamicPrompt.getPeerGroupingTag()) + .subscribe((peerGroup) => { + this.component.peerGroup = peerGroup; + this.evaluatePeerGroup(referenceComponent); + }); } else { this.evaluatePersonal(referenceComponent); } @@ -31,9 +36,14 @@ export abstract class DynamicPromptEvaluator { const evaluator = this.component.dynamicPrompt.isPeerGroupingTagSpecified() ? new FeedbackRuleEvaluatorMultipleStudents( feedbackRuleComponent, + this.component.configService, this.component.constraintService ) - : new FeedbackRuleEvaluator(feedbackRuleComponent, this.component.constraintService); + : new FeedbackRuleEvaluator( + feedbackRuleComponent, + this.component.configService, + this.component.constraintService + ); evaluator.setReferenceComponent(referenceComponent); return evaluator; } diff --git a/src/assets/wise5/directives/dynamic-prompt/DynamicPromptMultipleChoiceEvaluator.ts b/src/assets/wise5/directives/dynamic-prompt/DynamicPromptMultipleChoiceEvaluator.ts index 0d552382bb..5785746d2a 100644 --- a/src/assets/wise5/directives/dynamic-prompt/DynamicPromptMultipleChoiceEvaluator.ts +++ b/src/assets/wise5/directives/dynamic-prompt/DynamicPromptMultipleChoiceEvaluator.ts @@ -12,6 +12,7 @@ export class DynamicPromptMultipleChoiceEvaluator extends DynamicPromptEvaluator }); }); const feedbackRuleEvaluator = this.getFeedbackRuleEvaluator(referenceComponent); + feedbackRuleEvaluator.setPeerGroup(this.component.peerGroup); this.setPromptAndEmitRule(feedbackRuleEvaluator.getFeedbackRule(responses)); }); } diff --git a/src/assets/wise5/directives/dynamic-prompt/DynamicPromptOpenResponseEvaluator.ts b/src/assets/wise5/directives/dynamic-prompt/DynamicPromptOpenResponseEvaluator.ts index 310de2b0c8..60053464b8 100644 --- a/src/assets/wise5/directives/dynamic-prompt/DynamicPromptOpenResponseEvaluator.ts +++ b/src/assets/wise5/directives/dynamic-prompt/DynamicPromptOpenResponseEvaluator.ts @@ -14,6 +14,7 @@ export class DynamicPromptOpenResponseEvaluator extends DynamicPromptEvaluator { }); }); const feedbackRuleEvaluator = this.getFeedbackRuleEvaluator(referenceComponent); + feedbackRuleEvaluator.setPeerGroup(this.component.peerGroup); this.setPromptAndEmitRule(feedbackRuleEvaluator.getFeedbackRule(cRaterResponses)); }); } diff --git a/src/assets/wise5/directives/dynamic-prompt/dynamic-prompt.component.ts b/src/assets/wise5/directives/dynamic-prompt/dynamic-prompt.component.ts index bfa9c42330..9dc5ccbf43 100644 --- a/src/assets/wise5/directives/dynamic-prompt/dynamic-prompt.component.ts +++ b/src/assets/wise5/directives/dynamic-prompt/dynamic-prompt.component.ts @@ -9,6 +9,7 @@ import { DynamicPrompt } from './DynamicPrompt'; import { ConstraintService } from '../../services/constraintService'; import { DynamicPromptOpenResponseEvaluator } from './DynamicPromptOpenResponseEvaluator'; import { DynamicPromptMultipleChoiceEvaluator } from './DynamicPromptMultipleChoiceEvaluator'; +import { PeerGroup } from '../../components/peerChat/PeerGroup'; @Component({ selector: 'dynamic-prompt', @@ -24,8 +25,9 @@ export class DynamicPromptComponent implements OnInit { @Input() dynamicPrompt: DynamicPrompt; @Output() dynamicPromptChanged: EventEmitter = new EventEmitter(); @Input() nodeId: string; - prompt: string; + peerGroup: PeerGroup; peerGroupService: PeerGroupService; + prompt: string; constructor( annotationService: AnnotationService, diff --git a/src/messages.xlf b/src/messages.xlf index 044d9e2372..75c2605644 100644 --- a/src/messages.xlf +++ b/src/messages.xlf @@ -16018,7 +16018,7 @@ Are you ready to receive feedback on this answer? Thanks for submitting your response. src/assets/wise5/components/common/feedbackRule/FeedbackRuleEvaluator.ts - 12 + 14