diff --git a/apps/map-viewer/src/app/app.module.ts b/apps/map-viewer/src/app/app.module.ts index d4e8f2a5f1..46bbf1fb44 100644 --- a/apps/map-viewer/src/app/app.module.ts +++ b/apps/map-viewer/src/app/app.module.ts @@ -4,8 +4,9 @@ import { BrowserModule } from '@angular/platform-browser' import { AppComponent } from './app.component' import { FeatureMapModule, - MapStateContainerComponent, + GeocodingComponent, LayersPanelComponent, + MapStateContainerComponent, } from '@geonetwork-ui/feature/map' import { ThemeService } from '@geonetwork-ui/util/shared' import { TranslateModule } from '@ngx-translate/core' @@ -41,6 +42,7 @@ export const metaReducers: MetaReducer[] = !environment.production FeatureCatalogModule, LayersPanelComponent, MapStateContainerComponent, + GeocodingComponent, ], providers: [ importProvidersFrom(FeatureAuthModule), diff --git a/libs/feature/catalog/src/lib/feature-catalog.module.ts b/libs/feature/catalog/src/lib/feature-catalog.module.ts index 7c97c0d726..543275fb8d 100644 --- a/libs/feature/catalog/src/lib/feature-catalog.module.ts +++ b/libs/feature/catalog/src/lib/feature-catalog.module.ts @@ -1,6 +1,9 @@ import { InjectionToken, NgModule } from '@angular/core' import { SiteTitleComponent } from './site-title/site-title.component' -import { UiCatalogModule } from '@geonetwork-ui/ui/catalog' +import { + OrganisationsFilterComponent, + UiCatalogModule, +} from '@geonetwork-ui/ui/catalog' import { GroupsApiService, SearchApiService, @@ -64,6 +67,7 @@ const organizationsServiceFactory = ( UtilI18nModule, TranslateModule.forChild(), UiElementsModule, + OrganisationsFilterComponent, ], exports: [SiteTitleComponent, SourceLabelComponent, OrganisationsComponent], providers: [ diff --git a/libs/feature/map/src/lib/feature-map.module.ts b/libs/feature/map/src/lib/feature-map.module.ts index 9b795377d2..e9af470e2d 100644 --- a/libs/feature/map/src/lib/feature-map.module.ts +++ b/libs/feature/map/src/lib/feature-map.module.ts @@ -11,13 +11,10 @@ import * as fromMap from './+state/map.reducer' import { MapFacade } from './+state/map.facade' import { UiElementsModule } from '@geonetwork-ui/ui/elements' import { TextInputComponent, UiInputsModule } from '@geonetwork-ui/ui/inputs' -import { GeocodingComponent } from './geocoding/geocoding.component' import { GEOCODING_PROVIDER, GeocodingProvider } from './geocoding.service' import { AddLayerFromOgcApiComponent } from './add-layer-from-ogc-api/add-layer-from-ogc-api.component' @NgModule({ - declarations: [GeocodingComponent], - exports: [GeocodingComponent], imports: [ CommonModule, UiLayoutModule, diff --git a/libs/feature/map/src/lib/geocoding/geocoding.component.spec.ts b/libs/feature/map/src/lib/geocoding/geocoding.component.spec.ts index 193b2e258c..d0ea25be65 100644 --- a/libs/feature/map/src/lib/geocoding/geocoding.component.spec.ts +++ b/libs/feature/map/src/lib/geocoding/geocoding.component.spec.ts @@ -1,63 +1,36 @@ import { ComponentFixture, TestBed } from '@angular/core/testing' import { GeocodingComponent } from './geocoding.component' -import { MapManagerService } from '../manager/map-manager.service' -import { NO_ERRORS_SCHEMA } from '@angular/core' -import Map from 'ol/Map' -import TileLayer from 'ol/layer/Tile' -import XYZ from 'ol/source/XYZ' -import VectorLayer from 'ol/layer/Vector' -import VectorSource from 'ol/source/Vector' -import GeoJSON from 'ol/format/GeoJSON' -import { pointFeatureCollectionFixture } from '@geonetwork-ui/common/fixtures' -import Feature from 'ol/Feature' -import { Geometry } from 'ol/geom' -import { TranslateModule } from '@ngx-translate/core' import { GeocodingService } from '../geocoding.service' import { of } from 'rxjs' - -const vectorLayer = new VectorLayer({ - source: new VectorSource({ - features: new GeoJSON().readFeatures(pointFeatureCollectionFixture(), { - featureProjection: 'EPSG:3857', - dataProjection: 'EPSG:4326', - }), - }) as VectorSource>, -}) - -const mapMock = new Map({ - layers: [ - new TileLayer({ - source: new XYZ({ - url: 'http://test', - }), - }), - vectorLayer, - ], -}) - -const mapManagerMock = { - map: mapMock, -} - -const geocodingServiceMock = { - query: jest.fn().mockReturnValue(of([])), -} +import { MockBuilder, MockProvider } from 'ng-mocks' +import { MapFacade } from '../+state/map.facade' describe('GeocodingComponent', () => { let component: GeocodingComponent let fixture: ComponentFixture + let mapFacade: MapFacade + + beforeEach(() => { + return MockBuilder(GeocodingComponent) + }) beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot()], - declarations: [GeocodingComponent], providers: [ - { provide: MapManagerService, useValue: mapManagerMock }, - { provide: GeocodingService, useValue: geocodingServiceMock }, + MockProvider(GeocodingService, { + query: jest.fn().mockReturnValue(of([])), + }), + MockProvider(MapFacade, { + context$: of({ + layers: [], + view: null, + }), + applyContext: jest.fn(), + }), ], - schemas: [NO_ERRORS_SCHEMA], }).compileComponents() + mapFacade = TestBed.inject(MapFacade) fixture = TestBed.createComponent(GeocodingComponent) component = fixture.componentInstance fixture.detectChanges() @@ -91,36 +64,21 @@ describe('GeocodingComponent', () => { }) describe('zoomToLocation', () => { - let viewMock: any - let zoomToPointSpy: jest.SpyInstance - let zoomToPolygonSpy: jest.SpyInstance - - beforeEach(() => { - viewMock = { - setCenter: jest.fn(), - setZoom: jest.fn(), - fit: jest.fn(), - } - mapMock.getView = jest.fn().mockReturnValue(viewMock) - zoomToPointSpy = jest.spyOn(component, 'zoomToPoint') - zoomToPolygonSpy = jest.spyOn(component, 'zoomToPolygon') - }) - - it('should zoom to the location of the result if geometry type is Point', () => { + it('should zoom to the location of the result if geometry type is Point', async () => { const result = { geom: { type: 'Point', coordinates: [0, 0], }, } - component.zoomToLocation(result) - expect(zoomToPointSpy).toHaveBeenCalledWith( - result.geom.coordinates, - viewMock - ) + await component.zoomToLocation(result) + expect(mapFacade.applyContext).toHaveBeenCalledWith({ + layers: [], + view: { center: [0, 0], zoom: 10 }, + }) }) - it('should zoom to the location of the result if geometry type is Polygon', () => { + it('should zoom to the location of the result if geometry type is Polygon', async () => { const result = { geom: { type: 'Polygon', @@ -134,14 +92,26 @@ describe('GeocodingComponent', () => { ], }, } - component.zoomToLocation(result) - expect(zoomToPolygonSpy).toHaveBeenCalledWith( - result.geom.coordinates, - viewMock - ) + await component.zoomToLocation(result) + expect(mapFacade.applyContext).toHaveBeenCalledWith({ + layers: [], + view: { + geometry: { + coordinates: [ + [ + [0, 0], + [1, 1], + [2, 2], + [0, 0], + ], + ], + type: 'Polygon', + }, + }, + }) }) - it('should log an error if geometry type is unsupported', () => { + it('should log an error if geometry type is unsupported', async () => { const consoleSpy = jest.spyOn(console, 'error').mockImplementation() const result = { geom: { @@ -149,7 +119,7 @@ describe('GeocodingComponent', () => { coordinates: [0, 0], }, } - component.zoomToLocation(result) + await component.zoomToLocation(result) expect(consoleSpy).toHaveBeenCalledWith( `Unsupported geometry type: ${result.geom.type}` ) diff --git a/libs/feature/map/src/lib/geocoding/geocoding.component.ts b/libs/feature/map/src/lib/geocoding/geocoding.component.ts index 551b3243e6..5af0a7527b 100644 --- a/libs/feature/map/src/lib/geocoding/geocoding.component.ts +++ b/libs/feature/map/src/lib/geocoding/geocoding.component.ts @@ -3,11 +3,22 @@ import { catchError, firstValueFrom, from, Subject, takeUntil } from 'rxjs' import { debounceTime, switchMap } from 'rxjs/operators' import { GeocodingService } from '../geocoding.service' import { MapFacade } from '../+state/map.facade' +import { CommonModule } from '@angular/common' +import { SearchInputComponent, UiInputsModule } from '@geonetwork-ui/ui/inputs' +import { TranslateModule } from '@ngx-translate/core' +import { MapContextView } from '@geospatial-sdk/core' @Component({ selector: 'gn-ui-geocoding', templateUrl: './geocoding.component.html', styleUrls: ['./geocoding.component.css'], + standalone: true, + imports: [ + CommonModule, + UiInputsModule, + TranslateModule, + SearchInputComponent, + ], }) export class GeocodingComponent implements OnDestroy { searchText = '' @@ -60,13 +71,13 @@ export class GeocodingComponent implements OnDestroy { this.errorMessage = null } - zoomToLocation(result: any) { + async zoomToLocation(result: any) { const geometry = result.geom if (geometry.type === 'Point') { - this.zoomToPoint(geometry.coordinates) + await this.zoomToPoint(geometry.coordinates) } else if (geometry.type === 'Polygon') { - this.zoomToPolygon(geometry.coordinates) + await this.zoomToPolygon(geometry.coordinates) } else { console.error(`Unsupported geometry type: ${geometry.type}`) } @@ -74,17 +85,27 @@ export class GeocodingComponent implements OnDestroy { async zoomToPoint(pointCoords: [number, number]) { const context = await firstValueFrom(this.mapFacade.context$) + const view: MapContextView = { + center: pointCoords, + zoom: 10, + } this.mapFacade.applyContext({ ...context, - // TODO: change context to fit point + view, }) } async zoomToPolygon(polygonCoords: [[number, number][]]) { const context = await firstValueFrom(this.mapFacade.context$) + const view: MapContextView = { + geometry: { + type: 'Polygon', + coordinates: polygonCoords, + }, + } this.mapFacade.applyContext({ ...context, - // TODO: change context to fit polygon + view, }) } diff --git a/libs/ui/catalog/src/lib/organisations-filter/organisations-filter.component.spec.ts b/libs/ui/catalog/src/lib/organisations-filter/organisations-filter.component.spec.ts index 60ec309274..76a44d41ac 100644 --- a/libs/ui/catalog/src/lib/organisations-filter/organisations-filter.component.spec.ts +++ b/libs/ui/catalog/src/lib/organisations-filter/organisations-filter.component.spec.ts @@ -1,32 +1,18 @@ import { ComponentFixture, TestBed } from '@angular/core/testing' import { OrganisationsFilterComponent } from './organisations-filter.component' -import { Component, EventEmitter, Input, Output } from '@angular/core' import { TranslateModule } from '@ngx-translate/core' - -@Component({ - selector: 'gn-ui-dropdown-selector', - template: '', -}) -class DropdownSelectorMockComponent { - @Input() showTitle: unknown - @Input() choices: { - value: unknown - label: string - }[] - @Input() selected: unknown - @Output() selectValue = new EventEmitter() -} +import { MockBuilder } from 'ng-mocks' describe('OrganisationsOrderComponent', () => { let component: OrganisationsFilterComponent let fixture: ComponentFixture + beforeEach(() => { + return MockBuilder(OrganisationsFilterComponent) + }) + beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ - OrganisationsFilterComponent, - DropdownSelectorMockComponent, - ], imports: [TranslateModule.forRoot()], }).compileComponents() diff --git a/libs/ui/catalog/src/lib/organisations-filter/organisations-filter.component.ts b/libs/ui/catalog/src/lib/organisations-filter/organisations-filter.component.ts index b6f2049525..fd0287f5c3 100644 --- a/libs/ui/catalog/src/lib/organisations-filter/organisations-filter.component.ts +++ b/libs/ui/catalog/src/lib/organisations-filter/organisations-filter.component.ts @@ -6,12 +6,19 @@ import { } from '@angular/core' import { marker } from '@biesbjerg/ngx-translate-extract-marker' import { SortByField } from '@geonetwork-ui/common/domain/model/search' -import { Subject, debounceTime } from 'rxjs' +import { debounceTime, Subject } from 'rxjs' +import { + DropdownSelectorComponent, + SearchInputComponent, +} from '@geonetwork-ui/ui/inputs' +import { TranslateModule } from '@ngx-translate/core' @Component({ selector: 'gn-ui-organisations-filter', templateUrl: './organisations-filter.component.html', changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [SearchInputComponent, DropdownSelectorComponent, TranslateModule], }) export class OrganisationsFilterComponent { choices: { value: string; label: string }[] = [ diff --git a/libs/ui/catalog/src/lib/ui-catalog.module.ts b/libs/ui/catalog/src/lib/ui-catalog.module.ts index 6a9a1fdfdd..e940d3ba11 100644 --- a/libs/ui/catalog/src/lib/ui-catalog.module.ts +++ b/libs/ui/catalog/src/lib/ui-catalog.module.ts @@ -5,7 +5,6 @@ import { OrganisationPreviewComponent } from './organisation-preview/organisatio import { TranslateModule } from '@ngx-translate/core' import { MatIconModule } from '@angular/material/icon' import { UiElementsModule } from '@geonetwork-ui/ui/elements' -import { OrganisationsFilterComponent } from './organisations-filter/organisations-filter.component' import { UiInputsModule } from '@geonetwork-ui/ui/inputs' import { LanguageSwitcherComponent } from './language-switcher/language-switcher.component' import { OrganisationsResultComponent } from './organisations-result/organisations-result.component' @@ -15,7 +14,6 @@ import { RouterLink } from '@angular/router' declarations: [ CatalogTitleComponent, OrganisationPreviewComponent, - OrganisationsFilterComponent, LanguageSwitcherComponent, OrganisationsResultComponent, ], @@ -30,7 +28,6 @@ import { RouterLink } from '@angular/router' exports: [ CatalogTitleComponent, OrganisationPreviewComponent, - OrganisationsFilterComponent, LanguageSwitcherComponent, OrganisationsResultComponent, ], diff --git a/libs/ui/inputs/src/lib/search-input/search-input.component.spec.ts b/libs/ui/inputs/src/lib/search-input/search-input.component.spec.ts index 09b77fe969..eaf7c1a61f 100644 --- a/libs/ui/inputs/src/lib/search-input/search-input.component.spec.ts +++ b/libs/ui/inputs/src/lib/search-input/search-input.component.spec.ts @@ -8,7 +8,7 @@ describe('SearchInputComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ - declarations: [SearchInputComponent], + imports: [SearchInputComponent], }) fixture = TestBed.createComponent(SearchInputComponent) component = fixture.componentInstance diff --git a/libs/ui/inputs/src/lib/search-input/search-input.component.ts b/libs/ui/inputs/src/lib/search-input/search-input.component.ts index 622f74d53d..c39c65684e 100644 --- a/libs/ui/inputs/src/lib/search-input/search-input.component.ts +++ b/libs/ui/inputs/src/lib/search-input/search-input.component.ts @@ -4,12 +4,16 @@ import { Input, Output, } from '@angular/core' -import { Subject, distinctUntilChanged } from 'rxjs' +import { distinctUntilChanged, Subject } from 'rxjs' +import { MatIconModule } from '@angular/material/icon' +import { CommonModule } from '@angular/common' @Component({ selector: 'gn-ui-search-input', templateUrl: './search-input.component.html', changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [CommonModule, MatIconModule], }) export class SearchInputComponent { @Input() value = '' diff --git a/libs/ui/inputs/src/lib/ui-inputs.module.ts b/libs/ui/inputs/src/lib/ui-inputs.module.ts index c1a677c35c..42af613057 100644 --- a/libs/ui/inputs/src/lib/ui-inputs.module.ts +++ b/libs/ui/inputs/src/lib/ui-inputs.module.ts @@ -24,7 +24,6 @@ import { CopyTextButtonComponent } from './copy-text-button/copy-text-button.com import { MatTooltipModule } from '@angular/material/tooltip' import { CommonModule } from '@angular/common' import { CheckboxComponent } from './checkbox/checkbox.component' -import { SearchInputComponent } from './search-input/search-input.component' import { DateRangePickerComponent } from './date-range-picker/date-range-picker.component' import { MatFormFieldModule } from '@angular/material/form-field' import { MatInputModule } from '@angular/material/input' @@ -43,7 +42,6 @@ import { ImageInputComponent } from './image-input/image-input.component' ViewportIntersectorComponent, CopyTextButtonComponent, CheckboxComponent, - SearchInputComponent, ], imports: [ CommonModule, @@ -85,7 +83,6 @@ import { ImageInputComponent } from './image-input/image-input.component' CheckToggleComponent, CopyTextButtonComponent, CheckboxComponent, - SearchInputComponent, DateRangePickerComponent, EditableLabelDirective, ImageInputComponent,