From d6674600c19ec6a3d30b784fac7845fffb293029 Mon Sep 17 00:00:00 2001 From: cazenave <cazenave@cines.fr> Date: Sun, 15 Nov 2020 15:08:32 +0100 Subject: [PATCH 01/18] add mapping --- package-lock.json | 8 +++++++ package.json | 1 + src/app/app.module.ts | 4 +++- src/app/mapping/mapping.component.html | 1 + src/app/mapping/mapping.component.scss | 0 src/app/mapping/mapping.component.spec.ts | 25 ++++++++++++++++++++ src/app/mapping/mapping.component.ts | 15 ++++++++++++ src/app/publishapi/publishapi.component.html | 1 + 8 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 src/app/mapping/mapping.component.html create mode 100644 src/app/mapping/mapping.component.scss create mode 100644 src/app/mapping/mapping.component.spec.ts create mode 100644 src/app/mapping/mapping.component.ts diff --git a/package-lock.json b/package-lock.json index 6e2dc8224..40cb39f3d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2883,6 +2883,14 @@ } } }, + "@ngx-lite/json-ld": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@ngx-lite/json-ld/-/json-ld-0.6.2.tgz", + "integrity": "sha512-oFWyYqBPOKQZBqP2ev3Xkn5UjjiWAC1dKYsCduvpDJTA3phc573NhPDpBqxMDfoeIuu72QOJogPehFWJV5991w==", + "requires": { + "tslib": "^1.9.0" + } + }, "@nodelib/fs.scandir": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", diff --git a/package.json b/package.json index 930d39430..ff6a33d39 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "@angular/router": "~9.1.11", "@nebular/auth": "^6.2.1", "@nebular/theme": "^5.1.0", + "@ngx-lite/json-ld": "^0.6.2", "file-saver": "^2.0.2", "ng2-cookies": "^1.0.12", "ngx-filesaver": "^9.0.0", diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 50cab74b0..b3bb3590d 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -44,6 +44,7 @@ import { AccountComponent } from './account/account.component'; import { AccountModule } from './account/account.module'; import { SearchModule} from './search/search.module'; import { StatsComponent } from './stats/stats.component'; +import { MappingComponent } from './mapping/mapping.component'; @NgModule({ @@ -64,7 +65,8 @@ import { StatsComponent } from './stats/stats.component'; PublishApiComponent, SearchComponent, AccountComponent, - StatsComponent + StatsComponent, + MappingComponent ], imports: [ BrowserModule, diff --git a/src/app/mapping/mapping.component.html b/src/app/mapping/mapping.component.html new file mode 100644 index 000000000..b04ead3c3 --- /dev/null +++ b/src/app/mapping/mapping.component.html @@ -0,0 +1 @@ +<p>mapping works!</p> diff --git a/src/app/mapping/mapping.component.scss b/src/app/mapping/mapping.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/mapping/mapping.component.spec.ts b/src/app/mapping/mapping.component.spec.ts new file mode 100644 index 000000000..dd48d2db4 --- /dev/null +++ b/src/app/mapping/mapping.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MappingComponent } from './mapping.component'; + +describe('MappingComponent', () => { + let component: MappingComponent; + let fixture: ComponentFixture<MappingComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ MappingComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(MappingComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/mapping/mapping.component.ts b/src/app/mapping/mapping.component.ts new file mode 100644 index 000000000..f5ac89394 --- /dev/null +++ b/src/app/mapping/mapping.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-mapping', + templateUrl: './mapping.component.html', + styleUrls: ['./mapping.component.scss'] +}) +export class MappingComponent implements OnInit { + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/src/app/publishapi/publishapi.component.html b/src/app/publishapi/publishapi.component.html index 1dcac6658..fba8aa56b 100644 --- a/src/app/publishapi/publishapi.component.html +++ b/src/app/publishapi/publishapi.component.html @@ -36,6 +36,7 @@ <p class="lorem"> Map your metadata schema with DCAT schema </p> + <app-mapping></app-mapping> <button class="prev-button" nbButton nbStepperPrevious>prev</button> <button class="next-button" nbButton nbStepperNext>next</button> </nb-step> -- GitLab From 1582b041ad45d9afdfc621c99b14dc2dc27a96bb Mon Sep 17 00:00:00 2001 From: Baptiste Toulemonde <toulemonde@cines.fr> Date: Mon, 31 May 2021 11:34:12 +0200 Subject: [PATCH 02/18] init mapping component --- src/app/app.module.ts | 1 + .../authentication/services/auth.service.ts | 2 +- src/app/mapping/mapping.component.html | 23 ++++++++++++++++++- src/app/mapping/mapping.component.scss | 16 +++++++++++++ 4 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 80797bb61..cb42b8198 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -63,6 +63,7 @@ import { DashboardComponent } from './dashboard/dashboard.component'; SearchComponent, StatsComponent, DashboardComponent, + MappingComponent ], imports: [ BrowserModule, diff --git a/src/app/authentication/services/auth.service.ts b/src/app/authentication/services/auth.service.ts index 915698895..fd53b6610 100644 --- a/src/app/authentication/services/auth.service.ts +++ b/src/app/authentication/services/auth.service.ts @@ -6,7 +6,7 @@ import { map } from "rxjs/operators"; import { AppConfiguration } from 'src/app/AppConfiguration'; -const AUTH_API = "https://f2ds.eosc-pillar.eu/harvester/auth"; +const AUTH_API = "http://localhost:8080/harvester/auth"; const F2DSAPI = "https://f2ds.eosc-pillar.eu" const httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/json' }) diff --git a/src/app/mapping/mapping.component.html b/src/app/mapping/mapping.component.html index b04ead3c3..a0fead3cb 100644 --- a/src/app/mapping/mapping.component.html +++ b/src/app/mapping/mapping.component.html @@ -1 +1,22 @@ -<p>mapping works!</p> +<div class="card-row"> + <div class="card-col"> + <nb-card size="giant"> + <nb-card-header>Dataset metadata</nb-card-header> + <nb-card-body></nb-card-body> + </nb-card> + </div> + <div class="card-col"> + <nb-card size="giant"> + <nb-card-header>Dcat dataset</nb-card-header> + <nb-card-body></nb-card-body> + </nb-card> + </div> +</div> +<div class="card-row"> + <div class="card-col"> + <nb-card> + <nb-card-header>Map</nb-card-header> + <nb-card-body></nb-card-body> + </nb-card> + </div> +</div> \ No newline at end of file diff --git a/src/app/mapping/mapping.component.scss b/src/app/mapping/mapping.component.scss index e69de29bb..b89c9d5ad 100644 --- a/src/app/mapping/mapping.component.scss +++ b/src/app/mapping/mapping.component.scss @@ -0,0 +1,16 @@ +:host { + display: block; + max-height: 25rem; + overflow-x: hidden; + overflow-y: auto; + } + + .card-row { + display: flex; + margin: 0 -0.5rem; + } + + .card-col { + flex: 1 0 calc(50% - 1rem); + margin: 0 0.5rem; + } \ No newline at end of file -- GitLab From 352f14b81d52f70664829d5ca7b1f1c88016024f Mon Sep 17 00:00:00 2001 From: Baptiste Toulemonde <toulemonde@cines.fr> Date: Mon, 31 May 2021 11:48:04 +0200 Subject: [PATCH 03/18] resolve merge conflicts --- src/app/authentication/services/auth.service.ts | 5 ----- src/app/services/parse-xml.service.ts | 4 ---- src/environments/environment.prod.ts | 4 ---- 3 files changed, 13 deletions(-) diff --git a/src/app/authentication/services/auth.service.ts b/src/app/authentication/services/auth.service.ts index a23960c77..d4ab6aa4e 100644 --- a/src/app/authentication/services/auth.service.ts +++ b/src/app/authentication/services/auth.service.ts @@ -6,13 +6,8 @@ import { map } from "rxjs/operators"; import { AppConfiguration } from 'src/app/AppConfiguration'; -<<<<<<< HEAD const AUTH_API = "http://localhost:8080/harvester/auth"; const F2DSAPI = "https://f2ds.eosc-pillar.eu" -======= -const AUTH_API = "https://ffds.eosc-pillar.eu/harvester/auth"; -const F2DSAPI = "https://ffds.eosc-pillar.eu" ->>>>>>> c3c1ead3ae1d28e003a33da588d1b6130e0145fb const httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/json' }) }; diff --git a/src/app/services/parse-xml.service.ts b/src/app/services/parse-xml.service.ts index cc9d97c70..44089781b 100644 --- a/src/app/services/parse-xml.service.ts +++ b/src/app/services/parse-xml.service.ts @@ -7,11 +7,7 @@ import { HttpClient, HttpHeaders } from '@angular/common/http'; }) export class ParseXmlService { -<<<<<<< HEAD blazePath = "https://f2ds.eosc-pillar.eu/blazegraph/sparql" -======= - blazePath = "https://ffds.eosc-pillar.eu/blazegraph/sparql" ->>>>>>> c3c1ead3ae1d28e003a33da588d1b6130e0145fb constructor(private http:HttpClient) { } diff --git a/src/environments/environment.prod.ts b/src/environments/environment.prod.ts index 44102195a..3d96a7919 100644 --- a/src/environments/environment.prod.ts +++ b/src/environments/environment.prod.ts @@ -1,8 +1,4 @@ export const environment = { production: true, -<<<<<<< HEAD apiurl: 'f2ds.eosc-pillar.eu', -======= - apiurl: 'ffds.eosc-pillar.eu', ->>>>>>> c3c1ead3ae1d28e003a33da588d1b6130e0145fb }; -- GitLab From 7aab623f89a9eefd9b6ffb703056583fe2734157 Mon Sep 17 00:00:00 2001 From: Baptiste Toulemonde <toulemonde@cines.fr> Date: Fri, 25 Jun 2021 14:51:25 +0200 Subject: [PATCH 04/18] datasets descriptions --- src/app/app.module.ts | 4 +- src/app/datasets/datasets.component.ts | 15 +- .../datasets/services/dataset-crud.service.ts | 7 +- src/app/mapping/mapping.component.html | 4 +- src/app/mapping/mapping.component.scss | 12 +- src/app/mapping/mapping.component.ts | 167 +++++++++++++++++- src/app/mapping/tree/tree.component.html | 15 ++ src/app/mapping/tree/tree.component.scss | 0 src/app/mapping/tree/tree.component.spec.ts | 25 +++ src/app/mapping/tree/tree.component.ts | 25 +++ src/app/repository/repository.component.ts | 2 +- src/assets/dataset.json | 148 ++++++++++++++++ 12 files changed, 402 insertions(+), 22 deletions(-) create mode 100644 src/app/mapping/tree/tree.component.html create mode 100644 src/app/mapping/tree/tree.component.scss create mode 100644 src/app/mapping/tree/tree.component.spec.ts create mode 100644 src/app/mapping/tree/tree.component.ts create mode 100644 src/assets/dataset.json diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 56b0179d9..cfc2895ae 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -39,6 +39,7 @@ import { NbLayoutModule, NbThemeModule, NbTooltipModule, NbSpinnerModule, NbSele import { NbAuthModule } from '@nebular/auth/auth.module'; import { NbDummyAuthStrategy } from '@nebular/auth/strategies/dummy/dummy-strategy'; import { DashboardComponent } from './dashboard/dashboard.component'; +import { TreeComponent } from './mapping/tree/tree.component'; @NgModule({ @@ -55,7 +56,8 @@ import { DashboardComponent } from './dashboard/dashboard.component'; SearchComponent, StatsComponent, DashboardComponent, - MappingComponent + MappingComponent, + TreeComponent, ], imports: [ BrowserModule, diff --git a/src/app/datasets/datasets.component.ts b/src/app/datasets/datasets.component.ts index f4528aafa..7b2675b5b 100644 --- a/src/app/datasets/datasets.component.ts +++ b/src/app/datasets/datasets.component.ts @@ -20,7 +20,7 @@ export class DatasetsComponent implements OnInit { Object = Object; urlrepo = "dataverse.ird.fr"; -// urlrepo = "data.inrae.fr"; +// urlrepo = "data.inrae.fr"; constructor( private appConfig: AppConfiguration, @@ -103,7 +103,7 @@ export class DatasetsComponent implements OnInit { for (var i = 0; i < item['datasetVersion']['metadataBlocks']['citation']['fields'].length; i++) { if (item['datasetVersion']['metadataBlocks']['citation']['fields'][i]['typeName'] == "dsDescription") { - description = JSON.stringify(item['datasetVersion']['metadataBlocks']['citation']['fields'][i]['value']); + description = JSON.stringify(item['datasetVersion']['metadataBlocks']['citation']['fields'][i]['value'][0]['dsDescriptionValue']['value']); } if (item['datasetVersion']['metadataBlocks']['citation']['fields'][i]['typeName'] == "title") { name = JSON.stringify( item['datasetVersion']['metadataBlocks']['citation']['fields'][i]['value'] ); @@ -117,12 +117,11 @@ export class DatasetsComponent implements OnInit { @prefix language: <http://id.loc.gov/vocabulary/iso639-1/>.\n\ @prefix s: <'+ this.appConfig.fdpurl + '/>.\n\ @prefix c: <'+ this.appConfig.fdpurl + '/catalog/>.\n\ - \n\ s:new\n\ a dcat:Dataset, dcat:Resource;\n\ - dct:description '+ description + ';\n\ + dct:description ' + description + ';\n\ dct:hasVersion "1.0";\n\ - dct:isPartOf c:a21f9b06-b7e7-43c0-869d-d81f09053383;\n\ + dct:isPartOf <http://fdp-api.f2ds.svc.cluster.local/catalog/e5f49dbf-c976-4ca7-b4ee-7cc90923d9f3>;\n\ dct:language language:en;\n\ dct:license <http://rdflicense.appspot.com/rdflicense/cc-by-nc-nd3.0>;\n\ dct:title '+ name + ';\n\ @@ -130,7 +129,7 @@ export class DatasetsComponent implements OnInit { console.log(data); - // return this.dataSetService.createDataSet(data); + //return this.dataSetService.createDataSet(data); } @@ -152,8 +151,8 @@ export class DatasetsComponent implements OnInit { data='@prefix dcat: <http://www.w3.org/ns/dcat#>.\n\ @prefix dct: <http://purl.org/dc/terms/>.\n\ @prefix language: <http://id.loc.gov/vocabulary/iso639-1/>.\n\ - @prefix ffd: <https://ffds.eosc-pillar.eu/>.\n\ - @prefix d: <https://ffds.eosc-pillar.eu/dataset/>.\n\ + @prefix ffd: <https://f2ds.eosc-pillar.eu/>.\n\ + @prefix d: <https://f2ds.eosc-pillar.eu/dataset/>.\n\ @prefix GVW: <https://dataverse.ird.fr/dataset.xhtml?persistentId=doi:10.23708/GVWCA0#>.\n\ \n\ ffd:new\n\ diff --git a/src/app/datasets/services/dataset-crud.service.ts b/src/app/datasets/services/dataset-crud.service.ts index 3abb6be9e..a1b0657ab 100644 --- a/src/app/datasets/services/dataset-crud.service.ts +++ b/src/app/datasets/services/dataset-crud.service.ts @@ -1,5 +1,6 @@ import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; import { AppConfiguration } from 'src/app/AppConfiguration'; import { AuthService } from 'src/app/authentication/services/auth.service'; import { ParseXmlService } from '../../services/parse-xml.service'; @@ -28,7 +29,7 @@ export class DatasetCrudService { }) }; - let resultat = this.http.post(this.appConfig.fdpurl+"/catalog", data, httpOptions ).subscribe( (r)=>{console.log('reponse: ', r)}) ; + let resultat = this.http.post(this.appConfig.fdpurl+"/dataset", data, httpOptions ).subscribe( (r)=>{console.log('reponse: ', r)}) ; if (resultat){ console.log("resultat: " + JSON.stringify(resultat)); return JSON.stringify(resultat); @@ -78,6 +79,10 @@ export class DatasetCrudService { return exist } + getLocally<T = any>(path: string): Observable<T> { + console.log('On getLocally using filepath : ', `${path}`); + return this.http.get<T>(`${path}`); + } } diff --git a/src/app/mapping/mapping.component.html b/src/app/mapping/mapping.component.html index a0fead3cb..003393480 100644 --- a/src/app/mapping/mapping.component.html +++ b/src/app/mapping/mapping.component.html @@ -2,7 +2,9 @@ <div class="card-col"> <nb-card size="giant"> <nb-card-header>Dataset metadata</nb-card-header> - <nb-card-body></nb-card-body> + <nb-card-body> + <app-tree [items]="Object.keys(itemsdataset)" [itemsDataset]="itemsdataset"></app-tree> + </nb-card-body> </nb-card> </div> <div class="card-col"> diff --git a/src/app/mapping/mapping.component.scss b/src/app/mapping/mapping.component.scss index b89c9d5ad..2326b68a6 100644 --- a/src/app/mapping/mapping.component.scss +++ b/src/app/mapping/mapping.component.scss @@ -1,16 +1,12 @@ -:host { - display: block; - max-height: 25rem; - overflow-x: hidden; - overflow-y: auto; - } - + .card-row { display: flex; + flex: 1 0 calc(100%); margin: 0 -0.5rem; } .card-col { - flex: 1 0 calc(50% - 1rem); + width: 50%; + flex: calc(50% ); margin: 0 0.5rem; } \ No newline at end of file diff --git a/src/app/mapping/mapping.component.ts b/src/app/mapping/mapping.component.ts index f5ac89394..75a75adbf 100644 --- a/src/app/mapping/mapping.component.ts +++ b/src/app/mapping/mapping.component.ts @@ -1,4 +1,10 @@ +import { HttpClient } from '@angular/common/http'; import { Component, OnInit } from '@angular/core'; +import { FormControl, FormGroup } from '@angular/forms'; +import { FileSaverService } from 'ngx-filesaver'; +import { AppConfiguration } from '../AppConfiguration'; +import { DatasetCrudService } from '../datasets/services/dataset-crud.service'; + @Component({ selector: 'app-mapping', @@ -7,9 +13,166 @@ import { Component, OnInit } from '@angular/core'; }) export class MappingComponent implements OnInit { - constructor() { } + itemsdatasets: any; + itemsdataset: Object; + fields : Map<number, string[]>; + Object = Object; + + urlrepo = "dataverse.ird.fr"; + // urlrepo = "data.inrae.fr"; + + constructor( + private appConfig: AppConfiguration, + private dataSetService: DatasetCrudService + ) { } + + ngOnInit() { + this.itemsdataset = []; + this.listdatasets(); + + + } + + listdatasets() { + var myHeaders = new Headers(); + myHeaders.append("Content-Type", "Application/json"); + var myInit = { method: 'GET', headers: myHeaders }; + + + //appeler smart havester pour récuperer l'api à lancer + + + var myRequest = new Request('https://' + this.urlrepo + '/api/search?q=*&per_page=5&type=dataset&start=50&show_facets=true&show_my_data=true', myInit); - ngOnInit(): void { + fetch(myRequest, myInit) + .then(response => { + response.json() + .then(data => { + this.itemsdatasets = data['data']['items']; + + for (var i = 0; i < this.itemsdatasets.length; i++) { + if (!this.dataSetService.findDataSetByTitle(this.itemsdatasets[i]['name'])) { + if (data['data']['items'][i]['global_id']) { + this.populatecatalogue(data['data']['items'][i]['global_id']); + } + } + } + }); + }); + return null; } + + populatecatalogue(id: string) { + var myHeaders = new Headers(); + myHeaders.append("Content-Type", "Application/json"); + var myInit = { method: 'GET', headers: myHeaders }; + + //appeler smart havester pour récuperer l'api à lancer + + var myRequest = new Request('https://' + this.urlrepo + '/api/datasets/export?exporter=dataverse_json&persistentId=' + id, myInit); + + fetch(myRequest, myInit) + .then(response => { + response.json() + .then(data => { + this.itemsdataset = data; + //this.createdataset(this.itemsdataset); + //this.createdistribution(this.itemsdataset); + }); + }); + + + + + } + + + + + createdataset(item: any) { + //console.log(item); + let data: string; + let description = ""; + let name = ""; + let url: string; + + for (var i = 0; i < item['datasetVersion']['metadataBlocks']['citation']['fields'].length; i++) { + if (item['datasetVersion']['metadataBlocks']['citation']['fields'][i]['typeName'] == "dsDescription") { + description = JSON.stringify(item['datasetVersion']['metadataBlocks']['citation']['fields'][i]['value']); + } + if (item['datasetVersion']['metadataBlocks']['citation']['fields'][i]['typeName'] == "title") { + name = JSON.stringify(item['datasetVersion']['metadataBlocks']['citation']['fields'][i]['value']); + } + } + + url = JSON.stringify(item['persistentUrl']); + + data = '\@prefix dcat: <http://www.w3.org/ns/dcat#>.\n\ + @prefix dct: <http://purl.org/dc/terms/>.\n\ + @prefix language: <http://id.loc.gov/vocabulary/iso639-1/>.\n\ + @prefix s: <'+ this.appConfig.fdpurl + '/>.\n\ + @prefix c: <'+ this.appConfig.fdpurl + '/catalog/>.\n\ + \n\ + s:new\n\ + a dcat:Dataset, dcat:Resource;\n\ + dct:description '+ description + ';\n\ + dct:hasVersion "1.0";\n\ + dct:isPartOf c:e5f49dbf-c976-4ca7-b4ee-7cc90923d9f3;\n\ + dct:language language:en;\n\ + dct:license <http://rdflicense.appspot.com/rdflicense/cc-by-nc-nd3.0>;\n\ + dct:title '+ name + ';\n\ + dcat:keyword '+ url + '.\n' + + + console.log('data: ' + data); + return this.dataSetService.createDataSet(data); + + } + + + + createdistribution(item: any) { + + // si file alors download url https://dataverse.ird.fr/api/access/datafile/['files']['dataFile'][i]['id']] + + console.log(item); + let data: string; + let description: string; + description = JSON.stringify(item['description']); + let name: string; + name = JSON.stringify(item['name']); + let url: string; + url = JSON.stringify(item['url']); + + data = '@prefix dcat: <http://www.w3.org/ns/dcat#>.\n\ + @prefix dct: <http://purl.org/dc/terms/>.\n\ + @prefix language: <http://id.loc.gov/vocabulary/iso639-1/>.\n\ + @prefix ffd: <https://f2ds.eosc-pillar.eu/>.\n\ + @prefix d: <https://f2ds.eosc-pillar.eu/dataset/>.\n\ + @prefix GVW: <https://dataverse.ird.fr/dataset.xhtml?persistentId=doi:10.23708/GVWCA0#>.\n\ + \n\ + ffd:new\n\ + a dcat:Distribution, dcat:Resource;\n\ + dct:description "Botinelli_VNM_2016.png ";\n\ + dct:hasVersion "v1.0";\n\ + dct:isPartOf d:e5f49dbf-c976-4ca7-b4ee-7cc90923d9f3;\n\ + dct:language language:fr;\n\ + dct:license <http://rdflicense.appspot.com/rdflicense/cc-by-nc-nd3.0>;\n\ + dct:title "Botinelli_VNM_2016.png ";\n\ + dcat:accessURL GVW:;\n\ + dcat:downloadURL\n\ + <https://dataverse.ird.fr/api/access/datafile/262?imageThumb=400>;\n\ + dcat:format "png";\n\ + dcat:mediaType "png".' + + + return this.dataSetService.createDistribution(data); + } + + + + + + } diff --git a/src/app/mapping/tree/tree.component.html b/src/app/mapping/tree/tree.component.html new file mode 100644 index 000000000..78b0caf8e --- /dev/null +++ b/src/app/mapping/tree/tree.component.html @@ -0,0 +1,15 @@ + + <div *ngFor="let item of items"> + <ul> + <li> + <label> + {{item}} + </label> + <input *ngIf="!isObject(itemsDataset[item])" type="text" value="{{itemsDataset[item]}}" disabled > + </li> + </ul> + <ul *ngIf="isObject(itemsDataset[item])"> + <app-tree [items]="Object.keys(itemsDataset[item])" [itemsDataset]="itemsDataset[item]"></app-tree> + </ul> + + </div> diff --git a/src/app/mapping/tree/tree.component.scss b/src/app/mapping/tree/tree.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/mapping/tree/tree.component.spec.ts b/src/app/mapping/tree/tree.component.spec.ts new file mode 100644 index 000000000..e3df2c328 --- /dev/null +++ b/src/app/mapping/tree/tree.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TreeComponent } from './tree.component'; + +describe('TreeComponent', () => { + let component: TreeComponent; + let fixture: ComponentFixture<TreeComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ TreeComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(TreeComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/mapping/tree/tree.component.ts b/src/app/mapping/tree/tree.component.ts new file mode 100644 index 000000000..e33d93f4f --- /dev/null +++ b/src/app/mapping/tree/tree.component.ts @@ -0,0 +1,25 @@ +import { Component, Input, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-tree', + templateUrl: './tree.component.html', + styleUrls: ['./tree.component.scss'] +}) +export class TreeComponent implements OnInit { + @Input() items; + @Input() itemsDataset; + Object = Object; + + constructor() { } + + ngOnInit(): void { + } + + isObject(object: Object): boolean{ + if(typeof object === 'object'){ + return true; + } else { + return false; + } + } +} diff --git a/src/app/repository/repository.component.ts b/src/app/repository/repository.component.ts index bb17611ec..5ef513406 100644 --- a/src/app/repository/repository.component.ts +++ b/src/app/repository/repository.component.ts @@ -110,7 +110,7 @@ repository:\n\ a dcat:Catalog, dcat:Resource;\n\ dct:description "'+ this.Form.value.repodescription + '";\n\ dct:hasVersion "'+ this.Form.value.repoversion + '";\n\ - dct:isPartOf <'+ this.appConfig.fdpurl + '>;\n\ + dct:isPartOf <http://146.59.2.80>;\n\ dcat:keyword "'+ this.Form.value.repotype + '";\n\ dct:title "'+ this.Form.value.reponame + '".\n' diff --git a/src/assets/dataset.json b/src/assets/dataset.json new file mode 100644 index 000000000..14e72c039 --- /dev/null +++ b/src/assets/dataset.json @@ -0,0 +1,148 @@ +{ + "description": { + "identier": "dct:descritpion", + "usageNote": "Mandatory property. This property contains a free-text account of the Dataset. This property can be repeated for parallel language versions of the description." + }, + "title": { + "identifier": "dct:title", + "usageNote": "Mandatory property. This property contains a name given to the Dataset. This property can be repeated for parallel language versions of the name." + }, + "contactPoint": { + "identifier": "dcat:contactPoint", + "usageNote": "Recommended property.This property contains contact information that can be used for sending comments about the Dataset." + }, + "distribution": { + "identifier": "dcat:distribution", + "usageNote": "Recommended property. This property links the Dataset to an available Distribution." + }, + "keyword": { + "identifier": "dcat:keyword", + "usageNote": "Recommended property. This property contains a keyword or tag describing the Dataset." + }, + "publisher": { + "identifier": "dct:publisher", + "usageNote": "Recommended property. This property refers to an entity (organisation) responsible for making the Dataset available." + }, + "spatial": { + "identifier": "dct:spatial", + "usageNote": "Recommended property. This property refers to a geographic region that is covered by the Dataset. " + }, + "theme": { + "identifier": "dcat:theme", + "usageNote": "Recommended property. This property refers to a category of the Dataset. A Dataset may be associated with multiple themes. Subproperty of dct:subject." + }, + "temporal": { + "identifier": "dct:temporal", + "usageNote": "Recommended property. This property refers to a temporal period that the Dataset covers." + }, + "conformsTo": { + "identifier": "dct:conformsTo", + "usageNote": "Optional property. This property refers to an implementing rule or other specification." + }, + "accrualPeriodicity": { + "identifier": "dct:accrualPeriodicity", + "usageNote": "Optional property. This property refers to the frequency at which Dataset is updated." + }, + "identifier": { + "identifier": "dct:identifier", + "usageNote": "Optional property. This property contains the main identifier for the Dataset, e.g. the URI or other unique identifier in the context of the Catalogue." + }, + "landingPage": { + "identifier": "dcat:landingPage", + "usageNote": "Optional property. This property refers to a web page that provides access to the Dataset, its Distributions and/or additional information." + }, + "language": { + "identifier": "dct:language", + "usageNote": "Optional property. This property refers to a language of the Dataset. This property can be repeated if there are multiple languages in the Dataset." + }, + "other identifier": { + "identifier": "adms:identifier", + "usageNote": "Optional property. This property contains the date of formal issuance (e.g., publication) of the Dataset." + }, + "issued": { + "identifier": "dct:issued", + "usageNote": "Optional property. This property contains the date of formal issuance (e.g., publication) of the Dataset." + }, + "modified": { + "identifier": "dct:modified", + "usageNote": "Optional property. This property contains the most recent date on which the Dataset was changed or modified." + }, + "provenance": { + "identifier": "dct:provenance", + "usageNote": "Optional property. This property contains a statement about the lineage of a Dataset." + }, + "sample": { + "identifier": "adms:sample", + "usageNote": "Optional property. This property refers to a sample distribution of the dataset." + }, + "source": { + "identifier": "dct:source", + "usageNote": "Optional property. This property refers to a related Dataset from which the described Dataset is derived." + }, + "type": { + "identifier": "dct:type", + "usageNote": "Optional property. This property refers to the type of the Dataset. A controlled vocabulary for the values has not been established." + }, + "relation": { + "identifier": "dct:relation", + "usageNote": "Optional property. This property refers to a related resource." + }, + "versionInfo": { + "identifier": "owl:versionInfo", + "usageNote": "Optional property. This property contains a version number or other version designation of the Dataset." + }, + "versionNotes": { + "identifier": "adms:versionNotes", + "usageNote": "Optional property. This property contains a description of the differences between this version and a previous version of the Dataset." + }, + "isVersionOf": { + "identifier": "dct:isVersionOf", + "usageNote": "Optional property. This property refers to a related Dataset of which the described Dataset is a version, edition, or adaptation." + }, + "hasVersion": { + "identifier": "dct:hasVersion", + "usageNote": "Optional property.This property refers to a related Dataset that is a version, edition, or adaptation of the described Dataset." + }, + "page": { + "identifier": "foaf:page", + "usageNote": "Optional property. This property refers to a page or document about this Dataset." + }, + "accessRights": { + "identifier": "dct:accessRights", + "usageNote": "Optional property. This property refers to information that indicates whether the Dataset is open data, has access restrictions or is not public. A controlled vocabulary with three members (:public, :restricted, :non-public) will be created and maintained by the Publications Office of the EU." + }, + "creator": { + "identifier": "dct:creator", + "usageNote": "Optional property. This property refers to an entity primarily responsible for making the resource." + }, + "qualifiedAttribution": { + "identifier": "prov:qualifiedAttribution", + "usageNote": "Optional property. This property refers to the link to an Agent having some form of responsibility for the resource. " + }, + "wasGeneratedBy": { + "identifier": "prov:wasGeneratedBy", + "usageNote": "Optional property. This property refers to an activity that generated, or provides the business context for, the creation of the dataset." + }, + "temporalResolution": { + "identifier": "dcat:temporalResolution", + "usageNote": "This property refers to the minimum time period resolvable in the dataset." + }, + "spatialResolutionInMeters": { + "identifier": "dcat:spatialResolutionInMeters", + "usageNote": "Optional property. This property refers to the minimum spatial separation resolvable in a dataset, measured in meters. " + }, + "qualifiedRelation": { + "identifier": "dcat:qualifiedRelation", + "usageNote": "Optional property. This property provides a link to a description of a relationship with another resource." + }, + "isReferencedBy": { + "identifier": "dct:isReferencedBy", + "usageNote": "Optional property. This property refers to a related resource, such as a publication, that references, cites, or otherwise points to the dataset." + } + + + + + + +} \ No newline at end of file -- GitLab From 400da95da016942ddd764dedc744388d9b38fa4c Mon Sep 17 00:00:00 2001 From: Baptiste Toulemonde <toulemonde@cines.fr> Date: Mon, 28 Jun 2021 15:34:30 +0200 Subject: [PATCH 05/18] parmeters from dcat --- package.json | 2 +- src/app/app-routing.module.ts | 1 - src/app/app.module.ts | 3 +- .../datasets/services/dataset-crud.service.ts | 8 +- src/app/mapping/class/dataset.ts | 6 + src/app/mapping/mapping.component.html | 9 +- src/app/mapping/mapping.component.scss | 11 ++ src/app/mapping/mapping.component.ts | 84 +++++-------- src/app/mapping/tree/tree.component.html | 36 ++++-- src/app/mapping/tree/tree.component.scss | 19 +++ src/app/mapping/tree/tree.component.ts | 11 +- src/assets/dataset.json | 117 +++++++++++------- 12 files changed, 186 insertions(+), 121 deletions(-) create mode 100644 src/app/mapping/class/dataset.ts diff --git a/package.json b/package.json index 68906ca9c..3a089dcb9 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "scripts": { "ng": "ng", "start": "ng serve", - "build": "ng build", + "build": "ng build ", "test": "ng test", "lint": "ng lint", "e2e": "ng e2e" diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 8ffa36222..7dba399fd 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -12,7 +12,6 @@ import { SearchComponent } from './search/search.component'; import { AuthenticationComponent } from './authentication/authentication.component'; import { SigninComponent } from './authentication/signin/signin.component'; import { SignupComponent } from './authentication/signup/signup.component'; -import { AppComponent } from './app.component'; import { DashboardComponent } from './dashboard/dashboard.component'; import { AuthGuardService } from './authentication/services/auth.guard'; import { StatsComponent } from './stats/stats.component'; diff --git a/src/app/app.module.ts b/src/app/app.module.ts index cfc2895ae..39fc439ff 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -42,6 +42,7 @@ import { DashboardComponent } from './dashboard/dashboard.component'; import { TreeComponent } from './mapping/tree/tree.component'; + @NgModule({ declarations: [ AppComponent, @@ -82,7 +83,7 @@ import { TreeComponent } from './mapping/tree/tree.component'; NbSpinnerModule, NbSelectModule, NbTabsetModule, - NbTooltipModule + NbTooltipModule, ], providers: [ diff --git a/src/app/datasets/services/dataset-crud.service.ts b/src/app/datasets/services/dataset-crud.service.ts index a1b0657ab..d981d8cb0 100644 --- a/src/app/datasets/services/dataset-crud.service.ts +++ b/src/app/datasets/services/dataset-crud.service.ts @@ -60,7 +60,11 @@ export class DatasetCrudService { } } - + getDatasetsFromApi(url: string, params: string): Observable<any[]> { + const httpOptions = { + headers: new HttpHeaders({'Content-Type': 'Application/json'})}; + return this.http.get<any[]>(`${url}/${params}`, httpOptions); + } findDataSetByTitle(title:string){ @@ -72,7 +76,7 @@ export class DatasetCrudService { this.results = []; data.results.bindings.forEach(element => { this.results.push(element);}); if (this.results[0]) { - console.log(this.results[0]['uri'].value.substring(36,72)); + let exist = true; } }}); diff --git a/src/app/mapping/class/dataset.ts b/src/app/mapping/class/dataset.ts new file mode 100644 index 000000000..ed57278a8 --- /dev/null +++ b/src/app/mapping/class/dataset.ts @@ -0,0 +1,6 @@ +export class Dataset { + public name: string; + public identifier: string; + public usageNote: string; +} + diff --git a/src/app/mapping/mapping.component.html b/src/app/mapping/mapping.component.html index 003393480..7e279ea49 100644 --- a/src/app/mapping/mapping.component.html +++ b/src/app/mapping/mapping.component.html @@ -3,16 +3,11 @@ <nb-card size="giant"> <nb-card-header>Dataset metadata</nb-card-header> <nb-card-body> - <app-tree [items]="Object.keys(itemsdataset)" [itemsDataset]="itemsdataset"></app-tree> + <app-tree [itemsDataset]="itemsdataset" [datasetModel]="datasetModel"></app-tree> </nb-card-body> </nb-card> </div> - <div class="card-col"> - <nb-card size="giant"> - <nb-card-header>Dcat dataset</nb-card-header> - <nb-card-body></nb-card-body> - </nb-card> - </div> + </div> <div class="card-row"> <div class="card-col"> diff --git a/src/app/mapping/mapping.component.scss b/src/app/mapping/mapping.component.scss index 2326b68a6..d7a337d69 100644 --- a/src/app/mapping/mapping.component.scss +++ b/src/app/mapping/mapping.component.scss @@ -4,8 +4,19 @@ flex: 1 0 calc(100%); margin: 0 -0.5rem; } + .row { + display: flex; + flex: 1 0 calc(100%); + margin: 0 -0.5rem; + } .card-col { + width: 100%; + flex: calc(50% ); + margin: 0 0.5rem; + } + + .col-6 { width: 50%; flex: calc(50% ); margin: 0 0.5rem; diff --git a/src/app/mapping/mapping.component.ts b/src/app/mapping/mapping.component.ts index 75a75adbf..2d65fc058 100644 --- a/src/app/mapping/mapping.component.ts +++ b/src/app/mapping/mapping.component.ts @@ -1,9 +1,10 @@ -import { HttpClient } from '@angular/common/http'; + import { Component, OnInit } from '@angular/core'; -import { FormControl, FormGroup } from '@angular/forms'; -import { FileSaverService } from 'ngx-filesaver'; +import { Observable } from 'rxjs'; import { AppConfiguration } from '../AppConfiguration'; import { DatasetCrudService } from '../datasets/services/dataset-crud.service'; +import { Dataset } from './class/Dataset'; + @Component({ @@ -15,76 +16,57 @@ export class MappingComponent implements OnInit { itemsdatasets: any; itemsdataset: Object; - fields : Map<number, string[]>; + datasetModel: Dataset[]; Object = Object; - urlrepo = "dataverse.ird.fr"; + urlrepo = "https://dataverse.ird.fr"; // urlrepo = "data.inrae.fr"; constructor( private appConfig: AppConfiguration, private dataSetService: DatasetCrudService - ) { } + ) { + + } ngOnInit() { this.itemsdataset = []; this.listdatasets(); + this.dataSetService.getLocally('./assets/dataset.json').subscribe( + dataset => this.datasetModel = dataset, + error => console.error(error) + ); + - } + listdatasets() { - var myHeaders = new Headers(); - myHeaders.append("Content-Type", "Application/json"); - var myInit = { method: 'GET', headers: myHeaders }; - - //appeler smart havester pour récuperer l'api à lancer - - - var myRequest = new Request('https://' + this.urlrepo + '/api/search?q=*&per_page=5&type=dataset&start=50&show_facets=true&show_my_data=true', myInit); - - fetch(myRequest, myInit) - .then(response => { - response.json() - .then(data => { - this.itemsdatasets = data['data']['items']; + let params = 'api/search?q=*&per_page=5&type=dataset&start=50&show_facets=true&show_my_data=true'; + this.dataSetService.getDatasetsFromApi(this.urlrepo, params).subscribe(data => { + this.itemsdatasets = data['data']['items']; - for (var i = 0; i < this.itemsdatasets.length; i++) { - if (!this.dataSetService.findDataSetByTitle(this.itemsdatasets[i]['name'])) { - if (data['data']['items'][i]['global_id']) { - this.populatecatalogue(data['data']['items'][i]['global_id']); - } - } - } - }); - }); - return null; + for (var i = 0; i < this.itemsdatasets.length; i++) { + if (!this.dataSetService.findDataSetByTitle(this.itemsdatasets[i]['name'])) { + if (data['data']['items'][i]['global_id']) { + this.populatecatalogue(data['data']['items'][i]['global_id']); + } + } + } + }); } populatecatalogue(id: string) { - var myHeaders = new Headers(); - myHeaders.append("Content-Type", "Application/json"); - var myInit = { method: 'GET', headers: myHeaders }; - + let params = `api/datasets/export?exporter=dataverse_json&persistentId=${id}`; + //appeler smart havester pour récuperer l'api à lancer - - var myRequest = new Request('https://' + this.urlrepo + '/api/datasets/export?exporter=dataverse_json&persistentId=' + id, myInit); - - fetch(myRequest, myInit) - .then(response => { - response.json() - .then(data => { - this.itemsdataset = data; - //this.createdataset(this.itemsdataset); - //this.createdistribution(this.itemsdataset); - }); - }); - - - - + this.dataSetService.getDatasetsFromApi(this.urlrepo, params).subscribe(data => { + this.itemsdataset = data; + //this.createdataset(this.itemsdataset); + //this.createdistribution(this.itemsdataset); + }); } diff --git a/src/app/mapping/tree/tree.component.html b/src/app/mapping/tree/tree.component.html index 78b0caf8e..bd2c7ad11 100644 --- a/src/app/mapping/tree/tree.component.html +++ b/src/app/mapping/tree/tree.component.html @@ -1,15 +1,27 @@ - <div *ngFor="let item of items"> - <ul> - <li> - <label> - {{item}} - </label> - <input *ngIf="!isObject(itemsDataset[item])" type="text" value="{{itemsDataset[item]}}" disabled > - </li> - </ul> - <ul *ngIf="isObject(itemsDataset[item])"> - <app-tree [items]="Object.keys(itemsDataset[item])" [itemsDataset]="itemsDataset[item]"></app-tree> - </ul> +<div *ngFor="let item of Object.keys(itemsDataset); let i "> + <div class="row"> + + <dl> + <dt> + <h5> + {{item}} + </h5> + <input *ngIf="!isObject(itemsDataset[item])" type="text" value="{{itemsDataset[item]}}" disabled> + <nb-select [size]="size" *ngIf="!isObject(itemsDataset[item])" > + <nb-option value="">no value</nb-option> + <nb-option *ngFor="let data of datasetModel " value="{{ data.identifier}}">{{ data.name}} ({{ data.identifier}})</nb-option> + + </nb-select> + </dt> + + </dl> </div> + + + <dl *ngIf="isObject(itemsDataset[item])"> + <app-tree [itemsDataset]="itemsDataset[item]" ></app-tree> + </dl> + +</div> \ No newline at end of file diff --git a/src/app/mapping/tree/tree.component.scss b/src/app/mapping/tree/tree.component.scss index e69de29bb..72f397eed 100644 --- a/src/app/mapping/tree/tree.component.scss +++ b/src/app/mapping/tree/tree.component.scss @@ -0,0 +1,19 @@ +dl, dt, dd { + margin-left: 10px; +} + +.row { + display: block; +} + +input { + float: left; + width: 60%; + padding: 10px; +} + +select { + float: left; + width: 40%; + padding: 10px; +} \ No newline at end of file diff --git a/src/app/mapping/tree/tree.component.ts b/src/app/mapping/tree/tree.component.ts index e33d93f4f..6278c0144 100644 --- a/src/app/mapping/tree/tree.component.ts +++ b/src/app/mapping/tree/tree.component.ts @@ -1,4 +1,7 @@ import { Component, Input, OnInit } from '@angular/core'; +import { NbComponentSize } from '@nebular/theme'; +import { Observable } from 'rxjs'; +import { Dataset } from '../class/Dataset'; @Component({ selector: 'app-tree', @@ -6,11 +9,15 @@ import { Component, Input, OnInit } from '@angular/core'; styleUrls: ['./tree.component.scss'] }) export class TreeComponent implements OnInit { - @Input() items; + @Input() itemsDataset; + @Input() datasetModel: Dataset[]; Object = Object; + size: NbComponentSize = 'medium'; - constructor() { } + constructor() { + + } ngOnInit(): void { } diff --git a/src/assets/dataset.json b/src/assets/dataset.json index 14e72c039..9e96bc255 100644 --- a/src/assets/dataset.json +++ b/src/assets/dataset.json @@ -1,148 +1,177 @@ -{ - "description": { - "identier": "dct:descritpion", +[ + { + "name": "descritpion", + "identifier": "dct:descritpion", "usageNote": "Mandatory property. This property contains a free-text account of the Dataset. This property can be repeated for parallel language versions of the description." }, - "title": { + { + "name": "title", "identifier": "dct:title", "usageNote": "Mandatory property. This property contains a name given to the Dataset. This property can be repeated for parallel language versions of the name." }, - "contactPoint": { + { + "name": "contact point", "identifier": "dcat:contactPoint", "usageNote": "Recommended property.This property contains contact information that can be used for sending comments about the Dataset." }, - "distribution": { + { + "name": "dataset distribution", "identifier": "dcat:distribution", "usageNote": "Recommended property. This property links the Dataset to an available Distribution." }, - "keyword": { + { + "name": "keyword/ tag", "identifier": "dcat:keyword", "usageNote": "Recommended property. This property contains a keyword or tag describing the Dataset." }, - "publisher": { + { + "name": "publisher", "identifier": "dct:publisher", "usageNote": "Recommended property. This property refers to an entity (organisation) responsible for making the Dataset available." }, - "spatial": { + { + "name": "spatial/geographical coverage", "identifier": "dct:spatial", "usageNote": "Recommended property. This property refers to a geographic region that is covered by the Dataset. " }, - "theme": { + { + "name": "theme/category", "identifier": "dcat:theme", "usageNote": "Recommended property. This property refers to a category of the Dataset. A Dataset may be associated with multiple themes. Subproperty of dct:subject." }, - "temporal": { + { + "name": "temporal coverage", "identifier": "dct:temporal", "usageNote": "Recommended property. This property refers to a temporal period that the Dataset covers." }, - "conformsTo": { + { + "name": "conforms to", "identifier": "dct:conformsTo", "usageNote": "Optional property. This property refers to an implementing rule or other specification." }, - "accrualPeriodicity": { + { + "name": "frequency", "identifier": "dct:accrualPeriodicity", "usageNote": "Optional property. This property refers to the frequency at which Dataset is updated." }, - "identifier": { + { + "name": "identifier", "identifier": "dct:identifier", "usageNote": "Optional property. This property contains the main identifier for the Dataset, e.g. the URI or other unique identifier in the context of the Catalogue." }, - "landingPage": { + { + "name": "landing page", "identifier": "dcat:landingPage", "usageNote": "Optional property. This property refers to a web page that provides access to the Dataset, its Distributions and/or additional information." }, - "language": { + { + "name": "language", "identifier": "dct:language", "usageNote": "Optional property. This property refers to a language of the Dataset. This property can be repeated if there are multiple languages in the Dataset." }, - "other identifier": { + { + "name": "other identifier", "identifier": "adms:identifier", "usageNote": "Optional property. This property contains the date of formal issuance (e.g., publication) of the Dataset." }, - "issued": { + { + "name": "release date datele", "identifier": "dct:issued", "usageNote": "Optional property. This property contains the date of formal issuance (e.g., publication) of the Dataset." }, - "modified": { + { + "name": "update/modification date", "identifier": "dct:modified", "usageNote": "Optional property. This property contains the most recent date on which the Dataset was changed or modified." }, - "provenance": { + { + "name": "provenance", "identifier": "dct:provenance", "usageNote": "Optional property. This property contains a statement about the lineage of a Dataset." }, - "sample": { + { + "name": "sample", "identifier": "adms:sample", "usageNote": "Optional property. This property refers to a sample distribution of the dataset." }, - "source": { + { + "name": "source", "identifier": "dct:source", "usageNote": "Optional property. This property refers to a related Dataset from which the described Dataset is derived." }, - "type": { + { + "name": "type", "identifier": "dct:type", "usageNote": "Optional property. This property refers to the type of the Dataset. A controlled vocabulary for the values has not been established." }, - "relation": { + { + "name": "related resource", "identifier": "dct:relation", "usageNote": "Optional property. This property refers to a related resource." }, - "versionInfo": { + { + "name": "version", "identifier": "owl:versionInfo", "usageNote": "Optional property. This property contains a version number or other version designation of the Dataset." }, - "versionNotes": { + { + "name": "version notes", "identifier": "adms:versionNotes", "usageNote": "Optional property. This property contains a description of the differences between this version and a previous version of the Dataset." }, - "isVersionOf": { + { + "name": "is Version Of", "identifier": "dct:isVersionOf", "usageNote": "Optional property. This property refers to a related Dataset of which the described Dataset is a version, edition, or adaptation." }, - "hasVersion": { + { + "name": "has Version", "identifier": "dct:hasVersion", "usageNote": "Optional property.This property refers to a related Dataset that is a version, edition, or adaptation of the described Dataset." }, - "page": { + { + "name": "documentation", "identifier": "foaf:page", "usageNote": "Optional property. This property refers to a page or document about this Dataset." }, - "accessRights": { + { + "name": "access rights", "identifier": "dct:accessRights", "usageNote": "Optional property. This property refers to information that indicates whether the Dataset is open data, has access restrictions or is not public. A controlled vocabulary with three members (:public, :restricted, :non-public) will be created and maintained by the Publications Office of the EU." }, - "creator": { + { + "name": "creator", "identifier": "dct:creator", "usageNote": "Optional property. This property refers to an entity primarily responsible for making the resource." }, - "qualifiedAttribution": { + { + "name": "qualified attribution", "identifier": "prov:qualifiedAttribution", "usageNote": "Optional property. This property refers to the link to an Agent having some form of responsibility for the resource. " }, - "wasGeneratedBy": { + { + "name": "was generated by", "identifier": "prov:wasGeneratedBy", "usageNote": "Optional property. This property refers to an activity that generated, or provides the business context for, the creation of the dataset." }, - "temporalResolution": { + { + "name": "temporal resolution", "identifier": "dcat:temporalResolution", "usageNote": "This property refers to the minimum time period resolvable in the dataset." }, - "spatialResolutionInMeters": { + { + "name": "spatial resolution", "identifier": "dcat:spatialResolutionInMeters", "usageNote": "Optional property. This property refers to the minimum spatial separation resolvable in a dataset, measured in meters. " }, - "qualifiedRelation": { + { + "name": "qualified Relation", "identifier": "dcat:qualifiedRelation", "usageNote": "Optional property. This property provides a link to a description of a relationship with another resource." }, - "isReferencedBy": { + { + "name": "is reference by", "identifier": "dct:isReferencedBy", "usageNote": "Optional property. This property refers to a related resource, such as a publication, that references, cites, or otherwise points to the dataset." } - - - - - - -} \ No newline at end of file +] \ No newline at end of file -- GitLab From e58246ee0d36143d2da58307412720ae1b57de3f Mon Sep 17 00:00:00 2001 From: Baptiste Toulemonde <toulemonde@cines.fr> Date: Thu, 1 Jul 2021 09:13:53 +0200 Subject: [PATCH 06/18] (mapping) user interface --- src/app/app.module.ts | 3 +- src/app/datasets/datasets.component.ts | 8 +- .../elasticsearch/elasticsearch.component.ts | 50 -------- src/app/mapping/class/group.ts | 9 ++ src/app/mapping/mapping.component.html | 39 ++++++- src/app/mapping/mapping.component.scss | 24 +++- src/app/mapping/mapping.component.ts | 108 +++++++++++++++--- src/app/mapping/tree/tree.component.html | 8 +- 8 files changed, 170 insertions(+), 79 deletions(-) delete mode 100644 src/app/elasticsearch/elasticsearch.component.ts create mode 100644 src/app/mapping/class/group.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 367b0cca7..049072989 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -35,7 +35,7 @@ import { MappingComponent } from './mapping/mapping.component'; import { NebularModule } from './nebular.module'; import { AppRoutingModule } from './app-routing.module'; -import { NbLayoutModule, NbThemeModule, NbTooltipModule, NbSpinnerModule, NbSelectModule, NbTabsetModule } from '@nebular/theme'; +import { NbLayoutModule, NbThemeModule, NbTooltipModule, NbSpinnerModule, NbSelectModule, NbTabsetModule, NbAutocompleteModule } from '@nebular/theme'; import { DashboardComponent } from './dashboard/dashboard.component'; import { TreeComponent } from './mapping/tree/tree.component'; @@ -83,6 +83,7 @@ import { TreeComponent } from './mapping/tree/tree.component'; NbSelectModule, NbTabsetModule, NbTooltipModule, + NbAutocompleteModule ], providers: [ diff --git a/src/app/datasets/datasets.component.ts b/src/app/datasets/datasets.component.ts index 7b2675b5b..3ec9688ea 100644 --- a/src/app/datasets/datasets.component.ts +++ b/src/app/datasets/datasets.component.ts @@ -81,8 +81,8 @@ export class DatasetsComponent implements OnInit { console.log( this.itemsdataset); - this.createdataset(data); - //this.createdistribution(this.itemsdataset); + //this.createdataset(data); + //this.createdistribution(this.itemsdataset); }); }); @@ -121,7 +121,7 @@ export class DatasetsComponent implements OnInit { a dcat:Dataset, dcat:Resource;\n\ dct:description ' + description + ';\n\ dct:hasVersion "1.0";\n\ - dct:isPartOf <http://fdp-api.f2ds.svc.cluster.local/catalog/e5f49dbf-c976-4ca7-b4ee-7cc90923d9f3>;\n\ + dct:isPartOf <https://f2ds.eosc-pillar.eu/catalog/afe472f9-2e70-409c-ad26-f174799e7834>;\n\ dct:language language:en;\n\ dct:license <http://rdflicense.appspot.com/rdflicense/cc-by-nc-nd3.0>;\n\ dct:title '+ name + ';\n\ @@ -129,7 +129,7 @@ export class DatasetsComponent implements OnInit { console.log(data); - //return this.dataSetService.createDataSet(data); + // return this.dataSetService.createDataSet(data); } diff --git a/src/app/elasticsearch/elasticsearch.component.ts b/src/app/elasticsearch/elasticsearch.component.ts deleted file mode 100644 index b2f9e2abd..000000000 --- a/src/app/elasticsearch/elasticsearch.component.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { AppConfiguration } from '../AppConfiguration'; -import { HttpClient } from '@angular/common/http'; -import { FileSaverService } from 'ngx-filesaver'; -import { FormControl} from '@angular/forms'; -import { FormGroup} from '@angular/forms'; -import { Observable } from 'rxjs'; -import { environment } from 'src/environments/environment.prod'; - -@Component({ - selector: 'app-elasticsearch', - templateUrl: './elasticsearch.component.html', - styleUrls: ['./elasticsearch.component.scss'] -}) -export class ElasticsearchComponent implements OnInit { - - - Form = new FormGroup({ - elasticurl: new FormControl(), -}); - - constructor( - private appConfig: AppConfiguration, - private http: HttpClient, - private _FileSaverService: FileSaverService - ) {} - - ngOnInit() { - this.Form.setValue({ - elasticurl: this.appConfig.elasticurl , - }); - } - - - SaveElasticsearchSetting() { - let data: string; - data ='\ - {\n\ - "fdpurl": "'+ this.appConfig.fdpurl +'", \n\ - "fdpemail": "'+ this.appConfig.fdpemail +'", \n\ - "fdppassword": "'+ this.appConfig.fdppassword +'", \n\ - "elasticurl": "'+ this.Form.value.elasticurl +'", \n\ - "smartapiurl": "'+ this.appConfig.smartapiurl +'" \n\ - }' - console.log(data); - return this.http.post("https://"+environment.apiurl+"/api/setting", data,{responseType: 'text'}).subscribe( (r)=>{console.log(r)}) ; - }; - - -} diff --git a/src/app/mapping/class/group.ts b/src/app/mapping/class/group.ts new file mode 100644 index 000000000..c280f781a --- /dev/null +++ b/src/app/mapping/class/group.ts @@ -0,0 +1,9 @@ +export class Group { + public name: string; + public children: string[]; + + constructor(name: string, children: string[]) { + this.name = name; + this.children = children; + } +} \ No newline at end of file diff --git a/src/app/mapping/mapping.component.html b/src/app/mapping/mapping.component.html index 7e279ea49..04a8e2fe2 100644 --- a/src/app/mapping/mapping.component.html +++ b/src/app/mapping/mapping.component.html @@ -3,11 +3,46 @@ <nb-card size="giant"> <nb-card-header>Dataset metadata</nb-card-header> <nb-card-body> - <app-tree [itemsDataset]="itemsdataset" [datasetModel]="datasetModel"></app-tree> + <div class="row"> + <div class="col-4"> + <div *ngFor="let dataset of datasetModel"> + <nb-form-field> + <input nbInput fullWidth type="text" name="{{dataset.identifier}}" + value="{{dataset.identifier}}" disabled /> + <button nbSuffix nbTooltip="{{dataset.usageNote}}" nbTooltipStatus="info" nbButton + status="basic" ghost> + <nb-icon [icon]=" 'question-mark-circle-outline' " pack="eva"> + </nb-icon> + </button> + </nb-form-field> + </div> + </div> + <div class="col-8"> + <div *ngFor="let dataset of datasetModel"> + <nb-form-field> + <input [formControl]="inputFormControl" + nbInput fullWidth + type="text" + placeholder="Enter value" + [nbAutocomplete]="auto" /> + + <nb-autocomplete #auto> + + <nb-option-group *ngFor="let group of filteredGroups | async; trackBy: trackByFn" [title]="group.name" > + <nb-option *ngFor="let option of group.children" [value]="option"> + {{ option }} + </nb-option> + </nb-option-group> + + </nb-autocomplete> + </nb-form-field> + </div> + </div> + </div> </nb-card-body> </nb-card> </div> - + </div> <div class="card-row"> <div class="card-col"> diff --git a/src/app/mapping/mapping.component.scss b/src/app/mapping/mapping.component.scss index d7a337d69..3867e933a 100644 --- a/src/app/mapping/mapping.component.scss +++ b/src/app/mapping/mapping.component.scss @@ -16,8 +16,24 @@ margin: 0 0.5rem; } - .col-6 { - width: 50%; - flex: calc(50% ); - margin: 0 0.5rem; + .col-4 { + width: 30%; + + margin-right: 10px; + align-items: stretch; + } + + .col-8 { + width: 70%; + + margin: 10 0.5rem; + align-items: stretch; + } + input { + margin: 10px 10px; + + } + + input-basic-disabled-text-color { + color: black; } \ No newline at end of file diff --git a/src/app/mapping/mapping.component.ts b/src/app/mapping/mapping.component.ts index 2d65fc058..88f6fe454 100644 --- a/src/app/mapping/mapping.component.ts +++ b/src/app/mapping/mapping.component.ts @@ -1,16 +1,20 @@ -import { Component, OnInit } from '@angular/core'; -import { Observable } from 'rxjs'; +import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; +import { FormControl } from '@angular/forms'; +import { Observable, of } from 'rxjs'; +import { map, startWith } from 'rxjs/operators'; import { AppConfiguration } from '../AppConfiguration'; import { DatasetCrudService } from '../datasets/services/dataset-crud.service'; import { Dataset } from './class/Dataset'; +import { Group } from './class/group'; @Component({ selector: 'app-mapping', templateUrl: './mapping.component.html', - styleUrls: ['./mapping.component.scss'] + styleUrls: ['./mapping.component.scss'], + }) export class MappingComponent implements OnInit { @@ -18,6 +22,13 @@ export class MappingComponent implements OnInit { itemsdataset: Object; datasetModel: Dataset[]; Object = Object; + groups: Group[] = []; + filteredGroups: Observable<Group[]>; + inputFormControl: FormControl; + keychild: string = ''; + + + urlrepo = "https://dataverse.ird.fr"; // urlrepo = "data.inrae.fr"; @@ -26,27 +37,44 @@ export class MappingComponent implements OnInit { private appConfig: AppConfiguration, private dataSetService: DatasetCrudService ) { - - } + + } ngOnInit() { this.itemsdataset = []; this.listdatasets(); this.dataSetService.getLocally('./assets/dataset.json').subscribe( - dataset => this.datasetModel = dataset, + dataset => { + this.datasetModel = dataset; + console.log(this.datasetModel); + + }, error => console.error(error) ); - - + + + this.filteredGroups = of(this.groups); + this.inputFormControl = new FormControl(); + + this.filteredGroups = this.inputFormControl.valueChanges + .pipe( + startWith(''), + map(filterString => this.filter(filterString)), + ); + + + + + } - + listdatasets() { //appeler smart havester pour récuperer l'api à lancer - let params = 'api/search?q=*&per_page=5&type=dataset&start=50&show_facets=true&show_my_data=true'; + let params = 'api/search?q=*&per_page=1&type=dataset&start=50&show_facets=true&show_my_data=true'; this.dataSetService.getDatasetsFromApi(this.urlrepo, params).subscribe(data => { this.itemsdatasets = data['data']['items']; - + for (var i = 0; i < this.itemsdatasets.length; i++) { if (!this.dataSetService.findDataSetByTitle(this.itemsdatasets[i]['name'])) { if (data['data']['items'][i]['global_id']) { @@ -60,13 +88,16 @@ export class MappingComponent implements OnInit { populatecatalogue(id: string) { let params = `api/datasets/export?exporter=dataverse_json&persistentId=${id}`; - + //appeler smart havester pour récuperer l'api à lancer this.dataSetService.getDatasetsFromApi(this.urlrepo, params).subscribe(data => { this.itemsdataset = data; + this.getFields(this.itemsdataset) + //this.createdataset(this.itemsdataset); //this.createdistribution(this.itemsdataset); }); + } @@ -152,9 +183,56 @@ export class MappingComponent implements OnInit { return this.dataSetService.createDistribution(data); } - - - + + getFields(obj: Object): Group[] { + + let tab = [] + + for (let key in obj) { + + if (typeof obj[key] !== 'object') { + tab.push(key) + } else if (typeof obj[key] === 'object') { + this.groups.push(new Group(this.keychild, tab)); + if (this.keychild === ''){ + this.keychild = key; + } else { + this.keychild += ':' + key; + } + + this.getFields(obj[key]); + } + } + + return this.groups; + } + + private filterChildren(children: string[], filterValue: string) { + return children.filter(optionValue => optionValue.toLowerCase().includes(filterValue)); + } + + private filter(value: string): Group[] { + const filterValue = value.toLowerCase(); + return this.groups + .map(group => { + return { + name: group.name, + children: this.filterChildren(group.children, filterValue), + } + }) + .filter(group => group.children.length); + } + + trackByFn(index, item) { + return item.name; + } } + + + + + + + diff --git a/src/app/mapping/tree/tree.component.html b/src/app/mapping/tree/tree.component.html index bd2c7ad11..61393b92e 100644 --- a/src/app/mapping/tree/tree.component.html +++ b/src/app/mapping/tree/tree.component.html @@ -1,5 +1,5 @@ -<div *ngFor="let item of Object.keys(itemsDataset); let i "> +<div *ngFor="let item of Object.keys(itemsDataset) "> <div class="row"> @@ -8,13 +8,15 @@ <h5> {{item}} </h5> - <input *ngIf="!isObject(itemsDataset[item])" type="text" value="{{itemsDataset[item]}}" disabled> + <input nbInput nbTooltip="This is a tooltip" nbTooltipStatus="primary" *ngIf="!isObject(itemsDataset[item])" type="text" value="{{itemsDataset[item]}}" disabled> + </dt> + <dd> <nb-select [size]="size" *ngIf="!isObject(itemsDataset[item])" > <nb-option value="">no value</nb-option> <nb-option *ngFor="let data of datasetModel " value="{{ data.identifier}}">{{ data.name}} ({{ data.identifier}})</nb-option> </nb-select> - </dt> + </dd> </dl> </div> -- GitLab From 343b132b77248a0560db44d4b48266fc5b4b8ec1 Mon Sep 17 00:00:00 2001 From: Baptiste Toulemonde <toulemonde@cines.fr> Date: Thu, 1 Jul 2021 09:40:24 +0200 Subject: [PATCH 07/18] fix(mapping) --- src/app/app.module.ts | 4 +-- src/app/mapping/tree/tree.component.html | 29 ------------------- src/app/mapping/tree/tree.component.scss | 19 ------------ src/app/mapping/tree/tree.component.spec.ts | 25 ---------------- src/app/mapping/tree/tree.component.ts | 32 --------------------- 5 files changed, 2 insertions(+), 107 deletions(-) delete mode 100644 src/app/mapping/tree/tree.component.html delete mode 100644 src/app/mapping/tree/tree.component.scss delete mode 100644 src/app/mapping/tree/tree.component.spec.ts delete mode 100644 src/app/mapping/tree/tree.component.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 049072989..135de077a 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -38,7 +38,7 @@ import { AppRoutingModule } from './app-routing.module'; import { NbLayoutModule, NbThemeModule, NbTooltipModule, NbSpinnerModule, NbSelectModule, NbTabsetModule, NbAutocompleteModule } from '@nebular/theme'; import { DashboardComponent } from './dashboard/dashboard.component'; -import { TreeComponent } from './mapping/tree/tree.component'; + @@ -57,7 +57,7 @@ import { TreeComponent } from './mapping/tree/tree.component'; StatsComponent, DashboardComponent, MappingComponent, - TreeComponent, + ], imports: [ BrowserModule, diff --git a/src/app/mapping/tree/tree.component.html b/src/app/mapping/tree/tree.component.html deleted file mode 100644 index 61393b92e..000000000 --- a/src/app/mapping/tree/tree.component.html +++ /dev/null @@ -1,29 +0,0 @@ - -<div *ngFor="let item of Object.keys(itemsDataset) "> - - <div class="row"> - - <dl> - <dt> - <h5> - {{item}} - </h5> - <input nbInput nbTooltip="This is a tooltip" nbTooltipStatus="primary" *ngIf="!isObject(itemsDataset[item])" type="text" value="{{itemsDataset[item]}}" disabled> - </dt> - <dd> - <nb-select [size]="size" *ngIf="!isObject(itemsDataset[item])" > - <nb-option value="">no value</nb-option> - <nb-option *ngFor="let data of datasetModel " value="{{ data.identifier}}">{{ data.name}} ({{ data.identifier}})</nb-option> - - </nb-select> - </dd> - - </dl> - </div> - - - <dl *ngIf="isObject(itemsDataset[item])"> - <app-tree [itemsDataset]="itemsDataset[item]" ></app-tree> - </dl> - -</div> \ No newline at end of file diff --git a/src/app/mapping/tree/tree.component.scss b/src/app/mapping/tree/tree.component.scss deleted file mode 100644 index 72f397eed..000000000 --- a/src/app/mapping/tree/tree.component.scss +++ /dev/null @@ -1,19 +0,0 @@ -dl, dt, dd { - margin-left: 10px; -} - -.row { - display: block; -} - -input { - float: left; - width: 60%; - padding: 10px; -} - -select { - float: left; - width: 40%; - padding: 10px; -} \ No newline at end of file diff --git a/src/app/mapping/tree/tree.component.spec.ts b/src/app/mapping/tree/tree.component.spec.ts deleted file mode 100644 index e3df2c328..000000000 --- a/src/app/mapping/tree/tree.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { TreeComponent } from './tree.component'; - -describe('TreeComponent', () => { - let component: TreeComponent; - let fixture: ComponentFixture<TreeComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ TreeComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(TreeComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/mapping/tree/tree.component.ts b/src/app/mapping/tree/tree.component.ts deleted file mode 100644 index 6278c0144..000000000 --- a/src/app/mapping/tree/tree.component.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { NbComponentSize } from '@nebular/theme'; -import { Observable } from 'rxjs'; -import { Dataset } from '../class/Dataset'; - -@Component({ - selector: 'app-tree', - templateUrl: './tree.component.html', - styleUrls: ['./tree.component.scss'] -}) -export class TreeComponent implements OnInit { - - @Input() itemsDataset; - @Input() datasetModel: Dataset[]; - Object = Object; - size: NbComponentSize = 'medium'; - - constructor() { - - } - - ngOnInit(): void { - } - - isObject(object: Object): boolean{ - if(typeof object === 'object'){ - return true; - } else { - return false; - } - } -} -- GitLab From 6ee79ef9e523f45bcd8c5cbe606a8b96dc8471d0 Mon Sep 17 00:00:00 2001 From: Baptiste Toulemonde <toulemonde@cines.fr> Date: Tue, 6 Jul 2021 15:14:56 +0200 Subject: [PATCH 08/18] mapping: fixes --- src/app/datasets/services/dataset-crud.service.ts | 1 - src/assets/dataset.json | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/app/datasets/services/dataset-crud.service.ts b/src/app/datasets/services/dataset-crud.service.ts index d981d8cb0..a6d1bfc9a 100644 --- a/src/app/datasets/services/dataset-crud.service.ts +++ b/src/app/datasets/services/dataset-crud.service.ts @@ -84,7 +84,6 @@ export class DatasetCrudService { } getLocally<T = any>(path: string): Observable<T> { - console.log('On getLocally using filepath : ', `${path}`); return this.http.get<T>(`${path}`); } diff --git a/src/assets/dataset.json b/src/assets/dataset.json index 9e96bc255..abaaa625f 100644 --- a/src/assets/dataset.json +++ b/src/assets/dataset.json @@ -1,7 +1,7 @@ [ { - "name": "descritpion", - "identifier": "dct:descritpion", + "name": "description", + "identifier": "dct:description", "usageNote": "Mandatory property. This property contains a free-text account of the Dataset. This property can be repeated for parallel language versions of the description." }, { -- GitLab From 5b0fb761404556a73912dfb6b2545ea9bd060e20 Mon Sep 17 00:00:00 2001 From: Baptiste Toulemonde <toulemonde@cines.fr> Date: Wed, 7 Jul 2021 14:26:46 +0200 Subject: [PATCH 09/18] mapping: add features & upgrade features --- src/app/datasets/datasets.component.ts | 2 +- src/app/mapping/mapping.component.html | 2 +- src/app/mapping/mapping.component.ts | 122 ++++++++++++------------- 3 files changed, 63 insertions(+), 63 deletions(-) diff --git a/src/app/datasets/datasets.component.ts b/src/app/datasets/datasets.component.ts index 57ac8d999..3a1e1fb54 100644 --- a/src/app/datasets/datasets.component.ts +++ b/src/app/datasets/datasets.component.ts @@ -82,7 +82,7 @@ export class DatasetsComponent implements OnInit { console.log( this.itemsdataset); this.createdataset(data); - //this.createdistribution(this.itemsdataset); + this.createdistribution(this.itemsdataset); }); }); diff --git a/src/app/mapping/mapping.component.html b/src/app/mapping/mapping.component.html index 700424e65..72395c52c 100644 --- a/src/app/mapping/mapping.component.html +++ b/src/app/mapping/mapping.component.html @@ -24,7 +24,7 @@ <nb-form-field> <input #autoInput #{{dataset.identifier}} fullWidth id="{{dataset.identifier}}" nbInput (input)="onChange()" - placeholder="Enter value" [nbAutocomplete]="auto" [(ngModel)]="identifiers[index]" (focus)="reset()"/> + placeholder="Enter value" [nbAutocomplete]="auto" [(ngModel)]="selectedPaths[index]" (focus)="reset()"/> <nb-autocomplete #auto> diff --git a/src/app/mapping/mapping.component.ts b/src/app/mapping/mapping.component.ts index 5b575662c..853dce8fd 100644 --- a/src/app/mapping/mapping.component.ts +++ b/src/app/mapping/mapping.component.ts @@ -1,17 +1,11 @@ -import { ValueConverter } from '@angular/compiler/src/render3/view/template'; import { Component, OnInit, ViewChild } from '@angular/core'; -import { FormGroup } from '@angular/forms'; - import { Observable, of } from 'rxjs'; import { map } from 'rxjs/operators'; import { AppConfiguration } from '../AppConfiguration'; import { DatasetCrudService } from '../datasets/services/dataset-crud.service'; import { Dataset } from './class/Dataset'; - - - @Component({ selector: 'app-mapping', templateUrl: './mapping.component.html', @@ -21,46 +15,35 @@ import { Dataset } from './class/Dataset'; export class MappingComponent implements OnInit { itemsdatasets: any; - itemsdataset: Object; + itemsdataset: Object[] = [] datasetModel: Dataset[]; filteredOptions: Observable<string[]>; - jsonTreeMap: Map<string, string> = new Map(); - form: FormGroup - identifiers: string[]; - options: string[] = []; + keys: string[] = []; + KeysMap: Map<number, string[]> = new Map(); + selectedPaths: string[]; @ViewChild('autoInput') input; - - urlrepo = "https://data.inrae.fr"; // urlrepo = "dataverse.ird.fr"; - constructor( - private appConfig: AppConfiguration, - private dataSetService: DatasetCrudService - ) { - - } + constructor(private appConfig: AppConfiguration, private dataSetService: DatasetCrudService) { } ngOnInit() { - this.itemsdataset = []; this.listdatasets(); this.dataSetService.getLocally('./assets/dataset.json').subscribe( dataset => { this.datasetModel = dataset; - this.identifiers = new Array(dataset.length); + this.selectedPaths = new Array(dataset.length); }, error => console.error(error) ); } - - listdatasets() { //appeler smart havester pour récuperer l'api à lancer - let params = 'api/search?q=*&per_page=1&type=dataset&start=50&show_facets=true&show_my_data=true'; + let params = 'api/search?q=*&per_page=5&type=dataset&start=50&show_facets=true&show_my_data=true'; this.dataSetService.getDatasetsFromApi(this.urlrepo, params).subscribe(data => { this.itemsdatasets = data['data']['items']; for (var i = 0; i < this.itemsdatasets.length; i++) { @@ -73,30 +56,29 @@ export class MappingComponent implements OnInit { }); } - populatecatalogue(id: string) { let params = `api/datasets/export?exporter=dataverse_json&persistentId=${id}`; //appeler smart havester pour récuperer l'api à lancer - this.dataSetService.getDatasetsFromApi(this.urlrepo, params).subscribe(data => { - this.itemsdataset = data; - this.getJsonTree(this.itemsdataset, ''); - this.jsonTreeMap.forEach( (value, key) => this.options.push(key)); - this.filteredOptions = of(this.options); + this.dataSetService.getDatasetsFromApi(this.urlrepo, params).subscribe((data: Object) => { + this.itemsdataset.push(data); + + this.KeysMap.set(this.itemsdataset.length, this.getKeysFromMetadata(data, '')); + this.filteredOptions = of(this.keys); }); } + createDataset(item: Object) { + let data: string = ''; + let properties: string = ''; - - - createDataset(map: Map<string, string>) { - let data: string; - let dcat: string = ''; - - map.forEach((value, key) => { - dcat += key + ' "' + value + '";\n' - }) + for (let i = 0; i < this.selectedPaths.length; i++) { + if (this.selectedPaths[i]) { + let tab = this.selectedPaths[i].split('/'); + properties += this.datasetModel[i].identifier + ' "' + this.getValue(tab, item) + '";\n' + } + } data = '\@prefix dcat: <http://www.w3.org/ns/dcat#>.\n\ @prefix dct: <http://purl.org/dc/terms/>.\n\ @@ -104,58 +86,76 @@ export class MappingComponent implements OnInit { @prefix s: <'+ this.appConfig.fdpurl + '/>.\n\ @prefix c: <'+ this.appConfig.fdpurl + '/catalog/>.\n\ \n\ - s:new\n' + dcat; + s:new\n' + properties; console.log('data: ' + data); //return this.dataSetService.createDataSet(data); } - + private getValue(tab: string[], item: Object): string { + let obj: Object + for (let i = 0; i < tab.length; i++) { + if (tab.length == 1) { + return item[tab[0]]; + } else { + if (i == 0) { + obj = item[tab[i]] + } else if (i < tab.length - 1) { + obj = obj[tab[i]]; + } else { + return obj[tab[i]]; + } + } + } + } + mapDataset() { + this.itemsdataset.forEach((data: Object) => { + this.createDataset(data); + }) + } /* function to get recursively all the keys and values from the JSON object */ - getJsonTree(obj: Object, keyParent: string) { + getKeysFromMetadata(obj: Object, keyParent: string): string[] { Object.keys(obj).forEach(key => { if (typeof obj[key] === 'object') { if (Array.isArray(obj[key])) { obj[key].forEach(e => { if (typeof e === 'object') { - this.getJsonTree(e, keyParent + '[\'' + key + '\']' + '[\'' + obj[key].indexOf(e) + '\']'); + this.getKeysFromMetadata(e, keyParent + '/' + key + '/' + obj[key].indexOf(e)); } else { - this.jsonTreeMap.set(keyParent + '[\'' + key + '\']' + '[\'' + obj[key].indexOf(e) + '\']', e) + this.keys.push(keyParent + '/' + key + '/' + obj[key].indexOf(e)) } }); } else { - this.getJsonTree(obj[key], keyParent + '[\'' + key + '\']'); + if (keyParent) { + this.getKeysFromMetadata(obj[key], keyParent + '/' + key); + } else { + this.getKeysFromMetadata(obj[key], key); + } } } else { - this.jsonTreeMap.set(keyParent + '[\'' + key + '\']', obj[key]) + if (keyParent) { + this.keys.push(keyParent + '/' + key) + } else { + this.keys.push(key) + } } }); + return this.keys; } - - mapDataset() { - let mappedMetadatas:Map<string, string> = new Map(); - for (let i = 0; i < this.identifiers.length; i++) { - this.jsonTreeMap.forEach((value, key) => { - if (this.identifiers[i] === key) { - mappedMetadatas.set(this.datasetModel[i].identifier, value) - - } - }) - } - this.createDataset(mappedMetadatas); - } + trackByIndex(index: number, obj: any): any { return index; } + /* autocompletion functions */ private filter(value: string): string[] { let filterValue = value.toLowerCase(); - return this.options.filter(optionValue => optionValue.toLowerCase().includes(filterValue)); + return this.keys.filter(optionValue => optionValue.toLowerCase().includes(filterValue)); } getFilteredOptions(value: string): Observable<string[]> { @@ -170,7 +170,7 @@ export class MappingComponent implements OnInit { this.filteredOptions = this.getFilteredOptions($event); } reset() { - this.filteredOptions = of(this.options); + this.filteredOptions = of(this.keys); } } -- GitLab From 5701db796701d515df9ea366c8ea1a8d4f864f69 Mon Sep 17 00:00:00 2001 From: Baptiste Toulemonde <toulemonde@cines.fr> Date: Thu, 8 Jul 2021 14:32:15 +0200 Subject: [PATCH 10/18] mapping: improved mapping user interface --- src/app/app.module.ts | 3 +- src/app/mapping/mapping.component.html | 42 +++++++++---- src/app/mapping/mapping.component.ts | 87 +++++++++++++++++--------- 3 files changed, 88 insertions(+), 44 deletions(-) diff --git a/src/app/app.module.ts b/src/app/app.module.ts index d023bb8be..01eff55d8 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -35,7 +35,7 @@ import { MappingComponent } from './mapping/mapping.component'; import { NebularModule } from './nebular.module'; import { AppRoutingModule } from './app-routing.module'; -import { NbLayoutModule, NbThemeModule, NbTooltipModule, NbSpinnerModule, NbSelectModule, NbTabsetModule, NbAutocompleteModule } from '@nebular/theme'; +import { NbLayoutModule, NbThemeModule, NbTooltipModule, NbSpinnerModule, NbSelectModule, NbTabsetModule, NbAutocompleteModule, NbListModule } from '@nebular/theme'; import { DashboardComponent } from './dashboard/dashboard.component'; @@ -84,6 +84,7 @@ import { DashboardComponent } from './dashboard/dashboard.component'; NbTabsetModule, NbTooltipModule, NbAutocompleteModule, + NbListModule, ], providers: [ diff --git a/src/app/mapping/mapping.component.html b/src/app/mapping/mapping.component.html index 72395c52c..685b10ddb 100644 --- a/src/app/mapping/mapping.component.html +++ b/src/app/mapping/mapping.component.html @@ -10,26 +10,26 @@ <div class="col-4"> - - <label nbInput fullWidth type="text" for="{{dataset.identifier}}">{{dataset.identifier}} + <nb-form-field> + <input nbInput fullWidth type="text" value="{{dataset.identifier}}" disabled /> <button nbSuffix nbTooltip="{{dataset.name}}: {{dataset.usageNote}}" nbTooltipStatus="info" nbButton status="basic" ghost> <nb-icon [icon]=" 'question-mark-circle-outline' " pack="eva"> </nb-icon> </button> - </label> + </nb-form-field> </div> <div class="col-8"> <nb-form-field> - <input #autoInput #{{dataset.identifier}} fullWidth id="{{dataset.identifier}}" nbInput (input)="onChange()" - placeholder="Enter value" [nbAutocomplete]="auto" [(ngModel)]="selectedPaths[index]" (focus)="reset()"/> + <input #autoInput #{{dataset.identifier}} fullWidth id="{{dataset.identifier}}" + nbInput (input)="onChange()" placeholder="Enter value" [nbAutocomplete]="auto" + [(ngModel)]="selectedPaths[index]" (focus)="reset()" /> <nb-autocomplete #auto> - <nb-option *ngFor="let option of filteredOptions | async" - [value]="option"> + <nb-option *ngFor="let option of filteredOptions | async" [value]="option"> {{ option }} </nb-option> @@ -49,11 +49,27 @@ <div class="card-col"> <nb-card> <nb-card-header>Map</nb-card-header> - <nb-card-body></nb-card-body> + <nb-card-body> + <nb-list> + <nb-list-item *ngFor="let d of mappedMetadatas | keyvalue"> + {{d.key}} => {{d.value}} + </nb-list-item> + </nb-list> + + </nb-card-body> + <nb-card-footer> + <div class="row"> + <div *ngIf=" !first "> + <button nbButton (click)=" prev()" [disabled]="index == 0">prev</button> + </div> + <div *ngIf="first"> + <button nbButton (click)="mapDataset()">Check mapping</button> + </div> + <div *ngIf="!first "> + <button nbButton (click)=" next()" [disabled]="index == itemsdataset.length -1">next</button> + </div> + </div> + </nb-card-footer> </nb-card> </div> -</div> - -<div> - <button (click)="mapDataset()">test</button> -</div> +</div> \ No newline at end of file diff --git a/src/app/mapping/mapping.component.ts b/src/app/mapping/mapping.component.ts index 853dce8fd..0d18fb0d8 100644 --- a/src/app/mapping/mapping.component.ts +++ b/src/app/mapping/mapping.component.ts @@ -9,8 +9,7 @@ import { Dataset } from './class/Dataset'; @Component({ selector: 'app-mapping', templateUrl: './mapping.component.html', - styleUrls: ['./mapping.component.scss'], - + styleUrls: ['./mapping.component.scss'] }) export class MappingComponent implements OnInit { @@ -19,9 +18,12 @@ export class MappingComponent implements OnInit { datasetModel: Dataset[]; filteredOptions: Observable<string[]>; keys: string[] = []; - KeysMap: Map<number, string[]> = new Map(); + keysMap: Map<number, string[]> = new Map(); selectedPaths: string[]; - + mappedMetadatas: Map<string, string> = new Map(); + DatasetToPublish: Map<string, string>[]; + index: number = 0 + first: boolean = true; @ViewChild('autoInput') input; @@ -45,6 +47,7 @@ export class MappingComponent implements OnInit { //appeler smart havester pour récuperer l'api à lancer let params = 'api/search?q=*&per_page=5&type=dataset&start=50&show_facets=true&show_my_data=true'; this.dataSetService.getDatasetsFromApi(this.urlrepo, params).subscribe(data => { + console.log(data) this.itemsdatasets = data['data']['items']; for (var i = 0; i < this.itemsdatasets.length; i++) { if (!this.dataSetService.findDataSetByTitle(this.itemsdatasets[i]['name'])) { @@ -62,35 +65,44 @@ export class MappingComponent implements OnInit { //appeler smart havester pour récuperer l'api à lancer this.dataSetService.getDatasetsFromApi(this.urlrepo, params).subscribe((data: Object) => { this.itemsdataset.push(data); - - this.KeysMap.set(this.itemsdataset.length, this.getKeysFromMetadata(data, '')); - this.filteredOptions = of(this.keys); + this.keys = []; + this.getKeysFromMetadata(data, '') + this.keysMap.set(this.itemsdataset.length, this.keys); + this.filteredOptions = of(this.keysMap.get(1)); }); } createDataset(item: Object) { - let data: string = ''; - let properties: string = ''; + + for (let i = 0; i < this.selectedPaths.length; i++) { if (this.selectedPaths[i]) { - let tab = this.selectedPaths[i].split('/'); - properties += this.datasetModel[i].identifier + ' "' + this.getValue(tab, item) + '";\n' + let tab = this.selectedPaths[i].split(' : '); + this.mappedMetadatas.set(this.datasetModel[i].identifier, this.getValue(tab, item)); } } - data = '\@prefix dcat: <http://www.w3.org/ns/dcat#>.\n\ - @prefix dct: <http://purl.org/dc/terms/>.\n\ - @prefix language: <http://id.loc.gov/vocabulary/iso639-1/>.\n\ - @prefix s: <'+ this.appConfig.fdpurl + '/>.\n\ - @prefix c: <'+ this.appConfig.fdpurl + '/catalog/>.\n\ - \n\ - s:new\n' + properties; + + } + + publishDataset() { + let data: string = ''; + let properties: string = ''; + + properties += this.mappedMetadatas.keys[this.index] + ' "' + this.mappedMetadatas.get(this.mappedMetadatas.keys[this.index]) + '";\n'; + + data = '\@prefix dcat: <http://www.w3.org/ns/dcat#>.\n\ + @prefix dct: <http://purl.org/dc/terms/>.\n\ + @prefix language: <http://id.loc.gov/vocabulary/iso639-1/>.\n\ + @prefix s: <'+ this.appConfig.fdpurl + '/>.\n\ + @prefix c: <'+ this.appConfig.fdpurl + '/catalog/>.\n\ + \n\ +s:new\n' + properties; console.log('data: ' + data); //return this.dataSetService.createDataSet(data); - } private getValue(tab: string[], item: Object): string { @@ -110,46 +122,61 @@ export class MappingComponent implements OnInit { } } mapDataset() { - this.itemsdataset.forEach((data: Object) => { - this.createDataset(data); - }) + this.createDataset(this.itemsdataset[this.index]); + this.first = false; + } + next() { + if (this.index < this.itemsdataset.length) { + this.index += 1; + this.createDataset(this.itemsdataset[this.index]) + console.log('index = ' + this.index); + } + } + prev() { + this.index -= 1; + this.createDataset(this.itemsdataset[this.index]) + console.log('index = ' + this.index); } + /* function to get recursively all the keys and values from the JSON object */ - getKeysFromMetadata(obj: Object, keyParent: string): string[] { + getKeysFromMetadata(obj: Object, keyParent: string) { Object.keys(obj).forEach(key => { if (typeof obj[key] === 'object') { if (Array.isArray(obj[key])) { obj[key].forEach(e => { if (typeof e === 'object') { - this.getKeysFromMetadata(e, keyParent + '/' + key + '/' + obj[key].indexOf(e)); + this.getKeysFromMetadata(e, keyParent + ' : ' + key + ' : ' + obj[key].indexOf(e)); } else { - this.keys.push(keyParent + '/' + key + '/' + obj[key].indexOf(e)) + this.keys.push(keyParent + ' : ' + key + ' : ' + obj[key].indexOf(e)) } }); } else { if (keyParent) { - this.getKeysFromMetadata(obj[key], keyParent + '/' + key); + this.getKeysFromMetadata(obj[key], keyParent + ' : ' + key); } else { this.getKeysFromMetadata(obj[key], key); } } } else { if (keyParent) { - this.keys.push(keyParent + '/' + key) + this.keys.push(keyParent + ' : ' + key) } else { this.keys.push(key) } } }); - return this.keys; + } - + trackByIndex(index: number, obj: any): any { return index; } - + + + + /* autocompletion functions */ -- GitLab From 4c1c1075b0b06e5b1a5ed98a632ed084aa8d6ca8 Mon Sep 17 00:00:00 2001 From: Baptiste Toulemonde <toulemonde@cines.fr> Date: Fri, 9 Jul 2021 09:26:50 +0200 Subject: [PATCH 11/18] mapping: feature to delete properties once selected --- src/app/mapping/mapping.component.html | 26 +++++++++++------ src/app/mapping/mapping.component.scss | 12 ++++++++ src/app/mapping/mapping.component.ts | 39 ++++++++++++++++++-------- 3 files changed, 58 insertions(+), 19 deletions(-) diff --git a/src/app/mapping/mapping.component.html b/src/app/mapping/mapping.component.html index 685b10ddb..970249d6e 100644 --- a/src/app/mapping/mapping.component.html +++ b/src/app/mapping/mapping.component.html @@ -39,11 +39,14 @@ </div> </nb-form-field> </ng-container> - </nb-card-body> </nb-card> </div> - +</div> +<div class="row"> + <div> + <button nbButton (click)="mapDataset()">Check mapping</button> + </div> </div> <div class="card-row"> <div class="card-col"> @@ -51,9 +54,18 @@ <nb-card-header>Map</nb-card-header> <nb-card-body> <nb-list> - <nb-list-item *ngFor="let d of mappedMetadatas | keyvalue"> - {{d.key}} => {{d.value}} - </nb-list-item> + + <nb-list-item *ngFor="let data of mappedMetadatas[index] | keyvalue "> + <div class="row"> + <div class="col-5">{{data.key}} : </div> + <div class="col-5">{{data.value}}</div> + <div class="col-2"><button nbButton ghost> + <nb-icon icon="trash-2-outline" status="danger" (click)="deleteProperty(data.key)"> + </nb-icon> + </button></div> + </div> + </nb-list-item> + </nb-list> </nb-card-body> @@ -62,9 +74,7 @@ <div *ngIf=" !first "> <button nbButton (click)=" prev()" [disabled]="index == 0">prev</button> </div> - <div *ngIf="first"> - <button nbButton (click)="mapDataset()">Check mapping</button> - </div> + <div *ngIf="!first "> <button nbButton (click)=" next()" [disabled]="index == itemsdataset.length -1">next</button> </div> diff --git a/src/app/mapping/mapping.component.scss b/src/app/mapping/mapping.component.scss index 3867e933a..4c11d8514 100644 --- a/src/app/mapping/mapping.component.scss +++ b/src/app/mapping/mapping.component.scss @@ -16,6 +16,18 @@ margin: 0 0.5rem; } + .col-5 { + width: 45%; + + margin-right: 10px; + align-items: stretch; + } + .col-2 { + width: 10%; + vertical-align: middle; + margin-right: 10px; + align-items: stretch; + } .col-4 { width: 30%; diff --git a/src/app/mapping/mapping.component.ts b/src/app/mapping/mapping.component.ts index 0d18fb0d8..0bd54f71e 100644 --- a/src/app/mapping/mapping.component.ts +++ b/src/app/mapping/mapping.component.ts @@ -20,7 +20,8 @@ export class MappingComponent implements OnInit { keys: string[] = []; keysMap: Map<number, string[]> = new Map(); selectedPaths: string[]; - mappedMetadatas: Map<string, string> = new Map(); + mappedMetadatas: Map<string, string>[] = []; + obsMappedMetadatas: Observable<Map<string, string>[]>; DatasetToPublish: Map<string, string>[]; index: number = 0 first: boolean = true; @@ -41,6 +42,7 @@ export class MappingComponent implements OnInit { }, error => console.error(error) ); + this.obsMappedMetadatas = of(this.mappedMetadatas) } listdatasets() { @@ -73,17 +75,16 @@ export class MappingComponent implements OnInit { } - createDataset(item: Object) { - - - + createDataset(item: Object): Map<string, string> { + let mappedMetadata: Map<string, string> = new Map() for (let i = 0; i < this.selectedPaths.length; i++) { if (this.selectedPaths[i]) { let tab = this.selectedPaths[i].split(' : '); - this.mappedMetadatas.set(this.datasetModel[i].identifier, this.getValue(tab, item)); + mappedMetadata.set(this.datasetModel[i].identifier, this.getValue(tab, item)); } } - + + return mappedMetadata; } @@ -91,7 +92,8 @@ export class MappingComponent implements OnInit { let data: string = ''; let properties: string = ''; - properties += this.mappedMetadatas.keys[this.index] + ' "' + this.mappedMetadatas.get(this.mappedMetadatas.keys[this.index]) + '";\n'; + this.mappedMetadatas.forEach((value: Map<string, string>, key: number) => { + properties += value.keys[this.index] + ' "' + value.get(value.keys[this.index]) + '";\n'; data = '\@prefix dcat: <http://www.w3.org/ns/dcat#>.\n\ @prefix dct: <http://purl.org/dc/terms/>.\n\ @@ -103,6 +105,8 @@ s:new\n' + properties; console.log('data: ' + data); //return this.dataSetService.createDataSet(data); + }) + } private getValue(tab: string[], item: Object): string { @@ -113,16 +117,24 @@ s:new\n' + properties; } else { if (i == 0) { obj = item[tab[i]] - } else if (i < tab.length - 1) { + } else if (i < tab.length - 1 && obj[tab[i]]) { obj = obj[tab[i]]; } else { - return obj[tab[i]]; + if (obj[tab[i]]) { + return obj[tab[i]]; + } else { + return 'undefined'; + } + } } } } mapDataset() { - this.createDataset(this.itemsdataset[this.index]); + this.itemsdataset.forEach( (dataset: Object) => { + this.mappedMetadatas.push(this.createDataset(dataset)) + }) + console.log(this.mappedMetadatas) this.first = false; } next() { @@ -138,6 +150,11 @@ s:new\n' + properties; console.log('index = ' + this.index); } + // to delete a property of dcat dataset mapped + deleteProperty(key: string) { + this.mappedMetadatas[this.index].delete(key); + } + /* function to get recursively all the keys and values from the JSON object */ getKeysFromMetadata(obj: Object, keyParent: string) { -- GitLab From 05cc3729fa0ac6ec995d1d8153adb3628ecfd97c Mon Sep 17 00:00:00 2001 From: Baptiste Toulemonde <toulemonde@cines.fr> Date: Tue, 13 Jul 2021 13:40:48 +0200 Subject: [PATCH 12/18] mapping: get datas from previous step --- src/app/app-routing.module.ts | 1 - src/app/datasets/datasets.component.ts | 16 ++- .../datasets/services/dataset-crud.service.ts | 49 +++++--- src/app/mapping/mapping.component.html | 12 +- src/app/mapping/mapping.component.ts | 111 ++++++++---------- src/app/publishapi/publishapi.component.html | 12 +- src/app/publishapi/publishapi.component.ts | 1 + 7 files changed, 108 insertions(+), 94 deletions(-) diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 7dba399fd..560a04624 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -30,7 +30,6 @@ const routes: ICustomRoute[] = [ { path: 'repository', component: RepositoryComponent }, { path: 'repositoryinfo', component: RepositoryinfoComponent }, { path: 'accessapi', component: AccessapiComponent }, - { path: 'datasets', component: DatasetsComponent }, { path: 'stats', component: StatsComponent }, { path: 'settingfdp', component: SettingfdpComponent }, { path: 'settingsmartharvester', component: SettingsmartapiComponent }, diff --git a/src/app/datasets/datasets.component.ts b/src/app/datasets/datasets.component.ts index 041608330..e823b558e 100644 --- a/src/app/datasets/datasets.component.ts +++ b/src/app/datasets/datasets.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, Input, OnInit, Output } from '@angular/core'; import { AppConfiguration } from '../AppConfiguration'; import { DatasetCrudService } from './services/dataset-crud.service'; import { OpenApi } from '../publishapi/class/openapi'; @@ -27,8 +27,8 @@ export class DatasetsComponent implements OnInit { previews = new Map<string, any>(); spinners = new Map<string, boolean>(); - itemsdatasets: any; - itemsdataset: any; + + Object = Object; //urlrepo = "dataverse.ird.fr"; @@ -44,7 +44,8 @@ export class DatasetsComponent implements OnInit { } ngOnInit() { - this.itemsdataset = []; + this.dataSetService.itemsDataset = []; + } ngOnChanges() { @@ -119,6 +120,9 @@ export class DatasetsComponent implements OnInit { break; case OpenApiTag.dataset: this.processDataSet(data, pathName, preview); + if (response.status.toString().startsWith('2')) + this.dataSetService.saveDatasets(data); + console.log(this.dataSetService.itemsDataset) break; } }).finally(() => this.spinners.set(pathName, false)); @@ -215,7 +219,7 @@ export class DatasetsComponent implements OnInit { return null; } - listdatasets() { + /*listdatasets() { var myHeaders = new Headers(); myHeaders.append("Content-Type", "Application/json"); var myInit = { method: 'GET', headers: myHeaders }; @@ -353,7 +357,7 @@ export class DatasetsComponent implements OnInit { return this.dataSetService.createDistribution(data); - } + }*/ diff --git a/src/app/datasets/services/dataset-crud.service.ts b/src/app/datasets/services/dataset-crud.service.ts index a6d1bfc9a..74692eb03 100644 --- a/src/app/datasets/services/dataset-crud.service.ts +++ b/src/app/datasets/services/dataset-crud.service.ts @@ -12,30 +12,38 @@ import { ParseXmlService } from '../../services/parse-xml.service'; export class DatasetCrudService { fds2Token: string - public results: string[] = []; + public results: string[] = []; + itemsDataset: Object[] = [] ; constructor(private http: HttpClient,private appConfig: AppConfiguration, private authService: AuthService, private parserService: ParseXmlService) { } createDataSet(data:string){ - this.authService.getF2DSAuthToken().subscribe(data=>{ - this.fds2Token = data.token - }) - if (this.fds2Token) { - const httpOptions = { - headers: new HttpHeaders({ - 'Accept': 'text/turtle', - 'Content-Type': 'text/turtle', - 'Authorization': 'Bearer '+ this.fds2Token - }) - }; - - let resultat = this.http.post(this.appConfig.fdpurl+"/dataset", data, httpOptions ).subscribe( (r)=>{console.log('reponse: ', r)}) ; - if (resultat){ - console.log("resultat: " + JSON.stringify(resultat)); - return JSON.stringify(resultat); + this.authService.getF2DSAuthToken().subscribe(token=>{ + this.fds2Token = token.token + if (this.fds2Token) { + const httpOptions = { + headers: new HttpHeaders({ + 'Accept': 'text/turtle', + 'Content-Type': 'text/turtle', + 'Authorization': 'Bearer '+ this.fds2Token + }) + }; + + this.http.post(this.appConfig.fdpurl+"/dataset", data, httpOptions ).subscribe( + (r)=>{ + if (r){ + console.log("resultat: " + JSON.stringify(r)); + + } + + }, + error => console.error("The repository has not been published") + + ) ; + } - return "The repository has not been published" - } + }) + } createDistribution(data:string){ @@ -86,6 +94,9 @@ export class DatasetCrudService { getLocally<T = any>(path: string): Observable<T> { return this.http.get<T>(`${path}`); } + saveDatasets(obj: Object) { + this.itemsDataset.push(obj); + } } diff --git a/src/app/mapping/mapping.component.html b/src/app/mapping/mapping.component.html index 970249d6e..0ad1f4190 100644 --- a/src/app/mapping/mapping.component.html +++ b/src/app/mapping/mapping.component.html @@ -1,6 +1,9 @@ <div class="card-row"> <div class="card-col"> - <nb-card size="giant"> + <nb-card size="giant" [nbSpinner]="loading" + nbSpinnerStatus="primary" + nbSpinnerSize="large" + nbSpinnerMessage="Loading..."> <nb-card-header>Dataset metadata</nb-card-header> <nb-card-body> <div></div> @@ -50,7 +53,7 @@ </div> <div class="card-row"> <div class="card-col"> - <nb-card> + <nb-card > <nb-card-header>Map</nb-card-header> <nb-card-body> <nb-list> @@ -76,7 +79,10 @@ </div> <div *ngIf="!first "> - <button nbButton (click)=" next()" [disabled]="index == itemsdataset.length -1">next</button> + <button nbButton (click)=" next()" [disabled]="index == mappedMetadatas.length -1">next</button> + </div> + <div *ngIf="!first "> + <button nbButton (click)=" publishDataset()">Publish</button> </div> </div> </nb-card-footer> diff --git a/src/app/mapping/mapping.component.ts b/src/app/mapping/mapping.component.ts index 0bd54f71e..27239c7d3 100644 --- a/src/app/mapping/mapping.component.ts +++ b/src/app/mapping/mapping.component.ts @@ -1,5 +1,5 @@ -import { Component, OnInit, ViewChild } from '@angular/core'; +import { Component, Input, OnInit, ViewChild } from '@angular/core'; import { Observable, of } from 'rxjs'; import { map } from 'rxjs/operators'; import { AppConfiguration } from '../AppConfiguration'; @@ -13,7 +13,7 @@ import { Dataset } from './class/Dataset'; }) export class MappingComponent implements OnInit { - itemsdatasets: any; + itemsdataset: Object[] = [] datasetModel: Dataset[]; filteredOptions: Observable<string[]>; @@ -22,57 +22,44 @@ export class MappingComponent implements OnInit { selectedPaths: string[]; mappedMetadatas: Map<string, string>[] = []; obsMappedMetadatas: Observable<Map<string, string>[]>; - DatasetToPublish: Map<string, string>[]; + DatasetToPublish: Map<string, string>[]; index: number = 0 first: boolean = true; + loading: boolean = false; @ViewChild('autoInput') input; - - - urlrepo = "https://data.inrae.fr"; - // urlrepo = "dataverse.ird.fr"; + @Input() catalogId: any; constructor(private appConfig: AppConfiguration, private dataSetService: DatasetCrudService) { } + ngOnInit() { - this.listdatasets(); this.dataSetService.getLocally('./assets/dataset.json').subscribe( dataset => { this.datasetModel = dataset; this.selectedPaths = new Array(dataset.length); }, - error => console.error(error) + error => { + console.error(error); + }, ); + this.obsMappedMetadatas = of(this.mappedMetadatas) + this.populatecatalogue(); } - listdatasets() { - //appeler smart havester pour récuperer l'api à lancer - let params = 'api/search?q=*&per_page=5&type=dataset&start=50&show_facets=true&show_my_data=true'; - this.dataSetService.getDatasetsFromApi(this.urlrepo, params).subscribe(data => { - console.log(data) - this.itemsdatasets = data['data']['items']; - for (var i = 0; i < this.itemsdatasets.length; i++) { - if (!this.dataSetService.findDataSetByTitle(this.itemsdatasets[i]['name'])) { - if (data['data']['items'][i]['global_id']) { - this.populatecatalogue(data['data']['items'][i]['global_id']); - } - } - } - }); - } - populatecatalogue(id: string) { - let params = `api/datasets/export?exporter=dataverse_json&persistentId=${id}`; - //appeler smart havester pour récuperer l'api à lancer - this.dataSetService.getDatasetsFromApi(this.urlrepo, params).subscribe((data: Object) => { - this.itemsdataset.push(data); - this.keys = []; - this.getKeysFromMetadata(data, '') - this.keysMap.set(this.itemsdataset.length, this.keys); - this.filteredOptions = of(this.keysMap.get(1)); - }); + populatecatalogue() { + this.itemsdataset = this.dataSetService.itemsDataset; + this.keys = []; + for (let i = 0; i< this.itemsdataset.length; i++){ + if (i === 0) { + this.getKeysFromMetadata(this.itemsdataset[i], ''); + this.keysMap.set(this.itemsdataset.length, this.keys); + this.filteredOptions = of(this.keysMap.get(1)); + } + } } createDataset(item: Object): Map<string, string> { @@ -83,31 +70,41 @@ export class MappingComponent implements OnInit { mappedMetadata.set(this.datasetModel[i].identifier, this.getValue(tab, item)); } } - + return mappedMetadata; } - publishDataset() { - let data: string = ''; - let properties: string = ''; - - this.mappedMetadatas.forEach((value: Map<string, string>, key: number) => { - properties += value.keys[this.index] + ' "' + value.get(value.keys[this.index]) + '";\n'; + - data = '\@prefix dcat: <http://www.w3.org/ns/dcat#>.\n\ - @prefix dct: <http://purl.org/dc/terms/>.\n\ - @prefix language: <http://id.loc.gov/vocabulary/iso639-1/>.\n\ - @prefix s: <'+ this.appConfig.fdpurl + '/>.\n\ - @prefix c: <'+ this.appConfig.fdpurl + '/catalog/>.\n\ - \n\ -s:new\n' + properties; +publishDataset() { + let data: string = ''; + let properties: string = ''; - console.log('data: ' + data); - //return this.dataSetService.createDataSet(data); + this.mappedMetadatas.forEach((value: Map<string, string>, key: number) => { + properties = ""; + value.forEach( (value: string, key: string) => { + + properties += key+ ' "' + value + '";\n'; }) - - } + + + data = '\@prefix dcat: <http://www.w3.org/ns/dcat#>.\n\ + @prefix dct: <http://purl.org/dc/terms/>.\n\ + @prefix language: <http://id.loc.gov/vocabulary/iso639-1/>.\n\ + @prefix s: <'+ this.appConfig.fdpurl + '/>.\n\ + @prefix c: <'+ this.appConfig.fdpurl + '/catalog/>.\n\ + \n\ +s:new\n\ +a dcat:Dataset, dcat:Resource;\n\ +dct:isPartOf c:'+ this.catalogId + ';\n' + properties + '.'; + + console.log('data: ' + data); + this.dataSetService.createDataSet(data); + }) + +} + private getValue(tab: string[], item: Object): string { let obj: Object @@ -125,13 +122,14 @@ s:new\n' + properties; } else { return 'undefined'; } - + } } } } mapDataset() { - this.itemsdataset.forEach( (dataset: Object) => { + this.mappedMetadatas = []; + this.itemsdataset.forEach((dataset: Object) => { this.mappedMetadatas.push(this.createDataset(dataset)) }) console.log(this.mappedMetadatas) @@ -186,15 +184,10 @@ s:new\n' + properties; } - trackByIndex(index: number, obj: any): any { return index; } - - - - /* autocompletion functions */ private filter(value: string): string[] { diff --git a/src/app/publishapi/publishapi.component.html b/src/app/publishapi/publishapi.component.html index 0fd440c98..693ef4e73 100644 --- a/src/app/publishapi/publishapi.component.html +++ b/src/app/publishapi/publishapi.component.html @@ -4,7 +4,7 @@ <nb-card> <nb-card-body> - <nb-stepper orientation="horizontal" disableStepNavigation> + <nb-stepper orientation="horizontal" disableStepNavigation > <nb-step [label]="labelOne"> <ng-template #labelOne>First step</ng-template> <h4>Describe API</h4> @@ -292,16 +292,16 @@ <h4>Use parameters & launch request</h4> <app-datasets [openApi]="openApi"></app-datasets> <button class="prev-button" nbButton nbStepperPrevious>prev</button> - <button class="next-button" nbButton nbStepperNext>next</button> + <button class="next-button" nbButton nbStepperNext (click)="initLabelThree = true">next</button> </nb-step> - <nb-step [label]="labelThree"> + <nb-step [label]="labelThree" > <ng-template #labelThree>Third step</ng-template> <h4>Map DCAT Schema </h4> <p class="lorem"> Map your metadata schema with DCAT schema - </p> - <app-mapping></app-mapping> - <button class="prev-button" nbButton nbStepperPrevious>prev</button> + </p> + <app-mapping *ngIf="initLabelThree" [catalogId]="openApi.info['x-catalog-id']"></app-mapping> + <button class="prev-button" nbButton nbStepperPrevious (click)="initLabelThree = false">prev</button> <button class="next-button" nbButton nbStepperNext>next</button> </nb-step> <nb-step [label]="labelFour"> diff --git a/src/app/publishapi/publishapi.component.ts b/src/app/publishapi/publishapi.component.ts index 085fbae77..3a3cf8853 100644 --- a/src/app/publishapi/publishapi.component.ts +++ b/src/app/publishapi/publishapi.component.ts @@ -31,6 +31,7 @@ export class PublishApiComponent implements OnInit { httpStatusCodes: string[]; catalogList: { title: string, catId: string, server: string }[] = []; canNext = false; + initLabelThree: boolean = false; ngOnInit(): void { this.openApi = new OpenApi(null, null); -- GitLab From 13bc51e05f34e27915366d7bae8a025d9a7e83bd Mon Sep 17 00:00:00 2001 From: Baptiste Toulemonde <toulemonde@cines.fr> Date: Tue, 13 Jul 2021 17:08:19 +0200 Subject: [PATCH 13/18] mapping: small fix --- .../datasets/services/dataset-crud.service.ts | 31 ++++++------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/src/app/datasets/services/dataset-crud.service.ts b/src/app/datasets/services/dataset-crud.service.ts index 74692eb03..cafd63ee3 100644 --- a/src/app/datasets/services/dataset-crud.service.ts +++ b/src/app/datasets/services/dataset-crud.service.ts @@ -2,7 +2,7 @@ import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { AppConfiguration } from 'src/app/AppConfiguration'; -import { AuthService } from 'src/app/authentication/services/auth.service'; +import { TokenStorageService } from 'src/app/authentication/services/token-storage.service'; import { ParseXmlService } from '../../services/parse-xml.service'; @@ -11,15 +11,12 @@ import { ParseXmlService } from '../../services/parse-xml.service'; }) export class DatasetCrudService { - fds2Token: string + fds2Token: string = this.sessionStorage.getFDPToken(); public results: string[] = []; itemsDataset: Object[] = [] ; - constructor(private http: HttpClient,private appConfig: AppConfiguration, private authService: AuthService, private parserService: ParseXmlService) { } + constructor(private http: HttpClient,private appConfig: AppConfiguration, private parserService: ParseXmlService, private sessionStorage: TokenStorageService) { } createDataSet(data:string){ - - this.authService.getF2DSAuthToken().subscribe(token=>{ - this.fds2Token = token.token if (this.fds2Token) { const httpOptions = { headers: new HttpHeaders({ @@ -29,28 +26,21 @@ export class DatasetCrudService { }) }; - this.http.post(this.appConfig.fdpurl+"/dataset", data, httpOptions ).subscribe( - (r)=>{ - if (r){ + this.http.post(this.appConfig.fdpurl+"/dataset", data, httpOptions ).subscribe( r => { console.log("resultat: " + JSON.stringify(r)); - - } - }, - error => console.error("The repository has not been published") + error => console.error("The repository has not been published: " + error) , + () => console.log("The datasets has benn published") ) ; } - }) + } createDistribution(data:string){ - this.authService.getF2DSAuthToken().subscribe(data=>{ - this.fds2Token = data.token - }) if (this.fds2Token) { const httpOptions = { headers: new HttpHeaders({ @@ -60,11 +50,10 @@ export class DatasetCrudService { }) }; - let resultat = this.http.post(this.appConfig.fdpurl+"/distribution", data, httpOptions ).subscribe( (r)=>{console.log('reponse: ', r)}) ; - if (resultat){ - console.log("resultat: " + JSON.stringify(resultat)); + let resultat = this.http.post(this.appConfig.fdpurl+"/distribution", data, httpOptions ).subscribe((r)=>{ + console.log('reponse: ', r); return JSON.stringify(resultat); - } + }) ; } } -- GitLab From 1935e8d27a649067e74a9d7408b49fa1b61c67b1 Mon Sep 17 00:00:00 2001 From: Baptiste Toulemonde <toulemonde@cines.fr> Date: Thu, 15 Jul 2021 15:43:32 +0200 Subject: [PATCH 14/18] fix token management and logout feature --- src/app/app-routing.module.ts | 3 +- .../authentication/services/auth.service.ts | 32 +++++++++++++------ .../services/token-storage.service.ts | 2 ++ .../authentication/signin/signin.component.ts | 16 ++++++---- .../authentication/signup/signup.component.ts | 2 +- src/app/dashboard/dashboard.component.html | 5 +-- src/app/dashboard/dashboard.component.scss | 3 ++ src/app/dashboard/dashboard.component.ts | 7 ++++ src/app/repository/repository.component.ts | 2 +- .../services/publish-repository.service.ts | 11 +++---- src/app/user/model/user.ts | 10 +++++- 11 files changed, 63 insertions(+), 30 deletions(-) diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 560a04624..292358d56 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -1,9 +1,8 @@ import { NgModule } from '@angular/core'; -import { Routes, RouterModule, Route } from '@angular/router'; +import { RouterModule, Route } from '@angular/router'; import { UserComponent } from './user/user.component'; import { RepositoryComponent } from './repository/repository.component'; import { AccessapiComponent } from './accessapi/accessapi.component'; -import { DatasetsComponent } from './datasets/datasets.component'; import { SettingfdpComponent } from './settingfdp/settingfdp.component'; import { SettingsmartapiComponent } from './settingsmartapi/settingsmartapi.component'; import { RepositoryinfoComponent } from './repositoryinfo/repositoryinfo.component'; diff --git a/src/app/authentication/services/auth.service.ts b/src/app/authentication/services/auth.service.ts index 13de15a0c..6c88d160a 100644 --- a/src/app/authentication/services/auth.service.ts +++ b/src/app/authentication/services/auth.service.ts @@ -2,23 +2,29 @@ import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { TokenStorageService } from './token-storage.service'; -import { map } from "rxjs/operators"; import { AppConfiguration } from 'src/app/AppConfiguration'; -import { env } from 'process'; import { environment } from 'src/environments/environment'; + + const AUTH_API = environment.smartharvesterUrl + '/harvester/auth'; const httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/json' }) }; + @Injectable({ providedIn: 'root' }) export class AuthService { - constructor(private http: HttpClient, private tokenService: TokenStorageService, private appConfig:AppConfiguration) { } + + + constructor(private http: HttpClient, private tokenService: TokenStorageService, private appConfig: AppConfiguration) { } + + + login(credentials): Observable<any> { let data: any @@ -41,16 +47,16 @@ export class AuthService { update(user): Observable<any> { return this.http.post(AUTH_API + '/user', { - catalog_id: user.cat_id + catalog_id: user.cat_id }, httpOptions); } - getF2DSAuthToken():Observable<any> { - return this.http.post(this.appConfig.fdpurl+'/tokens', { - email: this.appConfig.fdpemail, - password: this.appConfig.fdppassword - },httpOptions); + getF2DSAuthToken(credentials): Observable<any> { + return this.http.post(this.appConfig.fdpurl + '/tokens', { + email: credentials.email, + password: credentials.password + }, httpOptions); } public isLoggedIn() { @@ -58,6 +64,12 @@ export class AuthService { } public logout() { - this.tokenService.removeToken(); + const config = { + headers: new HttpHeaders({ + 'Content-Type': 'application/x-www-form-urlencoded' + }) + }; + this.tokenService.signOut(); + return this.http.post(`${environment.smartharvesterUrl}/logout`, null, config); } } diff --git a/src/app/authentication/services/token-storage.service.ts b/src/app/authentication/services/token-storage.service.ts index 4acab50b5..5efd47144 100644 --- a/src/app/authentication/services/token-storage.service.ts +++ b/src/app/authentication/services/token-storage.service.ts @@ -17,6 +17,7 @@ export class TokenStorageService { public saveToken(token: string,f2dsToken:string): void { window.sessionStorage.removeItem(TOKEN_KEY); + window.sessionStorage.removeItem(F2DS_TOKEN_KEY); window.sessionStorage.setItem(TOKEN_KEY, token); window.sessionStorage.setItem(F2DS_TOKEN_KEY, f2dsToken); } @@ -38,6 +39,7 @@ export class TokenStorageService { } public removeToken(){ window.localStorage.removeItem(TOKEN_KEY); + window.sessionStorage.removeItem(F2DS_TOKEN_KEY); } diff --git a/src/app/authentication/signin/signin.component.ts b/src/app/authentication/signin/signin.component.ts index ba61f6ab1..63f28e0f3 100644 --- a/src/app/authentication/signin/signin.component.ts +++ b/src/app/authentication/signin/signin.component.ts @@ -21,7 +21,7 @@ export class SigninComponent implements OnInit { isLoginFailed = false; errorMessage = ''; showPassword = false; - user: SmartHarvesterUser = new SmartHarvesterUser(); + user: SmartHarvesterUser = new SmartHarvesterUser({}); constructor(private authService: AuthService, private router: Router, private tokenStorage: TokenStorageService) { } @@ -31,27 +31,29 @@ export class SigninComponent implements OnInit { // Uncomment line to avoid re-authentication if token is still valid //this.isLoggedIn = true; } - this.authService.getF2DSAuthToken().subscribe((response:F2DSResponse) => { - if (response) this.f2dsToken = response.token; - console.log("F2ds token is : ", this.f2dsToken) - }) + } //get formControls() { return this.formGroup.controls; } onSubmit(): void { - + this.authService.login(this.user).subscribe( data => { - this.tokenStorage.saveToken(data.accessToken, this.f2dsToken); + this.authService.getF2DSAuthToken(this.user).subscribe((response:F2DSResponse) => { + if (response) this.f2dsToken = response.token; + console.log("F2ds token is : ", this.f2dsToken); + this.tokenStorage.saveToken(data.accessToken, this.f2dsToken); this.tokenStorage.saveUser(data); this.isLoginFailed = false; this.isLoggedIn = true; console.log("User data : ", data) this.router.navigateByUrl('/dashboard'); + }) + //this.reloadPage(); }, err => { diff --git a/src/app/authentication/signup/signup.component.ts b/src/app/authentication/signup/signup.component.ts index b9e374291..8a757692f 100644 --- a/src/app/authentication/signup/signup.component.ts +++ b/src/app/authentication/signup/signup.component.ts @@ -16,7 +16,7 @@ export class SignupComponent implements OnInit { isLoginFailed = false; errorMessage = ''; showPassword = false; - user: SmartHarvesterUser = new SmartHarvesterUser(); + user: SmartHarvesterUser = new SmartHarvesterUser({}); constructor(private authService: AuthService, private router: Router) { } diff --git a/src/app/dashboard/dashboard.component.html b/src/app/dashboard/dashboard.component.html index 439aa3d7b..57e29c2f9 100644 --- a/src/app/dashboard/dashboard.component.html +++ b/src/app/dashboard/dashboard.component.html @@ -4,9 +4,10 @@ <a routerLink="/dashboard" routerLinkActive="active"> <img width="80" alt="Angular Logo" src="assets/images/logo.png" /> </a> - + <h3 style="width: 100%;text-align: center;"> <strong></strong></h3> <!--User badge--> + <nb-user style="white-space: pre;" name="{{userData.firstName}}" title="{{userData.lastName}}" @@ -14,7 +15,7 @@ nbContextMenuTag="my-context-menu" badgePosition="right"> </nb-user> - <!--<button routerLink="/login" nbContextMenuPlacement="right" outline nbButton>Login</button>--> + <button (click)="logout()" nbContextMenuPlacement="right" outline nbButton>Logout</button> </nb-layout-header> diff --git a/src/app/dashboard/dashboard.component.scss b/src/app/dashboard/dashboard.component.scss index e69de29bb..10fd21b25 100644 --- a/src/app/dashboard/dashboard.component.scss +++ b/src/app/dashboard/dashboard.component.scss @@ -0,0 +1,3 @@ +button { + margin-left: 10px; +} \ No newline at end of file diff --git a/src/app/dashboard/dashboard.component.ts b/src/app/dashboard/dashboard.component.ts index ebcd85424..83fdcceab 100644 --- a/src/app/dashboard/dashboard.component.ts +++ b/src/app/dashboard/dashboard.component.ts @@ -91,4 +91,11 @@ export class DashboardComponent implements OnInit { this.sidebarService.toggle(true); return false; } + + logout() { + this.authService.logout().subscribe( + value => this.route.navigateByUrl('/auth/signin') + ); + + } } diff --git a/src/app/repository/repository.component.ts b/src/app/repository/repository.component.ts index e9c83cc6e..00a7335ae 100644 --- a/src/app/repository/repository.component.ts +++ b/src/app/repository/repository.component.ts @@ -43,7 +43,7 @@ export class RepositoryComponent implements OnInit { ) { } ngOnInit() { - this.authService.getF2DSAuthToken(); + this.publishService.getPersistentUrl().subscribe({ next: (response) => this.persistentUrl = response.persistentUrl }); diff --git a/src/app/repository/services/publish-repository.service.ts b/src/app/repository/services/publish-repository.service.ts index 84dca3fab..913909bbc 100644 --- a/src/app/repository/services/publish-repository.service.ts +++ b/src/app/repository/services/publish-repository.service.ts @@ -15,6 +15,7 @@ interface PersistentUrlResponse { providedIn: 'root' }) export class PublishRepositoryService { + fds2Token: string = this.tokenService.getFDPToken(); constructor( private http: HttpClient, @@ -29,14 +30,12 @@ export class PublishRepositoryService { publishRepository(data: string) { - this.authService.getF2DSAuthToken().subscribe(tokenResponse => { - const fds2Token = tokenResponse.token; - if (fds2Token) { + if (this.fds2Token) { const myHeaders = new Headers(); myHeaders.append('Accept', 'text/turtle'); myHeaders.append('Content-Type', 'text/turtle'); - myHeaders.append('Authorization', 'Bearer ' + fds2Token); + myHeaders.append('Authorization', 'Bearer ' + this.fds2Token); const myInit = { method: 'POST', body: data, headers: myHeaders }; const myRequest = new Request(this.appConfig.fdpurl + "/catalog", myInit); @@ -53,7 +52,7 @@ export class PublishRepositoryService { return "The repository has not been published" } - }); + } getPersistentUrl(): Observable<PersistentUrlResponse> { @@ -61,7 +60,7 @@ export class PublishRepositoryService { } async addUserCatalog(catId: string): Promise<any> { - const tokenResponse = this.tokenService.getToken; + const tokenResponse = this.tokenService.getToken(); const user = this.tokenService.getUser(); return this.http.post(this.smartApiUrl + '/user/' + user.email + '/catalogs', catId, diff --git a/src/app/user/model/user.ts b/src/app/user/model/user.ts index ad90ab747..fbd9c6fd1 100644 --- a/src/app/user/model/user.ts +++ b/src/app/user/model/user.ts @@ -6,5 +6,13 @@ export class SmartHarvesterUser { public passwordConfirm?: string; public id?: "5fbfb86b688c8577c7b8aeff" public token?: "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0ZXN0QGNpbmVzLmZyIiwiaWF0IjoxNjA2ODQzNjkwLCJleHAiOjE2MDY5MzAwOTB9.UcmKMRmIEyNLW_kCEEI83uMuDG3Lgf5BKeAHvOhhjiFsV-8keKXxy5VLyHR4LvX_7vZL9WN_H_49-sLxGFTJyQ" - public tokenType?: "Bearer" + public tokenType?: "Bearer"; + + constructor(params: any) { + Object.assign(this, params); + } + + isAnonyme(): boolean { + return this.email === undefined; + } } -- GitLab From 74756c940d8945df5ce026f86c5df2541ec42916 Mon Sep 17 00:00:00 2001 From: Baptiste Toulemonde <toulemonde@cines.fr> Date: Thu, 15 Jul 2021 15:54:36 +0200 Subject: [PATCH 15/18] fix logout path --- src/app/authentication/services/auth.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/authentication/services/auth.service.ts b/src/app/authentication/services/auth.service.ts index 6c88d160a..be1686c49 100644 --- a/src/app/authentication/services/auth.service.ts +++ b/src/app/authentication/services/auth.service.ts @@ -70,6 +70,6 @@ export class AuthService { }) }; this.tokenService.signOut(); - return this.http.post(`${environment.smartharvesterUrl}/logout`, null, config); + return this.http.post(`${AUTH_API}/logout`, null, config); } } -- GitLab From 0f653d5035aebc88f77f8482d953eb8f74d2df14 Mon Sep 17 00:00:00 2001 From: Baptiste Toulemonde <toulemonde@cines.fr> Date: Fri, 16 Jul 2021 09:03:27 +0200 Subject: [PATCH 16/18] delete fdp & smartharvester settings: config from environement and get user connected to provide tokens --- src/app/app-routing.module.ts | 4 ++-- src/app/authentication/services/auth.service.ts | 3 ++- src/app/dashboard/dashboard.component.ts | 4 ++-- src/app/datasets/datasets.component.ts | 6 ++++-- src/app/datasets/services/dataset-crud.service.ts | 7 ++++--- src/app/mapping/mapping.component.ts | 6 ++++-- src/app/repository/repository.component.ts | 3 ++- src/app/repository/services/publish-repository.service.ts | 4 ++-- src/app/services/catalog.service.ts | 4 +++- 9 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 292358d56..a78e3ca46 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -30,8 +30,8 @@ const routes: ICustomRoute[] = [ { path: 'repositoryinfo', component: RepositoryinfoComponent }, { path: 'accessapi', component: AccessapiComponent }, { path: 'stats', component: StatsComponent }, - { path: 'settingfdp', component: SettingfdpComponent }, - { path: 'settingsmartharvester', component: SettingsmartapiComponent }, + /* { path: 'settingfdp', component: SettingfdpComponent }, + { path: 'settingsmartharvester', component: SettingsmartapiComponent },*/ { path: 'publishapi', component: PublishApiComponent }, { path: 'advancedsearch', component: SearchComponent }, ] diff --git a/src/app/authentication/services/auth.service.ts b/src/app/authentication/services/auth.service.ts index be1686c49..a4ee7ca60 100644 --- a/src/app/authentication/services/auth.service.ts +++ b/src/app/authentication/services/auth.service.ts @@ -9,6 +9,7 @@ import { environment } from 'src/environments/environment'; const AUTH_API = environment.smartharvesterUrl + '/harvester/auth'; +const FDP_URL = environment.fdpUrl; const httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/json' }) }; @@ -53,7 +54,7 @@ export class AuthService { getF2DSAuthToken(credentials): Observable<any> { - return this.http.post(this.appConfig.fdpurl + '/tokens', { + return this.http.post(FDP_URL + '/tokens', { email: credentials.email, password: credentials.password }, httpOptions); diff --git a/src/app/dashboard/dashboard.component.ts b/src/app/dashboard/dashboard.component.ts index 83fdcceab..2dab938b9 100644 --- a/src/app/dashboard/dashboard.component.ts +++ b/src/app/dashboard/dashboard.component.ts @@ -52,7 +52,7 @@ export class DashboardComponent implements OnInit { link: '/dashboard/simplesearch', pathMatch: 'full' }, - { + /*{ title: 'Settings', icon: 'options-2-outline', children: [ @@ -67,7 +67,7 @@ export class DashboardComponent implements OnInit { pathMatch: 'full' } ], - }, + },*/ ]; constructor(private readonly sidebarService: NbSidebarService, diff --git a/src/app/datasets/datasets.component.ts b/src/app/datasets/datasets.component.ts index e823b558e..e57dc1e1b 100644 --- a/src/app/datasets/datasets.component.ts +++ b/src/app/datasets/datasets.component.ts @@ -4,6 +4,7 @@ import { DatasetCrudService } from './services/dataset-crud.service'; import { OpenApi } from '../publishapi/class/openapi'; import { ParameterType } from '../publishapi/class/openapi-enum'; import { OpenApiTag } from '../publishapi/class/openapi-dto'; +import { environment } from 'src/environments/environment.prod'; interface RequestInfo { value?: string; @@ -26,6 +27,7 @@ export class DatasetsComponent implements OnInit { values = new Map<string, Map<string, Map<string, RequestInfo>>>(); previews = new Map<string, any>(); spinners = new Map<string, boolean>(); + FDP_URL = environment.fdpUrl; @@ -300,8 +302,8 @@ export class DatasetsComponent implements OnInit { data = '\@prefix dcat: <http://www.w3.org/ns/dcat#>.\n\ @prefix dct: <http://purl.org/dc/terms/>.\n\ @prefix language: <http://id.loc.gov/vocabulary/iso639-1/>.\n\ - @prefix s: <'+ this.appConfig.fdpurl + '/>.\n\ - @prefix c: <'+ this.appConfig.fdpurl + '/catalog/>.\n\ + @prefix s: <'+ this.FDP_URL + '/>.\n\ + @prefix c: <'+ this.FDP_URL+ '/catalog/>.\n\ s:new\n\ a dcat:Dataset, dcat:Resource;\n\ dct:description ' + description + ';\n\ diff --git a/src/app/datasets/services/dataset-crud.service.ts b/src/app/datasets/services/dataset-crud.service.ts index cafd63ee3..f894912d4 100644 --- a/src/app/datasets/services/dataset-crud.service.ts +++ b/src/app/datasets/services/dataset-crud.service.ts @@ -3,9 +3,10 @@ import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { AppConfiguration } from 'src/app/AppConfiguration'; import { TokenStorageService } from 'src/app/authentication/services/token-storage.service'; +import { environment } from 'src/environments/environment.prod'; import { ParseXmlService } from '../../services/parse-xml.service'; - +const FDP_URL = environment.fdpUrl; @Injectable({ providedIn: 'root' }) @@ -26,7 +27,7 @@ export class DatasetCrudService { }) }; - this.http.post(this.appConfig.fdpurl+"/dataset", data, httpOptions ).subscribe( r => { + this.http.post(FDP_URL +"/dataset", data, httpOptions ).subscribe( r => { console.log("resultat: " + JSON.stringify(r)); }, error => console.error("The repository has not been published: " + error) , @@ -50,7 +51,7 @@ export class DatasetCrudService { }) }; - let resultat = this.http.post(this.appConfig.fdpurl+"/distribution", data, httpOptions ).subscribe((r)=>{ + let resultat = this.http.post(FDP_URL +"/distribution", data, httpOptions ).subscribe((r)=>{ console.log('reponse: ', r); return JSON.stringify(resultat); }) ; diff --git a/src/app/mapping/mapping.component.ts b/src/app/mapping/mapping.component.ts index 27239c7d3..511a8a756 100644 --- a/src/app/mapping/mapping.component.ts +++ b/src/app/mapping/mapping.component.ts @@ -2,6 +2,7 @@ import { Component, Input, OnInit, ViewChild } from '@angular/core'; import { Observable, of } from 'rxjs'; import { map } from 'rxjs/operators'; +import { environment } from 'src/environments/environment.prod'; import { AppConfiguration } from '../AppConfiguration'; import { DatasetCrudService } from '../datasets/services/dataset-crud.service'; import { Dataset } from './class/Dataset'; @@ -26,6 +27,7 @@ export class MappingComponent implements OnInit { index: number = 0 first: boolean = true; loading: boolean = false; + FDP_URL = environment.fdpUrl; @ViewChild('autoInput') input; @Input() catalogId: any; @@ -92,8 +94,8 @@ publishDataset() { data = '\@prefix dcat: <http://www.w3.org/ns/dcat#>.\n\ @prefix dct: <http://purl.org/dc/terms/>.\n\ @prefix language: <http://id.loc.gov/vocabulary/iso639-1/>.\n\ - @prefix s: <'+ this.appConfig.fdpurl + '/>.\n\ - @prefix c: <'+ this.appConfig.fdpurl + '/catalog/>.\n\ + @prefix s: <'+ this.FDP_URL + '/>.\n\ + @prefix c: <'+ this.FDP_URL + '/catalog/>.\n\ \n\ s:new\n\ a dcat:Dataset, dcat:Resource;\n\ diff --git a/src/app/repository/repository.component.ts b/src/app/repository/repository.component.ts index 00a7335ae..425df4800 100644 --- a/src/app/repository/repository.component.ts +++ b/src/app/repository/repository.component.ts @@ -22,6 +22,7 @@ export class RepositoryComponent implements OnInit { public importFile: File; public resultat: any; public persistentUrl: string; + FDP_URL = environment.fdpUrl; Form = new FormGroup({ repotype: new FormControl(), @@ -115,7 +116,7 @@ repository:\n\ @prefix dct: <http://purl.org/dc/terms/>.\n\ @prefix foaf: <http://xmlns.com/foaf/0.1/> .\n\ @prefix lang: <http://id.loc.gov/vocabulary/iso639-1/>. \n\ -@prefix fdp: <'+ this.appConfig.fdpurl + '/>.\n\nfdp:new \n\ +@prefix fdp: <'+ this.FDP_URL + '/>.\n\nfdp:new \n\ a dcat:Catalog, dcat:Resource;\n\ dct:description "'+ this.Form.value.repodescription + '";\n\ dct:hasVersion "'+ this.Form.value.repoversion + '";\n\ diff --git a/src/app/repository/services/publish-repository.service.ts b/src/app/repository/services/publish-repository.service.ts index 913909bbc..934455262 100644 --- a/src/app/repository/services/publish-repository.service.ts +++ b/src/app/repository/services/publish-repository.service.ts @@ -10,7 +10,7 @@ interface PersistentUrlResponse { persistentUrl: string; } - +const FDP_URL = environment.fdpUrl; @Injectable({ providedIn: 'root' }) @@ -38,7 +38,7 @@ export class PublishRepositoryService { myHeaders.append('Authorization', 'Bearer ' + this.fds2Token); const myInit = { method: 'POST', body: data, headers: myHeaders }; - const myRequest = new Request(this.appConfig.fdpurl + "/catalog", myInit); + const myRequest = new Request(FDP_URL + "/catalog", myInit); fetch(myRequest, myInit) .then(response => { diff --git a/src/app/services/catalog.service.ts b/src/app/services/catalog.service.ts index e90209f39..f839c4026 100644 --- a/src/app/services/catalog.service.ts +++ b/src/app/services/catalog.service.ts @@ -17,6 +17,8 @@ export interface FdpApiResponseItem { context: string } +const FDP_URL = environment.fdpUrl; + @Injectable({ providedIn: 'root' }) @@ -49,6 +51,6 @@ export class CatalogService { } getCatalogContentById(catId: string) { - return this.http.get<FdpApiResponseItem[]>(this.appConfig.fdpurl + '/catalog/' + catId, this.httpOptionsFDP); + return this.http.get<FdpApiResponseItem[]>(FDP_URL + '/catalog/' + catId, this.httpOptionsFDP); } } -- GitLab From 91adbfb57422bdaef6429110c1ea7eb590ac8d79 Mon Sep 17 00:00:00 2001 From: Baptiste Toulemonde <toulemonde@cines.fr> Date: Fri, 16 Jul 2021 10:18:42 +0200 Subject: [PATCH 17/18] remove step 4 --- src/app/publishapi/publishapi.component.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/publishapi/publishapi.component.html b/src/app/publishapi/publishapi.component.html index 693ef4e73..1640975f8 100644 --- a/src/app/publishapi/publishapi.component.html +++ b/src/app/publishapi/publishapi.component.html @@ -302,9 +302,9 @@ </p> <app-mapping *ngIf="initLabelThree" [catalogId]="openApi.info['x-catalog-id']"></app-mapping> <button class="prev-button" nbButton nbStepperPrevious (click)="initLabelThree = false">prev</button> - <button class="next-button" nbButton nbStepperNext>next</button> + <button class="next-button" nbButton disabled nbStepperNext>next</button> </nb-step> - <nb-step [label]="labelFour"> + <!--<nb-step [label]="labelFour"> <ng-template #labelFour>Fourth step</ng-template> <h4>Populate FDP</h4> <p class="lorem"> @@ -312,7 +312,7 @@ </p> <button class="prev-button" nbButton nbStepperPrevious>prev</button> <button class="next-button" nbButton disabled nbStepperNext>next</button> - </nb-step> + </nb-step>--> </nb-stepper> </nb-card-body> </nb-card> -- GitLab From d5d134c7daab520f18dfedebf5060dc82f448b1c Mon Sep 17 00:00:00 2001 From: Baptiste Toulemonde <toulemonde@cines.fr> Date: Fri, 16 Jul 2021 13:50:05 +0200 Subject: [PATCH 18/18] mapping: delete dataset --- src/app/mapping/mapping.component.html | 40 ++++++++++++++------------ src/app/mapping/mapping.component.scss | 7 ++++- src/app/mapping/mapping.component.ts | 7 +++-- 3 files changed, 32 insertions(+), 22 deletions(-) diff --git a/src/app/mapping/mapping.component.html b/src/app/mapping/mapping.component.html index 0ad1f4190..cd2e7483b 100644 --- a/src/app/mapping/mapping.component.html +++ b/src/app/mapping/mapping.component.html @@ -1,9 +1,7 @@ <div class="card-row"> <div class="card-col"> - <nb-card size="giant" [nbSpinner]="loading" - nbSpinnerStatus="primary" - nbSpinnerSize="large" - nbSpinnerMessage="Loading..."> + <nb-card size="giant" [nbSpinner]="loading" nbSpinnerStatus="primary" nbSpinnerSize="large" + nbSpinnerMessage="Loading..."> <nb-card-header>Dataset metadata</nb-card-header> <nb-card-body> <div></div> @@ -53,31 +51,35 @@ </div> <div class="card-row"> <div class="card-col"> - <nb-card > + <nb-card> <nb-card-header>Map</nb-card-header> <nb-card-body> <nb-list> - - <nb-list-item *ngFor="let data of mappedMetadatas[index] | keyvalue "> - <div class="row"> - <div class="col-5">{{data.key}} : </div> - <div class="col-5">{{data.value}}</div> - <div class="col-2"><button nbButton ghost> - <nb-icon icon="trash-2-outline" status="danger" (click)="deleteProperty(data.key)"> - </nb-icon> - </button></div> - </div> - </nb-list-item> - - </nb-list> + <nb-list-item *ngFor="let data of mappedMetadatas[index] | keyvalue; trackBy:trackByIndex; "> + <div class="row"> + <div class="col-5"><label for="{{data.key}}">{{data.key}}</label></div> + <div class="col-5"> <input nbInput autofocus [ngModel]="data.value" + (ngModelChange)="mappedMetadatas[index].set(data.key, $event)" /> </div> + <div class="col-2"><button nbButton ghost> + <nb-icon icon="trash-2-outline" status="danger" (click)="deleteProperty(data.key)"> + </nb-icon> + </button></div> + </div> + </nb-list-item> + + </nb-list> + <div class="row"> + <button class="button-center" nbButton status="danger" (click)="mappedMetadatas.splice(index, 1); prev()">Delete datset<nb-icon icon="trash-2-outline"> + </nb-icon></button> + </div> </nb-card-body> <nb-card-footer> <div class="row"> <div *ngIf=" !first "> <button nbButton (click)=" prev()" [disabled]="index == 0">prev</button> </div> - + <div *ngIf="!first "> <button nbButton (click)=" next()" [disabled]="index == mappedMetadatas.length -1">next</button> </div> diff --git a/src/app/mapping/mapping.component.scss b/src/app/mapping/mapping.component.scss index 4c11d8514..9a0e26439 100644 --- a/src/app/mapping/mapping.component.scss +++ b/src/app/mapping/mapping.component.scss @@ -18,7 +18,7 @@ .col-5 { width: 45%; - + vertical-align: middle; margin-right: 10px; align-items: stretch; } @@ -48,4 +48,9 @@ input-basic-disabled-text-color { color: black; + } + + .button-center{ + vertical-align: middle; + margin: auto } \ No newline at end of file diff --git a/src/app/mapping/mapping.component.ts b/src/app/mapping/mapping.component.ts index 511a8a756..3d3c947af 100644 --- a/src/app/mapping/mapping.component.ts +++ b/src/app/mapping/mapping.component.ts @@ -102,7 +102,7 @@ a dcat:Dataset, dcat:Resource;\n\ dct:isPartOf c:'+ this.catalogId + ';\n' + properties + '.'; console.log('data: ' + data); - this.dataSetService.createDataSet(data); + //this.dataSetService.createDataSet(data); }) } @@ -145,7 +145,10 @@ dct:isPartOf c:'+ this.catalogId + ';\n' + properties + '.'; } } prev() { - this.index -= 1; + if(this.index > 0){ + this.index -= 1; + } + this.createDataset(this.itemsdataset[this.index]) console.log('index = ' + this.index); } -- GitLab