diff --git a/src/app/dataset-detail/components/dataset-detail/dataset-detail.component.html b/src/app/dataset-detail/components/dataset-detail/dataset-detail.component.html index 63026ff4193c7dcce32c426ee6749f50b0528d1f..7754060a3774899b47674c3aac6c78ecbbc8e139 100644 --- a/src/app/dataset-detail/components/dataset-detail/dataset-detail.component.html +++ b/src/app/dataset-detail/components/dataset-detail/dataset-detail.component.html @@ -46,6 +46,26 @@ </div> </a> </li> + <li [routerLinkActive]="'is-active'"> + <a (click)="setPosition()" [routerLink]="[AppRoutes.downloads.uri]" class="tab-link"> + <svg class="tab-icon" xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 30 30"> + <path class="secondary" + d="M21.323 13.961h-.338c-.339 0-.677.339-.677.677v4.57H1.692v-4.57a.667.667 0 0 0-.677-.677H.677c-.339 0-.677.339-.677.677V20.223c0 .423.338.677.677.677h20.646c.338 0 .677-.339.677-.677v-5.585a.667.667 0 0 0-.677-.677z" /> + <path class="secondary" + d="M10.323 15.315c.085.085.254.17.338.17.085.084.254.084.339.084.085 0 .254 0 .338-.084.17 0 .254-.085.339-.17L17.6 9.223c.17-.254.17-.592 0-.761l-.423-.424c-.17-.253-.593-.253-.762 0l-4.569 4.654V.846C11.846.338 11.508 0 11 0s-.846.338-.846.846v11.846l-4.57-4.654c-.169-.253-.507-.253-.761 0l-.423.424c-.17.253-.17.592 0 .761l5.923 6.092z" /> + </svg> + <div> + <div> + <span class="tab-title tab-title-long" i18n="@@dataset.detail.downloads">Downloads</span> + <span class="tab-title tab-title-short">Downloads</span> + </div> + <div> + <span class="tab-subtitle">{{ datasetServicesList }}</span> + </div> + </div> + </a> + </li> <li [routerLinkActive]="'is-active'"> <a (click)="setPosition()" [routerLink]="[AppRoutes.resources.uri]" class="tab-link"> <svg class="tab-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"> @@ -66,7 +86,7 @@ </svg> <div> <div> - <span class="tab-title tab-title-long" i18n="@@dataset.detail.api">API and download</span> + <span class="tab-title tab-title-long" i18n="@@dataset.detail.api">API</span> <span class="tab-title tab-title-short">API</span> </div> <div> diff --git a/src/app/dataset-detail/dataset-detail-routing.module.ts b/src/app/dataset-detail/dataset-detail-routing.module.ts index 0485df6dfe8d76b018b63dfd488dbde4d5fbc43e..632807c597f5c73b57c0cba53f54eac385433ce1 100644 --- a/src/app/dataset-detail/dataset-detail-routing.module.ts +++ b/src/app/dataset-detail/dataset-detail-routing.module.ts @@ -1,5 +1,15 @@ import { NgModule } from '@angular/core'; +<<<<<<< HEAD:src/app/dataset-detail/dataset-detail-routing.module.ts import { RouterModule, Routes } from '@angular/router'; +======= +import { Routes, RouterModule } from '@angular/router'; +import { + ResultsComponent, DatasetDetailComponent, ResearchComponent, DatasetInfoComponent, + DatasetAPIComponent, + DatasetTableMapComponent, + DatasetDownloadsComponent, +} from './components'; +>>>>>>> WIP:src/app/geosource/geosource-routing.module.ts import { AppRoutes } from '../routes'; // tslint:disable-next-line: max-line-length import { DatasetDetailComponent, DatasetInfoComponent, DatasetResourcesComponent, DatasetTableMapComponent } from './components'; @@ -31,11 +41,18 @@ export const routes: Routes = [ }, { path: AppRoutes.resources.uri, - component: DatasetResourcesComponent, + component: DatasetAPIComponent, data: { title: AppRoutes.resources.title, }, }, + { + path: AppRoutes.downloads.uri, + component: DatasetDownloadsComponent, + data: { + title: AppRoutes.downloads.title, + }, + }, ], }, ]; diff --git a/src/app/geosource/components/dataset-detail/dataset-api/dataset-api.component.html b/src/app/geosource/components/dataset-detail/dataset-api/dataset-api.component.html new file mode 100644 index 0000000000000000000000000000000000000000..ac3e9789b95eac1369c3129fb356375f7d933d3e --- /dev/null +++ b/src/app/geosource/components/dataset-detail/dataset-api/dataset-api.component.html @@ -0,0 +1,17 @@ +<div *ngIf="metadata" class="resource-container"> + <div class="restricted-access-container" *ngIf="isSample"> + <app-restricted-access-banner></app-restricted-access-banner> + </div> + + <div class="resource-queryable" *ngIf="hasQueryableResources"> + <ng-container *ngFor="let resource of queryableResources | keyvalue"> + <div class="resource-description"> + <span>{{resource.key}}</span> + </div> + + <app-resources-queryable [resources]="resource.value" [metadata]="metadata"> + </app-resources-queryable> + </ng-container> + + </div> +</div> \ No newline at end of file diff --git a/src/app/geosource/components/dataset-detail/dataset-api/dataset-api.component.scss b/src/app/geosource/components/dataset-detail/dataset-api/dataset-api.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..8c5f1b4c52d967e2905b7c4f54f96bfca9a5355f --- /dev/null +++ b/src/app/geosource/components/dataset-detail/dataset-api/dataset-api.component.scss @@ -0,0 +1,97 @@ +@import "../../../../../scss/variables"; +@import "../../../../../../node_modules/bulma/sass/utilities/_all"; + +.resource-container { + background-color: $grey-background-color; + padding: 2rem 1.25rem 1.25rem 1.25rem; +} + +.restricted-access-container { + margin-top: -2rem; + margin-left: -1.25rem; + margin-right: -1.25rem; + margin-bottom: 1rem; +} + +.card-header-title { + justify-content: center; +} + +.unlock-icon { + margin-bottom: 0.5rem; + + i { + font-size: 1.5rem; + } +} + +h3 { + margin-top: 0; + margin-bottom: 0; +} + +h4 { + font-weight: 700; +} + +.underlined { + text-decoration: underline; +} + +.columns { + margin: 0; + margin-bottom: 2rem; +} + +.services.columns { + justify-content: space-evenly; +} + +.resource-queryable { + padding-bottom: 3rem; + border-bottom: 2px solid $grey-background-color; + + .resource-description { + border-bottom: 2px solid $grey-background-color; + padding-bottom: 1.5rem; + + span { + font-weight: 600; + line-height: 1; + font-size: 1rem; + } + } +} + +.resource-other-link { + a { + font-size: 0.875rem; + } +} + +.resource-header { + display: flex; + align-items: center; + margin-bottom: 1rem; +} + +.resource-header-title { + font-size: 1.25rem; + font-weight: 700; + margin-left: 1rem; +} + +.resource-header-icon { + height: 2.25rem; + width: 2.25rem; + background-color: $grey-super-light-color; + display: flex; + align-items: center; + justify-content: center; + border-radius: 4px; + + svg { + height: 1.125rem; + fill: white; + } +} diff --git a/src/app/geosource/components/dataset-detail/dataset-api/dataset-api.component.spec.ts b/src/app/geosource/components/dataset-detail/dataset-api/dataset-api.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..f3d404757bfc4869e8ce6cbd5eb1962806acd907 --- /dev/null +++ b/src/app/geosource/components/dataset-detail/dataset-api/dataset-api.component.spec.ts @@ -0,0 +1,54 @@ +// import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +// import { DatasetExportComponent } from './dataset-export.component'; +// import { LicenseModalComponent } from '../..'; +// import { ActivatedRoute } from '@angular/router'; +// import { Observable, of } from 'rxjs'; +// import { DatasetDetailService, ElasticsearchService } from '../../../services'; +// import { HttpClientModule } from '@angular/common/http'; +// import { Metadata } from '../../../models'; +// import { NotificationService, ErrorService } from '../../../../core/services'; + +// describe('DatasetExportComponent', () => { +// let component: DatasetExportComponent; +// let fixture: ComponentFixture<DatasetExportComponent>; +// let service: DatasetDetailService; + +// beforeEach(async(() => { +// TestBed.configureTestingModule({ +// imports: [ +// HttpClientModule, +// ], +// declarations: [DatasetExportComponent, LicenseModalComponent], +// providers: [ +// { +// provide: ActivatedRoute, +// useValue: { +// parent: { +// get paramMap(): Observable<any> { +// return of(); +// }, +// }, +// }, +// }, +// DatasetDetailService, +// ElasticsearchService, +// ErrorService, +// NotificationService, +// ], +// }) +// .compileComponents(); +// })); + +// beforeEach(() => { +// fixture = TestBed.createComponent(DatasetExportComponent); +// component = fixture.componentInstance; +// service = TestBed.get(DatasetDetailService); +// spyOn(service, 'getDatasetMetadata').and.returnValue(of(new Metadata())); +// fixture.detectChanges(); +// }); + +// it('should create', () => { +// expect(component).toBeTruthy(); +// }); +// }); diff --git a/src/app/geosource/components/dataset-detail/dataset-api/dataset-api.component.ts b/src/app/geosource/components/dataset-detail/dataset-api/dataset-api.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..d90fc434920e515bf87062755aef4cef3eaebd48 --- /dev/null +++ b/src/app/geosource/components/dataset-detail/dataset-api/dataset-api.component.ts @@ -0,0 +1,126 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { DatasetDetailService, ResourcesService } from '../../../services'; +import { Metadata, Resource } from '../../../models'; +import { Subscription, forkJoin } from 'rxjs'; +import { IMetadataLink } from '../../../models/metadata.model'; +import { NotificationService } from '../../../../core/services'; +import { notificationMessages } from '../../../../../i18n/traductions'; +import { Notification } from '../../../../core/models'; + +@Component({ + selector: 'app-dataset-api', + templateUrl: './dataset-api.component.html', + styleUrls: ['./dataset-api.component.scss'], +}) +export class DatasetAPIComponent implements OnInit, OnDestroy { + + metadata: Metadata; + resources: Resource[]; + displayLicenseModal = false; + sub: Subscription; + hasBeenInitialized = false; + + isSample = false; + + // To display in the template + queryableResources: Resource[]; + downloadableResources: IMetadataLink[]; + otherResources: IMetadataLink[]; + + constructor( + private _datasetDetailService: DatasetDetailService, + private _resourcesService: ResourcesService, + private _notificationService: NotificationService, + ) { } + + ngOnInit() { + this.resources = []; + this.queryableResources = []; + this.downloadableResources = []; + this.otherResources = []; + this.isSample = this._datasetDetailService.dataset.editorialMetadata.isSample; + + this.initialize(); + this._resourcesService.getResources().subscribe( + (results) => { + this.resources = results; + + this.initialize(); + this.sub = this._datasetDetailService.dataset$.subscribe(() => { + this.initialize(); + }); + }, + (err) => { + this._notificationService.notify(new Notification({ + type: 'error', + message: `${notificationMessages.resources.initializationError}`, + })); + }, + ); + + } + + ngOnDestroy() { + if (this.sub) { + this.sub.unsubscribe(); + } + } + + // Resources are organized on 2 levels : + // -> 1st level: by metadata link description + // -> 2nd level: for each link description in 3 categories: + // - queryable + // - downloadable + // - other + // How to organize: we compare the type of one resource from our resource service + // and the ES metadata link property. If there is a match, the service will let us know if the resource + // is queryable or downloadable. If there is no match and the ES resource cannot be found in the service, + // we put it in "others" resources catagory. + initialize() { + this.metadata = this._datasetDetailService.datasetMetadata; + if (this.metadata && this.resources.length > 0 && !this.hasBeenInitialized) { + this.hasBeenInitialized = true; + if (this.metadata.link) { + this.metadata.link.forEach((link) => { + if (link.service) { + this.resources.forEach((resource) => { + const resourceCopy = Object.assign({}, resource); + resourceCopy.metadataLink = link; + if (link.service === resource.type && resourceCopy.isQueryable) { + if (!this.queryableResources[link.description]) { + this.queryableResources[link.description] = []; + } + this.queryableResources[link.description].push(resourceCopy); + } + }); + } else if (link.service === undefined) { + if (link.formats) { + if (!this.downloadableResources[link.description]) { + this.downloadableResources[link.description] = []; + } + this.downloadableResources[link.description].push(link); + } else { + this.otherResources.push(link); + } + } + }); + } + } + } + + toggleLicenseModal() { + this.displayLicenseModal = !this.displayLicenseModal; + } + + get hasQueryableResources() { + return Object.keys(this.queryableResources).length > 0; + } + + get hasDownloadableResources() { + return Object.keys(this.downloadableResources).length > 0; + } + + get hasOtherResources() { + return Object.keys(this.otherResources).length > 0; + } +} diff --git a/src/app/geosource/components/dataset-detail/dataset-api/icon-format/icon-format.component.html b/src/app/geosource/components/dataset-detail/dataset-api/icon-format/icon-format.component.html new file mode 100644 index 0000000000000000000000000000000000000000..7acfa98b2ba27a93089ffa294cabf18dcca37468 --- /dev/null +++ b/src/app/geosource/components/dataset-detail/dataset-api/icon-format/icon-format.component.html @@ -0,0 +1,8 @@ +<div class="format-icon" [ngClass]="'type-' + resourceType + ' is-' + size"> + <svg xmlns="http://www.w3.org/2000/svg" id="format" viewBox="0 0 70 40"> + <path d="M68 3.5v32.9c0 .8-.7 1.5-1.5 1.5h-63c-.8.1-1.5-.6-1.5-1.4V14.1c0-.4.1-.7.4-1l8.9-10.6c.2-.3.7-.5 1.1-.5h54.1c.8 0 1.5.7 1.5 1.5z" class="white"/> + <path d="M66 4v32H4V14.3L12.6 4H66m.5-2H12.4c-.4 0-.8.2-1.1.5L2.4 13.1c-.2.3-.4.6-.4 1v22.4c0 .8.7 1.5 1.5 1.5h63c.8 0 1.5-.7 1.5-1.5v-33c0-.8-.7-1.5-1.5-1.5z" class="st0"/> + <path d="M12 12.1V2.4L2 14h8.1c1 0 1.9-.9 1.9-1.9z" class="st0"/> + </svg> + <span> {{ resourceType }} </span> +</div> \ No newline at end of file diff --git a/src/app/geosource/components/dataset-detail/dataset-api/icon-format/icon-format.component.scss b/src/app/geosource/components/dataset-detail/dataset-api/icon-format/icon-format.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..cd9d207b1223a7999165d62779b2619ae92efcfa --- /dev/null +++ b/src/app/geosource/components/dataset-detail/dataset-api/icon-format/icon-format.component.scss @@ -0,0 +1,51 @@ +.format-icon { + position: relative; + display: inline-flex; + + &.is-big { + span { + font-size: 1.25rem; + } + svg { + height: 46px; + } + } + + svg { + height: 36px; + + .white { + fill: white; + } + } + + &.type-KML svg{ + fill: #98b3e9; + } + + &.type-WMS svg{ + fill: #a6e0c1; + } + + &.type-WS svg{ + fill: #eec982; + } + + &.type-WFS svg{ + fill: #ec9bd5; + } + + &.type-WCS svg{ + fill: #cbde96; + } + + span { + position: absolute; + left: 50%; + font-size: 0.875rem; + top: 50%; + transform: translate(-50%,-50%); + font-weight: 700; + line-height: 1; + } +} \ No newline at end of file diff --git a/src/app/geosource/components/dataset-detail/dataset-api/icon-format/icon-format.component.ts b/src/app/geosource/components/dataset-detail/dataset-api/icon-format/icon-format.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..372f89b168edc66339e92aa5f45bf3a984df0d9f --- /dev/null +++ b/src/app/geosource/components/dataset-detail/dataset-api/icon-format/icon-format.component.ts @@ -0,0 +1,15 @@ +import { OnInit, Input, Component } from '@angular/core'; + +@Component({ + selector: 'app-icon-format', + templateUrl: './icon-format.component.html', + styleUrls: ['./icon-format.component.scss'], +}) +export class IconFormatComponent implements OnInit { + + @Input() resourceType: string; + @Input() size?: string; + + ngOnInit() { + } +} diff --git a/src/app/geosource/components/dataset-detail/dataset-api/resources-queryable/resource-queryable/resource-queryable.component.html b/src/app/geosource/components/dataset-detail/dataset-api/resources-queryable/resource-queryable/resource-queryable.component.html new file mode 100644 index 0000000000000000000000000000000000000000..62f0c7b2955d06330b26792f121a36712e1dc396 --- /dev/null +++ b/src/app/geosource/components/dataset-detail/dataset-api/resources-queryable/resource-queryable/resource-queryable.component.html @@ -0,0 +1,236 @@ + <div class="full-line-resource resource-item" [ngClass]="{'is-open': requestOpen}"> + + <div class="layer-name"> + <!-- <app-icon-format [resourceType]="resource.type" [size]="'big'"></app-icon-format> --> + <span>{{ resource.metadataLink.name }}</span> + </div> + + + <div class="root-url"> + <div class="root-url-label title-label"> + <span i18n="@@dataset.resources.url.root"> + Root URL + </span> + </div> + <div class="root-url-input"> + <div class="link-with-copy"> + <span class="parameters-url"> + <a [href]="resource.metadataLink.url" target="_blank">{{ resource.metadataLink.url }}</a> + </span> + <button type="button" (click)="copyToClipboard(resource.metadataLink.url, true)" + class="button is-medium tooltip" [attr.data-tooltip]="messageClipboardRoot"> + <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" viewBox="0 0 20 20"> + <path fill="#818080" fill-rule="evenodd" + d="M1.852 7.777a2.619 2.619 0 0 1 0-3.703l2.222-2.222a2.619 2.619 0 0 1 3.704 0l2.963 2.963a2.619 2.619 0 0 1 0 3.703l-.37.37.74.741.37-.37a2.619 2.619 0 0 1 3.704 0l2.963 2.963a2.619 2.619 0 0 1 0 3.704l-2.222 2.222a2.619 2.619 0 0 1-3.704 0L9.26 15.185a2.619 2.619 0 0 1 0-3.704l.37-.37-.74-.741-.37.37a2.619 2.619 0 0 1-3.704 0L1.852 7.777zm7.037-.37l-.74-.74a1.048 1.048 0 0 0-1.482 1.48l.74.742-.37.37a.524.524 0 0 1-.74 0L3.332 6.296a.524.524 0 0 1 0-.74l2.223-2.223a.524.524 0 0 1 .74 0L9.26 6.296a.524.524 0 0 1 0 .74l-.37.371zm2.222 5.185l-.37.37a.524.524 0 0 0 0 .742l2.963 2.962a.524.524 0 0 0 .74 0l2.223-2.222a.524.524 0 0 0 0-.74l-2.963-2.963a.524.524 0 0 0-.741 0l-.37.37.74.74a1.047 1.047 0 1 1-1.481 1.482l-.74-.74z" + clip-rule="evenodd" /> + </svg> + </button> + </div> + </div> + </div> + + <div class="create-request" (click)="requestOpen = !requestOpen" [ngClass]="{'is-open': requestOpen}" + *ngIf="allSettingsOK"> + <span i18n="@@dataset.resources.createRequest"> + Create a request + </span> + <span class="create-request-icon"> + <svg xmlns="http://www.w3.org/2000/svg" id="chevron" viewBox="0 0 15 9"> + <path + d="M7.5 7.5c-.1 0-.3-.1-.4-.1l-6-6C1 1.1 1 .8 1.1.6s.5-.2.7 0l5.6 5.6L13 .6c.2-.2.5-.2.7 0s.2.5 0 .7l-6 6c.1.1-.1.2-.2.2z" + class="brandcolor" /> + <path + d="M7.5 7.5c-.1 0-.3-.1-.4-.1l-6-6C1 1.1 1 .8 1.1.6s.5-.2.7 0l5.6 5.6L13 .6c.2-.2.5-.2.7 0s.2.5 0 .7l-6 6c.1.1-.1.2-.2.2z" + class="brandcolor" /> + </svg> + </span> + </div> + + <div class="no-custom-url" *ngIf="!allSettingsOK"> + <span i18n="@@dataset.resources.impossibleCreate"> + Impossible de créer une requête personnalisée pour ce jeu de données + </span> + </div> + + <ng-container *ngIf="requestOpen && allSettingsOK"> + <div class="format-item"> + <div class="label-dropdown title-label"> + <span i18n="@@dataset.resources.format"> + Output format + </span> + </div> + <!-- Dropdow for formats --> + <div class="dropdown" [ngClass]="{'is-active': dropDownFormatsToggle}" *ngIf="resource.formats.length > 1" + (click)="dropDownFormatsToggle=!dropDownFormatsToggle" (clickOutside)="dropDownFormatsToggle = false;"> + <div class="dropdown-trigger"> + <button class="button" aria-haspopup="true" aria-controls="dropdown-menu"> + <span>{{ selectedFormat.name }}</span> + <span class="icon is-small"> + <i class="fas fa-angle-down" aria-hidden="true"></i> + </span> + </button> + </div> + <div class="dropdown-menu" id="dropdown-menu" role="menu"> + <div class="dropdown-content"> + <a class="dropdown-item" *ngFor="let format of resource.formats" (click)="setFormat(format)"> + {{ format.name }} + </a> + </div> + + </div> + </div> + <div *ngIf="resource.formats.length < 2"> + <span>{{ selectedFormat.name }}</span> + </div> + </div> + + <div class="projection-item" *ngIf="selectedFormat.isProjectable"> + <div class="label-dropdown title-label"> + <span i18n="@@dataset.resources.projectionsystem"> + Projection system + </span> + </div> + <div> + <!-- Dropdow for projections --> + <div class="dropdown" [ngClass]="{'is-active': dropDownProjectionToggle}" + (click)="dropDownProjectionToggle=!dropDownProjectionToggle" + (clickOutside)="dropDownProjectionToggle = false;"> + <div class="dropdown-trigger"> + <button class="button" aria-haspopup="true" aria-controls="dropdown-menu"> + <span>{{ getProjectionLabel(selectedProjection.name) }}</span> + <span class="icon is-small"> + <i class="fas fa-angle-down" aria-hidden="true"></i> + </span> + </button> + </div> + <div class="dropdown-menu" id="dropdown-menu" role="menu"> + <div class="dropdown-content"> + <a class="dropdown-item" *ngFor="let projection of projectionList" (click)="setProjection(projection)"> + {{ getProjectionLabel(projection.name) }} + </a> + </div> + </div> + </div> + </div> + </div> + + <div class="division-item" *ngIf="selectedFormat.isCuttable && inseeLabel"> + <div class="label-dropdown title-label"> + <span i18n="@@dataset.resources.divisionbycommune"> + Division by municipality + </span> + </div> + <div> + <!-- Dropdown for insee when needed --> + <div class="dropdown dropdown-insee" [ngClass]="{'is-active': dropDownInseeToggle}" + (click)="dropDownInseeToggle=!dropDownInseeToggle" (clickOutside)="dropDownInseeToggle = false;"> + <div class="dropdown-trigger"> + <button class="button" aria-haspopup="true" aria-controls="dropdown-menu"> + <span + *ngIf="selectedInsee">{{ selectedInsee ? selectedInsee.commune + ' - ' + selectedInsee.insee : ''}}</span> + <span *ngIf="!selectedInsee" i18n="@@dataset.resources.commune">Municipality</span> + <span class="icon is-small"> + <i class="fas fa-angle-down" aria-hidden="true"></i> + </span> + </button> + </div> + <div class="dropdown-menu" id="dropdown-menu" role="menu"> + <div class="dropdown-content"> + <a class="dropdown-item" (click)="setInsee(null)" i18n="@@global.all.feminine">All</a> + <a class="dropdown-item" *ngFor="let zone of communeInseeList" (click)="setInsee(zone)"> + {{ zone.commune }} - {{ zone.insee }} + </a> + </div> + </div> + </div> + </div> + </div> + + <ng-container *ngIf="resource.type === linkFormats.wfs || resource.type === linkFormats.ws"> + <div class="maxFeatures-item"> + <div class="title-label"> + <label for="countFeatures"> Nombre d'enregistrements</label> + </div> + <div class="countFeatures"> + <div> + <input class="input" id="countFeatures" [value]="inputCountFeatures" type="number" min="1" max="10000" + [(ngModel)]="inputCountFeatures" (change)="setActiveCountFeatures()" [disabled]="isAllFeaturesChecked"> + </div> + <div class="allFeatures"> + <input [id]="'allFeatures_' + resource.type" class="is-checkradio is-small" type="checkbox" + (change)="checkAllFeatures()" [(ngModel)]="isAllFeaturesChecked" [value]="isAllFeaturesChecked"> + <label [for]="'allFeatures_' + resource.type" class="label checkbox-label">Tous</label> + </div> + + </div> + <div class="warning" *ngIf="numberFeatures > 1000"> + <span>à partir de 1000 enregistrements, le temps de chargement peut devenir + important</span> + </div> + + </div> + <div class="fromFeature-item"> + <div class="title-label"> + <label [for]="'fromFeature_' + resource.type"> Numéro du 1er enregistrement</label> + </div> + <div> + <input class="input" [id]="'fromFeature_' + resource.type" type="number" [value]="fromFeature" + [min]="minFromFeature" [max]="totalData" [(ngModel)]="fromFeature" (change)="setActiveFromFeature()"> + </div> + + </div> + </ng-container> + + + + <div class="personnalized-url"> + <div class="title-label"> + <span i18n="@@dataset.resources.url.personalized"> + URL personnalisée + </span> + </div> + <div class="link-with-copy"> + <span class="parameters-url column is-narrow-tablet"> + <a [href]="queryableUrl" target="_blank" [ngClass]="{'is-disabled': isAllFeaturesChecked}" + [innerHtml]="queryableUrlToDisplay"> + </a> + </span> + <button type="button" (click)="copyToClipboard(queryableUrl)" class="button is-medium tooltip" + [attr.data-tooltip]="messageClipboard"> + <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" viewBox="0 0 20 20"> + <path fill="#818080" fill-rule="evenodd" + d="M1.852 7.777a2.619 2.619 0 0 1 0-3.703l2.222-2.222a2.619 2.619 0 0 1 3.704 0l2.963 2.963a2.619 2.619 0 0 1 0 3.703l-.37.37.74.741.37-.37a2.619 2.619 0 0 1 3.704 0l2.963 2.963a2.619 2.619 0 0 1 0 3.704l-2.222 2.222a2.619 2.619 0 0 1-3.704 0L9.26 15.185a2.619 2.619 0 0 1 0-3.704l.37-.37-.74-.741-.37.37a2.619 2.619 0 0 1-3.704 0L1.852 7.777zm7.037-.37l-.74-.74a1.048 1.048 0 0 0-1.482 1.48l.74.742-.37.37a.524.524 0 0 1-.74 0L3.332 6.296a.524.524 0 0 1 0-.74l2.223-2.223a.524.524 0 0 1 .74 0L9.26 6.296a.524.524 0 0 1 0 .74l-.37.371zm2.222 5.185l-.37.37a.524.524 0 0 0 0 .742l2.963 2.962a.524.524 0 0 0 .74 0l2.223-2.222a.524.524 0 0 0 0-.74l-2.963-2.963a.524.524 0 0 0-.741 0l-.37.37.74.74a1.047 1.047 0 1 1-1.481 1.482l-.74-.74z" + clip-rule="evenodd" /> + </svg> + </button> + <div class="resource-download-icon" (click)="saveFile(queryableUrl)"> + <a> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 23"> + <g id="btn-download"> + <path + d="M22 14c-.6 0-1 .4-1 1v5H3v-5c0-.6-.4-1-1-1s-1 .4-1 1v6c0 .6.4 1 1 1h20c.6 0 1-.4 1-1v-6c0-.6-.4-1-1-1z" + class="download_x002D_color" /> + <path + d="M11.3 16.7c.2.2.5.3.7.3s.5-.1.7-.3l6-6c.4-.4.4-1 0-1.4s-1-.4-1.4 0L13 13.6V2c0-.6-.4-1-1-1s-1 .4-1 1v11.6L6.7 9.3c-.4-.4-1-.4-1.4 0s-.4 1 0 1.4l6 6z" + class="download_x002D_color" /> + <g> + <path + d="M22 14c-.6 0-1 .4-1 1v5H3v-5c0-.6-.4-1-1-1s-1 .4-1 1v6c0 .6.4 1 1 1h20c.6 0 1-.4 1-1v-6c0-.6-.4-1-1-1z" + class="download_x002D_color" /> + <path + d="M11.3 16.7c.2.2.5.3.7.3s.5-.1.7-.3l6-6c.4-.4.4-1 0-1.4s-1-.4-1.4 0L13 13.6V2c0-.6-.4-1-1-1s-1 .4-1 1v11.6L6.7 9.3c-.4-.4-1-.4-1.4 0s-.4 1 0 1.4l6 6z" + class="download_x002D_color" /> + </g> + </g> + </svg> + </a> + </div> + + + </div> + + + </div> + + </ng-container> + </div> \ No newline at end of file diff --git a/src/app/geosource/components/dataset-detail/dataset-api/resources-queryable/resource-queryable/resource-queryable.component.scss b/src/app/geosource/components/dataset-detail/dataset-api/resources-queryable/resource-queryable/resource-queryable.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..1c9d6847d596df202e6a9f0017db436a9fcf3553 --- /dev/null +++ b/src/app/geosource/components/dataset-detail/dataset-api/resources-queryable/resource-queryable/resource-queryable.component.scss @@ -0,0 +1,303 @@ +@import '../../../../../../../scss/variables.scss'; + +.resource-item { + display: grid; + grid-auto-rows: auto; + grid-template-columns: 1fr 1fr; + grid-row-gap: 1rem; + grid-column-gap: 1rem; +} + +// Defined the named areas +.layer-name { + grid-column: 1 / 3; + display: flex; + align-items: center; + + span { + font-size: 1.125rem; + font-weight: 600; + line-height: 1; + margin-left: 1rem; + word-break: break-all; + } +} + +.root-url { + grid-column: 1 / 3; + border-bottom: 2px solid $grey-background-color; + padding-bottom: 1rem; +} + +.format-item { + grid-column: 1 / 2; +} + +.projection-item { + grid-column: 2 / 3; +} + +.division-item { + grid-column: 1 / 2; +} + +.no-custom-url { + grid-column: 1 / 3; + + span { + color: $warning-color; + } +} + +.title-label { + margin-bottom: 0.4rem; + + span, + label { + text-transform: uppercase; + color: $grey-dark-color; + font-size: 0.875rem; + line-height: 1.4; + } +} + +.fromFeature-item { + grid-column: 2 / 3; + + // Remove Bulma default 100% width + .input { + width: unset; + } +} + +.parameters-url { + word-break: break-all; +} + +.create-request-icon { + svg { + margin-right: 1.2rem; + width: 16px; + fill: grey; + transform: rotate(-90deg); + } +} + +.resource-download-icon { + padding: 0.5rem 0.4rem; + border: 1px solid $grey-super-light-color; + border-radius: 4px; + margin-left: 0.5rem; + + a { + display: flex; + } + + svg { + height: 1.5rem; + fill: $link-color; + } + + &:hover { + opacity: 0.7; + } +} + +.link-with-copy { + display: flex; + justify-content: space-between; + + a, + /* stylelint-disable-next-line */ + a span { + color: $link-color; + text-decoration: none; + + &:hover { + text-decoration: underline; + } + } + + .parameters-url-icon { + color: $brand-color; + + &:hover { + cursor: pointer; + } + } + + .parameters-url { + background-color: $grey-background-color; + transition: all 0.5s ease; + word-break: break-all; + flex-grow: 1; + flex-shrink: 1; + padding: 0.7rem 0.5rem; + + // ng-deep needed because of the innerHtml breaks the styling + /* stylelint-disable-next-line */ + ::ng-deep .is-active-parameter { + font-weight: bold; + color: $link-color; + } + + /* stylelint-disable-next-line */ + a.is-disabled ::ng-deep .is-active-parameter { + font-weight: bold; + color: $grey-dark-color; + } + + a.is-disabled, + a.is-disabled span { + pointer-events: none; + color: $grey-dark-color; + } + } + + .button { + font-size: 0.875rem; + margin-left: 0.5rem; + height: 2.75rem; + + svg { + width: 1.25rem; + } + + svg path { + fill: $grey-dark-color; + } + } + + .button:hover { + svg { + opacity: 0.7; + } + } +} + +.create-request { + cursor: pointer; + grid-column: 1 / 3; + display: flex; + align-items: center; + justify-content: space-between; + padding-bottom: 1rem; + border-bottom: 2px solid $grey-background-color; + + /* stylelint-disable-next-line */ + span:first-of-type { + font-weight: 600; + } +} + +.maxFeatures-item { + grid-column: 1 / 2; + + // Remove Bulma default 100% width + .input { + width: unset; + } + + .warning { + margin-top: 0.5rem; + + /* stylelint-disable-next-line */ + span { + color: $warning-color; + } + } +} + +.personnalized-url { + grid-column: 1 / 3; + flex-wrap: wrap; + align-items: stretch; + + .link-with-copy { + align-items: flex-start; + } +} + +.icon { + cursor: pointer; + // Make icon clickable + pointer-events: initial !important; +} + +.tooltip { + cursor: pointer; +} + +h3 { + margin-top: 0; +} + +// Make Bulma dropdown to 100% of the parent div width +.dropdown, +.dropdown-trigger, +.dropdown-trigger button, +.dropdown-menu { + width: 100%; +} + +.dropdown-menu { + height: 2.5rem; +} + +.dropdown-insee { + .dropdown-menu { + height: 200px; + max-height: 200px; + overflow-y: scroll; + overflow-x: hidden; + } +} + +/* stylelint-disable-next-line */ +.dropdown-trigger .button { + justify-content: space-between; +} + +.resource-title { + cursor: pointer; + font-weight: 500; +} + +.full-line-resource { + border-bottom: 1px solid white; +} + +.collapsible { + overflow: hidden; + max-height: 0; + padding-top: 0; + padding-bottom: 0; +} + +.create-request.is-open { + border-bottom: none; + + .create-request-icon svg { + transform: rotate(0deg); + } +} + +.countFeatures { + display: flex; + align-items: center; +} + +.allFeatures { + display: flex; + align-items: center; + margin-left: 0.5rem; + + label { + font-weight: 400; + } +} + +.is-checkradio[type="checkbox"] + label { + padding: unset; + padding-left: 1.75rem; +} diff --git a/src/app/geosource/components/dataset-detail/dataset-api/resources-queryable/resource-queryable/resource-queryable.component.ts b/src/app/geosource/components/dataset-detail/dataset-api/resources-queryable/resource-queryable/resource-queryable.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..75d3923cffc1ed8fa6fe64a9c4d75b2eee8bea86 --- /dev/null +++ b/src/app/geosource/components/dataset-detail/dataset-api/resources-queryable/resource-queryable/resource-queryable.component.ts @@ -0,0 +1,502 @@ +import { Component, OnInit, Input } from '@angular/core'; +import { SafeHtml, DomSanitizer } from '@angular/platform-browser'; +import { Resource, Metadata } from '../../../../../models'; +import { Format } from '../../../../../models/resource.model'; +import { communeInsee } from '../../../../../../../assets/resources/commune-insee'; +import { DatasetDetailService } from '../../../../../services'; +import { linkFormats } from '../../../../../models/metadata.model'; +import { geosource, notificationMessages } from '../../../../../../../i18n/traductions'; +import { saveAs } from 'file-saver'; +import { NotificationService } from '../../../../../../core/services'; +import { Projection } from '../../../../../models/projection.model'; + +@Component({ + selector: 'app-resource-queryable', + templateUrl: './resource-queryable.component.html', + styleUrls: ['./resource-queryable.component.scss'], +}) +export class ResourceQueryableComponent implements OnInit { + linkFormats = linkFormats; + + @Input() resource: Resource; + @Input() metadata: Metadata; + @Input() projections: Projection[]; + + messageClipboard: string; + messageClipboardRoot: string; + requestOpen: boolean = false; + + queryableUrl: string; + queryableUrlToDisplay: SafeHtml; + allSettingsOK: boolean = true; + + shpProjections = { + 'EPSG:4171': 'EPSG:4171', + 'EPSG:3946': 'EPSG:3946', + 'EPSG:2154': 'EPSG:2154', + 'EPSG:4326': 'EPSG:4326', + 'EPSG:4258': 'EPSG:4258', + }; + + labelFormat = { + WFS: 'outputFormat', + WMS: 'FORMAT', + WCS: 'FORMAT', + }; + labelLayer = { + WFS: 'typename', + WMS: 'layers', + WCS: 'identifiers', + }; + + inseeLabel: string; + + // Dropdown format + dropDownFormatsToggle: false; + selectedFormat: Format; + + // Dropdown projection + dropDownProjectionToggle: false; + selectedProjection: { + name: '', + bbox: any, + }; + projectionList; + + // Dropdown insee + dropDownInseeToggle: false; + selectedInsee: { + commune: '', + insee: '', + }; + communeInseeList = communeInsee; + + // number of features (for WFS) + numberFeatures: number = 100; + inputCountFeatures: number = 100; + isAllFeaturesChecked = false; + + fromFeature: number = 0; + minFromFeature: number = 0; + + // Object that will manage the display of the queryable url + queryableParameters = { + baseUrl: '', + baseParameters: '', + layer: '', + outputFormat: '', + outputFormatActive: false, + projection: '', + projectionActive: false, + bbox: '', + insee: '', + inseeActive: false, + numberFeatures: false, + fromFeature: false, + }; + + constructor( + private _datasetDetailService: DatasetDetailService, + private _notificationService: NotificationService, + private _sanitizer: DomSanitizer, + ) { } + + // reset the values when the input( selectedResource) is changed + ngOnChanges() { + + this.queryableParameters = { + baseUrl: '', + baseParameters: '', + layer: '', + outputFormat: '', + outputFormatActive: false, + projection: '', + projectionActive: false, + bbox: '', + insee: '', + inseeActive: false, + numberFeatures: false, + fromFeature: false, + }; + + this.initSettings(); + } + + initSettings() { + // By default we display for each resource the root URL. + // Then we check if all necessary information are there to init the custom URL tool + this.allSettingsOK = true; + if ((this.resource.formats && this.resource.formats.length < 1) || + (this.resource.type === linkFormats.wms && !this.resource.metadataLink.bbox_by_projection) || + (this.resource.type === linkFormats.wcs && !this.resource.metadataLink.bbox_by_projection) || + this.resource.type === linkFormats.wfs && + (!this.resource.metadataLink.projections || this.resource.metadataLink.projections.length < 1)) { + this.allSettingsOK = false; + } + + if (this.allSettingsOK) { + // This is the starting index feature. For WS: 1, WFS: 0 + if (this.resource.type === linkFormats.ws) { + this.minFromFeature = this.fromFeature = 1; + } else if (this.resource.type === linkFormats.wfs) { + this.minFromFeature = this.fromFeature = 0; + } + this.requestOpen = true; + this.isAllFeaturesChecked = false; + this.inputCountFeatures = 100; + this.numberFeatures = 100; + this.initURLCustomization(); + } + } + + ngOnInit() { + this.messageClipboard = geosource.mapMessages.share; + this.messageClipboardRoot = geosource.mapMessages.share; + + this.initSettings(); + } + + initURLCustomization() { + this.projectionList = []; + + // Set the insee property label for this dataset + if (this._datasetDetailService.datasetData[0]) { + const properties = Object.keys(this._datasetDetailService.datasetData[0].properties); + this.inseeLabel = properties.find((prop) => { return prop.includes('insee'); }); + } + + this.selectedFormat = this.resource.formats[0]; + this.communeInseeList.sort((a, b) => (a.commune > b.commune) ? 1 : -1); + + // Get projections and set the default one (depending on the resource) + if (this.resource.type === linkFormats.wms) { + this.projectionList = this.transformObjectToArray(this.resource.metadataLink.bbox_by_projection); + this.selectedProjection = this.projectionList[0]; + } else if (this.resource.type === linkFormats.wfs) { + this.resource.metadataLink.projections.forEach((key) => { + this.projectionList.push({ + name: key, + bbox: key, + }); + }); + this.selectedProjection = this.projectionList[0]; + } else if (this.resource.type === linkFormats.wcs) { + this.projectionList = this.transformObjectToArray(this.resource.metadataLink.bbox_by_projection); + this.selectedProjection = this.projectionList[0]; + } else if (this.resource.type === linkFormats.ws) { + this.projectionList = this.transformObjectToArray(this.shpProjections); + this.selectedProjection = this.projectionList[0]; + } + + // Init the url query parameters that will not be changed by the user + this.queryableParameters.baseUrl = this.resource.metadataLink.url; + if (this.resource.type === linkFormats.ws) { + // Exception for this service, we modify the root URL + // this.resource.metadataLink.url += '/all.json'; + this.queryableParameters.baseUrl += `/${this.resource.metadataLink.name}/all.json`; + } + this.queryableParameters.baseParameters = this.resource.parametersUrl ? `?${this.resource.parametersUrl}` : ''; + + if (this.resource.type === linkFormats.kml) { + this.queryableParameters.baseParameters = `?${this.resource.parametersUrl}` + + `&typename=${this.resource.metadataLink.name}`; + } + + this.setProjection(this.selectedProjection); + + if (this.resource.isStandard) { + this.queryableParameters.layer = `&${this.labelLayer[this.resource.type]}=${this.resource.metadataLink.name}`; + this.queryableParameters.outputFormat = `&${this.labelFormat[this.resource.type]}=` + + `${this.selectedFormat.mapServerType}`; + } + + this.updateQueryableUrl(); + this.updateQueryableurlToDisplay(); + } + + // When the user changes parameters (or when view init), we update the url provided + // to the <a> link + updateQueryableUrl() { + this.queryableUrl = this.queryableParameters.baseUrl + + this.queryableParameters.baseParameters; + this.queryableUrl += this.queryableParameters.layer + + this.queryableParameters.outputFormat + + this.queryableParameters.insee + + this.queryableParameters.projection + + this.queryableParameters.bbox + ; + + if (this.resource.type === linkFormats.wfs) { + this.queryableUrl += `&startIndex=${this.fromFeature}`; + } else if (this.resource.type === linkFormats.ws) { + if (this.selectedFormat.name === 'JSON') { + this.queryableUrl += `?maxfeatures=${this.numberFeatures}&start=${this.fromFeature}`; + } else { + this.queryableUrl += `&maxfeatures=${this.numberFeatures}&start=${this.fromFeature}`; + } + } + + if (!this.isAllFeaturesChecked && this.resource.type === linkFormats.wfs) { + this.queryableUrl += `&count=${this.numberFeatures}`; + } + + } + + updateQueryableurlToDisplay() { + let queryableUrlToDisplay = ''; + + queryableUrlToDisplay = this.queryableParameters.baseUrl + + this.queryableParameters.baseParameters + + this.queryableParameters.layer; + + // Project & bbox + if (this.queryableParameters.projectionActive) { + queryableUrlToDisplay += `<span class="is-active-parameter">${this.queryableParameters.projection}` + + `${this.queryableParameters.bbox}</span>`; + } else { + queryableUrlToDisplay += this.queryableParameters.projection + this.queryableParameters.bbox; + } + + // Format + if (this.selectedFormat) { + if (this.queryableParameters.outputFormatActive) { + queryableUrlToDisplay += + `<span class="is-active-parameter">${this.queryableParameters.outputFormat}</span>`; + } else { + queryableUrlToDisplay += this.queryableParameters.outputFormat; + } + } + + // Insee + if (this.selectedInsee) { + if (this.queryableParameters.inseeActive) { + queryableUrlToDisplay += + `<span class="is-active-parameter">${this.queryableParameters.insee}</span>`; + } else { + queryableUrlToDisplay += this.queryableParameters.insee; + } + } + + // Number features WFS + if (!this.isAllFeaturesChecked && this.resource.type === this.linkFormats.wfs) { + if (this.queryableParameters.numberFeatures) { + queryableUrlToDisplay += + `<span class="is-active-parameter">&count=${this.numberFeatures}</span>`; + } else { + queryableUrlToDisplay += `&count=${this.numberFeatures}`; + } + } + + // Number features WS + if (this.resource.type === this.linkFormats.ws) { + if (this.queryableParameters.numberFeatures) { + queryableUrlToDisplay += this.selectedFormat.name === 'JSON' ? + `<span class="is-active-parameter">?maxfeatures=${this.numberFeatures}</span>` : + `<span class="is-active-parameter">&maxfeatures=${this.numberFeatures}</span>`; + } else { + queryableUrlToDisplay += this.selectedFormat.name === 'JSON' ? + `?maxfeatures=${this.numberFeatures}` : + `&maxfeatures=${this.numberFeatures}`; + } + } + + // From feature WFS + if (this.resource.type === this.linkFormats.wfs) { + if (this.queryableParameters.fromFeature) { + queryableUrlToDisplay += + `<span class="is-active-parameter">&startIndex=${this.fromFeature}</span>`; + } else { + queryableUrlToDisplay += `&startIndex=${this.fromFeature}`; + } + } + + // From feature WS + if (this.resource.type === this.linkFormats.ws) { + if (this.queryableParameters.fromFeature) { + queryableUrlToDisplay += + `<span class="is-active-parameter">&start=${this.fromFeature}</span>`; + } else { + queryableUrlToDisplay += `&start=${this.fromFeature}`; + } + } + + this.queryableUrlToDisplay = this._sanitizer.bypassSecurityTrustHtml(queryableUrlToDisplay); + } + + // Set the selected format and set the queryable parameters + // depending on the resource + setFormat(format: Format) { + this.selectedFormat = format; + this.resetUrlHilightedParameters(); + if (this.resource.type !== linkFormats.ws) { + this.queryableParameters.outputFormat = `&${this.labelFormat[this.resource.type]}=` + + `${this.selectedFormat.mapServerType}`; + this.queryableParameters.outputFormatActive = true; + this.queryableParameters.inseeActive = false; + if (!this.selectedFormat.isProjectable) { + this.queryableParameters.insee = ''; + } + } else { + // Specific treatment for the WS service. We need manipulate the url + // depending the json or shapefile format wanted + if (this.selectedFormat.name === 'JSON') { + const specificRootURL = this.resource.metadataLink.url.replace('all.json', ''); + this.queryableParameters.baseUrl = `${specificRootURL}/${this.resource.metadataLink.name}/all.json`; + this.selectedInsee = null; + this.queryableParameters.insee = ''; + this.queryableParameters.projection = ''; + } else { + this.queryableParameters.baseUrl = this.resource.metadataLink.url.replace('/all.json', ''); + this.queryableParameters.baseUrl += `/${this.resource.metadataLink.name}.shp?`; + if (this.selectedFormat.isProjectable) { + this.setProjection(this.selectedProjection); + } + } + } + + this.updateQueryableUrl(); + this.updateQueryableurlToDisplay(); + } + + // Set the selected insee and set the queryable parameters + // depending on the resource + setInsee(insee) { + this.selectedInsee = insee; + if (!this.selectedInsee || !this.inseeLabel) { + this.queryableParameters.insee = ''; + } else { + this.resetUrlHilightedParameters(); + if (this.resource.type === linkFormats.wfs) { + this.queryableParameters.insee = '&filter=Filter=<Filter> <PropertyIsLike wildcard="*" ' + + 'singleChar=\'.\' escape=\'_\'> <PropertyName>' + + `${this.inseeLabel}</PropertyName><Literal>${this.selectedInsee.insee}` + + '</Literal></PropertyIsLike> </Filter>'; + } else if (this.resource.type === linkFormats.ws) { + this.queryableParameters.baseUrl = this.resource.metadataLink.name.replace('\/all.json', ''); + const match = (/\/ws\/([^\/]+)/g).exec(this.resource.metadataLink.url); + const serviceName = match[1] ? match[1] : ''; + this.queryableParameters.insee = `&mask_db=${serviceName}&mask_layer=adr_voie_lieu.adrcommune` + + `&mask_field=insee&mask_value=${this.selectedInsee.insee}`; + } + this.queryableParameters.inseeActive = true; + } + + this.updateQueryableUrl(); + this.updateQueryableurlToDisplay(); + } + + // Set the selected projection and set the queryable parameters + // depending on the resource + setProjection(projection) { + this.selectedProjection = projection; + this.resetUrlHilightedParameters(); + if (this.resource.type === linkFormats.wfs) { + this.queryableParameters.projection = `&SRSNAME=${projection.name}`; + } else if (this.resource.type === linkFormats.wms || this.resource.type === linkFormats.wcs) { + this.queryableParameters.projection = `&CRS=${projection.name}`; + this.queryableParameters.bbox = `&BBOX=${projection.bbox.minx},` + + `${projection.bbox.miny},` + + `${projection.bbox.maxx},` + + `${projection.bbox.maxy}`; + } else if (this.resource.type === linkFormats.ws) { + if (this.selectedFormat.name !== 'JSON') { + this.queryableParameters.projection = `srsname=${projection.name}`; + } + } + + this.queryableParameters.projectionActive = true; + this.updateQueryableUrl(); + this.updateQueryableurlToDisplay(); + } + + setActiveCountFeatures() { + this.numberFeatures = this.inputCountFeatures; + this.resetUrlHilightedParameters(); + this.queryableParameters.numberFeatures = true; + this.updateQueryableUrl(); + this.updateQueryableurlToDisplay(); + } + + setActiveFromFeature() { + this.resetUrlHilightedParameters(); + this.queryableParameters.fromFeature = true; + this.updateQueryableUrl(); + this.updateQueryableurlToDisplay(); + } + + checkAllFeatures() { + this.numberFeatures = this.isAllFeaturesChecked ? + this._datasetDetailService.dataset.totalData : this.inputCountFeatures; + this.updateQueryableUrl(); + this.updateQueryableurlToDisplay(); + } + + // Reset the variables used to highlight some parameters in the + // personnalized url + resetUrlHilightedParameters() { + this.queryableParameters.projectionActive = false; + this.queryableParameters.inseeActive = false; + this.queryableParameters.outputFormatActive = false; + this.queryableParameters.fromFeature = false; + this.queryableParameters.numberFeatures = false; + } + + transformObjectToArray(object) { + const array = []; + const keys = Object.keys(object); + keys.forEach((key) => { + array.push({ + name: key, + bbox: object[key], + }); + }); + return array; + } + + saveFile(url: string) { + saveAs(url, `${this.resource.metadataLink.name}.${this.selectedFormat.fileExtension}`); + this._notificationService.notify( + { + type: 'success', + message: notificationMessages.general.startDownload, + }, + ); + } + + get totalData() { + return this._datasetDetailService.dataset.totalData; + } + + getProjectionLabel(name: string) { + + const projection = this.projections.find((projection) => { + return projection.name === name; + }); + return projection ? `${projection.commonName} (${projection.name})` : name; + } + + copyToClipboard(text, isRoot) { + const selBox = document.createElement('textarea'); + selBox.style.position = 'fixed'; + selBox.style.height = '0'; + selBox.value = text; + document.body.appendChild(selBox); + selBox.focus(); + selBox.select(); + document.execCommand('copy'); + document.body.removeChild(selBox); + + if (isRoot) { + this.messageClipboardRoot = geosource.mapMessages.copied; + setTimeout(() => { + this.messageClipboardRoot = geosource.mapMessages.share; + }, 2000); + } else { + this.messageClipboard = geosource.mapMessages.copied; + setTimeout(() => { + this.messageClipboard = geosource.mapMessages.share; + }, 2000); + } + + } +} diff --git a/src/app/geosource/components/dataset-detail/dataset-api/resources-queryable/resources-queryable.component.html b/src/app/geosource/components/dataset-detail/dataset-api/resources-queryable/resources-queryable.component.html new file mode 100644 index 0000000000000000000000000000000000000000..f2ce7c8d09eb6dd926131283df32fd6f6691273c --- /dev/null +++ b/src/app/geosource/components/dataset-detail/dataset-api/resources-queryable/resources-queryable.component.html @@ -0,0 +1,38 @@ +<div class="columns resources"> + <div class="column resources-list"> + <div class="column is-12 resource-title" *ngFor="let resource of resources" + (click)="updateSelectedResource(resource.id)" [ngClass]="{'is-active': selectedResource === resource}"> + <div class="columns is-vcentered is-mobile"> + <div class="column is-narrow"> + <app-icon-format [resourceType]="resource.type"></app-icon-format> + </div> + <div class="resource-information"> + <div> + <span class="resource-name"> + {{ resource.name }} + </span> + </div> + <span class="resource-description">{{ resource.description }}</span> + </div> + <span class="icon tooltip is-tooltip-multiline pirate-alert" [attr.data-tooltip]="getMessageWarning(resource)" + *ngIf="getMessageWarning(resource)"> + <i class="fas fa-exclamation-triangle fa-lg"></i> + </span> + <div class="resource-icon"> + <svg xmlns="http://www.w3.org/2000/svg" id="chevron" viewBox="0 0 15 9"> + <path + d="M7.5 7.5c-.1 0-.3-.1-.4-.1l-6-6C1 1.1 1 .8 1.1.6s.5-.2.7 0l5.6 5.6L13 .6c.2-.2.5-.2.7 0s.2.5 0 .7l-6 6c.1.1-.1.2-.2.2z" + class="brandcolor" /> + <path + d="M7.5 7.5c-.1 0-.3-.1-.4-.1l-6-6C1 1.1 1 .8 1.1.6s.5-.2.7 0l5.6 5.6L13 .6c.2-.2.5-.2.7 0s.2.5 0 .7l-6 6c.1.1-.1.2-.2.2z" + class="brandcolor" /> + </svg> + </div> + </div> + <div class="column" *ngIf="this.selectedApis[resource.id]"> + <app-resource-queryable [resource]="resource" [metadata]="metadata" [projections]="projections"> + </app-resource-queryable> + </div> + </div> + </div> +</div> \ No newline at end of file diff --git a/src/app/geosource/components/dataset-detail/dataset-api/resources-queryable/resources-queryable.component.scss b/src/app/geosource/components/dataset-detail/dataset-api/resources-queryable/resources-queryable.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..b6e32fcc6e1f017b601eb6fe3f6c7c4d50f56f7a --- /dev/null +++ b/src/app/geosource/components/dataset-detail/dataset-api/resources-queryable/resources-queryable.component.scss @@ -0,0 +1,58 @@ +@import '../../../../../../scss/variables.scss'; + +.resources { + margin: 0; +} + +.resources-list { + padding-top: 0; + padding-left: 0; +} + +.resource-title { + background-color: $grey-background-color; + border-bottom: 1px solid white; + transition: background-color 0.5s ease; + cursor: pointer; + + svg { + fill: white; + } + + &:hover { + .resource-name { + font-weight: 600; + } + } +} + +.resource-description { + color: $grey-dark-color; +} + +.resource-icon { + margin-left: auto; + + svg { + margin-right: 1rem; + width: 16px; + transform: rotate(-90deg); + } +} + +.resource-title.is-active { + background-color: white; + border-bottom: 1px solid $grey-background-color; + + .resource-name { + font-weight: 600; + } + + svg { + fill: $grey-dark-color; + } +} + +.pirate-alert { + margin-left: 1rem; +} diff --git a/src/app/geosource/components/dataset-detail/dataset-api/resources-queryable/resources-queryable.component.ts b/src/app/geosource/components/dataset-detail/dataset-api/resources-queryable/resources-queryable.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..58dae74d1824c633c5a7620b369556ea3480451e --- /dev/null +++ b/src/app/geosource/components/dataset-detail/dataset-api/resources-queryable/resources-queryable.component.ts @@ -0,0 +1,41 @@ +import { Component, OnInit, Input } from '@angular/core'; +import { Resource, Metadata } from '../../../../models'; +import { ResourcesService } from '../../../../services'; +import { Projection } from '../../../../models/projection.model'; +import { environment } from '../../../../../../environments/environment'; + +@Component({ + selector: 'app-resources-queryable', + templateUrl: './resources-queryable.component.html', + styleUrls: ['./resources-queryable.component.scss'], +}) +export class ResourcesQueryableComponent implements OnInit { + @Input() resources: Resource[]; + @Input() metadata: Metadata; + selectedApis: {}; + projections: Projection[]; + + constructor( + private _resourcesService: ResourcesService, + ) { + } + + ngOnInit() { + this.selectedApis = {}; + this._resourcesService.getProjections().subscribe((projections) => { + this.projections = projections; + // this.selectedResource = this.resources[0]; + }); + } + + updateSelectedResource(idResource: string) { + this.selectedApis[idResource] = !this.selectedApis[idResource]; + + } + + getMessageWarning(resource: Resource) { + return window.location.href.includes(environment.angularAppHost.en) ? + resource.messageWarningEn : + resource.messageWarningFr; + } +} diff --git a/src/app/geosource/components/dataset-detail/dataset-downloads/dataset-downloads.component.html b/src/app/geosource/components/dataset-detail/dataset-downloads/dataset-downloads.component.html new file mode 100644 index 0000000000000000000000000000000000000000..f2dfc85f34d6e1dfe33fc3ae1483dfc22db6977b --- /dev/null +++ b/src/app/geosource/components/dataset-detail/dataset-downloads/dataset-downloads.component.html @@ -0,0 +1,34 @@ +<div class="downloads"> + + <div class="resources-downloadable" *ngIf="hasDownloadableResources"> + <div class="resource-downloadable" *ngFor="let downloadable of downloadableResources | keyvalue"> + <div class="resource-description"> + <span>{{downloadable.key}}</span> + </div> + <div class="resource-downloadable-files" *ngFor="let resource of downloadable.value"> + <app-resource-downloadable [link]="resource"> + </app-resource-downloadable> + </div> + </div> + </div> + + <div class="resources-other" *ngIf="hasOtherResources"> + <div class="resource-header"> + <span class="resource-header-title" i18n="@@dataset.resources.other.title"> Downloadable Resources </span> + </div> + + <ng-container *ngIf="otherResources"> + <div class="resource-other" *ngFor="let other of otherResources"> + <div class="resource-other-title"> + <span>{{ other.name }}</span> + </div> + <div class="resource-other-link"> + <a [href]="other.url" target="_blank">{{ other.url }}</a> + </div> + + </div> + </ng-container> + + + </div> +</div> \ No newline at end of file diff --git a/src/app/geosource/components/dataset-detail/dataset-downloads/dataset-downloads.component.scss b/src/app/geosource/components/dataset-detail/dataset-downloads/dataset-downloads.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..53f65ff3e3409351eac4e8f364c1948dd03a7952 --- /dev/null +++ b/src/app/geosource/components/dataset-detail/dataset-downloads/dataset-downloads.component.scss @@ -0,0 +1,57 @@ +@import "../../../../../scss/variables.scss"; + +.downloads { + display: flex; +} + +.resources-downloadable { + width: 60%; + margin-top: 2rem; + margin-right: 2rem; + border-bottom: 2px solid $grey-background-color; +} + +.resource-downloadable { + margin-top: 1rem; + padding-bottom: 1rem; + + &:not(:last-of-type) { + border-bottom: 1px solid $grey-background-color; + } +} + +.resources-other { + margin-top: 2rem; +} + +.resource-other-title { + margin-top: 1rem; + margin-bottom: 1rem; + + span { + /* stylelint-disable-line */ + font-size: 1.1rem; + font-weight: 600; + } +} + +.resource-other-link { + a { + font-size: 0.875rem; + } +} + +.resource-header-icon { + height: 2.25rem; + width: 2.25rem; + background-color: $grey-super-light-color; + display: flex; + align-items: center; + justify-content: center; + border-radius: 4px; + + svg { + height: 1.125rem; + fill: white; + } +} \ No newline at end of file diff --git a/src/app/geosource/components/dataset-detail/dataset-downloads/dataset-downloads.component.spec.ts b/src/app/geosource/components/dataset-detail/dataset-downloads/dataset-downloads.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..aae8691b510297f17af963822e908ea9ce672a1a --- /dev/null +++ b/src/app/geosource/components/dataset-detail/dataset-downloads/dataset-downloads.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DatasetDownloadsComponent } from './dataset-downloads.component'; + +describe('DatasetDownloadsComponent', () => { + let component: DatasetDownloadsComponent; + let fixture: ComponentFixture<DatasetDownloadsComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ DatasetDownloadsComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DatasetDownloadsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/geosource/components/dataset-detail/dataset-downloads/dataset-downloads.component.ts b/src/app/geosource/components/dataset-detail/dataset-downloads/dataset-downloads.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..357efc05e50163f7bdbd958cd8dade076f46655a --- /dev/null +++ b/src/app/geosource/components/dataset-detail/dataset-downloads/dataset-downloads.component.ts @@ -0,0 +1,102 @@ +import { Component, OnInit } from '@angular/core'; +import { IMetadataLink, Metadata, Resource } from '../../../models'; +import { DatasetDetailService, ResourcesService } from '../../../services'; +import { NotificationService } from '../../../../core/services'; +import { Subscription } from 'rxjs'; +import { notificationMessages } from '../../../../../i18n/traductions'; +import { Notification } from '../../../../core/models'; + +@Component({ + selector: 'app-dataset-downloads', + templateUrl: './dataset-downloads.component.html', + styleUrls: ['./dataset-downloads.component.scss'] +}) +export class DatasetDownloadsComponent implements OnInit { + + metadata: Metadata; + sub: Subscription; + downloadableResources: IMetadataLink[]; + otherResources: IMetadataLink[]; + + isSample = false; + resources: Resource[]; + hasBeenInitialized = false; + + constructor( + private _datasetDetailService: DatasetDetailService, + private _resourcesService: ResourcesService, + private _notificationService: NotificationService, + ) { } + + ngOnInit() { + this.resources = []; + this.downloadableResources = []; + this.otherResources = []; + + this.isSample = this._datasetDetailService.dataset.editorialMetadata.isSample; + + this.initialize(); + this._resourcesService.getResources().subscribe( + (results) => { + this.resources = results; + + this.initialize(); + this.sub = this._datasetDetailService.dataset$.subscribe(() => { + this.initialize(); + }); + }, + (err) => { + this._notificationService.notify(new Notification({ + type: 'error', + message: `${notificationMessages.resources.initializationError}`, + })); + }, + ); + } + + ngOnDestroy() { + if (this.sub) { + this.sub.unsubscribe(); + } + } + + // Resources are organized on 2 levels : + // -> 1st level: by metadata link description + // -> 2nd level: for each link description in 3 categories: + // - queryable + // - downloadable + // - other + // How to organize: we compare the type of one resource from our resource service + // and the ES metadata link property. If there is a match, the service will let us know if the resource + // is queryable or downloadable. If there is no match and the ES resource cannot be found in the service, + // we put it in "others" resources catagory. + initialize() { + this.metadata = this._datasetDetailService.datasetMetadata; + if (this.metadata && this.resources.length > 0 && !this.hasBeenInitialized) { + this.hasBeenInitialized = true; + if (this.metadata.link) { + this.metadata.link.forEach((link) => { + if (link.service === undefined) { + if (link.formats) { + if (!this.downloadableResources[link.description]) { + this.downloadableResources[link.description] = []; + } + this.downloadableResources[link.description].push(link); + } else { + this.otherResources.push(link); + } + } + }); + } + } + } + + get hasDownloadableResources() { + return Object.keys(this.downloadableResources).length > 0; + } + + get hasOtherResources() { + return Object.keys(this.otherResources).length > 0; + } + +} diff --git a/src/app/geosource/components/dataset-detail/dataset-downloads/resource-downloadable/resource-downloadable.component.html b/src/app/geosource/components/dataset-detail/dataset-downloads/resource-downloadable/resource-downloadable.component.html new file mode 100644 index 0000000000000000000000000000000000000000..175409d3c36623e35e8628382ddf6b05f96637e6 --- /dev/null +++ b/src/app/geosource/components/dataset-detail/dataset-downloads/resource-downloadable/resource-downloadable.component.html @@ -0,0 +1,44 @@ +<div class="resource"> + + <div class="resource-left"> + <div class="resource-icon" [ngClass]="link.formats[0]"> + <span [inlineSVG]="formatSVGPath"> + </span> + </div> + <div class="resource-main"> + <div class="resource-main-name"> + <span>{{ link.name }} + </span> + </div> + <div class="resource-main-size"> + <span *ngIf="!humanFileSize(link['content-length'], true).includes('NaN')"> + {{ humanFileSize(link['content-length'], true) }} + </span> + </div> + </div> + </div> + + <div class="resource-download-icon"> + <a [href]="link.url" target="_blank"> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 23"> + <g id="btn-download"> + <path + d="M22 14c-.6 0-1 .4-1 1v5H3v-5c0-.6-.4-1-1-1s-1 .4-1 1v6c0 .6.4 1 1 1h20c.6 0 1-.4 1-1v-6c0-.6-.4-1-1-1z" + class="download_x002D_color" /> + <path + d="M11.3 16.7c.2.2.5.3.7.3s.5-.1.7-.3l6-6c.4-.4.4-1 0-1.4s-1-.4-1.4 0L13 13.6V2c0-.6-.4-1-1-1s-1 .4-1 1v11.6L6.7 9.3c-.4-.4-1-.4-1.4 0s-.4 1 0 1.4l6 6z" + class="download_x002D_color" /> + <g> + <path + d="M22 14c-.6 0-1 .4-1 1v5H3v-5c0-.6-.4-1-1-1s-1 .4-1 1v6c0 .6.4 1 1 1h20c.6 0 1-.4 1-1v-6c0-.6-.4-1-1-1z" + class="download_x002D_color" /> + <path + d="M11.3 16.7c.2.2.5.3.7.3s.5-.1.7-.3l6-6c.4-.4.4-1 0-1.4s-1-.4-1.4 0L13 13.6V2c0-.6-.4-1-1-1s-1 .4-1 1v11.6L6.7 9.3c-.4-.4-1-.4-1.4 0s-.4 1 0 1.4l6 6z" + class="download_x002D_color" /> + </g> + </g> + </svg> + </a> + </div> + +</div> diff --git a/src/app/geosource/components/dataset-detail/dataset-downloads/resource-downloadable/resource-downloadable.component.scss b/src/app/geosource/components/dataset-detail/dataset-downloads/resource-downloadable/resource-downloadable.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..0e2b726c42b81a1b0b70c0f274532c1ecb694455 --- /dev/null +++ b/src/app/geosource/components/dataset-detail/dataset-downloads/resource-downloadable/resource-downloadable.component.scss @@ -0,0 +1,85 @@ +@import '../../../../../../scss/variables.scss'; + +.resource { + background-color: white; + display: flex; + justify-content: space-between; + align-items: center; +} + +.resource-download-icon { + padding: 0.5rem 0.4rem; + border: 1px solid $grey-super-light-color; + border-radius: 4px; + margin-right: 0.75rem; + + a { + display: flex; + } + + svg { + height: 1.5rem; + fill: $link-color; + } + + &:hover { + opacity: 0.7; + } +} + +.resource-left { + display: flex; + align-items: center; + + .resource-main { + margin-left: 1rem; + } + + .resource-main-name span { + word-break: break-all; + } + + .resource-icon { + /deep/ svg { + height: 2.125rem; + + .grey { + fill: #707070; + } + } + + span { + display: flex; + } + } + + .resource-icon.PDF { + /deep/ svg { + fill: #ef7575; + } + } + + .resource-icon.ZIP { + /deep/ svg { + fill: #e5bb4e; + } + } + + .resource-icon.ECW { + /deep/ svg { + fill: #da92bb; + } + } + + .resource-icon.CSV { + /deep/ svg { + fill: #86b89b; + } + } + + .resource-icon.TIF { + /deep/ svg { + fill: #7e99ce; + } + } +} diff --git a/src/app/geosource/components/dataset-detail/dataset-downloads/resource-downloadable/resource-downloadable.component.ts b/src/app/geosource/components/dataset-detail/dataset-downloads/resource-downloadable/resource-downloadable.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..fa58db23c78f9c1606f84813c1be7841b1e95ee6 --- /dev/null +++ b/src/app/geosource/components/dataset-detail/dataset-downloads/resource-downloadable/resource-downloadable.component.ts @@ -0,0 +1,54 @@ +import { Component, OnInit, Input } from '@angular/core'; +import { IMetadataLink } from '../../../../models'; +import { NotificationService, FileService } from '../../../../../core/services'; + +@Component({ + selector: 'app-resource-downloadable', + templateUrl: './resource-downloadable.component.html', + styleUrls: ['./resource-downloadable.component.scss'], +}) +export class ResourceDownloadableComponent implements OnInit { + @Input() link: IMetadataLink; + formatSVGPath: string; + + constructor( + private _fileService: FileService, + private _notificationService: NotificationService, + ) { } + + ngOnInit() { + // Set the picto image. + if (this.link.formats.includes('PDF')) { + this.formatSVGPath = './assets/img/api_picto_pdf.svg'; + } else if (this.link.formats.includes('ZIP')) { + this.formatSVGPath = './assets/img/api_picto_zip.svg'; + } else if (this.link.formats.includes('ECW')) { + this.formatSVGPath = './assets/img/api_picto_ecw.svg'; + } else if (this.link.formats.includes('CSV')) { + this.formatSVGPath = './assets/img/api_picto_csv.svg'; + } else if (this.link.formats.includes('TIF')) { + this.formatSVGPath = './assets/img/api_picto_tif.svg'; + } else if (this.link.formats.includes('XML')) { + this.formatSVGPath = './assets/img/api_picto_xml.svg'; + } else { + this.formatSVGPath = './assets/img/api_picto_placeholder.svg'; + } + } + + humanFileSize(bytes: string, si: boolean) { + let sizeFilebytes = Number(bytes); + const thresh = si ? 1000 : 1024; + if (Math.abs(Number((bytes))) < thresh) { + return `${bytes} B`; + } + const units = si + ? ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] + : ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']; + let u = -1; + do { + sizeFilebytes /= thresh; + u += 1; + } while (Math.abs(sizeFilebytes) >= thresh && u < units.length - 1); + return `${sizeFilebytes.toFixed(1)} ${units[u]}`; + } +} diff --git a/src/app/geosource/components/index.ts b/src/app/geosource/components/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..9b80e6767e59dc4f2ab4347a0d1c9c6da881229f --- /dev/null +++ b/src/app/geosource/components/index.ts @@ -0,0 +1,78 @@ +import { ResultsComponent } from './results/results.component'; +import { DatasetDetailComponent } from './dataset-detail/dataset-detail.component'; + +import { DatasetAPIComponent } from './dataset-detail/dataset-api/dataset-api.component'; +import { DatasetDownloadsComponent } from './dataset-detail/dataset-downloads/dataset-downloads.component'; +// tslint:disable-next-line:max-line-length +import { ResourceQueryableComponent } from './dataset-detail/dataset-api/resources-queryable/resource-queryable/resource-queryable.component'; +// tslint:disable-next-line:max-line-length +import { ResourcesQueryableComponent } from './dataset-detail/dataset-api/resources-queryable/resources-queryable.component'; +// tslint:disable-next-line:max-line-length +import { ResourceDownloadableComponent } from './dataset-detail/dataset-downloads/resource-downloadable/resource-downloadable.component'; +import { DatasetMapComponent } from './dataset-detail/dataset-map/dataset-map.component'; +import { DatasetInfoComponent } from './dataset-detail/dataset-info/dataset-info.component'; +import { DatasetTableComponent } from './dataset-detail/dataset-table/dataset-table.component'; +import { IconFormatComponent } from './dataset-detail/dataset-api/icon-format/icon-format.component'; +import { SearchBarComponent } from './search-bar/search-bar.component'; +import { ResearchComponent } from './research/research.component'; +import { SortComponent } from './sort/sort.component'; +import { FilterListComponent } from './filter-list/filter-list.component'; +import { FilterDetailComponent } from './filter-list/filter-detail/filter-detail.component'; +import { ResultDatasetComponent } from './results/result-dataset/result-dataset.component'; +import { ResultsTabScopeComponent } from './results/results-tab-scope/results-tab-scope.component'; +import { ResultPostComponent } from './results/result-post/result-post.component'; +import { DatasetTableMapComponent } from './dataset-detail/dataset-table-map/dataset-table-map.component'; +import { DatasetDataDetailsComponent } from './dataset-detail/dataset-data-details/dataset-data-details.component'; +// tslint:disable-next-line: max-line-length +import { DatasetDataDetailPropertiesComponent } from './dataset-detail/dataset-data-details/dataset-data-detail-properties/dataset-data-detail-properties.component'; + +export { + DatasetDetailComponent, + DatasetAPIComponent, + ResourceQueryableComponent, + ResourceDownloadableComponent, + DatasetMapComponent, + DatasetInfoComponent, + DatasetTableMapComponent, + DatasetTableComponent, + ResultsComponent, + SearchBarComponent, + ResearchComponent, + SortComponent, + FilterListComponent, + FilterDetailComponent, + ResultDatasetComponent, + ResultsTabScopeComponent, + ResultPostComponent, + ResourcesQueryableComponent, + IconFormatComponent, + DatasetDataDetailsComponent, + DatasetDataDetailPropertiesComponent, + DatasetDownloadsComponent, +}; + +// tslint:disable-next-line:variable-name +export const GeosourceComponents = [ + DatasetDetailComponent, + DatasetAPIComponent, + ResourceQueryableComponent, + ResourceDownloadableComponent, + DatasetMapComponent, + DatasetInfoComponent, + DatasetTableMapComponent, + DatasetTableComponent, + ResultsComponent, + SearchBarComponent, + ResearchComponent, + SortComponent, + FilterListComponent, + FilterDetailComponent, + ResultDatasetComponent, + ResultsTabScopeComponent, + ResultPostComponent, + ResourcesQueryableComponent, + IconFormatComponent, + DatasetDataDetailsComponent, + DatasetDataDetailPropertiesComponent, + DatasetDownloadsComponent, +]; diff --git a/src/app/routes.ts b/src/app/routes.ts index 762fe7626d3462282e731b1ab3fd440e02bb791b..d84f440695d9c00a60b7da7db706345357fcce98 100644 --- a/src/app/routes.ts +++ b/src/app/routes.ts @@ -211,10 +211,17 @@ export const AppRoutes = { }, }, resources: { - uri: 'ressources', + uri: 'api', title: { - fr: 'Ressources', - en: 'Resources', + fr: 'API', + en: 'API', + }, + }, + downloads: { + uri: 'telechargements', + title: { + fr: 'Téléchargements', + en: 'Downloads', }, }, beta: { diff --git a/src/app/shared/models/metadata.model.ts b/src/app/shared/models/metadata.model.ts index 908463a9fd93587c2aab52e9f7ca9209839d9169..8824c361de4926b9ba5dd77093959d86ae4f1dc7 100644 --- a/src/app/shared/models/metadata.model.ts +++ b/src/app/shared/models/metadata.model.ts @@ -183,7 +183,7 @@ export class Metadata { } }); } - this.providers = Array.from(providersToAdd); + this.providers = Array.from(providersToAdd) as string[]; this.link = data.link ? data.link : []; this.publicationDate = data.publicationDate; this.topic_category = data.topic_category; diff --git a/src/i18n/messages.en.xlf b/src/i18n/messages.en.xlf index 23c9c04d0db2493cf61940f72a3d188050d0140a..5247408e9fc48e4a63a97d71372eaf4b90c5bda6 100644 --- a/src/i18n/messages.en.xlf +++ b/src/i18n/messages.en.xlf @@ -434,8 +434,8 @@ <target>Center to my position</target> </trans-unit> <trans-unit id="dataset.detail.api" datatype="html"> - <source>API and download</source> - <target>API and download</target> + <source>Downloads</source> + <target>Downloads</target> </trans-unit> <trans-unit id="dataset.detail.info" datatype="html"> <source>This dataset doesn't contain geographical data.</source> diff --git a/src/i18n/messages.fr.xlf b/src/i18n/messages.fr.xlf index 39f43d6bd043f0344ba2aa577c202c84ef8b22c9..0a0ec78bf2d836ad93da93228595150f0e508172 100644 --- a/src/i18n/messages.fr.xlf +++ b/src/i18n/messages.fr.xlf @@ -429,13 +429,19 @@ données sont en accès restreint. Pour consulter ou utiliser l’intégralité <source>Share the map</source> <target>Partager la carte</target> </trans-unit> +<<<<<<< HEAD <trans-unit id="dataset.detail.map.center" datatype="html"> <source>Center to my position</source> <target>Centrer sur ma position</target> +======= + <trans-unit id="dataset.detail.downloads" datatype="html"> + <source>API</source> + <target>Téléchargements</target> +>>>>>>> WIP </trans-unit> <trans-unit id="dataset.detail.api" datatype="html"> - <source>API and download</source> - <target>API et téléchargements</target> + <source>API</source> + <target>API</target> </trans-unit> <trans-unit id="dataset.detail.info" datatype="html"> <source>This dataset doesn't contain geographical data.</source> diff --git a/update.sh b/update.sh new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391