diff --git a/apps/datahub-e2e/src/e2e/datasetDetailPage.cy.ts b/apps/datahub-e2e/src/e2e/datasetDetailPage.cy.ts index 0e9813850e..4db1f53251 100644 --- a/apps/datahub-e2e/src/e2e/datasetDetailPage.cy.ts +++ b/apps/datahub-e2e/src/e2e/datasetDetailPage.cy.ts @@ -1,4 +1,5 @@ import 'cypress-real-events' +import { tile } from 'ol/loadingstrategy' import path from 'path' beforeEach(() => { @@ -355,6 +356,9 @@ describe('dataset pages', () => { }) cy.screenshot({ capture: 'fullPage' }) }) + it('should display the sharing options', () => { + cy.get('gn-ui-data-view-share').should('be.visible') + }) }) describe('features', () => { it('MAP : should open a popup on layer click', () => { diff --git a/apps/datahub/src/app/record/record-metadata/record-metadata.component.html b/apps/datahub/src/app/record/record-metadata/record-metadata.component.html index efc77e05c4..0a28b804b9 100644 --- a/apps/datahub/src/app/record/record-metadata/record-metadata.component.html +++ b/apps/datahub/src/app/record/record-metadata/record-metadata.component.html @@ -110,7 +110,8 @@
{ fixture.debugElement.query(By.directive(MockDataViewComponent)) ).toBeFalsy() }) - it('does not render the permalink component', () => { + it('does render the permalink component', () => { expect( fixture.debugElement.query(By.directive(MockDataViewShareComponent)) - ).toBeFalsy() + ).toBeTruthy() }) }) describe('when a DATA link present', () => { @@ -446,14 +446,14 @@ describe('RecordMetadataComponent', () => { .length ).toEqual(2) }) - it('does not render the permalink component', () => { + it('does render the permalink component', () => { expect( fixture.debugElement.query(By.directive(MockDataViewShareComponent)) - ).toBeFalsy() + ).toBeTruthy() }) - describe('when selectedTabIndex$ is 2 (chart tab)', () => { + describe('when selectedView$ is chart', () => { beforeEach(() => { - component.selectedTabIndex$.next(2) + component.selectedView$.next('chart') fixture.detectChanges() }) it('renders the permalink component', () => { diff --git a/apps/datahub/src/app/record/record-metadata/record-metadata.component.ts b/apps/datahub/src/app/record/record-metadata/record-metadata.component.ts index 602cd1b312..43c712f165 100644 --- a/apps/datahub/src/app/record/record-metadata/record-metadata.component.ts +++ b/apps/datahub/src/app/record/record-metadata/record-metadata.component.ts @@ -83,7 +83,7 @@ export class RecordMetadataComponent { errorTypes = ErrorType - selectedTabIndex$ = new BehaviorSubject(0) + selectedView$ = new BehaviorSubject('map') thumbnailUrl$ = this.metadataViewFacade.metadata$.pipe( map((metadata) => { @@ -108,7 +108,18 @@ export class RecordMetadataComponent { ) {} onTabIndexChange(index: number): void { - this.selectedTabIndex$.next(index) + let view + switch (index) { + case 0: + view = 'map' + break + case 1: + view = 'table' + break + default: + view = 'chart' + } + this.selectedView$.next(view) setTimeout(() => { window.dispatchEvent(new Event('resize')) }, 0) diff --git a/apps/webcomponents/src/app/components/gn-dataset-view-map/gn-dataset-view-map.component.css b/apps/webcomponents/src/app/components/gn-dataset-view-map/gn-dataset-view-map.component.css index f1146d699b..6ac7bba4dd 100644 --- a/apps/webcomponents/src/app/components/gn-dataset-view-map/gn-dataset-view-map.component.css +++ b/apps/webcomponents/src/app/components/gn-dataset-view-map/gn-dataset-view-map.component.css @@ -1 +1,7 @@ @import '../../../styles.css'; +@import 'ol/ol.css'; + +:host { + display: block; + height: 500px; +} diff --git a/apps/webcomponents/src/app/components/gn-dataset-view-map/gn-dataset-view-map.component.ts b/apps/webcomponents/src/app/components/gn-dataset-view-map/gn-dataset-view-map.component.ts index 7f7c3907b4..7c5494e54b 100644 --- a/apps/webcomponents/src/app/components/gn-dataset-view-map/gn-dataset-view-map.component.ts +++ b/apps/webcomponents/src/app/components/gn-dataset-view-map/gn-dataset-view-map.component.ts @@ -1,13 +1,17 @@ import { ChangeDetectionStrategy, + ChangeDetectorRef, Component, Injector, + Input, OnInit, ViewEncapsulation, } from '@angular/core' import { MdViewFacade } from '@geonetwork-ui/feature/record' import { SearchFacade } from '@geonetwork-ui/feature/search' import { BaseComponent } from '../base.component' +import { LinkUsage } from '@geonetwork-ui/util/shared' +import { DatasetDistribution } from '@geonetwork-ui/common/domain/model/record' @Component({ selector: 'wc-gn-dataset-view-map', @@ -18,10 +22,22 @@ import { BaseComponent } from '../base.component' providers: [SearchFacade], }) export class GnDatasetViewMapComponent extends BaseComponent implements OnInit { - constructor(injector: Injector, private mdViewFacade: MdViewFacade) { + constructor( + injector: Injector, + private mdViewFacade: MdViewFacade, + private changeDetector: ChangeDetectorRef + ) { super(injector) } - ngOnInit(): void { - this.mdViewFacade.loadFull('ee965118-2416-4d48-b07e-bbc696f002c2') + @Input() datasetId: string + link: DatasetDistribution + async init() { + super.init() + this.mdViewFacade.loadFull(this.datasetId) + this.link = await this.getRecordLink(this.datasetId, [ + LinkUsage.MAP_API, + LinkUsage.GEODATA, + ]) + this.changeDetector.detectChanges() } } diff --git a/apps/webcomponents/src/app/components/gn-dataset-view-map/gn-dataset-view-map.sample.html b/apps/webcomponents/src/app/components/gn-dataset-view-map/gn-dataset-view-map.sample.html new file mode 100644 index 0000000000..f46c32478d --- /dev/null +++ b/apps/webcomponents/src/app/components/gn-dataset-view-map/gn-dataset-view-map.sample.html @@ -0,0 +1,53 @@ + + + + + Web Component Demo + + + + + + + + +
+
+

+ Visualize Map dataset from a Metadata Record with + gn-dataset-view-map web component +

+
+ + + +
+ + diff --git a/apps/webcomponents/src/app/webcomponents.module.ts b/apps/webcomponents/src/app/webcomponents.module.ts index 37862f3fff..c6fd1c4238 100644 --- a/apps/webcomponents/src/app/webcomponents.module.ts +++ b/apps/webcomponents/src/app/webcomponents.module.ts @@ -36,6 +36,7 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations' import { provideGn4 } from '@geonetwork-ui/api/repository' import { GnFigureDatasetsComponent } from './components/gn-figure-datasets/gn-figure-datasets.component' import { UiDatavizModule } from '@geonetwork-ui/ui/dataviz' +import { GnDatasetViewMapComponent } from './components/gn-dataset-view-map/gn-dataset-view-map.component' const CUSTOM_ELEMENTS: [new (...args) => BaseComponent, string][] = [ [GnFacetsComponent, 'gn-facets'], @@ -46,6 +47,7 @@ const CUSTOM_ELEMENTS: [new (...args) => BaseComponent, string][] = [ [GnDatasetViewChartComponent, 'gn-dataset-view-chart'], [GnMapViewerComponent, 'gn-map-viewer'], [GnFigureDatasetsComponent, 'gn-figure-datasets'], + [GnDatasetViewMapComponent, 'gn-dataset-view-map'], ] @NgModule({ @@ -61,6 +63,7 @@ const CUSTOM_ELEMENTS: [new (...args) => BaseComponent, string][] = [ GnDatasetViewChartComponent, GnMapViewerComponent, GnFigureDatasetsComponent, + GnDatasetViewMapComponent, ], imports: [ CommonModule, diff --git a/apps/webcomponents/src/index.html b/apps/webcomponents/src/index.html index 5368d639da..11553c7c9a 100644 --- a/apps/webcomponents/src/index.html +++ b/apps/webcomponents/src/index.html @@ -81,6 +81,9 @@

GeoNetwork demo

>Preview dataset as chart +
  • + Preview dataset as map +
  • Map viewer
  • diff --git a/libs/feature/record/src/lib/data-view-permalink/data-view-permalink.component.spec.ts b/libs/feature/record/src/lib/data-view-permalink/data-view-permalink.component.spec.ts index ac42247bc6..381b66ecbf 100644 --- a/libs/feature/record/src/lib/data-view-permalink/data-view-permalink.component.spec.ts +++ b/libs/feature/record/src/lib/data-view-permalink/data-view-permalink.component.spec.ts @@ -75,6 +75,7 @@ describe('DataViewPermalinkComponent', () => { facade = TestBed.inject(MdViewFacade) fixture = TestBed.createComponent(DataViewPermalinkComponent) component = fixture.componentInstance + component.viewType$.next('chart') fixture.detectChanges() }) @@ -82,39 +83,79 @@ describe('DataViewPermalinkComponent', () => { expect(component).toBeTruthy() }) - describe('init permalinkUrl$', () => { - it('should generate URL based on configs', async () => { - const url = await firstValueFrom(component.permalinkUrl$) - expect(url).toBe( - `https://example.com/wc-embedder?v=${gnUiVersion}&e=gn-dataset-view-chart&a=api-url%3D${encodeURIComponent( - component.config.basePath - )}&a=dataset-id%3D${ - metadata.uniqueIdentifier - }&a=primary-color%3D%230f4395&a=secondary-color%3D%238bc832&a=main-color%3D%23555&a=background-color%3D%23fdfbff&a=aggregation%3D${ - chartConfig1.aggregation - }&a=x-property%3D${chartConfig1.xProperty}&a=y-property%3D${ - chartConfig1.yProperty - }&a=chart-type%3D${chartConfig1.chartType}` - ) + describe('Chart view', () => { + describe('init permalinkUrl$', () => { + it('should generate URL based on configs', async () => { + const url = await firstValueFrom(component.permalinkUrl$) + expect(url).toBe( + `https://example.com/wc-embedder?v=${gnUiVersion}&e=gn-dataset-view-chart&a=aggregation%3D${ + chartConfig1.aggregation + }&a=x-property%3D${chartConfig1.xProperty}&a=y-property%3D${ + chartConfig1.yProperty + }&a=chart-type%3D${ + chartConfig1.chartType + }&a=api-url%3D${encodeURIComponent( + component.config.basePath + )}&a=dataset-id%3D${ + metadata.uniqueIdentifier + }&a=primary-color%3D%230f4395&a=secondary-color%3D%238bc832&a=main-color%3D%23555&a=background-color%3D%23fdfbff` + ) + }) + }) + describe('update permalinkUrl$', () => { + beforeEach(() => { + facade.chartConfig$.next(chartConfig2) + }) + it('should update URL based on configs', async () => { + const url = await firstValueFrom(component.permalinkUrl$) + expect(url).toBe( + `https://example.com/wc-embedder?v=${gnUiVersion}&e=gn-dataset-view-chart&a=aggregation%3D${ + chartConfig2.aggregation + }&a=x-property%3D${chartConfig2.xProperty}&a=y-property%3D${ + chartConfig2.yProperty + }&a=chart-type%3D${ + chartConfig2.chartType + }&a=api-url%3D${encodeURIComponent( + component.config.basePath + )}&a=dataset-id%3D${ + metadata.uniqueIdentifier + }&a=primary-color%3D%230f4395&a=secondary-color%3D%238bc832&a=main-color%3D%23555&a=background-color%3D%23fdfbff` + ) + }) + }) + }) + describe('Map view', () => { + beforeEach(() => { + component.viewType$.next('map') + }) + describe('init permalinkUrl$', () => { + it('should generate URL based on configs', async () => { + const url = await firstValueFrom(component.permalinkUrl$) + expect(url).toBe( + `https://example.com/wc-embedder?v=${gnUiVersion}&e=gn-dataset-view-map&a=api-url%3D${encodeURIComponent( + component.config.basePath + )}&a=dataset-id%3D${ + metadata.uniqueIdentifier + }&a=primary-color%3D%230f4395&a=secondary-color%3D%238bc832&a=main-color%3D%23555&a=background-color%3D%23fdfbff` + ) + }) }) }) - describe('update permalinkUrl$', () => { + describe('Table view', () => { beforeEach(() => { - facade.chartConfig$.next(chartConfig2) + component.viewType$.next('table') }) - it('should update URL based on configs', async () => { - const url = await firstValueFrom(component.permalinkUrl$) - expect(url).toBe( - `https://example.com/wc-embedder?v=${gnUiVersion}&e=gn-dataset-view-chart&a=api-url%3D${encodeURIComponent( - component.config.basePath - )}&a=dataset-id%3D${ - metadata.uniqueIdentifier - }&a=primary-color%3D%230f4395&a=secondary-color%3D%238bc832&a=main-color%3D%23555&a=background-color%3D%23fdfbff&a=aggregation%3D${ - chartConfig2.aggregation - }&a=x-property%3D${chartConfig2.xProperty}&a=y-property%3D${ - chartConfig2.yProperty - }&a=chart-type%3D${chartConfig2.chartType}` - ) + describe('init permalinkUrl$', () => { + it('should generate URL based on configs', async () => { + const url = await firstValueFrom(component.permalinkUrl$) + expect(url).toBe( + `https://example.com/wc-embedder?v=${gnUiVersion}&e=gn-dataset-view-table&a=api-url%3D${encodeURIComponent( + component.config.basePath + )}&a=dataset-id%3D${ + metadata.uniqueIdentifier + }&a=primary-color%3D%230f4395&a=secondary-color%3D%238bc832&a=main-color%3D%23555&a=background-color%3D%23fdfbff` + ) + }) }) }) }) diff --git a/libs/feature/record/src/lib/data-view-permalink/data-view-permalink.component.ts b/libs/feature/record/src/lib/data-view-permalink/data-view-permalink.component.ts index 1bff396f40..ef55091071 100644 --- a/libs/feature/record/src/lib/data-view-permalink/data-view-permalink.component.ts +++ b/libs/feature/record/src/lib/data-view-permalink/data-view-permalink.component.ts @@ -3,10 +3,11 @@ import { Component, Inject, InjectionToken, + Input, Optional, } from '@angular/core' import { Configuration } from '@geonetwork-ui/data-access/gn4' -import { combineLatest, map } from 'rxjs' +import { BehaviorSubject, combineLatest, map } from 'rxjs' import { MdViewFacade } from '../state' import { GN_UI_VERSION } from '../gn-ui-version.token' @@ -21,29 +22,45 @@ export const WEB_COMPONENT_EMBEDDER_URL = new InjectionToken( changeDetection: ChangeDetectionStrategy.OnPush, }) export class DataViewPermalinkComponent { + viewType$ = new BehaviorSubject('map') + @Input() + set viewType(value: string) { + this.viewType$.next(value) + } + permalinkUrl$ = combineLatest([ + this.viewType$, this.facade.chartConfig$, this.facade.metadata$, ]).pipe( - map(([config, metadata]) => { - if (config) { - const { aggregation, xProperty, yProperty, chartType } = config - const url = new URL(`${this.wcEmbedderBaseUrl}`, window.location.origin) - url.searchParams.set('v', `${this.version}`) - url.searchParams.append('e', `gn-dataset-view-chart`) - url.searchParams.append('a', `api-url=${this.config.basePath}`) - url.searchParams.append('a', `dataset-id=${metadata.uniqueIdentifier}`) - url.searchParams.append('a', `primary-color=#0f4395`) - url.searchParams.append('a', `secondary-color=#8bc832`) - url.searchParams.append('a', `main-color=#555`) - url.searchParams.append('a', `background-color=#fdfbff`) - url.searchParams.append('a', `aggregation=${aggregation}`) - url.searchParams.append('a', `x-property=${xProperty}`) - url.searchParams.append('a', `y-property=${yProperty}`) - url.searchParams.append('a', `chart-type=${chartType}`) - return url.toString() + map(([viewType, config, metadata]) => { + const url = new URL(`${this.wcEmbedderBaseUrl}`, window.location.origin) + url.searchParams.set('v', `${this.version}`) + if (viewType === 'chart') { + if (config) { + const { aggregation, xProperty, yProperty, chartType } = config + url.searchParams.append('e', `gn-dataset-view-chart`) + url.searchParams.append('a', `aggregation=${aggregation}`) + url.searchParams.append('a', `x-property=${xProperty}`) + url.searchParams.append('a', `y-property=${yProperty}`) + url.searchParams.append('a', `chart-type=${chartType}`) + } else { + return '' + } + } else if (viewType === 'table') { + // table + url.searchParams.append('e', `gn-dataset-view-table`) + } else { + // map + url.searchParams.append('e', `gn-dataset-view-map`) } - return '' + url.searchParams.append('a', `api-url=${this.config.basePath}`) + url.searchParams.append('a', `dataset-id=${metadata.uniqueIdentifier}`) + url.searchParams.append('a', `primary-color=#0f4395`) + url.searchParams.append('a', `secondary-color=#8bc832`) + url.searchParams.append('a', `main-color=#555`) + url.searchParams.append('a', `background-color=#fdfbff`) + return url.toString() }) ) diff --git a/libs/feature/record/src/lib/data-view-share/data-view-share.component.html b/libs/feature/record/src/lib/data-view-share/data-view-share.component.html index 4af8536077..8fd544693c 100644 --- a/libs/feature/record/src/lib/data-view-share/data-view-share.component.html +++ b/libs/feature/record/src/lib/data-view-share/data-view-share.component.html @@ -10,7 +10,9 @@ share.tab.permalink - + @@ -24,7 +26,9 @@ >share.tab.webComponent - +
    diff --git a/libs/feature/record/src/lib/data-view-share/data-view-share.component.ts b/libs/feature/record/src/lib/data-view-share/data-view-share.component.ts index 2480fd2e67..95085e9e0b 100644 --- a/libs/feature/record/src/lib/data-view-share/data-view-share.component.ts +++ b/libs/feature/record/src/lib/data-view-share/data-view-share.component.ts @@ -2,6 +2,7 @@ import { ChangeDetectionStrategy, Component, Inject, + Input, Optional, } from '@angular/core' import { WEB_COMPONENT_EMBEDDER_URL } from '../data-view-permalink/data-view-permalink.component' @@ -13,6 +14,16 @@ import { WEB_COMPONENT_EMBEDDER_URL } from '../data-view-permalink/data-view-per changeDetection: ChangeDetectionStrategy.OnPush, }) export class DataViewShareComponent { + private _viewType: string + + @Input() + set viewType(value: string) { + this._viewType = value + } + + get viewType(): string { + return this._viewType + } constructor( @Optional() @Inject(WEB_COMPONENT_EMBEDDER_URL) diff --git a/libs/feature/record/src/lib/data-view-web-component/data-view-web-component.component.spec.ts b/libs/feature/record/src/lib/data-view-web-component/data-view-web-component.component.spec.ts index b274b4299b..7521751966 100644 --- a/libs/feature/record/src/lib/data-view-web-component/data-view-web-component.component.spec.ts +++ b/libs/feature/record/src/lib/data-view-web-component/data-view-web-component.component.spec.ts @@ -69,6 +69,7 @@ describe('DataViewWebComponentComponent', () => { facade = TestBed.inject(MdViewFacade) fixture = TestBed.createComponent(DataViewWebComponentComponent) component = fixture.componentInstance + component.viewType$.next('chart') fixture.detectChanges() }) @@ -76,51 +77,99 @@ describe('DataViewWebComponentComponent', () => { expect(component).toBeTruthy() }) - describe('init webComponentHtml$', () => { - it('should generate HTML based on configs', async () => { - const html = await firstValueFrom(component.webComponentHtml$) - expect(html).toBe( - ` -` - ) + describe('Chart view', () => { + describe('init webComponentHtml$', () => { + it('should generate HTML based on configs', async () => { + const html = await firstValueFrom(component.webComponentHtml$) + expect(html).toBe( + ` + ` + ) + }) + }) + describe('update webComponentHtml$', () => { + beforeEach(() => { + facade.chartConfig$.next(chartConfig2) + }) + it('should update HTML based on configs', async () => { + const html = await firstValueFrom(component.webComponentHtml$) + expect(html).toBe( + ` + ` + ) + }) }) }) - describe('update webComponentHtml$', () => { + describe('Map view', () => { beforeEach(() => { - facade.chartConfig$.next(chartConfig2) + component.viewType$.next('map') }) - it('should update HTML based on configs', async () => { - const html = await firstValueFrom(component.webComponentHtml$) - expect(html).toBe( - ` - { + it('should generate HTML based on configs', async () => { + const html = await firstValueFrom(component.webComponentHtml$) + expect(html).toBe( + ` +` - ) +>` + ) + }) + }) + }) + describe('Table view', () => { + beforeEach(() => { + component.viewType$.next('table') + }) + describe('init webComponentHtml$', () => { + it('should generate HTML based on configs', async () => { + const html = await firstValueFrom(component.webComponentHtml$) + expect(html).toBe( + ` + ` + ) + }) }) }) }) diff --git a/libs/feature/record/src/lib/data-view-web-component/data-view-web-component.component.ts b/libs/feature/record/src/lib/data-view-web-component/data-view-web-component.component.ts index 37b84acfd2..98a9baa7b5 100644 --- a/libs/feature/record/src/lib/data-view-web-component/data-view-web-component.component.ts +++ b/libs/feature/record/src/lib/data-view-web-component/data-view-web-component.component.ts @@ -1,7 +1,12 @@ -import { ChangeDetectionStrategy, Component, Inject } from '@angular/core' +import { + ChangeDetectionStrategy, + Component, + Inject, + Input, +} from '@angular/core' import { Configuration } from '@geonetwork-ui/data-access/gn4' import { MdViewFacade } from '../state' -import { combineLatest, map } from 'rxjs' +import { BehaviorSubject, combineLatest, map } from 'rxjs' import { GN_UI_VERSION } from '../gn-ui-version.token' @Component({ @@ -11,35 +16,77 @@ import { GN_UI_VERSION } from '../gn-ui-version.token' changeDetection: ChangeDetectionStrategy.OnPush, }) export class DataViewWebComponentComponent { + viewType$ = new BehaviorSubject('map') + @Input() + set viewType(value: string) { + this.viewType$.next(value) + } webComponentHtml$ = combineLatest( + this.viewType$, this.facade.chartConfig$, this.facade.metadata$ ).pipe( - map(([config, metadata]) => { - if (config) { - const { aggregation, xProperty, yProperty, chartType } = config + map(([viewType, config, metadata]) => { + if (viewType === 'chart') { + if (config) { + const { aggregation, xProperty, yProperty, chartType } = config + return ` + ` + } + return '' + } else if (viewType === 'table') { return ` -` + } else { + return ` +` +>` } - return '' }) )