diff --git a/frontend/src/app/filter/ad-hoc-filter.component.spec.ts b/frontend/src/app/filter/ad-hoc-filter.component.spec.ts deleted file mode 100644 index 4c92ce6bb..000000000 --- a/frontend/src/app/filter/ad-hoc-filter.component.spec.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { commonTestBed } from '../common-test-bed'; - -import { AdHocFilterComponent } from './ad-hoc-filter.component'; - -describe('AdHocFilterComponent', () => { - let component: AdHocFilterComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - commonTestBed().testingModule.compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(AdHocFilterComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/frontend/src/app/filter/ad-hoc-filter.component.ts b/frontend/src/app/filter/ad-hoc-filter.component.ts deleted file mode 100644 index 84dafb611..000000000 --- a/frontend/src/app/filter/ad-hoc-filter.component.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Component } from '@angular/core'; -import { AdHocFilter, } from '../models'; -import { BaseFilterComponent } from './base-filter.component'; - -@Component({ - selector: 'ia-ad-hoc-filter', - templateUrl: './ad-hoc-filter.component.html', - styleUrls: ['./ad-hoc-filter.component.scss'] -}) -export class AdHocFilterComponent extends BaseFilterComponent { -} diff --git a/frontend/src/app/filter/ad-hoc-filter.component.html b/frontend/src/app/filter/ad-hoc-filter/ad-hoc-filter.component.html similarity index 100% rename from frontend/src/app/filter/ad-hoc-filter.component.html rename to frontend/src/app/filter/ad-hoc-filter/ad-hoc-filter.component.html diff --git a/frontend/src/app/filter/ad-hoc-filter.component.scss b/frontend/src/app/filter/ad-hoc-filter/ad-hoc-filter.component.scss similarity index 100% rename from frontend/src/app/filter/ad-hoc-filter.component.scss rename to frontend/src/app/filter/ad-hoc-filter/ad-hoc-filter.component.scss diff --git a/frontend/src/app/filter/ad-hoc-filter/ad-hoc-filter.component.spec.ts b/frontend/src/app/filter/ad-hoc-filter/ad-hoc-filter.component.spec.ts new file mode 100644 index 000000000..a31a9b131 --- /dev/null +++ b/frontend/src/app/filter/ad-hoc-filter/ad-hoc-filter.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { commonTestBed } from '../../common-test-bed'; + +import { AdHocFilterComponent } from './ad-hoc-filter.component'; + +describe('AdHocFilterComponent', () => { + let component: AdHocFilterComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + commonTestBed().testingModule.compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(AdHocFilterComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/filter/ad-hoc-filter/ad-hoc-filter.component.ts b/frontend/src/app/filter/ad-hoc-filter/ad-hoc-filter.component.ts new file mode 100644 index 000000000..b79fccdb6 --- /dev/null +++ b/frontend/src/app/filter/ad-hoc-filter/ad-hoc-filter.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; +import { AdHocFilter, } from '../../models'; +import { BaseFilterComponent } from './../base-filter.component'; + +@Component({ + selector: 'ia-ad-hoc-filter', + templateUrl: './ad-hoc-filter.component.html', + styleUrls: ['./ad-hoc-filter.component.scss'] +}) +export class AdHocFilterComponent extends BaseFilterComponent { +} diff --git a/frontend/src/app/filter/boolean-filter.component.ts b/frontend/src/app/filter/boolean-filter.component.ts deleted file mode 100644 index d63d1ebe1..000000000 --- a/frontend/src/app/filter/boolean-filter.component.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Component } from '@angular/core'; - -import { BaseFilterComponent } from './base-filter.component'; -import { BooleanFilter } from '../models'; - -@Component({ - selector: 'ia-boolean-filter', - templateUrl: './boolean-filter.component.html', - styleUrls: ['./boolean-filter.component.scss'] -}) -export class BooleanFilterComponent extends BaseFilterComponent { -} diff --git a/frontend/src/app/filter/boolean-filter.component.html b/frontend/src/app/filter/boolean-filter/boolean-filter.component.html similarity index 100% rename from frontend/src/app/filter/boolean-filter.component.html rename to frontend/src/app/filter/boolean-filter/boolean-filter.component.html diff --git a/frontend/src/app/filter/boolean-filter.component.scss b/frontend/src/app/filter/boolean-filter/boolean-filter.component.scss similarity index 100% rename from frontend/src/app/filter/boolean-filter.component.scss rename to frontend/src/app/filter/boolean-filter/boolean-filter.component.scss diff --git a/frontend/src/app/filter/boolean-filter.component.spec.ts b/frontend/src/app/filter/boolean-filter/boolean-filter.component.spec.ts similarity index 90% rename from frontend/src/app/filter/boolean-filter.component.spec.ts rename to frontend/src/app/filter/boolean-filter/boolean-filter.component.spec.ts index f2386df95..74072fdb3 100644 --- a/frontend/src/app/filter/boolean-filter.component.spec.ts +++ b/frontend/src/app/filter/boolean-filter/boolean-filter.component.spec.ts @@ -1,8 +1,8 @@ import { ComponentFixture, TestBed, fakeAsync, tick, waitForAsync } from '@angular/core/testing'; -import { mockCorpus3, mockField } from '../../mock-data/corpus'; +import { mockCorpus3, mockField } from '../../../mock-data/corpus'; -import { commonTestBed } from '../common-test-bed'; -import { BooleanFilter, QueryModel } from '../models'; +import { commonTestBed } from '../../common-test-bed'; +import { BooleanFilter, QueryModel } from '../../models'; import { BooleanFilterComponent } from './boolean-filter.component'; import { By } from '@angular/platform-browser'; diff --git a/frontend/src/app/filter/boolean-filter/boolean-filter.component.ts b/frontend/src/app/filter/boolean-filter/boolean-filter.component.ts new file mode 100644 index 000000000..d67899f86 --- /dev/null +++ b/frontend/src/app/filter/boolean-filter/boolean-filter.component.ts @@ -0,0 +1,12 @@ +import { Component } from '@angular/core'; + +import { BaseFilterComponent } from '../base-filter.component'; +import { BooleanFilter } from '../../models'; + +@Component({ + selector: 'ia-boolean-filter', + templateUrl: './boolean-filter.component.html', + styleUrls: ['./boolean-filter.component.scss'] +}) +export class BooleanFilterComponent extends BaseFilterComponent { +} diff --git a/frontend/src/app/filter/date-filter.component.html b/frontend/src/app/filter/date-filter/date-filter.component.html similarity index 100% rename from frontend/src/app/filter/date-filter.component.html rename to frontend/src/app/filter/date-filter/date-filter.component.html diff --git a/frontend/src/app/filter/date-filter.component.scss b/frontend/src/app/filter/date-filter/date-filter.component.scss similarity index 78% rename from frontend/src/app/filter/date-filter.component.scss rename to frontend/src/app/filter/date-filter/date-filter.component.scss index 103bf4541..a5a02a474 100644 --- a/frontend/src/app/filter/date-filter.component.scss +++ b/frontend/src/app/filter/date-filter/date-filter.component.scss @@ -1,8 +1,8 @@ -@import "../../_utilities"; +@import "../../../_utilities"; ::ng-deep .p-datepicker { margin: 1px 0; .p-highlight { background-color: $primary !important; }; -} \ No newline at end of file +} diff --git a/frontend/src/app/filter/date-filter.component.spec.ts b/frontend/src/app/filter/date-filter/date-filter.component.spec.ts similarity index 90% rename from frontend/src/app/filter/date-filter.component.spec.ts rename to frontend/src/app/filter/date-filter/date-filter.component.spec.ts index 74fd0b881..1b4b728ae 100644 --- a/frontend/src/app/filter/date-filter.component.spec.ts +++ b/frontend/src/app/filter/date-filter/date-filter.component.spec.ts @@ -1,8 +1,8 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { mockCorpus3, mockFieldDate } from '../../mock-data/corpus'; +import { mockCorpus3, mockFieldDate } from '../../../mock-data/corpus'; -import { commonTestBed } from '../common-test-bed'; -import { DateFilter, DateFilterData, QueryModel } from '../models'; +import { commonTestBed } from '../../common-test-bed'; +import { DateFilter, DateFilterData, QueryModel } from '../../models'; import { DateFilterComponent } from './date-filter.component'; diff --git a/frontend/src/app/filter/date-filter.component.ts b/frontend/src/app/filter/date-filter/date-filter.component.ts similarity index 74% rename from frontend/src/app/filter/date-filter.component.ts rename to frontend/src/app/filter/date-filter/date-filter.component.ts index bdacc2a79..80fb09467 100644 --- a/frontend/src/app/filter/date-filter.component.ts +++ b/frontend/src/app/filter/date-filter/date-filter.component.ts @@ -1,14 +1,14 @@ import { Component } from '@angular/core'; import * as _ from 'lodash'; -import { DateFilter } from '../models'; -import { BaseFilterComponent } from './base-filter.component'; +import { DateFilter } from '../../models'; +import { BaseFilterComponent } from '../base-filter.component'; import { BehaviorSubject, combineLatest } from 'rxjs'; @Component({ - selector: 'ia-date-filter', - templateUrl: './date-filter.component.html', - styleUrls: ['./date-filter.component.scss'] + selector: 'ia-date-filter', + templateUrl: './date-filter.component.html', + styleUrls: ['./date-filter.component.scss'] }) export class DateFilterComponent extends BaseFilterComponent { public minDate: Date; @@ -25,7 +25,7 @@ export class DateFilterComponent extends BaseFilterComponent { this.selectedMaxDate = new BehaviorSubject(filter.currentData.max); combineLatest([this.selectedMinDate, this.selectedMaxDate]).subscribe(([min, max]) => - this.update({min, max}) + this.update({ min, max }) ); } diff --git a/frontend/src/app/filter/filter-box/filter-box.component.html b/frontend/src/app/filter/filter-box/filter-box.component.html new file mode 100644 index 000000000..391948020 --- /dev/null +++ b/frontend/src/app/filter/filter-box/filter-box.component.html @@ -0,0 +1,32 @@ +
+
+
+ +
+

+ + +

+
+ + + + + + + + + +
diff --git a/frontend/src/app/filter/filter-box/filter-box.component.scss b/frontend/src/app/filter/filter-box/filter-box.component.scss new file mode 100644 index 000000000..0af5fbc2b --- /dev/null +++ b/frontend/src/app/filter/filter-box/filter-box.component.scss @@ -0,0 +1,16 @@ +@import "../../../_utilities"; + +.filter-container{ + &:hover{ + box-shadow: 0 0 0 1px $primary; + } + margin-bottom: 5px; +} + +.filter-container.on{ + box-shadow: 0 0 0 2px $primary; +} + +.control { + z-index: 20; +} diff --git a/frontend/src/app/filter/filter-box/filter-box.component.spec.ts b/frontend/src/app/filter/filter-box/filter-box.component.spec.ts new file mode 100644 index 000000000..0ce114a32 --- /dev/null +++ b/frontend/src/app/filter/filter-box/filter-box.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { FilterBoxComponent } from './filter-box.component'; +import { commonTestBed } from '../../common-test-bed'; + +describe('FilterBoxComponent', () => { + let component: FilterBoxComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + commonTestBed().testingModule.compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(FilterBoxComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/filter/filter-box/filter-box.component.ts b/frontend/src/app/filter/filter-box/filter-box.component.ts new file mode 100644 index 000000000..b167fe63f --- /dev/null +++ b/frontend/src/app/filter/filter-box/filter-box.component.ts @@ -0,0 +1,13 @@ +import { Component, Input } from '@angular/core'; +import { QueryModel, SearchFilter } from '../../models'; + +@Component({ + selector: 'ia-filter-box', + templateUrl: './filter-box.component.html', + styleUrls: ['./filter-box.component.scss'] +}) +export class FilterBoxComponent { + @Input() filter: SearchFilter; + @Input() queryModel: QueryModel; + +} diff --git a/frontend/src/app/filter/filter-manager.component.html b/frontend/src/app/filter/filter-manager.component.html index e03cafafe..2f21c5d68 100644 --- a/frontend/src/app/filter/filter-manager.component.html +++ b/frontend/src/app/filter/filter-manager.component.html @@ -18,37 +18,8 @@

Filters

-
-
-
- -
-

- - -

-
- - - - - - - - - +
+
diff --git a/frontend/src/app/filter/filter-manager.component.scss b/frontend/src/app/filter/filter-manager.component.scss index 01749467a..e69de29bb 100644 --- a/frontend/src/app/filter/filter-manager.component.scss +++ b/frontend/src/app/filter/filter-manager.component.scss @@ -1,20 +0,0 @@ -@import "../../_utilities"; - -.filter-container{ - &:hover{ - box-shadow: 0 0 0 1px $primary; - } - margin-bottom: 5px; -} - -.filter-container.on{ - box-shadow: 0 0 0 2px $primary; -} - -.filter-icon { - border: none; -} - -.control { - z-index: 20; -} \ No newline at end of file diff --git a/frontend/src/app/filter/filter.module.ts b/frontend/src/app/filter/filter.module.ts index ee3f5771d..661a7e265 100644 --- a/frontend/src/app/filter/filter.module.ts +++ b/frontend/src/app/filter/filter.module.ts @@ -1,15 +1,16 @@ import { NgModule } from '@angular/core'; import { SharedModule } from '../shared/shared.module'; -import { AdHocFilterComponent } from './ad-hoc-filter.component'; -import { BooleanFilterComponent } from './boolean-filter.component'; -import { DateFilterComponent } from './date-filter.component'; +import { AdHocFilterComponent } from './ad-hoc-filter/ad-hoc-filter.component'; +import { BooleanFilterComponent } from './boolean-filter/boolean-filter.component'; +import { DateFilterComponent } from './date-filter/date-filter.component'; import { FilterManagerComponent } from './filter-manager.component'; -import { MultipleChoiceFilterComponent } from './multiple-choice-filter.component'; -import { RangeFilterComponent } from './range-filter.component'; +import { MultipleChoiceFilterComponent } from './multiple-choice-filter/multiple-choice-filter.component'; +import { RangeFilterComponent } from './range-filter/range-filter.component'; import { SearchService } from '../services'; import { SliderModule } from 'primeng/slider'; import { MultiSelectModule } from 'primeng/multiselect'; import { CheckboxModule } from 'primeng/checkbox'; +import { FilterBoxComponent } from './filter-box/filter-box.component'; @@ -25,6 +26,7 @@ import { CheckboxModule } from 'primeng/checkbox'; FilterManagerComponent, MultipleChoiceFilterComponent, RangeFilterComponent, + FilterBoxComponent, ], imports: [ CheckboxModule, diff --git a/frontend/src/app/filter/index.ts b/frontend/src/app/filter/index.ts index 069d8b8f0..96e458a6e 100644 --- a/frontend/src/app/filter/index.ts +++ b/frontend/src/app/filter/index.ts @@ -1,6 +1,6 @@ export * from './base-filter.component'; -export * from './boolean-filter.component'; -export * from './date-filter.component'; +export * from './boolean-filter/boolean-filter.component'; +export * from './date-filter/date-filter.component'; export * from './filter-manager.component'; -export * from './multiple-choice-filter.component'; -export * from './range-filter.component'; +export * from './multiple-choice-filter/multiple-choice-filter.component'; +export * from './range-filter/range-filter.component'; diff --git a/frontend/src/app/filter/multiple-choice-filter.component.spec.ts b/frontend/src/app/filter/multiple-choice-filter.component.spec.ts deleted file mode 100644 index cbaa3a0de..000000000 --- a/frontend/src/app/filter/multiple-choice-filter.component.spec.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { mockCorpus, mockFieldMultipleChoice } from '../../mock-data/corpus'; - -import { commonTestBed } from '../common-test-bed'; -import { MultipleChoiceFilter, QueryModel } from '../models'; - -import { MultipleChoiceFilterComponent } from './multiple-choice-filter.component'; -import * as _ from 'lodash'; - -describe('MultipleChoiceFilterComponent', () => { - let component: MultipleChoiceFilterComponent; - let fixture: ComponentFixture; - - beforeEach(waitForAsync(() => { - commonTestBed().testingModule.compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(MultipleChoiceFilterComponent); - component = fixture.componentInstance; - const corpus = _.cloneDeep(mockCorpus); - corpus.fields.push(mockFieldMultipleChoice); - component.queryModel = new QueryModel(corpus); - component.filter = component.queryModel.filterForField(mockFieldMultipleChoice) as MultipleChoiceFilter; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/frontend/src/app/filter/multiple-choice-filter.component.html b/frontend/src/app/filter/multiple-choice-filter/multiple-choice-filter.component.html similarity index 100% rename from frontend/src/app/filter/multiple-choice-filter.component.html rename to frontend/src/app/filter/multiple-choice-filter/multiple-choice-filter.component.html diff --git a/frontend/src/app/filter/multiple-choice-filter.component.scss b/frontend/src/app/filter/multiple-choice-filter/multiple-choice-filter.component.scss similarity index 92% rename from frontend/src/app/filter/multiple-choice-filter.component.scss rename to frontend/src/app/filter/multiple-choice-filter/multiple-choice-filter.component.scss index c5b6f5856..27fe9029f 100644 --- a/frontend/src/app/filter/multiple-choice-filter.component.scss +++ b/frontend/src/app/filter/multiple-choice-filter/multiple-choice-filter.component.scss @@ -1,4 +1,4 @@ -@import "../../_utilities"; +@import "../../../_utilities"; ::ng-deep .p-multiselect-panel { max-width: 300px; @@ -24,4 +24,4 @@ max-width: 180px; vertical-align: top; flex-grow: 2; -} \ No newline at end of file +} diff --git a/frontend/src/app/filter/multiple-choice-filter/multiple-choice-filter.component.spec.ts b/frontend/src/app/filter/multiple-choice-filter/multiple-choice-filter.component.spec.ts new file mode 100644 index 000000000..154cedf51 --- /dev/null +++ b/frontend/src/app/filter/multiple-choice-filter/multiple-choice-filter.component.spec.ts @@ -0,0 +1,31 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; +import { mockCorpus, mockFieldMultipleChoice } from '../../../mock-data/corpus'; + +import { commonTestBed } from '../../common-test-bed'; +import { MultipleChoiceFilter, QueryModel } from '../../models'; + +import { MultipleChoiceFilterComponent } from './multiple-choice-filter.component'; +import * as _ from 'lodash'; + +describe('MultipleChoiceFilterComponent', () => { + let component: MultipleChoiceFilterComponent; + let fixture: ComponentFixture; + + beforeEach(waitForAsync(() => { + commonTestBed().testingModule.compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(MultipleChoiceFilterComponent); + component = fixture.componentInstance; + const corpus = _.cloneDeep(mockCorpus); + corpus.fields.push(mockFieldMultipleChoice); + component.queryModel = new QueryModel(corpus); + component.filter = component.queryModel.filterForField(mockFieldMultipleChoice) as MultipleChoiceFilter; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/filter/multiple-choice-filter.component.ts b/frontend/src/app/filter/multiple-choice-filter/multiple-choice-filter.component.ts similarity index 77% rename from frontend/src/app/filter/multiple-choice-filter.component.ts rename to frontend/src/app/filter/multiple-choice-filter/multiple-choice-filter.component.ts index 4678628ec..8bea15441 100644 --- a/frontend/src/app/filter/multiple-choice-filter.component.ts +++ b/frontend/src/app/filter/multiple-choice-filter/multiple-choice-filter.component.ts @@ -2,14 +2,14 @@ import { Component } from '@angular/core'; import * as _ from 'lodash'; -import { BaseFilterComponent } from './base-filter.component'; -import { MultipleChoiceFilter, MultipleChoiceFilterOptions } from '../models'; -import { SearchService } from '../services'; +import { BaseFilterComponent } from '../base-filter.component'; +import { MultipleChoiceFilter, MultipleChoiceFilterOptions } from '../../models'; +import { SearchService } from '../../services'; @Component({ - selector: 'ia-multiple-choice-filter', - templateUrl: './multiple-choice-filter.component.html', - styleUrls: ['./multiple-choice-filter.component.scss'] + selector: 'ia-multiple-choice-filter', + templateUrl: './multiple-choice-filter.component.html', + styleUrls: ['./multiple-choice-filter.component.scss'] }) export class MultipleChoiceFilterComponent extends BaseFilterComponent { options: { label: string; value: string; doc_count: number }[] = []; @@ -29,7 +29,7 @@ export class MultipleChoiceFilterComponent extends BaseFilterComponent { if (this.filter && this.queryModel) { const optionCount = (this.filter.corpusField.filterOptions as MultipleChoiceFilterOptions).option_count; - const aggregator = {name: this.filter.corpusField.name, size: optionCount}; + const aggregator = { name: this.filter.corpusField.name, size: optionCount }; const queryModel = this.queryModel.clone(); queryModel.filterForField(this.filter.corpusField).deactivate(); this.searchService.aggregateSearch(queryModel.corpus, queryModel, [aggregator]).then( diff --git a/frontend/src/app/filter/range-filter.component.spec.ts b/frontend/src/app/filter/range-filter.component.spec.ts deleted file mode 100644 index 038f382dd..000000000 --- a/frontend/src/app/filter/range-filter.component.spec.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; - -import { commonTestBed } from '../common-test-bed'; - -import { RangeFilterComponent } from './range-filter.component'; -import { QueryModel, RangeFilter } from '../models'; -import { mockCorpus3, mockField3 } from '../../mock-data/corpus'; - -describe('RangeFilterComponent', () => { - let component: RangeFilterComponent; - let fixture: ComponentFixture; - - beforeEach(waitForAsync(() => { - commonTestBed().testingModule.compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(RangeFilterComponent); - component = fixture.componentInstance; - component.queryModel = new QueryModel(mockCorpus3); - component.filter = component.queryModel.filterForField(mockField3) as RangeFilter; - component.filter.set({min: 1984, max: 1984}); - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/frontend/src/app/filter/range-filter.component.html b/frontend/src/app/filter/range-filter/range-filter.component.html similarity index 100% rename from frontend/src/app/filter/range-filter.component.html rename to frontend/src/app/filter/range-filter/range-filter.component.html diff --git a/frontend/src/app/filter/range-filter.component.scss b/frontend/src/app/filter/range-filter/range-filter.component.scss similarity index 100% rename from frontend/src/app/filter/range-filter.component.scss rename to frontend/src/app/filter/range-filter/range-filter.component.scss diff --git a/frontend/src/app/filter/range-filter/range-filter.component.spec.ts b/frontend/src/app/filter/range-filter/range-filter.component.spec.ts new file mode 100644 index 000000000..098cfdc30 --- /dev/null +++ b/frontend/src/app/filter/range-filter/range-filter.component.spec.ts @@ -0,0 +1,29 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; + +import { commonTestBed } from '../../common-test-bed'; + +import { RangeFilterComponent } from './range-filter.component'; +import { QueryModel, RangeFilter } from '../../models'; +import { mockCorpus3, mockField3 } from '../../../mock-data/corpus'; + +describe('RangeFilterComponent', () => { + let component: RangeFilterComponent; + let fixture: ComponentFixture; + + beforeEach(waitForAsync(() => { + commonTestBed().testingModule.compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(RangeFilterComponent); + component = fixture.componentInstance; + component.queryModel = new QueryModel(mockCorpus3); + component.filter = component.queryModel.filterForField(mockField3) as RangeFilter; + component.filter.set({ min: 1984, max: 1984 }); + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/filter/range-filter.component.ts b/frontend/src/app/filter/range-filter/range-filter.component.ts similarity index 64% rename from frontend/src/app/filter/range-filter.component.ts rename to frontend/src/app/filter/range-filter/range-filter.component.ts index 061f7a10c..de01e0926 100644 --- a/frontend/src/app/filter/range-filter.component.ts +++ b/frontend/src/app/filter/range-filter/range-filter.component.ts @@ -1,12 +1,12 @@ import { Component } from '@angular/core'; -import { RangeFilterData, RangeFilter } from '../models'; -import { BaseFilterComponent } from './base-filter.component'; +import { RangeFilterData, RangeFilter } from '../../models'; +import { BaseFilterComponent } from '../base-filter.component'; @Component({ - selector: 'ia-range-filter', - templateUrl: './range-filter.component.html', - styleUrls: ['./range-filter.component.scss'] + selector: 'ia-range-filter', + templateUrl: './range-filter.component.html', + styleUrls: ['./range-filter.component.scss'] }) export class RangeFilterComponent extends BaseFilterComponent { min: number; diff --git a/frontend/src/app/models/query.spec.ts b/frontend/src/app/models/query.spec.ts index bb68a04ae..5e1464959 100644 --- a/frontend/src/app/models/query.spec.ts +++ b/frontend/src/app/models/query.spec.ts @@ -3,6 +3,8 @@ import { Corpus, } from './corpus'; import { QueryModel } from './query'; import { DateFilter, MultipleChoiceFilter, SearchFilter } from './field-filter'; import { convertToParamMap } from '@angular/router'; +import * as _ from 'lodash'; +import { paramsHaveChanged } from '../utils/params'; const corpus: Corpus = { name: 'mock-corpus', @@ -169,6 +171,24 @@ describe('QueryModel', () => { expect(newQuery.activeFilters.length).toBe(1); }); + it('should reflect the highlight state in parameters', () => { + const highlightParam = () => _.get(query.toRouteParam(), 'highlight'); + + expect(highlightParam()).toBe(null); + + query.setHighlight(200); + expect(highlightParam()).toBe(null); + + query.setQueryText('test'); + expect(highlightParam()).toBe('200'); + + query.setHighlight(400); + expect(highlightParam()).toBe('400'); + + query.setHighlight(); + expect(highlightParam()).toBe(null); + }); + it('should formulate a link', () => { query.setQueryText('test'); filter.setToValue(someDate); diff --git a/frontend/src/app/models/query.ts b/frontend/src/app/models/query.ts index 25f90f4a0..5188fc127 100644 --- a/frontend/src/app/models/query.ts +++ b/frontend/src/app/models/query.ts @@ -5,7 +5,7 @@ import { Corpus, CorpusField, EsFilter, SortBy, SortConfiguration, SortDirection import { EsQuery } from '../models'; import { combineSearchClauseAndFilters, makeHighlightSpecification } from '../utils/es-query'; import { - filtersFromParams, highlightFromParams, omitNullParameters, queryFiltersToParams, + filtersFromParams, highlightFromParams, highlightToParams, omitNullParameters, queryFiltersToParams, queryFromParams, searchFieldsFromParams } from '../utils/params'; import { SearchFilter } from './field-filter'; @@ -77,7 +77,6 @@ export class QueryModel { filters: SearchFilter[]; sort: SortConfiguration; highlightSize: number; - highlightSwitchedOff: boolean; update = new Subject(); @@ -95,6 +94,10 @@ export class QueryModel { return this.filters.filter(f => f.active.value); } + get highlightDisabled() { + return !this.queryText; + } + setQueryText(text?: string) { this.queryText = text || undefined; this.update.next(); @@ -134,11 +137,8 @@ export class QueryModel { ); } - setHighlight(size?: number, switchedOff?: boolean) { - this.highlightSize = size; - if (switchedOff) { - this.highlightSwitchedOff = true; - } + setHighlight(size?: number) { + this.highlightSize = size || undefined; this.update.next(); } @@ -160,7 +160,7 @@ export class QueryModel { const queryTextParams = { query: this.queryText || null }; const searchFieldsParams = { fields: this.searchFields?.map(f => f.name).join(',') || null}; const sortParams = this.sort.toRouteParam(); - const highlightParams = { highlight: this.highlightSize || null }; + const highlightParams = highlightToParams(this); const filterParams = queryFiltersToParams(this); return { diff --git a/frontend/src/app/search/highlight-selector.component.html b/frontend/src/app/search/highlight-selector.component.html index 8feb23f1d..4d149b929 100644 --- a/frontend/src/app/search/highlight-selector.component.html +++ b/frontend/src/app/search/highlight-selector.component.html @@ -5,22 +5,30 @@

Toggle highlights:

-
+
- -
-
diff --git a/frontend/src/app/search/highlight-selector.component.spec.ts b/frontend/src/app/search/highlight-selector.component.spec.ts index 82fd70d69..e047bf3fc 100644 --- a/frontend/src/app/search/highlight-selector.component.spec.ts +++ b/frontend/src/app/search/highlight-selector.component.spec.ts @@ -1,26 +1,61 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { mockCorpus2 } from '../../mock-data/corpus'; +import { mockCorpus, mockCorpus2 } from '../../mock-data/corpus'; import { commonTestBed } from '../common-test-bed'; import { QueryModel } from '../models'; import { HighlightSelectorComponent } from './highlight-selector.component'; +import { By } from '@angular/platform-browser'; +import { DebugElement } from '@angular/core'; describe('HighlightSelectorComponent', () => { - let component: HighlightSelectorComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - commonTestBed().testingModule.compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(HighlightSelectorComponent); - component = fixture.componentInstance; - component.queryModel = new QueryModel(mockCorpus2); - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); + let component: HighlightSelectorComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + commonTestBed().testingModule.compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(HighlightSelectorComponent); + component = fixture.componentInstance; + component.queryModel = new QueryModel(mockCorpus2); + fixture.detectChanges(); + }); + + beforeEach(() => { + component.queryModel = new QueryModel(mockCorpus); + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should reflect the query model state', () => { + const button = fixture.debugElement.query(By.css('.highlight-toggle')); + + const disabled = (el: DebugElement) => el.nativeElement.disabled; + const innerText = (el: DebugElement) => el.nativeElement.innerText; + + expect(disabled(button)).toBeTrue(); + expect(innerText(button)).toBe('OFF'); + + component.queryModel.queryText = 'test'; + fixture.detectChanges(); + + expect(disabled(button)).toBeFalse(); + expect(innerText(button)).toBe('OFF'); + + component.queryModel.setHighlight(200); + fixture.detectChanges(); + + expect(disabled(button)).toBeFalse(); + expect(innerText(button)).toBe('ON'); + + component.queryModel.queryText = undefined; + fixture.detectChanges(); + + expect(disabled(button)).toBeTrue(); + expect(innerText(button)).toBe('ON'); + }); }); diff --git a/frontend/src/app/search/highlight-selector.component.ts b/frontend/src/app/search/highlight-selector.component.ts index 611b80d7c..f6f4a5ed8 100644 --- a/frontend/src/app/search/highlight-selector.component.ts +++ b/frontend/src/app/search/highlight-selector.component.ts @@ -1,6 +1,5 @@ -import { Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core'; +import { Component, Input, OnDestroy } from '@angular/core'; import { QueryModel } from '../models'; -import { Subscription } from 'rxjs'; @Component({ @@ -8,44 +7,33 @@ import { Subscription } from 'rxjs'; templateUrl: './highlight-selector.component.html', styleUrls: ['./highlight-selector.component.scss'] }) -export class HighlightSelectorComponent implements OnChanges, OnDestroy, OnInit { +export class HighlightSelectorComponent implements OnDestroy { @Input() queryModel: QueryModel; - public highlight = 0; - private highlightSubscription: Subscription; constructor() { } - ngOnInit() { - this.highlightSubscription = this.queryModel.update.subscribe(() => { - this.setStateFromQueryModel(); - }); + get highlight(): number { + return this.queryModel?.highlightSize; } - ngOnChanges(changes: SimpleChanges): void { - if (this.queryModel) { - this.setStateFromQueryModel(); - } + get highlightDisabled(): boolean { + return this.queryModel?.highlightDisabled; } ngOnDestroy(): void { - this.queryModel.setHighlight(0, true); - this.highlightSubscription.unsubscribe(); - } - - setStateFromQueryModel() { - this.highlight = this.queryModel.highlightSize; + this.queryModel.setHighlight(); } updateHighlightSize(instruction?: string) { - if (instruction === 'on' && this.queryModel.highlightSize === 0) { + if (instruction === 'on' && !this.queryModel.highlightSize) { this.queryModel.setHighlight(200); } else if (instruction === 'more' && this.queryModel.highlightSize < 800) { this.queryModel.setHighlight(this.queryModel.highlightSize + 200); } else if (instruction === 'less' && this.queryModel.highlightSize > 200) { this.queryModel.setHighlight(this.queryModel.highlightSize - 200); } else if (instruction === 'off') { - this.queryModel.setHighlight(0, true); + this.queryModel.setHighlight(); } } diff --git a/frontend/src/app/search/search.component.ts b/frontend/src/app/search/search.component.ts index 9f44e00c1..80d377c1d 100644 --- a/frontend/src/app/search/search.component.ts +++ b/frontend/src/app/search/search.component.ts @@ -150,19 +150,7 @@ export class SearchComponent extends ParamDirective { this.queryText = queryModel.queryText; this.queryModel.update.subscribe(() => { this.queryText = this.queryModel.queryText; - this.checkHighlight(); this.setParams(this.queryModel.toRouteParam()); }); } - /** - * This method checks whether the highlighter needs to be turned on or off - * If the user has disabled the highlighter, it will not turn on by default - */ - public checkHighlight() { - if (!this.queryModel.queryText) { - this.queryModel.highlightSize = null; - } else if (!this.queryModel.highlightSize && !this.queryModel.highlightSwitchedOff) { - this.queryModel.highlightSize = 200; - } - } } diff --git a/frontend/src/app/utils/params.spec.ts b/frontend/src/app/utils/params.spec.ts index d5b519622..9d7dd93da 100644 --- a/frontend/src/app/utils/params.spec.ts +++ b/frontend/src/app/utils/params.spec.ts @@ -70,4 +70,24 @@ describe('paramsHaveChanged', () => { expect(paramsHaveChanged(queryModel, params)).toBeTrue(); }); + + it('should detect changes in highlighting', () => { + queryModel.setQueryText('test'); + + const noHighlight = convertToParamMap({ query: 'test' }); + const withHighlight = convertToParamMap({ query: 'test', highlight: '200' }); + + expect(paramsHaveChanged(queryModel, noHighlight)).toBeFalse(); + expect(paramsHaveChanged(queryModel, withHighlight)).toBeTrue(); + + queryModel.setHighlight(200); + + expect(paramsHaveChanged(queryModel, noHighlight)).toBeTrue(); + expect(paramsHaveChanged(queryModel, withHighlight)).toBeFalse(); + + queryModel.setHighlight(); + + expect(paramsHaveChanged(queryModel, noHighlight)).toBeFalse(); + expect(paramsHaveChanged(queryModel, withHighlight)).toBeTrue(); + }); }); diff --git a/frontend/src/app/utils/params.ts b/frontend/src/app/utils/params.ts index 5e2491ecf..3bf62a9dd 100644 --- a/frontend/src/app/utils/params.ts +++ b/frontend/src/app/utils/params.ts @@ -18,6 +18,16 @@ export const searchFieldsFromParams = (params: ParamMap, corpus: Corpus): Corpus } }; +// highlight + +export const highlightToParams = (queryModel: QueryModel): { highlight: string | null } => { + if (queryModel.highlightDisabled || !queryModel.highlightSize) { + return { highlight: null }; + } + + return { highlight: queryModel.highlightSize.toString() }; +}; + export const highlightFromParams = (params: ParamMap): number => Number(params.get('highlight'));