Skip to content

Commit

Permalink
feat(Teacher): Implement apply tags button (#1687)
Browse files Browse the repository at this point in the history
  • Loading branch information
geoffreykwan authored Mar 14, 2024
1 parent 5bfd1fb commit 65c80ee
Show file tree
Hide file tree
Showing 13 changed files with 210 additions and 17 deletions.
5 changes: 5 additions & 0 deletions src/app/domain/tag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface Tag {
checked?: boolean;
id: number;
text: string;
}
23 changes: 23 additions & 0 deletions src/app/teacher/apply-tags-button/apply-tags-button.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<button
mat-icon-button
[matMenuTriggerFor]="applyTagsMenu"
matTooltip="Apply tags"
matTooltipPosition="above"
i18n-matTooltip
>
<mat-icon>sell</mat-icon>
</button>
<mat-menu #applyTagsMenu>
<div class="menu-info secondary-text" i18n>Apply tags</div>
<mat-divider></mat-divider>
<div *ngFor="let tag of tags" mat-menu-item>
<mat-checkbox
color="primary"
[checked]="tag.checked"
(change)="toggleTagOnProjects(tag, $event.checked)"
(click)="$event.stopPropagation()"
>
{{ tag.text }}
</mat-checkbox>
</div>
</mat-menu>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.menu-info {
margin: 0 16px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ApplyTagsButtonComponent } from './apply-tags-button.component';
import { ApplyTagsButtonModule } from './apply-tags-button.module';
import { HttpClientTestingModule } from '@angular/common/http/testing';

describe('ApplyTagsButtonComponent', () => {
let component: ApplyTagsButtonComponent;
let fixture: ComponentFixture<ApplyTagsButtonComponent>;

beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ApplyTagsButtonComponent],
imports: [ApplyTagsButtonModule, HttpClientTestingModule]
});
fixture = TestBed.createComponent(ApplyTagsButtonComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
58 changes: 58 additions & 0 deletions src/app/teacher/apply-tags-button/apply-tags-button.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Component, Input, OnInit } from '@angular/core';
import { Project } from '../../domain/project';
import { TagService } from '../../../assets/wise5/services/tagService';
import { Tag } from '../../domain/tag';

@Component({
selector: 'apply-tags-button',
templateUrl: './apply-tags-button.component.html',
styleUrls: ['./apply-tags-button.component.scss']
})
export class ApplyTagsButtonComponent implements OnInit {
@Input() selectedProjects: Project[] = [];
protected tags: Tag[] = [];

constructor(private tagService: TagService) {}

ngOnInit(): void {
this.tagService.retrieveUserTags().subscribe((tags: Tag[]) => {
for (const tag of tags) {
tag.checked = this.doesAnyProjectHaveTag(tag);
}
this.tags = tags;
});
}

private doesAnyProjectHaveTag(tag: Tag): boolean {
for (const project of this.selectedProjects) {
if (project.tags.includes(tag.text)) {
return true;
}
}
return false;
}

protected toggleTagOnProjects(tag: Tag, addTag: boolean): void {
if (addTag) {
this.addTagToProjects(tag, this.selectedProjects);
this.tagService.applyTagToProjects(tag, this.selectedProjects);
} else {
this.removeTagFromProjects(tag, this.selectedProjects);
this.tagService.removeTagFromProjects(tag, this.selectedProjects);
}
}

private addTagToProjects(tag: Tag, projects: Project[]): void {
for (const project of projects) {
project.tags.push(tag.text);
project.tags.sort();
}
}

private removeTagFromProjects(tag: Tag, projects: Project[]): void {
for (const project of projects) {
project.tags = project.tags.filter((projectTag: string) => projectTag !== tag.text);
project.tags.sort();
}
}
}
32 changes: 32 additions & 0 deletions src/app/teacher/apply-tags-button/apply-tags-button.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { NgModule } from '@angular/core';
import { ApplyTagsButtonComponent } from './apply-tags-button.component';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatTooltipModule } from '@angular/material/tooltip';
import { MatMenuModule } from '@angular/material/menu';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { TagService } from '../../../assets/wise5/services/tagService';
import { StudentTeacherCommonServicesModule } from '../../student-teacher-common-services.module';
import { CommonModule } from '@angular/common';
import { FlexLayoutModule } from '@angular/flex-layout';
import { FormsModule } from '@angular/forms';
import { MatDividerModule } from '@angular/material/divider';

