Skip to content

Commit

Permalink
CSCEXAM-1211 More information to library search dropdowns
Browse files Browse the repository at this point in the history
  • Loading branch information
Matti Lupari committed Dec 14, 2023
1 parent 6e84a0a commit 26d17c2
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 33 deletions.
4 changes: 3 additions & 1 deletion app/controllers/ExamController.java
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,9 @@ public Result listExams(
List<Long> courses = courseIds.orElse(Collections.emptyList());
List<Long> sections = sectionIds.orElse(Collections.emptyList());
List<Long> tags = tagIds.orElse(Collections.emptyList());
PathProperties pp = PathProperties.parse("(id, name, course(id, code), examSections(id, name))");
PathProperties pp = PathProperties.parse(
"(id, name, examActiveStartDate, examActiveEndDate, course(id, code), examSections(id, name))"
);
Query<Exam> query = DB.find(Exam.class);
pp.apply(query);
ExpressionList<Exam> el = query.where().isNotNull("name").isNotNull("course").isNull("parent");
Expand Down
12 changes: 12 additions & 0 deletions ui/src/app/question/library/library.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,18 @@ import { LibraryTagsDialogComponent } from './tags/library-tags-dialog.component
<div class="row ms-4 mt-2">
<div class="col-12">
<strong>{{ 'sitnet_search' | translate }}:</strong>
<span
ngbPopover="{{ 'sitnet_library_search_instructions' | translate }}"
popoverTitle="{{ 'sitnet_instructions' | translate }}"
triggers="mouseenter:mouseleave"
class="ms-2"
>
<img
src="/assets/images/icon_tooltip.svg"
alt=""
onerror="this.onerror=null;this.src='/assets/images/icon_tooltip.png';"
/>
</span>
</div>
</div>
<xm-library-search (updated)="resultsUpdated($event)"></xm-library-search>
Expand Down
21 changes: 10 additions & 11 deletions ui/src/app/question/library/search/library-search.component.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
<div class="row ms-3 me-3" *ngIf="user.isAdmin">
<div class="col-md-12 ms-1">
{{ 'sitnet_choose_atleast_one' | translate }}
</div>
</div>
<div class="row ms-3 me-3 align-items-center">
<div class="col-md-4">
<div class="col-md-6">
<span class="m-1" ngbDropdown [autoClose]="'outside'">
<button
class="btn btn-outline-secondary btn-sm"
Expand All @@ -22,7 +17,7 @@
[(ngModel)]="limitations.course"
(ngModelChange)="filterCourses()"
class="form-control"
placeholder="{{ 'sitnet_search' | translate }}"
placeholder="{{ 'sitnet_search_course_hint' | translate }}"
aria-describedby="search-icon-1"
/>
<div class="input-group-append">
Expand All @@ -38,7 +33,7 @@
(click)="applyFilter(course)"
ngbDropdownItem
>
<a role="menuitem">{{ course.name }}</a>
<a role="menuitem">{{ formatCourse(course) }} {{ course.name }}</a>
</li>
</ul>
</span>
Expand All @@ -58,7 +53,7 @@
[(ngModel)]="limitations.exam"
(ngModelChange)="filterExams()"
class="form-control"
placeholder="{{ 'sitnet_search' | translate }}"
placeholder="{{ 'sitnet_search_exam_hint' | translate }}"
aria-describedby="search-icon-2"
/>
<div class="input-group-append">
Expand All @@ -74,7 +69,10 @@
(click)="applyFilter(exam)"
ngbDropdownItem
>
<a role="menuitem">{{ exam.name }}</a>
<a role="menuitem"
>{{ formatCourse(exam) }} {{ exam.name }}
<small *ngIf="exam.period" class="text-muted">({{ exam.period }})</small></a
>
</li>
</ul>
</span>
Expand Down Expand Up @@ -163,8 +161,9 @@
</li>
</ul>
</span>
<span class="ms-2 text-muted" *ngIf="user.isAdmin">{{ 'sitnet_choose_atleast_one' | translate }}</span>
</div>
<div class="col-md-8">
<div class="col-md-6">
<div class="row">
<div [ngClass]="user.isAdmin ? 'col-md-6' : 'col-md-12'">
<form>
Expand Down
42 changes: 30 additions & 12 deletions ui/src/app/question/library/search/library-search.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@
*/
import type { OnInit } from '@angular/core';
import { Component, EventEmitter, Output } from '@angular/core';
import { DateTime } from 'luxon';
import type { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
import { CourseCodeService } from 'src/app/shared/miscellaneous/course-code.service';
import type { Course, Exam, ExamSection, Tag } from '../../../exam/exam.model';
import type { User } from '../../../session/session.service';
import { SessionService } from '../../../session/session.service';
Expand All @@ -27,7 +29,9 @@ interface Filterable<T> {
filtered: boolean;
object: T;
name: string;
code?: string;
usage?: number;
period?: string;
}

@Component({
Expand All @@ -50,7 +54,11 @@ export class LibrarySearchComponent implements OnInit {
filteredTags = this.tags;
questions: LibraryQuestion[] = [];

constructor(private Library: LibraryService, private Session: SessionService) {
constructor(
private Library: LibraryService,
private Session: SessionService,
private CourseCode: CourseCodeService,
) {
this.user = this.Session.getUser();
}

Expand All @@ -63,15 +71,15 @@ export class LibrarySearchComponent implements OnInit {
this.tags = this.filteredTags = storedData.filters.tags || [];
this.filter.text = storedData.filters.text;
this.filter.owner = storedData.filters.owner;
this.query().subscribe((questions) => {
this.query$().subscribe((questions) => {
if (this.filter.text || this.filter.owner) {
this.applySearchFilter();
} else {
this.updated.emit(questions);
}
});
} else {
this.query().subscribe((resp) => this.updated.emit(resp));
this.query$().subscribe((resp) => this.updated.emit(resp));
}
}

Expand All @@ -92,6 +100,7 @@ export class LibrarySearchComponent implements OnInit {
resp.map((r) => ({
id: r.id,
name: r.name,
code: r.code,
object: r,
filtered: false,
})),
Expand All @@ -112,6 +121,8 @@ export class LibrarySearchComponent implements OnInit {
name: r.name || '',
object: r,
filtered: false,
code: r.course?.code,
period: this.formatPeriod(r.examActiveStartDate, r.examActiveEndDate),
})),
);
}),
Expand Down Expand Up @@ -164,33 +175,40 @@ export class LibrarySearchComponent implements OnInit {

applyFilter = (f: Filterable<unknown>) => {
f.filtered = !f.filtered;
this.query().subscribe(() => this.applySearchFilter());
this.query$().subscribe(() => this.applySearchFilter());
};

filterCourses = () => {
this.filteredCourses = this.courses.filter(
(c) => c.name.toLowerCase().indexOf(this.limitations.course.toLowerCase()) > -1,
(c) =>
c.name.toLowerCase().includes(this.limitations.course.toLowerCase()) ||
(c.code && c.code.toLowerCase().includes(this.limitations.course.toLowerCase())),
);
};

filterExams = () => {
this.filteredExams = this.exams.filter(
(e) => e.name.toLowerCase().indexOf(this.limitations.exam.toLowerCase()) > -1,
(e) =>
e.name.toLowerCase().includes(this.limitations.exam.toLowerCase()) ||
(e.code && e.code.toLowerCase().includes(this.limitations.exam.toLowerCase())),
);
};

filterSections = () => {
this.filteredSections = this.sections.filter(
(s) => s.name.toLowerCase().indexOf(this.limitations.section.toLowerCase()) > -1,
this.filteredSections = this.sections.filter((s) =>
s.name.toLowerCase().includes(this.limitations.section.toLowerCase()),
);
};

filterTags = () => {
this.filteredTags = this.tags.filter(
(t) => t.name.toLowerCase().indexOf(this.limitations.tag.toLowerCase()) > -1,
);
this.filteredTags = this.tags.filter((t) => t.name.toLowerCase().includes(this.limitations.tag.toLowerCase()));
};

formatCourse = (f: Filterable<Course | Exam>) => (f.code ? this.CourseCode.formatCode(f.code) : '');

formatPeriod = (s: string | null, e: string | null) =>
s && e ? `${DateTime.fromISO(s).toFormat('dd.LL.yyyy')}-${DateTime.fromISO(e).toFormat('dd.LL.yyyy')}` : '';

private saveFilters = () => {
const filters = {
courses: this.courses,
Expand All @@ -213,7 +231,7 @@ export class LibrarySearchComponent implements OnInit {
return filtered.concat(tags.filter((t) => filteredIds.indexOf(t.id) === -1));
}

private query = (): Observable<LibraryQuestion[]> =>
private query$ = (): Observable<LibraryQuestion[]> =>
this.Library.search(this.getCourseIds(), this.getExamIds(), this.getSectionIds(), this.getTagIds()).pipe(
tap((questions) => {
this.questions = questions;
Expand Down
8 changes: 2 additions & 6 deletions ui/src/app/shared/miscellaneous/course-code.component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Component, Inject, Input } from '@angular/core';
import { SESSION_STORAGE, WebStorageService } from 'ngx-webstorage-service';
import { Component, Input } from '@angular/core';
import type { Course } from '../../exam/exam.model';
import { CourseCodeService } from './course-code.service';

Expand All @@ -9,10 +8,7 @@ import { CourseCodeService } from './course-code.service';
})
export class CourseCodeComponent {
@Input() course!: Course;
constructor(
@Inject(SESSION_STORAGE) private webStorageService: WebStorageService,
private CodeService: CourseCodeService,
) {}
constructor(private CodeService: CourseCodeService) {}

formatCode = () => this.CodeService.formatCode(this.course.code);
}
5 changes: 4 additions & 1 deletion ui/src/assets/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1150,5 +1150,8 @@
"sitnet_wrong_machine_title": "Wrong computer",
"sitnet_examination_logout_title": "Examination logout",
"sitnet_tag_questions": "Lisää kysymyksille avainsanoja EN",
"sitnet_actions": "Toimenpiteet EN"
"sitnet_actions": "Toimenpiteet EN",
"sitnet_search_course_hint": "Hae opintojakson koodilla tai nimellä EN",
"sitnet_search_exam_hint": "Hae opintojakson koodilla tai tentin nimellä EN",
"sitnet_library_search_instructions": "Ohjeet kysymyspankin haun toiminnalle EN"
}
5 changes: 4 additions & 1 deletion ui/src/assets/i18n/fi.json
Original file line number Diff line number Diff line change
Expand Up @@ -1150,5 +1150,8 @@
"sitnet_wrong_machine_title": "Väärä tenttikone",
"sitnet_examination_logout_title": "Tentin uloskirjautuminen",
"sitnet_tag_questions": "Lisää kysymyksille avainsanoja",
"sitnet_actions": "Toimenpiteet"
"sitnet_actions": "Toimenpiteet",
"sitnet_search_course_hint": "Hae opintojakson koodilla tai nimellä",
"sitnet_search_exam_hint": "Hae opintojakson koodilla tai tentin nimellä",
"sitnet_library_search_instructions": "Ohjeet kysymyspankin haun toiminnalle TBD"
}
5 changes: 4 additions & 1 deletion ui/src/assets/i18n/sv.json
Original file line number Diff line number Diff line change
Expand Up @@ -1150,5 +1150,8 @@
"sitnet_wrong_machine_title": "Fel dator",
"sitnet_examination_logout_title": "Utloggning",
"sitnet_tag_questions": "Lisää kysymyksille avainsanoja SV",
"sitnet_actions": "Toimenpiteet SV"
"sitnet_actions": "Toimenpiteet SV",
"sitnet_search_course_hint": "Hae opintojakson koodilla tai nimellä SV",
"sitnet_search_exam_hint": "Hae opintojakson koodilla tai tentin nimellä SV",
"sitnet_library_search_instructions": "Ohjeet kysymyspankin haun toiminnalle EN"
}

0 comments on commit 26d17c2

Please sign in to comment.