From ce024bdb706d49e68f92e2174e8be810522bcb65 Mon Sep 17 00:00:00 2001 From: Hiroki Terashima Date: Mon, 31 Mar 2025 15:54:36 -0700 Subject: [PATCH 01/12] Add EditUnitResourcesComponent to allow authors to add and delete UnitResources in the project info page Co-authored-by: Aaron Detre --- src/app/teacher/authoring-tool.module.ts | 2 + .../edit-unit-resources.component.html | 70 +++++++++++++++++++ .../edit-unit-resources.component.scss | 37 ++++++++++ .../edit-unit-resources.component.spec.ts | 67 ++++++++++++++++++ .../edit-unit-resources.component.ts | 69 ++++++++++++++++++ .../project-info-authoring.component.html | 1 + .../project-info-authoring.component.spec.ts | 14 ++-- .../project-info-authoring.component.ts | 11 +-- src/messages.xlf | 42 +++++++++++ 9 files changed, 304 insertions(+), 9 deletions(-) create mode 100644 src/assets/wise5/authoringTool/edit-unit-resources/edit-unit-resources.component.html create mode 100644 src/assets/wise5/authoringTool/edit-unit-resources/edit-unit-resources.component.scss create mode 100644 src/assets/wise5/authoringTool/edit-unit-resources/edit-unit-resources.component.spec.ts create mode 100644 src/assets/wise5/authoringTool/edit-unit-resources/edit-unit-resources.component.ts diff --git a/src/app/teacher/authoring-tool.module.ts b/src/app/teacher/authoring-tool.module.ts index 8b4f180fe20..4866c1a9bc4 100644 --- a/src/app/teacher/authoring-tool.module.ts +++ b/src/app/teacher/authoring-tool.module.ts @@ -61,6 +61,7 @@ import { AddComponentComponent } from '../../assets/wise5/authoringTool/node/add import { SideMenuComponent } from '../../assets/wise5/common/side-menu/side-menu.component'; import { MainMenuComponent } from '../../assets/wise5/common/main-menu/main-menu.component'; import { ChooseImportComponentComponent } from '../../assets/wise5/authoringTool/importComponent/choose-import-component/choose-import-component.component'; +import { EditUnitResourcesComponent } from '../../assets/wise5/authoringTool/edit-unit-resources/edit-unit-resources.component'; @NgModule({ declarations: [ @@ -106,6 +107,7 @@ import { ChooseImportComponentComponent } from '../../assets/wise5/authoringTool CreateBranchComponent, EditBranchComponent, EditNodeTitleComponent, + EditUnitResourcesComponent, MatBadgeModule, MatChipsModule, MatExpansionModule, diff --git a/src/assets/wise5/authoringTool/edit-unit-resources/edit-unit-resources.component.html b/src/assets/wise5/authoringTool/edit-unit-resources/edit-unit-resources.component.html new file mode 100644 index 00000000000..c6a7ba7ce69 --- /dev/null +++ b/src/assets/wise5/authoringTool/edit-unit-resources/edit-unit-resources.component.html @@ -0,0 +1,70 @@ + + + +
+
+ Resources + + +
+
    + @for ( + resource of resources; + track $index; + let resourceIndex = $index, first = $first, last = $last + ) { +
  • + +
    +
    + {{ resourceIndex + 1 }} +
    +
    + + Resource Name + + + + Resource URL + + +
    +
    + +
    +
    +
    +
  • + } +
