From f79de3d7dd40de9452213842f7fc9940498e0e37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Barbeau?= Date: Tue, 13 Aug 2019 17:01:10 -0400 Subject: [PATCH 01/18] fix(*): minors bugs --- packages/geo/src/lib/layer/layer-list/layer-list.component.ts | 4 ++-- .../directions/directions-tool/directions-tool.component.html | 2 +- .../search-results-tool/search-results-tool.component.html | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/geo/src/lib/layer/layer-list/layer-list.component.ts b/packages/geo/src/lib/layer/layer-list/layer-list.component.ts index 4a114cbc08..ff638d1a54 100644 --- a/packages/geo/src/lib/layer/layer-list/layer-list.component.ts +++ b/packages/geo/src/lib/layer/layer-list/layer-list.component.ts @@ -145,13 +145,13 @@ export class LayerListComponent implements OnInit, OnDestroy { getLowerLayer() { return this.layers.filter(l => !l.baseLayer).reduce((prev, current) => { return (prev.zIndex < current.zIndex) ? prev : current; - }); + }, { zIndex: undefined }); } getUpperLayer() { return this.layers.filter(l => !l.baseLayer).reduce((prev, current) => { return (prev.zIndex > current.zIndex) ? prev : current; - }); + }, { zIndex: undefined }); } private next() { diff --git a/packages/integration/src/lib/directions/directions-tool/directions-tool.component.html b/packages/integration/src/lib/directions/directions-tool/directions-tool.component.html index 6fe918136a..995e95ed95 100644 --- a/packages/integration/src/lib/directions/directions-tool/directions-tool.component.html +++ b/packages/integration/src/lib/directions/directions-tool/directions-tool.component.html @@ -1 +1 @@ - + diff --git a/packages/integration/src/lib/search/search-results-tool/search-results-tool.component.html b/packages/integration/src/lib/search/search-results-tool/search-results-tool.component.html index 756c305411..ceb9deba64 100644 --- a/packages/integration/src/lib/search/search-results-tool/search-results-tool.component.html +++ b/packages/integration/src/lib/search/search-results-tool/search-results-tool.component.html @@ -3,7 +3,9 @@ initial="100%" initialMobile="100%" collapsed="60%" + collapsedMobile="60%" expanded="calc(100% - 58px)" + expandedMobile="calc(100% - 58px)" [state]="topPanelState">
From 7c801fef8927cf81365f3c0fd11819b2181ed214 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Barbeau?= Date: Wed, 14 Aug 2019 09:53:38 -0400 Subject: [PATCH 02/18] fix(layer-list): id missing --- packages/geo/src/lib/layer/layer-list/layer-list.component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/geo/src/lib/layer/layer-list/layer-list.component.ts b/packages/geo/src/lib/layer/layer-list/layer-list.component.ts index ff638d1a54..d13956f8a3 100644 --- a/packages/geo/src/lib/layer/layer-list/layer-list.component.ts +++ b/packages/geo/src/lib/layer/layer-list/layer-list.component.ts @@ -145,13 +145,13 @@ export class LayerListComponent implements OnInit, OnDestroy { getLowerLayer() { return this.layers.filter(l => !l.baseLayer).reduce((prev, current) => { return (prev.zIndex < current.zIndex) ? prev : current; - }, { zIndex: undefined }); + }, { zIndex: undefined, id: undefined }); } getUpperLayer() { return this.layers.filter(l => !l.baseLayer).reduce((prev, current) => { return (prev.zIndex > current.zIndex) ? prev : current; - }, { zIndex: undefined }); + }, { zIndex: undefined, id: undefined }); } private next() { From ecf80c83d8fc9ddec8cb46a8d718be073135eed2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Barbeau?= Date: Wed, 14 Aug 2019 11:04:08 -0400 Subject: [PATCH 03/18] fix(context-list): dectect change --- .../lib/context-manager/context-list/context-list.component.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/context/src/lib/context-manager/context-list/context-list.component.ts b/packages/context/src/lib/context-manager/context-list/context-list.component.ts index ff1deac422..0ae4e7b946 100644 --- a/packages/context/src/lib/context-manager/context-list/context-list.component.ts +++ b/packages/context/src/lib/context-manager/context-list/context-list.component.ts @@ -19,6 +19,7 @@ export class ContextListComponent { } set contexts(value: ContextsList) { this._contexts = value; + this.cdRef.detectChanges(); } private _contexts: ContextsList = { ours: [] }; From 70f2ad0382e366e32234c0bb5b3b234d40202959 Mon Sep 17 00:00:00 2001 From: PhilippeLafreniere18 <53181414+PhilippeLafreniere18@users.noreply.github.com> Date: Thu, 15 Aug 2019 10:15:45 -0400 Subject: [PATCH 04/18] feat/ui (search) : feature details panel, add/remove layer button, clear feature (#386) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat/ui (search-assemblage): panel de détails, bouton add/remove layer, cleanFeature --- .../search-results-tool.component.html | 19 +++++++++++----- .../search-results-tool.component.ts | 22 ++++++++++++++----- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/packages/integration/src/lib/search/search-results-tool/search-results-tool.component.html b/packages/integration/src/lib/search/search-results-tool/search-results-tool.component.html index ceb9deba64..2907b499bf 100644 --- a/packages/integration/src/lib/search/search-results-tool/search-results-tool.component.html +++ b/packages/integration/src/lib/search/search-results-tool/search-results-tool.component.html @@ -2,17 +2,24 @@ #topPanel initial="100%" initialMobile="100%" - collapsed="60%" - collapsedMobile="60%" - expanded="calc(100% - 58px)" - expandedMobile="calc(100% - 58px)" + collapsed="calc(100% - 58px)" + collapsedMobile="calc(100% - 58px)" + expanded="60%" + expandedMobile="60%" [state]="topPanelState">
+ (resultSelect)="onResultFocus($event)"> + + + +
@@ -24,7 +31,7 @@ panelLeftButton class="igo-icon-button" (click)="toggleTopPanel()"> - + @@ -50,7 +50,7 @@ - +
diff --git a/packages/geo/src/lib/search/search-bar/search-bar.component.ts b/packages/geo/src/lib/search/search-bar/search-bar.component.ts index 9b1d8fb32c..299816a190 100644 --- a/packages/geo/src/lib/search/search-bar/search-bar.component.ts +++ b/packages/geo/src/lib/search/search-bar/search-bar.component.ts @@ -83,6 +83,16 @@ export class SearchBarComponent implements OnInit, OnDestroy { */ @Input() searchIcon: string; + /** + * Search Selector + */ + @Input() searchSelector = false; + + /** + * Search Settings + */ + @Input() searchSettings = false; + /** * Search results store */ @@ -149,7 +159,7 @@ export class SearchBarComponent implements OnInit, OnDestroy { get placeholder(): string { return this.empty ? this._placeholder : ''; } - private _placeholder = ''; + private _placeholder = 'search.placeholder'; constructor(private searchService: SearchService) {} @@ -212,6 +222,10 @@ export class SearchBarComponent implements OnInit, OnDestroy { this.doSearch(this.term); } + onSearchSettingsChange() { + this.doSearch(this.term); + } + /** * Send the term into the stream only if this component is not disabled * @param term Search term diff --git a/packages/geo/src/lib/search/search-selector/search-selector.component.ts b/packages/geo/src/lib/search/search-selector/search-selector.component.ts index 39cee64a30..4ccaaf8c62 100644 --- a/packages/geo/src/lib/search/search-selector/search-selector.component.ts +++ b/packages/geo/src/lib/search/search-selector/search-selector.component.ts @@ -1,5 +1,3 @@ -import {MatCheckboxChange, MatRadioChange } from '@angular/material'; - import { Component, Input, @@ -11,8 +9,6 @@ import { import { SEARCH_TYPES } from '../shared/search.enums'; import { SearchSourceService } from '../shared/search-source.service'; -import { SearchSource } from '../shared/sources/source'; -import { SearchSourceSettings, SettingOptions } from '../shared/sources/source.interfaces'; /** * This component allows a user to select a search type yo enable. In it's diff --git a/packages/geo/src/lib/search/search-settings/search-settings.component.ts b/packages/geo/src/lib/search/search-settings/search-settings.component.ts index 383d487309..348cc04077 100644 --- a/packages/geo/src/lib/search/search-settings/search-settings.component.ts +++ b/packages/geo/src/lib/search/search-settings/search-settings.component.ts @@ -2,7 +2,6 @@ import {MatCheckboxChange, MatRadioChange } from '@angular/material'; import { Component, - Input, Output, EventEmitter, ChangeDetectionStrategy @@ -32,7 +31,7 @@ export class SearchSettingsComponent { /** * Event emitted when the enabled search type changes */ - @Output() change = new EventEmitter(); + @Output() change = new EventEmitter(); constructor(private searchSourceService: SearchSourceService) {} @@ -41,7 +40,7 @@ export class SearchSettingsComponent { * @internal */ getSearchSources(): SearchSource[] { - return this.searchSourceService.getSources(); + return this.searchSourceService.getSources().filter(s => s.available && s.getId() !== 'map'); } /** @@ -56,6 +55,7 @@ export class SearchSettingsComponent { ) { settingValue.enabled = event.checked; source.setParamFromSetting(setting); + this.change.emit(source); } /** @@ -76,10 +76,12 @@ export class SearchSettingsComponent { } }); source.setParamFromSetting(setting); + this.change.emit(source); } onCheckSearchSource(event: MatCheckboxChange, source: SearchSource) { source.enabled = event.checked; + this.change.emit(source); } } diff --git a/packages/geo/src/lib/search/shared/sources/coordinates.ts b/packages/geo/src/lib/search/shared/sources/coordinates.ts index 98534e84ee..7fea29d167 100644 --- a/packages/geo/src/lib/search/shared/sources/coordinates.ts +++ b/packages/geo/src/lib/search/shared/sources/coordinates.ts @@ -38,7 +38,8 @@ export class CoordinatesReverseSearchSource extends SearchSource protected getDefaultOptions(): SearchSourceOptions { return { - title: 'Coordinates' + title: 'Coordinates', + order: 1 }; } @@ -76,6 +77,10 @@ export class CoordinatesReverseSearchSource extends SearchSource data[0], data[1] ) + }, + meta: { + id: '1', + title: String(data[0]) + ', ' + String(data[1]) } }, meta: { diff --git a/packages/geo/src/lib/search/shared/sources/icherche.ts b/packages/geo/src/lib/search/shared/sources/icherche.ts index c16680668d..51e4ebf340 100644 --- a/packages/geo/src/lib/search/shared/sources/icherche.ts +++ b/packages/geo/src/lib/search/shared/sources/icherche.ts @@ -276,7 +276,7 @@ export class IChercheSearchSource extends SearchSource implements TextSearch { ); } - return Object.assign(properties, { type: data.index }, googleLinksProperties); + return Object.assign({ type: data.index }, properties, googleLinksProperties); } /** diff --git a/packages/geo/src/lib/search/shared/sources/nominatim.ts b/packages/geo/src/lib/search/shared/sources/nominatim.ts index 4bf1b11500..7600175114 100644 --- a/packages/geo/src/lib/search/shared/sources/nominatim.ts +++ b/packages/geo/src/lib/search/shared/sources/nominatim.ts @@ -8,7 +8,7 @@ import { FEATURE, Feature, FeatureGeometry } from '../../../feature'; import { SearchResult } from '../search.interfaces'; import { SearchSource, TextSearch } from './source'; -import { SearchSourceOptions, TextSearchOptions, SearchSourceSettings } from './source.interfaces'; +import { SearchSourceOptions, TextSearchOptions } from './source.interfaces'; import { NominatimData } from './nominatim.interfaces'; /** diff --git a/packages/geo/src/locale/en.geo.json b/packages/geo/src/locale/en.geo.json index c9b5c9fff6..9707d01a6a 100644 --- a/packages/geo/src/locale/en.geo.json +++ b/packages/geo/src/locale/en.geo.json @@ -286,6 +286,7 @@ } }, "search": { + "placeholder": "Search for a localisation or a layer", "feature.title": "Localisation", "feature.placeholder": "Search for a place localisation", "layer.title": "Layer", diff --git a/packages/geo/src/locale/fr.geo.json b/packages/geo/src/locale/fr.geo.json index d5294e60d5..ed9cbfe06f 100644 --- a/packages/geo/src/locale/fr.geo.json +++ b/packages/geo/src/locale/fr.geo.json @@ -285,6 +285,7 @@ } }, "search": { + "placeholder": "Rechercher une localisation ou une couche de données", "feature.title": "Localisation", "feature.placeholder": "Rechercher une localisation", "layer.title": "Couche de données", diff --git a/packages/integration/src/lib/search/search-results-tool/search-results-tool.component.ts b/packages/integration/src/lib/search/search-results-tool/search-results-tool.component.ts index be5c4e6f98..e1a6e42156 100644 --- a/packages/integration/src/lib/search/search-results-tool/search-results-tool.component.ts +++ b/packages/integration/src/lib/search/search-results-tool/search-results-tool.component.ts @@ -70,6 +70,9 @@ export class SearchResultsToolComponent { .pipe( map(element => { this.feature = element ? (element.entity.data as Feature) : undefined; + if (!this.feature) { + this.topPanelState = 'initial'; + } return this.feature; }) ); From 09e221840bf9a62846df98aae4672de7f2834b88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Barbeau?= Date: Mon, 19 Aug 2019 13:50:01 -0400 Subject: [PATCH 10/18] fix(geo-layer-id): id is the same with or whitout origin --- .../src/lib/catalog/shared/catalog.service.ts | 54 ++++++++++--------- .../src/lib/datasource/utils/id-generator.ts | 3 +- 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/packages/geo/src/lib/catalog/shared/catalog.service.ts b/packages/geo/src/lib/catalog/shared/catalog.service.ts index f02e82fb00..8289b948e9 100644 --- a/packages/geo/src/lib/catalog/shared/catalog.service.ts +++ b/packages/geo/src/lib/catalog/shared/catalog.service.ts @@ -3,6 +3,7 @@ import { HttpClient, HttpErrorResponse } from '@angular/common/http'; import { EMPTY, Observable, of, concat } from 'rxjs'; import { map, catchError } from 'rxjs/operators'; +import { uuid } from '@igo2/utils'; import { LanguageService, ConfigService } from '@igo2/core'; import { CapabilitiesService, @@ -40,36 +41,41 @@ export class CatalogService { const apiUrl = catalogConfig.url || contextConfig.url; const catalogsFromConfig = catalogConfig.sources || []; - if (apiUrl === undefined) { - return of(catalogsFromConfig); - } - const observables$ = []; - // Base layers catalog - if (catalogConfig.baseLayers) { - const translate = this.languageService.translate; - const title = translate.instant('igo.geo.catalog.baseLayers'); - const baseLayersCatalog = { - id: 'catalog.baselayers', - title, - url: `${apiUrl}/baselayers`, - type: 'baselayers' - }; - observables$.push(of(baseLayersCatalog)); - } + if (apiUrl) { + // Base layers catalog + if (catalogConfig.baseLayers) { + const translate = this.languageService.translate; + const title = translate.instant('igo.geo.catalog.baseLayers'); + const baseLayersCatalog = { + id: 'catalog.baselayers', + title, + url: `${apiUrl}/baselayers`, + type: 'baselayers' + }; + observables$.push(of(baseLayersCatalog)); + } - // Catalogs from API - const catalogsFromApi$ = this.http - .get(`${apiUrl}/catalogs`) - .pipe( - catchError((response: HttpErrorResponse) => EMPTY) - ); - observables$.push(catalogsFromApi$); + // Catalogs from API + const catalogsFromApi$ = this.http + .get(`${apiUrl}/catalogs`) + .pipe( + catchError((response: HttpErrorResponse) => EMPTY) + ); + observables$.push(catalogsFromApi$); + } // Catalogs from config if (catalogsFromConfig.length > 0) { - observables$.push(of(catalogsFromConfig)); + observables$.push(of(catalogsFromConfig).pipe( + map((catalogs: Catalog[]) => catalogs.map((c) => { + if (!c.id) { + c.id = uuid(); + } + return c; + })) + )); } return concat(...observables$) as Observable; diff --git a/packages/geo/src/lib/datasource/utils/id-generator.ts b/packages/geo/src/lib/datasource/utils/id-generator.ts index 9784dafdb8..45e70ad70e 100644 --- a/packages/geo/src/lib/datasource/utils/id-generator.ts +++ b/packages/geo/src/lib/datasource/utils/id-generator.ts @@ -31,7 +31,8 @@ export function generateIdFromSourceOptions(options: DataSourceOptions): string */ export function generateWMSIdFromSourceOptions(options: WMSDataSourceOptions) { const layers = options.params.layers; - const chain = 'wms' + options.url + layers; + const url = options.url.charAt(0) === '/'? window.location.origin + options.url : options.url + const chain = 'wms' + url + layers; return Md5.hashStr(chain) as string; } From d8b41d6a1faef0e608a8276ef4fe0714a9e327ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Barbeau?= Date: Mon, 19 Aug 2019 15:31:32 -0400 Subject: [PATCH 11/18] feat(base): possibility to use a base file to put repetitive elements (tools) --- demo/src/contexts/_base.json | 17 ++++++++++ demo/src/contexts/_default.json | 15 +-------- demo/src/contexts/context2.json | 1 - demo/src/contexts/context3.json | 1 - demo/src/contexts/context4.json | 1 - .../shared/context.interface.ts | 1 + .../context-manager/shared/context.service.ts | 32 ++++++++++++++++--- 7 files changed, 47 insertions(+), 21 deletions(-) create mode 100644 demo/src/contexts/_base.json diff --git a/demo/src/contexts/_base.json b/demo/src/contexts/_base.json new file mode 100644 index 0000000000..83ade12316 --- /dev/null +++ b/demo/src/contexts/_base.json @@ -0,0 +1,17 @@ +{ + "map": { + "view": { + "projection": "EPSG:3857", + "center": [-72, 50], + "zoom": 8 + } + }, + "layers": [ + { + "title": "OSM", + "sourceOptions": { + "type": "osm" + } + } + ] +} diff --git a/demo/src/contexts/_default.json b/demo/src/contexts/_default.json index 2c73fb2d19..e806d8d3db 100644 --- a/demo/src/contexts/_default.json +++ b/demo/src/contexts/_default.json @@ -1,20 +1,7 @@ { "uri": "_default", - "title": "Default Context", - "map": { - "view": { - "projection": "EPSG:3857", - "center": [-72, 50], - "zoom": 8 - } - }, + "base": "_base", "layers": [ - { - "title": "OSM", - "sourceOptions": { - "type": "osm" - } - }, { "sourceOptions": { "type": "wms", diff --git a/demo/src/contexts/context2.json b/demo/src/contexts/context2.json index d7c0984804..1d3673bbf3 100644 --- a/demo/src/contexts/context2.json +++ b/demo/src/contexts/context2.json @@ -1,6 +1,5 @@ { "uri": "context2", - "title": "Context 2", "map": { "view": { "projection": "EPSG:3857", diff --git a/demo/src/contexts/context3.json b/demo/src/contexts/context3.json index 3296d73d98..030cbca77e 100644 --- a/demo/src/contexts/context3.json +++ b/demo/src/contexts/context3.json @@ -1,6 +1,5 @@ { "uri": "context3", - "title": "CARTO examples", "map": { "view": { "projection": "EPSG:3857", diff --git a/demo/src/contexts/context4.json b/demo/src/contexts/context4.json index e2d0b0ac88..a7826da483 100644 --- a/demo/src/contexts/context4.json +++ b/demo/src/contexts/context4.json @@ -1,6 +1,5 @@ { "uri": "context4", - "title": "ArcGIS / TileArcGIS Rest examples ", "map": { "view": { "projection": "EPSG:3857", diff --git a/packages/context/src/lib/context-manager/shared/context.interface.ts b/packages/context/src/lib/context-manager/shared/context.interface.ts index acc5af1d8e..767222d8b6 100644 --- a/packages/context/src/lib/context-manager/shared/context.interface.ts +++ b/packages/context/src/lib/context-manager/shared/context.interface.ts @@ -21,6 +21,7 @@ export interface ContextsList { } export interface DetailedContext extends Context { + base?: string; map?: ContextMap; layers?: LayerOptions[]; tools?: Tool[]; diff --git a/packages/context/src/lib/context-manager/shared/context.service.ts b/packages/context/src/lib/context-manager/shared/context.service.ts index 5d346405eb..77eddde781 100644 --- a/packages/context/src/lib/context-manager/shared/context.service.ts +++ b/packages/context/src/lib/context-manager/shared/context.service.ts @@ -1,13 +1,13 @@ import { Injectable, Optional } from '@angular/core'; import { HttpClient } from '@angular/common/http'; -import { BehaviorSubject, Observable } from 'rxjs'; -import { map, tap, catchError, debounceTime } from 'rxjs/operators'; +import { BehaviorSubject, Observable, of } from 'rxjs'; +import { map, tap, catchError, debounceTime, flatMap } from 'rxjs/operators'; import olPoint from 'ol/geom/Point'; import { Tool } from '@igo2/common'; -import { uuid } from '@igo2/utils'; +import { uuid, ObjectUtils } from '@igo2/utils'; import { ConfigService, RouteService, @@ -214,9 +214,33 @@ export class ContextService { ); } - getLocalContext(uri): Observable { + getLocalContext(uri: string): Observable { const url = this.getPath(`${uri}.json`); return this.http.get(url).pipe( + flatMap((res) => { + if (!res.base) { + return of(res); + } + const urlBase = this.getPath(`${res.base}.json`); + return this.http.get(urlBase).pipe( + map((resBase: DetailedContext) => { + const resMerge = res; + resMerge.map = ObjectUtils.mergeDeep(resBase.map, res.map); + resMerge.layers = (resBase.layers || []).concat((res.layers || [])).reverse() + .filter((l, index, self) => !l.id || self.findIndex((l2) => l2.id === l.id) === index) + .reverse(); + resMerge.toolbar = [...new Set( + (resBase.toolbar || []).concat((res.toolbar || [])).reverse()) as any + ].reverse(); + resMerge.tools = (res.tools || []).concat((resBase.tools || [])) + .filter((t, index, self) => self.findIndex((t2) => t2.name === t.name) === index); + return resMerge; + }), + catchError(res => { + return this.handleError(res, uri); + }) + ); + }), catchError(res => { return this.handleError(res, uri); }) From 76f9197022c7bea1e0b57cfb59993cb3dd437d0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Barbeau?= Date: Wed, 21 Aug 2019 17:27:35 -0400 Subject: [PATCH 12/18] fix(icherche): catch error --- demo/src/app/core/request/request.module.ts | 2 +- demo/src/app/geo/search/search.component.html | 2 ++ demo/src/app/geo/search/search.module.ts | 5 +++ .../core/src/lib/request/error.interceptor.ts | 4 +-- .../src/lib/search/shared/sources/icherche.ts | 35 ++++++++++++++----- 5 files changed, 35 insertions(+), 13 deletions(-) diff --git a/demo/src/app/core/request/request.module.ts b/demo/src/app/core/request/request.module.ts index 8911ff247e..18b704316c 100644 --- a/demo/src/app/core/request/request.module.ts +++ b/demo/src/app/core/request/request.module.ts @@ -2,7 +2,7 @@ import { NgModule } from '@angular/core'; import { HttpClientModule } from '@angular/common/http'; import { MatCardModule, MatButtonModule } from '@angular/material'; -import { IgoLoggingModule, IgoErrorModule } from '@igo2/core'; +import { IgoErrorModule } from '@igo2/core'; import { AppRequestComponent } from './request.component'; import { AppRequestRoutingModule } from './request-routing.module'; diff --git a/demo/src/app/geo/search/search.component.html b/demo/src/app/geo/search/search.component.html index 70872a528b..3a1db2df9f 100644 --- a/demo/src/app/geo/search/search.component.html +++ b/demo/src/app/geo/search/search.component.html @@ -50,3 +50,5 @@ [mode]="'context'"> + + diff --git a/demo/src/app/geo/search/search.module.ts b/demo/src/app/geo/search/search.module.ts index 9db87568ee..041fc59205 100644 --- a/demo/src/app/geo/search/search.module.ts +++ b/demo/src/app/geo/search/search.module.ts @@ -8,11 +8,14 @@ import { MatTooltipModule } from '@angular/material'; +import { IgoMessageModule, IgoErrorModule } from '@igo2/core'; + import { IgoPanelModule, IgoActionbarModule, IgoContextMenuModule } from '@igo2/common'; + import { IgoFeatureModule, IgoMapModule, @@ -38,6 +41,8 @@ import { AppSearchRoutingModule } from './search-routing.module'; MatButtonModule, MatIconModule, MatTooltipModule, + IgoMessageModule.forRoot(), + IgoErrorModule.forRoot(), IgoPanelModule, IgoMapModule, IgoSearchModule.forRoot(), diff --git a/packages/core/src/lib/request/error.interceptor.ts b/packages/core/src/lib/request/error.interceptor.ts index 1d2f8052b4..8834df655a 100644 --- a/packages/core/src/lib/request/error.interceptor.ts +++ b/packages/core/src/lib/request/error.interceptor.ts @@ -34,9 +34,7 @@ export class ErrorInterceptor implements HttpInterceptor { } private handleError(httpError: HttpErrorResponse, req: HttpRequest) { - const msg = `${req.method} ${req.urlWithParams} ${httpError.status} (${ - httpError.statusText - })`; + const msg = `${req.method} ${req.urlWithParams} ${httpError.status} (${httpError.statusText})`; if (httpError instanceof HttpErrorResponse) { const errorObj = httpError.error === 'object' ? httpError.error : {}; diff --git a/packages/geo/src/lib/search/shared/sources/icherche.ts b/packages/geo/src/lib/search/shared/sources/icherche.ts index 51e4ebf340..d389068f3f 100644 --- a/packages/geo/src/lib/search/shared/sources/icherche.ts +++ b/packages/geo/src/lib/search/shared/sources/icherche.ts @@ -2,7 +2,7 @@ import { Injectable, Inject } from '@angular/core'; import { HttpClient, HttpParams } from '@angular/common/http'; import { Observable } from 'rxjs'; -import { map } from 'rxjs/operators'; +import { map, catchError } from 'rxjs/operators'; import { LanguageService } from '@igo2/core'; @@ -201,9 +201,14 @@ export class IChercheSearchSource extends SearchSource implements TextSearch { options?: TextSearchOptions ): Observable[]> { const params = this.computeRequestParams(term, options || {}); - return this.http - .get(this.searchUrl, { params }) - .pipe(map((response: IChercheResponse) => this.extractResults(response))); + return this.http.get(this.searchUrl, { params }).pipe( + map((response: IChercheResponse) => this.extractResults(response)), + catchError(err => { + err.error.toDisplay = true; + err.error.title = this.getDefaultOptions().title; + throw err; + }) + ); } private computeRequestParams( @@ -234,6 +239,7 @@ export class IChercheSearchSource extends SearchSource implements TextSearch { const properties = this.computeProperties(data); const id = [this.getId(), properties.type, properties.code].join('.'); + const titleHtml = data.highlight.title || data.properties.nom; const subtitleHtml = data.highlight.title2 ? ' ' + data.highlight.title2 + '' : ''; @@ -255,7 +261,7 @@ export class IChercheSearchSource extends SearchSource implements TextSearch { dataType: FEATURE, id, title: data.properties.nom, - titleHtml: data.highlight.title + subtitleHtml, + titleHtml: titleHtml + subtitleHtml, icon: 'map-marker' } }; @@ -267,16 +273,27 @@ export class IChercheSearchSource extends SearchSource implements TextSearch { IChercheSearchSource.propertiesBlacklist ); - const googleLinksProperties: { GoogleMaps: string, GoogleStreetView?: string } = { - GoogleMaps: GoogleLinks.getGoogleMapsLink(data.geometry.coordinates[0], data.geometry.coordinates[1]) + const googleLinksProperties: { + GoogleMaps: string; + GoogleStreetView?: string; + } = { + GoogleMaps: GoogleLinks.getGoogleMapsLink( + data.geometry.coordinates[0], + data.geometry.coordinates[1] + ) }; if (data.geometry.type === 'Point') { googleLinksProperties.GoogleStreetView = GoogleLinks.getGoogleStreetViewLink( - data.geometry.coordinates[0], data.geometry.coordinates[1] + data.geometry.coordinates[0], + data.geometry.coordinates[1] ); } - return Object.assign({ type: data.index }, properties, googleLinksProperties); + return Object.assign( + { type: data.index }, + properties, + googleLinksProperties + ); } /** From 15b42dcae58da41095da330227ab23da107a9250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Barbeau?= Date: Thu, 22 Aug 2019 13:12:09 -0400 Subject: [PATCH 13/18] refactor(error): refactor error interceptor --- demo/src/app/app.module.ts | 14 ++++- .../src/app/core/request/request.component.ts | 5 +- demo/src/app/core/request/request.module.ts | 3 +- demo/src/app/geo/feature/feature.module.ts | 2 - demo/src/app/geo/measure/measure.module.ts | 2 - demo/src/app/geo/search/search.module.ts | 3 +- package-lock.json | 56 +++++++++---------- .../core/src/lib/request/error.interceptor.ts | 49 ++++++++-------- packages/core/src/lib/request/error.module.ts | 15 ++++- 9 files changed, 88 insertions(+), 61 deletions(-) diff --git a/demo/src/app/app.module.ts b/demo/src/app/app.module.ts index 5ec9a675b1..95f7d14188 100644 --- a/demo/src/app/app.module.ts +++ b/demo/src/app/app.module.ts @@ -1,7 +1,9 @@ -import { BrowserModule } from '@angular/platform-browser'; +import { BrowserModule, DomSanitizer } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { NgModule } from '@angular/core'; +import {} from '@angular/platform-browser'; import { + MatIconRegistry, MatSidenavModule, MatToolbarModule, MatButtonModule, @@ -98,4 +100,12 @@ import { AppComponent } from './app.component'; ], bootstrap: [AppComponent] }) -export class AppModule {} +export class AppModule { + constructor(matIconRegistry: MatIconRegistry, domSanitizer: DomSanitizer) { + matIconRegistry.addSvgIconSet( + domSanitizer.bypassSecurityTrustResourceUrl( + './assets/igo2/core/icons/mdi.svg' + ) + ); + } +} diff --git a/demo/src/app/core/request/request.component.ts b/demo/src/app/core/request/request.component.ts index bea9d97884..38e6bf492f 100644 --- a/demo/src/app/core/request/request.component.ts +++ b/demo/src/app/core/request/request.component.ts @@ -1,13 +1,16 @@ import { Component } from '@angular/core'; import { HttpClient } from '@angular/common/http'; +import { LanguageService } from '@igo2/core'; + + @Component({ selector: 'app-request', templateUrl: './request.component.html', styleUrls: ['./request.component.scss'] }) export class AppRequestComponent { - constructor(private http: HttpClient) {} + constructor(private http: HttpClient, public languageService: LanguageService) {} callHttp() { const url = '/locale/en.json'; diff --git a/demo/src/app/core/request/request.module.ts b/demo/src/app/core/request/request.module.ts index 18b704316c..2c1bc049d4 100644 --- a/demo/src/app/core/request/request.module.ts +++ b/demo/src/app/core/request/request.module.ts @@ -2,7 +2,7 @@ import { NgModule } from '@angular/core'; import { HttpClientModule } from '@angular/common/http'; import { MatCardModule, MatButtonModule } from '@angular/material'; -import { IgoErrorModule } from '@igo2/core'; +import { IgoErrorModule, IgoLanguageModule } from '@igo2/core'; import { AppRequestComponent } from './request.component'; import { AppRequestRoutingModule } from './request-routing.module'; @@ -14,6 +14,7 @@ import { AppRequestRoutingModule } from './request-routing.module'; MatCardModule, MatButtonModule, HttpClientModule, + IgoLanguageModule.forRoot(), IgoErrorModule.forRoot() // Only if you want register errors from http call in console // IgoLoggingModule.forRoot() // Only if you want register http calls in console ], diff --git a/demo/src/app/geo/feature/feature.module.ts b/demo/src/app/geo/feature/feature.module.ts index d9467ea9da..63357442bc 100644 --- a/demo/src/app/geo/feature/feature.module.ts +++ b/demo/src/app/geo/feature/feature.module.ts @@ -6,7 +6,6 @@ import { MatIconModule } from '@angular/material'; -import { IgoCoreModule } from '@igo2/core'; import { IgoPanelModule, IgoEntityTableModule } from '@igo2/common'; import { IgoMapModule, IgoFeatureModule } from '@igo2/geo'; @@ -21,7 +20,6 @@ import { AppFeatureRoutingModule } from './feature-routing.module'; MatCardModule, MatButtonModule, MatIconModule, - IgoCoreModule, IgoPanelModule, IgoEntityTableModule, IgoMapModule, diff --git a/demo/src/app/geo/measure/measure.module.ts b/demo/src/app/geo/measure/measure.module.ts index 5bd271012c..4145c4d3a5 100644 --- a/demo/src/app/geo/measure/measure.module.ts +++ b/demo/src/app/geo/measure/measure.module.ts @@ -1,7 +1,6 @@ import { NgModule } from '@angular/core'; import { MatCardModule } from '@angular/material'; -import { IgoCoreModule } from '@igo2/core'; import { IgoMapModule, IgoMeasureModule } from '@igo2/geo'; import { AppMeasureComponent } from './measure.component'; @@ -12,7 +11,6 @@ import { AppMeasureRoutingModule } from './measure-routing.module'; imports: [ AppMeasureRoutingModule, MatCardModule, - IgoCoreModule, IgoMapModule, IgoMeasureModule ], diff --git a/demo/src/app/geo/search/search.module.ts b/demo/src/app/geo/search/search.module.ts index 041fc59205..e0d3812f91 100644 --- a/demo/src/app/geo/search/search.module.ts +++ b/demo/src/app/geo/search/search.module.ts @@ -8,7 +8,7 @@ import { MatTooltipModule } from '@angular/material'; -import { IgoMessageModule, IgoErrorModule } from '@igo2/core'; +import { IgoMessageModule } from '@igo2/core'; import { IgoPanelModule, @@ -42,7 +42,6 @@ import { AppSearchRoutingModule } from './search-routing.module'; MatIconModule, MatTooltipModule, IgoMessageModule.forRoot(), - IgoErrorModule.forRoot(), IgoPanelModule, IgoMapModule, IgoSearchModule.forRoot(), diff --git a/package-lock.json b/package-lock.json index 84f003c7b4..a19bfdcf87 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1552,7 +1552,7 @@ }, "acorn-globals": { "version": "1.0.9", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-1.0.9.tgz", + "resolved": "http://registry.npmjs.org/acorn-globals/-/acorn-globals-1.0.9.tgz", "integrity": "sha1-VbtemGkVB7dFedBRNBMhfDgMVM8=", "requires": { "acorn": "^2.1.0" @@ -1721,7 +1721,7 @@ "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", @@ -1865,7 +1865,7 @@ "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "integrity": "sha1-aALmJk79GMeQobDVF/DyYnvyyUo=", "dev": true }, "archy": { @@ -1917,7 +1917,7 @@ "arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE=", "dev": true }, "arr-map": { @@ -1949,7 +1949,7 @@ }, "array-equal": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=" }, "array-filter": { @@ -2453,7 +2453,7 @@ "base": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "integrity": "sha1-e95c7RRbbVUakNuH+DxVi060io8=", "dev": true, "requires": { "cache-base": "^1.0.1", @@ -2654,7 +2654,7 @@ "bn.js": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "integrity": "sha1-LN4J617jQfSEdGuwMJsyU7GxRC8=", "dev": true }, "body-parser": { @@ -3001,7 +3001,7 @@ "buffer-indexof": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", - "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", + "integrity": "sha1-Uvq8xqYG0aADAoAmSO9o9jnaJow=", "dev": true }, "buffer-xor": { @@ -3058,7 +3058,7 @@ "cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "integrity": "sha1-Cn9GQWgxyLZi7jb+TnxZ129marI=", "dev": true, "requires": { "collection-visit": "^1.0.0", @@ -3263,7 +3263,7 @@ "cipher-base": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "integrity": "sha1-h2Dk7MJy9MNjUy+SbYdKriwTl94=", "dev": true, "requires": { "inherits": "^2.0.1", @@ -3687,7 +3687,7 @@ "content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=", "dev": true }, "conventional-changelog": { @@ -4436,7 +4436,7 @@ "copy-concurrently": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", - "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "integrity": "sha1-kilzmMrjSTf8r9bsgTnBgFHwteA=", "dev": true, "requires": { "aproba": "^1.1.1", @@ -5662,7 +5662,7 @@ "evp_bytestokey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "integrity": "sha1-f8vbGY3HGVlDLv4ThCaE4FJaywI=", "dev": true, "requires": { "md5.js": "^1.3.4", @@ -6952,7 +6952,7 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=", "dev": true }, "gauge": { @@ -7533,7 +7533,7 @@ "globals": { "version": "9.18.0", "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "integrity": "sha1-qjiWs+abSH8X4x7SFD1pqOMMLYo=", "dev": true }, "globby": { @@ -8808,7 +8808,7 @@ "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", "dev": true, "requires": { "isobject": "^3.0.1" @@ -9317,7 +9317,7 @@ }, "jsdom": { "version": "8.5.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-8.5.0.tgz", + "resolved": "http://registry.npmjs.org/jsdom/-/jsdom-8.5.0.tgz", "integrity": "sha1-1Nj12/J2hjW2KmKCO5R89wcevJg=", "requires": { "abab": "^1.0.0", @@ -10478,7 +10478,7 @@ "miller-rabin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "integrity": "sha1-8IA1HIZbDcViqEYpZtqlNUPHik0=", "dev": true, "requires": { "bn.js": "^4.0.0", @@ -10542,7 +10542,7 @@ "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", "dev": true, "requires": { "brace-expansion": "^1.1.7" @@ -11296,7 +11296,7 @@ "npmlog": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "integrity": "sha1-CKfyqL9zRgR3mp76StXMcXq7lUs=", "dev": true, "requires": { "are-we-there-yet": "~1.1.2", @@ -11686,7 +11686,7 @@ "p-map": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", - "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", + "integrity": "sha1-5OlPMR6rvIYzoeeZCBZfyiYkG2s=", "dev": true }, "p-try": { @@ -12036,7 +12036,7 @@ }, "pause-stream": { "version": "0.0.11", - "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "resolved": "http://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", "dev": true, "requires": { @@ -12046,7 +12046,7 @@ "pbf": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.1.0.tgz", - "integrity": "sha512-/hYJmIsTmh7fMkHAWWXJ5b8IKLWdjdlAFb3IHkRBn1XUhIYBChVGfVwmHEAV3UfXTxsP/AKfYTXTS/dCPxJd5w==", + "integrity": "sha1-9wAEutyygXYeq7HnbJLxefCBiek=", "requires": { "ieee754": "^1.1.6", "resolve-protobuf-schema": "^2.0.0" @@ -12514,7 +12514,7 @@ "promise": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "integrity": "sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078=", "dev": true, "optional": true, "requires": { @@ -13272,7 +13272,7 @@ "replacestream": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/replacestream/-/replacestream-4.0.3.tgz", - "integrity": "sha512-AC0FiLS352pBBiZhd4VXB1Ab/lh0lEgpP+GGvZqbQh8a5cmXVoTe5EX/YeTFArnp4SRGTHh1qCHu9lGs1qG8sA==", + "integrity": "sha1-PuV5gJK+Nksc2xSEMISSyz3/LzY=", "dev": true, "requires": { "escape-string-regexp": "^1.0.3", @@ -14216,7 +14216,7 @@ "snapdragon-node": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "integrity": "sha1-bBdfhv8UvbByRWPo88GwIaKGhTs=", "dev": true, "requires": { "define-property": "^1.0.0", @@ -14267,7 +14267,7 @@ "snapdragon-util": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "integrity": "sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI=", "dev": true, "requires": { "kind-of": "^3.2.0" @@ -16237,7 +16237,7 @@ "vlq": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz", - "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==", + "integrity": "sha1-jz5DKM9jsVQMDWfhsneDhviXWyY=", "dev": true }, "vm-browserify": { diff --git a/packages/core/src/lib/request/error.interceptor.ts b/packages/core/src/lib/request/error.interceptor.ts index 8834df655a..2413cd7802 100644 --- a/packages/core/src/lib/request/error.interceptor.ts +++ b/packages/core/src/lib/request/error.interceptor.ts @@ -13,10 +13,10 @@ import { catchError, finalize } from 'rxjs/operators'; import { MessageService } from '../message/shared/message.service'; import { LanguageService } from '../language/shared/language.service'; -@Injectable() +@Injectable({ + providedIn: 'root' +}) export class ErrorInterceptor implements HttpInterceptor { - private httpError: HttpErrorResponse; - constructor( private messageService: MessageService, private injector: Injector @@ -26,23 +26,26 @@ export class ErrorInterceptor implements HttpInterceptor { req: HttpRequest, next: HttpHandler ): Observable> { + const errorContainer = { httpError: undefined }; return next.handle(req).pipe( - catchError(error => this.handleError(error, req)), - finalize(() => this.handleCaughtError()), - finalize(() => this.handleUncaughtError()) + catchError(error => this.handleError(error, errorContainer)), + finalize(() => { + this.handleCaughtError(errorContainer); + this.handleUncaughtError(errorContainer); + }) ); } - private handleError(httpError: HttpErrorResponse, req: HttpRequest) { - const msg = `${req.method} ${req.urlWithParams} ${httpError.status} (${httpError.statusText})`; - + private handleError( + httpError: HttpErrorResponse, + errorContainer: { httpError: HttpErrorResponse } + ) { if (httpError instanceof HttpErrorResponse) { const errorObj = httpError.error === 'object' ? httpError.error : {}; errorObj.message = httpError.error.message || httpError.statusText; errorObj.caught = false; - console.error(msg, '\n', errorObj.message, '\n\n', httpError); - this.httpError = new HttpErrorResponse({ + httpError = new HttpErrorResponse({ error: errorObj, headers: httpError.headers, status: httpError.status, @@ -51,25 +54,27 @@ export class ErrorInterceptor implements HttpInterceptor { }); } - return throwError(this.httpError); + errorContainer.httpError = httpError; + return throwError(httpError); } - private handleCaughtError() { - if (this.httpError && this.httpError.error.toDisplay) { - this.httpError.error.caught = true; - this.messageService.error( - this.httpError.error.message, - this.httpError.error.title - ); + private handleCaughtError(errorContainer: { httpError: HttpErrorResponse }) { + const httpError = errorContainer.httpError; + if (httpError && httpError.error.toDisplay) { + httpError.error.caught = true; + this.messageService.error(httpError.error.message, httpError.error.title); } } - private handleUncaughtError() { - if (this.httpError && !this.httpError.error.caught) { + private handleUncaughtError(errorContainer: { + httpError: HttpErrorResponse; + }) { + const httpError = errorContainer.httpError; + if (httpError && !httpError.error.caught) { const translate = this.injector.get(LanguageService).translate; const message = translate.instant('igo.core.errors.uncaught.message'); const title = translate.instant('igo.core.errors.uncaught.title'); - this.httpError.error.caught = true; + httpError.error.caught = true; this.messageService.error(message, title); } } diff --git a/packages/core/src/lib/request/error.module.ts b/packages/core/src/lib/request/error.module.ts index a94a35f6ad..9e34903870 100644 --- a/packages/core/src/lib/request/error.module.ts +++ b/packages/core/src/lib/request/error.module.ts @@ -1,4 +1,9 @@ -import { NgModule, ModuleWithProviders } from '@angular/core'; +import { + NgModule, + ModuleWithProviders, + Optional, + SkipSelf +} from '@angular/core'; import { HTTP_INTERCEPTORS } from '@angular/common/http'; import { ErrorInterceptor } from './error.interceptor'; @@ -21,4 +26,12 @@ export class IgoErrorModule { ] }; } + + constructor(@Optional() @SkipSelf() parentModule: IgoErrorModule) { + if (parentModule) { + throw new Error( + 'IgoErrorModule is already loaded. Import it in the AppModule only' + ); + } + } } From 1dbc008f4c644814cab6a88ba54135b0c95517c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Barbeau?= Date: Thu, 22 Aug 2019 18:33:59 -0400 Subject: [PATCH 14/18] hashtag alias --- demo/src/environments/environment.ts | 36 +++---- .../src/lib/search/shared/search.service.ts | 31 +++++-- .../src/lib/search/shared/sources/icherche.ts | 48 +++++----- .../lib/search/shared/sources/nominatim.ts | 86 ++++++++--------- .../shared/sources/source.interfaces.ts | 6 +- .../src/lib/search/shared/sources/source.ts | 93 +++++++++++-------- 6 files changed, 159 insertions(+), 141 deletions(-) diff --git a/demo/src/environments/environment.ts b/demo/src/environments/environment.ts index e5af44ae8d..6fcae8266d 100644 --- a/demo/src/environments/environment.ts +++ b/demo/src/environments/environment.ts @@ -65,40 +65,28 @@ export const environment: Environment = { }, searchSources: { nominatim: { - enabled: false, - disabled: true - }, - reseautq: { - searchUrl: 'https://ws.mapserver.transports.gouv.qc.ca/swtq', - locateUrl: 'https://ws.mapserver.transports.gouv.qc.ca/swtq', - limit: 5, - locateLimit: 15, - zoomMaxOnSelect: 8, - enabled: false, - propertiesAlias: [ - { name: 'title', alias: 'Titre' }, - { name: 'etiquette', alias: 'Informations' }, - { name: 'nommun', alias: 'Municipalité' }, - { name: 'messagpan', alias: 'Message' }, - { name: 'noroute', alias: '# de route' }, - { name: 'nosortie', alias: '# de sortie' }, - { name: 'direction', alias: 'Direction' }, - { name: 'typesort', alias: 'Type de sortie' } - ], - distance: 0.5 + enabled: true }, icherche: { searchUrl: '/apis/icherche/geocode', - zoomMaxOnSelect: 10, - enabled: true + order: 2, + enabled: true, + params: { + limit: '8' + } }, icherchereverse: { searchUrl: '/apis/territoires/locate', + order: 3, enabled: true }, ilayer: { searchUrl: '/apis/layers/search', - enabled: true + order: 4, + enabled: true, + params: { + limit: '5' + } } } } diff --git a/packages/geo/src/lib/search/shared/search.service.ts b/packages/geo/src/lib/search/shared/search.service.ts index 28435d38f6..81059a7bab 100644 --- a/packages/geo/src/lib/search/shared/search.service.ts +++ b/packages/geo/src/lib/search/shared/search.service.ts @@ -4,7 +4,10 @@ import { stringToLonLat } from '../../map'; import { MapService } from '../../map/shared/map.service'; import { SearchSource, TextSearch, ReverseSearch } from './sources/source'; -import { TextSearchOptions, ReverseSearchOptions } from './sources/source.interfaces'; +import { + TextSearchOptions, + ReverseSearchOptions +} from './sources/source.interfaces'; import { SearchSourceService } from './search-source.service'; import { Research } from './search.interfaces'; import { sourceCanSearch, sourceCanReverseSearch } from './search.utils'; @@ -20,8 +23,10 @@ import { sourceCanSearch, sourceCanReverseSearch } from './search.utils'; providedIn: 'root' }) export class SearchService { - - constructor(private searchSourceService: SearchSourceService, private mapService: MapService) {} + constructor( + private searchSourceService: SearchSourceService, + private mapService: MapService + ) {} /** * Perform a research by text @@ -40,8 +45,10 @@ export class SearchService { console.log(response.message); } - const sources = this.searchSourceService.getEnabledSources() + const sources = this.searchSourceService + .getEnabledSources() .filter(sourceCanSearch); + return this.searchSources(sources, term, options || {}); } @@ -51,7 +58,8 @@ export class SearchService { * @returns Researches */ reverseSearch(lonLat: [number, number], options?: ReverseSearchOptions) { - const sources = this.searchSourceService.getEnabledSources() + const sources = this.searchSourceService + .getEnabledSources() .filter(sourceCanReverseSearch); return this.reverseSearchSources(sources, lonLat, options || {}); } @@ -62,10 +70,14 @@ export class SearchService { * @param term Search term * @returns Observable of Researches */ - private searchSources(sources: SearchSource[], term: string, options: TextSearchOptions): Research[] { + private searchSources( + sources: SearchSource[], + term: string, + options: TextSearchOptions + ): Research[] { return sources.map((source: SearchSource) => { return { - request: (source as any as TextSearch).search(term, options), + request: ((source as any) as TextSearch).search(term, options), reverse: false, source }; @@ -85,7 +97,10 @@ export class SearchService { ): Research[] { return sources.map((source: SearchSource) => { return { - request: (source as any as ReverseSearch).reverseSearch(lonLat, options), + request: ((source as any) as ReverseSearch).reverseSearch( + lonLat, + options + ), reverse: true, source }; diff --git a/packages/geo/src/lib/search/shared/sources/icherche.ts b/packages/geo/src/lib/search/shared/sources/icherche.ts index d389068f3f..4930033495 100644 --- a/packages/geo/src/lib/search/shared/sources/icherche.ts +++ b/packages/geo/src/lib/search/shared/sources/icherche.ts @@ -1,7 +1,7 @@ import { Injectable, Inject } from '@angular/core'; import { HttpClient, HttpParams } from '@angular/common/http'; -import { Observable } from 'rxjs'; +import { Observable, of } from 'rxjs'; import { map, catchError } from 'rxjs/operators'; import { LanguageService } from '@igo2/core'; @@ -69,7 +69,8 @@ export class IChercheSearchSource extends SearchSource implements TextSearch { { title: 'Adresse', value: 'adresses', - enabled: true + enabled: true, + hashtags: ['adresse'] }, // { // title: 'Ancienne adresse', @@ -79,17 +80,20 @@ export class IChercheSearchSource extends SearchSource implements TextSearch { { title: 'Code Postal', value: 'codes-postaux', - enabled: true + enabled: true, + hashtags: ['code-postal'] }, { title: 'Route', value: 'routes', - enabled: false + enabled: false, + hashtags: ['route'] }, { title: 'Municipalité', value: 'municipalites', - enabled: true + enabled: true, + hashtags: ['municipalité'] }, // { // title: 'Ancienne municipalité', @@ -104,22 +108,26 @@ export class IChercheSearchSource extends SearchSource implements TextSearch { { title: 'Région administrative', value: 'regadmin', - enabled: true + enabled: true, + hashtags: ['région-administrative'] }, { title: 'Lieu', value: 'lieux', - enabled: true + enabled: true, + hashtags: ['lieu'] }, { title: 'Borne', value: 'bornes', - enabled: false + enabled: false, + hashtags: ['borne'] }, { title: 'Entreprise', value: 'entreprises', - enabled: false + enabled: false, + hashtags: ['entreprise'] } ] }, @@ -201,6 +209,9 @@ export class IChercheSearchSource extends SearchSource implements TextSearch { options?: TextSearchOptions ): Observable[]> { const params = this.computeRequestParams(term, options || {}); + if (!params.get('type').length) { + return of(); + } return this.http.get(this.searchUrl, { params }).pipe( map((response: IChercheResponse) => this.extractResults(response)), catchError(err => { @@ -313,22 +324,13 @@ export class IChercheSearchSource extends SearchSource implements TextSearch { term: string, options: TextSearchOptions ): TextSearchOptions { - const tags = term.match(/(#[^\s]+)/g); - if (tags) { - let typeValue = ''; - let hashtagToAdd = false; - tags.forEach(value => { - if (super.hashtagValid(super.getSettingsValues('type'), value, true)) { - typeValue += value.substring(1) + ','; - hashtagToAdd = true; - } + const hashtags = super.getHashtagsValid(term, 'type'); + if (hashtags) { + options.params = Object.assign(options.params || {}, { + type: hashtags.join(',') }); - if (hashtagToAdd) { - options.params = Object.assign(options.params || {}, { - type: typeValue.slice(0, -1) - }); - } } + return options; } } diff --git a/packages/geo/src/lib/search/shared/sources/nominatim.ts b/packages/geo/src/lib/search/shared/sources/nominatim.ts index 7600175114..9cf217fd7d 100644 --- a/packages/geo/src/lib/search/shared/sources/nominatim.ts +++ b/packages/geo/src/lib/search/shared/sources/nominatim.ts @@ -32,39 +32,42 @@ export class NominatimSearchSource extends SearchSource implements TextSearch { /* * Source : https://wiki.openstreetmap.org/wiki/Key:amenity - */ + */ protected getDefaultOptions(): SearchSourceOptions { return { title: 'Nominatim (OSM)', searchUrl: 'https://nominatim.openstreetmap.org/search', settings: [ { - type: 'checkbox', - title: 'results type', - name: 'amenity', - values: [ - { - title: 'Restauration', - value: 'bar,bbq,biergaten,cafe,drinking_water,fast_food,food_court,ice_cream,pub,restaurant', - enabled: false - }, - { - title: 'Santé', - value: 'baby_hatch,clinic,dentist,doctors,hospital,nursing_home,pharmacy,social_facility,veterinary', - enabled: false - }, - { - title: 'Divertissement', - value: 'arts_centre,brothel,casino,cinema,community_center_fountain,gambling,nightclub,planetarium \ + type: 'checkbox', + title: 'results type', + name: 'amenity', + values: [ + { + title: 'Restauration', + value: + 'bar,bbq,biergaten,cafe,drinking_water,fast_food,food_court,ice_cream,pub,restaurant', + enabled: false + }, + { + title: 'Santé', + value: + 'baby_hatch,clinic,dentist,doctors,hospital,nursing_home,pharmacy,social_facility,veterinary', + enabled: false + }, + { + title: 'Divertissement', + value: + 'arts_centre,brothel,casino,cinema,community_center_fountain,gambling,nightclub,planetarium \ ,public_bookcase,social_centre,stripclub,studio,swingerclub,theatre,internet_cafe', - enabled: false - }, - { - title: 'Finance', - value: 'atm,bank,bureau_de_change', - enabled: false - } - ] + enabled: false + }, + { + title: 'Finance', + value: 'atm,bank,bureau_de_change', + enabled: false + } + ] }, { type: 'radiobutton', @@ -225,23 +228,16 @@ export class NominatimSearchSource extends SearchSource implements TextSearch { * @param term Query with hashtag */ private computeTermTags(term: string): string { - const tags = term.match(/(#[^\s]+)/g); - - let addTagsFromSettings = true; - if ( tags ) { - tags.forEach( value => { - term = term.replace(value, ''); - if ( super.hashtagValid(super.getSettingsValues('amenity'), value) ) { - term += '+[' + value.substring(1) + ']'; - addTagsFromSettings = false; - } - }); - addTagsFromSettings = false; + const hashtags = super.getHashtagsValid(term, 'amenity'); + if (!hashtags) { + return this.computeTermSettings(term); } - if (addTagsFromSettings) { - term = this.computeTermSettings(term); - } + term = term.replace(/(#[^\s]*)/g, ''); + hashtags.forEach(tag => { + term += '+[' + tag + ']'; + }); + return term; } @@ -250,12 +246,12 @@ export class NominatimSearchSource extends SearchSource implements TextSearch { * @param term Query */ private computeTermSettings(term: string): string { - this.options.settings.forEach( settings => { - if (settings.name === 'amenity') { - settings.values.forEach( conf => { + this.options.settings.forEach(settings => { + if (settings.name === 'amenity') { + settings.values.forEach(conf => { if (conf.enabled && typeof conf.value === 'string') { const splitted = conf.value.split(','); - splitted.forEach( value => { + splitted.forEach(value => { term += '+[' + value + ']'; }); } diff --git a/packages/geo/src/lib/search/shared/sources/source.interfaces.ts b/packages/geo/src/lib/search/shared/sources/source.interfaces.ts index 3be4dcb330..8bd1de75a2 100644 --- a/packages/geo/src/lib/search/shared/sources/source.interfaces.ts +++ b/packages/geo/src/lib/search/shared/sources/source.interfaces.ts @@ -11,17 +11,19 @@ export interface SearchSourceOptions { } export interface SearchSourceSettings { - type: 'radiobutton'|'checkbox'; + type: 'radiobutton' | 'checkbox'; values: SettingOptions[]; title: string; name: string; } export interface SettingOptions { - value: string|number; + value: string | number; enabled: boolean; title: string; + hashtags?: string[]; } + export interface TextSearchOptions { params?: { [key: string]: string }; } diff --git a/packages/geo/src/lib/search/shared/sources/source.ts b/packages/geo/src/lib/search/shared/sources/source.ts index d788c5de5b..ebcb85ef5b 100644 --- a/packages/geo/src/lib/search/shared/sources/source.ts +++ b/packages/geo/src/lib/search/shared/sources/source.ts @@ -95,27 +95,29 @@ export class SearchSource { * Set params from selected settings */ setParamFromSetting(setting: SearchSourceSettings) { - switch (setting.type) { - case 'radiobutton': - setting.values.forEach( conf => { - if (conf.enabled) { - this.options.params = Object.assign( (this.options.params || {}), - { [setting.name] : conf.value } ); - } - }); - break; - case 'checkbox': - let confValue = ''; - setting.values.forEach( conf => { - if (conf.enabled) { - confValue += conf.value + ','; - } - }); - confValue = confValue.slice(0, -1); - this.options.params = Object.assign( (this.options.params || {}), - { [setting.name] : confValue } ); - break; - } + switch (setting.type) { + case 'radiobutton': + setting.values.forEach(conf => { + if (conf.enabled) { + this.options.params = Object.assign(this.options.params || {}, { + [setting.name]: conf.value + }); + } + }); + break; + case 'checkbox': + let confValue = ''; + setting.values.forEach(conf => { + if (conf.enabled) { + confValue += conf.value + ','; + } + }); + confValue = confValue.slice(0, -1); + this.options.params = Object.assign(this.options.params || {}, { + [setting.name]: confValue + }); + break; + } } /** @@ -129,36 +131,49 @@ export class SearchSource { this.options = Object.assign({}, this.getDefaultOptions(), options); // Set Default Params from Settings - this.settings.forEach( setting => { + this.settings.forEach(setting => { this.setParamFromSetting(setting); }); } /** - * Check if hashtag is valid + * Get hashtags valid * @param hashtag hashtag from query - * @param completeMatch boolean - */ - hashtagValid(searchSourceSetting: SearchSourceSettings, hashtag: string, completeMatch = false): boolean { - let hashtagIsValid = false; - searchSourceSetting.values.forEach( conf => { - const re = new RegExp('' + hashtag.substring(1) + '', 'g'); - if ( typeof conf.value === 'string') { - if ( (completeMatch && conf.value === hashtag.substring(1)) || - ( !completeMatch && conf.value.match(re)) ) { - hashtagIsValid = true; + */ + getHashtagsValid(term: string, settingsName: string): string[] { + const hashtags = term.match(/(#[^\s]+)/g); + if (!hashtags) { + return undefined; + } + + const searchSourceSetting = this.getSettingsValues(settingsName); + let hashtagsValid = []; + hashtags.forEach(hashtag => { + searchSourceSetting.values.forEach(conf => { + const hashtagKey = hashtag.substring(1); + if (typeof conf.value === 'string') { + const types = conf.value.split(','); + const index = types.indexOf(hashtagKey); + if (index !== -1) { + hashtagsValid.push(types[index]); + } } - } + if (conf.hashtags && conf.hashtags.indexOf(hashtagKey) !== -1) { + hashtagsValid.push(conf.value); + } + }); }); - return hashtagIsValid; + + return hashtagsValid; } getSettingsValues(search: string): SearchSourceSettings { - return this.getDefaultOptions().settings.find( (value: SearchSourceSettings) => { - return value.name === search; - }); + return this.getDefaultOptions().settings.find( + (value: SearchSourceSettings) => { + return value.name === search; + } + ); } - } /** From a77a2dbc113afa3bdfc64c27679b3c603c752a95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Barbeau?= Date: Fri, 23 Aug 2019 16:31:16 -0400 Subject: [PATCH 15/18] feat(search hashtag): add hashtag to nominatim and ilayer --- demo/src/app/geo/search/search.component.html | 1 + .../src/lib/search/shared/sources/icherche.ts | 3 +- .../src/lib/search/shared/sources/ilayer.ts | 73 +++++++++++++++---- .../lib/search/shared/sources/nominatim.ts | 12 ++- .../src/lib/search/shared/sources/source.ts | 2 +- 5 files changed, 70 insertions(+), 21 deletions(-) diff --git a/demo/src/app/geo/search/search.component.html b/demo/src/app/geo/search/search.component.html index 3a1db2df9f..7b647ba35e 100644 --- a/demo/src/app/geo/search/search.component.html +++ b/demo/src/app/geo/search/search.component.html @@ -16,6 +16,7 @@ diff --git a/packages/geo/src/lib/search/shared/sources/icherche.ts b/packages/geo/src/lib/search/shared/sources/icherche.ts index 4930033495..af1af459b7 100644 --- a/packages/geo/src/lib/search/shared/sources/icherche.ts +++ b/packages/geo/src/lib/search/shared/sources/icherche.ts @@ -210,7 +210,7 @@ export class IChercheSearchSource extends SearchSource implements TextSearch { ): Observable[]> { const params = this.computeRequestParams(term, options || {}); if (!params.get('type').length) { - return of(); + return of([]); } return this.http.get(this.searchUrl, { params }).pipe( map((response: IChercheResponse) => this.extractResults(response)), @@ -360,7 +360,6 @@ export class IChercheReverseSearchSource extends SearchSource return { title: 'Territoire (Géocodage inversé)', searchUrl: 'https://geoegl.msp.gouv.qc.ca/apis/territoires/locate', - settings: [ { type: 'checkbox', diff --git a/packages/geo/src/lib/search/shared/sources/ilayer.ts b/packages/geo/src/lib/search/shared/sources/ilayer.ts index 8e86727e30..da5d7be056 100644 --- a/packages/geo/src/lib/search/shared/sources/ilayer.ts +++ b/packages/geo/src/lib/search/shared/sources/ilayer.ts @@ -1,7 +1,7 @@ import { Injectable, Inject } from '@angular/core'; import { HttpClient, HttpParams } from '@angular/common/http'; -import { Observable, BehaviorSubject } from 'rxjs'; +import { Observable, BehaviorSubject, of } from 'rxjs'; import { map } from 'rxjs/operators'; import { LanguageService } from '@igo2/core'; @@ -13,7 +13,13 @@ import { QueryHtmlTarget } from './../../../query/shared/query.enums'; import { SearchResult } from '../search.interfaces'; import { SearchSource, TextSearch } from './source'; import { TextSearchOptions } from './source.interfaces'; -import { ILayerSearchSourceOptions, ILayerData, ILayerItemResponse, ILayerServiceResponse, ILayerDataSource } from './ilayer.interfaces'; +import { + ILayerSearchSourceOptions, + ILayerData, + ILayerItemResponse, + ILayerServiceResponse, + ILayerDataSource +} from './ilayer.interfaces'; @Injectable() export class ILayerSearchResultFormatter { @@ -24,11 +30,13 @@ export class ILayerSearchResultFormatter { const property = Object.entries(data.properties) .filter(([key]) => allowedKey.indexOf(key) !== -1) - .reduce((out: {[key: string]: any}, entries: [string, any]) => { + .reduce((out: { [key: string]: any }, entries: [string, any]) => { const [key, value] = entries; let newKey; try { - newKey = this.languageService.translate.instant('igo.geo.search.ilayer.properties.' + key); + newKey = this.languageService.translate.instant( + 'igo.geo.search.ilayer.properties.' + key + ); } catch (e) { newKey = key; } @@ -48,7 +56,6 @@ export class ILayerSearchResultFormatter { */ @Injectable() export class ILayerSearchSource extends SearchSource implements TextSearch { - static id = 'ilayer'; static type = LAYER; @@ -66,7 +73,9 @@ export class ILayerSearchSource extends SearchSource implements TextSearch { private formatter: ILayerSearchResultFormatter ) { super(options); - this.languageService.translate.get(this.options.title).subscribe(title => this.title$.next(title)); + this.languageService.translate + .get(this.options.title) + .subscribe(title => this.title$.next(title)); } getId(): string { @@ -90,6 +99,9 @@ export class ILayerSearchSource extends SearchSource implements TextSearch { options?: TextSearchOptions ): Observable[]> { const params = this.computeSearchRequestParams(term, options || {}); + if (!params.get('q')) { + return of([]); + } return this.http .get(this.searchUrl, { params }) .pipe( @@ -97,15 +109,42 @@ export class ILayerSearchSource extends SearchSource implements TextSearch { ); } - private computeSearchRequestParams(term: string, options: TextSearchOptions): HttpParams { + private computeSearchRequestParams( + term: string, + options: TextSearchOptions + ): HttpParams { return new HttpParams({ - fromObject: Object.assign({ - q: term - }, this.params, options.params || {}) + fromObject: Object.assign( + { + q: this.computeTerm(term) + }, + this.params, + options.params || {} + ) }); } - private extractResults(response: ILayerServiceResponse): SearchResult[] { + /** + * Remove hashtag from query + * @param term Query with hashtag + */ + private computeTerm(term: string): string { + const hashtags = term.match(/(#[^\s]+)/g); + if (hashtags) { + const validHashtags = ['layer', 'layers', 'couche', 'couches']; + const valid = hashtags.filter(h => + validHashtags.some(v => h === '#' + v) + ); + if (!valid.length) { + return null; + } + } + return term.replace(/(#[^\s]*)/g, ''); + } + + private extractResults( + response: ILayerServiceResponse + ): SearchResult[] { return response.items.map((data: ILayerData) => this.dataToResult(data)); } @@ -127,7 +166,9 @@ export class ILayerSearchSource extends SearchSource implements TextSearch { private computeLayerOptions(data: ILayerData): ILayerItemResponse { const url = data.properties.url; - const queryParams: QueryableDataSourceOptions = this.extractQueryParamsFromSourceUrl(url); + const queryParams: QueryableDataSourceOptions = this.extractQueryParamsFromSourceUrl( + url + ); return { sourceOptions: { id: data.properties.id, @@ -146,7 +187,9 @@ export class ILayerSearchSource extends SearchSource implements TextSearch { }; } - private extractQueryParamsFromSourceUrl(url: string): {queryFormat: QueryFormat; queryHtmlTarget: QueryHtmlTarget; } { + private extractQueryParamsFromSourceUrl( + url: string + ): { queryFormat: QueryFormat; queryHtmlTarget: QueryHtmlTarget } { let queryFormat = QueryFormat.GML2; let queryHtmlTarget; const formatOpt = (this.options as ILayerSearchSourceOptions).queryFormat; @@ -158,9 +201,9 @@ export class ILayerSearchSource extends SearchSource implements TextSearch { break; } - const urls = (value as any as {urls: string[]}).urls; + const urls = ((value as any) as { urls: string[] }).urls; if (Array.isArray(urls)) { - urls.forEach((urlOpt) => { + urls.forEach(urlOpt => { if (url.indexOf(urlOpt) !== -1) { queryFormat = QueryFormat[key.toUpperCase()]; } diff --git a/packages/geo/src/lib/search/shared/sources/nominatim.ts b/packages/geo/src/lib/search/shared/sources/nominatim.ts index 9cf217fd7d..113686c5f5 100644 --- a/packages/geo/src/lib/search/shared/sources/nominatim.ts +++ b/packages/geo/src/lib/search/shared/sources/nominatim.ts @@ -1,7 +1,7 @@ import { Injectable, Inject } from '@angular/core'; import { HttpClient, HttpParams } from '@angular/common/http'; -import { Observable } from 'rxjs'; +import { Observable, of } from 'rxjs'; import { map } from 'rxjs/operators'; import { FEATURE, Feature, FeatureGeometry } from '../../../feature'; @@ -139,6 +139,9 @@ export class NominatimSearchSource extends SearchSource implements TextSearch { options?: TextSearchOptions ): Observable[]> { const params = this.computeSearchRequestParams(term, options || {}); + if (!params.get('q')) { + return of([]); + } return this.http .get(this.searchUrl, { params }) .pipe(map((response: NominatimData[]) => this.extractResults(response))); @@ -219,8 +222,7 @@ export class NominatimSearchSource extends SearchSource implements TextSearch { } private computeTerm(term: string): string { - term = this.computeTermTags(term); - return term; + return this.computeTermTags(term); } /** @@ -233,6 +235,10 @@ export class NominatimSearchSource extends SearchSource implements TextSearch { return this.computeTermSettings(term); } + if (!hashtags.length) { + return null; + } + term = term.replace(/(#[^\s]*)/g, ''); hashtags.forEach(tag => { term += '+[' + tag + ']'; diff --git a/packages/geo/src/lib/search/shared/sources/source.ts b/packages/geo/src/lib/search/shared/sources/source.ts index ebcb85ef5b..f58305253d 100644 --- a/packages/geo/src/lib/search/shared/sources/source.ts +++ b/packages/geo/src/lib/search/shared/sources/source.ts @@ -147,7 +147,7 @@ export class SearchSource { } const searchSourceSetting = this.getSettingsValues(settingsName); - let hashtagsValid = []; + const hashtagsValid = []; hashtags.forEach(hashtag => { searchSourceSetting.values.forEach(conf => { const hashtagKey = hashtag.substring(1); From 7d879072ccfc84d69b3df325303ef17c8659e8dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Barbeau?= Date: Fri, 23 Aug 2019 18:22:37 -0400 Subject: [PATCH 16/18] feat(search): decrease latency --- .../geo/src/lib/search/search-bar/search-bar.component.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/geo/src/lib/search/search-bar/search-bar.component.ts b/packages/geo/src/lib/search/search-bar/search-bar.component.ts index 299816a190..8f01702f9d 100644 --- a/packages/geo/src/lib/search/search-bar/search-bar.component.ts +++ b/packages/geo/src/lib/search/search-bar/search-bar.component.ts @@ -171,7 +171,7 @@ export class SearchBarComponent implements OnInit, OnDestroy { this.stream$$ = this.stream$ .pipe( debounce((term: string) => { - return term === '' ? EMPTY : timer(300); + return term === '' ? EMPTY : timer(200); }), distinctUntilChanged() ) @@ -236,8 +236,10 @@ export class SearchBarComponent implements OnInit, OnDestroy { } this.term = term; - if (term.replace(/(#[^\s]*)/g, '').trim().length >= this.minLength || - term.replace(/(#[^\s]*)/g, '').trim().length === 0) { + if ( + term.replace(/(#[^\s]*)/g, '').trim().length >= this.minLength || + term.replace(/(#[^\s]*)/g, '').trim().length === 0 + ) { this.stream$.next(term); } } From a80392c6f8dc7233ce03717db745e5acfda1a09d Mon Sep 17 00:00:00 2001 From: cbourget Date: Mon, 26 Aug 2019 12:29:05 -0400 Subject: [PATCH 17/18] style(workspace): move stuff into a method --- packages/common/src/lib/workspace/shared/workspace.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/common/src/lib/workspace/shared/workspace.ts b/packages/common/src/lib/workspace/shared/workspace.ts index 3db3a8b4aa..d10ec48fef 100644 --- a/packages/common/src/lib/workspace/shared/workspace.ts +++ b/packages/common/src/lib/workspace/shared/workspace.ts @@ -3,7 +3,7 @@ import { debounceTime } from 'rxjs/operators'; import { ActionStore } from '../../action'; import { Widget } from '../../widget'; -import { EntityRecord, EntityStore } from '../../entity'; +import { EntityStore } from '../../entity'; import { WorkspaceOptions } from './workspace.interfaces'; @@ -110,7 +110,7 @@ export class Workspace { if (this.actionStore !== undefined) { this.change$ = this.change .pipe(debounceTime(35)) - .subscribe(() => this.actionStore.updateActionsAvailability()); + .subscribe(() => this.updateActionsAvailability()); } this.change.next(); @@ -157,6 +157,12 @@ export class Workspace { this.change.next(); } + updateActionsAvailability() { + if (this.actionStore !== undefined) { + this.actionStore.updateActionsAvailability(); + } + } + /** * When the state changes, update the actions availability. */ From b70d4042d2d3ee15ce5c3c1878bf417212cf352d Mon Sep 17 00:00:00 2001 From: cbourget Date: Mon, 26 Aug 2019 12:29:54 -0400 Subject: [PATCH 18/18] feat(form): form autocomplete may now be disabled --- packages/common/src/lib/form/form/form.component.html | 1 + packages/common/src/lib/form/form/form.component.ts | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/packages/common/src/lib/form/form/form.component.html b/packages/common/src/lib/form/form/form.component.html index 10dcab580e..79d346895c 100644 --- a/packages/common/src/lib/form/form/form.component.html +++ b/packages/common/src/lib/form/form/form.component.html @@ -1,5 +1,6 @@
diff --git a/packages/common/src/lib/form/form/form.component.ts b/packages/common/src/lib/form/form/form.component.ts index cb673c3d72..2031c8f846 100644 --- a/packages/common/src/lib/form/form/form.component.ts +++ b/packages/common/src/lib/form/form/form.component.ts @@ -36,6 +36,11 @@ export class FormComponent implements OnChanges { */ @Input() formData: { [key: string]: any}; + /** + * Form autocomplete + */ + @Input() autocomplete: string = 'off'; + /** * Event emitted when the form is submitted */