@NgModule({
declarations: [ApplyTagsButtonComponent],
exports: [ApplyTagsButtonComponent],
imports: [
CommonModule,
FlexLayoutModule,
FormsModule,
MatButtonModule,
MatCheckboxModule,
MatDividerModule,
MatIconModule,
MatMenuModule,
MatTooltipModule,
StudentTeacherCommonServicesModule
],
providers: [TagService]
})
export class ApplyTagsButtonModule {}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@
<div *ngIf="run.shared" class="info" i18n>
Shared by {{ run.owner.firstName }} {{ run.owner.lastName }}
</div>
<div fxLayout="row">
<div *ngFor="let tag of run.project.tags" class="tag">{{ tag }}</div>
</div>
</ng-template>

<mat-card
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,10 @@
margin: -8px;
display: block;
}

.tag {
margin-right: 10px;
padding: 0px 5px;
border: 1px solid gray;
border-radius: 5px;
}
22 changes: 14 additions & 8 deletions src/app/teacher/teacher-run-list/teacher-run-list.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,20 @@
<p i18n>Looks like you don't have any archived classroom units.</p>
</div>
</ng-container>
<select-runs-controls
*ngIf="filteredRuns.length > 0"
(archiveProjectsEvent)="archiveProjects($event)"
[runChangedEventEmitter]="runChangedEventEmitter"
[runs]="filteredRuns"
(selectRunsOptionChosenEvent)="selectRunsOptionChosen($event)"
[showArchive]="!showArchivedView"
></select-runs-controls>
<div fxLayout="row">
<select-runs-controls
*ngIf="filteredRuns.length > 0"
(archiveProjectsEvent)="archiveProjects($event)"
[runChangedEventEmitter]="runChangedEventEmitter"
[runs]="filteredRuns"
(selectRunsOptionChosenEvent)="selectRunsOptionChosen($event)"
[showArchive]="!showArchivedView"
></select-runs-controls>
<apply-tags-button
*ngIf="getSelectedProjects().length > 0"
[selectedProjects]="getSelectedProjects()"
></apply-tags-button>
</div>
<app-timeline>
<ng-container *ngFor="let run of filteredRuns.sort(sortByStartTimeDesc); let i = index">
<app-timeline-item
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ export class TeacherRunListComponent implements OnInit {
this.archiveProjectService.archiveProjects(this.getSelectedProjects(), archive);
}

