-
Notifications
You must be signed in to change notification settings - Fork 261
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* [ACS-5181] Add logical search component * [ACS-5181] Add unit tests to logical search components * [ACS-5181] Logical filter components docs * [ACS-5181] CR fixes * [ACS-5181] CR and accessibility fixes
- Loading branch information
1 parent
9845b1e
commit 85fd988
Showing
18 changed files
with
756 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
49 changes: 49 additions & 0 deletions
49
docs/content-services/components/search-chip-input.component.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
--- | ||
Title: Search Chip Input component | ||
Added: v6.1.0 | ||
Status: Active | ||
Last reviewed: 2023-06-01 | ||
--- | ||
|
||
# [Search Chip Input component](../../../lib/content-services/src/lib/search/components/search-chip-input/search-chip-input.component.ts "Defined in search-chip-input.component.ts") | ||
|
||
Represents an input with stacked list of chips as phrases added through input. | ||
|
||
![Search Chip Input](../../docassets/images/search-chip-input.png) | ||
|
||
## Basic usage | ||
|
||
```html | ||
<adf-search-chip-input | ||
[label]="'Some label'" | ||
[onReset]="onResetObservable" | ||
(phrasesChanged)="handlePhraseChanged($event)"> | ||
</adf-search-chip-input> | ||
``` | ||
|
||
### Properties | ||
|
||
| Name | Type | Default value | Description | | ||
| ---- | ---- | ------------- | ----------- | | ||
| label | `string` | | Label that will be associated with the input | | ||
| addOnBlur | `boolean` | true | Specifies whether new phrase will be added when input blurs | | ||
| onReset | [`Observable`](https://rxjs.dev/guide/observable)`<void>` | | Observable that will listen to any reset event causing component to clear the chips and input | | ||
|
||
### Events | ||
|
||
| Name | Type | Description | | ||
| ---- | ---- | ----------- | | ||
| phrasesChanged | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<string[]>` | Emitted when new phrase is entered | | ||
|
||
## See also | ||
|
||
- [Search Configuration Guide](../../user-guide/search-configuration-guide.md) | ||
- [Search Query Builder service](../services/search-query-builder.service.md) | ||
- [Search Widget Interface](../interfaces/search-widget.interface.md) | ||
- [Search Logical Filter component](search-logical-filter.component.md) | ||
- [Search check list component](search-check-list.component.md) | ||
- [Search date range component](search-date-range.component.md) | ||
- [Search number range component](search-number-range.component.md) | ||
- [Search radio component](search-radio.component.md) | ||
- [Search slider component](search-slider.component.md) | ||
- [Search text component](search-text.component.md) |
61 changes: 61 additions & 0 deletions
61
docs/content-services/components/search-logical-filter.component.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
--- | ||
Title: Search Logical Filter component | ||
Added: v6.1.0 | ||
Status: Active | ||
Last reviewed: 2023-06-01 | ||
--- | ||
|
||
# [Search Logical Filter component](../../../lib/content-services/src/lib/search/components/search-logical-filter/search-logical-filter.component.ts "Defined in search-logical-filter.component.ts") | ||
|
||
Implements a [search widget](../../../lib/content-services/src/lib/search/models/search-widget.interface.ts) consisting of 3 chip inputs representing logical conditions to form search query from. | ||
|
||
![Search Logical Filter](../../docassets/images/search-logical-filter.png) | ||
|
||
## Basic usage | ||
|
||
```json | ||
{ | ||
"search": { | ||
"categories": [ | ||
{ | ||
"id": "logic", | ||
"name": "Logic", | ||
"enabled": true, | ||
"component": { | ||
"selector": "logical-filter", | ||
"settings": { | ||
"allowUpdateOnChange": false, | ||
"hideDefaultAction": true, | ||
"field": "cm:name,cm:title,TEXT" | ||
} | ||
} | ||
} | ||
] | ||
} | ||
} | ||
``` | ||
|
||
### Settings | ||
|
||
| Name | Type | Description | | ||
| ---- | ---- | ----------- | | ||
| field | string | Field/fields to apply the query to. Required value | | ||
| hideDefaultAction | boolean | Show/hide the [widget](../../../lib/testing/src/lib/protractor/core/pages/form/widgets/widget.ts) actions. By default is false. | | ||
|
||
## Details | ||
|
||
This component lets the user provide logical conditions to apply to each `field` in the search query. | ||
See the [Search chip input component](search-chip-input.component.md) for full details of how to use chip inputs. | ||
|
||
## See also | ||
|
||
- [Search Configuration Guide](../../user-guide/search-configuration-guide.md) | ||
- [Search Query Builder service](../services/search-query-builder.service.md) | ||
- [Search Widget Interface](../interfaces/search-widget.interface.md) | ||
- [Search Chip Input component](search-chip-input.component.md) | ||
- [Search check list component](search-check-list.component.md) | ||
- [Search date range component](search-date-range.component.md) | ||
- [Search number range component](search-number-range.component.md) | ||
- [Search radio component](search-radio.component.md) | ||
- [Search slider component](search-slider.component.md) | ||
- [Search text component](search-text.component.md) |
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 15 additions & 0 deletions
15
...ent-services/src/lib/search/components/search-chip-input/search-chip-input.component.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<mat-label>{{label | translate}}</mat-label> | ||
<mat-chip-list #chipList [attr.aria-label]="label | translate"> | ||
<mat-chip *ngFor="let phrase of phrases; let i = index" (removed)="removePhrase(i)"> | ||
<span>{{phrase}}</span> | ||
<button matChipRemove [attr.aria-label]="('SEARCH.FILTER.BUTTONS.REMOVE' | translate) + ' ' + phrase"> | ||
<mat-icon>cancel</mat-icon> | ||
</button> | ||
</mat-chip> | ||
<input placeholder="{{ 'SEARCH.LOGICAL_SEARCH.SEARCH_CHIP_INPUT.ADD_PHRASE' | translate }}" | ||
[attr.aria-label]="'SEARCH.LOGICAL_SEARCH.SEARCH_CHIP_INPUT.ADD_PHRASE' | translate" | ||
[matChipInputFor]="chipList" | ||
[matChipInputSeparatorKeyCodes]="separatorKeysCodes" | ||
[matChipInputAddOnBlur]="addOnBlur" | ||
(matChipInputTokenEnd)="addPhrase($event)" /> | ||
</mat-chip-list> |
18 changes: 18 additions & 0 deletions
18
...ent-services/src/lib/search/components/search-chip-input/search-chip-input.component.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
.adf-search-chip-input { | ||
padding-bottom: 15px; | ||
|
||
.mat-chip-list-wrapper { | ||
border: 1px solid var(--adf-theme-mat-grey-color-a400); | ||
border-radius: 5px; | ||
margin-top: 5px; | ||
|
||
.mat-chip { | ||
word-break: break-all; | ||
height: unset; | ||
} | ||
|
||
input { | ||
height: 25px; | ||
} | ||
} | ||
} |
161 changes: 161 additions & 0 deletions
161
...-services/src/lib/search/components/search-chip-input/search-chip-input.component.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
/*! | ||
* @license | ||
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
import { ComponentFixture, TestBed } from '@angular/core/testing'; | ||
import { MatChip, MatChipRemove } from '@angular/material/chips'; | ||
import { By } from '@angular/platform-browser'; | ||
import { TranslateModule } from '@ngx-translate/core'; | ||
import { Subject } from 'rxjs'; | ||
import { ContentTestingModule } from '../../../testing/content.testing.module'; | ||
import { SearchChipInputComponent } from './search-chip-input.component'; | ||
|
||
describe('SearchChipInputComponent', () => { | ||
let component: SearchChipInputComponent; | ||
let fixture: ComponentFixture<SearchChipInputComponent>; | ||
const onResetSubject = new Subject<void>(); | ||
|
||
beforeEach(() => { | ||
TestBed.configureTestingModule({ | ||
declarations: [SearchChipInputComponent], | ||
imports: [ | ||
TranslateModule.forRoot(), | ||
ContentTestingModule | ||
] | ||
}); | ||
|
||
fixture = TestBed.createComponent(SearchChipInputComponent); | ||
component = fixture.componentInstance; | ||
component.onReset = onResetSubject.asObservable(); | ||
fixture.detectChanges(); | ||
}); | ||
|
||
afterEach(() => removeAllChips()); | ||
|
||
function getChipInput(): HTMLInputElement { | ||
return fixture.debugElement.query(By.css('input')).nativeElement; | ||
} | ||
|
||
function getChipList(): MatChip[] { | ||
return fixture.debugElement.queryAll(By.css('mat-chip')).map((chip) => chip.nativeElement); | ||
} | ||
|
||
function getChipValue(index: number): string { | ||
return fixture.debugElement.queryAll(By.css('mat-chip span')).map((chip) => chip.nativeElement)[index].innerText; | ||
} | ||
|
||
function enterNewChip(value: string) { | ||
const input = getChipInput(); | ||
input.value = value; | ||
fixture.detectChanges(); | ||
input.dispatchEvent(new KeyboardEvent('keydown', {keyCode: 13})); | ||
fixture.detectChanges(); | ||
} | ||
|
||
function removeAllChips() { | ||
const chips = getChipList(); | ||
if (!!chips && chips.length > 0) { | ||
chips.forEach((chip) => chip.remove()); | ||
} | ||
} | ||
|
||
function removeChip(index: number) { | ||
const removeBtns = fixture.debugElement.queryAll(By.directive(MatChipRemove)).map((removeBtn) => removeBtn.nativeElement); | ||
removeBtns[index].click(); | ||
fixture.detectChanges(); | ||
} | ||
|
||
it('should display label provided as component input', () => { | ||
const label = 'Test'; | ||
component.label = label; | ||
fixture.detectChanges(); | ||
const matLabel = fixture.debugElement.query(By.css('mat-label')).nativeElement.innerText; | ||
expect(matLabel).toBe(label); | ||
}); | ||
|
||
it('should display proper placeholder for chip input', () => { | ||
const input = getChipInput(); | ||
expect(input.placeholder).toBe('SEARCH.LOGICAL_SEARCH.SEARCH_CHIP_INPUT.ADD_PHRASE'); | ||
}); | ||
|
||
it('should not display any chips initially', () => { | ||
const chips = getChipList(); | ||
expect(chips).toEqual([]); | ||
}); | ||
|
||
it('should add new chip when input has value and enter was hit', () => { | ||
const phrasesChangedSpy = spyOn(component.phrasesChanged, 'emit'); | ||
enterNewChip('test'); | ||
expect(phrasesChangedSpy).toHaveBeenCalledOnceWith(['test']); | ||
expect(getChipList().length).toBe(1); | ||
expect(getChipValue(0)).toBe('test'); | ||
}); | ||
|
||
it('should add input value as whole phrase even if it contains whitespaces and special signs', () => { | ||
const phrase = 'test another world &*,.;""!@#$$%^*()[]-+='; | ||
enterNewChip(phrase); | ||
expect(getChipList().length).toBe(1); | ||
expect(getChipValue(0)).toBe(phrase); | ||
}); | ||
|
||
it('should add new chip when input is blurred', () => { | ||
const input = getChipInput(); | ||
input.value = 'test'; | ||
fixture.detectChanges(); | ||
input.dispatchEvent(new InputEvent('blur')); | ||
fixture.detectChanges(); | ||
expect(input.value).toBe(''); | ||
expect(getChipList().length).toBe(1); | ||
expect(getChipValue(0)).toBe('test'); | ||
}); | ||
|
||
it('should not add new chip when input is blurred if addOnBlur is false', () => { | ||
component.addOnBlur = false; | ||
const input = getChipInput(); | ||
input.value = 'test'; | ||
fixture.detectChanges(); | ||
input.dispatchEvent(new InputEvent('blur')); | ||
fixture.detectChanges(); | ||
expect(input.value).toBe('test'); | ||
expect(getChipList().length).toBe(0); | ||
}); | ||
|
||
it('should clear the input after new chip is added', () => { | ||
const input = getChipInput(); | ||
enterNewChip('test2'); | ||
expect(input.value).toBe(''); | ||
}); | ||
|
||
it('should reset all chips when onReset event is emitted', () => { | ||
enterNewChip('test1'); | ||
enterNewChip('test2'); | ||
enterNewChip('test3'); | ||
const phrasesChangedSpy = spyOn(component.phrasesChanged, 'emit'); | ||
onResetSubject.next(); | ||
fixture.detectChanges(); | ||
expect(phrasesChangedSpy).toHaveBeenCalledOnceWith([]); | ||
expect(getChipList()).toEqual([]); | ||
}); | ||
|
||
it('should remove chip upon clicking remove button', () => { | ||
enterNewChip('test1'); | ||
enterNewChip('test2'); | ||
const phrasesChangedSpy = spyOn(component.phrasesChanged, 'emit'); | ||
removeChip(0); | ||
expect(phrasesChangedSpy).toHaveBeenCalledOnceWith(['test2']); | ||
expect(getChipList().length).toEqual(1); | ||
}); | ||
}); |
Oops, something went wrong.