diff --git a/client/src/app/data-types.ts b/client/src/app/data-types.ts index 1d416038e..f042ca683 100644 --- a/client/src/app/data-types.ts +++ b/client/src/app/data-types.ts @@ -369,6 +369,11 @@ export namespace Model { addresses: Address[]; local_name: Name; remote_name: Name; + credential_type: CredentialType; + credential_set: CredentialSet; + effective_date: string; + inactive: boolean; + revoked: boolean; static resourceName = "topic"; @@ -498,6 +503,11 @@ export namespace Model { return ["/topic", this.type, this.source_id]; } + get issuer(): Issuer { + return this.credential_type && this.credential_type.issuer; + } + set issuer(val: Issuer) {} + extLink(...args): string[] { return this.link.concat(args); } @@ -515,12 +525,12 @@ export namespace Model { static childResource = "related_to"; } - export class TopicSearchResult extends Credential { - static resourceName = "v3/search/topic"; + export class TopicSearchResult extends Topic { + static resourceName = "v4/search/topic"; } - export class TopicFacetSearchResult extends Credential { - static resourceName = "v3/search/topic/facets"; + export class TopicFacetSearchResult extends Topic { + static resourceName = "v4/search/topic/facets"; } export class TopicRelationship extends BaseModel { diff --git a/client/src/app/general-data.service.ts b/client/src/app/general-data.service.ts index 613d8cf08..b5006f228 100644 --- a/client/src/app/general-data.service.ts +++ b/client/src/app/general-data.service.ts @@ -2,7 +2,7 @@ import { HttpClient, HttpParams } from '@angular/common/http'; import { Inject, Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; -import { BehaviorSubject, from, Observable, Observer, of, Subscription , throwError as _throw } from 'rxjs'; +import { BehaviorSubject, from, Observable, Observer, of, Subscription, throwError as _throw } from 'rxjs'; import { catchError, map, mergeMap, shareReplay } from 'rxjs/operators'; import { Fetch, Filter, Model } from './data-types'; @@ -148,27 +148,14 @@ export class GeneralDataService { return from([]); } let params = new HttpParams().set('q', term).append('inactive', inactive.toString()); - - return this.loadFromApi('search/autocomplete', params).pipe( - map(response => { - let ret = []; - for (let row of response['results']) { - let found = null; - for (let name of row.names) { - if (~name.text.toLowerCase().indexOf(term.toLowerCase())) { - found = name.text; - break; - } else if (found === null) { - found = name.text; - } - } - if (found !== null) { - ret.push({ id: row.id, term: found }); - } - } - return ret; - }), - ); + return this.loadFromApi('v3/search/autocomplete', params) + .pipe( + map(({ results }: { results? }) => results || []), + map(results => results.map(row => ({ + id: row.id, + term: row.value + }))) + ); } makeHttpParams(query?: { [key: string]: string } | HttpParams) { @@ -270,6 +257,8 @@ export class GeneralDataService { count: optitem.count, }; } + } else if (optname === 'credential_type_id') { + optval.label = this._translate.instant(`name.${optval.label}`) } if (optidx in options) { options[optidx].push(optval); diff --git a/client/src/app/search/advanced-search.component.ts b/client/src/app/search/advanced-search.component.ts index 4378dfd39..65c344b04 100644 --- a/client/src/app/search/advanced-search.component.ts +++ b/client/src/app/search/advanced-search.component.ts @@ -14,7 +14,8 @@ export interface IAdvancedSearchOption { const FilterSpec = [ { - name: "name", + name: "q", + alias: "query", hidden: true }, { @@ -26,7 +27,7 @@ const FilterSpec = [ label: "cred.issuer" }, { - name: "topic_credential_type_id", + name: "credential_type_id", label: "cred.cred-type" }, { @@ -43,7 +44,7 @@ const FilterSpec = [ options: [ { tlabel: "general.show-inactive", - value: "true" + value: "any" } ], defval: "false", @@ -77,7 +78,8 @@ export class AdvancedSearchComponent implements OnInit, OnDestroy { credentialTypeOptions$: Observable; yesNoOptions: ISelectOption[] = [ - { value: 'true', description: 'Yes' } + { value: 'false', description: 'No' }, + { value: 'any', description: 'Yes' } ]; /* TODO: Parameterize these to include a method of defining the input option */ @@ -87,9 +89,6 @@ export class AdvancedSearchComponent implements OnInit, OnDestroy { { label: 'historical credentials', helper: 'Include results that have expired or are no longer active.' }, ]; - yesNoSelected: ISelectOption = { value: 'false', description: 'No' } - credentialTypeSelected: ISelectOption = { value: '', description: 'any' }; - fg: FormGroup = new FormGroup({ text: new FormControl(''), type: new FormControl(''), @@ -121,6 +120,15 @@ export class AdvancedSearchComponent implements OnInit, OnDestroy { return parseInt(this._currentPage, 10); } + private get _queryParams(): { text: string, type: string, archived: string } { + const queryParamMap: any = this.route.snapshot.queryParamMap; + const queryParams: any = this.route.snapshot.queryParams; + const q = queryParamMap.get('q') || queryParamMap.get('query') || ''; + const credential_type_id = queryParamMap.get('credential_type_id') || ''; + const inactive = queryParamMap.get('inactive') || 'false'; + return { ...queryParams, q, credential_type_id, inactive }; + } + get filters(): Filter.FieldSet { return this._filters; } @@ -139,7 +147,11 @@ export class AdvancedSearchComponent implements OnInit, OnDestroy { map(res => res.data.map(type => ({ value: type.id, description: type.description - }))) + }))), + map(credentialTypeOptions => [ + { value: '', description: 'any' }, + ...credentialTypeOptions + ]) ); this.credentials$ = this._cLoader.stream @@ -176,17 +188,13 @@ export class AdvancedSearchComponent implements OnInit, OnDestroy { } private patchForm(): void { - const queryParamMap: any = this.route.snapshot.queryParamMap; - this.fg.patchValue({ - text: queryParamMap.get('name') || '', - type: queryParamMap.get('topic_credential_type_id') || '', - archived: queryParamMap.get('inactive') || 'false' - }); + const { q: text, credential_type_id: type, inactive: archived }: any = this._queryParams; + this.fg.patchValue({ text, type, archived }); } private updateFilters(): void { - const { text: name, archived: inactive, type: topic_credential_type_id } = this.fg.value; - this._filters.update({ name, inactive, topic_credential_type_id, page: this._currentPage }); + const { text: q, archived: inactive, type: credential_type_id } = this.fg.value; + this._filters.update({ ...this._queryParams, q, inactive, credential_type_id, page: this._currentPage }); } private updateUrl() { diff --git a/client/src/app/search/form.component.ts b/client/src/app/search/form.component.ts index d824f8a4b..791cfba8b 100644 --- a/client/src/app/search/form.component.ts +++ b/client/src/app/search/form.component.ts @@ -9,7 +9,7 @@ import { Subscription } from 'rxjs'; const FilterSpec = [ { - name: "name", + name: "q", alias: "query", hidden: true }, @@ -22,10 +22,6 @@ const FilterSpec = [ name: "issuer_id", label: "cred.issuer" }, - { - name: "topic_credential_type_id", - label: "cred.cred-type" - }, { name: "category:entity_type", label: "attribute.entity_type" @@ -36,26 +32,12 @@ const FilterSpec = [ options: [ { tlabel: "general.show-inactive", - value: "" - } - ], - defval: "false", - blank: true - } - /* - { - name: "revoked", - label: "cred.status", - options: [ - { - tlabel: "general.show-revoked", - value: "" + value: "any" } ], defval: "false", blank: true } - */ ]; @Component({ @@ -131,7 +113,7 @@ export class SearchComponent implements OnInit, OnDestroy, AfterViewInit { ngAfterViewInit() { if(this._searchInput) { - this._searchInput.value = this._filters.getFieldValue('name'); + this._searchInput.value = this._filters.getFieldValue('q'); } } @@ -198,7 +180,7 @@ export class SearchComponent implements OnInit, OnDestroy, AfterViewInit { this._loader.reset(); this._refresh = true; this._filters.update({ - name: this._searchInput.value, + q: this._searchInput.value, page: '1' }); } @@ -206,18 +188,18 @@ export class SearchComponent implements OnInit, OnDestroy, AfterViewInit { public initSearch() { if(this._searchInput) - this._searchInput.value = this._filters.getFieldValue('name'); + this._searchInput.value = this._filters.getFieldValue('q'); this._inited = true; this._performSearch(); } get blankQuery() { - return this._filters.getFieldValue('name') === ''; + return this._filters.getFieldValue('q') === ''; } _performSearch() { let query = this._filters.values; - if('name' in query && query['name'] !== '') { + if('q' in query && query['q'] !== '') { this._dataService.loadList(this._loader, {query}); } else { this._loader.reset(); diff --git a/client/src/app/search/input.component.ts b/client/src/app/search/input.component.ts index 6bc1a607b..56554805d 100644 --- a/client/src/app/search/input.component.ts +++ b/client/src/app/search/input.component.ts @@ -1,10 +1,10 @@ import { Component, AfterViewInit, ElementRef, EventEmitter, Input, Output, Renderer2, ViewChild } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; import { Observable } from 'rxjs'; -import { catchError, debounceTime, distinctUntilChanged, map, tap, switchMap } from 'rxjs/operators'; +import { debounceTime, distinctUntilChanged, map, switchMap } from 'rxjs/operators'; import { GeneralDataService } from 'app/general-data.service'; import { HttpService } from 'app/core/services/http.service'; import { ICredentialTypeResult } from 'app/core/interfaces/icredential-type-results.interface'; -import { Router } from '@angular/router'; import { AppConfigService } from 'app/app-config.service'; export interface ICredentialTypeOption { @@ -86,9 +86,10 @@ export class SearchInputComponent implements AfterViewInit { private _renderer: Renderer2, private _dataService: GeneralDataService, private httpSvc: HttpService, + private route: ActivatedRoute, private router: Router, private configSvc: AppConfigService, - ) {} + ) { } async ngOnInit() { const $categories = this.httpSvc @@ -185,10 +186,11 @@ export class SearchInputComponent implements AfterViewInit { } advancedSearch() { + const queryParams = this.route.snapshot.queryParams; const query = this._input.nativeElement.value; const lang = this._dataService.language; const nav = `/${lang}/advanced-search`; - query ? this.router.navigate([nav], { queryParams: { name: query } }) : this.router.navigate([nav]); + this.router.navigate([nav], { queryParams: { ...queryParams, query: query } }); } } diff --git a/client/src/app/shared/components/select/select.component.ts b/client/src/app/shared/components/select/select.component.ts index 4418dceb6..d06ca1894 100644 --- a/client/src/app/shared/components/select/select.component.ts +++ b/client/src/app/shared/components/select/select.component.ts @@ -1,6 +1,6 @@ -import { Component, OnInit, Input, forwardRef } from '@angular/core'; -import { LangChangeEvent, TranslateService } from '@ngx-translate/core'; -import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { Component, Input, forwardRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR } from '@angular/forms'; export interface ISelectOption { value: string | boolean | number; @@ -19,36 +19,34 @@ export interface ISelectOption { }, ], }) -export class SelectComponent implements OnInit, ControlValueAccessor { +export class SelectComponent implements ControlValueAccessor { + select = new FormControl(''); + @Input() options: ISelectOption[]; - @Input() selected: ISelectOption; @Input() translateSelector: string; - value: any; - disabled: boolean; - onChange: (any) => void; onTouch: (any) => void; - writeValue(obj: any): void { - this.value = obj; + constructor(public translate: TranslateService) { } + + writeValue(value: any): void { + value && this.select.setValue(value); } + registerOnChange(fn: any): void { - this.onChange = fn; + this.select.valueChanges.subscribe(fn); } + registerOnTouched(fn: any): void { this.onTouch = fn; } + setDisabledState?(isDisabled: boolean): void { - this.disabled = isDisabled; + isDisabled ? this.select.disable() : this.select.enable(); } - constructor(public translate: TranslateService) { } - - ngOnInit() { } - changeEvent(value: string) { - this.value = value; - this.onChange(value); + this.select.setValue(value); this.onTouch(value); } } diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts index 040f23b6e..0dc280da9 100644 --- a/client/src/app/shared/shared.module.ts +++ b/client/src/app/shared/shared.module.ts @@ -1,12 +1,18 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { TranslateModule } from '@ngx-translate/core'; import { CheckboxComponent } from './components/checkbox/checkbox.component'; import { SelectComponent } from './components/select/select.component'; -import { TranslateModule } from '@ngx-translate/core'; @NgModule({ - imports: [CommonModule, TranslateModule.forChild()], + imports: [ + CommonModule, + FormsModule, + ReactiveFormsModule, + TranslateModule.forChild() + ], declarations: [CheckboxComponent, SelectComponent], exports: [CheckboxComponent, SelectComponent], }) -export class SharedModule {} +export class SharedModule { } diff --git a/client/themes/base/cred/list.component.html b/client/themes/base/cred/list.component.html index 19be9b7eb..5de9f47b9 100644 --- a/client/themes/base/cred/list.component.html +++ b/client/themes/base/cred/list.component.html @@ -1,3 +1,4 @@ +
@@ -5,7 +6,8 @@

- {{cred.credential_type.description}} + {{cred.credential_type.description}}

{{cred.effective_date | dateFormat: 'effectiveDate'}} @@ -20,11 +22,13 @@

+
{{cred.effective_date | dateFormat: 'effectiveDate'}} @@ -41,12 +45,12 @@
+ +
\ No newline at end of file diff --git a/client/themes/base/search/advanced-search.component.html b/client/themes/base/search/advanced-search.component.html index 7df43341f..cd76f7b93 100644 --- a/client/themes/base/search/advanced-search.component.html +++ b/client/themes/base/search/advanced-search.component.html @@ -12,10 +12,10 @@

What this search type does

- + - +
- Advanced Search -
+ Advanced Search + \ No newline at end of file diff --git a/client/themes/base/shared/select.component.html b/client/themes/base/shared/select.component.html index 95016ebda..46b3e101b 100644 --- a/client/themes/base/shared/select.component.html +++ b/client/themes/base/shared/select.component.html @@ -1,13 +1,5 @@ - -