private getSelectedProjects(): Project[] {
protected getSelectedProjects(): Project[] {
return this.filteredRuns
.filter((run: TeacherRun) => run.project.selected)
.map((run: TeacherRun) => run.project);
Expand Down
2 changes: 2 additions & 0 deletions src/app/teacher/teacher.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import { MatToolbarModule } from '@angular/material/toolbar';
import { MatListModule } from '@angular/material/list';
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
import { SelectRunsControlsModule } from './select-runs-controls/select-runs-controls.module';
import { ApplyTagsButtonModule } from './apply-tags-button/apply-tags-button.module';

const materialModules = [
MatAutocompleteModule,
Expand All @@ -66,6 +67,7 @@ const materialModules = [
];
@NgModule({
imports: [
ApplyTagsButtonModule,
CommonModule,
FlexLayoutModule,
FormsModule,
Expand Down
22 changes: 21 additions & 1 deletion src/assets/wise5/services/tagService.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
'use strict';

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { HttpClient, HttpParams } from '@angular/common/http';
import { ConfigService } from './configService';
import { map } from 'rxjs/operators';
import { ProjectService } from './projectService';
import { Observable, Subscription } from 'rxjs';
import { Project } from '../../../app/domain/project';
import { Tag } from '../../../app/domain/tag';

@Injectable()
export class TagService {
Expand Down Expand Up @@ -80,4 +83,21 @@ export class TagService {
hasTagName(tagName: string): boolean {
return this.getExistingTagNames().includes(tagName);
}

retrieveUserTags(): Observable<Tag[]> {
return this.http.get<Tag[]>(`/api/user/tags`);
}

applyTagToProjects(tag: Tag, projects: Project[]): Subscription {
const projectIds = projects.map((project) => project.id);
return this.http.put(`/api/projects/tag/${tag.text}`, projectIds).subscribe();
}

removeTagFromProjects(tag: Tag, projects: Project[]): Subscription {
let params = new HttpParams();
for (const project of projects) {
params = params.append('projectIds', project.id);
}
return this.http.delete(`/api/projects/tag/${tag.text}`, { params: params }).subscribe();
}
}
25 changes: 18 additions & 7 deletions src/messages.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -5496,7 +5496,7 @@ Click &quot;Cancel&quot; to keep the invalid JSON open so you can fix it.</sourc
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/teacher/teacher-run-list-item/teacher-run-list-item.component.html</context>
<context context-type="linenumber">83</context>
<context context-type="linenumber">86</context>
</context-group>
</trans-unit>
<trans-unit id="59a08e65c39e2cecb841fc7123a77756f52c8db3" datatype="html">
Expand Down Expand Up @@ -6282,7 +6282,7 @@ Click &quot;Cancel&quot; to keep the invalid JSON open so you can fix it.</sourc
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/teacher/teacher-run-list/teacher-run-list.component.html</context>
<context context-type="linenumber">104</context>
<context context-type="linenumber">110</context>
</context-group>
</trans-unit>
<trans-unit id="3376099465386156138" datatype="html">
Expand Down Expand Up @@ -7730,7 +7730,7 @@ Click &quot;Cancel&quot; to keep the invalid JSON open so you can fix it.</sourc
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/teacher/teacher-run-list-item/teacher-run-list-item.component.html</context>
<context context-type="linenumber">119</context>
<context context-type="linenumber">122</context>
</context-group>
</trans-unit>
<trans-unit id="2874cc3a35edcf67e588849afeb796f57163458b" datatype="html">
Expand Down Expand Up @@ -8010,6 +8010,17 @@ Click &quot;Cancel&quot; to keep the invalid JSON open so you can fix it.</sourc
<context context-type="linenumber">121,123</context>
</context-group>
</trans-unit>
<trans-unit id="4aec117738aef2c652af2cabf15863b130aa2196" datatype="html">
<source>Apply tags</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/teacher/apply-tags-button/apply-tags-button.component.html</context>
<context context-type="linenumber">4</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/teacher/apply-tags-button/apply-tags-button.component.html</context>
<context context-type="linenumber">11</context>
</context-group>
</trans-unit>
<trans-unit id="a2d9400df68d9f4e89fe24f6a3f40bc5322f19f2" datatype="html">
<source>1. Choose Periods</source>
<context-group purpose="location">
Expand Down Expand Up @@ -8628,7 +8639,7 @@ Click &quot;Cancel&quot; to keep the invalid JSON open so you can fix it.</sourc
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/teacher/teacher-run-list-item/teacher-run-list-item.component.html</context>
<context context-type="linenumber">62</context>
<context context-type="linenumber">65</context>
</context-group>
</trans-unit>
<trans-unit id="cf5b9a99a7f19adbf75653f4c7ff54dc64afbff6" datatype="html">
Expand Down Expand Up @@ -8962,21 +8973,21 @@ Click &quot;Cancel&quot; to keep the invalid JSON open so you can fix it.</sourc
<source>(Legacy Unit)</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/teacher/teacher-run-list-item/teacher-run-list-item.component.html</context>
<context context-type="linenumber">86</context>
<context context-type="linenumber">89</context>
</context-group>
</trans-unit>
<trans-unit id="f88e7633c282be79dd79aa3765a3a853a9b5a5a4" datatype="html">
<source>Last student login: <x id="INTERPOLATION" equiv-text="{{ run.lastRun | date: &apos;short&apos; }}"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/teacher/teacher-run-list-item/teacher-run-list-item.component.html</context>
<context context-type="linenumber">116</context>
<context context-type="linenumber">119</context>
</context-group>
</trans-unit>
<trans-unit id="f31a4ac5cfc26f2d23677bd24f59219dc5f1c491" datatype="html">
<source>Teacher Tools</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/teacher/teacher-run-list-item/teacher-run-list-item.component.html</context>
<context context-type="linenumber">127</context>
<context context-type="linenumber">130</context>
</context-group>
</trans-unit>
<trans-unit id="1133960927497534087" datatype="html">
Expand Down

0 comments on commit 65c80ee

Please sign in to comment.