diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 8c31ce0ad70293d0dd58be3433d856f744407754..c40405f3e423aa84402c07145aee5800dc9b0c8d 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -36,12 +36,13 @@ 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, NbListModule, NbAccordionModule } from '@nebular/theme'; +import { NbLayoutModule, NbThemeModule, NbTooltipModule, NbSpinnerModule, NbSelectModule, NbTabsetModule, NbAutocompleteModule, NbListModule, NbAccordionModule, NbDialogModule } from '@nebular/theme'; import { DashboardComponent } from './dashboard/dashboard.component'; +import { FeedbackDialogComponent } from './mapping/dialog/feedback-dialog/feedback-dialog.component'; import { NbToastrModule } from '@nebular/theme'; import { DatasetsDialogComponent } from './datasets/datasets-dialog/datasets-dialog.component'; -import { NbDialogModule } from '@nebular/theme'; + @@ -61,6 +62,7 @@ import { NbDialogModule } from '@nebular/theme'; StatsComponent, DashboardComponent, MappingComponent, + FeedbackDialogComponent, DatasetsDialogComponent, ], imports: [ @@ -94,7 +96,7 @@ import { NbDialogModule } from '@nebular/theme'; NbToastrModule.forRoot(), NbDialogModule.forRoot(), ], - entryComponents: [DatasetsDialogComponent], + entryComponents: [DatasetsDialogComponent, FeedbackDialogComponent], providers: [ AppConfiguration, ParseXmlService, diff --git a/src/app/datasets/datasets.component.ts b/src/app/datasets/datasets.component.ts index f80db3dc76d9ea9eb84f546c6fb3d98a77aefcaf..a3990d466ffe18016f8deab25a6d77b004d6b5e8 100644 --- a/src/app/datasets/datasets.component.ts +++ b/src/app/datasets/datasets.component.ts @@ -56,7 +56,7 @@ export class DatasetsComponent implements OnInit, OnChanges { } ngOnInit() { - this.dataSetService.itemsDataset = []; + this.dataSetService.resetDataset() } @@ -227,7 +227,7 @@ export class DatasetsComponent implements OnInit, OnChanges { continue; } - return content.example.split(':'); + return content.example.split('#'); } } } @@ -315,7 +315,7 @@ export class DatasetsComponent implements OnInit, OnChanges { for (const id of datasetId) { const requestPromise = this.launchRequest(datasetRequestPathName, datasetRequestHttpMethod, false, id) .then((dataset) => { - this.dataSetService.saveDatasets(dataset); + this.dataSetService.saveDatasets(dataset, id); }); requestPromises.push(requestPromise); } diff --git a/src/app/datasets/services/dataset-crud.service.ts b/src/app/datasets/services/dataset-crud.service.ts index 0199c6eb7dbbf31601e1136f9456867983a54341..73ba27ffa86b80dace78a65732911ec4e2bacce9 100644 --- a/src/app/datasets/services/dataset-crud.service.ts +++ b/src/app/datasets/services/dataset-crud.service.ts @@ -15,20 +15,22 @@ export class DatasetCrudService { fds2Token: string = this.sessionStorage.getFDPToken(); public results: string[] = []; itemsDataset: Object[] = []; + ids: number[] = []; constructor(private http: HttpClient, private appConfig: AppConfiguration, private parserService: ParseXmlService, private sessionStorage: TokenStorageService) { } - createDataset(data: string): Observable<any> { + async createDataset(data: string): Promise<any> { if (this.fds2Token) { - const httpOptions = { - headers: new HttpHeaders({ - 'Accept': 'text/turtle', - 'Content-Type': 'text/turtle', - 'Authorization': 'Bearer ' + this.fds2Token - }) - }; + const httpOptions = new Headers(); + httpOptions.append( 'Accept', 'text/turtle'); + httpOptions.append('Content-Type', 'text/turtle'); + httpOptions.append('Authorization', 'Bearer '+ this.fds2Token ); + + + const myInit = { method: 'POST', body: data , headers: httpOptions }; + const myRequest = new Request(`${FDP_URL}/dataset`, myInit); - return this.http.post(FDP_URL + "/dataset", data, httpOptions); + return fetch(myRequest, myInit) } } @@ -104,12 +106,16 @@ export class DatasetCrudService { getLocally<T = any>(path: string): Observable<T> { return this.http.get<T>(`${path}`); } - saveDatasets(obj: Object) { + saveDatasets(obj: Object, id: number) { this.itemsDataset.push(obj); + this.ids.push(id); } resetDataset() { this.itemsDataset = []; + this.ids = []; } + + } diff --git a/src/app/mapping/class/dataset.ts b/src/app/mapping/class/dataset.ts index 67c5bf82c9ee1bbffdda75b945d198c5e9f931a0..d4f2f6499b23d8608265d2e3ea7a7ce25e098516 100644 --- a/src/app/mapping/class/dataset.ts +++ b/src/app/mapping/class/dataset.ts @@ -4,4 +4,14 @@ export class Dataset { public usageNote: string; } +export class DatasetPath { + public dcatProperty: string; + public path: string + + constructor(dcatProperty: string, path: string) { + this.dcatProperty = dcatProperty; + this.path = path; + } +} + diff --git a/src/app/mapping/dialog/feedback-dialog/feedback-dialog.component.html b/src/app/mapping/dialog/feedback-dialog/feedback-dialog.component.html new file mode 100644 index 0000000000000000000000000000000000000000..176c0ca3ffd9bc21f19f36bfdef1cdf3c68d7aad --- /dev/null +++ b/src/app/mapping/dialog/feedback-dialog/feedback-dialog.component.html @@ -0,0 +1,30 @@ +<nb-card [size]="'medium'"> + <nb-card-header> + <h3 style="text-align: center;">Feedback: </h3> + </nb-card-header> + <nb-card-body> + <nb-card > + <nb-card-body> + <p class="error" *ngIf="data.notPostedMetadatas.length > 0">An error occurred while publishing the following Datasets: </p> + <ul class="error" *ngFor="let data of data.notPostedMetadatas"> + <li class="error">{{ data }}</li> + </ul> + </nb-card-body> + </nb-card> + <nb-card> + <nb-card-body> + <p class="success" *ngIf="data.postedMetadatas.length > 0">The following datasets have been published successfully: </p> + <ul *ngFor="let data of data.postedMetadatas"> + <li class="success" >{{ data }}</li> + </ul> + </nb-card-body> + </nb-card> + </nb-card-body> + <nb-card-footer> + <div class="row"> + <div class="button-center"> + <button nbButton status="primary" (click)="close()">Close</button> + </div> + </div> + </nb-card-footer> +</nb-card> \ No newline at end of file diff --git a/src/app/mapping/dialog/feedback-dialog/feedback-dialog.component.scss b/src/app/mapping/dialog/feedback-dialog/feedback-dialog.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..ee702541104cc5b078a21109158390c37dbe8e6d --- /dev/null +++ b/src/app/mapping/dialog/feedback-dialog/feedback-dialog.component.scss @@ -0,0 +1,8 @@ +.error { + color: crimson; +} + +.success { + color: forestgreen; +} + diff --git a/src/app/mapping/dialog/feedback-dialog/feedback-dialog.component.spec.ts b/src/app/mapping/dialog/feedback-dialog/feedback-dialog.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..a1639307eb8688facec2c3cbae846b028965fd97 --- /dev/null +++ b/src/app/mapping/dialog/feedback-dialog/feedback-dialog.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { FeedbackDialogComponent } from './feedback-dialog.component'; + +describe('FeedbackDialogComponent', () => { + let component: FeedbackDialogComponent; + let fixture: ComponentFixture<FeedbackDialogComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ FeedbackDialogComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(FeedbackDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/mapping/dialog/feedback-dialog/feedback-dialog.component.ts b/src/app/mapping/dialog/feedback-dialog/feedback-dialog.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..0cde1a03f9bf127e8a762746a1e417bdc0aef548 --- /dev/null +++ b/src/app/mapping/dialog/feedback-dialog/feedback-dialog.component.ts @@ -0,0 +1,24 @@ +import { Component, Inject, OnInit } from '@angular/core'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { NbDialogRef } from '@nebular/theme'; + +@Component({ + selector: 'app-feedback-dialog', + templateUrl: './feedback-dialog.component.html', + styleUrls: ['./feedback-dialog.component.scss'] +}) +export class FeedbackDialogComponent implements OnInit { + + + + constructor(private dialog: MatDialogRef<FeedbackDialogComponent>, + @Inject(MAT_DIALOG_DATA) public data: {postedMetadatas: string[], notPostedMetadatas: string[]} ) { } + + ngOnInit(): void { + } + + close() { + this.dialog.close(); + } + +} diff --git a/src/app/mapping/mapping.component.html b/src/app/mapping/mapping.component.html index b9235c6fccde0b333264266b9b92b9b7b7c8a75e..06db8c7672e015667c7aac231b4bc261b49b5bdf 100644 --- a/src/app/mapping/mapping.component.html +++ b/src/app/mapping/mapping.component.html @@ -1,10 +1,17 @@ <form #form="ngForm"> <div class="card-row"> <div class="card-col"> - <nb-card size="giant" [nbSpinner]="loading" nbSpinnerStatus="primary" nbSpinnerSize="large" - nbSpinnerMessage="Loading..."> + <nb-card size="giant"> <nb-card-header>Dataset metadata</nb-card-header> <nb-card-body> + <div class="row"> + <p>Upload Or fill out the form with the path corresponding to the dcat property and save a new + file for next mappings:</p> + <button class="button-center" nbButton status="primary" (click)="openFileInputDialog()"> + <nb-icon icon="upload-outline"></nb-icon>Import file + </button> + <input type="file" id="file" (change)="importJson($event)" accept=".json" /> + </div> <ng-container *ngFor="let dataset of datasetModel; let index = index;trackBy:trackByIndex;"> <nb-form-field> @@ -35,7 +42,7 @@ required #autoInput #{{dataset.identifier}}="ngModel" fullWidth id="{{dataset.identifier}}" name="{{dataset.identifier}}" nbInput (input)="onChange()" placeholder="Enter value" [nbAutocomplete]="auto" - [(ngModel)]="selectedPaths[index]" (focus)="reset()" /> + [(ngModel)]="selectedPaths[index]" autocomplete="false" (focus)="reset()" /> <div *ngIf="dataset.identifier.invalid && (dataset.identifier.dirty || dataset.identifier.touched)"> champ obligatoire</div> @@ -44,7 +51,7 @@ #autoInput #{{dataset.identifier}}="ngModel" fullWidth id="{{dataset.identifier}}" name="{{dataset.identifier}}" nbInput (input)="onChange()" placeholder="Enter value" [nbAutocomplete]="auto" - [(ngModel)]="selectedPaths[index]" (focus)="reset()" /> + [(ngModel)]="selectedPaths[index]" autocomplete="false" (focus)="reset()" /> <nb-autocomplete #auto> @@ -64,6 +71,9 @@ </nb-card> </div> </div> + <div class="row"> + <button class="button-center" nbButton status="primary" (click)="downloadJson()">Save locally</button> + </div> <div class="row"> <button class="button-center" nbButton status="primary" (click)="mapDataset()" [disabled]="!form.valid">Check mapping</button> @@ -71,7 +81,7 @@ </form> <div class="card-row"> <div class="card-col"> - <nb-card [nbSpinner]="loading" nbSpinnerStatus="primary" nbSpinnerSize="large" nbSpinnerMessage="loading"> + <nb-card [nbSpinner]="loadingCr" nbSpinnerStatus="primary" nbSpinnerSize="giant" nbSpinnerMessage="loading"> <nb-card-header>Map</nb-card-header> <nb-card-body> <nb-list> @@ -79,7 +89,7 @@ <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" + <div class="col-5"> <input nbInput [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)"> @@ -108,11 +118,10 @@ </div> <div class="row"> <div class="button-center" *ngIf="!first "> - <button nbButton status="primary" (click)=" publishDataset()">Publish</button> + <button nbButton status="primary" (click)=" publishDataset()" [nbSpinner]="loading" + nbSpinnerStatus="basic">Publish</button> </div> </div> - <nb-alert status="success" *ngIf="messageOk" closable style="margin-top: 10px;">{{ messageOk }} - </nb-alert> </nb-card-footer> </nb-card> diff --git a/src/app/mapping/mapping.component.scss b/src/app/mapping/mapping.component.scss index 9a0e2643936659799adea87b351a84d6e9554564..289b1adb30bc1c8f8318a28430e4f59d1f7a397b 100644 --- a/src/app/mapping/mapping.component.scss +++ b/src/app/mapping/mapping.component.scss @@ -7,7 +7,8 @@ .row { display: flex; flex: 1 0 calc(100%); - margin: 0 -0.5rem; + margin: 5px -0.5rem; + } .card-col { @@ -53,4 +54,9 @@ .button-center{ vertical-align: middle; margin: auto - } \ No newline at end of file + } + + #file { + display: none; + } + diff --git a/src/app/mapping/mapping.component.ts b/src/app/mapping/mapping.component.ts index 9c09a0918c31c30819be9397dc0dc99a9c497e90..5e76bf221cb38851c10b5103764d39485a77386a 100644 --- a/src/app/mapping/mapping.component.ts +++ b/src/app/mapping/mapping.component.ts @@ -1,11 +1,18 @@ + +import { HttpResponse } from '@angular/common/http'; import { Component, Input, OnInit, ViewChild } from '@angular/core'; -import { Observable, of } from 'rxjs'; +import { MatDialog } from '@angular/material/dialog'; +import { Router } from '@angular/router'; +import { FileSaverService } from 'ngx-filesaver'; + +import { Observable, of, Subscription } from 'rxjs'; import { map } from 'rxjs/operators'; import { environment } from 'src/environments/environment.prod'; import { DatasetCrudService } from '../datasets/services/dataset-crud.service'; -import { ParseXmlService } from '../services/parse-xml.service'; -import { Dataset } from './class/dataset'; + +import { Dataset, DatasetPath } from './class/dataset'; +import { FeedbackDialogComponent } from './dialog/feedback-dialog/feedback-dialog.component'; @Component({ @@ -27,13 +34,14 @@ export class MappingComponent implements OnInit { index: number = 0 first: boolean = true; loading: boolean = false; + loadingCr = false; FDP_URL = environment.fdpUrl; - messageOk: string; + ids: number[]; @ViewChild('autoInput') input; @Input() catalogId: any; - constructor(private dataSetService: DatasetCrudService, private parserService: ParseXmlService) { } + constructor(private dataSetService: DatasetCrudService, private dialog: MatDialog, private route: Router, private fileSaverService: FileSaverService) { } ngOnInit() { this.dataSetService.getLocally('./assets/dataset.json').subscribe( @@ -54,14 +62,12 @@ export class MappingComponent implements OnInit { populatecatalogue() { this.itemsdataset = this.dataSetService.itemsDataset; + this.ids = this.dataSetService.ids; + this.ids 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)); - } - } + this.getKeysFromMetadata(this.itemsdataset[0], ''); + this.keysMap.set(this.itemsdataset.length, this.keys); + this.filteredOptions = of(this.keysMap.get(1)); } createDataset(item: Object): Map<string, string> { @@ -72,18 +78,21 @@ export class MappingComponent implements OnInit { mappedMetadata.set(this.datasetModel[i].identifier, this.getValue(tab, item)); } } + this.loadingCr = false; return mappedMetadata; } publishDataset() { let data: string = ''; let properties: string = ''; - let result = ''; - + let postedDatastes = []; + let notPostedDatasets = []; + this.loading = true; + const requestPromises: Promise<any>[] = []; for (let i = 0; i < this.mappedMetadatas.length; i++) { + let title = ""; properties = ""; - this.messageOk = ""; this.mappedMetadatas[i].forEach((value: string, key: string) => { if (key === 'dct:title') { title = value }; switch (key) { @@ -96,6 +105,9 @@ export class MappingComponent implements OnInit { case 'dcat:contactPoint': properties += key + ' <' + value + '>;\n'; break; + case 'dct:language': + properties += key + ' <' + value + '>;\n'; + break; default: properties += key + ' "' + value + '";\n'; break; @@ -112,29 +124,65 @@ export class MappingComponent implements OnInit { a dcat:Dataset, dcat:Resource;\n\ dct:isPartOf c:'+ this.catalogId + ';\n' + properties + '.'; - let query = 'query=PREFIX dcat: <http://www.w3.org/ns/dcat#>\n\ + /*let query = 'query=PREFIX dcat: <http://www.w3.org/ns/dcat#>\n\ PREFIX dct: <http://purl.org/dc/terms/>\n\ SELECT ?dataset\n\ where {\n\ ?dataset a dcat:Dataset;\n\ dct:title "' + title + '" ;\n\ - dct:isPartOf <https://f2ds.eosc-pillar.eu/catalog/' + this.catalogId + '>. } ' - - console.log('data: ' + data); - - this.dataSetService.createDataset(data).subscribe( - r => { - console.log(r); - this.loading = true; - }, - () => { - this.messageOk = "Dataset published successfully" - this.loading = false; + dct:isPartOf <https://f2ds.eosc-pillar.eu/catalog/' + this.catalogId + '>. } '*/ + + + let requestPromise = this.dataSetService.createDataset(data).then((resp: HttpResponse<any>) => { + if (resp.status.toString().startsWith('2')) { + postedDatastes.push(this.ids[i]); + } else { + notPostedDatasets.push(this.ids[i]); } - ) + }) + requestPromises.push(requestPromise); } + Promise.all(requestPromises).finally(() => { + this.loading = false; + this.dialog.open(FeedbackDialogComponent, { + data: { + postedMetadatas: postedDatastes, + notPostedMetadatas: notPostedDatasets + } + }).afterClosed().subscribe(() => this.route.navigateByUrl('/dashboard')); + + }) } + /* function to get recursively all the keys and values from the JSON object */ + 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)); + } else { + this.keys.push(keyParent + ' : ' + key + ' : ' + obj[key].indexOf(e)) + } + }); + } else { + if (keyParent) { + this.getKeysFromMetadata(obj[key], keyParent + ' : ' + key); + } else { + this.getKeysFromMetadata(obj[key], key); + } + } + } else { + if (keyParent) { + this.keys.push(keyParent + ' : ' + key) + } else { + this.keys.push(key) + } + } + }); + } private getValue(tab: string[], item: Object): string { let obj: Object @@ -147,24 +195,52 @@ export class MappingComponent implements OnInit { } else if (i < tab.length - 1 && obj[tab[i]]) { obj = obj[tab[i]]; } else { - if (obj[tab[i]]) { + if (obj[tab[i]] && typeof obj[tab[i]] !== 'object') { return obj[tab[i]]; } else { - return 'undefined'; + if (i == tab.length - 2) { + this.getKeysFromMetadata(item, ""); + console.log(tab[i] + " " + i) + this.keys.forEach(k => { + let table = k.split(" : "); + if (table[table.length - 2] === tab[i]) { + for (let i = 0; i < tab.length; i++) { + if (table.length == 1) { + return item[tab[0]]; + } else { + if (i == 0) { + obj = item[table[i]] + } else if (i < table.length - 1 && obj[table[i]]) { + obj = obj[table[i]]; + } else { + if (obj[table[i]] && typeof obj[tab[i]] !== 'object') { + return obj[table[i]]; + } else { + return 'undefined'; + } + } + } + } + } + }) + } } } } } } + + mapDataset() { + this.loadingCr = true; this.mappedMetadatas = []; this.itemsdataset.forEach((dataset: Object) => { - this.mappedMetadatas.push(this.createDataset(dataset)) + this.mappedMetadatas.push(this.createDataset(dataset)); }) - console.log(this.mappedMetadatas) - this.first = false; - } + console.log(this.mappedMetadatas); + this.first = false; } next() { + this.loadingCr = true; if (this.index < this.itemsdataset.length) { this.index += 1; this.createDataset(this.itemsdataset[this.index]) @@ -172,6 +248,7 @@ export class MappingComponent implements OnInit { } } prev() { + this.loadingCr = true; if (this.index > 0) { this.index -= 1; } @@ -179,39 +256,45 @@ export class MappingComponent implements OnInit { console.log('index = ' + this.index); } - // to delete a property of dcat dataset mapped - deleteProperty(key: string) { - this.mappedMetadatas[this.index].delete(key); + downloadJson() { + let datasetPathArray: DatasetPath[] = []; + for (let i = 0; i < this.datasetModel.length; i++){ + if (this.selectedPaths[i]) { + datasetPathArray.push(new DatasetPath(this.datasetModel[i].identifier, this.selectedPaths[i])); + } else { + datasetPathArray.push(new DatasetPath(this.datasetModel[i].identifier, "")); + } + + } + + const fileName = 'paths.json'; + const fileType = this.fileSaverService.genType(fileName); + const txtBlob = new Blob([(JSON.stringify(datasetPathArray)).toString()], {type: fileName}); + this.fileSaverService.save(txtBlob, fileName); } - /* function to get recursively all the keys and values from the JSON object */ - getKeysFromMetadata(obj: Object, keyParent: string) { + openFileInputDialog(): void { + document.getElementById('file').click(); + } - 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)); - } else { - this.keys.push(keyParent + ' : ' + key + ' : ' + obj[key].indexOf(e)) - } - }); - } else { - if (keyParent) { - this.getKeysFromMetadata(obj[key], keyParent + ' : ' + key); - } else { - this.getKeysFromMetadata(obj[key], key); - } - } - } else { - if (keyParent) { - this.keys.push(keyParent + ' : ' + key) - } else { - this.keys.push(key) - } - } - }); + importJson(event: Event) { + const files: FileList = (event.target as HTMLInputElement).files; + const jsonFile = files[0]; + console.log(jsonFile) + let reader = new FileReader(); + let datasetPath: DatasetPath[] = []; + reader.onloadend = () => { + + datasetPath = <DatasetPath[]> JSON.parse(reader.result as string); + datasetPath.forEach(e => { + this.selectedPaths[datasetPath.indexOf(e)] = e.path; + }) + } + reader.readAsText(jsonFile); + } + // to delete a property of dcat dataset mapped + deleteProperty(key: string) { + this.mappedMetadatas[this.index].delete(key); } trackByIndex(index: number, obj: any): any { diff --git a/src/app/publishapi/publishapi.component.html b/src/app/publishapi/publishapi.component.html index 1dbd5fd3c6eb77be97e4e91653e7305e5be2915f..0faee30e90e69dcf393c3644eae036efddf1809b 100644 --- a/src/app/publishapi/publishapi.component.html +++ b/src/app/publishapi/publishapi.component.html @@ -161,25 +161,36 @@ <tbody> <tr *ngFor="let parameter of request.parameters"> <td> - <input [(ngModel)]="parameter.name" nbInput /> + <nb-form-field> + <nb-icon *ngIf="parameter.required" nbSuffix + icon="question-mark-circle-outline" pack="eva" + nbTooltip="Dataset id (Required parameter)" + nbTooltipPlacement="right"></nb-icon> + <input [(ngModel)]="parameter.name" + [status]="parameter.required ? 'primary' : 'basic'" nbInput /> + </nb-form-field> </td> <td> - <nb-select [(ngModel)]="parameter.in"> + <nb-select [(ngModel)]="parameter.in" + [status]="parameter.required ? 'primary' : 'basic'"> <nb-option *ngFor="let type of parametersTypes" value="{{type}}"> {{type}}</nb-option> </nb-select> </td> <td> - <nb-select [(ngModel)]="parameter.schema.type"> + <nb-select [(ngModel)]="parameter.schema.type" + [status]="parameter.required ? 'primary' : 'basic'"> <nb-option *ngFor="let type of shemaTypes" value="{{type}}">{{type}} </nb-option> </nb-select> </td> <td> - <input name="default" [(ngModel)]="parameter.schema.default" nbInput /> + <input name="default" [(ngModel)]="parameter.schema.default" + [status]="parameter.required ? 'primary' : 'basic'"nbInput /> </td> <td> - <input name="default" [(ngModel)]="parameter.description" nbInput /> + <input name="default" [(ngModel)]="parameter.description" + [status]="parameter.required ? 'primary' : 'basic'" nbInput /> </td> <td> <nb-icon icon="copy-outline" nbTooltip="Duplicate parameter" @@ -239,7 +250,7 @@ <div *ngFor="let content of response.contents"> <nb-form-field> <nb-icon nbSuffix icon="question-mark-circle-outline" pack="eva" - nbTooltip="Example: key1:key2:key3" nbTooltipPlacement="right"> + nbTooltip="Example: key1#key2#key3" nbTooltipPlacement="right"> </nb-icon> <input name="default" [(ngModel)]="content.example" nbInput /> </nb-form-field> diff --git a/src/app/publishapi/publishapi.component.ts b/src/app/publishapi/publishapi.component.ts index 19c5c2714d814da0bddbdb7574052d69b6b20eea..2079ab1d93f284f6d10db23de17262a0fb1e8310 100644 --- a/src/app/publishapi/publishapi.component.ts +++ b/src/app/publishapi/publishapi.component.ts @@ -68,7 +68,7 @@ export class PublishApiComponent implements OnInit { }).catch( (error) => { if (error.status === 404) { - this.catalogService.deleteCatalog(catalog.catId); + this.catalogService.deleteCatalog(catalog.catId).subscribe(); } else { this.catalogList.push({ catId: catalog.catId, title: catalog.catId, server: null }); } @@ -205,7 +205,9 @@ export class PublishApiComponent implements OnInit { } duplicateParameter(request: Request, parameter: Parameter): void { - request.parameters.unshift(cloneDeep(parameter)); + const newParam = cloneDeep(parameter); + newParam.required = false; + request.parameters.unshift(newParam); } deleteParameter(request: Request, parameter: Parameter): void { diff --git a/src/app/repository/repository.component.html b/src/app/repository/repository.component.html index baabf0007c721cda0990fc8d8b7d75e05b9008d6..3a97da5f7ce1352e9af1b28d0faa6e299150f397 100644 --- a/src/app/repository/repository.component.html +++ b/src/app/repository/repository.component.html @@ -1,48 +1,49 @@ +<form [formGroup]="Form"> -<form [formGroup]="Form" > - - <label>Upload and fill form width repository description file: </label><br> - <input type="file" id="repofile" name="repofile " class="btn btn-primary" (change)="yamlToRepository()" ><br> - <label>Or describe your repository and save a new file for publishing in the FDP database:</label><br> + <label>Upload and fill form width repository description file: </label><br> + <input type="file" id="repofile" name="repofile " class="btn btn-primary" (change)="yamlToRepository()"><br> + <label>Or describe your repository and save a new file for publishing in the FDP database:</label><br> <div> - <label>Repository Type</label> - <select class="form-control" formControlName="repotype" required> - <option value="Dataverse">Dataverse</option>> - <option value="Custom">Custom</option>> - </select> + <label>Repository Type*</label> + <nb-select class="form-control" formControlName="repotype" required> + <nb-option value="Dataverse">Dataverse</nb-option> + <nb-option value="Custom">Custom</nb-option> + </nb-select> </div> <div class="form-group"> - <label>Repository Name</label> - <input type="text" class="form-control" formControlName="reponame" required> + <label>Repository Name*</label> + <input nbInput type="text" class="form-control" formControlName="reponame" required> </div> - <div class="form-group"> + <div class="form-group"> <label>Description</label> - <textarea class="form-control" formControlName="repodescription"></textarea> + <textarea nbInput class="form-control" formControlName="repodescription"></textarea> </div> <div class="form-group"> - <label>url</label> - <input type="text" class="form-control" formControlName="repourl" required> + <label>url*</label> + <input nbInput type="text" class="form-control" formControlName="repourl" required> </div> <div class="form-group"> <label>Version</label> - <input type="text" class="form-control" formControlName="repoversion"> - </div> <div class="form-group"> - <label>License</label> - <input type="text" class="form-control" formControlName="repolicence"> -</div> <div class="form-group"> - <label>Language</label> - <input type="text" class="form-control" formControlName="repolanguage"> -</div> + <input nbInput type="text" class="form-control" formControlName="repoversion"> + </div> + <div class="form-group"> + <label>License</label> + <input nbInput type="text" class="form-control" formControlName="repolicence"> + </div> + <div class="form-group"> + <label>Language</label> + <input nbInput type="text" class="form-control" formControlName="repolanguage"> + </div> <div> <br> - <button type="submit" (click)="repositorytoyaml()" class="btn btn-primary">Save repository description file</button> + <button nbButton type="submit" (click)="repositorytoyaml()" class="btn btn-primary">Save repository description file</button> </div> <div> <br> - <button type="submit" (click)="publishCatalog()" class="btn btn-success" [disabled]="!Form.valid">Publish catalog description in FDP</button> + <button nbButton type="submit" (click)="publishCatalog()" class="btn btn-success" [disabled]="!Form.valid">Publish catalog + description in FDP</button> </div> -</form> - +</form> \ No newline at end of file diff --git a/src/app/services/catalog.service.ts b/src/app/services/catalog.service.ts index 729d79ef285729bfc298c348455ae91f78462f3b..6c90a711ad2895820193dbcc2dfb54bd82753f17 100644 --- a/src/app/services/catalog.service.ts +++ b/src/app/services/catalog.service.ts @@ -54,6 +54,6 @@ export class CatalogService { } deleteCatalog(catId: string) { - return this.http.delete(this.smartApiUrl + '/catalog/' + catId, this.httpOptionsSmartHarvester); + return this.http.delete(this.smartApiUrl + '/catalogs/' + catId, this.httpOptionsSmartHarvester); } }