+
+ +
+
diff --git a/src/assets/wise5/authoringTool/edit-unit-resources/edit-unit-resources.component.scss b/src/assets/wise5/authoringTool/edit-unit-resources/edit-unit-resources.component.scss new file mode 100644 index 00000000000..faea007bb8c --- /dev/null +++ b/src/assets/wise5/authoringTool/edit-unit-resources/edit-unit-resources.component.scss @@ -0,0 +1,37 @@ +@import 'style/abstracts/variables'; + +.resource-descriptions { + padding: 16px; + border-radius: $card-border-radius; +} + +h5 { + margin-top: 0; +} + +ul { + margin: 16px 0 0 0; + padding: 0 0 16px; +} + +li { + list-style-type: none; +} + +.resource { + position: relative; +} + +.resource-content { + width: 100%; + padding: 8px; + margin-bottom: 8px; +} + +.resource-input { + width: 100%; +} + +.mat-subtitle-1 { + margin: 0; +} diff --git a/src/assets/wise5/authoringTool/edit-unit-resources/edit-unit-resources.component.spec.ts b/src/assets/wise5/authoringTool/edit-unit-resources/edit-unit-resources.component.spec.ts new file mode 100644 index 00000000000..3072b8b76f2 --- /dev/null +++ b/src/assets/wise5/authoringTool/edit-unit-resources/edit-unit-resources.component.spec.ts @@ -0,0 +1,67 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { EditUnitResourcesComponent } from './edit-unit-resources.component'; +import { MockProvider } from 'ng-mocks'; +import { TeacherProjectService } from '../../services/teacherProjectService'; +import { By } from '@angular/platform-browser'; + +let component: EditUnitResourcesComponent; +let fixture: ComponentFixture; +describe('EditUnitResourcesComponent', () => { + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [EditUnitResourcesComponent], + providers: [MockProvider(TeacherProjectService)] + }).compileComponents(); + + fixture = TestBed.createComponent(EditUnitResourcesComponent); + component = fixture.componentInstance; + component.resources = [ + { name: 'Resource 1', url: 'http://example.com/resource1' }, + { name: 'Resource 2', url: 'http://example.com/resource2' } + ]; + fixture.detectChanges(); + }); + + it('should show the correct number of resources', () => { + const resourceElements = fixture.debugElement.queryAll(By.css('input')); + expect(resourceElements.length).toBe(2); + expect(resourceElements[0].nativeElement.value).toContain('Resource 1'); + expect(resourceElements[1].nativeElement.value).toContain('Resource 2'); + }); + + clickTopAddButton_addNewResourceAtTheBeginning(); + clickBottomTopButton_addNewResourceAtTheEnd(); +}); + +function clickTopAddButton_addNewResourceAtTheBeginning() { + describe('Clicking on the top Add Resource button', () => { + let initialLength = 0; + beforeEach(() => { + initialLength = component.resources.length; + fixture.debugElement.queryAll(By.css('button'))[0].nativeElement.click(); + fixture.detectChanges(); + }); + it('should add a new resource to the beginning of the list', () => { + expect(component.resources.length).toBe(initialLength + 1); + expect(component.resources[0].name).toEqual(''); + expect(component.resources[0].url).toEqual(''); + }); + }); +} + +function clickBottomTopButton_addNewResourceAtTheEnd() { + describe('Clicking on the bottom Add Resource button', () => { + let initialLength = 0; + beforeEach(() => { + initialLength = component.resources.length; + const allButtons = fixture.debugElement.queryAll(By.css('button')); + allButtons[allButtons.length - 1].nativeElement.click(); + fixture.detectChanges(); + }); + it('should add a new resource to the end of the list', () => { + expect(component.resources.length).toBe(initialLength + 1); + expect(component.resources.at(-1).name).toEqual(''); + expect(component.resources.at(-1).url).toEqual(''); + }); + }); +} diff --git a/src/assets/wise5/authoringTool/edit-unit-resources/edit-unit-resources.component.ts b/src/assets/wise5/authoringTool/edit-unit-resources/edit-unit-resources.component.ts new file mode 100644 index 00000000000..591514bd67d --- /dev/null +++ b/src/assets/wise5/authoringTool/edit-unit-resources/edit-unit-resources.component.ts @@ -0,0 +1,69 @@ +import { CdkTextareaAutosize } from '@angular/cdk/text-field'; +import { CommonModule } from '@angular/common'; +import { Component, Input } from '@angular/core'; +import { FlexLayoutModule } from '@angular/flex-layout'; +import { FormsModule } from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { MatCardModule } from '@angular/material/card'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { TeacherProjectService } from '../../services/teacherProjectService'; + +class UnitResource { + name: string; + url: string; + constructor(name: string, url: string) { + this.name = name; + this.url = url; + } +} + +@Component({ + imports: [ + CommonModule, + CdkTextareaAutosize, + FlexLayoutModule, + FormsModule, + MatCardModule, + MatInputModule, + MatFormFieldModule, + MatButtonModule, + MatIconModule, + MatTooltipModule + ], + selector: 'edit-unit-resources', + styleUrl: './edit-unit-resources.component.scss', + templateUrl: './edit-unit-resources.component.html' +}) +export class EditUnitResourcesComponent { + @Input() resources: UnitResource[] = []; + + constructor(private projectService: TeacherProjectService) {} + + protected addNewResource(addToTop: boolean): void { + const location = addToTop ? 0 : this.resources.length; + this.resources.splice(location, 0, new UnitResource('', '')); + this.projectService.saveProject(); + if (!addToTop) { + this.scrollToBottomOfList(); + } + } + + private scrollToBottomOfList(): void { + setTimeout(() => { + const button = document.getElementById('add-new-resource-bottom-button'); + if (button) { + button.scrollIntoView(); + } + }, 0); + } + + protected deleteResource(resourceIndex: number): void { + if (confirm($localize`Are you sure you want to delete this resource?`)) { + this.resources.splice(resourceIndex, 1); + this.projectService.saveProject(); + } + } +} diff --git a/src/assets/wise5/authoringTool/project-info-authoring/project-info-authoring.component.html b/src/assets/wise5/authoringTool/project-info-authoring/project-info-authoring.component.html index f49ce39b7ff..274b0707193 100644 --- a/src/assets/wise5/authoringTool/project-info-authoring/project-info-authoring.component.html +++ b/src/assets/wise5/authoringTool/project-info-authoring/project-info-authoring.component.html @@ -85,3 +85,4 @@ + diff --git a/src/assets/wise5/authoringTool/project-info-authoring/project-info-authoring.component.spec.ts b/src/assets/wise5/authoringTool/project-info-authoring/project-info-authoring.component.spec.ts index 9ff473921e5..b720f857542 100644 --- a/src/assets/wise5/authoringTool/project-info-authoring/project-info-authoring.component.spec.ts +++ b/src/assets/wise5/authoringTool/project-info-authoring/project-info-authoring.component.spec.ts @@ -1,11 +1,11 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ProjectInfoAuthoringComponent } from './project-info-authoring.component'; import { provideHttpClientTesting } from '@angular/common/http/testing'; -import { MatDialogModule } from '@angular/material/dialog'; import { TeacherProjectService } from '../../services/teacherProjectService'; import { StudentTeacherCommonServicesModule } from '../../../../app/student-teacher-common-services.module'; import { ConfigService } from '../../services/configService'; import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; +import { EditUnitResourcesComponent } from '../edit-unit-resources/edit-unit-resources.component'; describe('ProjectInfoAuthoringComponent', () => { let component: ProjectInfoAuthoringComponent; @@ -13,10 +13,14 @@ describe('ProjectInfoAuthoringComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ProjectInfoAuthoringComponent], - imports: [MatDialogModule, StudentTeacherCommonServicesModule], - providers: [TeacherProjectService, provideHttpClient(withInterceptorsFromDi()), provideHttpClientTesting()] -}).compileComponents(); + declarations: [ProjectInfoAuthoringComponent], + imports: [EditUnitResourcesComponent, StudentTeacherCommonServicesModule], + providers: [ + TeacherProjectService, + provideHttpClient(withInterceptorsFromDi()), + provideHttpClientTesting() + ] + }).compileComponents(); spyOn(TestBed.inject(TeacherProjectService), 'getProjectMetadata').and.returnValue({}); spyOn(TestBed.inject(ConfigService), 'getConfigParam').and.returnValue('{ "fields": [] }'); fixture = TestBed.createComponent(ProjectInfoAuthoringComponent); diff --git a/src/assets/wise5/authoringTool/project-info-authoring/project-info-authoring.component.ts b/src/assets/wise5/authoringTool/project-info-authoring/project-info-authoring.component.ts index 7025c50608a..7ffe0ca0f5d 100644 --- a/src/assets/wise5/authoringTool/project-info-authoring/project-info-authoring.component.ts +++ b/src/assets/wise5/authoringTool/project-info-authoring/project-info-authoring.component.ts @@ -6,10 +6,10 @@ import { Subject, debounceTime } from 'rxjs'; import { AssetChooser } from '../project-asset-authoring/asset-chooser'; @Component({ - selector: 'project-info-authoring', - templateUrl: './project-info-authoring.component.html', - styleUrls: ['./project-info-authoring.component.scss'], - standalone: false + selector: 'project-info-authoring', + templateUrl: './project-info-authoring.component.html', + styleUrls: ['./project-info-authoring.component.scss'], + standalone: false }) export class ProjectInfoAuthoringComponent { isEditingProjectIcon: boolean = false; @@ -30,6 +30,9 @@ export class ProjectInfoAuthoringComponent { ngOnInit(): void { this.metadata = this.projectService.getProjectMetadata(); + if (this.metadata.resources == null) { + this.metadata.resources = []; + } this.metadataAuthoring = JSON.parse( this.configService.getConfigParam('projectMetadataSettings') ); diff --git a/src/messages.xlf b/src/messages.xlf index 7bee4632296..520f6dcbf60 100644 --- a/src/messages.xlf +++ b/src/messages.xlf @@ -11125,6 +11125,48 @@ The branches will be removed but the steps will remain in the unit. 161 + + Add a new resource + + src/assets/wise5/authoringTool/edit-unit-resources/edit-unit-resources.component.html + 5,8 + + + + Resources + + src/assets/wise5/authoringTool/edit-unit-resources/edit-unit-resources.component.html + 15,16 + + + + Resource Name + + src/assets/wise5/authoringTool/edit-unit-resources/edit-unit-resources.component.html + 33,36 + + + + Resource URL + + src/assets/wise5/authoringTool/edit-unit-resources/edit-unit-resources.component.html + 41,44 + + + + Delete resource + + src/assets/wise5/authoringTool/edit-unit-resources/edit-unit-resources.component.html + 55,57 + + + + Are you sure you want to delete this resource? + + src/assets/wise5/authoringTool/edit-unit-resources/edit-unit-resources.component.ts + 64 + + Choose the component(s) that you want to import, then select Submit. From 9cecade3eacdb1a4f7731179e77788f553b05ffb Mon Sep 17 00:00:00 2001 From: Hiroki Terashima Date: Mon, 31 Mar 2025 16:36:04 -0700 Subject: [PATCH 02/12] Show resource links in the Unit Details view that opens in a new window --- .../library-project-details.component.html | 11 ++++++++ .../library-project-details.component.spec.ts | 8 +++++- src/messages.xlf | 25 ++++++++++++------- 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/app/modules/library/library-project-details/library-project-details.component.html b/src/app/modules/library/library-project-details/library-project-details.component.html index 65d00c9e538..0aee7628eda 100644 --- a/src/app/modules/library/library-project-details/library-project-details.component.html +++ b/src/app/modules/library/library-project-details/library-project-details.component.html @@ -90,6 +90,17 @@ }

} + @if (project.metadata.resources?.length > 0) { +

+ Resources:  + @for (resource of project.metadata.resources; track resource.name; let last = $last) { + {{ + resource.name + }} + {{ last ? '' : ' | ' }} + } +

+ } @if (project.metadata.discourseCategoryURL) { diff --git a/src/app/modules/library/library-project-details/library-project-details.component.spec.ts b/src/app/modules/library/library-project-details/library-project-details.component.spec.ts index f1a16c0e3e8..20ee74ebc0b 100644 --- a/src/app/modules/library/library-project-details/library-project-details.component.spec.ts +++ b/src/app/modules/library/library-project-details/library-project-details.component.spec.ts @@ -34,7 +34,8 @@ describe('LibraryProjectDetailsComponent', () => { authors: [ { id: 10, firstName: 'Spaceman', lastName: 'Spiff', username: 'SpacemanSpiff' }, { id: 12, firstName: 'Captain', lastName: 'Napalm', username: 'CaptainNapalm' } - ] + ], + resources: [{ name: 'Resource 1', uri: 'http://example.com/resource1' }] }; const ngssObject: any = { disciplines: [ @@ -90,6 +91,11 @@ describe('LibraryProjectDetailsComponent', () => { expect(compiled.textContent).toContain('by Spaceman Spiff, Captain Napalm'); }); + it('should show project resources', () => { + const compiled = fixture.debugElement.nativeElement; + expect(compiled.textContent).toContain('Resource 1'); + }); + it('should show copied project info', () => { component['project'].metadata.authors = []; component['parentProject'] = new ParentProject({ diff --git a/src/messages.xlf b/src/messages.xlf index 520f6dcbf60..9a0a9444de0 100644 --- a/src/messages.xlf +++ b/src/messages.xlf @@ -287,7 +287,7 @@
src/app/modules/library/library-project-details/library-project-details.component.html - 150,151 + 161,162 src/app/modules/library/official-library/official-library-details.html @@ -5828,53 +5828,60 @@ Click "Cancel" to keep the invalid JSON open so you can fix it.70,71
+ + Resources: + + src/app/modules/library/library-project-details/library-project-details.component.html + 95,96 + + This unit is a copy of (used under CC BY-SA). src/app/modules/library/library-project-details/library-project-details.component.html - 104,106 + 115,117 This unit is a copy of by (used under CC BY-SA). src/app/modules/library/library-project-details/library-project-details.component.html - 110,113 + 121,124 This unit is licensed under CC BY-SA. src/app/modules/library/library-project-details/library-project-details.component.html - 121,122 + 132,133 This unit is licensed under CC BY-SA by . src/app/modules/library/library-project-details/library-project-details.component.html - 126,129 + 137,140 View License src/app/modules/library/library-project-details/library-project-details.component.html - 135,139 + 146,150 More src/app/modules/library/library-project-details/library-project-details.component.html - 143,149 + 154,160 Use with Class src/app/modules/library/library-project-details/library-project-details.component.html - 154,158 + 165,169 src/app/teacher/create-run-dialog/create-run-dialog.component.html @@ -5885,7 +5892,7 @@ Click "Cancel" to keep the invalid JSON open so you can fix it.Preview src/app/modules/library/library-project-details/library-project-details.component.html - 159,162 + 170,173 src/app/teacher/run-menu/run-menu.component.html From ba3a5e858f17184ef92949f2718ed367db9f627c Mon Sep 17 00:00:00 2001 From: Hiroki Terashima Date: Tue, 1 Apr 2025 12:15:05 -0700 Subject: [PATCH 03/12] Implemented saving changes to Unit Resources in the AT info page --- .../edit-unit-resources.component.ts | 15 +++++++++++++++ src/messages.xlf | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/assets/wise5/authoringTool/edit-unit-resources/edit-unit-resources.component.ts b/src/assets/wise5/authoringTool/edit-unit-resources/edit-unit-resources.component.ts index 591514bd67d..6858ac0cc5c 100644 --- a/src/assets/wise5/authoringTool/edit-unit-resources/edit-unit-resources.component.ts +++ b/src/assets/wise5/authoringTool/edit-unit-resources/edit-unit-resources.component.ts @@ -10,6 +10,7 @@ import { MatIconModule } from '@angular/material/icon'; import { MatInputModule } from '@angular/material/input'; import { MatTooltipModule } from '@angular/material/tooltip'; import { TeacherProjectService } from '../../services/teacherProjectService'; +import { debounceTime, distinctUntilChanged, Subject, Subscription } from 'rxjs'; class UnitResource { name: string; @@ -38,10 +39,24 @@ class UnitResource { templateUrl: './edit-unit-resources.component.html' }) export class EditUnitResourcesComponent { + protected inputChanged: Subject = new Subject(); @Input() resources: UnitResource[] = []; + private subscriptions: Subscription = new Subscription(); constructor(private projectService: TeacherProjectService) {} + ngOnInit(): void { + this.subscriptions.add( + this.inputChanged + .pipe(debounceTime(1000), distinctUntilChanged()) + .subscribe(() => this.projectService.saveProject()) + ); + } + + ngOnDestroy(): void { + this.subscriptions.unsubscribe(); + } + protected addNewResource(addToTop: boolean): void { const location = addToTop ? 0 : this.resources.length; this.resources.splice(location, 0, new UnitResource('', '')); diff --git a/src/messages.xlf b/src/messages.xlf index 9a0a9444de0..68e63f785b0 100644 --- a/src/messages.xlf +++ b/src/messages.xlf @@ -11171,7 +11171,7 @@ The branches will be removed but the steps will remain in the unit. Are you sure you want to delete this resource? src/assets/wise5/authoringTool/edit-unit-resources/edit-unit-resources.component.ts - 64 + 79 From 2e21a4de1a69db82e378920ac1be98f23e45a55c Mon Sep 17 00:00:00 2001 From: Hiroki Terashima Date: Tue, 1 Apr 2025 13:07:11 -0700 Subject: [PATCH 04/12] Hide Use with Classroom and Preview buttons if this is a Resource Unit --- .../library-project-details.component.html | 15 +++++-- .../library-project-details.component.spec.ts | 40 +++++++++++++++++-- src/messages.xlf | 6 +-- 3 files changed, 50 insertions(+), 11 deletions(-) diff --git a/src/app/modules/library/library-project-details/library-project-details.component.html b/src/app/modules/library/library-project-details/library-project-details.component.html index 0aee7628eda..1b81f45ac10 100644 --- a/src/app/modules/library/library-project-details/library-project-details.component.html +++ b/src/app/modules/library/library-project-details/library-project-details.component.html @@ -159,14 +159,21 @@
- @if (isTeacher && !isRunProject && project.wiseVersion !== 4) { + @if ( + isTeacher && + !isRunProject && + project.wiseVersion !== 4 && + project.metadata.unitType === 'Classroom' + ) { } - + @if (project.metadata.unitType === 'Classroom') { + + }
diff --git a/src/app/modules/library/library-project-details/library-project-details.component.spec.ts b/src/app/modules/library/library-project-details/library-project-details.component.spec.ts index 20ee74ebc0b..7742cc3b70a 100644 --- a/src/app/modules/library/library-project-details/library-project-details.component.spec.ts +++ b/src/app/modules/library/library-project-details/library-project-details.component.spec.ts @@ -6,14 +6,16 @@ import { Project } from '../../../domain/project'; import { NGSSStandards } from '../ngssStandards'; import { ConfigService } from '../../../services/config.service'; import { ParentProject } from '../../../domain/parentProject'; -import { MockProviders } from 'ng-mocks'; +import { MockComponent, MockProviders } from 'ng-mocks'; +import { By } from '@angular/platform-browser'; +import { LibraryProjectMenuComponent } from '../library-project-menu/library-project-menu.component'; +let component: LibraryProjectDetailsComponent; +let fixture: ComponentFixture; describe('LibraryProjectDetailsComponent', () => { - let component: LibraryProjectDetailsComponent; - let fixture: ComponentFixture; - beforeEach(() => { TestBed.configureTestingModule({ + declarations: [MockComponent(LibraryProjectMenuComponent)], imports: [LibraryProjectDetailsComponent], providers: [ MockProviders(ConfigService, MatDialog, MatDialogRef, UserService), @@ -30,6 +32,7 @@ describe('LibraryProjectDetailsComponent', () => { grades: ['7'], title: 'Photosynthesis & Cellular Respiration', summary: 'A really great unit.', + unitType: 'Classroom', totalTime: '6-7 hours', authors: [ { id: 10, firstName: 'Spaceman', lastName: 'Spiff', username: 'SpacemanSpiff' }, @@ -109,4 +112,33 @@ describe('LibraryProjectDetailsComponent', () => { const compiled = fixture.debugElement.nativeElement; expect(compiled.textContent).toContain('is a copy of Photosynthesis'); }); + + it('should show use with class and preview buttons', () => { + component['isTeacher'] = true; + fixture.detectChanges(); + expect(getButtonWithText('Use with Class')).toBeTruthy(); + expect(getButtonWithText('Preview')).toBeTruthy(); + }); + + isResourceUnitType_HideButtons(); }); + +function isResourceUnitType_HideButtons() { + describe('is not Resource unit type', () => { + beforeEach(() => { + component['project'].metadata.unitType = 'Resource'; + fixture.detectChanges(); + }); + + it('should hide buttons when unit type is Resource', () => { + expect(getButtonWithText('Use with Class')).toBeFalsy(); + expect(getButtonWithText('Preview')).toBeFalsy(); + }); + }); +} + +function getButtonWithText(text: string) { + return fixture.debugElement + .queryAll(By.css('button')) + .find((el) => el.nativeElement.textContent.includes(text)); +} diff --git a/src/messages.xlf b/src/messages.xlf index 68e63f785b0..30aa73b8ad9 100644 --- a/src/messages.xlf +++ b/src/messages.xlf @@ -287,7 +287,7 @@ src/app/modules/library/library-project-details/library-project-details.component.html - 161,162 + 161,165 src/app/modules/library/official-library/official-library-details.html @@ -5881,7 +5881,7 @@ Click "Cancel" to keep the invalid JSON open so you can fix it.Use with Class src/app/modules/library/library-project-details/library-project-details.component.html - 165,169 + 170,174 src/app/teacher/create-run-dialog/create-run-dialog.component.html @@ -5892,7 +5892,7 @@ Click "Cancel" to keep the invalid JSON open so you can fix it.Preview src/app/modules/library/library-project-details/library-project-details.component.html - 170,173 + 176,180 src/app/teacher/run-menu/run-menu.component.html From 3a8b37681a9cf39acbca2a865359f290abe5091d Mon Sep 17 00:00:00 2001 From: Aaron Detre Date: Tue, 8 Apr 2025 13:59:48 -0700 Subject: [PATCH 05/12] feat(Dialog Guidance): Summary display for teachers (#2115) Co-authored-by: Jonathan Lim-Breitbart --- .../shared/node-info/node-info.component.html | 14 ++ .../shared/node-info/node-info.component.scss | 5 + .../shared/node-info/node-info.component.ts | 44 +++--- .../components/common/cRater/CRaterRubric.ts | 4 + .../components/summary/summaryService.ts | 4 +- .../summary-display.component.html | 2 +- .../summary-display.component.scss | 4 - ...nce-teacher-summary-display.component.html | 65 +++++++++ ...-teacher-summary-display.component.spec.ts | 135 ++++++++++++++++++ ...dance-teacher-summary-display.component.ts | 121 ++++++++++++++++ src/messages.xlf | 49 +++++++ 11 files changed, 419 insertions(+), 28 deletions(-) create mode 100644 src/assets/wise5/directives/teacher-summary-display/dialog-guidance-teacher-summary-display.component.html create mode 100644 src/assets/wise5/directives/teacher-summary-display/dialog-guidance-teacher-summary-display.component.spec.ts create mode 100644 src/assets/wise5/directives/teacher-summary-display/dialog-guidance-teacher-summary-display.component.ts diff --git a/src/assets/wise5/classroomMonitor/classroomMonitorComponents/shared/node-info/node-info.component.html b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/shared/node-info/node-info.component.html index 906d9eac220..5f200e63117 100644 --- a/src/assets/wise5/classroomMonitor/classroomMonitorComponents/shared/node-info/node-info.component.html +++ b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/shared/node-info/node-info.component.html @@ -34,6 +34,7 @@

} @if (component.hasResponsesSummary && component.type === 'MultipleChoice') { } @if (component.hasScoresSummary && component.hasScoreAnnotation) { [doRender]="true" /> } + @if (component.hasResponsesSummary && component.type === 'DialogGuidance') { + + } } diff --git a/src/assets/wise5/classroomMonitor/classroomMonitorComponents/shared/node-info/node-info.component.scss b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/shared/node-info/node-info.component.scss index 983bc02da49..26d22af08da 100644 --- a/src/assets/wise5/classroomMonitor/classroomMonitorComponents/shared/node-info/node-info.component.scss +++ b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/shared/node-info/node-info.component.scss @@ -38,3 +38,8 @@ width: auto; } } + +.summary-display { + display: block; + margin: 16px 0; +} diff --git a/src/assets/wise5/classroomMonitor/classroomMonitorComponents/shared/node-info/node-info.component.ts b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/shared/node-info/node-info.component.ts index 2abf08445e9..8ea03190e0c 100644 --- a/src/assets/wise5/classroomMonitor/classroomMonitorComponents/shared/node-info/node-info.component.ts +++ b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/shared/node-info/node-info.component.ts @@ -1,34 +1,36 @@ -import { Component, Input } from '@angular/core'; -import { SummaryService } from '../../../../components/summary/summaryService'; import { AnnotationService } from '../../../../services/annotationService'; +import { CommonModule } from '@angular/common'; +import { Component, Input } from '@angular/core'; +import { ComponentFactory } from '../../../../common/ComponentFactory'; import { ComponentServiceLookupService } from '../../../../services/componentServiceLookupService'; import { ComponentTypeService } from '../../../../services/componentTypeService'; -import { TeacherDataService } from '../../../../services/teacherDataService'; -import { TeacherProjectService } from '../../../../services/teacherProjectService'; -import { ComponentFactory } from '../../../../common/ComponentFactory'; +import { DialogGuidanceTeacherSummaryDisplayComponent } from '../../../../directives/teacher-summary-display/dialog-guidance-teacher-summary-display.component'; +import { FlexLayoutModule } from '@angular/flex-layout'; import { isMatchingPeriods } from '../../../../common/period/period'; -import { Node } from '../../../../common/Node'; import { MatCardModule } from '@angular/material/card'; -import { MatIconModule } from '@angular/material/icon'; import { MatDividerModule } from '@angular/material/divider'; -import { FlexLayoutModule } from '@angular/flex-layout'; +import { MatIconModule } from '@angular/material/icon'; +import { Node } from '../../../../common/Node'; import { PreviewComponentComponent } from '../../../../authoringTool/components/preview-component/preview-component.component'; +import { SummaryService } from '../../../../components/summary/summaryService'; +import { TeacherDataService } from '../../../../services/teacherDataService'; +import { TeacherProjectService } from '../../../../services/teacherProjectService'; import { TeacherSummaryDisplayComponent } from '../../../../directives/teacher-summary-display/teacher-summary-display.component'; -import { CommonModule } from '@angular/common'; @Component({ - imports: [ - CommonModule, - MatCardModule, - MatIconModule, - MatDividerModule, - FlexLayoutModule, - PreviewComponentComponent, - TeacherSummaryDisplayComponent - ], - selector: 'node-info', - styleUrl: 'node-info.component.scss', - templateUrl: 'node-info.component.html' + imports: [ + DialogGuidanceTeacherSummaryDisplayComponent, + CommonModule, + MatCardModule, + MatIconModule, + MatDividerModule, + FlexLayoutModule, + PreviewComponentComponent, + TeacherSummaryDisplayComponent + ], + selector: 'node-info', + styleUrl: 'node-info.component.scss', + templateUrl: 'node-info.component.html' }) export class NodeInfoComponent { protected node: Node; diff --git a/src/assets/wise5/components/common/cRater/CRaterRubric.ts b/src/assets/wise5/components/common/cRater/CRaterRubric.ts index 59b118a166e..a93eea422b8 100644 --- a/src/assets/wise5/components/common/cRater/CRaterRubric.ts +++ b/src/assets/wise5/components/common/cRater/CRaterRubric.ts @@ -10,6 +10,10 @@ export class CRaterRubric { getIdea(ideaId: string): CRaterIdea { return this.ideas.find((idea) => idea.name === ideaId); } + + getIdeas(): CRaterIdea[] { + return this.ideas; + } } export function getUniqueIdeas(responses: any[], rubric: CRaterRubric): CRaterIdea[] { diff --git a/src/assets/wise5/components/summary/summaryService.ts b/src/assets/wise5/components/summary/summaryService.ts index 8951287bc03..61d6139170b 100644 --- a/src/assets/wise5/components/summary/summaryService.ts +++ b/src/assets/wise5/components/summary/summaryService.ts @@ -1,8 +1,8 @@ 'use strict'; import { ComponentService } from '../componentService'; -import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; @Injectable() @@ -26,7 +26,7 @@ export class SummaryService extends ComponentService { 'OpenResponse', 'Table' ]; - this.componentsWithResponsesSummary = ['MultipleChoice', 'Table']; + this.componentsWithResponsesSummary = ['DialogGuidance', 'MultipleChoice', 'Table']; } getComponentTypeLabel(): string { diff --git a/src/assets/wise5/directives/summary-display/summary-display.component.html b/src/assets/wise5/directives/summary-display/summary-display.component.html index d3af9269cd3..5cfd857cb7c 100644 --- a/src/assets/wise5/directives/summary-display/summary-display.component.html +++ b/src/assets/wise5/directives/summary-display/summary-display.component.html @@ -1,4 +1,4 @@ - + @if (hasWarning) {

{{ warningMessage }}

diff --git a/src/assets/wise5/directives/summary-display/summary-display.component.scss b/src/assets/wise5/directives/summary-display/summary-display.component.scss index be612a5974a..ec03009306b 100644 --- a/src/assets/wise5/directives/summary-display/summary-display.component.scss +++ b/src/assets/wise5/directives/summary-display/summary-display.component.scss @@ -1,7 +1,3 @@ -.summary-card { - margin: 16px 8px 8px; -} - .highcharts-chart { display: block; height: 400px; diff --git a/src/assets/wise5/directives/teacher-summary-display/dialog-guidance-teacher-summary-display.component.html b/src/assets/wise5/directives/teacher-summary-display/dialog-guidance-teacher-summary-display.component.html new file mode 100644 index 00000000000..c24dcac29d4 --- /dev/null +++ b/src/assets/wise5/directives/teacher-summary-display/dialog-guidance-teacher-summary-display.component.html @@ -0,0 +1,65 @@ + +
+ {{ idea.id }}. {{ idea.text }} (person{{ idea.count }}) +
+
+ + + +

Student Ideas Detected

+ @if (hasWarning) { +

{{ warningMessage }}

+ } + @if (doRender) { +
+
+

Most Common:

+
    + @for (idea of mostCommonIdeas; track idea.id) { +
  • + +
  • + } +
+
+
+

Least Common:

+
    + @for (idea of leastCommonIdeas; track idea.id) { +
  • + +
  • + } +
+
+
+ @if (seeAllIdeas) { +

All Ideas:

+
    + @for (idea of allIdeas; track idea.id) { +
  • + +
  • + } +
+ Hide all ideas + } @else { + Show all ideas + } + } @else { +
+ Your students' ideas will show up here as they are detected in the dialog. +
+ } +
+
diff --git a/src/assets/wise5/directives/teacher-summary-display/dialog-guidance-teacher-summary-display.component.spec.ts b/src/assets/wise5/directives/teacher-summary-display/dialog-guidance-teacher-summary-display.component.spec.ts new file mode 100644 index 00000000000..76446da3640 --- /dev/null +++ b/src/assets/wise5/directives/teacher-summary-display/dialog-guidance-teacher-summary-display.component.spec.ts @@ -0,0 +1,135 @@ +import { AnnotationService } from '../../services/annotationService'; +import { ComponentFixture } from '@angular/core/testing'; +import { ComponentState } from '../../../../app/domain/componentState'; +import { ConfigService } from '../../services/configService'; +import { CRaterIdea } from '../../components/common/cRater/CRaterIdea'; +import { CRaterRubric } from '../../components/common/cRater/CRaterRubric'; +import { CRaterService } from '../../services/cRaterService'; +import { DialogGuidanceTeacherSummaryDisplayComponent } from './dialog-guidance-teacher-summary-display.component'; +import { MockProviders } from 'ng-mocks'; +import { Observable, of } from 'rxjs'; +import { SummaryService } from '../../components/summary/summaryService'; +import { TeacherDataService } from '../../services/teacherDataService'; +import { TeacherProjectService } from '../../services/teacherProjectService'; +import { TestBed } from '@angular/core/testing'; + +let component: DialogGuidanceTeacherSummaryDisplayComponent; +let fixture: ComponentFixture; +describe('DialogGuidanceTeacherSummaryDisplayComponent', () => { + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [DialogGuidanceTeacherSummaryDisplayComponent], + providers: [ + MockProviders( + AnnotationService, + ConfigService, + CRaterService, + TeacherDataService, + TeacherProjectService, + SummaryService + ) + ] + }).compileComponents(); + + fixture = TestBed.createComponent(DialogGuidanceTeacherSummaryDisplayComponent); + component = fixture.componentInstance; + component.doRender = true; + // Set up component? + }); + beforeEach(() => { + spyOn(TestBed.inject(ConfigService), 'isPreview').and.returnValue(false); + spyOn(TestBed.inject(ConfigService), 'isAuthoring').and.returnValue(false); + spyOn(TestBed.inject(ConfigService), 'isStudentRun').and.returnValue(false); + spyOn(TestBed.inject(ConfigService), 'getNumberOfWorkgroupsInPeriod').and.returnValue(1); + }); + ngOnInit(); +}); + +function ngOnInit() { + describe('ngOnChanges()', () => { + ngInit_NoIdeasDetected_ShowMessage(); + ngInit_IdeasDetected_ShowSummary(); + ngInit_ManyIdeasDetected_ShowTopAndBottomThree(); + }); +} + +function ngInit_NoIdeasDetected_ShowMessage() { + describe('no ideas detected', () => { + beforeEach(() => { + spyOn(TestBed.inject(CRaterService), 'getCRaterRubric').and.returnValue( + generateMockRubric(3, 0) + ); + spyOn(TestBed.inject(SummaryService), 'getLatestClassmateStudentWork').and.returnValue( + generateMockStudentWork(0) + ); + }); + it('shows message to teacher', () => { + component.ngOnInit(); + fixture.detectChanges(); + expect(fixture.nativeElement.querySelector('.notice').textContent).toContain( + "Your students' ideas will show up here as they are detected in the dialog." + ); + }); + }); +} + +function ngInit_IdeasDetected_ShowSummary() { + describe('ideas detected', () => { + beforeEach(() => { + spyOn(TestBed.inject(CRaterService), 'getCRaterRubric').and.returnValue( + generateMockRubric(3, 1) + ); + spyOn(TestBed.inject(SummaryService), 'getLatestClassmateStudentWork').and.returnValue( + generateMockStudentWork(1) + ); + }); + it('shows summary display', () => { + component.ngOnInit(); + fixture.detectChanges(); + + expect(fixture.nativeElement.querySelector('h3').textContent).toEqual('Most Common:'); + }); + }); +} + +function ngInit_ManyIdeasDetected_ShowTopAndBottomThree() { + describe('more than 3 ideas detected', () => { + beforeEach(() => { + spyOn(TestBed.inject(CRaterService), 'getCRaterRubric').and.returnValue( + generateMockRubric(4, 4) + ); + spyOn(TestBed.inject(SummaryService), 'getLatestClassmateStudentWork').and.returnValue( + generateMockStudentWork(4) + ); + }); + it('shows only top and bottom three ideas', () => { + component.ngOnInit(); + fixture.detectChanges(); + expect(fixture.nativeElement.querySelectorAll('#most-common-ideas > li').length).toEqual(3); + expect(fixture.nativeElement.querySelectorAll('#least-common-ideas > li').length).toEqual(3); + }); + }); +} + +function generateMockRubric(numIdeas: number, numDetected: number): CRaterRubric { + const ideas = []; + for (let i = 0; i < numIdeas; i++) { + const idea = new CRaterIdea('idea ' + (i + 1), numDetected > 0 ? true : false); + ideas.push(idea); + numDetected--; + } + return new CRaterRubric({ ideas: ideas }); +} + +function generateMockStudentWork(numIdeasDetected: number): Observable { + const ideas = []; + for (let i = 0; i < numIdeasDetected; i++) { + ideas.push({ name: 'idea ' + (i + 1), detected: true }); + } + return of([ + new ComponentState({ + workgroupId: 1, + studentData: { responses: [{ ideas: ideas }] } + }) + ]); +} diff --git a/src/assets/wise5/directives/teacher-summary-display/dialog-guidance-teacher-summary-display.component.ts b/src/assets/wise5/directives/teacher-summary-display/dialog-guidance-teacher-summary-display.component.ts new file mode 100644 index 00000000000..c0307108509 --- /dev/null +++ b/src/assets/wise5/directives/teacher-summary-display/dialog-guidance-teacher-summary-display.component.ts @@ -0,0 +1,121 @@ +import { AnnotationService } from '../../services/annotationService'; +import { CommonModule } from '@angular/common'; +import { Component } from '@angular/core'; +import { ComponentState } from '../../../../app/domain/componentState'; +import { ConfigService } from '../../services/configService'; +import { CRaterIdea } from '../../components/common/cRater/CRaterIdea'; +import { CRaterRubric } from '../../components/common/cRater/CRaterRubric'; +import { CRaterService } from '../../services/cRaterService'; +import { MatCardModule } from '@angular/material/card'; +import { MatIconModule } from '@angular/material/icon'; +import { SummaryService } from '../../components/summary/summaryService'; +import { TeacherDataService } from '../../services/teacherDataService'; +import { TeacherProjectService } from '../../services/teacherProjectService'; +import { TeacherSummaryDisplayComponent } from './teacher-summary-display.component'; + +@Component({ + imports: [CommonModule, MatCardModule, MatIconModule], + selector: 'dialog-guidance-teacher-summary-display', + styles: ` + h3 { + margin-bottom: 8px; + } + + .idea { + @apply px-2 py-1 rounded-md bg-gray-100 my-1 text-sm; + } + + .mat-icon { + vertical-align: middle; + } + `, + templateUrl: 'dialog-guidance-teacher-summary-display.component.html' +}) +export class DialogGuidanceTeacherSummaryDisplayComponent extends TeacherSummaryDisplayComponent { + protected allIdeas: { id: string; text: string; count: number }[] = []; + protected ideaCountMap: Map> = new Map>(); + protected leastCommonIdeas: { id: string; text: string; count: number }[] = []; + protected mostCommonIdeas: { id: string; text: string; count: number }[] = []; + private rubric: CRaterRubric; + protected seeAllIdeas: boolean; + + constructor( + protected annotationService: AnnotationService, + protected configService: ConfigService, + private cRaterService: CRaterService, + protected dataService: TeacherDataService, + protected projectService: TeacherProjectService, + protected summaryService: SummaryService + ) { + super(annotationService, configService, dataService, projectService, summaryService); + } + + ngOnInit(): void { + this.rubric = this.cRaterService.getCRaterRubric(this.nodeId, this.componentId); + this.getLatestWork().subscribe((componentStates) => { + this.extractIdeas(componentStates); + this.allIdeas = this.getAllIdeas(); + if (!this.allIdeas.some((idea) => this.ideaCountMap.get(idea.id)?.size > 0)) { + this.doRender = false; + } else { + const sortedIdeas = this.sortIdeas(); + this.mostCommonIdeas = [...sortedIdeas].splice(0, 3); + this.leastCommonIdeas = [...sortedIdeas] + .splice(sortedIdeas.length - 3, sortedIdeas.length) + .reverse(); + } + }); + } + + private getAllIdeas(): { id: string; text: string; count: number }[] { + return this.rubric.getIdeas().map((idea) => ({ + id: idea.name, + text: this.useIdeaTextOrId(idea.name, idea.text), + count: this.ideaCountMap.get(idea.name)?.size ?? 0 + })); + } + + private useIdeaTextOrId(id: string, text: string): string { + return text ?? 'idea ' + id; + } + + private extractIdeas(componentStates: ComponentState[]): void { + componentStates.forEach((componentState) => + this.getDetectedIdeas(componentState).forEach((idea) => { + if (this.ideaCountMap.has(idea.name)) { + this.ideaCountMap.get(idea.name).add(componentState.workgroupId); + } else { + this.ideaCountMap.set(idea.name, new Set([componentState.workgroupId])); + } + }) + ); + } + + private getDetectedIdeas(componentState: ComponentState): CRaterIdea[] { + return componentState.studentData.responses.flatMap( + (response) => + response.ideas + ?.filter((idea) => idea.detected) + .map((idea) => new CRaterIdea(idea.name, idea.detected)) ?? [] + ); + } + + private sortIdeas(): { id: string; text: string; count: number }[] { + return [...this.ideaCountMap.entries()] + .sort((a, b) => b[1].size - a[1].size) + .map((mapIterator) => ({ + id: mapIterator[0], + text: this.getIdeaText(mapIterator[0]), + count: mapIterator[1].size + })); + } + + private getIdeaText(id: string): string { + return this.useIdeaTextOrId(id, this.rubric.getIdea(id).text); + } + + protected toggleSeeAllIdeas(event: Event): void { + event.preventDefault(); + this.seeAllIdeas = !this.seeAllIdeas; + } +} diff --git a/src/messages.xlf b/src/messages.xlf index 8b6ccf0f583..28e3d561108 100644 --- a/src/messages.xlf +++ b/src/messages.xlf @@ -21290,6 +21290,55 @@ If this problem continues, let your teacher know and move on to the next activit 424 + + Student Ideas Detected + + src/assets/wise5/directives/teacher-summary-display/dialog-guidance-teacher-summary-display.component.html + 10,12 + + + + Most Common: + + src/assets/wise5/directives/teacher-summary-display/dialog-guidance-teacher-summary-display.component.html + 17,19 + + + + Least Common: + + src/assets/wise5/directives/teacher-summary-display/dialog-guidance-teacher-summary-display.component.html + 30,32 + + + + All Ideas: + + src/assets/wise5/directives/teacher-summary-display/dialog-guidance-teacher-summary-display.component.html + 44,46 + + + + Hide all ideas + + src/assets/wise5/directives/teacher-summary-display/dialog-guidance-teacher-summary-display.component.html + 55,57 + + + + Show all ideas + + src/assets/wise5/directives/teacher-summary-display/dialog-guidance-teacher-summary-display.component.html + 57,61 + + + + Your students' ideas will show up here as they are detected in the dialog. + + src/assets/wise5/directives/teacher-summary-display/dialog-guidance-teacher-summary-display.component.html + 61,66 + + The student will see a graph of their individual data here. From 4a928d80c620c4734180e1105d29ea25320cc5e9 Mon Sep 17 00:00:00 2001 From: Hiroki Terashima Date: Tue, 8 Apr 2025 15:50:38 -0700 Subject: [PATCH 06/12] fix(Session): Make renewSession requests on mouse move #2134 --- src/assets/wise5/vle/vle.component.ts | 43 +++++++++++++++------------ 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/assets/wise5/vle/vle.component.ts b/src/assets/wise5/vle/vle.component.ts index 300fe87b682..5203691f433 100644 --- a/src/assets/wise5/vle/vle.component.ts +++ b/src/assets/wise5/vle/vle.component.ts @@ -32,25 +32,25 @@ import { NavigationComponent } from '../themes/default/navigation/navigation.com import { ChooseBranchPathDialogComponent } from '../../../app/preview/modules/choose-branch-path-dialog/choose-branch-path-dialog.component'; @Component({ - imports: [ - CommonModule, - ChooseBranchPathDialogComponent, - GroupTabsComponent, - MatSidenavModule, - NavigationComponent, - NodeComponent, - NodeNavigationComponent, - NotebookLauncherComponent, - NotebookNotesComponent, - NotebookReportComponent, - RunEndedAndLockedMessageComponent, - SafeUrl, - StepToolsComponent, - TopBarComponent - ], - selector: 'vle', - styleUrl: './vle.component.scss', - templateUrl: './vle.component.html' + imports: [ + CommonModule, + ChooseBranchPathDialogComponent, + GroupTabsComponent, + MatSidenavModule, + NavigationComponent, + NodeComponent, + NodeNavigationComponent, + NotebookLauncherComponent, + NotebookNotesComponent, + NotebookReportComponent, + RunEndedAndLockedMessageComponent, + SafeUrl, + StepToolsComponent, + TopBarComponent + ], + selector: 'vle', + styleUrl: './vle.component.scss', + templateUrl: './vle.component.html' }) export class VLEComponent implements AfterViewInit { protected currentNode: Node; @@ -303,6 +303,11 @@ export class VLEComponent implements AfterViewInit { document.querySelector('.top').scrollIntoView(); } + @HostListener('document:mousemove') + protected renewSession(): void { + this.sessionService.mouseMoved(); + } + /** * Returns WISE API */ From 8376c35c47142fdd2bd047ffe876b4b8cbd5c135 Mon Sep 17 00:00:00 2001 From: Aaron Detre Date: Tue, 8 Apr 2025 19:01:49 -0700 Subject: [PATCH 07/12] feat(OpenResponse): Allow authors to specify student-friendly text for ideas (#2130) --- .../components/common/cRater/CRaterIdea.ts | 8 ++- ...it-crater-idea-descriptions.component.html | 6 +- ...edit-crater-idea-descriptions.component.ts | 11 ++-- ...edit-dialog-guidance-advanced.component.ts | 6 +- ...edit-open-response-advanced.component.html | 11 ++++ .../edit-open-response-advanced.component.ts | 35 +++++++---- src/messages.xlf | 59 +++++++++++-------- 7 files changed, 88 insertions(+), 48 deletions(-) diff --git a/src/assets/wise5/components/common/cRater/CRaterIdea.ts b/src/assets/wise5/components/common/cRater/CRaterIdea.ts index a170da13909..4470bb9409c 100644 --- a/src/assets/wise5/components/common/cRater/CRaterIdea.ts +++ b/src/assets/wise5/components/common/cRater/CRaterIdea.ts @@ -1,11 +1,13 @@ export class CRaterIdea { name: string; - detected: boolean; + detected?: boolean; characterOffsets: any[]; text?: string; - constructor(name: string, detected: boolean) { + constructor(name: string, detected?: boolean) { this.name = name; - this.detected = detected; + if (detected) { + this.detected = detected; + } } } diff --git a/src/assets/wise5/components/common/cRater/edit-crater-idea-descriptions/edit-crater-idea-descriptions.component.html b/src/assets/wise5/components/common/cRater/edit-crater-idea-descriptions/edit-crater-idea-descriptions.component.html index d2144dc60b7..593579fee57 100644 --- a/src/assets/wise5/components/common/cRater/edit-crater-idea-descriptions/edit-crater-idea-descriptions.component.html +++ b/src/assets/wise5/components/common/cRater/edit-crater-idea-descriptions/edit-crater-idea-descriptions.component.html @@ -1,10 +1,10 @@
- Idea Names + Idea Descriptions