From bf8c57d6dbed22e312b2f72522289e2f86face01 Mon Sep 17 00:00:00 2001 From: jdestin <jeremy.destin@inra.fr> Date: Mon, 25 Feb 2019 09:40:21 +0100 Subject: [PATCH 01/20] style: Change style of the tables on the card. Minor fixes. GNP-5490 --- frontend/src/app/card-row/card-row.component.scss | 2 +- .../src/app/card-section/card-section.component.scss | 12 ++++++------ .../src/app/card-table/card-table.component.scss | 2 +- frontend/src/app/navbar/navbar.component.scss | 1 + frontend/src/assets/gpds/theme.scss | 10 ++++------ 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/frontend/src/app/card-row/card-row.component.scss b/frontend/src/app/card-row/card-row.component.scss index 5f6ecd43..6b1077b8 100644 --- a/frontend/src/app/card-row/card-row.component.scss +++ b/frontend/src/app/card-row/card-row.component.scss @@ -1,5 +1,5 @@ .row-sep { - border-top: 0.01px solid #f0f0f0; + border-top: 1px solid #f0f0f0; } .field { diff --git a/frontend/src/app/card-section/card-section.component.scss b/frontend/src/app/card-section/card-section.component.scss index 155466cf..10c46aaa 100644 --- a/frontend/src/app/card-section/card-section.component.scss +++ b/frontend/src/app/card-section/card-section.component.scss @@ -1,15 +1,15 @@ .card { margin-top: 25px; margin-bottom: 10px; - border-color: rgba(89, 89, 89, 0.33); - border-width: 1.5px; + border-color: rgba(15, 97, 145, 0.25); + border-width: 2px; } .card-header { font-size: large; font-weight: bold; - color: #0f6191; - background-color: #eaeaea; - border-color: rgba(29, 29, 29, 0.16); - border-width: 2.5px; + color: #f5f5f5; + background-color: #0f6191; + border-color: #0f6191; + border-width: 2px; } diff --git a/frontend/src/app/card-table/card-table.component.scss b/frontend/src/app/card-table/card-table.component.scss index f721891f..b5c78f56 100644 --- a/frontend/src/app/card-table/card-table.component.scss +++ b/frontend/src/app/card-table/card-table.component.scss @@ -3,7 +3,7 @@ max-height: 200px; overflow-y: auto; - thead { + thead th { position: sticky; top: 0; background-color: white; diff --git a/frontend/src/app/navbar/navbar.component.scss b/frontend/src/app/navbar/navbar.component.scss index 2a8c98cf..301875fc 100644 --- a/frontend/src/app/navbar/navbar.component.scss +++ b/frontend/src/app/navbar/navbar.component.scss @@ -14,6 +14,7 @@ .navbar .navbar-nav .nav-link, .navbar .navbar-brand { color: $theme-navbar-color; height: $theme-navbar-height; + text-decoration: none; &:hover { color: $theme-navbar-hover-color; diff --git a/frontend/src/assets/gpds/theme.scss b/frontend/src/assets/gpds/theme.scss index 286d878c..535bbace 100644 --- a/frontend/src/assets/gpds/theme.scss +++ b/frontend/src/assets/gpds/theme.scss @@ -29,12 +29,14 @@ $enable-shadows: true; //custom tables .table { - border-bottom: 2px solid #0f6191; - border-top: 2px solid #0f6191; table-layout: fixed; + thead { + background-color: #0f6191; + } } + a.btn.popovers { text-decoration: underline; //overflow: hidden; @@ -62,10 +64,6 @@ h4 { color: #0f6191; } -.table thead { - background-color: #0f6191; -} - .ellipsis { overflow: hidden; text-overflow: ellipsis; -- GitLab From a2a9eb389964bcf3b772f4bc818400db12f7edeb Mon Sep 17 00:00:00 2001 From: jdestin <jeremy.destin@inra.fr> Date: Fri, 1 Mar 2019 16:52:59 +0100 Subject: [PATCH 02/20] fix: Use components (card-section, card-row and card-table) to display elements on germaplasm card and reduce cyclomatic complexity. Fix tests. Minor fixes. GNP-5490 --- frontend/src/app/brapi.service.spec.ts | 10 +- .../src/app/card-row/card-row.component.scss | 4 +- .../germplasm-card.component.html | 1416 ++++++++++------- .../germplasm-card.component.spec.ts | 36 +- .../germplasm-card.component.ts | 58 +- frontend/src/app/gnpis.service.spec.ts | 9 +- .../src/app/models/brapi.germplasm.model.ts | 7 +- .../src/app/models/gnpis.germplasm.model.ts | 33 +- .../app/study-card/study-card.component.scss | 4 - frontend/src/assets/gpds/theme.scss | 1 - frontend/src/styles.scss | 20 + frontend/src/tslint.json | 2 +- 12 files changed, 918 insertions(+), 682 deletions(-) diff --git a/frontend/src/app/brapi.service.spec.ts b/frontend/src/app/brapi.service.spec.ts index aecbcbbe..67d30d57 100644 --- a/frontend/src/app/brapi.service.spec.ts +++ b/frontend/src/app/brapi.service.spec.ts @@ -22,6 +22,7 @@ import { import { Germplasm, GermplasmData, GermplasmResult, Institute, Origin, Site } from './models/gnpis.germplasm.model'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { TestBed } from '@angular/core/testing'; +import { Util } from 'leaflet'; describe('BrapiService', () => { @@ -192,7 +193,7 @@ describe('BrapiService', () => { address: '12', logo: null }; - const origin: Origin = { + const origin: Origin = { ... institute, institute: institute, germplasmPUI: '12', accessionNumber: '12', @@ -206,9 +207,10 @@ describe('BrapiService', () => { const brapiDonor: BrapiDonor = { donorInstitute: institute, - germplasmPUI: '12', - accessionNumber: '12', - donorInstituteCode: 'urgi' + donorGermplasmPUI: '12', + donorAccessionNumber: '12', + donorInstituteCode: 'urgi', + donationDate: null }; const brapiSet: BrapiSet = { diff --git a/frontend/src/app/card-row/card-row.component.scss b/frontend/src/app/card-row/card-row.component.scss index 6b1077b8..3cba0cba 100644 --- a/frontend/src/app/card-row/card-row.component.scss +++ b/frontend/src/app/card-row/card-row.component.scss @@ -1,6 +1,4 @@ -.row-sep { - border-top: 1px solid #f0f0f0; -} +@import '../../styles.scss'; .field { font-weight: bold; diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.html b/frontend/src/app/germplasm-card/germplasm-card.component.html index 7ffb0917..2ad0aaaf 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.html +++ b/frontend/src/app/germplasm-card/germplasm-card.component.html @@ -6,659 +6,837 @@ </h3> <div class="container-fluid"> - <div class="container"> - <div class="row"> - <div class="col-md-auto field" *ngIf="germplasmGnpis.photo && germplasmGnpis.photo.thumbnailFileName != null"> - <figure class="figure"> - <img - src="{{ IMAGES_SIREGAL_URL }}/{{ germplasmGnpis.holdingGenbank.instituteCode }}/{{ germplasmGnpis.photo.thumbnailFileName }}" - class="img-fluid"> - <figcaption class="figure-caption"> - <a class="btn popovers" data-boundary="window" placement="right" [ngbPopover]="imageTemplate" - [popoverTitle]="Details" container="body"> - Click to see more details. - </a> - </figcaption> - </figure> - - <ng-template #imageTemplate> - <div class="card ngb-popover-window "> - <img class="card-img-top" - src="{{ IMAGES_SIREGAL_URL }}/{{ germplasmGnpis.holdingGenbank.instituteCode }}/{{ germplasmGnpis.photo.fileName }}" - alt="" width="500px"> - <div class="card-body"> - <table class="table"> - <tr *ngIf="germplasmGnpis.photo.photoName"> - <th class="fieldName">Name</th> - <td class="field">{{ germplasmGnpis.photo.photoName }}</td> - </tr> - <tr *ngIf="germplasmGnpis.photo.description"> - <th class="fieldName">Description</th> - <td class="field">{{ germplasmGnpis.photo.description }}</td> - </tr> - <tr *ngIf="germplasmGnpis.photo.copyright"> - <th class="fieldName">Copyright</th> - <td class="field">{{ germplasmGnpis.photo.copyright }}</td> - </tr> - </table> - </div> + <div class="row"> + + <!--Section for the image representing the germplasm and the details about this image--> + <div class="col-md-auto field" *ngIf="germplasmGnpis.photo && germplasmGnpis.photo.thumbnailFileName"> + <figure class="figure"> + <img + [src]="IMAGES_SIREGAL_URL +'/' + germplasmGnpis.holdingGenbank.instituteCode + '/' + germplasmGnpis.photo.thumbnailFileName" + class="img-fluid"> + <figcaption class="figure-caption"> + <a class="btn popovers" data-boundary="window" placement="right" [ngbPopover]="imageTemplate" + [popoverTitle]="germplasmGnpis.photo.thumbnailFileName" container="body"> + Click to see more details. + </a> + </figcaption> + </figure> + + <ng-template #imageTemplate> + <div class="card ngb-popover-window "> + <img class="card-img-top" + [src]="IMAGES_SIREGAL_URL + '/' + germplasmGnpis.holdingGenbank.instituteCode + '/' + germplasmGnpis.photo.fileName" + alt="" width="250px"> + <div class="card-body"> + <gpds-card-row + label="Name" + [value]="germplasmGnpis.photo.photoName"> + </gpds-card-row> + + <gpds-card-row + label="Description" + [value]="germplasmGnpis.photo.description"> + </gpds-card-row> + + <gpds-card-row + label="Copyright" + [value]="germplasmGnpis.photo.copyright"> + </gpds-card-row> </div> - </ng-template> + </div> + </ng-template> + </div> - </div> - <div class="col"> - <table class="table table-sm .table-responsive{-sm|-md|-lg|-xl}"> - <thead class="text-white"> - <tr> - <th class="headerTitle" scope="col" colspan="2"> - Identification - </th> - </tr> - </thead> - <tr *ngIf="germplasmGnpis.accessionNumber"> - <th class="fieldName" scope="row">Accession number</th> - <td class="field">{{ germplasmGnpis.accessionNumber }}</td> - </tr> - <tr *ngIf="germplasmGnpis.acquisitionDate"> - <th class="fieldName" scope="row">Acquisition date</th> - <td - class="field">{{ germplasmGnpis.acquisitionDate | amParse:'YYYYMMDD' | amDateFormat:'YYYY-MM-DD' }}</td> - </tr> - <tr *ngIf="germplasmGnpis.germplasmName"> - <th class="fieldName" scope="row">Germplasm name</th> - <td class="field">{{ germplasmGnpis.germplasmName }}</td> - </tr> - <tr *ngIf="germplasmGnpis.germplasmPUI"> - <th class="fieldName" scope="row">Permanent Unique Identifier</th> - <td class="ellipsis field"> {{ germplasmGnpis.germplasmPUI }}</td> - </tr> - <tr *ngIf="germplasmGnpis.seedSource"> - <th class="fieldName" scope="row">Seed source</th> - <td class="field">{{ germplasmGnpis.seedSource }}</td> - </tr> - <tr *ngIf="germplasmGnpis.geneticNature"> - <th class="fieldName" scope="row">Genetic nature</th> - <td class="field">{{ germplasmGnpis.geneticNature }}</td> - </tr> - <tr *ngIf="germplasmGnpis.synonyms && germplasmGnpis.synonyms.length > 0"> - <th class="fieldName" scope="row">Accession synonyms</th> - <td class="field">{{ germplasmGnpis.synonyms.join(', ') }}</td> - </tr> - <tr> - <th class="fieldName" scope="row">Taxon</th> - <td class="field"> + <!--Section for the information about the identification of the germplasm--> + <gpds-card-section + class="col" + header="Identification"> + <ng-template> + <div class="card-body"> + + <gpds-card-row + label="Germplasm name" + [value]="germplasmGnpis.germplasmName"> + </gpds-card-row> + + <gpds-card-row + label="Permanent Unique Identifier" + [value]="germplasmGnpis.germplasmPUI"> + </gpds-card-row> + + <gpds-card-row + label="Accession number" + [value]="germplasmGnpis.accessionNumber"> + </gpds-card-row> + + <gpds-card-row + label="Acquisition date" + [test]="germplasmGnpis.acquisitionDate"> + <ng-template> + {{ germplasmGnpis.acquisitionDate | amParse:'YYYYMMDD' | amDateFormat:'YYYY-MM-DD' }} + </ng-template> + </gpds-card-row> + + <gpds-card-row + label="Seed source" + [value]="germplasmGnpis.seedSource"> + </gpds-card-row> + + <gpds-card-row + label="Genetic nature" + [value]="germplasmGnpis.geneticNature"> + </gpds-card-row> + + <gpds-card-row + label="Accession synonyms" + [test]="germplasmGnpis.synonyms && germplasmGnpis.synonyms.length > 0"> + <ng-template> + {{ germplasmGnpis.synonyms.join(', ') }} + </ng-template> + </gpds-card-row> + + <gpds-card-row + label="Taxon" + [test]="germplasmGnpis.genus || germplasmGnpis.species || germplasmGnpis.subtaxa"> + <ng-template> <i>{{ germplasmGnpis.genus }} {{ germplasmGnpis.species }} {{ germplasmGnpis.subtaxa }}</i> {{ germplasmGnpis.speciesAuthority ? '(' + germplasmGnpis.speciesAuthority + ')' : '' }} - </td> - </tr> + </ng-template> + </gpds-card-row> - <tr *ngIf="germplasmGnpis.taxonCommonNames && germplasmGnpis.taxonCommonNames.length > 0"> - <th class="fieldName" scope="row">Taxon common names</th> - <td class="ellipsis field"> {{ germplasmGnpis.taxonCommonNames.join(', ') }} - </td> - </tr> - <tr *ngIf="germplasmGnpis.taxonSynonyms && germplasmGnpis.taxonSynonyms.length > 0"> - <th class="fieldName" scope="row">Taxon synonyms</th> - <td class="scroll field"><i>{{ germplasmGnpis.taxonSynonyms.join(', ') }}</i></td> - </tr> - <tr *ngIf="germplasmGnpis.pedigree"> - <th class="fieldName" scope="row">Pedigree</th> - <td class="field">{{ germplasmGnpis.pedigree }}</td> - </tr> - <tr *ngIf="germplasmGnpis.biologicalStatusOfAccessionCode"> - <th class="fieldName" scope="row">Biological status</th> - <td class="field">{{ germplasmGnpis.biologicalStatusOfAccessionCode }}</td> - </tr> - <!--<tr> - <td>Source</td> - <td>{{ germplasmGnpis.source }}</td> - </tr> - <tr *ngIf="germplasmGnpis.source!='URGI'"> - <td>Source link</td> - <td><a>{{ germplasmGnpis.url }}</a></td> - </tr>--> - <tr *ngIf="germplasmGnpis.comment"> - <th class="fieldName" scope="row">Comments</th> - <td class="field">{{ germplasmGnpis.comment }}</td> - </tr> - </table> - </div> - </div> + + <gpds-card-row + label="Taxon common names" + [test]="germplasmGnpis.taxonCommonNames && germplasmGnpis.taxonCommonNames.length > 0"> + <ng-template> + {{ germplasmGnpis.taxonCommonNames.join(', ') }} + </ng-template> + </gpds-card-row> + + + <gpds-card-row + label="Taxon synonyms" + [test]="germplasmGnpis.taxonSynonyms && germplasmGnpis.taxonSynonyms.length > 0"> + <ng-template> + <i>{{ germplasmGnpis.taxonSynonyms.join(', ') }}</i> + </ng-template> + </gpds-card-row> + + <gpds-card-row + label="Pedigree" + [value]="germplasmGnpis.pedigree"> + </gpds-card-row> + + <gpds-card-row + label="Biological status" + [value]="germplasmGnpis.biologicalStatusOfAccessionCode"> + </gpds-card-row> + + <gpds-card-row + label="Comments" + [value]="germplasmGnpis.comment"> + </gpds-card-row> + + </div> + </ng-template> + </gpds-card-section> </div> - <div class="container"> - <div class="row" *ngIf="germplasmGnpis.holdingInstitute"> - <div class="col"> - <table class="table table-sm .table-responsive{-sm|-md|-lg|-xl}"> - <thead class="text-white"> - <tr> - <th class="headerTitle" scope="col" colspan="2"> - Holding - </th> - </tr> - </thead> - <tr> - <th class="fieldName" scope="row">Institution</th> - <td class="ellipsis field"><a class="btn popovers" data-boundary="window" placement="top" - [ngbPopover]="holdingInstituteTemplate" - [popoverTitle]="germplasmGnpis.holdingInstitute.instituteName" - container="body"> - {{ germplasmGnpis.holdingInstitute.instituteName }}</a></td> - </tr> - <tr *ngIf="germplasmGnpis.holdingGenbank.instituteName"> - <th class="fieldName" scope="row">Stock center name</th> + + <!--Templates for gerplasm card--> + <ng-template #holdingInstituteTemplate> + + <gpds-card-row + label="Institute name" + [value]="germplasmGnpis.holdingInstitute.instituteName"> + </gpds-card-row> + + <gpds-card-row + label="FAO code" + [value]="germplasmGnpis.holdingInstitute.instituteCode"> + </gpds-card-row> + + <gpds-card-row + label="Acronym" + [value]="germplasmGnpis.holdingInstitute.acronym"> + </gpds-card-row> + + <gpds-card-row + label="Organisation" + [value]="germplasmGnpis.holdingInstitute.organisation"> + </gpds-card-row> + + <gpds-card-row + label="Institute type" + [value]="germplasmGnpis.holdingInstitute.instituteType"> + </gpds-card-row> + + <gpds-card-row + label="Website" + [value]="germplasmGnpis.holdingInstitute.webSite"> + </gpds-card-row> + + + <gpds-card-row + label="Address" + [value]="germplasmGnpis.holdingInstitute.address"> + </gpds-card-row> + + </ng-template> + + + <ng-template #BreederInstituteTemplate> + + <gpds-card-row + label="Organisation" + [value]="germplasmGnpis.breeder.institute.organisation"> + </gpds-card-row> + + <gpds-card-row + label="Acronym" + [value]="germplasmGnpis.breeder.institute.acronym"> + </gpds-card-row> + + <gpds-card-row + label="Code" + [value]="germplasmGnpis.breeder.institute.instituteCode"> + </gpds-card-row> + + <gpds-card-row + label="Type" + [value]="germplasmGnpis.breeder.institute.instituteType"> + </gpds-card-row> + + <gpds-card-row + label="Link" + [test]="germplasmGnpis.breeder.institute.webSite"> + <ng-template> + <a [href]="germplasmGnpis.breeder.institute.webSite"> + {{ germplasmGnpis.breeder.institute.webSite }} + </a> + </ng-template> + </gpds-card-row> + + <gpds-card-row + label="Address" + [value]="germplasmGnpis.breeder.institute.address"> + </gpds-card-row> + + </ng-template> + + + <ng-template #CollectorInstituteTemplate> + + <gpds-card-row + label="Institute name" + [value]="germplasmGnpis.collector.instituteName"> + </gpds-card-row> + + <gpds-card-row + label="Acronym" + [value]="germplasmGnpis.collector.acronym"> + </gpds-card-row> + + <gpds-card-row + label="FAO code" + [value]="germplasmGnpis.collector.instituteCode"> + </gpds-card-row> + + <gpds-card-row + label="Organisation" + [value]="germplasmGnpis.collector.organisation"> + </gpds-card-row> + + <gpds-card-row + label="Link" + [test]="germplasmGnpis.collector.institute.webSite"> + <ng-template> + <a [href]="germplasmGnpis.collector.institute.webSite"> + {{ germplasmGnpis.collector.institute.webSite }} + </a> + </ng-template> + </gpds-card-row> + + <gpds-card-row + label="Address" + [value]="germplasmGnpis.collector.institute.address"> + </gpds-card-row> + + </ng-template> + + + <!--Section for the information about the holding of the germplasm--> + <gpds-card-section + header="Holding" + [test]="germplasmGnpis.holdingInstitute"> + <ng-template> + <div class="card-body"> + + + <gpds-card-row + label="Institution"> + <ng-template> + <a class="btn popovers" data-boundary="window" placement="top" + [ngbPopover]="holdingInstituteTemplate" + [popoverTitle]="germplasmGnpis.holdingInstitute.instituteName" + container="body"> + {{ germplasmGnpis.holdingInstitute.instituteName }}</a> + </ng-template> + </gpds-card-row> + + <gpds-card-row + label="Stock center name" + [test]="germplasmGnpis.holdingGenbank.instituteName"> + <ng-template> <ng-container *ngIf="germplasmGnpis.holdingGenbank.webSite"> - <td class="field"> - <a href="germplasmGnpis.holdingGenbank.webSite">{{ germplasmGnpis.holdingGenbank.instituteName }}</a> - </td> + <a [href]="germplasmGnpis.holdingGenbank.webSite"> + {{ germplasmGnpis.holdingGenbank.instituteName }} + </a> </ng-container> <ng-container *ngIf="!germplasmGnpis.holdingGenbank.webSite"> - <td class="field">{{ germplasmGnpis.holdingGenbank.instituteName }}</td> + {{ germplasmGnpis.holdingGenbank.instituteName }} </ng-container> + </ng-template> + </gpds-card-row> + + <gpds-card-row + label="Presence status" + [value]="germplasmGnpis.presenceStatus"> + </gpds-card-row> - </tr> - <tr *ngIf="germplasmGnpis.presenceStatus"> - <th class="fieldName" scope="row">Presence status</th> - <td class="field">{{ germplasmGnpis.presenceStatus }}</td> - </tr> - </table> - - - <ng-template #holdingInstituteTemplate> - <table class="popoverTable"> - <tr *ngIf="germplasmGnpis.holdingInstitute.instituteCode"> - <th class="fieldName" scope="row">FAO code</th> - <td class="field">{{ germplasmGnpis.holdingInstitute.instituteCode }}</td> - </tr> - <tr *ngIf="germplasmGnpis.holdingInstitute.instituteName"> - <th class="fieldName" scope="row">Institute name</th> - <td class="field">{{ germplasmGnpis.holdingInstitute.instituteName }}</td> - </tr> - <tr *ngIf="germplasmGnpis.holdingInstitute.acronym"> - <th class="fieldName" scope="row">Acronym</th> - <td class="field">{{ germplasmGnpis.holdingInstitute.acronym }}</td> - </tr> - <tr *ngIf="germplasmGnpis.holdingInstitute.organisation"> - <th class="fieldName" scope="row">Organisation</th> - <td class="field">{{ germplasmGnpis.holdingInstitute.organisation }}</td> - </tr> - <tr *ngIf="germplasmGnpis.holdingInstitute.instituteType"> - <th class="fieldName" scope="row">Institute type</th> - <td class="field">{{ germplasmGnpis.holdingInstitute.instituteType }}</td> - </tr> - <tr class="ellipsis" *ngIf="germplasmGnpis.holdingInstitute.webSite"> - <th class="fieldName" scope="row">Link</th> - <td class="ellipsis field"><a - href="{{ germplasmGnpis.holdingInstitute.webSite }}">{{ germplasmGnpis.holdingInstitute.webSite }}</a> - </td> - </tr> - <tr *ngIf="germplasmGnpis.holdingInstitute.address"> - <th class="fieldName" scope="row">Address</th> - <td class="field">{{ germplasmGnpis.holdingInstitute.address }}</td> - </tr> - </table> - </ng-template> </div> - </div> + </ng-template> + </gpds-card-section> - <div class="row" - *ngIf="germplasmGnpis.breeder && germplasmGnpis.breeder.institute && germplasmGnpis.breeder.institute.instituteName"> - <div class="col"> - <table class="table table-sm"> - <thead class="text-white"> - <tr> - <th class="headerTitle" scope="col" colspan="2"> - Breeder - </th> - </tr> - </thead> - <tr> - <th class="fieldName" scope="row">Institution</th> - <td class="ellipsis field"> - <a class="btn popovers" placement="top" [ngbPopover]="BreederInstituteTemplate" - [popoverTitle]="germplasmGnpis.breeder.institute.instituteName"> - {{ germplasmGnpis.breeder.institute.instituteName }} {{ germplasmGnpis.breeder.institute.instituteCode }}</a> - </td> - </tr> - <tr *ngIf="germplasmGnpis.breeder.accessionCreationDate"> - <th class="fieldName" scope="row">Accession Creation date</th> - <td - class="field">{{ germplasmGnpis.breeder.accessionCreationDate | amParse:'YYYYMMDD' | amDateFormat:'YYYY-MM-DD' }}</td> - </tr> - <tr *ngIf="germplasmGnpis.breeder.accessionNumber"> - <th class="fieldName" scope="row">Accession number</th> - <td class="field">{{ germplasmGnpis.breeder.accessionNumber }}</td> - </tr> - <tr *ngIf="germplasmGnpis.breeder.deregistrationYear"> - <th class="fieldName" scope="row">Deregistration year</th> - <td class="field">{{ germplasmGnpis.breeder.deregistrationYear }}</td> - </tr> - <tr *ngIf="germplasmGnpis.breeder.registrationYear"> - <th class="fieldName" scope="row">Registration year</th> - <td class="field">{{ germplasmGnpis.breeder.registrationYear }}</td> - </tr> - <tr *ngIf="germplasmGnpis.breeder.distributionStatus"> - <th class="fieldName" scope="row">distributionStatus</th> - <td class="field">{{ germplasmGnpis.breeder.distributionStatus }}</td> - </tr> - <tr *ngIf="germplasmGnpis.breeder.germplasmPUI"> - <th class="fieldName" scope="row">germplasmPUI</th> - <td class="field">{{ germplasmGnpis.breeder.germplasmPUI }}</td> - </tr> - </table> - </div> - </div> + <gpds-card-section + header="Origin" + [test]="testOrigin()"> + <ng-template> + <div class="card-body"> - <div class="row" *ngIf="germplasmGnpis.collector || germplasmGnpis.collectingSite"> - <div class="col"> - <table class="table table-sm .table-responsive{-sm|-md|-lg|-xl}"> - <thead class="text-white"> - <tr> - <th class="headerTitle" scope="col" colspan="2"> - Collecting - </th> - </tr> - </thead> - <tr - *ngIf="germplasmGnpis.collector && germplasmGnpis.collector.institute && germplasmGnpis.collector.institute.instituteName"> - <th class="fieldName" scope="row">Institution</th> - <td class="ellipsis field"><a class="btn popovers" placement="top" - [ngbPopover]="CollectorInstituteTemplate" - [popoverTitle]="germplasmGnpis.collector.institute.instituteName"> - {{ germplasmGnpis.collector.institute.instituteName }}</a></td> - </tr> - <tr *ngIf="germplasmGnpis.collector && germplasmGnpis.collector.accessionCreationDate"> - <th class="fieldName" scope="row">Accession Creation date</th> - <td - class="field">{{ germplasmGnpis.collector.accessionCreationDate | amParse:'YYYYMMDD' | amDateFormat:'YYYY-MM-DD' }}</td> - </tr> - <tr *ngIf="germplasmGnpis.collector && germplasmGnpis.collector.accessionNumber"> - <th class="fieldName" scope="row">Accession number</th> - <td class="field">{{ germplasmGnpis.collector.accessionNumber }}</td> - </tr> - <tr *ngIf="germplasmGnpis.collector && germplasmGnpis.collector.collectors"> - <th class="fieldName" scope="row">collectors</th> - <td class="field">{{ germplasmGnpis.collector.collectors }}</td> - </tr> - <tr *ngIf="germplasmGnpis.collector && germplasmGnpis.collector.distributionStatus"> - <th class="fieldName" scope="row">distributionStatus</th> - <td class="field">{{ germplasmGnpis.collector.distributionStatus }}</td> - </tr> - <tr *ngIf="germplasmGnpis.collector && germplasmGnpis.collector.germplasmPUI"> - <th class="fieldName" scope="row">germplasmPUI</th> - <td class="field">{{ germplasmGnpis.collector.germplasmPUI }}</td> - </tr> - <tr *ngIf="germplasmGnpis.collector && germplasmGnpis.collector.materialType"> - <th class="fieldName" scope="row">Material type</th> - <td class="field">{{ germplasmGnpis.collector.materialType }}</td> - </tr> + <gpds-card-row + label="Geographical origin" + [test]="germplasmGnpis.originSite && germplasmGnpis.originSite.siteName"> + <ng-template> + <a [routerLink]="['/sites/', germplasmGnpis.originSite.siteId]"> + {{ germplasmGnpis.originSite.siteName }} + </a> + </ng-template> + </gpds-card-row> + + <gpds-card-row + label="Collecting" + [test]="testCollectorInstituteObject() || testCollectorInstituteFields() || (germplasmGnpis.collectingSite && germplasmGnpis.collectingSite.siteName)"> + <ng-template> + + <gpds-card-row + label="Institution" + [test]="germplasmGnpis.collector.institute && germplasmGnpis.collector.institute.instituteName"> + <ng-template> + <a class="btn popovers" placement="top" + [ngbPopover]="CollectorInstituteTemplate" + [popoverTitle]="germplasmGnpis.collector.institute.instituteName"> + {{ germplasmGnpis.collector.institute.instituteName }} + </a> + </ng-template> + </gpds-card-row> + + <gpds-card-row + label="Accession Creation date" + [test]="germplasmGnpis.collector.accessionCreationDate"> + <ng-template> + {{ germplasmGnpis.collector.accessionCreationDate | amParse:'YYYYMMDD' | amDateFormat:'YYYY-MM-DD' }} + </ng-template> + </gpds-card-row> + + <gpds-card-row + label="Accession number" + [value]="germplasmGnpis.collector.accessionNumber"> + </gpds-card-row> + + <gpds-card-row + label="Collectors" + [value]="germplasmGnpis.collector.collectors"> + </gpds-card-row> + + <gpds-card-row + label="Distribution status" + [value]="germplasmGnpis.collector.distributionStatus"> + </gpds-card-row> + + <gpds-card-row + label="Germplasm Permanent Unique Identifier" + [value]="germplasmGnpis.collector.germplasmPUI"> + </gpds-card-row> + + <gpds-card-row + label="Material type" + [value]="germplasmGnpis.collector.materialType"> + </gpds-card-row> + + <gpds-card-row + label="Collecting site" + [test]="germplasmGnpis.collectingSite && germplasmGnpis.collectingSite.siteName"> + <ng-template> + <a [routerLink]="['/sites/', germplasmGnpis.collectingSite.siteId]"> + {{ germplasmGnpis.collectingSite.siteName }} + </a> + </ng-template> + </gpds-card-row> + + </ng-template> + </gpds-card-row> + + + <gpds-card-row + label="Breeder" + [test]="germplasmGnpis.breeder"> + <ng-template> + + <gpds-card-row + label="Institute" + [test]="germplasmGnpis.breeder.institute && germplasmGnpis.breeder.institute.instituteName"> + <ng-template> + <!--TODO : Fix the issue with the overflow link (issue 13)--> + <a class="btn popovers" placement="top" + [ngbPopover]="BreederInstituteTemplate" + [popoverTitle]="germplasmGnpis.breeder.institute.instituteName"> + {{ germplasmGnpis.breeder.institute.instituteName }} {{ germplasmGnpis.breeder.institute.instituteCode }} + </a> + </ng-template> + </gpds-card-row> + + <gpds-card-row + label="Accession creation date" + [test]="germplasmGnpis.breeder.accessionCreationDate "> + <ng-template> + {{ germplasmGnpis.breeder.accessionCreationDate | amParse:'YYYYMMDD' | amDateFormat:'YYYY-MM-DD' }} + </ng-template> + </gpds-card-row> + + <gpds-card-row + label="Accession number" + [value]="germplasmGnpis.breeder.accessionNumber"> + </gpds-card-row> + + <gpds-card-row + label="germplasm Permanent Unique Identifier" + [value]="germplasmGnpis.breeder.germplasmPUI"> + </gpds-card-row> + + <gpds-card-row + label="Registration year" + [value]="germplasmGnpis.breeder.registrationYear"> + </gpds-card-row> + + <gpds-card-row + label="Deregistration year" + [value]="germplasmGnpis.breeder.deregistrationYear"> + </gpds-card-row> + + <gpds-card-row + label="Distribution status" + [value]="germplasmGnpis.breeder.distributionStatus"> + </gpds-card-row> + + </ng-template> + </gpds-card-row> + + + <gpds-card-row + label="Donation" + [test]="germplasmGnpis.donors && germplasmGnpis.donors.length > 0"> + <ng-template> + <ng-container + *ngFor="let donor of germplasmGnpis.donors"> + + <!--Template for the donor popover--> + <ng-template #DonorInstituteTemplate> + + <gpds-card-row + label="Code" + [value]="donor.donorInstitute.instituteCode"> + </gpds-card-row> + + <gpds-card-row + label="Acronym" + [value]="donor.donorInstitute.acronym"> + </gpds-card-row> + + <gpds-card-row + label="Organisation" + [value]="donor.donorInstitute.organisation"> + </gpds-card-row> + + <gpds-card-row + label="Type" + [value]="donor.donorInstitute.instituteType"> + </gpds-card-row> + + <gpds-card-row + label="Address" + [value]="donor.donorInstitute.address"> + </gpds-card-row> + + <gpds-card-row + label="Website" + [test]="donor.donorInstitute.webSite"> + <ng-template> + <a [href]=" donor.donorInstitute.webSite "> + {{ donor.donorInstitute.webSite }} + </a> + </ng-template> + </gpds-card-row> + </ng-template> + + + <div> + <gpds-card-row + label="Institute name" + [test]="donor.donorInstitute.instituteName"> + <ng-template> + <a class="btn popovers" placement="top" + [ngbPopover]="DonorInstituteTemplate" + [popoverTitle]="donor.donorInstitute.instituteName"> + {{ donor.donorInstitute.instituteName }} + </a> + </ng-template> + </gpds-card-row> + + <gpds-card-row + label="Donation date" + [test]="donor.donationDate"> + <ng-template> + {{ donor.donationDate | amParse:'YYYYMMDD' | amDateFormat:'YYYY-MM-DD' }} + </ng-template> + </gpds-card-row> + + <gpds-card-row + label="Donor Accession Number" + [value]="donor.donorAccessionNumber"> + </gpds-card-row> + + <gpds-card-row + label="Donor germplasm Permanent Unique Identifier" + [value]="donor.donorGermplasmPUI"> + </gpds-card-row> + + <gpds-card-row + label="Donor institution code" + [value]="donor.donorInstituteCode"> + </gpds-card-row> + + </div> + + </ng-container> + </ng-template> + </gpds-card-row> - <tr *ngIf="germplasmGnpis.collectingSite && germplasmGnpis.collectingSite.siteName"> - <th class="fieldName" scope="row">Collecting site</th> - <td class="field"><a - [routerLink]="['/sites/', germplasmGnpis.collectingSite.siteId]">{{ germplasmGnpis.collectingSite.siteName }}</a> - </td> - </tr> - </table> </div> - </div> + </ng-template> + </gpds-card-section> - <div class="row" *ngIf="germplasmGnpis.donors && germplasmGnpis.donors.length > 0"> - <div class="col"> - <table class="table table-sm .table-responsive{-sm|-md|-lg|-xl}"> - <thead class="text-white"> - <tr> - <th class="headerTitle" scope="col" colspan="2"> - Donation - </th> - </tr> - </thead> + <gpds-card-section + header="Distribution" + [test]="germplasmGnpis.distributors && germplasmGnpis.distributors.length>0"> + <ng-template> + + <gpds-card-table + [headers]="[ + 'Institute', + 'Accession number', + 'Distribution status' + ]" + [rows]="germplasmGnpis.distributors"> + <ng-template let-row> <tr> - <th class="thead-light fieldName" scope="col">Institute</th> - <th class="thead-light fieldName" scope="col">Date</th> - </tr> - <tr *ngFor="let donor of germplasmGnpis.donors"> - <td class="ellipsis field"><a class="btn popovers ellipsis" placement="top" - [ngbPopover]="DonorInstituteTemplate" - [popoverTitle]="donor.donorInstitute.instituteName"> - {{ donor.donorInstitute.instituteName }}</a></td> - <td class="field" - *ngIf="donor.donationDate">{{ donor.donationDate | amParse:'YYYYMMDD' | amDateFormat:'YYYY-MM-DD' }}</td> - - <ng-template #DonorInstituteTemplate> - <table> - <tr *ngIf="donor.donorInstitute.instituteCode"> - <th class="fieldName" scope="row">Code</th> - <td class="field">{{ donor.donorInstitute.instituteCode }}</td> - </tr> - <tr *ngIf="donor.donorInstitute.acronym"> - <th class="fieldName" scope="row">Acronym</th> - <td class="field">{{ donor.donorInstitute.acronym }}</td> - </tr> - <tr *ngIf="donor.donorInstitute.organisation"> - <th class="fieldName" scope="row">Organisation</th> - <td class="field">{{ donor.donorInstitute.organisation }}</td> - </tr> - <tr *ngIf="donor.donorInstitute.instituteType"> - <th class="fieldName" scope="row">Type</th> - <td class="field">{{ donor.donorInstitute.instituteType }}</td> - </tr> - <tr *ngIf="donor.donorInstitute.webSite"> - <th class="fieldName" scope="row">Link</th> - <td class="ellipsis field"><a - href="{{ donor.donorInstitute.webSite }}">{{ donor.donorInstitute.webSite }}</a></td> - </tr> - <tr *ngIf="donor.donorInstitute.address"> - <th class="fieldName" scope="row">Address</th> - <td class="field">{{ donor.donorInstitute.address }}</td> - </tr> - </table> + <ng-template #InstituteTemplate> + + <gpds-card-row + label="FAO code" + [value]="row.institute.instituteCode"> + </gpds-card-row> + + <gpds-card-row + label="Acronym" + [value]="row.institute.acronym"> + </gpds-card-row> + + <gpds-card-row + label="Organisation" + [value]="row.institute.organisation"> + </gpds-card-row> + + <gpds-card-row + label="Institute type" + [value]="row.institute.instituteType"> + </gpds-card-row> + + <gpds-card-row + label="Website" + [test]="row.institute.webSite"> + <ng-template> + <a [href]="row.institute.webSite"> + {{ row.institute.webSite }} + </a> + </ng-template> + </gpds-card-row> + + + <gpds-card-row + label="Address" + [value]="row.institute.address"> + </gpds-card-row> </ng-template> + + <td> + <a class="btn popovers" placement="top" + [ngbPopover]="InstituteTemplate" + [popoverTitle]="row.institute.instituteName"> + {{ row.institute.instituteName }} + </a> + </td> + <td>{{ row.accessionNumber }}</td> + <td>{{ row.distributionStatus }}</td> </tr> - </table> - </div> - </div> + </ng-template> - <div class="row"> - <div class="col"> - <ng-container *ngIf="germplasmGnpis.distributors && germplasmGnpis.distributors.length > 0"> - <table class="table table-sm .table-responsive{-sm|-md|-lg|-xl}"> - <thead class="text-white"> - <tr> - <th class="headerTitle" scope="col" colspan="2"> - Distribution - </th> - </tr> - </thead> - <ng-container *ngFor="let distributor of germplasmGnpis.distributors"> - <tr> - <th class="fieldName" scope="row">{{ distributor.institute.instituteName }}</th> - <td class="field">{{ distributor.distributionStatus }}</td> - </tr> - </ng-container> - </table> - </ng-container> - </div> - </div> + </gpds-card-table> - <ng-template #BreederInstituteTemplate> - <table> - <tr *ngIf="germplasmGnpis.breeder.institute.instituteCode"> - <th class="fieldName" scope="row">Code</th> - <td class="field">{{ germplasmGnpis.breeder.institute.instituteCode }}</td> - </tr> - <tr *ngIf="germplasmGnpis.breeder.institute.organisation"> - <th class="fieldName" scope="row">Organisation</th> - <td class="field">{{ germplasmGnpis.breeder.institute.organisation }}</td> - </tr> - <tr *ngIf="germplasmGnpis.breeder.institute.acronym"> - <th class="fieldName" scope="row">Acronym</th> - <td class="field">{{ germplasmGnpis.breeder.institute.acronym }}</td> - </tr> - <tr *ngIf="germplasmGnpis.breeder.institute.instituteType"> - <th class="fieldName" scope="row">Type</th> - <td class="field">{{ germplasmGnpis.breeder.institute.instituteType }}</td> - </tr> - <tr *ngIf="germplasmGnpis.breeder.institute.webSite"> - <th class="fieldName" scope="row">Link</th> - <td class="ellipsis field"><a - href="{{ germplasmGnpis.breeder.institute.webSite }}">{{ germplasmGnpis.breeder.institute.webSite }}</a> - </td> - </tr> - <tr *ngIf="germplasmGnpis.breeder.institute.address"> - <th class="fieldName" scope="row">Address</th> - <td class="field">{{ germplasmGnpis.breeder.institute.address }}</td> - </tr> - </table> </ng-template> + </gpds-card-section> - <ng-template #CollectorInstituteTemplate> - <table> - <tr *ngIf="germplasmGnpis.collector.instituteCode"> - <th class="fieldName" scope="row">FAO code</th> - <td class="field">{{ germplasmGnpis.collector.instituteCode }}</td> - </tr> - <tr *ngIf="germplasmGnpis.collector.instituteName"> - <th class="fieldName" scope="row">Institute name</th> - <td class="field">{{ germplasmGnpis.collector.instituteName }}</td> - </tr> - <tr *ngIf="germplasmGnpis.collector.acronym"> - <th class="fieldName" scope="row">Acronym</th> - <td class="field">{{ germplasmGnpis.collector.acronym }}</td> - </tr> - <tr *ngIf="germplasmGnpis.collector.organisation"> - <th class="fieldName" scope="row">Organisation</th> - <td class="field">{{ germplasmGnpis.collector.organisation }}</td> - </tr> - <tr *ngIf="germplasmGnpis.collector.institute.webSite"> - <th class="fieldName" scope="row">Link</th> - <td class="ellipsis field"><a - href="{{ germplasmGnpis.collector.institute.webSite }}">{{ germplasmGnpis.collector.institute.webSite }}</a> - </td> - </tr> - <tr *ngIf="germplasmGnpis.collector.institute.address"> - <th class="fieldName" scope="row">Address</th> - <td class="field">{{ germplasmGnpis.collector.institute.address }}</td> - </tr> - </table> - </ng-template> + <gpds-card-section + header="Genealogy" + [test]="testPedigree() || testProgeny()"> + <ng-template> + <div class="card-body"> + + <gpds-card-row + label="Crossing plan" + [value]="germplasmPedigree.crossingPlan"> + </gpds-card-row> + + <gpds-card-row + label="Crossing year" + [value]="germplasmPedigree.crossingYear"> + </gpds-card-row> + + <gpds-card-row + label="Family code" + [value]="germplasmPedigree.familyCode"> + </gpds-card-row> + + + <gpds-card-row + label="Parent accessions" + [test]="germplasmPedigree.parent1Name || germplasmPedigree.parent2Name"> + + <ng-template> + + <gpds-card-row + label="Mother" + [test]="germplasmPedigree.parent1Type && germplasmPedigree.parent1Type == 'FEMALE'"> + <ng-template> + <a [routerLink]="'/germplasm'" + [queryParams]="{id:germplasmPedigree.parent1DbId}"> + {{ germplasmPedigree.parent1Name }} + </a> + </ng-template> + </gpds-card-row> + + <gpds-card-row + label="Father" + [test]="germplasmPedigree.parent1Type && germplasmPedigree.parent1Type == 'MALE'"> + <ng-template> + <a [routerLink]="'/germplasm'" + [queryParams]="{id:germplasmPedigree.parent1DbId}"> + {{ germplasmPedigree.parent1Name }} + </a> + </ng-template> + </gpds-card-row> + + <gpds-card-row + label="Population" + [test]="germplasmPedigree.parent1Type && germplasmPedigree.parent1Type == 'POPULATION'"> + <ng-template> + {{ germplasmPedigree.parent1Name }} + </ng-template> + </gpds-card-row> + + <gpds-card-row + label="SELF" + [test]="germplasmPedigree.parent1Type == 'SELF'"> + <ng-template> + Self + </ng-template> + </gpds-card-row> + + + <gpds-card-row + label="Mother" + [test]="germplasmPedigree.parent2Type && germplasmPedigree.parent2Type == 'FEMALE'"> + <ng-template> + <a [routerLink]="'/germplasm'" + [queryParams]="{id:germplasmPedigree.parent2DbId}"> + {{ germplasmPedigree.parent2Name }} + </a> + </ng-template> + </gpds-card-row> + + <gpds-card-row + label="Father" + [test]="germplasmPedigree.parent2Type && germplasmPedigree.parent2Type == 'MALE'"> + <ng-template> + <a [routerLink]="'/germplasm'" + [queryParams]="{id:germplasmPedigree.parent2DbId}"> + {{ germplasmPedigree.parent2Name }} + </a> + </ng-template> + </gpds-card-row> + + <gpds-card-row + label="Population" + [test]="germplasmPedigree.parent2Type && germplasmPedigree.parent2Type == 'POPULATION'"> + <ng-template> + {{ germplasmPedigree.parent2Name }} + </ng-template> + </gpds-card-row> + + <gpds-card-row + label="SELF" + [test]="germplasmPedigree.parent2Type == 'SELF'"> + <ng-template> + Self + </ng-template> + </gpds-card-row> + + </ng-template> + </gpds-card-row> + + <gpds-card-row + label="Sibling accessions" + [test]="germplasmPedigree.siblings && germplasmPedigree.siblings.length > 0"> + <ng-template> + + <div class="content-overflow"> + <ng-container *ngFor="let sibling of germplasmPedigree.siblings"> + <a [routerLink]="'/germplasm'" [queryParams]="{id:sibling.germplasmDbId }"> + {{ sibling.defaultDisplayName }} + </a>, + </ng-container> + </div> + + </ng-template> + </gpds-card-row> + + <gpds-card-row + label="Descendant" + [test]="testProgeny()"> + <ng-template> + + <div class="content-overflow"> + <ng-container *ngFor="let child of germplasmProgeny.progeny"> + <a [routerLink]="'/germplasm'" [queryParams]="{id:child.germplasmDbId }"> + {{ child.defaultDisplayName }} + </a>, + </ng-container> + </div> + + </ng-template> + </gpds-card-row> - <ng-container *ngIf="testPedigree() || testProgeny()"> - <div class="row"> - <div class="col"> - <h4>Genealogy</h4> - </div> - </div> - <div class="row"> - <div class="col"> - <table class="table table-sm .table-responsive{-sm|-md|-lg|-xl}" *ngIf="testPedigree()"> - <thead class="text-white"> - <tr> - <th class="headerTitle" scope="col" colspan="2"> - Ascendants - </th> - </tr> - </thead> - <tr *ngIf="germplasmPedigree.result.crossingPlan"> - <th class="fieldName" scope="row">Crossing plan</th> - <td class="field">{{ germplasmPedigree.result.crossingPlan }}</td> - </tr> - <tr *ngIf="germplasmPedigree.result.crossingYear"> - <th class="fieldName" scope="row">Crossing year</th> - <td class="field">{{ germplasmPedigree.result.crossingYear }}</td> - </tr> - <tr *ngIf="germplasmPedigree.result.familyCode"> - <th class="fieldName" scope="row">Family code</th> - <td class="field">{{ germplasmPedigree.result.familyCode }}</td> - </tr> - <tr *ngIf="(germplasmPedigree.result.parent1Type || germplasmPedigree.result.parent2Type) - && (germplasmPedigree.result.parent1Type !='UNDEFINED' || germplasmPedigree.result.parent2Type !='UNDEFINED')"> - <th scope="row">Parent accessions</th> - <td> - <table> - <ng-container [ngSwitch]="germplasmPedigree.result.parent1Type"> - <tr *ngSwitchCase="'FEMALE'"> - <th class="fieldName" scope="row">Mother</th> - <td class="field"><a - [routerLink]="'/germplasm'" - [queryParams]="{id:germplasmPedigree.result.parent1DbId}">{{ germplasmPedigree.result.parent1Name }}</a> - </td> - </tr> - <tr *ngSwitchCase="'MALE'"> - <th class="fieldName" scope="row">Father</th> - <td class="field"><a - [routerLink]="'/germplasm'" - [queryParams]="{id:germplasmPedigree.result.parent1DbId}">{{ germplasmPedigree.result.parent1Name }}</a> - </td> - </tr> - <tr *ngSwitchCase="'SELF'"> - <td>Self</td> - </tr> - <tr *ngSwitchCase="'POPULATION'"> - <th class="fieldName" scope="row">Population</th> - <td class="field">{{ germplasmPedigree.result.parent1Name }}</td> - </tr> - </ng-container> - <ng-container [ngSwitch]="germplasmPedigree.result.parent2Type"> - <tr *ngSwitchCase="'FEMALE'"> - <th class="fieldName" scope="row">Mother</th> - <td class="field"><a - [routerLink]="'/germplasm'" - [queryParams]="{id:germplasmPedigree.result.parent2DbId}">{{ germplasmPedigree.result.parent2Name }}</a></td> - </tr> - <tr *ngSwitchCase="'MALE'"> - <th class="fieldName" scope="row">Father</th> - <td class="field"><a - [routerLink]="'/germplasm'" - [queryParams]="{id:germplasmPedigree.result.parent2DbId}">{{ germplasmPedigree.result.parent2Name }}</a></td> - </tr> - <tr *ngSwitchCase="'SELF'"> - <td>Self</td> - </tr> - <tr *ngSwitchCase="'POPULATION'"> - <th class="fieldName" scope="row">Population</th> - <td class="field">{{ germplasmPedigree.result.parent2Name }}</td> - </tr> - </ng-container> - </table> - </td> - </tr> - </table> - </div> </div> + </ng-template> + </gpds-card-section> + + <gpds-card-section + header="Evaluation Data" + [test]="germplasmAttributes && germplasmAttributes.length > 0"> + <ng-template> + <div class="card-body"> + + <ng-container *ngFor="let descriptor of germplasmAttributes"> + <gpds-card-row + [label]="descriptor.attributeName" + [value]="descriptor.value"> + </gpds-card-row> + </ng-container> - <ng-container *ngIf="germplasmPedigree.result.siblings && germplasmPedigree.result.siblings.length > 0"> - <div class="row "> - <div class="col"> - <table class="table table-sm .table-responsive{-sm|-md|-lg|-xl}"> - <thead class="text-white"> - <tr> - <th class="headerTitle" scope="col" colspan="2"> - Siblings - </th> - </tr> - </thead> - <tbody> - <tr> - <th class="fieldName">Accession numbers</th> - <td class="scroll field"> - <ng-container *ngFor="let sibling of germplasmPedigree.result.siblings"> - <a routerLink="/germplasm" [queryParams]="{id:sibling.germplasmDbId }"> - {{ sibling.defaultDisplayName }}</a> - </ng-container> - </td> - </tr> - </tbody> - </table> - </div> - </div> - </ng-container> - - <ng-container *ngIf="testProgeny()"> - <div class="row "> - <div class="col"> - <table class="table table-sm .table-responsive{-sm|-md|-lg|-xl}"> - <thead class="text-white"> - <tr> - <th class="headerTitle" scope="col" colspan="2"> - Descendants - </th> - </tr> - </thead> - <tbody> - <tr> - <th class="fieldName">Accession numbers</th> - <td class="scroll field"> - <ng-container *ngFor="let child of germplasmProgeny.result.progeny"> - <a routerLink="/germplasm" [queryParams]="{id:child.germplasmDbId }"> - {{ child.defaultDisplayName }}</a> - </ng-container> - </td> - </tr> - </tbody> - </table> - </div> - </div> - </ng-container> - </ng-container> - - <ng-container *ngIf="germplasmAttributes && germplasmAttributes.length > 0"> - <div class="row"> - <div class="col"> - <h4 class="headerTitle">Evaluation Data</h4> - <table class="table table-sm .table-responsive{-sm|-md|-lg|-xl}"> - - <ng-container *ngFor="let descriptor of germplasmAttributes"> - <tr> - <th class="fieldName" scope="row">{{ descriptor.attributeName }}</th> - <td class="field">{{ descriptor.value }}</td> - </tr> - </ng-container> - </table> - </div> </div> - </ng-container> - - <ng-container *ngIf="germplasmGnpis.collection && germplasmGnpis.collection.length > 0"> - <div class="row"> - <div class="col"> - <h4 class="headerTitle">Collection</h4> - <table class="table table-sm .table-responsive{-sm|-md|-lg|-xl}"> - <ng-container *ngFor="let collection of germplasmGnpis.collection"> - <tr> - <th class="fieldName" scope="row"> - {{ collection.type ? collection.name + ' (' + collection.type + ')' : collection.name }} - </th> - <td class="ellipsis field"><a routerLink="" [queryParams]="{germplasmLists: collection.name, types: 'Germplasm'}"> - {{ collection.germplasmCount }} accessions</a> - </td> - </tr> - </ng-container> - </table> - </div> + </ng-template> + </gpds-card-section> + + + <gpds-card-section + header="Collection" + [test]="germplasmGnpis.collection && germplasmGnpis.collection.length > 0"> + <ng-template> + <div class="card-body"> + + <ng-container *ngFor="let collection of germplasmGnpis.collection"> + <gpds-card-row + [label]="collection.type ? collection.name + ' (' + collection.type + ')' : collection.name"> + <ng-template> + <a [routerLink]="'/'" + [queryParams]="{germplasmLists: collection.name, types: 'Germplasm'}"> + {{ collection.germplasmCount }} accessions + </a> + </ng-template> + </gpds-card-row> + </ng-container> + </div> - </ng-container> - - <ng-container *ngIf="germplasmGnpis.panel && germplasmGnpis.panel.length > 0"> - <div class="row"> - <div class="col"> - <h4 class="headerTitle">Panel</h4> - <table class="table table-sm .table-responsive{-sm|-md|-lg|-xl}"> - <ng-container *ngFor="let panel of germplasmGnpis.panel"> - <tr> - <th class="fieldName" scope="row"> - {{ panel.type ? panel.name + ' (' + panel.type + ')' : panel.name }} - </th> - <td class="field"><a routerLink="" [queryParams]="{germplasmLists: panel.name, types: 'Germplasm'}"> - {{ panel.germplasmCount }} accessions</a></td> - </tr> - </ng-container> - </table> - </div> + </ng-template> + </gpds-card-section> + + + <gpds-card-section + header="Panel" + [test]="germplasmGnpis.panel && germplasmGnpis.panel.length > 0"> + <ng-template> + <div class="card-body"> + + <ng-container *ngFor="let panel of germplasmGnpis.panel"> + <gpds-card-row + [label]="panel.type ? panel.name + ' (' + panel.type + ')' : panel.name"> + <a [routerLink]="'/'" + [queryParams]="{germplasmLists: panel.name, types: 'Germplasm'}"> + {{ panel.germplasmCount }} accessions + </a> + </gpds-card-row> + </ng-container> + </div> - </ng-container> - - <ng-container *ngIf="germplasmGnpis.population && germplasmGnpis.population.length > 0"> - <div class="row"> - <div class="col"> - <h4 class="headerTitle">Population</h4> - <table class="table table-sm .table-responsive{-sm|-md|-lg|-xl}"> - <ng-container *ngFor="let population of germplasmGnpis.population"> - <tr> - <th class="fieldName" scope="row"> - {{ population.type ? population.name + ' (' + population.type + ')' : population.name }} - </th> - <td class="field"><a routerLink="" [queryParams]="{germplasmLists: population.name, types: 'Germplasm'}"> - {{ population.germplasmCount }} accessions</a></td> - </tr> - </ng-container> - </table> - </div> + </ng-template> + </gpds-card-section> + + + <gpds-card-section + header="Population" + [test]="germplasmGnpis.population && germplasmGnpis.population.length > 0"> + <ng-template> + <div class="card-body"> + + <ng-container *ngFor="let population of germplasmGnpis.population"> + <gpds-card-row + [label]="population.type ? population.name + ' (' + population.type + ')' : population.name"> + <ng-template> + <a [routerLink]="'/'" + [queryParams]="{germplasmLists: population.name, types: 'Germplasm'}"> + {{ population.germplasmCount }} accessions + </a> + </ng-template> + </gpds-card-row> + </ng-container> + </div> - </ng-container> - </div> + </ng-template> + </gpds-card-section> + + </div> diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts b/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts index 60c1d275..7490f856 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts +++ b/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts @@ -19,6 +19,9 @@ import { Germplasm, GermplasmData, GermplasmResult, Institute, Origin, Site } fr import { NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap'; import { MomentModule } from 'ngx-moment'; import { LoadingSpinnerComponent } from '../loading-spinner/loading-spinner.component'; +import { CardSectionComponent } from '../card-section/card-section.component'; +import { CardRowComponent } from '../card-row/card-row.component'; +import { CardTableComponent } from '../card-table/card-table.component'; import { MockComponent } from 'ng-mocks'; import { XrefsComponent } from '../xrefs/xrefs.component'; @@ -36,8 +39,8 @@ describe('GermplasmCardComponent', () => { return this.element('h3'); } - get headerTitle() { - return this.elements('.headerTitle'); + get cardHeader() { + return this.elements('div.card-header'); } } @@ -113,7 +116,7 @@ describe('GermplasmCardComponent', () => { logo: null }; - const brapiOrigin: Origin = { + const brapiOrigin: Origin = { ... brapiInstitute, institute: brapiInstitute, germplasmPUI: '12', accessionNumber: '12', @@ -127,9 +130,10 @@ describe('GermplasmCardComponent', () => { const brapiDonor: BrapiDonor = { donorInstitute: brapiInstitute, - germplasmPUI: '12', - accessionNumber: '12', - donorInstituteCode: 'urgi' + donorGermplasmPUI: '12', + donorAccessionNumber: '12', + donorInstituteCode: 'urgi', + donationDate: null }; const brapiSet: BrapiSet = { @@ -197,22 +201,18 @@ describe('GermplasmCardComponent', () => { population: [brapiSet] }; - const germplasmResultTest = { - result: germplasmTest - }; - beforeEach(async(() => { TestBed.configureTestingModule({ imports: [RouterTestingModule, NgbPopoverModule, MomentModule], declarations: [ GermplasmCardComponent, LoadingSpinnerComponent, MockComponent(XrefsComponent) + GermplasmCardComponent, CardSectionComponent, + CardRowComponent, LoadingSpinnerComponent, CardTableComponent ], providers: [ - // { provide: ActivatedRoute, useValue: activatedRoute }, { provide: BrapiService, useValue: brapiService }, { provide: GnpisService, useValue: gnpisService }, - { - provide: ActivatedRoute, + { provide: ActivatedRoute, useValue: { snapshot: { queryParams: convertToParamMap({ @@ -240,10 +240,12 @@ describe('GermplasmCardComponent', () => { expect(component.germplasmGnpis).toBeTruthy(); tester.detectChanges(); expect(tester.title).toContainText('Germplasm: test'); - expect(tester.headerTitle[0]).toContainText('Identification'); - expect(tester.headerTitle[1]).toContainText('Holding'); - expect(tester.headerTitle[2]).toContainText('Breeder'); - expect(tester.headerTitle[3]).toContainText('Collecting'); + expect(tester.cardHeader[0]).toContainText('Identification'); + expect(tester.cardHeader[1]).toContainText('Holding'); + expect(tester.cardHeader[2]).toContainText('Origin'); + expect(tester.cardHeader[3]).toContainText('Distribution'); + expect(tester.cardHeader[4]).toContainText('Genealogy'); + expect(tester.cardHeader[5]).toContainText('Evaluation Data'); }); })); }); diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.ts b/frontend/src/app/germplasm-card/germplasm-card.component.ts index 14fa0e9e..a5968aeb 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.ts +++ b/frontend/src/app/germplasm-card/germplasm-card.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { BrapiService } from '../brapi.service'; import { GnpisService } from '../gnpis.service'; -import { Germplasm, GermplasmResult } from '../models/gnpis.germplasm.model'; +import { Germplasm } from '../models/gnpis.germplasm.model'; import { BrapiGermplasmAttributes, BrapiGermplasmPedigree, BrapiGermplasmProgeny } from '../models/brapi.germplasm.model'; @Component({ @@ -18,8 +18,8 @@ export class GermplasmCardComponent implements OnInit { } germplasmGnpis: Germplasm; - germplasmPedigree: GermplasmResult<BrapiGermplasmPedigree>; - germplasmProgeny: GermplasmResult<BrapiGermplasmProgeny>; + germplasmPedigree: BrapiGermplasmPedigree; + germplasmProgeny: BrapiGermplasmProgeny; germplasmAttributes: BrapiGermplasmAttributes[]; germplasmId: string; germplasmPuid: string; @@ -35,19 +35,20 @@ export class GermplasmCardComponent implements OnInit { // console.log(this.route); this.germplasmId = this.route.snapshot.queryParams.id; this.germplasmPuid = this.route.snapshot.queryParams.pui; + const germplasm$ = this.getGermplasm(this.germplasmId, this.germplasmPuid); germplasm$.then(result => { const germplasmId = this.germplasmId ? this.germplasmId : result.germplasmDbId; const germplasmProgeny$ = this.brapiService.germplasmProgeny(germplasmId).toPromise(); germplasmProgeny$ .then(germplasmProgeny => { - this.germplasmProgeny = germplasmProgeny; + this.germplasmProgeny = germplasmProgeny.result; }); const germplasmPedigree$ = this.brapiService.germplasmPedigree(germplasmId).toPromise(); germplasmPedigree$ .then(germplasmPedigree => { - this.germplasmPedigree = germplasmPedigree; + this.germplasmPedigree = germplasmPedigree.result; }); const germplasmAttributes$ = this.brapiService.germplasmAttributes(germplasmId).toPromise(); @@ -85,22 +86,51 @@ export class GermplasmCardComponent implements OnInit { return germplasm$; } + // TODO: use a generic function to get path in object (or null if non-existent) testProgeny() { return (this.germplasmProgeny - && this.germplasmProgeny.result - && this.germplasmProgeny.result.progeny - && this.germplasmProgeny.result.progeny.length > 0); + && this.germplasmProgeny.progeny + && this.germplasmProgeny.progeny.length > 0); } testPedigree() { return (this.germplasmPedigree - && this.germplasmPedigree.result - && (this.germplasmPedigree.result.parent1Name - || this.germplasmPedigree.result.parent2Name - || this.germplasmPedigree.result.crossingPlan - || this.germplasmPedigree.result.crossingYear - || this.germplasmPedigree.result.familyCode) + && (this.germplasmPedigree.parent1Name + || this.germplasmPedigree.parent2Name + || this.germplasmPedigree.crossingPlan + || this.germplasmPedigree.crossingYear + || this.germplasmPedigree.familyCode) + ); + } + + + testCollectorInstituteObject() { + return ( + this.germplasmGnpis.collector + && this.germplasmGnpis.collector.institute + && this.germplasmGnpis.collector.institute.instituteName); + } + + testCollectorInstituteFields() { + return ( + this.germplasmGnpis.collector.germplasmPUI + || this.germplasmGnpis.collector.accessionNumber + || this.germplasmGnpis.collector.accessionCreationDate + || this.germplasmGnpis.collector.materialType + || this.germplasmGnpis.collector.collectors + || this.germplasmGnpis.collector.registrationYear + || this.germplasmGnpis.collector.deregistrationYear + || this.germplasmGnpis.collector.distributionStatus ); } + + testOrigin() { + + return (this.germplasmGnpis.originSite && this.germplasmGnpis.originSite.siteName) + || (this.germplasmGnpis.donors && this.germplasmGnpis.donors.length > 0) + || ((this.testCollectorInstituteObject() || this.testCollectorInstituteFields()) + || (this.germplasmGnpis.collectingSite && this.germplasmGnpis.collectingSite.siteName)) + || (this.germplasmGnpis.breeder); + } } diff --git a/frontend/src/app/gnpis.service.spec.ts b/frontend/src/app/gnpis.service.spec.ts index 512deece..9f8ff7a6 100644 --- a/frontend/src/app/gnpis.service.spec.ts +++ b/frontend/src/app/gnpis.service.spec.ts @@ -51,7 +51,7 @@ describe('GnpisService', () => { logo: null }; - const brapiOrigin: Origin = { + const brapiOrigin: Origin = { ...brapiInstitute, institute: brapiInstitute, germplasmPUI: '12', accessionNumber: '12', @@ -65,9 +65,10 @@ describe('GnpisService', () => { const brapiDonor: BrapiDonor = { donorInstitute: brapiInstitute, - germplasmPUI: '12', - accessionNumber: '12', - donorInstituteCode: 'urgi' + donorGermplasmPUI: '12', + donorAccessionNumber: '12', + donorInstituteCode: 'urgi', + donationDate: null }; const brapiSet: BrapiSet = { diff --git a/frontend/src/app/models/brapi.germplasm.model.ts b/frontend/src/app/models/brapi.germplasm.model.ts index 54ed2d04..b4ad65c3 100644 --- a/frontend/src/app/models/brapi.germplasm.model.ts +++ b/frontend/src/app/models/brapi.germplasm.model.ts @@ -40,10 +40,11 @@ export interface BrapiGermplasmAttributes { } export interface BrapiDonor { - donorInstitute: Institute; - germplasmPUI: string; - accessionNumber: string; + donorGermplasmPUI: string; + donorAccessionNumber: string; donorInstituteCode: string; + donationDate: number; + donorInstitute: Institute; } export interface BrapiSet { diff --git a/frontend/src/app/models/gnpis.germplasm.model.ts b/frontend/src/app/models/gnpis.germplasm.model.ts index a18cbb87..0ffc08d5 100644 --- a/frontend/src/app/models/gnpis.germplasm.model.ts +++ b/frontend/src/app/models/gnpis.germplasm.model.ts @@ -18,7 +18,7 @@ export interface Germplasm { germplasmPUI: string; pedigree: string; seedSource: string; - synonyms: string; + synonyms: string[]; commonCropName: string; instituteCode: string; instituteName: string; @@ -39,7 +39,7 @@ export interface Germplasm { taxonCommonNames: string[]; geneticNature: string; comment: string; - photo: string; + photo: Photo; holdingInstitute: Institute; holdingGenbank: Institute; presenceStatus: string; @@ -56,7 +56,18 @@ export interface Germplasm { population: BrapiSet[]; } -export interface Origin { +export interface Institute { + instituteName: string; + instituteCode: string; + acronym: string; + organisation: string; + instituteType: string; + webSite: string; + address: string; + logo: string; +} + +export interface Origin extends Institute { institute: Institute; germplasmPUI: string; accessionNumber: string; @@ -68,15 +79,13 @@ export interface Origin { distributionStatus: string; } -export interface Institute { - instituteName: string; - instituteCode: string; - acronym: string; - organisation: string; - instituteType: string; - webSite: string; - address: string; - logo: string; +export interface Photo { + copyright: string; + description: string; + fileName: string; + photoName: string; + thumbnailFileName: string; + } export interface GermplasmData<T> { diff --git a/frontend/src/app/study-card/study-card.component.scss b/frontend/src/app/study-card/study-card.component.scss index c344730e..c04ee673 100644 --- a/frontend/src/app/study-card/study-card.component.scss +++ b/frontend/src/app/study-card/study-card.component.scss @@ -1,8 +1,4 @@ @import "theme"; @import '../../styles.scss'; -h3 { - font-weight: bold; - color: #0f6191; -} diff --git a/frontend/src/assets/gpds/theme.scss b/frontend/src/assets/gpds/theme.scss index 535bbace..10ddd627 100644 --- a/frontend/src/assets/gpds/theme.scss +++ b/frontend/src/assets/gpds/theme.scss @@ -26,7 +26,6 @@ $enable-shadows: true; // public custom variables used in this theme, and in component styles - //custom tables .table { table-layout: fixed; diff --git a/frontend/src/styles.scss b/frontend/src/styles.scss index b7abb8b9..57a33dec 100644 --- a/frontend/src/styles.scss +++ b/frontend/src/styles.scss @@ -13,3 +13,23 @@ $fa-font-path: '~font-awesome/fonts'; a { text-decoration: underline; } + +h3 { + font-weight: bold; + color: #0f6191; +} +.row-sep { + border-top: 1px solid #f0f0f0; +} + +.content-overflow { + max-height: 175px; + overflow-y: auto; +} + +.display-spinner-front { + position: absolute; + top: 70px; + left: 720px; + background-color: #F9F9F9; +} diff --git a/frontend/src/tslint.json b/frontend/src/tslint.json index 9a8fed21..87a3bff4 100644 --- a/frontend/src/tslint.json +++ b/frontend/src/tslint.json @@ -15,7 +15,7 @@ ], "template-cyclomatic-complexity": [ true, - 260 + 11 ] } } -- GitLab From 64ccbd2aca399df382be7ff819762d1281df0b3b Mon Sep 17 00:00:00 2001 From: jdestin <jeremy.destin@inra.fr> Date: Mon, 4 Mar 2019 12:12:16 +0100 Subject: [PATCH 03/20] feat: Use components (card-section, card-row and card-table) to display the parents of the progeny. Use the germplasm GnpIS call for progeny.GNP-5490 --- frontend/src/app/brapi.service.spec.ts | 5 +- frontend/src/app/brapi.service.ts | 6 +- .../germplasm-card.component.html | 31 ++++--- .../germplasm-card.component.spec.ts | 9 +- .../germplasm-card.component.ts | 15 ++-- .../src/app/models/gnpis.germplasm.model.ts | 85 ++++++++++++------- frontend/src/styles.scss | 5 ++ frontend/src/tslint.json | 2 +- 8 files changed, 95 insertions(+), 63 deletions(-) diff --git a/frontend/src/app/brapi.service.spec.ts b/frontend/src/app/brapi.service.spec.ts index 67d30d57..6e71ee07 100644 --- a/frontend/src/app/brapi.service.spec.ts +++ b/frontend/src/app/brapi.service.spec.ts @@ -22,7 +22,6 @@ import { import { Germplasm, GermplasmData, GermplasmResult, Institute, Origin, Site } from './models/gnpis.germplasm.model'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { TestBed } from '@angular/core/testing'; -import { Util } from 'leaflet'; describe('BrapiService', () => { @@ -379,7 +378,7 @@ describe('BrapiService', () => { }); - it('should fetch the germplasm progeny', () => { + /*it('should fetch the germplasm progeny', () => { let fetchedGermplasmProgeny: GermplasmResult<BrapiGermplasmProgeny>; const germplasmDbId: string = brapiGermplasmProgeny.result.germplasmDbId; @@ -391,7 +390,7 @@ describe('BrapiService', () => { expect(fetchedGermplasmProgeny).toEqual(brapiGermplasmProgeny); - }); + });*/ it('should fetch the germplasm attributes', () => { diff --git a/frontend/src/app/brapi.service.ts b/frontend/src/app/brapi.service.ts index bed9d9a8..545589b5 100644 --- a/frontend/src/app/brapi.service.ts +++ b/frontend/src/app/brapi.service.ts @@ -11,7 +11,7 @@ import { BrapiStudy, BrapiTrial } from './models/brapi.model'; -import { BrapiGermplasmAttributes, BrapiGermplasmPedigree, BrapiGermplasmProgeny } from './models/brapi.germplasm.model'; +import { BrapiGermplasmAttributes, BrapiGermplasmPedigree } from './models/brapi.germplasm.model'; export const BASE_URL = 'brapi/v1'; @@ -33,9 +33,9 @@ export class BrapiService { .get<GermplasmResult<BrapiGermplasmPedigree>>(`${BASE_URL}/germplasm/${germplasmDbId}/pedigree`); } - germplasmProgeny(germplasmDbId: string): Observable<GermplasmResult<BrapiGermplasmProgeny>> { + /*germplasmProgeny(germplasmDbId: string): Observable<GermplasmResult<BrapiGermplasmProgeny>> { return this.http.get<GermplasmResult<BrapiGermplasmProgeny>>(`${BASE_URL}/germplasm/${germplasmDbId}/progeny`); - } + }*/ germplasmAttributes(germplasmDbId: string): Observable<GermplasmResult<GermplasmData<BrapiGermplasmAttributes[]>>> { return this.http diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.html b/frontend/src/app/germplasm-card/germplasm-card.component.html index 2ad0aaaf..d27135e4 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.html +++ b/frontend/src/app/germplasm-card/germplasm-card.component.html @@ -733,20 +733,29 @@ </gpds-card-row> <gpds-card-row - label="Descendant" + label="Descendant :" [test]="testProgeny()"> - <ng-template> + </gpds-card-row> - <div class="content-overflow"> - <ng-container *ngFor="let child of germplasmProgeny.progeny"> - <a [routerLink]="'/germplasm'" [queryParams]="{id:child.germplasmDbId }"> - {{ child.defaultDisplayName }} - </a>, - </ng-container> - </div> + <div class="content-overflow-big"> + <ng-container *ngFor="let child of germplasmProgeny"> - </ng-template> - </gpds-card-row> + <gpds-card-row + [label]="'Child of ' + child.firstParentName + ' and ' + child.secondParentName" + [test]="testProgeny()"> + <ng-template> + + <ng-container *ngFor="let sibling of child.sibblings"> + <a [routerLink]="'/germplasm'" [queryParams]="{pui:sibling.pui}"> + {{ sibling.name }} + </a>, + </ng-container> + + + </ng-template> + </gpds-card-row> + </ng-container> + </div> </div> </ng-template> diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts b/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts index 7490f856..b1033f77 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts +++ b/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts @@ -11,7 +11,6 @@ import { BrapiDonor, BrapiGermplasmAttributes, BrapiGermplasmPedigree, - BrapiGermplasmProgeny, BrapiSet, BrapiSibling } from '../models/brapi.germplasm.model'; @@ -47,7 +46,7 @@ describe('GermplasmCardComponent', () => { const brapiService = jasmine.createSpyObj( 'BrapiService', [ 'germplasm', - 'germplasmProgeny', + /*'germplasmProgeny',*/ 'germplasmPedigree', 'germplasmAttributes' ] @@ -97,13 +96,13 @@ describe('GermplasmCardComponent', () => { } }; - const brapiGermplasmProgeny: GermplasmResult<BrapiGermplasmProgeny> = { + /*const brapiGermplasmProgeny: GermplasmResult<BrapiGermplasmProgeny> = { result: { germplasmDbId: '11', defaultDisplayName: '11', progeny: [brapiSibling] } - }; + };*/ const brapiInstitute: Institute = { instituteName: 'urgi', @@ -228,7 +227,7 @@ describe('GermplasmCardComponent', () => { gnpisService.germplasm.and.returnValue(of(germplasmTest)); gnpisService.germplasmByPuid.and.returnValue(of(germplasmTest)); - brapiService.germplasmProgeny.and.returnValue(of(brapiGermplasmProgeny)); + /*brapiService.germplasmProgeny.and.returnValue(of(brapiGermplasmProgeny));*/ brapiService.germplasmPedigree.and.returnValue(of(brapiGermplasmPedigree)); brapiService.germplasmAttributes.and.returnValue(of(brapiGermplasmAttributes)); diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.ts b/frontend/src/app/germplasm-card/germplasm-card.component.ts index a5968aeb..da0b28db 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.ts +++ b/frontend/src/app/germplasm-card/germplasm-card.component.ts @@ -2,8 +2,8 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { BrapiService } from '../brapi.service'; import { GnpisService } from '../gnpis.service'; -import { Germplasm } from '../models/gnpis.germplasm.model'; -import { BrapiGermplasmAttributes, BrapiGermplasmPedigree, BrapiGermplasmProgeny } from '../models/brapi.germplasm.model'; +import { Germplasm, GermplasmProgeny } from '../models/gnpis.germplasm.model'; +import { BrapiGermplasmAttributes, BrapiGermplasmPedigree } from '../models/brapi.germplasm.model'; @Component({ selector: 'gpds-germplasm-card', @@ -19,7 +19,7 @@ export class GermplasmCardComponent implements OnInit { germplasmGnpis: Germplasm; germplasmPedigree: BrapiGermplasmPedigree; - germplasmProgeny: BrapiGermplasmProgeny; + germplasmProgeny: GermplasmProgeny[]; germplasmAttributes: BrapiGermplasmAttributes[]; germplasmId: string; germplasmPuid: string; @@ -39,11 +39,12 @@ export class GermplasmCardComponent implements OnInit { const germplasm$ = this.getGermplasm(this.germplasmId, this.germplasmPuid); germplasm$.then(result => { const germplasmId = this.germplasmId ? this.germplasmId : result.germplasmDbId; - const germplasmProgeny$ = this.brapiService.germplasmProgeny(germplasmId).toPromise(); + + /*const germplasmProgeny$ = this.brapiService.germplasmProgeny(germplasmId).toPromise(); germplasmProgeny$ .then(germplasmProgeny => { this.germplasmProgeny = germplasmProgeny.result; - }); + });*/ const germplasmPedigree$ = this.brapiService.germplasmPedigree(germplasmId).toPromise(); germplasmPedigree$ @@ -75,6 +76,7 @@ export class GermplasmCardComponent implements OnInit { germplasm$ .then(germplasmGnpis => { this.germplasmGnpis = germplasmGnpis; + this.germplasmProgeny = germplasmGnpis.children; }); } else { germplasm$ = this.gnpisService.germplasmByPuid(pui).toPromise(); @@ -89,8 +91,7 @@ export class GermplasmCardComponent implements OnInit { // TODO: use a generic function to get path in object (or null if non-existent) testProgeny() { return (this.germplasmProgeny - && this.germplasmProgeny.progeny - && this.germplasmProgeny.progeny.length > 0); + && this.germplasmProgeny.length > 0); } testPedigree() { diff --git a/frontend/src/app/models/gnpis.germplasm.model.ts b/frontend/src/app/models/gnpis.germplasm.model.ts index 0ffc08d5..d7278424 100644 --- a/frontend/src/app/models/gnpis.germplasm.model.ts +++ b/frontend/src/app/models/gnpis.germplasm.model.ts @@ -8,6 +8,57 @@ export interface Site { siteType: string; } +export interface Institute { + instituteName: string; + instituteCode: string; + acronym: string; + organisation: string; + instituteType: string; + webSite: string; + address: string; + logo: string; +} + +export interface Origin extends Institute { + institute: Institute; + germplasmPUI: string; + accessionNumber: string; + accessionCreationDate: string; + materialType: string; + collectors: string; + registrationYear: string; + deregistrationYear: string; + distributionStatus: string; +} + +export interface Photo { + copyright: string; + description: string; + fileName: string; + photoName: string; + thumbnailFileName: string; + +} + +export interface GermplasmProgeny { + + crossingPlan: string; + crossingYear: string; + familyCode: string; + firstParentName: string; + firstParentPUI: string; + firstParentType: string; + secondParentName: string; + secondParentPUI: string; + secondParentType: string; + sibblings: { + name: string; + pui: string; + value: string; + }[]; + +} + export interface Germplasm { source: string; url: string; @@ -43,7 +94,7 @@ export interface Germplasm { holdingInstitute: Institute; holdingGenbank: Institute; presenceStatus: string; - children: string; + children: GermplasmProgeny[]; descriptors: BrapiDescriptor[]; originSite: Site; collectingSite: Site; @@ -56,38 +107,6 @@ export interface Germplasm { population: BrapiSet[]; } -export interface Institute { - instituteName: string; - instituteCode: string; - acronym: string; - organisation: string; - instituteType: string; - webSite: string; - address: string; - logo: string; -} - -export interface Origin extends Institute { - institute: Institute; - germplasmPUI: string; - accessionNumber: string; - accessionCreationDate: string; - materialType: string; - collectors: string; - registrationYear: string; - deregistrationYear: string; - distributionStatus: string; -} - -export interface Photo { - copyright: string; - description: string; - fileName: string; - photoName: string; - thumbnailFileName: string; - -} - export interface GermplasmData<T> { data: T; } diff --git a/frontend/src/styles.scss b/frontend/src/styles.scss index 57a33dec..c8ad9be6 100644 --- a/frontend/src/styles.scss +++ b/frontend/src/styles.scss @@ -27,6 +27,11 @@ h3 { overflow-y: auto; } +.content-overflow-big { + max-height: 275px; + overflow-y: auto; +} + .display-spinner-front { position: absolute; top: 70px; diff --git a/frontend/src/tslint.json b/frontend/src/tslint.json index 87a3bff4..bfffe71c 100644 --- a/frontend/src/tslint.json +++ b/frontend/src/tslint.json @@ -15,7 +15,7 @@ ], "template-cyclomatic-complexity": [ true, - 11 + 12 ] } } -- GitLab From aed324536eb142aa14ed1ed6c3140eddefb77524 Mon Sep 17 00:00:00 2001 From: jdestin <jeremy.destin@inra.fr> Date: Mon, 4 Mar 2019 15:20:44 +0100 Subject: [PATCH 04/20] fix: Fix the bug for germplasm navigation page. GNP-5490 --- frontend/src/app/app-routing.module.ts | 10 +++++++--- .../germplasm-card.component.html | 18 +++++++++--------- .../germplasm-card/germplasm-card.component.ts | 14 ++++++++++++-- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts index baefb2f8..3e955fa6 100644 --- a/frontend/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -5,15 +5,19 @@ import { GermplasmCardComponent } from './germplasm-card/germplasm-card.componen import { StudyCardComponent } from './study-card/study-card.component'; import { SiteCardComponent } from './site-card/site-card.component'; -const routes: Routes = [ - { path: 'germplasm', component: GermplasmCardComponent }, +export const routes: Routes = [ { path: 'studies/:id', component: StudyCardComponent }, { path: 'sites/:id', component: SiteCardComponent }, { path: '', component: ResultPageComponent }, + { + path: 'germplasm', + component: GermplasmCardComponent, + runGuardsAndResolvers: 'paramsOrQueryParamsChange' + } ]; @NgModule({ - imports: [RouterModule.forRoot(routes)], + imports: [RouterModule.forRoot(routes, { onSameUrlNavigation: 'reload' })], exports: [RouterModule] }) export class AppRoutingModule { diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.html b/frontend/src/app/germplasm-card/germplasm-card.component.html index d27135e4..4e8068e3 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.html +++ b/frontend/src/app/germplasm-card/germplasm-card.component.html @@ -640,7 +640,7 @@ label="Mother" [test]="germplasmPedigree.parent1Type && germplasmPedigree.parent1Type == 'FEMALE'"> <ng-template> - <a [routerLink]="'/germplasm'" + <a [routerLink]="['/germplasm']" [queryParams]="{id:germplasmPedigree.parent1DbId}"> {{ germplasmPedigree.parent1Name }} </a> @@ -651,7 +651,7 @@ label="Father" [test]="germplasmPedigree.parent1Type && germplasmPedigree.parent1Type == 'MALE'"> <ng-template> - <a [routerLink]="'/germplasm'" + <a [routerLink]="['/germplasm']" [queryParams]="{id:germplasmPedigree.parent1DbId}"> {{ germplasmPedigree.parent1Name }} </a> @@ -679,7 +679,7 @@ label="Mother" [test]="germplasmPedigree.parent2Type && germplasmPedigree.parent2Type == 'FEMALE'"> <ng-template> - <a [routerLink]="'/germplasm'" + <a [routerLink]="['/germplasm']" [queryParams]="{id:germplasmPedigree.parent2DbId}"> {{ germplasmPedigree.parent2Name }} </a> @@ -690,7 +690,7 @@ label="Father" [test]="germplasmPedigree.parent2Type && germplasmPedigree.parent2Type == 'MALE'"> <ng-template> - <a [routerLink]="'/germplasm'" + <a [routerLink]="['/germplasm']" [queryParams]="{id:germplasmPedigree.parent2DbId}"> {{ germplasmPedigree.parent2Name }} </a> @@ -723,7 +723,7 @@ <div class="content-overflow"> <ng-container *ngFor="let sibling of germplasmPedigree.siblings"> - <a [routerLink]="'/germplasm'" [queryParams]="{id:sibling.germplasmDbId }"> + <a [routerLink]="['/germplasm']" [queryParams]="{id:sibling.germplasmDbId }"> {{ sibling.defaultDisplayName }} </a>, </ng-container> @@ -746,7 +746,7 @@ <ng-template> <ng-container *ngFor="let sibling of child.sibblings"> - <a [routerLink]="'/germplasm'" [queryParams]="{pui:sibling.pui}"> + <a [routerLink]="['/germplasm']" [queryParams]="{id:sibling.pui}"> {{ sibling.name }} </a>, </ng-container> @@ -789,7 +789,7 @@ <gpds-card-row [label]="collection.type ? collection.name + ' (' + collection.type + ')' : collection.name"> <ng-template> - <a [routerLink]="'/'" + <a [routerLink]="['/']" [queryParams]="{germplasmLists: collection.name, types: 'Germplasm'}"> {{ collection.germplasmCount }} accessions </a> @@ -811,7 +811,7 @@ <ng-container *ngFor="let panel of germplasmGnpis.panel"> <gpds-card-row [label]="panel.type ? panel.name + ' (' + panel.type + ')' : panel.name"> - <a [routerLink]="'/'" + <a [routerLink]="['/']" [queryParams]="{germplasmLists: panel.name, types: 'Germplasm'}"> {{ panel.germplasmCount }} accessions </a> @@ -833,7 +833,7 @@ <gpds-card-row [label]="population.type ? population.name + ' (' + population.type + ')' : population.name"> <ng-template> - <a [routerLink]="'/'" + <a [routerLink]="['/']" [queryParams]="{germplasmLists: population.name, types: 'Germplasm'}"> {{ population.germplasmCount }} accessions </a> diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.ts b/frontend/src/app/germplasm-card/germplasm-card.component.ts index da0b28db..289177e4 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.ts +++ b/frontend/src/app/germplasm-card/germplasm-card.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; +import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; import { BrapiService } from '../brapi.service'; import { GnpisService } from '../gnpis.service'; import { Germplasm, GermplasmProgeny } from '../models/gnpis.germplasm.model'; @@ -14,7 +14,17 @@ import { BrapiGermplasmAttributes, BrapiGermplasmPedigree } from '../models/brap export class GermplasmCardComponent implements OnInit { - constructor(private brapiService: BrapiService, private gnpisService: GnpisService, private route: ActivatedRoute) { + constructor(private brapiService: BrapiService, + private gnpisService: GnpisService, + private route: ActivatedRoute, + private router: Router) { + + this.router.events.subscribe((event: any) => { + // If it is a NavigationEnd event re-initalise the component + if (event instanceof NavigationEnd) { + this.ngOnInit(); + } + }); } germplasmGnpis: Germplasm; -- GitLab From b88a3503c24122547928575581a8e5a4cee9458f Mon Sep 17 00:00:00 2001 From: jdestin <jeremy.destin@inra.fr> Date: Tue, 5 Mar 2019 18:42:05 +0100 Subject: [PATCH 05/20] fix: Fix display bugs on germplasm card. Uniformize style on the cards. Minor fixes. GNP-5490 --- .../src/app/card-row/card-row.component.scss | 3 + .../card-section/card-section.component.html | 2 +- .../card-section/card-section.component.scss | 14 ++-- .../app/card-table/card-table.component.html | 2 +- .../app/card-table/card-table.component.scss | 8 +++ frontend/src/app/form/form.component.scss | 4 ++ .../germplasm-card.component.html | 71 +++++++++++-------- .../germplasm-card.component.ts | 4 +- frontend/src/app/navbar/navbar.component.scss | 5 ++ .../app/site-card/site-card.component.html | 2 +- .../app/study-card/study-card.component.html | 2 +- frontend/src/assets/gpds/theme.scss | 3 +- frontend/src/styles.scss | 14 +++- 13 files changed, 90 insertions(+), 44 deletions(-) diff --git a/frontend/src/app/card-row/card-row.component.scss b/frontend/src/app/card-row/card-row.component.scss index 3cba0cba..fba9a857 100644 --- a/frontend/src/app/card-row/card-row.component.scss +++ b/frontend/src/app/card-row/card-row.component.scss @@ -2,4 +2,7 @@ .field { font-weight: bold; + overflow-wrap: normal; } + + diff --git a/frontend/src/app/card-section/card-section.component.html b/frontend/src/app/card-section/card-section.component.html index ffaa0ba6..bcf4fd14 100644 --- a/frontend/src/app/card-section/card-section.component.html +++ b/frontend/src/app/card-section/card-section.component.html @@ -1,4 +1,4 @@ -<div class="card mb-3 mt-4" *ngIf="test"> +<div class="card mb-3" *ngIf="test"> <div class="card-header"> {{ header }} </div> diff --git a/frontend/src/app/card-section/card-section.component.scss b/frontend/src/app/card-section/card-section.component.scss index 10c46aaa..2e137cc6 100644 --- a/frontend/src/app/card-section/card-section.component.scss +++ b/frontend/src/app/card-section/card-section.component.scss @@ -1,8 +1,11 @@ +@import '../../styles.scss'; + +a { + text-decoration: underline; +} + .card { - margin-top: 25px; - margin-bottom: 10px; - border-color: rgba(15, 97, 145, 0.25); - border-width: 2px; + border: none; } .card-header { @@ -10,6 +13,5 @@ font-weight: bold; color: #f5f5f5; background-color: #0f6191; - border-color: #0f6191; - border-width: 2px; } + diff --git a/frontend/src/app/card-table/card-table.component.html b/frontend/src/app/card-table/card-table.component.html index beb8c094..93b0d733 100644 --- a/frontend/src/app/card-table/card-table.component.html +++ b/frontend/src/app/card-table/card-table.component.html @@ -1,4 +1,4 @@ -<div class="table-responsive scroll-table"> +<div class="table-responsive scroll-table table-card-body"> <table class="table table-sm table-striped"> <thead *ngIf="headers"> <tr> diff --git a/frontend/src/app/card-table/card-table.component.scss b/frontend/src/app/card-table/card-table.component.scss index b5c78f56..85f3be7e 100644 --- a/frontend/src/app/card-table/card-table.component.scss +++ b/frontend/src/app/card-table/card-table.component.scss @@ -9,3 +9,11 @@ background-color: white; } } + +.table-card-body { + padding: 0; + border: 2px solid rgb(195, 214, 226); + border-top-width: 0px; + border-bottom-left-radius: 0.25rem; + border-bottom-right-radius: 0.25rem; +} diff --git a/frontend/src/app/form/form.component.scss b/frontend/src/app/form/form.component.scss index e93197f5..da9bf710 100644 --- a/frontend/src/app/form/form.component.scss +++ b/frontend/src/app/form/form.component.scss @@ -6,6 +6,10 @@ label { } } +.nav-link { + text-decoration: none; +} + .nav-tabs { .nav-link.active { font-weight: bold; diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.html b/frontend/src/app/germplasm-card/germplasm-card.component.html index 4e8068e3..2964ebeb 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.html +++ b/frontend/src/app/germplasm-card/germplasm-card.component.html @@ -6,10 +6,10 @@ </h3> <div class="container-fluid"> - <div class="row"> + <div class="row align-items-center"> <!--Section for the image representing the germplasm and the details about this image--> - <div class="col-md-auto field" *ngIf="germplasmGnpis.photo && germplasmGnpis.photo.thumbnailFileName"> + <div class="col-auto field" *ngIf="germplasmGnpis.photo && germplasmGnpis.photo.thumbnailFileName"> <figure class="figure"> <img [src]="IMAGES_SIREGAL_URL +'/' + germplasmGnpis.holdingGenbank.instituteCode + '/' + germplasmGnpis.photo.thumbnailFileName" @@ -49,10 +49,10 @@ <!--Section for the information about the identification of the germplasm--> <gpds-card-section - class="col" + class="col-12 col-lg" header="Identification"> <ng-template> - <div class="card-body"> + <div class="card-body card-section-body"> <gpds-card-row label="Germplasm name" @@ -270,13 +270,13 @@ header="Holding" [test]="germplasmGnpis.holdingInstitute"> <ng-template> - <div class="card-body"> + <div class="card-body card-section-body"> <gpds-card-row label="Institution"> <ng-template> - <a class="btn popovers" data-boundary="window" placement="top" + <a class="popovers" data-boundary="window" placement="top" [ngbPopover]="holdingInstituteTemplate" [popoverTitle]="germplasmGnpis.holdingInstitute.instituteName" container="body"> @@ -313,7 +313,7 @@ header="Origin" [test]="testOrigin()"> <ng-template> - <div class="card-body"> + <div class="card-body card-section-body"> <gpds-card-row label="Geographical origin" @@ -334,7 +334,7 @@ label="Institution" [test]="germplasmGnpis.collector.institute && germplasmGnpis.collector.institute.instituteName"> <ng-template> - <a class="btn popovers" placement="top" + <a class="popovers" placement="top" [ngbPopover]="CollectorInstituteTemplate" [popoverTitle]="germplasmGnpis.collector.institute.instituteName"> {{ germplasmGnpis.collector.institute.instituteName }} @@ -399,7 +399,7 @@ [test]="germplasmGnpis.breeder.institute && germplasmGnpis.breeder.institute.instituteName"> <ng-template> <!--TODO : Fix the issue with the overflow link (issue 13)--> - <a class="btn popovers" placement="top" + <a class="popovers" placement="top" [ngbPopover]="BreederInstituteTemplate" [popoverTitle]="germplasmGnpis.breeder.institute.instituteName"> {{ germplasmGnpis.breeder.institute.instituteName }} {{ germplasmGnpis.breeder.institute.instituteCode }} @@ -496,7 +496,7 @@ label="Institute name" [test]="donor.donorInstitute.instituteName"> <ng-template> - <a class="btn popovers" placement="top" + <a class="popovers" placement="top" [ngbPopover]="DonorInstituteTemplate" [popoverTitle]="donor.donorInstitute.instituteName"> {{ donor.donorInstitute.instituteName }} @@ -591,7 +591,7 @@ </ng-template> <td> - <a class="btn popovers" placement="top" + <a class="popovers" placement="top" [ngbPopover]="InstituteTemplate" [popoverTitle]="row.institute.instituteName"> {{ row.institute.instituteName }} @@ -612,33 +612,42 @@ header="Genealogy" [test]="testPedigree() || testProgeny()"> <ng-template> - <div class="card-body"> + <div class="card-body card-section-body"> <gpds-card-row label="Crossing plan" - [value]="germplasmPedigree.crossingPlan"> + [test]="germplasmPedigree && germplasmPedigree.crossingPlan"> + <ng-template> + {{ germplasmPedigree.crossingPlan }} + </ng-template> </gpds-card-row> <gpds-card-row label="Crossing year" - [value]="germplasmPedigree.crossingYear"> + [test]="germplasmPedigree && germplasmPedigree.crossingYear"> + <ng-template> + {{ germplasmPedigree.crossingYear }} + </ng-template> </gpds-card-row> <gpds-card-row label="Family code" - [value]="germplasmPedigree.familyCode"> + [test]="germplasmPedigree && germplasmPedigree.familyCode"> + <ng-template> + {{ germplasmPedigree.familyCode }} + </ng-template> </gpds-card-row> <gpds-card-row label="Parent accessions" - [test]="germplasmPedigree.parent1Name || germplasmPedigree.parent2Name"> + [test]="germplasmPedigree && (germplasmPedigree.parent1Name || germplasmPedigree.parent2Name)"> <ng-template> <gpds-card-row label="Mother" - [test]="germplasmPedigree.parent1Type && germplasmPedigree.parent1Type == 'FEMALE'"> + [test]="germplasmPedigree && (germplasmPedigree.parent1Type && germplasmPedigree.parent1Type == 'FEMALE')"> <ng-template> <a [routerLink]="['/germplasm']" [queryParams]="{id:germplasmPedigree.parent1DbId}"> @@ -649,7 +658,7 @@ <gpds-card-row label="Father" - [test]="germplasmPedigree.parent1Type && germplasmPedigree.parent1Type == 'MALE'"> + [test]="germplasmPedigree && (germplasmPedigree.parent1Type && germplasmPedigree.parent1Type == 'MALE')"> <ng-template> <a [routerLink]="['/germplasm']" [queryParams]="{id:germplasmPedigree.parent1DbId}"> @@ -660,7 +669,7 @@ <gpds-card-row label="Population" - [test]="germplasmPedigree.parent1Type && germplasmPedigree.parent1Type == 'POPULATION'"> + [test]="germplasmPedigree && (germplasmPedigree.parent1Type && germplasmPedigree.parent1Type == 'POPULATION')"> <ng-template> {{ germplasmPedigree.parent1Name }} </ng-template> @@ -668,7 +677,7 @@ <gpds-card-row label="SELF" - [test]="germplasmPedigree.parent1Type == 'SELF'"> + [test]="germplasmPedigree && (germplasmPedigree.parent1Type == 'SELF')"> <ng-template> Self </ng-template> @@ -677,7 +686,7 @@ <gpds-card-row label="Mother" - [test]="germplasmPedigree.parent2Type && germplasmPedigree.parent2Type == 'FEMALE'"> + [test]="germplasmPedigree && (germplasmPedigree.parent2Type && germplasmPedigree.parent2Type == 'FEMALE')"> <ng-template> <a [routerLink]="['/germplasm']" [queryParams]="{id:germplasmPedigree.parent2DbId}"> @@ -688,7 +697,7 @@ <gpds-card-row label="Father" - [test]="germplasmPedigree.parent2Type && germplasmPedigree.parent2Type == 'MALE'"> + [test]="germplasmPedigree && (germplasmPedigree.parent2Type && germplasmPedigree.parent2Type == 'MALE')"> <ng-template> <a [routerLink]="['/germplasm']" [queryParams]="{id:germplasmPedigree.parent2DbId}"> @@ -699,7 +708,7 @@ <gpds-card-row label="Population" - [test]="germplasmPedigree.parent2Type && germplasmPedigree.parent2Type == 'POPULATION'"> + [test]="germplasmPedigree && (germplasmPedigree.parent2Type && germplasmPedigree.parent2Type == 'POPULATION')"> <ng-template> {{ germplasmPedigree.parent2Name }} </ng-template> @@ -707,7 +716,7 @@ <gpds-card-row label="SELF" - [test]="germplasmPedigree.parent2Type == 'SELF'"> + [test]="germplasmPedigree && (germplasmPedigree.parent2Type == 'SELF')"> <ng-template> Self </ng-template> @@ -718,7 +727,7 @@ <gpds-card-row label="Sibling accessions" - [test]="germplasmPedigree.siblings && germplasmPedigree.siblings.length > 0"> + [test]="germplasmPedigree && (germplasmPedigree.siblings && germplasmPedigree.siblings.length > 0)"> <ng-template> <div class="content-overflow"> @@ -740,8 +749,8 @@ <div class="content-overflow-big"> <ng-container *ngFor="let child of germplasmProgeny"> - <gpds-card-row - [label]="'Child of ' + child.firstParentName + ' and ' + child.secondParentName" + <gpds-card-row class="text" + [label]="'child(ren) of ' + child.firstParentName + ' and ' + child.secondParentName" [test]="testProgeny()"> <ng-template> @@ -765,7 +774,7 @@ header="Evaluation Data" [test]="germplasmAttributes && germplasmAttributes.length > 0"> <ng-template> - <div class="card-body"> + <div class="card-body card-section-body"> <ng-container *ngFor="let descriptor of germplasmAttributes"> <gpds-card-row @@ -783,7 +792,7 @@ header="Collection" [test]="germplasmGnpis.collection && germplasmGnpis.collection.length > 0"> <ng-template> - <div class="card-body"> + <div class="card-body card-section-body"> <ng-container *ngFor="let collection of germplasmGnpis.collection"> <gpds-card-row @@ -806,7 +815,7 @@ header="Panel" [test]="germplasmGnpis.panel && germplasmGnpis.panel.length > 0"> <ng-template> - <div class="card-body"> + <div class="card-body card-section-body"> <ng-container *ngFor="let panel of germplasmGnpis.panel"> <gpds-card-row @@ -827,7 +836,7 @@ header="Population" [test]="germplasmGnpis.population && germplasmGnpis.population.length > 0"> <ng-template> - <div class="card-body"> + <div class="card-body card-section-body card-section-body"> <ng-container *ngFor="let population of germplasmGnpis.population"> <gpds-card-row diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.ts b/frontend/src/app/germplasm-card/germplasm-card.component.ts index 289177e4..91dd3037 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.ts +++ b/frontend/src/app/germplasm-card/germplasm-card.component.ts @@ -13,6 +13,7 @@ import { BrapiGermplasmAttributes, BrapiGermplasmPedigree } from '../models/brap export class GermplasmCardComponent implements OnInit { + alreadyInitialize = false; constructor(private brapiService: BrapiService, private gnpisService: GnpisService, @@ -21,7 +22,7 @@ export class GermplasmCardComponent implements OnInit { this.router.events.subscribe((event: any) => { // If it is a NavigationEnd event re-initalise the component - if (event instanceof NavigationEnd) { + if (this.alreadyInitialize && event instanceof NavigationEnd) { this.ngOnInit(); } }); @@ -75,6 +76,7 @@ export class GermplasmCardComponent implements OnInit { this.loaded = Promise.all([germplasm$]); this.loaded.then(() => { this.loading = false; + this.alreadyInitialize = true; }); } diff --git a/frontend/src/app/navbar/navbar.component.scss b/frontend/src/app/navbar/navbar.component.scss index 301875fc..e3e12a57 100644 --- a/frontend/src/app/navbar/navbar.component.scss +++ b/frontend/src/app/navbar/navbar.component.scss @@ -24,4 +24,9 @@ .dropdown-container { position: relative; + text-decoration: none; +} + +.dropdown-item { + text-decoration: none; } diff --git a/frontend/src/app/site-card/site-card.component.html b/frontend/src/app/site-card/site-card.component.html index 9144f1af..3f949ca4 100644 --- a/frontend/src/app/site-card/site-card.component.html +++ b/frontend/src/app/site-card/site-card.component.html @@ -14,7 +14,7 @@ <gpds-card-section header="Details"> <ng-template> - <div class="card-body"> + <div class="card-body card-section-body"> <gpds-card-row label="Site type" [value]="location.locationType"> diff --git a/frontend/src/app/study-card/study-card.component.html b/frontend/src/app/study-card/study-card.component.html index 0ccf9c30..652a3231 100644 --- a/frontend/src/app/study-card/study-card.component.html +++ b/frontend/src/app/study-card/study-card.component.html @@ -12,7 +12,7 @@ <gpds-card-section header="Identification"> <ng-template> - <div class="card-body"> + <div class="card-body card-section-body"> <gpds-card-row label="Name" diff --git a/frontend/src/assets/gpds/theme.scss b/frontend/src/assets/gpds/theme.scss index 10ddd627..44791e76 100644 --- a/frontend/src/assets/gpds/theme.scss +++ b/frontend/src/assets/gpds/theme.scss @@ -29,6 +29,7 @@ $enable-shadows: true; //custom tables .table { table-layout: fixed; + thead { background-color: #0f6191; } @@ -43,7 +44,7 @@ a.btn.popovers { } .popover { - max-width: 50%; + max-width: 100%; } /*table th, table td { overflow: hidden; }*/ diff --git a/frontend/src/styles.scss b/frontend/src/styles.scss index c8ad9be6..84ba4d7a 100644 --- a/frontend/src/styles.scss +++ b/frontend/src/styles.scss @@ -18,10 +18,22 @@ h3 { font-weight: bold; color: #0f6191; } + +.card-section-body { + border: 2px solid rgb(195, 214, 226); + border-top-width: 0px; + border-bottom-left-radius: 0.25rem; + border-bottom-right-radius: 0.25rem; +} + .row-sep { border-top: 1px solid #f0f0f0; } +.row-sep .row-sep:first-of-type { + border: none; +} + .content-overflow { max-height: 175px; overflow-y: auto; @@ -29,7 +41,7 @@ h3 { .content-overflow-big { max-height: 275px; - overflow-y: auto; + overflow: auto; } .display-spinner-front { -- GitLab From 246a37c16d5a717dc0fab0ad21754ece1aa9484a Mon Sep 17 00:00:00 2001 From: jdestin <jeremy.destin@inra.fr> Date: Wed, 6 Mar 2019 12:22:20 +0100 Subject: [PATCH 06/20] fix: Fix germplasm card's bug about test before display. Rebase on the last version of master. Minor fixes GNP-5490 --- .../germplasm-card.component.html | 1355 +++++++++-------- .../germplasm-card.component.ts | 4 +- 2 files changed, 684 insertions(+), 675 deletions(-) diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.html b/frontend/src/app/germplasm-card/germplasm-card.component.html index 2964ebeb..86e21d4d 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.html +++ b/frontend/src/app/germplasm-card/germplasm-card.component.html @@ -5,854 +5,863 @@ Germplasm: {{ germplasmGnpis.germplasmName }} </h3> - <div class="container-fluid"> - <div class="row align-items-center"> - - <!--Section for the image representing the germplasm and the details about this image--> - <div class="col-auto field" *ngIf="germplasmGnpis.photo && germplasmGnpis.photo.thumbnailFileName"> - <figure class="figure"> - <img - [src]="IMAGES_SIREGAL_URL +'/' + germplasmGnpis.holdingGenbank.instituteCode + '/' + germplasmGnpis.photo.thumbnailFileName" - class="img-fluid"> - <figcaption class="figure-caption"> - <a class="btn popovers" data-boundary="window" placement="right" [ngbPopover]="imageTemplate" - [popoverTitle]="germplasmGnpis.photo.thumbnailFileName" container="body"> - Click to see more details. - </a> - </figcaption> - </figure> - - <ng-template #imageTemplate> - <div class="card ngb-popover-window "> - <img class="card-img-top" - [src]="IMAGES_SIREGAL_URL + '/' + germplasmGnpis.holdingGenbank.instituteCode + '/' + germplasmGnpis.photo.fileName" - alt="" width="250px"> - <div class="card-body"> - <gpds-card-row - label="Name" - [value]="germplasmGnpis.photo.photoName"> - </gpds-card-row> - - <gpds-card-row - label="Description" - [value]="germplasmGnpis.photo.description"> - </gpds-card-row> - - <gpds-card-row - label="Copyright" - [value]="germplasmGnpis.photo.copyright"> - </gpds-card-row> - </div> - </div> - </ng-template> - </div> - - <!--Section for the information about the identification of the germplasm--> - <gpds-card-section - class="col-12 col-lg" - header="Identification"> - <ng-template> - <div class="card-body card-section-body"> - + <div class="row align-items-center"> + + <!--Section for the image representing the germplasm and the details about this image--> + <div class="col-auto field" *ngIf="germplasmGnpis.photo && germplasmGnpis.photo.thumbnailFileName"> + <figure class="figure"> + <img + [src]="IMAGES_SIREGAL_URL +'/' + germplasmGnpis.holdingGenbank.instituteCode + '/' + germplasmGnpis.photo.thumbnailFileName" + class="img-fluid"> + <figcaption class="figure-caption"> + <a class="btn popovers" data-boundary="window" placement="right" [ngbPopover]="imageTemplate" + [popoverTitle]="germplasmGnpis.photo.thumbnailFileName" container="body"> + Click to see more details. + </a> + </figcaption> + </figure> + + <ng-template #imageTemplate> + <div class="card ngb-popover-window "> + <img class="card-img-top" + [src]="IMAGES_SIREGAL_URL + '/' + germplasmGnpis.holdingGenbank.instituteCode + '/' + germplasmGnpis.photo.fileName" + alt="" width="250px"> + <div class="card-body"> <gpds-card-row - label="Germplasm name" - [value]="germplasmGnpis.germplasmName"> + label="Name" + [value]="germplasmGnpis.photo.photoName"> </gpds-card-row> <gpds-card-row - label="Permanent Unique Identifier" - [value]="germplasmGnpis.germplasmPUI"> + label="Description" + [value]="germplasmGnpis.photo.description"> </gpds-card-row> <gpds-card-row - label="Accession number" - [value]="germplasmGnpis.accessionNumber"> + label="Copyright" + [value]="germplasmGnpis.photo.copyright"> </gpds-card-row> + </div> + </div> + </ng-template> + </div> - <gpds-card-row - label="Acquisition date" - [test]="germplasmGnpis.acquisitionDate"> - <ng-template> - {{ germplasmGnpis.acquisitionDate | amParse:'YYYYMMDD' | amDateFormat:'YYYY-MM-DD' }} - </ng-template> - </gpds-card-row> + <!--Section for the information about the identification of the germplasm--> + <gpds-card-section + class="col-12 col-lg" + header="Identification"> + <ng-template> + <div class="card-body card-section-body"> - <gpds-card-row - label="Seed source" - [value]="germplasmGnpis.seedSource"> - </gpds-card-row> + <gpds-card-row + label="Germplasm name" + [value]="germplasmGnpis.germplasmName"> + </gpds-card-row> - <gpds-card-row - label="Genetic nature" - [value]="germplasmGnpis.geneticNature"> - </gpds-card-row> + <gpds-card-row + label="Permanent Unique Identifier" + [value]="germplasmGnpis.germplasmPUI"> + </gpds-card-row> - <gpds-card-row - label="Accession synonyms" - [test]="germplasmGnpis.synonyms && germplasmGnpis.synonyms.length > 0"> - <ng-template> - {{ germplasmGnpis.synonyms.join(', ') }} - </ng-template> - </gpds-card-row> + <gpds-card-row + label="Accession number" + [value]="germplasmGnpis.accessionNumber"> + </gpds-card-row> - <gpds-card-row - label="Taxon" - [test]="germplasmGnpis.genus || germplasmGnpis.species || germplasmGnpis.subtaxa"> - <ng-template> - <i>{{ germplasmGnpis.genus }} {{ germplasmGnpis.species }} {{ germplasmGnpis.subtaxa }}</i> - {{ germplasmGnpis.speciesAuthority ? '(' + germplasmGnpis.speciesAuthority + ')' : '' }} - </ng-template> - </gpds-card-row> + <gpds-card-row + label="Acquisition date" + [test]="germplasmGnpis.acquisitionDate"> + <ng-template> + {{ germplasmGnpis.acquisitionDate | amParse:'YYYYMMDD' | amDateFormat:'YYYY-MM-DD' }} + </ng-template> + </gpds-card-row> + <gpds-card-row + label="Seed source" + [value]="germplasmGnpis.seedSource"> + </gpds-card-row> - <gpds-card-row - label="Taxon common names" - [test]="germplasmGnpis.taxonCommonNames && germplasmGnpis.taxonCommonNames.length > 0"> - <ng-template> - {{ germplasmGnpis.taxonCommonNames.join(', ') }} - </ng-template> - </gpds-card-row> + <gpds-card-row + label="Genetic nature" + [value]="germplasmGnpis.geneticNature"> + </gpds-card-row> + <gpds-card-row + label="Accession synonyms" + [test]="germplasmGnpis.synonyms && germplasmGnpis.synonyms.length > 0"> + <ng-template> + {{ germplasmGnpis.synonyms.join(', ') }} + </ng-template> + </gpds-card-row> - <gpds-card-row - label="Taxon synonyms" - [test]="germplasmGnpis.taxonSynonyms && germplasmGnpis.taxonSynonyms.length > 0"> - <ng-template> - <i>{{ germplasmGnpis.taxonSynonyms.join(', ') }}</i> - </ng-template> - </gpds-card-row> + <gpds-card-row + label="Taxon" + [test]="germplasmGnpis.genus || germplasmGnpis.species || germplasmGnpis.subtaxa"> + <ng-template> + <i>{{ germplasmGnpis.genus }} {{ germplasmGnpis.species }} {{ germplasmGnpis.subtaxa }}</i> + {{ germplasmGnpis.speciesAuthority ? '(' + germplasmGnpis.speciesAuthority + ')' : '' }} + </ng-template> + </gpds-card-row> - <gpds-card-row - label="Pedigree" - [value]="germplasmGnpis.pedigree"> - </gpds-card-row> - <gpds-card-row - label="Biological status" - [value]="germplasmGnpis.biologicalStatusOfAccessionCode"> - </gpds-card-row> + <gpds-card-row + label="Taxon common names" + [test]="germplasmGnpis.taxonCommonNames && germplasmGnpis.taxonCommonNames.length > 0"> + <ng-template> + {{ germplasmGnpis.taxonCommonNames.join(', ') }} + </ng-template> + </gpds-card-row> - <gpds-card-row - label="Comments" - [value]="germplasmGnpis.comment"> - </gpds-card-row> - </div> - </ng-template> - </gpds-card-section> - </div> + <gpds-card-row + label="Taxon synonyms" + [test]="germplasmGnpis.taxonSynonyms && germplasmGnpis.taxonSynonyms.length > 0"> + <ng-template> + <i>{{ germplasmGnpis.taxonSynonyms.join(', ') }}</i> + </ng-template> + </gpds-card-row> + <gpds-card-row + label="Pedigree" + [value]="germplasmGnpis.pedigree"> + </gpds-card-row> - <!--Templates for gerplasm card--> - <ng-template #holdingInstituteTemplate> + <gpds-card-row + label="Biological status" + [value]="germplasmGnpis.biologicalStatusOfAccessionCode"> + </gpds-card-row> - <gpds-card-row - label="Institute name" - [value]="germplasmGnpis.holdingInstitute.instituteName"> - </gpds-card-row> + <gpds-card-row + label="Comments" + [value]="germplasmGnpis.comment"> + </gpds-card-row> - <gpds-card-row - label="FAO code" - [value]="germplasmGnpis.holdingInstitute.instituteCode"> - </gpds-card-row> + </div> + </ng-template> + </gpds-card-section> + </div> - <gpds-card-row - label="Acronym" - [value]="germplasmGnpis.holdingInstitute.acronym"> - </gpds-card-row> - <gpds-card-row - label="Organisation" - [value]="germplasmGnpis.holdingInstitute.organisation"> - </gpds-card-row> + <!--Templates for gerplasm card--> + <ng-template #holdingInstituteTemplate> - <gpds-card-row - label="Institute type" - [value]="germplasmGnpis.holdingInstitute.instituteType"> - </gpds-card-row> + <gpds-card-row + label="Institute name" + [value]="germplasmGnpis.holdingInstitute.instituteName"> + </gpds-card-row> - <gpds-card-row - label="Website" - [value]="germplasmGnpis.holdingInstitute.webSite"> - </gpds-card-row> + <gpds-card-row + label="FAO code" + [value]="germplasmGnpis.holdingInstitute.instituteCode"> + </gpds-card-row> + <gpds-card-row + label="Acronym" + [value]="germplasmGnpis.holdingInstitute.acronym"> + </gpds-card-row> - <gpds-card-row - label="Address" - [value]="germplasmGnpis.holdingInstitute.address"> - </gpds-card-row> + <gpds-card-row + label="Organisation" + [value]="germplasmGnpis.holdingInstitute.organisation"> + </gpds-card-row> - </ng-template> + <gpds-card-row + label="Institute type" + [value]="germplasmGnpis.holdingInstitute.instituteType"> + </gpds-card-row> + <gpds-card-row + label="Website" + [value]="germplasmGnpis.holdingInstitute.webSite"> + </gpds-card-row> - <ng-template #BreederInstituteTemplate> - <gpds-card-row - label="Organisation" - [value]="germplasmGnpis.breeder.institute.organisation"> - </gpds-card-row> + <gpds-card-row + label="Address" + [value]="germplasmGnpis.holdingInstitute.address"> + </gpds-card-row> - <gpds-card-row - label="Acronym" - [value]="germplasmGnpis.breeder.institute.acronym"> - </gpds-card-row> + </ng-template> - <gpds-card-row - label="Code" - [value]="germplasmGnpis.breeder.institute.instituteCode"> - </gpds-card-row> - <gpds-card-row - label="Type" - [value]="germplasmGnpis.breeder.institute.instituteType"> - </gpds-card-row> + <ng-template #BreederInstituteTemplate> - <gpds-card-row - label="Link" - [test]="germplasmGnpis.breeder.institute.webSite"> - <ng-template> - <a [href]="germplasmGnpis.breeder.institute.webSite"> - {{ germplasmGnpis.breeder.institute.webSite }} - </a> - </ng-template> - </gpds-card-row> + <gpds-card-row + label="Organisation" + [value]="germplasmGnpis.breeder.institute.organisation"> + </gpds-card-row> - <gpds-card-row - label="Address" - [value]="germplasmGnpis.breeder.institute.address"> - </gpds-card-row> + <gpds-card-row + label="Acronym" + [value]="germplasmGnpis.breeder.institute.acronym"> + </gpds-card-row> - </ng-template> + <gpds-card-row + label="Code" + [value]="germplasmGnpis.breeder.institute.instituteCode"> + </gpds-card-row> + <gpds-card-row + label="Type" + [value]="germplasmGnpis.breeder.institute.instituteType"> + </gpds-card-row> - <ng-template #CollectorInstituteTemplate> + <gpds-card-row + label="Link" + [test]="germplasmGnpis.breeder.institute.webSite"> + <ng-template> + <a [href]="germplasmGnpis.breeder.institute.webSite"> + {{ germplasmGnpis.breeder.institute.webSite }} + </a> + </ng-template> + </gpds-card-row> - <gpds-card-row - label="Institute name" - [value]="germplasmGnpis.collector.instituteName"> - </gpds-card-row> + <gpds-card-row + label="Address" + [value]="germplasmGnpis.breeder.institute.address"> + </gpds-card-row> - <gpds-card-row - label="Acronym" - [value]="germplasmGnpis.collector.acronym"> - </gpds-card-row> + </ng-template> - <gpds-card-row - label="FAO code" - [value]="germplasmGnpis.collector.instituteCode"> - </gpds-card-row> - <gpds-card-row - label="Organisation" - [value]="germplasmGnpis.collector.organisation"> - </gpds-card-row> + <ng-template #CollectorInstituteTemplate> - <gpds-card-row - label="Link" - [test]="germplasmGnpis.collector.institute.webSite"> - <ng-template> - <a [href]="germplasmGnpis.collector.institute.webSite"> - {{ germplasmGnpis.collector.institute.webSite }} - </a> - </ng-template> - </gpds-card-row> + <gpds-card-row + label="Institute name" + [value]="germplasmGnpis.collector.instituteName"> + </gpds-card-row> - <gpds-card-row - label="Address" - [value]="germplasmGnpis.collector.institute.address"> - </gpds-card-row> + <gpds-card-row + label="Acronym" + [value]="germplasmGnpis.collector.acronym"> + </gpds-card-row> - </ng-template> + <gpds-card-row + label="FAO code" + [value]="germplasmGnpis.collector.instituteCode"> + </gpds-card-row> + <gpds-card-row + label="Organisation" + [value]="germplasmGnpis.collector.organisation"> + </gpds-card-row> - <!--Section for the information about the holding of the germplasm--> - <gpds-card-section - header="Holding" - [test]="germplasmGnpis.holdingInstitute"> + <gpds-card-row + label="Link" + [test]="germplasmGnpis.collector.institute.webSite"> <ng-template> - <div class="card-body card-section-body"> - - - <gpds-card-row - label="Institution"> - <ng-template> - <a class="popovers" data-boundary="window" placement="top" - [ngbPopover]="holdingInstituteTemplate" - [popoverTitle]="germplasmGnpis.holdingInstitute.instituteName" - container="body"> - {{ germplasmGnpis.holdingInstitute.instituteName }}</a> - </ng-template> - </gpds-card-row> - - <gpds-card-row - label="Stock center name" - [test]="germplasmGnpis.holdingGenbank.instituteName"> - <ng-template> - <ng-container *ngIf="germplasmGnpis.holdingGenbank.webSite"> - <a [href]="germplasmGnpis.holdingGenbank.webSite"> - {{ germplasmGnpis.holdingGenbank.instituteName }} - </a> - </ng-container> - <ng-container *ngIf="!germplasmGnpis.holdingGenbank.webSite"> - {{ germplasmGnpis.holdingGenbank.instituteName }} - </ng-container> - </ng-template> - </gpds-card-row> - - <gpds-card-row - label="Presence status" - [value]="germplasmGnpis.presenceStatus"> - </gpds-card-row> - - </div> + <a [href]="germplasmGnpis.collector.institute.webSite"> + {{ germplasmGnpis.collector.institute.webSite }} + </a> </ng-template> - </gpds-card-section> - - - <gpds-card-section - header="Origin" - [test]="testOrigin()"> - <ng-template> - <div class="card-body card-section-body"> - - <gpds-card-row - label="Geographical origin" - [test]="germplasmGnpis.originSite && germplasmGnpis.originSite.siteName"> - <ng-template> - <a [routerLink]="['/sites/', germplasmGnpis.originSite.siteId]"> - {{ germplasmGnpis.originSite.siteName }} + </gpds-card-row> + + <gpds-card-row + label="Address" + [value]="germplasmGnpis.collector.institute.address"> + </gpds-card-row> + + </ng-template> + + + <!--Section for the information about the holding of the germplasm--> + <gpds-card-section + header="Holding" + [test]="germplasmGnpis.holdingInstitute"> + <ng-template> + <div class="card-body card-section-body"> + + <gpds-card-row + label="Institution"> + <ng-template> + <a class="popovers" data-boundary="window" placement="top" + [ngbPopover]="holdingInstituteTemplate" + [popoverTitle]="germplasmGnpis.holdingInstitute.instituteName" + container="body"> + {{ germplasmGnpis.holdingInstitute.instituteName }}</a> + </ng-template> + </gpds-card-row> + + <gpds-card-row + label="Stock center name" + [test]="germplasmGnpis.holdingGenbank.instituteName"> + <ng-template> + <ng-container *ngIf="germplasmGnpis.holdingGenbank.webSite"> + <a [href]="germplasmGnpis.holdingGenbank.webSite"> + {{ germplasmGnpis.holdingGenbank.instituteName }} </a> - </ng-template> - </gpds-card-row> + </ng-container> + <ng-container *ngIf="!germplasmGnpis.holdingGenbank.webSite"> + {{ germplasmGnpis.holdingGenbank.instituteName }} + </ng-container> + </ng-template> + </gpds-card-row> - <gpds-card-row - label="Collecting" - [test]="testCollectorInstituteObject() || testCollectorInstituteFields() || (germplasmGnpis.collectingSite && germplasmGnpis.collectingSite.siteName)"> - <ng-template> + <gpds-card-row + label="Presence status" + [value]="germplasmGnpis.presenceStatus"> + </gpds-card-row> - <gpds-card-row - label="Institution" - [test]="germplasmGnpis.collector.institute && germplasmGnpis.collector.institute.instituteName"> - <ng-template> - <a class="popovers" placement="top" - [ngbPopover]="CollectorInstituteTemplate" - [popoverTitle]="germplasmGnpis.collector.institute.instituteName"> - {{ germplasmGnpis.collector.institute.instituteName }} - </a> - </ng-template> - </gpds-card-row> + </div> + </ng-template> + </gpds-card-section> - <gpds-card-row - label="Accession Creation date" - [test]="germplasmGnpis.collector.accessionCreationDate"> - <ng-template> - {{ germplasmGnpis.collector.accessionCreationDate | amParse:'YYYYMMDD' | amDateFormat:'YYYY-MM-DD' }} - </ng-template> - </gpds-card-row> - <gpds-card-row - label="Accession number" - [value]="germplasmGnpis.collector.accessionNumber"> - </gpds-card-row> + <gpds-card-section + header="Origin" + [test]="testOrigin()"> + <ng-template> + <div class="card-body card-section-body"> - <gpds-card-row - label="Collectors" - [value]="germplasmGnpis.collector.collectors"> - </gpds-card-row> + <gpds-card-row + label="Geographical origin" + [test]="germplasmGnpis.originSite && germplasmGnpis.originSite.siteName"> + <ng-template> + <a [routerLink]="['/sites/', germplasmGnpis.originSite.siteId]"> + {{ germplasmGnpis.originSite.siteName }} + </a> + </ng-template> + </gpds-card-row> - <gpds-card-row - label="Distribution status" - [value]="germplasmGnpis.collector.distributionStatus"> - </gpds-card-row> + <gpds-card-row + label="Collecting" + [test]="testCollectorInstituteObject() || testCollectorInstituteFields() || (germplasmGnpis.collectingSite && germplasmGnpis.collectingSite.siteName)"> + <ng-template> - <gpds-card-row - label="Germplasm Permanent Unique Identifier" - [value]="germplasmGnpis.collector.germplasmPUI"> - </gpds-card-row> + <gpds-card-row + label="Institution" + [test]="germplasmGnpis.collector.institute && germplasmGnpis.collector.institute.instituteName"> + <ng-template> + <a class="popovers" placement="top" + [ngbPopover]="CollectorInstituteTemplate" + [popoverTitle]="germplasmGnpis.collector.institute.instituteName"> + {{ germplasmGnpis.collector.institute.instituteName }} + </a> + </ng-template> + </gpds-card-row> - <gpds-card-row - label="Material type" - [value]="germplasmGnpis.collector.materialType"> - </gpds-card-row> + <gpds-card-row + label="Accession Creation date" + [test]="germplasmGnpis.collector.accessionCreationDate"> + <ng-template> + {{ germplasmGnpis.collector.accessionCreationDate | amParse:'YYYYMMDD' | amDateFormat:'YYYY-MM-DD' }} + </ng-template> + </gpds-card-row> - <gpds-card-row - label="Collecting site" - [test]="germplasmGnpis.collectingSite && germplasmGnpis.collectingSite.siteName"> - <ng-template> - <a [routerLink]="['/sites/', germplasmGnpis.collectingSite.siteId]"> - {{ germplasmGnpis.collectingSite.siteName }} - </a> - </ng-template> - </gpds-card-row> + <gpds-card-row + label="Accession number" + [test]="germplasmGnpis.collector && germplasmGnpis.collector.accessionNumber"> + <ng-template> + {{ germplasmGnpis.collector.accessionNumber }} + </ng-template> + </gpds-card-row> - </ng-template> - </gpds-card-row> + <gpds-card-row + label="Collectors" + [test]="germplasmGnpis.collector && germplasmGnpis.collector.collectors"> + <ng-template> + {{ germplasmGnpis.collector.collectors }} + </ng-template> + </gpds-card-row> + <gpds-card-row + label="Distribution status" + [test]="germplasmGnpis.collector && germplasmGnpis.collector.distributionStatus"> + <ng-template> + {{ germplasmGnpis.collector.distributionStatus }} + </ng-template> + </gpds-card-row> - <gpds-card-row - label="Breeder" - [test]="germplasmGnpis.breeder"> - <ng-template> + <gpds-card-row + label="Germplasm Permanent Unique Identifier" + [test]="germplasmGnpis.collector && germplasmGnpis.collector.germplasmPUI"> + <ng-template> + {{ germplasmGnpis.collector.germplasmPUI }} + </ng-template> + </gpds-card-row> - <gpds-card-row - label="Institute" - [test]="germplasmGnpis.breeder.institute && germplasmGnpis.breeder.institute.instituteName"> - <ng-template> - <!--TODO : Fix the issue with the overflow link (issue 13)--> - <a class="popovers" placement="top" - [ngbPopover]="BreederInstituteTemplate" - [popoverTitle]="germplasmGnpis.breeder.institute.instituteName"> - {{ germplasmGnpis.breeder.institute.instituteName }} {{ germplasmGnpis.breeder.institute.instituteCode }} - </a> - </ng-template> - </gpds-card-row> + <gpds-card-row + label="Material type" + [test]="germplasmGnpis.collector && germplasmGnpis.collector.materialType"> + <ng-template> + {{ germplasmGnpis.collector.materialType }} + </ng-template> + </gpds-card-row> - <gpds-card-row - label="Accession creation date" - [test]="germplasmGnpis.breeder.accessionCreationDate "> - <ng-template> - {{ germplasmGnpis.breeder.accessionCreationDate | amParse:'YYYYMMDD' | amDateFormat:'YYYY-MM-DD' }} - </ng-template> - </gpds-card-row> + <gpds-card-row + label="Collecting site" + [test]="germplasmGnpis.collectingSite && germplasmGnpis.collectingSite.siteName"> + <ng-template> + <a [routerLink]="['/sites/', germplasmGnpis.collectingSite.siteId]"> + {{ germplasmGnpis.collectingSite.siteName }} + </a> + </ng-template> + </gpds-card-row> - <gpds-card-row - label="Accession number" - [value]="germplasmGnpis.breeder.accessionNumber"> - </gpds-card-row> + </ng-template> + </gpds-card-row> - <gpds-card-row - label="germplasm Permanent Unique Identifier" - [value]="germplasmGnpis.breeder.germplasmPUI"> - </gpds-card-row> - <gpds-card-row - label="Registration year" - [value]="germplasmGnpis.breeder.registrationYear"> - </gpds-card-row> + <gpds-card-row + label="Breeder" + [test]="germplasmGnpis.breeder"> + <ng-template> - <gpds-card-row - label="Deregistration year" - [value]="germplasmGnpis.breeder.deregistrationYear"> - </gpds-card-row> + <gpds-card-row + label="Institute" + [test]="germplasmGnpis.breeder.institute && germplasmGnpis.breeder.institute.instituteName"> + <ng-template> + <!--TODO : Fix the issue with the overflow link (issue 13)--> + <a class="popovers" placement="top" + [ngbPopover]="BreederInstituteTemplate" + [popoverTitle]="germplasmGnpis.breeder.institute.instituteName"> + {{ germplasmGnpis.breeder.institute.instituteName }} {{ germplasmGnpis.breeder.institute.instituteCode }} + </a> + </ng-template> + </gpds-card-row> - <gpds-card-row - label="Distribution status" - [value]="germplasmGnpis.breeder.distributionStatus"> - </gpds-card-row> + <gpds-card-row + label="Accession creation date" + [test]="germplasmGnpis.breeder.accessionCreationDate "> + <ng-template> + {{ germplasmGnpis.breeder.accessionCreationDate | amParse:'YYYYMMDD' | amDateFormat:'YYYY-MM-DD' }} + </ng-template> + </gpds-card-row> - </ng-template> - </gpds-card-row> + <gpds-card-row + label="Accession number" + [value]="germplasmGnpis.breeder.accessionNumber"> + </gpds-card-row> + <gpds-card-row + label="germplasm Permanent Unique Identifier" + [value]="germplasmGnpis.breeder.germplasmPUI"> + </gpds-card-row> - <gpds-card-row - label="Donation" - [test]="germplasmGnpis.donors && germplasmGnpis.donors.length > 0"> - <ng-template> - <ng-container - *ngFor="let donor of germplasmGnpis.donors"> - - <!--Template for the donor popover--> - <ng-template #DonorInstituteTemplate> - - <gpds-card-row - label="Code" - [value]="donor.donorInstitute.instituteCode"> - </gpds-card-row> - - <gpds-card-row - label="Acronym" - [value]="donor.donorInstitute.acronym"> - </gpds-card-row> - - <gpds-card-row - label="Organisation" - [value]="donor.donorInstitute.organisation"> - </gpds-card-row> - - <gpds-card-row - label="Type" - [value]="donor.donorInstitute.instituteType"> - </gpds-card-row> - - <gpds-card-row - label="Address" - [value]="donor.donorInstitute.address"> - </gpds-card-row> - - <gpds-card-row - label="Website" - [test]="donor.donorInstitute.webSite"> - <ng-template> - <a [href]=" donor.donorInstitute.webSite "> - {{ donor.donorInstitute.webSite }} - </a> - </ng-template> - </gpds-card-row> - </ng-template> + <gpds-card-row + label="Registration year" + [value]="germplasmGnpis.breeder.registrationYear"> + </gpds-card-row> + <gpds-card-row + label="Deregistration year" + [value]="germplasmGnpis.breeder.deregistrationYear"> + </gpds-card-row> - <div> - <gpds-card-row - label="Institute name" - [test]="donor.donorInstitute.instituteName"> - <ng-template> - <a class="popovers" placement="top" - [ngbPopover]="DonorInstituteTemplate" - [popoverTitle]="donor.donorInstitute.instituteName"> - {{ donor.donorInstitute.instituteName }} - </a> - </ng-template> - </gpds-card-row> - - <gpds-card-row - label="Donation date" - [test]="donor.donationDate"> - <ng-template> - {{ donor.donationDate | amParse:'YYYYMMDD' | amDateFormat:'YYYY-MM-DD' }} - </ng-template> - </gpds-card-row> - - <gpds-card-row - label="Donor Accession Number" - [value]="donor.donorAccessionNumber"> - </gpds-card-row> - - <gpds-card-row - label="Donor germplasm Permanent Unique Identifier" - [value]="donor.donorGermplasmPUI"> - </gpds-card-row> - - <gpds-card-row - label="Donor institution code" - [value]="donor.donorInstituteCode"> - </gpds-card-row> - - </div> + <gpds-card-row + label="Distribution status" + [value]="germplasmGnpis.breeder.distributionStatus"> + </gpds-card-row> - </ng-container> - </ng-template> - </gpds-card-row> + </ng-template> + </gpds-card-row> - </div> - </ng-template> - </gpds-card-section> - <gpds-card-section - header="Distribution" - [test]="germplasmGnpis.distributors && germplasmGnpis.distributors.length>0"> - <ng-template> + <gpds-card-row + label="Donation" + [test]="germplasmGnpis.donors && germplasmGnpis.donors.length > 0"> + <ng-template> + <ng-container + *ngFor="let donor of germplasmGnpis.donors"> - <gpds-card-table - [headers]="[ - 'Institute', - 'Accession number', - 'Distribution status' - ]" - [rows]="germplasmGnpis.distributors"> - <ng-template let-row> - <tr> - <ng-template #InstituteTemplate> + <!--Template for the donor popover--> + <ng-template #DonorInstituteTemplate> <gpds-card-row - label="FAO code" - [value]="row.institute.instituteCode"> + label="Code" + [value]="donor.donorInstitute.instituteCode"> </gpds-card-row> <gpds-card-row label="Acronym" - [value]="row.institute.acronym"> + [value]="donor.donorInstitute.acronym"> </gpds-card-row> <gpds-card-row label="Organisation" - [value]="row.institute.organisation"> + [value]="donor.donorInstitute.organisation"> </gpds-card-row> <gpds-card-row - label="Institute type" - [value]="row.institute.instituteType"> + label="Type" + [value]="donor.donorInstitute.instituteType"> + </gpds-card-row> + + <gpds-card-row + label="Address" + [value]="donor.donorInstitute.address"> </gpds-card-row> <gpds-card-row label="Website" - [test]="row.institute.webSite"> + [test]="donor.donorInstitute.webSite"> <ng-template> - <a [href]="row.institute.webSite"> - {{ row.institute.webSite }} + <a [href]=" donor.donorInstitute.webSite "> + {{ donor.donorInstitute.webSite }} </a> </ng-template> </gpds-card-row> - + </ng-template> <gpds-card-row - label="Address" - [value]="row.institute.address"> + label="Institute name" + [test]="donor.donorInstitute.instituteName"> + <ng-template> + <a class="popovers" placement="top" + [ngbPopover]="DonorInstituteTemplate" + [popoverTitle]="donor.donorInstitute.instituteName"> + {{ donor.donorInstitute.instituteName }} + </a> + </ng-template> </gpds-card-row> - </ng-template> - - <td> - <a class="popovers" placement="top" - [ngbPopover]="InstituteTemplate" - [popoverTitle]="row.institute.instituteName"> - {{ row.institute.instituteName }} - </a> - </td> - <td>{{ row.accessionNumber }}</td> - <td>{{ row.distributionStatus }}</td> - </tr> - </ng-template> - - </gpds-card-table> - - </ng-template> - </gpds-card-section> - - <gpds-card-section - header="Genealogy" - [test]="testPedigree() || testProgeny()"> - <ng-template> - <div class="card-body card-section-body"> + <gpds-card-row + label="Donation date" + [test]="donor.donationDate"> + <ng-template> + {{ donor.donationDate | amParse:'YYYYMMDD' | amDateFormat:'YYYY-MM-DD' }} + </ng-template> + </gpds-card-row> - <gpds-card-row - label="Crossing plan" - [test]="germplasmPedigree && germplasmPedigree.crossingPlan"> - <ng-template> - {{ germplasmPedigree.crossingPlan }} - </ng-template> - </gpds-card-row> + <gpds-card-row + label="Donor Accession Number" + [value]="donor.donorAccessionNumber"> + </gpds-card-row> - <gpds-card-row - label="Crossing year" - [test]="germplasmPedigree && germplasmPedigree.crossingYear"> - <ng-template> - {{ germplasmPedigree.crossingYear }} - </ng-template> - </gpds-card-row> + <gpds-card-row + label="Donor germplasm Permanent Unique Identifier" + [value]="donor.donorGermplasmPUI"> + </gpds-card-row> - <gpds-card-row - label="Family code" - [test]="germplasmPedigree && germplasmPedigree.familyCode"> - <ng-template> - {{ germplasmPedigree.familyCode }} - </ng-template> - </gpds-card-row> + <gpds-card-row + label="Donor institution code" + [value]="donor.donorInstituteCode"> + </gpds-card-row> + </ng-container> + </ng-template> + </gpds-card-row> - <gpds-card-row - label="Parent accessions" - [test]="germplasmPedigree && (germplasmPedigree.parent1Name || germplasmPedigree.parent2Name)"> + </div> + </ng-template> + </gpds-card-section> - <ng-template> + <gpds-card-section + header="Distribution" + [test]="germplasmGnpis.distributors && germplasmGnpis.distributors.length>0"> + <ng-template> - <gpds-card-row - label="Mother" - [test]="germplasmPedigree && (germplasmPedigree.parent1Type && germplasmPedigree.parent1Type == 'FEMALE')"> - <ng-template> - <a [routerLink]="['/germplasm']" - [queryParams]="{id:germplasmPedigree.parent1DbId}"> - {{ germplasmPedigree.parent1Name }} - </a> - </ng-template> - </gpds-card-row> + <gpds-card-table + [headers]="[ + 'Institute', + 'Accession number', + 'Distribution status' + ]" + [rows]="germplasmGnpis.distributors"> + <ng-template let-row> + <tr> + <ng-template #InstituteTemplate> <gpds-card-row - label="Father" - [test]="germplasmPedigree && (germplasmPedigree.parent1Type && germplasmPedigree.parent1Type == 'MALE')"> - <ng-template> - <a [routerLink]="['/germplasm']" - [queryParams]="{id:germplasmPedigree.parent1DbId}"> - {{ germplasmPedigree.parent1Name }} - </a> - </ng-template> + label="FAO code" + [value]="row.institute.instituteCode"> </gpds-card-row> <gpds-card-row - label="Population" - [test]="germplasmPedigree && (germplasmPedigree.parent1Type && germplasmPedigree.parent1Type == 'POPULATION')"> - <ng-template> - {{ germplasmPedigree.parent1Name }} - </ng-template> + label="Acronym" + [value]="row.institute.acronym"> </gpds-card-row> <gpds-card-row - label="SELF" - [test]="germplasmPedigree && (germplasmPedigree.parent1Type == 'SELF')"> - <ng-template> - Self - </ng-template> + label="Organisation" + [value]="row.institute.organisation"> </gpds-card-row> - <gpds-card-row - label="Mother" - [test]="germplasmPedigree && (germplasmPedigree.parent2Type && germplasmPedigree.parent2Type == 'FEMALE')"> - <ng-template> - <a [routerLink]="['/germplasm']" - [queryParams]="{id:germplasmPedigree.parent2DbId}"> - {{ germplasmPedigree.parent2Name }} - </a> - </ng-template> + label="Institute type" + [value]="row.institute.instituteType"> </gpds-card-row> <gpds-card-row - label="Father" - [test]="germplasmPedigree && (germplasmPedigree.parent2Type && germplasmPedigree.parent2Type == 'MALE')"> + label="Website" + [test]="row.institute.webSite"> <ng-template> - <a [routerLink]="['/germplasm']" - [queryParams]="{id:germplasmPedigree.parent2DbId}"> - {{ germplasmPedigree.parent2Name }} + <a [href]="row.institute.webSite"> + {{ row.institute.webSite }} </a> </ng-template> </gpds-card-row> - <gpds-card-row - label="Population" - [test]="germplasmPedigree && (germplasmPedigree.parent2Type && germplasmPedigree.parent2Type == 'POPULATION')"> - <ng-template> - {{ germplasmPedigree.parent2Name }} - </ng-template> - </gpds-card-row> <gpds-card-row - label="SELF" - [test]="germplasmPedigree && (germplasmPedigree.parent2Type == 'SELF')"> - <ng-template> - Self - </ng-template> + label="Address" + [value]="row.institute.address"> </gpds-card-row> - </ng-template> - </gpds-card-row> - <gpds-card-row - label="Sibling accessions" - [test]="germplasmPedigree && (germplasmPedigree.siblings && germplasmPedigree.siblings.length > 0)"> - <ng-template> + <td> + <a class="popovers" placement="top" + [ngbPopover]="InstituteTemplate" + [popoverTitle]="row.institute.instituteName"> + {{ row.institute.instituteName }} + </a> + </td> + <td>{{ row.accessionNumber }}</td> + <td>{{ row.distributionStatus }}</td> + </tr> + </ng-template> - <div class="content-overflow"> - <ng-container *ngFor="let sibling of germplasmPedigree.siblings"> - <a [routerLink]="['/germplasm']" [queryParams]="{id:sibling.germplasmDbId }"> - {{ sibling.defaultDisplayName }} - </a>, - </ng-container> - </div> + </gpds-card-table> - </ng-template> - </gpds-card-row> + </ng-template> + </gpds-card-section> - <gpds-card-row - label="Descendant :" - [test]="testProgeny()"> - </gpds-card-row> - <div class="content-overflow-big"> - <ng-container *ngFor="let child of germplasmProgeny"> + <gpds-card-section + header="Genealogy" + [test]="testPedigree() || testProgeny()"> + <ng-template> + <div class="card-body card-section-body"> - <gpds-card-row class="text" - [label]="'child(ren) of ' + child.firstParentName + ' and ' + child.secondParentName" - [test]="testProgeny()"> - <ng-template> + <gpds-card-row + label="Crossing plan" + [test]="germplasmPedigree && germplasmPedigree.crossingPlan"> + <ng-template> + {{ germplasmPedigree.crossingPlan }} + </ng-template> + </gpds-card-row> + + <gpds-card-row + label="Crossing year" + [test]="germplasmPedigree && germplasmPedigree.crossingYear"> + <ng-template> + {{ germplasmPedigree.crossingYear }} + </ng-template> + </gpds-card-row> - <ng-container *ngFor="let sibling of child.sibblings"> - <a [routerLink]="['/germplasm']" [queryParams]="{id:sibling.pui}"> - {{ sibling.name }} - </a>, - </ng-container> + <gpds-card-row + label="Family code" + [test]="germplasmPedigree && germplasmPedigree.familyCode"> + <ng-template> + {{ germplasmPedigree.familyCode }} + </ng-template> + </gpds-card-row> - </ng-template> - </gpds-card-row> - </ng-container> - </div> + <gpds-card-row + label="Parent accessions" + [test]="germplasmPedigree && (germplasmPedigree.parent1Name || germplasmPedigree.parent2Name)"> - </div> - </ng-template> - </gpds-card-section> + <ng-template> - <gpds-card-section - header="Evaluation Data" - [test]="germplasmAttributes && germplasmAttributes.length > 0"> - <ng-template> - <div class="card-body card-section-body"> + <gpds-card-row + label="Mother" + [test]="germplasmPedigree && (germplasmPedigree.parent1Type && germplasmPedigree.parent1Type == 'FEMALE')"> + <ng-template> + <a [routerLink]="['/germplasm']" + [queryParams]="{id:germplasmPedigree.parent1DbId}"> + {{ germplasmPedigree.parent1Name }} + </a> + </ng-template> + </gpds-card-row> - <ng-container *ngFor="let descriptor of germplasmAttributes"> <gpds-card-row - [label]="descriptor.attributeName" - [value]="descriptor.value"> + label="Father" + [test]="germplasmPedigree && (germplasmPedigree.parent1Type && germplasmPedigree.parent1Type == 'MALE')"> + <ng-template> + <a [routerLink]="['/germplasm']" + [queryParams]="{id:germplasmPedigree.parent1DbId}"> + {{ germplasmPedigree.parent1Name }} + </a> + </ng-template> </gpds-card-row> - </ng-container> - </div> - </ng-template> - </gpds-card-section> + <gpds-card-row + label="Population" + [test]="germplasmPedigree && (germplasmPedigree.parent1Type && germplasmPedigree.parent1Type == 'POPULATION')"> + <ng-template> + {{ germplasmPedigree.parent1Name }} + </ng-template> + </gpds-card-row> + <gpds-card-row + label="SELF" + [test]="germplasmPedigree && (germplasmPedigree.parent1Type == 'SELF')"> + <ng-template> + Self + </ng-template> + </gpds-card-row> - <gpds-card-section - header="Collection" - [test]="germplasmGnpis.collection && germplasmGnpis.collection.length > 0"> - <ng-template> - <div class="card-body card-section-body"> - <ng-container *ngFor="let collection of germplasmGnpis.collection"> <gpds-card-row - [label]="collection.type ? collection.name + ' (' + collection.type + ')' : collection.name"> + label="Mother" + [test]="germplasmPedigree && (germplasmPedigree.parent2Type && germplasmPedigree.parent2Type == 'FEMALE')"> <ng-template> - <a [routerLink]="['/']" - [queryParams]="{germplasmLists: collection.name, types: 'Germplasm'}"> - {{ collection.germplasmCount }} accessions + <a [routerLink]="['/germplasm']" + [queryParams]="{id:germplasmPedigree.parent2DbId}"> + {{ germplasmPedigree.parent2Name }} </a> </ng-template> </gpds-card-row> - </ng-container> - - </div> - </ng-template> - </gpds-card-section> + <gpds-card-row + label="Father" + [test]="germplasmPedigree && (germplasmPedigree.parent2Type && germplasmPedigree.parent2Type == 'MALE')"> + <ng-template> + <a [routerLink]="['/germplasm']" + [queryParams]="{id:germplasmPedigree.parent2DbId}"> + {{ germplasmPedigree.parent2Name }} + </a> + </ng-template> + </gpds-card-row> - <gpds-card-section - header="Panel" - [test]="germplasmGnpis.panel && germplasmGnpis.panel.length > 0"> - <ng-template> - <div class="card-body card-section-body"> + <gpds-card-row + label="Population" + [test]="germplasmPedigree && (germplasmPedigree.parent2Type && germplasmPedigree.parent2Type == 'POPULATION')"> + <ng-template> + {{ germplasmPedigree.parent2Name }} + </ng-template> + </gpds-card-row> - <ng-container *ngFor="let panel of germplasmGnpis.panel"> <gpds-card-row - [label]="panel.type ? panel.name + ' (' + panel.type + ')' : panel.name"> - <a [routerLink]="['/']" - [queryParams]="{germplasmLists: panel.name, types: 'Germplasm'}"> - {{ panel.germplasmCount }} accessions - </a> + label="SELF" + [test]="germplasmPedigree && (germplasmPedigree.parent2Type == 'SELF')"> + <ng-template> + Self + </ng-template> </gpds-card-row> - </ng-container> - </div> - </ng-template> - </gpds-card-section> + </ng-template> + </gpds-card-row> + + <gpds-card-row + label="Sibling accessions" + [test]="germplasmPedigree && (germplasmPedigree.siblings && germplasmPedigree.siblings.length > 0)"> + <ng-template> + + <div class="content-overflow"> + <ng-container *ngFor="let sibling of germplasmPedigree.siblings"> + <a [routerLink]="['/germplasm']" [queryParams]="{id:sibling.germplasmDbId }"> + {{ sibling.defaultDisplayName }} + </a>, + </ng-container> + </div> + </ng-template> + </gpds-card-row> - <gpds-card-section - header="Population" - [test]="germplasmGnpis.population && germplasmGnpis.population.length > 0"> - <ng-template> - <div class="card-body card-section-body card-section-body"> + <gpds-card-row + label="Descendant :" + [test]="testProgeny()"> + </gpds-card-row> - <ng-container *ngFor="let population of germplasmGnpis.population"> - <gpds-card-row - [label]="population.type ? population.name + ' (' + population.type + ')' : population.name"> + <div class="content-overflow-big"> + <ng-container *ngFor="let child of germplasmProgeny"> + + <gpds-card-row class="text" + [label]="'child(ren) of ' + child.firstParentName + ' and ' + child.secondParentName" + [test]="testProgeny()"> <ng-template> - <a [routerLink]="['/']" - [queryParams]="{germplasmLists: population.name, types: 'Germplasm'}"> - {{ population.germplasmCount }} accessions - </a> + + <ng-container *ngFor="let sibling of child.sibblings"> + <a [routerLink]="['/germplasm']" [queryParams]="{id:sibling.pui}"> + {{ sibling.name }} + </a>, + </ng-container> + + </ng-template> </gpds-card-row> </ng-container> - </div> - </ng-template> - </gpds-card-section> + + </div> + </ng-template> + </gpds-card-section> + + <gpds-card-section + header="Evaluation Data" + [test]="germplasmAttributes && germplasmAttributes.length > 0"> + <ng-template> + <div class="card-body card-section-body"> + + <ng-container *ngFor="let descriptor of germplasmAttributes"> + <gpds-card-row + [label]="descriptor.attributeName" + [value]="descriptor.value"> + </gpds-card-row> + </ng-container> + + </div> + </ng-template> + </gpds-card-section> + + + <gpds-card-section + header="Collection" + [test]="germplasmGnpis.collection && germplasmGnpis.collection.length > 0"> + <ng-template> + <div class="card-body card-section-body"> + + <ng-container *ngFor="let collection of germplasmGnpis.collection"> + <gpds-card-row + [label]="collection.type ? collection.name + ' (' + collection.type + ')' : collection.name"> + <ng-template> + <a [routerLink]="['/']" + [queryParams]="{germplasmLists: collection.name, types: 'Germplasm'}"> + {{ collection.germplasmCount }} accessions + </a> + </ng-template> + </gpds-card-row> + </ng-container> + + </div> + </ng-template> + </gpds-card-section> + + + <gpds-card-section + header="Panel" + [test]="germplasmGnpis.panel && germplasmGnpis.panel.length > 0"> + <ng-template> + <div class="card-body card-section-body"> + + <ng-container *ngFor="let panel of germplasmGnpis.panel"> + <gpds-card-row + [label]="panel.type ? panel.name + ' (' + panel.type + ')' : panel.name"> + <a [routerLink]="['/']" + [queryParams]="{germplasmLists: panel.name, types: 'Germplasm'}"> + {{ panel.germplasmCount }} accessions + </a> + </gpds-card-row> + </ng-container> + + </div> + </ng-template> + </gpds-card-section> + + + <gpds-card-section + header="Population" + [test]="germplasmGnpis.population && germplasmGnpis.population.length > 0"> + <ng-template> + <div class="card-body card-section-body card-section-body"> + + <ng-container *ngFor="let population of germplasmGnpis.population"> + <gpds-card-row + [label]="population.type ? population.name + ' (' + population.type + ')' : population.name"> + <ng-template> + <a [routerLink]="['/']" + [queryParams]="{germplasmLists: population.name, types: 'Germplasm'}"> + {{ population.germplasmCount }} accessions + </a> + </ng-template> + </gpds-card-row> + </ng-container> + + </div> + </ng-template> + </gpds-card-section> </div> diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.ts b/frontend/src/app/germplasm-card/germplasm-card.component.ts index 91dd3037..d9a55966 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.ts +++ b/frontend/src/app/germplasm-card/germplasm-card.component.ts @@ -125,8 +125,8 @@ export class GermplasmCardComponent implements OnInit { } testCollectorInstituteFields() { - return ( - this.germplasmGnpis.collector.germplasmPUI + return (this.germplasmGnpis.collector) && + (this.germplasmGnpis.collector.germplasmPUI || this.germplasmGnpis.collector.accessionNumber || this.germplasmGnpis.collector.accessionCreationDate || this.germplasmGnpis.collector.materialType -- GitLab From 4fa272eb87ca5c1f225585f79dd9124436ed7d17 Mon Sep 17 00:00:00 2001 From: jdestin <jeremy.destin@inra.fr> Date: Wed, 6 Mar 2019 15:34:30 +0100 Subject: [PATCH 07/20] feat: Add double links (external link and link to the card in the app) on result page. GNP-5490 --- .../germplasm-card/germplasm-card.component.ts | 1 - .../document/document.component.html | 4 +++- .../document/document.component.scss | 5 +++++ .../document/document.component.spec.ts | 2 +- .../result-page/document/document.component.ts | 18 +++++++++--------- 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.ts b/frontend/src/app/germplasm-card/germplasm-card.component.ts index d9a55966..b9cbcbff 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.ts +++ b/frontend/src/app/germplasm-card/germplasm-card.component.ts @@ -146,4 +146,3 @@ export class GermplasmCardComponent implements OnInit { || (this.germplasmGnpis.breeder); } } - diff --git a/frontend/src/app/result-page/document/document.component.html b/frontend/src/app/result-page/document/document.component.html index 9b1175eb..881e173b 100644 --- a/frontend/src/app/result-page/document/document.component.html +++ b/frontend/src/app/result-page/document/document.component.html @@ -10,8 +10,10 @@ <a class="title" *ngIf="getURL()" [href]="getURL()"> {{ document["schema:name"] }} </a> + </h5> + <h5> <a class="title" *ngIf="getRouterLink()" [routerLink]="getRouterLink()" [queryParams]="getQueryParam()"> - {{ document["schema:name"] }} + (go to this {{ document["@type"] }} card) </a> </h5> <span class="text-justify description"> diff --git a/frontend/src/app/result-page/document/document.component.scss b/frontend/src/app/result-page/document/document.component.scss index 2ca79221..940d9b86 100644 --- a/frontend/src/app/result-page/document/document.component.scss +++ b/frontend/src/app/result-page/document/document.component.scss @@ -1,3 +1,8 @@ + +a { + text-decoration: none; +} + .badge-source { background-color: #b54646; color: white; diff --git a/frontend/src/app/result-page/document/document.component.spec.ts b/frontend/src/app/result-page/document/document.component.spec.ts index 5f2d8366..5642ec36 100644 --- a/frontend/src/app/result-page/document/document.component.spec.ts +++ b/frontend/src/app/result-page/document/document.component.spec.ts @@ -94,7 +94,7 @@ describe('DocumentComponent', () => { tester.detectChanges(); expect(component).toBeTruthy(); - expect(tester.title).toContainText('doc_name'); + expect(tester.title).toContainText('(go to this Germplasm card)'); expect(tester.title.nativeElement['routerLink']).toEqual('/germplasm'); expect(component.getQueryParam().id).toEqual('g1'); diff --git a/frontend/src/app/result-page/document/document.component.ts b/frontend/src/app/result-page/document/document.component.ts index 69d83161..02b91a4d 100644 --- a/frontend/src/app/result-page/document/document.component.ts +++ b/frontend/src/app/result-page/document/document.component.ts @@ -22,22 +22,22 @@ export class DocumentComponent implements OnInit { needTruncation = false; opened = false; + getURL() { return this.document['schema:url'] || ''; } getRouterLink() { - if (!this.getURL()) { - for (const type of this.document['@type']) { - const cardUrl = DocumentComponent.CARD_TYPE[type]; - if (cardUrl === 'studies') { - return `/${cardUrl}/${this.document['schema:identifier']}`; - } - if (cardUrl === 'germplasm') { - return `/${cardUrl}`; - } + for (const type of this.document['@type']) { + const cardUrl = DocumentComponent.CARD_TYPE[type]; + if (cardUrl === 'studies') { + return `/${cardUrl}/${this.document['schema:identifier']}`; + } + if (cardUrl === 'germplasm') { + return `/${cardUrl}`; } } + return ''; } -- GitLab From b21eb5d700dbe77ca6f953bd083cfea99184a852 Mon Sep 17 00:00:00 2001 From: jdestin <jeremy.destin@inra.fr> Date: Thu, 7 Mar 2019 09:58:43 +0100 Subject: [PATCH 08/20] fix: Rename tab Variable into Trait. Manage the double links for URGI's study. Minor fixes. GNP-5490 --- frontend/src/app/form/form.component.html | 2 +- .../germplasm-card.component.html | 2 +- .../germplasm-card.component.ts | 29 ++++++++++++++----- .../document/document.component.html | 5 +++- .../document/document.component.ts | 5 ++++ 5 files changed, 32 insertions(+), 11 deletions(-) diff --git a/frontend/src/app/form/form.component.html b/frontend/src/app/form/form.component.html index 3df3dbe2..f0ffe680 100644 --- a/frontend/src/app/form/form.component.html +++ b/frontend/src/app/form/form.component.html @@ -10,7 +10,7 @@ <a tabindex="1" class="nav-link {{ activeTab == 'Variable' ? 'active' : ''}}" (click)="activeTab='Variable'"> - Variable + Trait </a> </li> </ul> diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.html b/frontend/src/app/germplasm-card/germplasm-card.component.html index 86e21d4d..bcdf63c0 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.html +++ b/frontend/src/app/germplasm-card/germplasm-card.component.html @@ -404,7 +404,7 @@ <gpds-card-row label="Breeder" - [test]="germplasmGnpis.breeder"> + [test]="testBreeder()"> <ng-template> <gpds-card-row diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.ts b/frontend/src/app/germplasm-card/germplasm-card.component.ts index b9cbcbff..fce0739b 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.ts +++ b/frontend/src/app/germplasm-card/germplasm-card.component.ts @@ -106,6 +106,19 @@ export class GermplasmCardComponent implements OnInit { && this.germplasmProgeny.length > 0); } + testBreeder() { + return (this.germplasmGnpis.breeder) + && (this.germplasmGnpis.breeder.institute.instituteName + || this.germplasmGnpis.breeder.germplasmPUI + || this.germplasmGnpis.breeder.accessionNumber + || this.germplasmGnpis.breeder.accessionCreationDate + || this.germplasmGnpis.breeder.materialType + || this.germplasmGnpis.breeder.collectors + || this.germplasmGnpis.breeder.registrationYear + || this.germplasmGnpis.breeder.deregistrationYear + || this.germplasmGnpis.breeder.distributionStatus); + } + testPedigree() { return (this.germplasmPedigree && (this.germplasmPedigree.parent1Name @@ -127,14 +140,14 @@ export class GermplasmCardComponent implements OnInit { testCollectorInstituteFields() { return (this.germplasmGnpis.collector) && (this.germplasmGnpis.collector.germplasmPUI - || this.germplasmGnpis.collector.accessionNumber - || this.germplasmGnpis.collector.accessionCreationDate - || this.germplasmGnpis.collector.materialType - || this.germplasmGnpis.collector.collectors - || this.germplasmGnpis.collector.registrationYear - || this.germplasmGnpis.collector.deregistrationYear - || this.germplasmGnpis.collector.distributionStatus - ); + || this.germplasmGnpis.collector.accessionNumber + || this.germplasmGnpis.collector.accessionCreationDate + || this.germplasmGnpis.collector.materialType + || this.germplasmGnpis.collector.collectors + || this.germplasmGnpis.collector.registrationYear + || this.germplasmGnpis.collector.deregistrationYear + || this.germplasmGnpis.collector.distributionStatus + ); } testOrigin() { diff --git a/frontend/src/app/result-page/document/document.component.html b/frontend/src/app/result-page/document/document.component.html index 881e173b..319bffa6 100644 --- a/frontend/src/app/result-page/document/document.component.html +++ b/frontend/src/app/result-page/document/document.component.html @@ -12,7 +12,10 @@ </a> </h5> <h5> - <a class="title" *ngIf="getRouterLink()" [routerLink]="getRouterLink()" [queryParams]="getQueryParam()"> + <a class="title" *ngIf="getRouterLink() && document['@type'] == 'Phenotyping Study'" [routerLink]="getRouterLink()"> + (go to this {{ document["@type"] }} card) + </a> + <a class="title" *ngIf="getRouterLink() && document['@type'] != 'Phenotyping Study'" [routerLink]="getRouterLink()" [queryParams]="getQueryParam()"> (go to this {{ document["@type"] }} card) </a> </h5> diff --git a/frontend/src/app/result-page/document/document.component.ts b/frontend/src/app/result-page/document/document.component.ts index 02b91a4d..96e0e571 100644 --- a/frontend/src/app/result-page/document/document.component.ts +++ b/frontend/src/app/result-page/document/document.component.ts @@ -28,9 +28,14 @@ export class DocumentComponent implements OnInit { } getRouterLink() { + const urgiStudy = this.document['schema:includedInDataCatalog']['schema:url'] === 'https://urgi.versailles.inra.fr'; for (const type of this.document['@type']) { const cardUrl = DocumentComponent.CARD_TYPE[type]; if (cardUrl === 'studies') { + if (urgiStudy) { + const studyId = this.document['@id'].replace(/urn:URGI\/study\//, ''); + return `/${cardUrl}/${studyId}`; + } return `/${cardUrl}/${this.document['schema:identifier']}`; } if (cardUrl === 'germplasm') { -- GitLab From a6db1694524b695644e750c172d9d90a6861ad7c Mon Sep 17 00:00:00 2001 From: jdestin <jeremy.destin@inra.fr> Date: Thu, 7 Mar 2019 18:45:00 +0100 Subject: [PATCH 09/20] feat: Manage fields displayed in germplasm card. Minor fixes. issue 11 --- .../germplasm-card.component.html | 862 +++++++++--------- .../germplasm-card.component.ts | 60 +- .../src/app/models/brapi.germplasm.model.ts | 7 - frontend/src/app/models/brapi.model.ts | 12 +- .../src/app/models/gnpis.germplasm.model.ts | 23 +- 5 files changed, 470 insertions(+), 494 deletions(-) diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.html b/frontend/src/app/germplasm-card/germplasm-card.component.html index bcdf63c0..f3194ad7 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.html +++ b/frontend/src/app/germplasm-card/germplasm-card.component.html @@ -1,21 +1,161 @@ <gpds-loading-spinner [loading]="loading" class="float-right"></gpds-loading-spinner> <ng-container *ngIf="germplasmGnpis"> - <h3> + <h3 class="mb-4"> + <figure *ngIf="germplasmGnpis.holdingGenbank && germplasmGnpis.holdingGenbank.instituteName"> + <img + [src]="IMAGES_BRC_URL" + align="right" /> + </figure> Germplasm: {{ germplasmGnpis.germplasmName }} </h3> + + + <!-- Display the map --> + <gpds-map *ngIf="germplasmLocations.length > 0" [locations]="germplasmLocations"></gpds-map> + <div class="row align-items-center"> + <!--Templates for gerplasm card--> + <ng-template #holdingInstituteTemplate > + + <figure *ngIf="germplasmGnpis.holdingInstitute && germplasmGnpis.holdingInstitute.logo"> + <img + [src]="IMAGES_INSTITUTION_URL + germplasmGnpis.holdingInstitute.logo" + align="middle" /> + </figure> + + <gpds-card-row + label="Code" + [value]="germplasmGnpis.holdingInstitute.instituteCode"> + </gpds-card-row> + + <gpds-card-row + label="Acronym" + [value]="germplasmGnpis.holdingInstitute.acronym"> + </gpds-card-row> + + <gpds-card-row + label="Organisation" + [value]="germplasmGnpis.holdingInstitute.organisation"> + </gpds-card-row> + + <gpds-card-row + label="Type" + [value]="germplasmGnpis.holdingInstitute.instituteType"> + </gpds-card-row> + + <gpds-card-row + label="Address" + [value]="germplasmGnpis.holdingInstitute.address"> + </gpds-card-row> + + <gpds-card-row + label="Website" + [value]="germplasmGnpis.holdingInstitute.webSite"> + </gpds-card-row> + + </ng-template> + + + <ng-template #BreederInstituteTemplate> + + <figure *ngIf="germplasmGnpis.breeder && germplasmGnpis.breeder.institute && germplasmGnpis.breeder.institute.logo"> + <img + [src]="IMAGES_INSTITUTION_URL + germplasmGnpis.breeder.institute.logo" + align="middle" /> + </figure> + + <gpds-card-row + label="Code" + [value]="germplasmGnpis.breeder.institute.instituteCode"> + </gpds-card-row> + + <gpds-card-row + label="Acronym" + [value]="germplasmGnpis.breeder.institute.acronym"> + </gpds-card-row> + + <gpds-card-row + label="Organisation" + [value]="germplasmGnpis.breeder.institute.organisation"> + </gpds-card-row> + + <gpds-card-row + label="Type" + [value]="germplasmGnpis.breeder.institute.instituteType"> + </gpds-card-row> + + <gpds-card-row + label="Address" + [value]="germplasmGnpis.breeder.institute.address"> + </gpds-card-row> + + <gpds-card-row + label="Website" + [test]="germplasmGnpis.breeder.institute.webSite"> + <ng-template> + <a [href]="germplasmGnpis.breeder.institute.webSite"> + {{ germplasmGnpis.breeder.institute.webSite }} + </a> + </ng-template> + </gpds-card-row> + + </ng-template> + + <ng-template #CollectorInstituteTemplate> + + <figure *ngIf="germplasmGnpis.collector && germplasmGnpis.collector.institute && germplasmGnpis.collector.institute.logo"> + <img + [src]="IMAGES_INSTITUTION_URL + germplasmGnpis.collector.institute.logo" + align="middle" /> + </figure> + + <gpds-card-row + label="Code" + [value]="germplasmGnpis.collector.instituteCode"> + </gpds-card-row> + + <gpds-card-row + label="Acronym" + [value]="germplasmGnpis.collector.acronym"> + </gpds-card-row> + + <gpds-card-row + label="Organisation" + [value]="germplasmGnpis.collector.organisation"> + </gpds-card-row> + + <gpds-card-row + label="Address" + [value]="germplasmGnpis.collector.institute.address"> + </gpds-card-row> + + <gpds-card-row + label="Website" + [test]="germplasmGnpis.collector.institute.webSite"> + <ng-template> + <a [href]="germplasmGnpis.collector.institute.webSite"> + {{ germplasmGnpis.collector.institute.webSite }} + </a> + </ng-template> + </gpds-card-row> + + + </ng-template> + + + <!--Section for the image representing the germplasm and the details about this image--> <div class="col-auto field" *ngIf="germplasmGnpis.photo && germplasmGnpis.photo.thumbnailFileName"> <figure class="figure"> <img - [src]="IMAGES_SIREGAL_URL +'/' + germplasmGnpis.holdingGenbank.instituteCode + '/' + germplasmGnpis.photo.thumbnailFileName" + [src]="IMAGES_ACCESSION_URL + germplasmGnpis.holdingGenbank.instituteCode + '/' + germplasmGnpis.photo.thumbnailFileName" class="img-fluid"> <figcaption class="figure-caption"> <a class="btn popovers" data-boundary="window" placement="right" [ngbPopover]="imageTemplate" - [popoverTitle]="germplasmGnpis.photo.thumbnailFileName" container="body"> + [popoverTitle]="germplasmGnpis.photo.photoName" container="body"> Click to see more details. </a> </figcaption> @@ -24,11 +164,17 @@ <ng-template #imageTemplate> <div class="card ngb-popover-window "> <img class="card-img-top" - [src]="IMAGES_SIREGAL_URL + '/' + germplasmGnpis.holdingGenbank.instituteCode + '/' + germplasmGnpis.photo.fileName" + [src]="IMAGES_ACCESSION_URL + germplasmGnpis.holdingGenbank.instituteCode + '/' + germplasmGnpis.photo.fileName" alt="" width="250px"> <div class="card-body"> + + <gpds-card-row + label="Accession name" + [value]="germplasmGnpis.germplasmName"> + </gpds-card-row> + <gpds-card-row - label="Name" + label="Photo name" [value]="germplasmGnpis.photo.photoName"> </gpds-card-row> @@ -39,7 +185,7 @@ <gpds-card-row label="Copyright" - [value]="germplasmGnpis.photo.copyright"> + [value]="'© '+germplasmGnpis.photo.copyright"> </gpds-card-row> </div> </div> @@ -58,32 +204,14 @@ [value]="germplasmGnpis.germplasmName"> </gpds-card-row> - <gpds-card-row - label="Permanent Unique Identifier" - [value]="germplasmGnpis.germplasmPUI"> - </gpds-card-row> - <gpds-card-row label="Accession number" [value]="germplasmGnpis.accessionNumber"> </gpds-card-row> <gpds-card-row - label="Acquisition date" - [test]="germplasmGnpis.acquisitionDate"> - <ng-template> - {{ germplasmGnpis.acquisitionDate | amParse:'YYYYMMDD' | amDateFormat:'YYYY-MM-DD' }} - </ng-template> - </gpds-card-row> - - <gpds-card-row - label="Seed source" - [value]="germplasmGnpis.seedSource"> - </gpds-card-row> - - <gpds-card-row - label="Genetic nature" - [value]="germplasmGnpis.geneticNature"> + label="Permanent Unique Identifier" + [value]="germplasmGnpis.germplasmPUI"> </gpds-card-row> <gpds-card-row @@ -103,7 +231,6 @@ </ng-template> </gpds-card-row> - <gpds-card-row label="Taxon common names" [test]="germplasmGnpis.taxonCommonNames && germplasmGnpis.taxonCommonNames.length > 0"> @@ -112,7 +239,6 @@ </ng-template> </gpds-card-row> - <gpds-card-row label="Taxon synonyms" [test]="germplasmGnpis.taxonSynonyms && germplasmGnpis.taxonSynonyms.length > 0"> @@ -122,13 +248,23 @@ </gpds-card-row> <gpds-card-row - label="Pedigree" - [value]="germplasmGnpis.pedigree"> + label="Biological status" + [value]="germplasmGnpis.biologicalStatusOfAccessionCode"> </gpds-card-row> <gpds-card-row - label="Biological status" - [value]="germplasmGnpis.biologicalStatusOfAccessionCode"> + label="Genetic nature" + [value]="germplasmGnpis.geneticNature"> + </gpds-card-row> + + <gpds-card-row + label="Seed source" + [value]="germplasmGnpis.seedSource"> + </gpds-card-row> + + <gpds-card-row + label="Pedigree" + [value]="germplasmGnpis.pedigree"> </gpds-card-row> <gpds-card-row @@ -141,129 +277,6 @@ </gpds-card-section> </div> - - <!--Templates for gerplasm card--> - <ng-template #holdingInstituteTemplate> - - <gpds-card-row - label="Institute name" - [value]="germplasmGnpis.holdingInstitute.instituteName"> - </gpds-card-row> - - <gpds-card-row - label="FAO code" - [value]="germplasmGnpis.holdingInstitute.instituteCode"> - </gpds-card-row> - - <gpds-card-row - label="Acronym" - [value]="germplasmGnpis.holdingInstitute.acronym"> - </gpds-card-row> - - <gpds-card-row - label="Organisation" - [value]="germplasmGnpis.holdingInstitute.organisation"> - </gpds-card-row> - - <gpds-card-row - label="Institute type" - [value]="germplasmGnpis.holdingInstitute.instituteType"> - </gpds-card-row> - - <gpds-card-row - label="Website" - [value]="germplasmGnpis.holdingInstitute.webSite"> - </gpds-card-row> - - - <gpds-card-row - label="Address" - [value]="germplasmGnpis.holdingInstitute.address"> - </gpds-card-row> - - </ng-template> - - - <ng-template #BreederInstituteTemplate> - - <gpds-card-row - label="Organisation" - [value]="germplasmGnpis.breeder.institute.organisation"> - </gpds-card-row> - - <gpds-card-row - label="Acronym" - [value]="germplasmGnpis.breeder.institute.acronym"> - </gpds-card-row> - - <gpds-card-row - label="Code" - [value]="germplasmGnpis.breeder.institute.instituteCode"> - </gpds-card-row> - - <gpds-card-row - label="Type" - [value]="germplasmGnpis.breeder.institute.instituteType"> - </gpds-card-row> - - <gpds-card-row - label="Link" - [test]="germplasmGnpis.breeder.institute.webSite"> - <ng-template> - <a [href]="germplasmGnpis.breeder.institute.webSite"> - {{ germplasmGnpis.breeder.institute.webSite }} - </a> - </ng-template> - </gpds-card-row> - - <gpds-card-row - label="Address" - [value]="germplasmGnpis.breeder.institute.address"> - </gpds-card-row> - - </ng-template> - - - <ng-template #CollectorInstituteTemplate> - - <gpds-card-row - label="Institute name" - [value]="germplasmGnpis.collector.instituteName"> - </gpds-card-row> - - <gpds-card-row - label="Acronym" - [value]="germplasmGnpis.collector.acronym"> - </gpds-card-row> - - <gpds-card-row - label="FAO code" - [value]="germplasmGnpis.collector.instituteCode"> - </gpds-card-row> - - <gpds-card-row - label="Organisation" - [value]="germplasmGnpis.collector.organisation"> - </gpds-card-row> - - <gpds-card-row - label="Link" - [test]="germplasmGnpis.collector.institute.webSite"> - <ng-template> - <a [href]="germplasmGnpis.collector.institute.webSite"> - {{ germplasmGnpis.collector.institute.webSite }} - </a> - </ng-template> - </gpds-card-row> - - <gpds-card-row - label="Address" - [value]="germplasmGnpis.collector.institute.address"> - </gpds-card-row> - - </ng-template> - - <!--Section for the information about the holding of the germplasm--> <gpds-card-section header="Holding" @@ -308,13 +321,13 @@ <gpds-card-section - header="Origin" - [test]="testOrigin()"> + header="Collecting" + [test]="checkOriginCollecting()"> <ng-template> <div class="card-body card-section-body"> <gpds-card-row - label="Geographical origin" + label="Origin site" [test]="germplasmGnpis.originSite && germplasmGnpis.originSite.siteName"> <ng-template> <a [routerLink]="['/sites/', germplasmGnpis.originSite.siteId]"> @@ -324,225 +337,188 @@ </gpds-card-row> <gpds-card-row - label="Collecting" - [test]="testCollectorInstituteObject() || testCollectorInstituteFields() || (germplasmGnpis.collectingSite && germplasmGnpis.collectingSite.siteName)"> + label="Collecting site" + [test]="germplasmGnpis.collectingSite && germplasmGnpis.collectingSite.siteName"> <ng-template> + <a [routerLink]="['/sites/', germplasmGnpis.collectingSite.siteId]"> + {{ germplasmGnpis.collectingSite.siteName }} + </a> + </ng-template> + </gpds-card-row> - <gpds-card-row - label="Institution" - [test]="germplasmGnpis.collector.institute && germplasmGnpis.collector.institute.instituteName"> - <ng-template> - <a class="popovers" placement="top" - [ngbPopover]="CollectorInstituteTemplate" - [popoverTitle]="germplasmGnpis.collector.institute.instituteName"> - {{ germplasmGnpis.collector.institute.instituteName }} - </a> - </ng-template> - </gpds-card-row> - - <gpds-card-row - label="Accession Creation date" - [test]="germplasmGnpis.collector.accessionCreationDate"> - <ng-template> - {{ germplasmGnpis.collector.accessionCreationDate | amParse:'YYYYMMDD' | amDateFormat:'YYYY-MM-DD' }} - </ng-template> - </gpds-card-row> + <gpds-card-row + label="Material type" + [test]="germplasmGnpis.collector && germplasmGnpis.collector.materialType"> + <ng-template> + {{ germplasmGnpis.collector.materialType }} + </ng-template> + </gpds-card-row> - <gpds-card-row - label="Accession number" - [test]="germplasmGnpis.collector && germplasmGnpis.collector.accessionNumber"> - <ng-template> - {{ germplasmGnpis.collector.accessionNumber }} - </ng-template> - </gpds-card-row> + <gpds-card-row + label="Collectors" + [test]="germplasmGnpis.collector && germplasmGnpis.collector.collectors"> + <ng-template> + {{ germplasmGnpis.collector.collectors }} + </ng-template> + </gpds-card-row> - <gpds-card-row - label="Collectors" - [test]="germplasmGnpis.collector && germplasmGnpis.collector.collectors"> - <ng-template> - {{ germplasmGnpis.collector.collectors }} - </ng-template> - </gpds-card-row> + <gpds-card-row + label="Acquisition/Creation date" + [test]="germplasmGnpis.collector.accessionCreationDate"> + <ng-template> + {{ germplasmGnpis.collector.accessionCreationDate | amParse:'YYYYMMDD' | amDateFormat:'YYYY-MM-DD' }} + </ng-template> + </gpds-card-row> - <gpds-card-row - label="Distribution status" - [test]="germplasmGnpis.collector && germplasmGnpis.collector.distributionStatus"> - <ng-template> - {{ germplasmGnpis.collector.distributionStatus }} - </ng-template> - </gpds-card-row> + <gpds-card-row + label="Acquisition/Creation date" + [test]="germplasmGnpis.acquisitionDate && !germplasmGnpis.collector.accessionCreationDate"> + <ng-template> + {{ germplasmGnpis.acquisitionDate }} + </ng-template> + </gpds-card-row> - <gpds-card-row - label="Germplasm Permanent Unique Identifier" - [test]="germplasmGnpis.collector && germplasmGnpis.collector.germplasmPUI"> - <ng-template> - {{ germplasmGnpis.collector.germplasmPUI }} - </ng-template> - </gpds-card-row> + <gpds-card-row + label="Institution" + [test]="germplasmGnpis.collector.institute && germplasmGnpis.collector.institute.instituteName"> + <ng-template> + <a class="popovers" placement="top" + [ngbPopover]="CollectorInstituteTemplate" + [popoverTitle]="germplasmGnpis.collector.institute.instituteName"> + {{ germplasmGnpis.collector.institute.instituteName }} + </a> + </ng-template> + </gpds-card-row> - <gpds-card-row - label="Material type" - [test]="germplasmGnpis.collector && germplasmGnpis.collector.materialType"> - <ng-template> - {{ germplasmGnpis.collector.materialType }} - </ng-template> - </gpds-card-row> + <gpds-card-row + label="Accession number" + [test]="germplasmGnpis.collector && germplasmGnpis.collector.accessionNumber"> + <ng-template> + {{ germplasmGnpis.collector.accessionNumber }} + </ng-template> + </gpds-card-row> + </div> + </ng-template> + </gpds-card-section> - <gpds-card-row - label="Collecting site" - [test]="germplasmGnpis.collectingSite && germplasmGnpis.collectingSite.siteName"> - <ng-template> - <a [routerLink]="['/sites/', germplasmGnpis.collectingSite.siteId]"> - {{ germplasmGnpis.collectingSite.siteName }} - </a> - </ng-template> - </gpds-card-row> + <gpds-card-section + header="Breeder" + [test]="checkBreeder()"> + <ng-template> + <div class="card-body card-section-body"> + <gpds-card-row + label="Institute" + [test]="germplasmGnpis.breeder.institute && germplasmGnpis.breeder.institute.instituteName"> + <ng-template> + <a class="popovers" placement="top" + [ngbPopover]="BreederInstituteTemplate" + [popoverTitle]="germplasmGnpis.breeder.institute.instituteName"> + {{ germplasmGnpis.breeder.institute.instituteName }} + </a> </ng-template> </gpds-card-row> - <gpds-card-row - label="Breeder" - [test]="testBreeder()"> + label="Accession creation year" + [test]="germplasmGnpis.breeder.accessionCreationDate "> <ng-template> + {{ germplasmGnpis.breeder.accessionCreationDate }} + </ng-template> + </gpds-card-row> - <gpds-card-row - label="Institute" - [test]="germplasmGnpis.breeder.institute && germplasmGnpis.breeder.institute.instituteName"> - <ng-template> - <!--TODO : Fix the issue with the overflow link (issue 13)--> - <a class="popovers" placement="top" - [ngbPopover]="BreederInstituteTemplate" - [popoverTitle]="germplasmGnpis.breeder.institute.instituteName"> - {{ germplasmGnpis.breeder.institute.instituteName }} {{ germplasmGnpis.breeder.institute.instituteCode }} - </a> - </ng-template> - </gpds-card-row> + <gpds-card-row + label="Accession number" + [value]="germplasmGnpis.breeder.accessionNumber"> + </gpds-card-row> - <gpds-card-row - label="Accession creation date" - [test]="germplasmGnpis.breeder.accessionCreationDate "> - <ng-template> - {{ germplasmGnpis.breeder.accessionCreationDate | amParse:'YYYYMMDD' | amDateFormat:'YYYY-MM-DD' }} - </ng-template> - </gpds-card-row> + <gpds-card-row + label="Catalog registration year" + [value]="germplasmGnpis.breeder.registrationYear"> + </gpds-card-row> - <gpds-card-row - label="Accession number" - [value]="germplasmGnpis.breeder.accessionNumber"> - </gpds-card-row> + <gpds-card-row + label="Catalog deregistration year" + [value]="germplasmGnpis.breeder.deregistrationYear"> + </gpds-card-row> + </div> + </ng-template> + </gpds-card-section> - <gpds-card-row - label="germplasm Permanent Unique Identifier" - [value]="germplasmGnpis.breeder.germplasmPUI"> - </gpds-card-row> + <gpds-card-section + header="Donation" + [test]="germplasmGnpis.donors && germplasmGnpis.donors.length > 0"> + <ng-template> + <gpds-card-table + [headers]="[ + 'Institute name', + 'Institute code', + 'Donation date', + 'Accession number', + 'Accession PUI' + ]" + [rows]="germplasmGnpis.donors"> + <ng-template let-row> + <tr> + <ng-template #InstituteTemplate> - <gpds-card-row - label="Registration year" - [value]="germplasmGnpis.breeder.registrationYear"> - </gpds-card-row> + <figure *ngIf="row.donorInstitute && row.donorInstitute.logo"> + <img + [src]="IMAGES_INSTITUTION_URL + row.donorInstitute.logo" + align="middle" /> + </figure> - <gpds-card-row - label="Deregistration year" - [value]="germplasmGnpis.breeder.deregistrationYear"> - </gpds-card-row> + <gpds-card-row + label="Code" + [value]="row.donorInstitute.instituteCode"> + </gpds-card-row> - <gpds-card-row - label="Distribution status" - [value]="germplasmGnpis.breeder.distributionStatus"> - </gpds-card-row> + <gpds-card-row + label="Acronym" + [value]="row.donorInstitute.acronym"> + </gpds-card-row> - </ng-template> - </gpds-card-row> + <gpds-card-row + label="Organisation" + [value]="row.donorInstitute.organisation"> + </gpds-card-row> + <gpds-card-row + label="Type" + [value]="row.donorInstitute.instituteType"> + </gpds-card-row> - <gpds-card-row - label="Donation" - [test]="germplasmGnpis.donors && germplasmGnpis.donors.length > 0"> - <ng-template> - <ng-container - *ngFor="let donor of germplasmGnpis.donors"> - - <!--Template for the donor popover--> - <ng-template #DonorInstituteTemplate> - - <gpds-card-row - label="Code" - [value]="donor.donorInstitute.instituteCode"> - </gpds-card-row> - - <gpds-card-row - label="Acronym" - [value]="donor.donorInstitute.acronym"> - </gpds-card-row> - - <gpds-card-row - label="Organisation" - [value]="donor.donorInstitute.organisation"> - </gpds-card-row> - - <gpds-card-row - label="Type" - [value]="donor.donorInstitute.instituteType"> - </gpds-card-row> - - <gpds-card-row - label="Address" - [value]="donor.donorInstitute.address"> - </gpds-card-row> - - <gpds-card-row - label="Website" - [test]="donor.donorInstitute.webSite"> - <ng-template> - <a [href]=" donor.donorInstitute.webSite "> - {{ donor.donorInstitute.webSite }} - </a> - </ng-template> - </gpds-card-row> - </ng-template> + <gpds-card-row + label="Address" + [value]="row.donorInstitute.address"> + </gpds-card-row> - <gpds-card-row - label="Institute name" - [test]="donor.donorInstitute.instituteName"> - <ng-template> - <a class="popovers" placement="top" - [ngbPopover]="DonorInstituteTemplate" - [popoverTitle]="donor.donorInstitute.instituteName"> - {{ donor.donorInstitute.instituteName }} - </a> - </ng-template> - </gpds-card-row> - - <gpds-card-row - label="Donation date" - [test]="donor.donationDate"> - <ng-template> - {{ donor.donationDate | amParse:'YYYYMMDD' | amDateFormat:'YYYY-MM-DD' }} - </ng-template> - </gpds-card-row> - - <gpds-card-row - label="Donor Accession Number" - [value]="donor.donorAccessionNumber"> - </gpds-card-row> - - <gpds-card-row - label="Donor germplasm Permanent Unique Identifier" - [value]="donor.donorGermplasmPUI"> - </gpds-card-row> - - <gpds-card-row - label="Donor institution code" - [value]="donor.donorInstituteCode"> - </gpds-card-row> + <gpds-card-row + label="Website" + [test]="row.donorInstitute.webSite"> + <ng-template> + <a [href]=" row.donorInstitute.webSite "> + {{ row.donorInstitute.webSite }} + </a> + </ng-template> + </gpds-card-row> + </ng-template> - </ng-container> - </ng-template> - </gpds-card-row> + <td> + <a class="popovers" placement="top" + [ngbPopover]="InstituteTemplate" + [popoverTitle]="row.donorInstitute.instituteName"> + {{ row.donorInstitute.instituteName }} + </a> + </td> + <td>{{ row.donorInstituteCode }}</td> + <td>{{ row.donationDate }}</td> + <td>{{ row.donorAccessionNumber }}</td> + <td>{{ row.donorGermplasmPUI }}</td> + </tr> + </ng-template> - </div> + </gpds-card-table> </ng-template> </gpds-card-section> @@ -551,19 +527,27 @@ [test]="germplasmGnpis.distributors && germplasmGnpis.distributors.length>0"> <ng-template> + <!--TODO : Add order column when ordering URL will be available--> <gpds-card-table [headers]="[ 'Institute', 'Accession number', 'Distribution status' + ]" [rows]="germplasmGnpis.distributors"> <ng-template let-row> <tr> <ng-template #InstituteTemplate> + <figure *ngIf="row.institute && row.institute.logo"> + <img + [src]="IMAGES_INSTITUTION_URL + row.institute.logo" + align="middle" /> + </figure> + <gpds-card-row - label="FAO code" + label="Code" [value]="row.institute.instituteCode"> </gpds-card-row> @@ -578,10 +562,15 @@ </gpds-card-row> <gpds-card-row - label="Institute type" + label="Type" [value]="row.institute.instituteType"> </gpds-card-row> + <gpds-card-row + label="Address" + [value]="row.institute.address"> + </gpds-card-row> + <gpds-card-row label="Website" [test]="row.institute.webSite"> @@ -591,12 +580,6 @@ </a> </ng-template> </gpds-card-row> - - - <gpds-card-row - label="Address" - [value]="row.institute.address"> - </gpds-card-row> </ng-template> <td> @@ -608,6 +591,7 @@ </td> <td>{{ row.accessionNumber }}</td> <td>{{ row.distributionStatus }}</td> + <!--<td>{{ '' }}</td>--> </tr> </ng-template> @@ -616,10 +600,26 @@ </ng-template> </gpds-card-section> + <gpds-card-section + header="Evaluation Data" + [test]="germplasmAttributes && germplasmAttributes.length > 0"> + <ng-template> + <div class="card-body card-section-body"> + + <ng-container *ngFor="let descriptor of germplasmAttributes"> + <gpds-card-row + [label]="descriptor.attributeName" + [value]="descriptor.value"> + </gpds-card-row> + </ng-container> + + </div> + </ng-template> + </gpds-card-section> <gpds-card-section header="Genealogy" - [test]="testPedigree() || testProgeny()"> + [test]="checkPedigree() || checkProgeny()"> <ng-template> <div class="card-body card-section-body"> @@ -647,16 +647,14 @@ </ng-template> </gpds-card-row> - <gpds-card-row label="Parent accessions" - [test]="germplasmPedigree && (germplasmPedigree.parent1Name || germplasmPedigree.parent2Name)"> + [test]="germplasmPedigree && germplasmPedigree.parent1Name"> <ng-template> - <gpds-card-row - label="Mother" - [test]="germplasmPedigree && (germplasmPedigree.parent1Type && germplasmPedigree.parent1Type == 'FEMALE')"> + [label]="germplasmPedigree.parent1Type" + [test]="germplasmPedigree && germplasmPedigree.parent1DbId"> <ng-template> <a [routerLink]="['/germplasm']" [queryParams]="{id:germplasmPedigree.parent1DbId}"> @@ -666,47 +664,8 @@ </gpds-card-row> <gpds-card-row - label="Father" - [test]="germplasmPedigree && (germplasmPedigree.parent1Type && germplasmPedigree.parent1Type == 'MALE')"> - <ng-template> - <a [routerLink]="['/germplasm']" - [queryParams]="{id:germplasmPedigree.parent1DbId}"> - {{ germplasmPedigree.parent1Name }} - </a> - </ng-template> - </gpds-card-row> - - <gpds-card-row - label="Population" - [test]="germplasmPedigree && (germplasmPedigree.parent1Type && germplasmPedigree.parent1Type == 'POPULATION')"> - <ng-template> - {{ germplasmPedigree.parent1Name }} - </ng-template> - </gpds-card-row> - - <gpds-card-row - label="SELF" - [test]="germplasmPedigree && (germplasmPedigree.parent1Type == 'SELF')"> - <ng-template> - Self - </ng-template> - </gpds-card-row> - - - <gpds-card-row - label="Mother" - [test]="germplasmPedigree && (germplasmPedigree.parent2Type && germplasmPedigree.parent2Type == 'FEMALE')"> - <ng-template> - <a [routerLink]="['/germplasm']" - [queryParams]="{id:germplasmPedigree.parent2DbId}"> - {{ germplasmPedigree.parent2Name }} - </a> - </ng-template> - </gpds-card-row> - - <gpds-card-row - label="Father" - [test]="germplasmPedigree && (germplasmPedigree.parent2Type && germplasmPedigree.parent2Type == 'MALE')"> + [label]="germplasmPedigree.parent2Type" + [test]="germplasmPedigree && germplasmPedigree.parent2DbId"> <ng-template> <a [routerLink]="['/germplasm']" [queryParams]="{id:germplasmPedigree.parent2DbId}"> @@ -715,22 +674,6 @@ </ng-template> </gpds-card-row> - <gpds-card-row - label="Population" - [test]="germplasmPedigree && (germplasmPedigree.parent2Type && germplasmPedigree.parent2Type == 'POPULATION')"> - <ng-template> - {{ germplasmPedigree.parent2Name }} - </ng-template> - </gpds-card-row> - - <gpds-card-row - label="SELF" - [test]="germplasmPedigree && (germplasmPedigree.parent2Type == 'SELF')"> - <ng-template> - Self - </ng-template> - </gpds-card-row> - </ng-template> </gpds-card-row> @@ -752,15 +695,15 @@ <gpds-card-row label="Descendant :" - [test]="testProgeny()"> + [test]="checkProgeny()"> </gpds-card-row> <div class="content-overflow-big"> <ng-container *ngFor="let child of germplasmProgeny"> <gpds-card-row class="text" - [label]="'child(ren) of ' + child.firstParentName + ' and ' + child.secondParentName" - [test]="testProgeny()"> + [label]="child.secondParentName ? 'child(ren) of ' + child.firstParentName + ' x ' + child.secondParentName : 'child(ren) of ' + child.firstParentName" + [test]="checkProgeny()"> <ng-template> <ng-container *ngFor="let sibling of child.sibblings"> @@ -769,7 +712,6 @@ </a>, </ng-container> - </ng-template> </gpds-card-row> </ng-container> @@ -780,15 +722,47 @@ </gpds-card-section> <gpds-card-section - header="Evaluation Data" - [test]="germplasmAttributes && germplasmAttributes.length > 0"> + header="Population" + [test]="germplasmGnpis.population && germplasmGnpis.population.length > 0"> <ng-template> - <div class="card-body card-section-body"> + <div class="card-body card-section-body card-section-body"> + + <ng-container *ngFor="let population of germplasmGnpis.population"> - <ng-container *ngFor="let descriptor of germplasmAttributes"> <gpds-card-row - [label]="descriptor.attributeName" - [value]="descriptor.value"> + [label]="population.type ? population.name + ' (' + population.type + ')' : population.name" + [test]="population.germplasmRef && population.germplasmRef.pui && population.germplasmRef.pui != germplasmGnpis.germplasmDbId"> + <ng-template> + <a [routerLink]="['/germplasm']" + [queryParams]="{id:population.germplasmRef.pui}"> + {{ population.germplasmRef.name }} + </a> is composed by <a + [routerLink]="['/']" + [queryParams]="{germplasmLists: population.name, types: 'Germplasm'}"> + {{ population.germplasmCount }} accessions + </a> + </ng-template> + </gpds-card-row> + <gpds-card-row + [label]="population.type ? population.name + ' (' + population.type + ')' : population.name" + [test]="population.germplasmRef && population.germplasmRef.pui && population.germplasmRef.pui == germplasmGnpis.germplasmDbId"> + <ng-template> + {{ population.germplasmRef.name }} is composed by <a + [routerLink]="['/']" + [queryParams]="{germplasmLists: population.name, types: 'Germplasm'}"> + {{ population.germplasmCount }} accessions + </a> + </ng-template> + </gpds-card-row> + <gpds-card-row + [label]="population.type ? population.name + ' (' + population.type + ')' : population.name" + [test]="population.germplasmRef && !population.germplasmRef.pui"> + <ng-template> + <a [routerLink]="['/']" + [queryParams]="{germplasmLists: population.name, types: 'Germplasm'}"> + {{ population.germplasmCount }} accessions + </a> + </ng-template> </gpds-card-row> </ng-container> @@ -796,7 +770,6 @@ </ng-template> </gpds-card-section> - <gpds-card-section header="Collection" [test]="germplasmGnpis.collection && germplasmGnpis.collection.length > 0"> @@ -829,31 +802,10 @@ <ng-container *ngFor="let panel of germplasmGnpis.panel"> <gpds-card-row [label]="panel.type ? panel.name + ' (' + panel.type + ')' : panel.name"> - <a [routerLink]="['/']" - [queryParams]="{germplasmLists: panel.name, types: 'Germplasm'}"> - {{ panel.germplasmCount }} accessions - </a> - </gpds-card-row> - </ng-container> - - </div> - </ng-template> - </gpds-card-section> - - - <gpds-card-section - header="Population" - [test]="germplasmGnpis.population && germplasmGnpis.population.length > 0"> - <ng-template> - <div class="card-body card-section-body card-section-body"> - - <ng-container *ngFor="let population of germplasmGnpis.population"> - <gpds-card-row - [label]="population.type ? population.name + ' (' + population.type + ')' : population.name"> <ng-template> <a [routerLink]="['/']" - [queryParams]="{germplasmLists: population.name, types: 'Germplasm'}"> - {{ population.germplasmCount }} accessions + [queryParams]="{germplasmLists: panel.name, types: 'Germplasm'}"> + {{ panel.germplasmCount }} accessions </a> </ng-template> </gpds-card-row> diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.ts b/frontend/src/app/germplasm-card/germplasm-card.component.ts index fce0739b..fa242587 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.ts +++ b/frontend/src/app/germplasm-card/germplasm-card.component.ts @@ -2,8 +2,9 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; import { BrapiService } from '../brapi.service'; import { GnpisService } from '../gnpis.service'; -import { Germplasm, GermplasmProgeny } from '../models/gnpis.germplasm.model'; +import { Germplasm, GermplasmProgeny, Site } from '../models/gnpis.germplasm.model'; import { BrapiGermplasmAttributes, BrapiGermplasmPedigree } from '../models/brapi.germplasm.model'; +import { BrapiLocation } from '../models/brapi.model'; @Component({ selector: 'gpds-germplasm-card', @@ -32,9 +33,13 @@ export class GermplasmCardComponent implements OnInit { germplasmPedigree: BrapiGermplasmPedigree; germplasmProgeny: GermplasmProgeny[]; germplasmAttributes: BrapiGermplasmAttributes[]; + germplasmLocations: BrapiLocation[] = []; germplasmId: string; germplasmPuid: string; - IMAGES_SIREGAL_URL = 'https://urgi.versailles.inra.fr/files/siregal/images/accession'; + IMAGES_ACCESSION_URL = 'https://urgi.versailles.inra.fr/files/siregal/images/accession/'; + IMAGES_INSTITUTION_URL = 'https://urgi.versailles.inra.fr/files/siregal/images//institution/'; + IMAGES_BRC_URL = 'https://urgi.versailles.inra.fr/files/siregal/images/grc/inra_brc_en.png'; + loaded: Promise<any>; loading = true; @@ -89,6 +94,11 @@ export class GermplasmCardComponent implements OnInit { .then(germplasmGnpis => { this.germplasmGnpis = germplasmGnpis; this.germplasmProgeny = germplasmGnpis.children; + this.siteToBrapiLocation(this.germplasmGnpis.collectingSite); + this.siteToBrapiLocation(this.germplasmGnpis.originSite); + for (const site of this.germplasmGnpis.evaluationSites) { + this.siteToBrapiLocation(site); + } }); } else { germplasm$ = this.gnpisService.germplasmByPuid(pui).toPromise(); @@ -100,26 +110,38 @@ export class GermplasmCardComponent implements OnInit { return germplasm$; } + siteToBrapiLocation(site: Site) { + if (site.siteId && site.latitude && site.longitude) { + this.germplasmLocations.push({ + locationDbId: site.siteId, + locationName: site.siteName, + locationType: site.siteType, + latitude: site.latitude, + longitude: site.longitude + }); + } + } + // TODO: use a generic function to get path in object (or null if non-existent) - testProgeny() { + checkProgeny() { return (this.germplasmProgeny && this.germplasmProgeny.length > 0); } - testBreeder() { + checkBreeder() { return (this.germplasmGnpis.breeder) && (this.germplasmGnpis.breeder.institute.instituteName - || this.germplasmGnpis.breeder.germplasmPUI - || this.germplasmGnpis.breeder.accessionNumber - || this.germplasmGnpis.breeder.accessionCreationDate - || this.germplasmGnpis.breeder.materialType - || this.germplasmGnpis.breeder.collectors - || this.germplasmGnpis.breeder.registrationYear - || this.germplasmGnpis.breeder.deregistrationYear - || this.germplasmGnpis.breeder.distributionStatus); + || this.germplasmGnpis.breeder.germplasmPUI + || this.germplasmGnpis.breeder.accessionNumber + || this.germplasmGnpis.breeder.accessionCreationDate + || this.germplasmGnpis.breeder.materialType + || this.germplasmGnpis.breeder.collectors + || this.germplasmGnpis.breeder.registrationYear + || this.germplasmGnpis.breeder.deregistrationYear + || this.germplasmGnpis.breeder.distributionStatus); } - testPedigree() { + checkPedigree() { return (this.germplasmPedigree && (this.germplasmPedigree.parent1Name || this.germplasmPedigree.parent2Name @@ -130,14 +152,14 @@ export class GermplasmCardComponent implements OnInit { } - testCollectorInstituteObject() { + checkCollectorInstituteObject() { return ( this.germplasmGnpis.collector && this.germplasmGnpis.collector.institute && this.germplasmGnpis.collector.institute.instituteName); } - testCollectorInstituteFields() { + checkCollectorInstituteFields() { return (this.germplasmGnpis.collector) && (this.germplasmGnpis.collector.germplasmPUI || this.germplasmGnpis.collector.accessionNumber @@ -150,12 +172,10 @@ export class GermplasmCardComponent implements OnInit { ); } - testOrigin() { + checkOriginCollecting() { return (this.germplasmGnpis.originSite && this.germplasmGnpis.originSite.siteName) - || (this.germplasmGnpis.donors && this.germplasmGnpis.donors.length > 0) - || ((this.testCollectorInstituteObject() || this.testCollectorInstituteFields()) - || (this.germplasmGnpis.collectingSite && this.germplasmGnpis.collectingSite.siteName)) - || (this.germplasmGnpis.breeder); + || (this.germplasmGnpis.collectingSite && this.germplasmGnpis.collectingSite.siteName) + || (this.checkCollectorInstituteObject() || this.checkCollectorInstituteFields()); } } diff --git a/frontend/src/app/models/brapi.germplasm.model.ts b/frontend/src/app/models/brapi.germplasm.model.ts index b4ad65c3..3730d768 100644 --- a/frontend/src/app/models/brapi.germplasm.model.ts +++ b/frontend/src/app/models/brapi.germplasm.model.ts @@ -47,10 +47,3 @@ export interface BrapiDonor { donorInstitute: Institute; } -export interface BrapiSet { - germplasmCount: number; - germplasmRef: string; - id: number; - name: string; - type: string; -} diff --git a/frontend/src/app/models/brapi.model.ts b/frontend/src/app/models/brapi.model.ts index 4360105b..285cc134 100644 --- a/frontend/src/app/models/brapi.model.ts +++ b/frontend/src/app/models/brapi.model.ts @@ -55,12 +55,12 @@ export interface BrapiLocation extends BrapiHasDocumentationURL { locationDbId: string; locationName: string; locationType: string; - abbreviation: string; - countryCode: string; - countryName: string; - institutionAddress: string; - institutionName: string; - altitude: number; + abbreviation?: string; + countryCode?: string; + countryName?: string; + institutionAddress?: string; + institutionName?: string; + altitude?: number; latitude: number; longitude: number; additionalInfo?: AdditionalInfo; diff --git a/frontend/src/app/models/gnpis.germplasm.model.ts b/frontend/src/app/models/gnpis.germplasm.model.ts index d7278424..a37a9537 100644 --- a/frontend/src/app/models/gnpis.germplasm.model.ts +++ b/frontend/src/app/models/gnpis.germplasm.model.ts @@ -1,9 +1,9 @@ -import { BrapiDescriptor, BrapiDonor, BrapiSet } from './brapi.germplasm.model'; +import { BrapiDescriptor, BrapiDonor } from './brapi.germplasm.model'; export interface Site { latitude: number; longitude: number; - siteId: number; + siteId: string; siteName: string; siteType: string; } @@ -54,7 +54,6 @@ export interface GermplasmProgeny { sibblings: { name: string; pui: string; - value: string; }[]; } @@ -102,11 +101,23 @@ export interface Germplasm { collector: Origin; breeder: Origin; distributors: Origin[]; - panel: BrapiSet[]; - collection: BrapiSet[]; - population: BrapiSet[]; + panel: GermplasmSet[]; + collection: GermplasmSet[]; + population: GermplasmSet[]; } +export interface GermplasmSet { + id: number; + name: string; + type: string; + germplasmCount: number; + germplasmRef: { + pui: string; + name: string; + }; +} + + export interface GermplasmData<T> { data: T; } -- GitLab From 09374a1e35362cf6b5a5721d0cdccaae9c0f0d3b Mon Sep 17 00:00:00 2001 From: jdestin <jeremy.destin@inra.fr> Date: Fri, 8 Mar 2019 10:41:34 +0100 Subject: [PATCH 10/20] fix: Fix test for germplasm card. Increase cyclomatic complexity due to new elements on germplasm page. GNP-5490 --- frontend/src/app/brapi.service.spec.ts | 11 ++++----- .../germplasm-card.component.spec.ts | 23 ++++++++++--------- frontend/src/app/gnpis.service.spec.ts | 14 +++++------ frontend/src/tslint.json | 2 +- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/frontend/src/app/brapi.service.spec.ts b/frontend/src/app/brapi.service.spec.ts index 6e71ee07..fa62fe54 100644 --- a/frontend/src/app/brapi.service.spec.ts +++ b/frontend/src/app/brapi.service.spec.ts @@ -16,10 +16,9 @@ import { BrapiGermplasmAttributes, BrapiGermplasmPedigree, BrapiGermplasmProgeny, - BrapiSet, BrapiSibling } from './models/brapi.germplasm.model'; -import { Germplasm, GermplasmData, GermplasmResult, Institute, Origin, Site } from './models/gnpis.germplasm.model'; +import { Germplasm, GermplasmData, GermplasmResult, GermplasmSet, Institute, Origin, Site } from './models/gnpis.germplasm.model'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { TestBed } from '@angular/core/testing'; @@ -212,7 +211,7 @@ describe('BrapiService', () => { donationDate: null }; - const brapiSet: BrapiSet = { + const germplasmSet: GermplasmSet = { germplasmCount: 12, germplasmRef: null, id: 12, @@ -272,9 +271,9 @@ describe('BrapiService', () => { collector: origin, breeder: origin, distributors: [origin], - panel: [brapiSet], - collection: [brapiSet], - population: [brapiSet] + panel: [germplasmSet], + collection: [germplasmSet], + population: [germplasmSet] }; const germplasmResultTest = { diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts b/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts index b1033f77..be45c114 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts +++ b/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts @@ -11,16 +11,16 @@ import { BrapiDonor, BrapiGermplasmAttributes, BrapiGermplasmPedigree, - BrapiSet, BrapiSibling } from '../models/brapi.germplasm.model'; -import { Germplasm, GermplasmData, GermplasmResult, Institute, Origin, Site } from '../models/gnpis.germplasm.model'; +import { Germplasm, GermplasmData, GermplasmResult, GermplasmSet, Institute, Origin, Site } from '../models/gnpis.germplasm.model'; import { NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap'; import { MomentModule } from 'ngx-moment'; import { LoadingSpinnerComponent } from '../loading-spinner/loading-spinner.component'; import { CardSectionComponent } from '../card-section/card-section.component'; import { CardRowComponent } from '../card-row/card-row.component'; import { CardTableComponent } from '../card-table/card-table.component'; +import { MapComponent } from '../map/map.component'; import { MockComponent } from 'ng-mocks'; import { XrefsComponent } from '../xrefs/xrefs.component'; @@ -135,7 +135,7 @@ describe('GermplasmCardComponent', () => { donationDate: null }; - const brapiSet: BrapiSet = { + const germplasmSet: GermplasmSet = { germplasmCount: 12, germplasmRef: null, id: 12, @@ -195,9 +195,9 @@ describe('GermplasmCardComponent', () => { collector: brapiOrigin, breeder: brapiOrigin, distributors: [brapiOrigin], - panel: [brapiSet], - collection: [brapiSet], - population: [brapiSet] + panel: [germplasmSet], + collection: [germplasmSet], + population: [germplasmSet] }; beforeEach(async(() => { @@ -206,7 +206,7 @@ describe('GermplasmCardComponent', () => { declarations: [ GermplasmCardComponent, LoadingSpinnerComponent, MockComponent(XrefsComponent) GermplasmCardComponent, CardSectionComponent, - CardRowComponent, LoadingSpinnerComponent, CardTableComponent + CardRowComponent, LoadingSpinnerComponent, CardTableComponent, MapComponent ], providers: [ { provide: BrapiService, useValue: brapiService }, @@ -241,10 +241,11 @@ describe('GermplasmCardComponent', () => { expect(tester.title).toContainText('Germplasm: test'); expect(tester.cardHeader[0]).toContainText('Identification'); expect(tester.cardHeader[1]).toContainText('Holding'); - expect(tester.cardHeader[2]).toContainText('Origin'); - expect(tester.cardHeader[3]).toContainText('Distribution'); - expect(tester.cardHeader[4]).toContainText('Genealogy'); - expect(tester.cardHeader[5]).toContainText('Evaluation Data'); + expect(tester.cardHeader[2]).toContainText('Collecting'); + expect(tester.cardHeader[3]).toContainText('Breeder'); + expect(tester.cardHeader[4]).toContainText('Donation'); + expect(tester.cardHeader[5]).toContainText('Distribution'); + expect(tester.cardHeader[6]).toContainText('Evaluation Data'); }); })); }); diff --git a/frontend/src/app/gnpis.service.spec.ts b/frontend/src/app/gnpis.service.spec.ts index 9f8ff7a6..63d96558 100644 --- a/frontend/src/app/gnpis.service.spec.ts +++ b/frontend/src/app/gnpis.service.spec.ts @@ -1,9 +1,9 @@ -import { Germplasm, Institute, Origin, Site } from './models/gnpis.germplasm.model'; +import { Germplasm, GermplasmSet, Institute, Origin, Site } from './models/gnpis.germplasm.model'; import { BASE_URL, BASE_URL_GERMPLASM, GnpisService } from './gnpis.service'; import { BrapiMetaData, BrapiResults } from './models/brapi.model'; import { DataDiscoveryCriteria, DataDiscoverySource } from './models/data-discovery.model'; -import { BrapiDescriptor, BrapiDonor, BrapiSet } from './models/brapi.germplasm.model'; +import { BrapiDescriptor, BrapiDonor } from './models/brapi.germplasm.model'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { TestBed } from '@angular/core/testing'; @@ -29,7 +29,7 @@ describe('GnpisService', () => { const site: Site = { latitude: null, longitude: null, - siteId: 1, + siteId: '1', siteName: 'Nantes', siteType: null }; @@ -71,7 +71,7 @@ describe('GnpisService', () => { donationDate: null }; - const brapiSet: BrapiSet = { + const germplasmSet: GermplasmSet = { germplasmCount: 12, germplasmRef: null, id: 12, @@ -122,9 +122,9 @@ describe('GnpisService', () => { collector: brapiOrigin, breeder: brapiOrigin, distributors: [brapiOrigin], - panel: [brapiSet], - collection: [brapiSet], - population: [brapiSet] + panel: [germplasmSet], + collection: [germplasmSet], + population: [germplasmSet] }; let gnpisService: GnpisService; diff --git a/frontend/src/tslint.json b/frontend/src/tslint.json index bfffe71c..f13a8ca1 100644 --- a/frontend/src/tslint.json +++ b/frontend/src/tslint.json @@ -15,7 +15,7 @@ ], "template-cyclomatic-complexity": [ true, - 12 + 18 ] } } -- GitLab From 21aff61113a1ebad951dd6abef9db9e0c90ad3c7 Mon Sep 17 00:00:00 2001 From: Celia Michotey <celia.michotey@inra.fr> Date: Fri, 8 Mar 2019 18:55:47 +0100 Subject: [PATCH 11/20] WIP: deduplicate models, reduce cyclomatic complexity, change display of additional info on site card. --- frontend/src/app/brapi.service.spec.ts | 77 ++++++----- frontend/src/app/brapi.service.ts | 4 +- .../germplasm-card.component.html | 119 +++++++++-------- .../germplasm-card.component.scss | 1 - .../germplasm-card.component.spec.ts | 69 +++++----- .../germplasm-card.component.ts | 12 +- frontend/src/app/gnpis.service.spec.ts | 8 +- frontend/src/app/map/map.component.html | 2 +- frontend/src/app/map/map.component.ts | 25 +++- .../src/app/models/brapi.germplasm.model.ts | 49 ------- frontend/src/app/models/brapi.model.ts | 120 ++++++++++++++---- ...npis.germplasm.model.ts => gnpis.model.ts} | 99 +++++---------- .../app/site-card/site-card.component.html | 106 ++++++++++++---- .../src/app/site-card/site-card.component.ts | 45 ++++++- .../app/study-card/study-card.component.html | 2 +- .../app/study-card/study-card.component.ts | 4 - frontend/src/assets/gpds/theme.scss | 7 - frontend/src/tslint.json | 2 +- 18 files changed, 433 insertions(+), 318 deletions(-) delete mode 100644 frontend/src/app/models/brapi.germplasm.model.ts rename frontend/src/app/models/{gnpis.germplasm.model.ts => gnpis.model.ts} (55%) diff --git a/frontend/src/app/brapi.service.spec.ts b/frontend/src/app/brapi.service.spec.ts index fa62fe54..9bca7064 100644 --- a/frontend/src/app/brapi.service.spec.ts +++ b/frontend/src/app/brapi.service.spec.ts @@ -1,26 +1,18 @@ import { BrapiService } from './brapi.service'; import { - BrapiContacts, - BrapiGermplasm, + BrapiContacts, BrapiData, BrapiDonor, + BrapiGermplasm, BrapiGermplasmAttributes, BrapiGermplasmPedigree, BrapiGermplasmProgeny, BrapiLocation, BrapiObservationVariable, - BrapiResult, - BrapiResults, - BrapiStudy, + BrapiResult, BrapiResults, BrapiSibling, + BrapiStudy, BrapiTaxonIds, BrapiTrial } from './models/brapi.model'; import { DataDiscoverySource } from './models/data-discovery.model'; -import { - BrapiDescriptor, - BrapiDonor, - BrapiGermplasmAttributes, - BrapiGermplasmPedigree, - BrapiGermplasmProgeny, - BrapiSibling -} from './models/brapi.germplasm.model'; -import { Germplasm, GermplasmData, GermplasmResult, GermplasmSet, Institute, Origin, Site } from './models/gnpis.germplasm.model'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { TestBed } from '@angular/core/testing'; +import {Germplasm, GermplasmInstitute, GermplasmSet, Institute, Site} from "./models/gnpis.model"; +import Result = jasmine.Result; describe('BrapiService', () => { @@ -111,17 +103,49 @@ describe('BrapiService', () => { data: [{ germplasmDbId: 'g1', accessionNumber: 'G_10', + defaultDisplayName: null, + germplasmPUI: null, + pedigree: null, + seedSource: null, + synonyms: null, + commonCropName: null, + instituteCode: null, + instituteName: null, + biologicalStatusOfAccessionCode: null, + countryOfOriginCode: null, + typeOfGermplasmStorageCode: null, + taxonIds: null, germplasmName: 'germplam1', genus: 'Populus', species: 'x generosa', - subtaxa: '' + subtaxa: '', + speciesAuthority: null, + subtaxaAuthority: null, + donors: null, + acquisitionDate: null }, { germplasmDbId: 'g2', accessionNumber: 'G_20', germplasmName: 'germplam2', genus: 'Triticum', species: 'aestivum', - subtaxa: 'subsp' + subtaxa: 'subsp', + defaultDisplayName: null, + germplasmPUI: null, + pedigree: null, + seedSource: null, + synonyms: null, + commonCropName: null, + instituteCode: null, + instituteName: null, + biologicalStatusOfAccessionCode: null, + countryOfOriginCode: null, + typeOfGermplasmStorageCode: null, + taxonIds: null, + speciesAuthority: null, + subtaxaAuthority: null, + donors: null, + acquisitionDate: null }], } }; @@ -148,13 +172,7 @@ describe('BrapiService', () => { defaultDisplayName: 'frere1' }; - const brapiDescriptor: BrapiDescriptor = { - name: 'caracteristique1', - pui: '12', - value: '32' - }; - - const brapiGermplasmPedigree: GermplasmResult<BrapiGermplasmPedigree> = { + const brapiGermplasmPedigree: BrapiResult<BrapiGermplasmPedigree> = { result: { germplasmDbId: 'test', defaultDisplayName: '12', @@ -172,7 +190,7 @@ describe('BrapiService', () => { } }; - const brapiGermplasmProgeny: GermplasmResult<BrapiGermplasmProgeny> = { + const brapiGermplasmProgeny: BrapiResult<BrapiGermplasmProgeny> = { result: { germplasmDbId: 'test', defaultDisplayName: '11', @@ -191,7 +209,7 @@ describe('BrapiService', () => { address: '12', logo: null }; - const origin: Origin = { ... institute, + const origin: GermplasmInstitute = { ... institute, institute: institute, germplasmPUI: '12', accessionNumber: '12', @@ -219,7 +237,7 @@ describe('BrapiService', () => { type: 'plan' }; - const brapiGermplasmAttributes: GermplasmResult<GermplasmData<BrapiGermplasmAttributes[]>> = { + const brapiGermplasmAttributes: BrapiResult<BrapiData<BrapiGermplasmAttributes[]>> = { result: { data: [{ attributeName: 'longueur', @@ -229,8 +247,6 @@ describe('BrapiService', () => { }; const germplasmTest: Germplasm = { - url: 'www.cirad.fr', - source: 'cirad', germplasmDbId: 'test', defaultDisplayName: 'test', accessionNumber: 'test', @@ -264,7 +280,6 @@ describe('BrapiService', () => { holdingGenbank: institute, presenceStatus: null, children: null, - descriptors: [brapiDescriptor], originSite: null, collectingSite: null, evaluationSites: null, @@ -365,7 +380,7 @@ describe('BrapiService', () => { it('should fetch the pedigree', () => { - let fetchedGermplasmPedigree: GermplasmResult<BrapiGermplasmPedigree>; + let fetchedGermplasmPedigree: BrapiResult<BrapiGermplasmPedigree>; const germplasmDbId: string = brapiGermplasmPedigree.result.germplasmDbId; brapiService.germplasmPedigree(germplasmDbId).subscribe(response => { fetchedGermplasmPedigree = response; @@ -393,7 +408,7 @@ describe('BrapiService', () => { it('should fetch the germplasm attributes', () => { - let fetchedGermplasmAttributes: GermplasmResult<GermplasmData<BrapiGermplasmAttributes[]>>; + let fetchedGermplasmAttributes: BrapiResult<BrapiData<BrapiGermplasmAttributes[]>>; const germplasmDbId: string = germplasmTest.germplasmDbId; brapiService.germplasmAttributes(germplasmDbId).subscribe(response => { fetchedGermplasmAttributes = response; diff --git a/frontend/src/app/brapi.service.ts b/frontend/src/app/brapi.service.ts index 545589b5..72740e34 100644 --- a/frontend/src/app/brapi.service.ts +++ b/frontend/src/app/brapi.service.ts @@ -3,7 +3,7 @@ import { Observable } from 'rxjs'; import { HttpClient } from '@angular/common/http'; import { Germplasm, GermplasmData, GermplasmResult } from './models/gnpis.germplasm.model'; import { - BrapiGermplasm, + BrapiGermplasm, BrapiGermplasmAttributes, BrapiLocation, BrapiObservationVariable, BrapiResult, @@ -11,7 +11,7 @@ import { BrapiStudy, BrapiTrial } from './models/brapi.model'; -import { BrapiGermplasmAttributes, BrapiGermplasmPedigree } from './models/brapi.germplasm.model'; +import { BrapiGermplasmPedigree } from './models/brapi.germplasm.model'; export const BASE_URL = 'brapi/v1'; diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.html b/frontend/src/app/germplasm-card/germplasm-card.component.html index f3194ad7..80c8b030 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.html +++ b/frontend/src/app/germplasm-card/germplasm-card.component.html @@ -2,29 +2,28 @@ <ng-container *ngIf="germplasmGnpis"> <h3 class="mb-4"> - <figure *ngIf="germplasmGnpis.holdingGenbank && germplasmGnpis.holdingGenbank.instituteName"> - <img - [src]="IMAGES_BRC_URL" - align="right" /> - </figure> + <img *ngIf="germplasmGnpis.holdingGenbank && germplasmGnpis.holdingGenbank.instituteName" + [src]="IMAGES_BRC_URL" + align="right"/> Germplasm: {{ germplasmGnpis.germplasmName }} </h3> - - <!-- Display the map --> - <gpds-map *ngIf="germplasmLocations.length > 0" [locations]="germplasmLocations"></gpds-map> + <gpds-map [locations]="germplasmLocations"></gpds-map> <div class="row align-items-center"> <!--Templates for gerplasm card--> - <ng-template #holdingInstituteTemplate > + <ng-template #holdingInstituteTemplate> - <figure *ngIf="germplasmGnpis.holdingInstitute && germplasmGnpis.holdingInstitute.logo"> - <img - [src]="IMAGES_INSTITUTION_URL + germplasmGnpis.holdingInstitute.logo" - align="middle" /> - </figure> + <gpds-card-row + label="" + [test]="germplasmGnpis.holdingInstitute && germplasmGnpis.holdingInstitute.logo"> + <ng-template> + <img + [src]="IMAGES_INSTITUTION_URL + germplasmGnpis.holdingInstitute.logo"/> + </ng-template> + </gpds-card-row> <gpds-card-row label="Code" @@ -53,7 +52,12 @@ <gpds-card-row label="Website" - [value]="germplasmGnpis.holdingInstitute.webSite"> + [test]="germplasmGnpis.holdingInstitute.webSite"> + <ng-template> + <a [href]="germplasmGnpis.breeder.institute.webSite"> + {{ germplasmGnpis.holdingInstitute.webSite }} + </a> + </ng-template> </gpds-card-row> </ng-template> @@ -61,11 +65,14 @@ <ng-template #BreederInstituteTemplate> - <figure *ngIf="germplasmGnpis.breeder && germplasmGnpis.breeder.institute && germplasmGnpis.breeder.institute.logo"> - <img - [src]="IMAGES_INSTITUTION_URL + germplasmGnpis.breeder.institute.logo" - align="middle" /> - </figure> + <gpds-card-row + label="" + [test]="germplasmGnpis.breeder && germplasmGnpis.breeder.institute && germplasmGnpis.breeder.institute.logo"> + <ng-template> + <img + [src]="IMAGES_INSTITUTION_URL + germplasmGnpis.breeder.institute.logo"/> + </ng-template> + </gpds-card-row> <gpds-card-row label="Code" @@ -106,11 +113,14 @@ <ng-template #CollectorInstituteTemplate> - <figure *ngIf="germplasmGnpis.collector && germplasmGnpis.collector.institute && germplasmGnpis.collector.institute.logo"> - <img - [src]="IMAGES_INSTITUTION_URL + germplasmGnpis.collector.institute.logo" - align="middle" /> - </figure> + <gpds-card-row + label="" + [test]="germplasmGnpis.collector && germplasmGnpis.collector.institute && germplasmGnpis.collector.institute.logo"> + <ng-template> + <img + [src]="IMAGES_INSTITUTION_URL + germplasmGnpis.collector.institute.logo"/> + </ng-template> + </gpds-card-row> <gpds-card-row label="Code" @@ -142,24 +152,20 @@ </ng-template> </gpds-card-row> - </ng-template> - <!--Section for the image representing the germplasm and the details about this image--> <div class="col-auto field" *ngIf="germplasmGnpis.photo && germplasmGnpis.photo.thumbnailFileName"> - <figure class="figure"> + <a class="btn popovers" data-boundary="window" placement="right" [ngbPopover]="imageTemplate" + [popoverTitle]="germplasmGnpis.photo.photoName" container="body"> <img [src]="IMAGES_ACCESSION_URL + germplasmGnpis.holdingGenbank.instituteCode + '/' + germplasmGnpis.photo.thumbnailFileName" class="img-fluid"> <figcaption class="figure-caption"> - <a class="btn popovers" data-boundary="window" placement="right" [ngbPopover]="imageTemplate" - [popoverTitle]="germplasmGnpis.photo.photoName" container="body"> - Click to see more details. - </a> + Click to see more details </figcaption> - </figure> + </a> <ng-template #imageTemplate> <div class="card ngb-popover-window "> @@ -287,7 +293,7 @@ <gpds-card-row label="Institution"> <ng-template> - <a class="popovers" data-boundary="window" placement="top" + <a class="popover-underline" data-boundary="window" placement="top" [ngbPopover]="holdingInstituteTemplate" [popoverTitle]="germplasmGnpis.holdingInstitute.instituteName" container="body"> @@ -297,16 +303,19 @@ <gpds-card-row label="Stock center name" - [test]="germplasmGnpis.holdingGenbank.instituteName"> + [test]="germplasmGnpis.holdingGenbank.instituteName && germplasmGnpis.holdingGenbank.webSite"> <ng-template> - <ng-container *ngIf="germplasmGnpis.holdingGenbank.webSite"> - <a [href]="germplasmGnpis.holdingGenbank.webSite"> - {{ germplasmGnpis.holdingGenbank.instituteName }} - </a> - </ng-container> - <ng-container *ngIf="!germplasmGnpis.holdingGenbank.webSite"> + <a [href]="germplasmGnpis.holdingGenbank.webSite"> {{ germplasmGnpis.holdingGenbank.instituteName }} - </ng-container> + </a> + </ng-template> + </gpds-card-row> + + <gpds-card-row + label="Stock center name" + [test]="germplasmGnpis.holdingGenbank.instituteName && !germplasmGnpis.holdingGenbank.webSite"> + <ng-template> + {{ germplasmGnpis.holdingGenbank.instituteName }} </ng-template> </gpds-card-row> @@ -462,11 +471,14 @@ <tr> <ng-template #InstituteTemplate> - <figure *ngIf="row.donorInstitute && row.donorInstitute.logo"> - <img - [src]="IMAGES_INSTITUTION_URL + row.donorInstitute.logo" - align="middle" /> - </figure> + <gpds-card-row + label="" + [test]="row.donorInstitute && row.donorInstitute.logo"> + <ng-template> + <img + [src]="IMAGES_INSTITUTION_URL + row.donorInstitute.logo"/> + </ng-template> + </gpds-card-row> <gpds-card-row label="Code" @@ -540,11 +552,14 @@ <tr> <ng-template #InstituteTemplate> - <figure *ngIf="row.institute && row.institute.logo"> - <img - [src]="IMAGES_INSTITUTION_URL + row.institute.logo" - align="middle" /> - </figure> + <gpds-card-row + label="" + [test]="row.institute && row.institute.logo"> + <ng-template> + <img + [src]="IMAGES_INSTITUTION_URL + row.institute.logo"/> + </ng-template> + </gpds-card-row> <gpds-card-row label="Code" diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.scss b/frontend/src/app/germplasm-card/germplasm-card.component.scss index 017b0c22..6a31757b 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.scss +++ b/frontend/src/app/germplasm-card/germplasm-card.component.scss @@ -1,3 +1,2 @@ @import "theme"; @import '../../styles.scss'; - diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts b/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts index be45c114..f3b95ee3 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts +++ b/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts @@ -6,14 +6,7 @@ import { BrapiService } from '../brapi.service'; import { ActivatedRoute, convertToParamMap } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { of } from 'rxjs'; -import { - BrapiDescriptor, - BrapiDonor, - BrapiGermplasmAttributes, - BrapiGermplasmPedigree, - BrapiSibling -} from '../models/brapi.germplasm.model'; -import { Germplasm, GermplasmData, GermplasmResult, GermplasmSet, Institute, Origin, Site } from '../models/gnpis.germplasm.model'; + import { NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap'; import { MomentModule } from 'ngx-moment'; import { LoadingSpinnerComponent } from '../loading-spinner/loading-spinner.component'; @@ -21,6 +14,13 @@ import { CardSectionComponent } from '../card-section/card-section.component'; import { CardRowComponent } from '../card-row/card-row.component'; import { CardTableComponent } from '../card-table/card-table.component'; import { MapComponent } from '../map/map.component'; +import { + BrapiGermplasmAttributes, + BrapiGermplasmPedigree, + BrapiResult, + BrapiSibling +} from "../models/brapi.model"; +import {Donor, Germplasm, GermplasmInstitute, GermplasmSet, Institute, Site} from "../models/gnpis.model"; import { MockComponent } from 'ng-mocks'; import { XrefsComponent } from '../xrefs/xrefs.component'; @@ -59,7 +59,7 @@ describe('GermplasmCardComponent', () => { ] ); - const brapiSite: Site = { + const gnpisSite: Site = { latitude: null, longitude: null, siteId: null, @@ -72,13 +72,9 @@ describe('GermplasmCardComponent', () => { defaultDisplayName: 'frere1' }; - const brapiDescriptor: BrapiDescriptor = { - name: 'caracteristique1', - pui: '12', - value: '32' - }; - const brapiGermplasmPedigree: GermplasmResult<BrapiGermplasmPedigree> = { + const brapiGermplasmPedigree: BrapiResult<BrapiGermplasmPedigree> = { + metadata: null, result: { germplasmDbId: '12', defaultDisplayName: '12', @@ -104,7 +100,7 @@ describe('GermplasmCardComponent', () => { } };*/ - const brapiInstitute: Institute = { + const gnpisInstitute: Institute = { instituteName: 'urgi', instituteCode: 'inra', acronym: 'urgi', @@ -115,9 +111,8 @@ describe('GermplasmCardComponent', () => { logo: null }; - const brapiOrigin: Origin = { ... brapiInstitute, - institute: brapiInstitute, - germplasmPUI: '12', + const gnpisGermplasmInstitute: GermplasmInstitute = { ... gnpisInstitute, + institute: gnpisInstitute, accessionNumber: '12', accessionCreationDate: '1993', materialType: 'feuille', @@ -127,15 +122,15 @@ describe('GermplasmCardComponent', () => { distributionStatus: null }; - const brapiDonor: BrapiDonor = { - donorInstitute: brapiInstitute, + const gnpisDonor: Donor = { + donorInstitute: gnpisInstitute, donorGermplasmPUI: '12', donorAccessionNumber: '12', donorInstituteCode: 'urgi', donationDate: null }; - const germplasmSet: GermplasmSet = { + const gnpisGermplasmSet: GermplasmSet = { germplasmCount: 12, germplasmRef: null, id: 12, @@ -143,18 +138,21 @@ describe('GermplasmCardComponent', () => { type: 'plan' }; - const brapiGermplasmAttributes: GermplasmResult<GermplasmData<BrapiGermplasmAttributes[]>> = { + const brapiGermplasmAttributes: BrapiResult<BrapiGermplasmAttributes> = { + metadata: null, result: { + germplasmDbId: '12', data: [{ attributeName: 'longueur', - value: '30' + value: '30', + attributeDbId: '1', + attributeCode: 'longeur', + determinedDate: 'today' }] } }; const germplasmTest: Germplasm = { - url: 'www.cirad.fr', - source: 'cirad', germplasmDbId: 'test', defaultDisplayName: 'test', accessionNumber: 'test', @@ -175,7 +173,7 @@ describe('GermplasmCardComponent', () => { speciesAuthority: 'L', subtaxa: null, subtaxaAuthority: null, - donors: [brapiDonor], + donors: [gnpisDonor], acquisitionDate: null, genusSpecies: null, genusSpeciesSubtaxa: null, @@ -184,20 +182,19 @@ describe('GermplasmCardComponent', () => { geneticNature: null, comment: null, photo: null, - holdingInstitute: brapiInstitute, - holdingGenbank: brapiInstitute, + holdingInstitute: gnpisInstitute, + holdingGenbank: gnpisInstitute, presenceStatus: null, children: null, - descriptors: [brapiDescriptor], originSite: null, collectingSite: null, evaluationSites: null, - collector: brapiOrigin, - breeder: brapiOrigin, - distributors: [brapiOrigin], - panel: [germplasmSet], - collection: [germplasmSet], - population: [germplasmSet] + collector: gnpisGermplasmInstitute, + breeder: gnpisGermplasmInstitute, + distributors: [gnpisGermplasmInstitute], + panel: [gnpisGermplasmSet], + collection: [gnpisGermplasmSet], + population: [gnpisGermplasmSet] }; beforeEach(async(() => { diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.ts b/frontend/src/app/germplasm-card/germplasm-card.component.ts index fa242587..760f2060 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.ts +++ b/frontend/src/app/germplasm-card/germplasm-card.component.ts @@ -2,15 +2,15 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; import { BrapiService } from '../brapi.service'; import { GnpisService } from '../gnpis.service'; -import { Germplasm, GermplasmProgeny, Site } from '../models/gnpis.germplasm.model'; -import { BrapiGermplasmAttributes, BrapiGermplasmPedigree } from '../models/brapi.germplasm.model'; -import { BrapiLocation } from '../models/brapi.model'; +import { Germplasm, Children, Site } from '../models/gnpis.germplasm.model'; +import { BrapiGermplasmPedigree } from '../models/brapi.germplasm.model'; +import { BrapiGermplasmAttributes, BrapiLocation } from '../models/brapi.model'; -@Component({ +@Component( { selector: 'gpds-germplasm-card', templateUrl: './germplasm-card.component.html', styleUrls: ['./germplasm-card.component.scss'] -}) +} ) export class GermplasmCardComponent implements OnInit { @@ -31,7 +31,7 @@ export class GermplasmCardComponent implements OnInit { germplasmGnpis: Germplasm; germplasmPedigree: BrapiGermplasmPedigree; - germplasmProgeny: GermplasmProgeny[]; + germplasmProgeny: Children[]; germplasmAttributes: BrapiGermplasmAttributes[]; germplasmLocations: BrapiLocation[] = []; germplasmId: string; diff --git a/frontend/src/app/gnpis.service.spec.ts b/frontend/src/app/gnpis.service.spec.ts index 63d96558..07f47f89 100644 --- a/frontend/src/app/gnpis.service.spec.ts +++ b/frontend/src/app/gnpis.service.spec.ts @@ -1,9 +1,9 @@ -import { Germplasm, GermplasmSet, Institute, Origin, Site } from './models/gnpis.germplasm.model'; +import { Germplasm, GermplasmSet, Institute, GermplasmInstitute, Site } from './models/gnpis.germplasm.model'; import { BASE_URL, BASE_URL_GERMPLASM, GnpisService } from './gnpis.service'; -import { BrapiMetaData, BrapiResults } from './models/brapi.model'; +import {BrapiDonor, BrapiMetaData, BrapiResults} from './models/brapi.model'; import { DataDiscoveryCriteria, DataDiscoverySource } from './models/data-discovery.model'; -import { BrapiDescriptor, BrapiDonor } from './models/brapi.germplasm.model'; +import { BrapiDescriptor} from './models/brapi.germplasm.model'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { TestBed } from '@angular/core/testing'; @@ -51,7 +51,7 @@ describe('GnpisService', () => { logo: null }; - const brapiOrigin: Origin = { ...brapiInstitute, + const brapiOrigin: GermplasmInstitute = { ...brapiInstitute, institute: brapiInstitute, germplasmPUI: '12', accessionNumber: '12', diff --git a/frontend/src/app/map/map.component.html b/frontend/src/app/map/map.component.html index d6143c13..9285cb1a 100644 --- a/frontend/src/app/map/map.component.html +++ b/frontend/src/app/map/map.component.html @@ -1,6 +1,6 @@ <div id="map" class="rounded"> </div> -<div id="maplegend"> +<div *ngIf="curatedLocationList.length > 0" id="maplegend"> <img src="assets/gpds/images/marker-icon-red.png" id="red"/> <label for="red">Origin site</label> <img src="assets/gpds/images/marker-icon-blue.png" id="blue"/> diff --git a/frontend/src/app/map/map.component.ts b/frontend/src/app/map/map.component.ts index df746dd8..a5898c75 100644 --- a/frontend/src/app/map/map.component.ts +++ b/frontend/src/app/map/map.component.ts @@ -11,17 +11,20 @@ import { BrapiLocation } from '../models/brapi.model'; export class MapComponent implements OnInit { @Input() locations: BrapiLocation[]; + curatedLocationList: BrapiLocation[] = []; constructor() { } ngOnInit() { - const container = L.DomUtil.get('map'); - if (container) { + + this.removeEmptyLocations(this.locations); + if (this.curatedLocationList.length > 0) { + const container = L.DomUtil.get('map'); const map = L.map('map'); // initialize map centered on the first site - const firstLocation: BrapiLocation = this.locations[0]; + const firstLocation: BrapiLocation = this.curatedLocationList[0]; if (firstLocation) { map.setView([firstLocation.latitude, firstLocation.longitude], 5); } @@ -30,9 +33,10 @@ export class MapComponent implements OnInit { attribution: 'Tiles © Esri — Source: Esri, DeLorme, NAVTEQ, USGS, Intermap, iPC, NRCAN, Esri Japan, METI, ' + 'Esri China (Hong Kong), Esri (Thailand), TomTom, 2012' }).addTo(map); + // add markers for all locations using markercluster plugin const markers = new MarkerClusterGroup(); - for (const location of this.locations) { + for (const location of this.curatedLocationList) { const icon = L.icon({ iconUrl: this.getMarkerIconUrl(location) }); @@ -49,11 +53,14 @@ export class MapComponent implements OnInit { ); } map.addLayer(markers); + } else { + L.DomUtil.get('map').remove(); } } + getMarkerIconUrl(site: BrapiLocation): string { - if (site.locationType === 'Origin site') { + if (site.locationType === 'GermplasmInstitute site') { return 'assets/gpds/images/marker-icon-red.png'; } if (site.locationType === 'Collecting site') { @@ -64,4 +71,12 @@ export class MapComponent implements OnInit { } return 'assets/gpds/images/marker-icon-purple.png'; } + + removeEmptyLocations(locations: BrapiLocation[]) { + for (const location of locations) { + if (location.latitude && location.longitude) { + this.curatedLocationList.push(location); + } + } + } } diff --git a/frontend/src/app/models/brapi.germplasm.model.ts b/frontend/src/app/models/brapi.germplasm.model.ts deleted file mode 100644 index 3730d768..00000000 --- a/frontend/src/app/models/brapi.germplasm.model.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { Institute } from './gnpis.germplasm.model'; - - -export interface BrapiSibling { - germplasmDbId: string; - defaultDisplayName: string; -} - -export interface BrapiDescriptor { - name: string; - pui: string; - value: string; -} - -export interface BrapiGermplasmPedigree { - germplasmDbId: string; - defaultDisplayName: string; - pedigree: string; - crossingPlan: string; - crossingYear: string; - familyCode: string; - parent1DbId: string; - parent1Name: string; - parent1Type: string; - parent2DbId: string; - parent2Name: string; - parent2Type: string; - siblings: BrapiSibling[]; -} - -export interface BrapiGermplasmProgeny { - germplasmDbId: string; - defaultDisplayName: string; - progeny: BrapiSibling[]; -} - -export interface BrapiGermplasmAttributes { - attributeName: string; - value: string; -} - -export interface BrapiDonor { - donorGermplasmPUI: string; - donorAccessionNumber: string; - donorInstituteCode: string; - donationDate: number; - donorInstitute: Institute; -} - diff --git a/frontend/src/app/models/brapi.model.ts b/frontend/src/app/models/brapi.model.ts index 285cc134..fa996380 100644 --- a/frontend/src/app/models/brapi.model.ts +++ b/frontend/src/app/models/brapi.model.ts @@ -14,7 +14,7 @@ export interface BrapiResult<T> { } -interface BrapiData<T> { +export interface BrapiData<T> { data: T[]; } @@ -42,7 +42,7 @@ export interface BrapiStudy extends BrapiHasDocumentationURL { trialDbIds: string[]; location: BrapiLocation; contacts: BrapiContacts[]; - additionalInfo: AdditionalInfo; + additionalInfo: BrapiAdditionalInfo; dataLinks: { name: string; type: string; @@ -51,6 +51,15 @@ export interface BrapiStudy extends BrapiHasDocumentationURL { } +export interface BrapiContacts { + contactDbId: string; + name: string; + email: string; + type: string; + institutionName: string; +} + + export interface BrapiLocation extends BrapiHasDocumentationURL { locationDbId: string; locationName: string; @@ -63,24 +72,15 @@ export interface BrapiLocation extends BrapiHasDocumentationURL { altitude?: number; latitude: number; longitude: number; - additionalInfo?: AdditionalInfo; + additionalInfo?: BrapiAdditionalInfo; } -export interface AdditionalInfo { +export interface BrapiAdditionalInfo { [key: string]: string; } -export interface BrapiContacts { - contactDbId: string; - name: string; - email: string; - type: string; - institutionName: string; -} - - export interface BrapiObservationVariable extends BrapiHasDocumentationURL { observationVariableDbId: string; contextOfUse: string[]; @@ -99,23 +99,99 @@ export interface BrapiObservationVariable extends BrapiHasDocumentationURL { } +export interface BrapiTrial extends BrapiHasDocumentationURL { + trialDbId: string; + trialName: string; + trialType: string; + active: boolean; + studies: { + studyDbId: string; + studyName: string; + }[]; +} + export interface BrapiGermplasm extends BrapiHasDocumentationURL { germplasmDbId: string; + defaultDisplayName: string; accessionNumber: string; germplasmName: string; + germplasmPUI: string; + pedigree: string; + seedSource: string; + synonyms: string[]; + commonCropName: string; + instituteCode: string; + instituteName: string; + biologicalStatusOfAccessionCode: string; + countryOfOriginCode: string; + typeOfGermplasmStorageCode: string[]; + taxonIds: BrapiTaxonIds[]; genus: string; species: string; + speciesAuthority: string; subtaxa: string; + subtaxaAuthority: string; + donors: BrapiDonor[]; + acquisitionDate: string; } -export interface BrapiTrial extends BrapiHasDocumentationURL { - trialDbId: string; - trialName: string; - trialType: string; - active: boolean; - studies: { - studyDbId: string; - studyName: string; - }[]; +export interface BrapiTaxonIds { + sourceName: string; + taxonId: string; +} + +export interface BrapiDonor { + donorGermplasmPUI: string; + donorAccessionNumber: string; + donorInstituteCode: string; + donationDate: number; +} + +export interface BrapiGermplasmPedigree { + germplasmDbId: string; + defaultDisplayName: string; + pedigree: string; + crossingPlan: string; + crossingYear: string; + familyCode: string; + parent1DbId: string; + parent1Name: string; + parent1Type: string; + parent2DbId: string; + parent2Name: string; + parent2Type: string; + siblings: BrapiSibling[]; +} + +export interface BrapiSibling { + germplasmDbId: string; + defaultDisplayName: string; +} + +export interface BrapiGermplasmProgeny { + germplasmDbId: string; + defaultDisplayName: string; + progeny: BrapiProgeny[]; +} + +export interface BrapiProgeny { + germplasmDbId: string; + defaultDisplayName: string; + parentType: string; + +} + + +export interface BrapiGermplasmAttributes { + germplasmDbId: string; + data: BrapiAttributeData[]; +} + +export interface BrapiAttributeData { + attributeDbId: string; + attributeName: string; + attributeCode: string; + value: string; + determinedDate: string; } diff --git a/frontend/src/app/models/gnpis.germplasm.model.ts b/frontend/src/app/models/gnpis.model.ts similarity index 55% rename from frontend/src/app/models/gnpis.germplasm.model.ts rename to frontend/src/app/models/gnpis.model.ts index a37a9537..41f0a216 100644 --- a/frontend/src/app/models/gnpis.germplasm.model.ts +++ b/frontend/src/app/models/gnpis.model.ts @@ -1,4 +1,28 @@ -import { BrapiDescriptor, BrapiDonor } from './brapi.germplasm.model'; +import {BrapiDonor, BrapiGermplasm} from "./brapi.model"; + +export interface Germplasm extends BrapiGermplasm { + genusSpecies: string; + genusSpeciesSubtaxa: string; + taxonSynonyms: string[]; + taxonCommonNames: string[]; + geneticNature: string; + comment: string; + photo: Photo; + holdingInstitute: Institute; + holdingGenbank: Institute; + presenceStatus: string; + children: Children[]; + originSite: Site; + collectingSite: Site; + evaluationSites: Site[]; + collector: GermplasmInstitute; + breeder: GermplasmInstitute; + donors: Donor[]; + distributors: GermplasmInstitute[]; + panel: GermplasmSet[]; + collection: GermplasmSet[]; + population: GermplasmSet[]; +} export interface Site { latitude: number; @@ -19,9 +43,8 @@ export interface Institute { logo: string; } -export interface Origin extends Institute { +export interface GermplasmInstitute extends Institute { institute: Institute; - germplasmPUI: string; accessionNumber: string; accessionCreationDate: string; materialType: string; @@ -40,17 +63,11 @@ export interface Photo { } -export interface GermplasmProgeny { - - crossingPlan: string; - crossingYear: string; - familyCode: string; +export interface Children { firstParentName: string; firstParentPUI: string; - firstParentType: string; secondParentName: string; secondParentPUI: string; - secondParentType: string; sibblings: { name: string; pui: string; @@ -58,54 +75,11 @@ export interface GermplasmProgeny { } -export interface Germplasm { - source: string; - url: string; - germplasmDbId: string; - defaultDisplayName: string; - accessionNumber: string; - germplasmName: string; - germplasmPUI: string; - pedigree: string; - seedSource: string; - synonyms: string[]; - commonCropName: string; - instituteCode: string; - instituteName: string; - biologicalStatusOfAccessionCode: string; - countryOfOriginCode: string; - typeOfGermplasmStorageCode: string; - taxonIds: string; - genus: string; - species: string; - speciesAuthority: string; - subtaxa: string; - subtaxaAuthority: string; - donors: BrapiDonor[]; - acquisitionDate: string; - genusSpecies: string; - genusSpeciesSubtaxa: string; - taxonSynonyms: string[]; - taxonCommonNames: string[]; - geneticNature: string; - comment: string; - photo: Photo; - holdingInstitute: Institute; - holdingGenbank: Institute; - presenceStatus: string; - children: GermplasmProgeny[]; - descriptors: BrapiDescriptor[]; - originSite: Site; - collectingSite: Site; - evaluationSites: Site[]; - collector: Origin; - breeder: Origin; - distributors: Origin[]; - panel: GermplasmSet[]; - collection: GermplasmSet[]; - population: GermplasmSet[]; +export interface Donor extends BrapiDonor{ + donorInstitute: Institute } + export interface GermplasmSet { id: number; name: string; @@ -116,16 +90,3 @@ export interface GermplasmSet { name: string; }; } - - -export interface GermplasmData<T> { - data: T; -} - -export interface GermplasmResult<T> { - result: T; -} - - - - diff --git a/frontend/src/app/site-card/site-card.component.html b/frontend/src/app/site-card/site-card.component.html index 3f949ca4..20f9dd15 100644 --- a/frontend/src/app/site-card/site-card.component.html +++ b/frontend/src/app/site-card/site-card.component.html @@ -7,7 +7,7 @@ </h3> - <gpds-map [locations]="[location]" *ngIf="location && location.latitude && location.longitude"></gpds-map> + <gpds-map [locations]="[location]"></gpds-map> @@ -15,10 +15,6 @@ header="Details"> <ng-template> <div class="card-body card-section-body"> - <gpds-card-row - label="Site type" - [value]="location.locationType"> - </gpds-card-row> <gpds-card-row label="Abbreviation" @@ -26,57 +22,117 @@ </gpds-card-row> <gpds-card-row - label="Country code" - [value]="location.countryCode"> + label="Type" + [value]="location.locationType"> </gpds-card-row> <gpds-card-row - label="Country name" - [test]="location.countryName && !location.additionalInfo['Geographical location']" - [value]="location.countryName"> + label="Status" + [value]="location.additionalInfo['Site status']"> </gpds-card-row> <gpds-card-row - label="Institution address" - [value]="location.institutionAddress"> + label="Institution/Landowner" + [value]="location.institutionName"> </gpds-card-row> <gpds-card-row - label="Institution name" + label="Institution address" [value]="location.institutionAddress"> </gpds-card-row> <gpds-card-row - label="Altitude" - [value]="location.altitude"> + label="Coordinates precision" + [value]="location.additionalInfo['Coordinates precision']"> </gpds-card-row> <gpds-card-row label="Latitude" [value]="location.latitude"> + <!--[value]="formatCoordinates(location.latitude)">--> </gpds-card-row> <gpds-card-row label="Longitude" [value]="location.longitude"> + <!--[value]="formatCoordinates(location.longitude)">--> + </gpds-card-row> + + <gpds-card-row + label="Geographical location" + [value]="location.additionalInfo['Geographical location']"> + </gpds-card-row> + + <gpds-card-row + label="Country name" + [test]="location.countryName && !location.additionalInfo['Geographical location']" + [value]="location.countryName"> </gpds-card-row> + + <gpds-card-row + label="Country code" + [test]="location.countryCode && !location.additionalInfo['Geographical location']"> + [value]="location.countryCode"> + </gpds-card-row> + + <gpds-card-row + label="Altitude" + [value]="location.altitude"> + </gpds-card-row> + + <gpds-card-row + label="Slope" + [value]="location.additionalInfo['Slope']"> + </gpds-card-row> + + <gpds-card-row + label="Exposure" + [value]="location.additionalInfo['Exposure']"> + </gpds-card-row> + + <gpds-card-row + label="Topography" + [value]="location.additionalInfo['Topography']"> + </gpds-card-row> + + <gpds-card-row + label="Environment type" + [value]="location.additionalInfo['Environment type']"> + </gpds-card-row> + + <gpds-card-row + label="Distance to city" + [value]="location.additionalInfo['Distance to city']"> + </gpds-card-row> + + <gpds-card-row + label="Direction from city" + [value]="location.additionalInfo['Direction from city']"> + </gpds-card-row> + + <gpds-card-row + label="Comment" + [value]="location.additionalInfo['Comment']"> + </gpds-card-row> + </div> </ng-template> </gpds-card-section> <gpds-card-section header="Additional information" - [test]="additionalInfos && additionalInfos.length != 0"> + [test]="additionalInfos && additionalInfos.length > 0"> <ng-template> - <gpds-card-table - [rows]="additionalInfos"> - <ng-template let-row> - <tr> - <td width="50%">{{ row.key }}</td> - <td>{{ row.value }}</td> - </tr> - </ng-template> - </gpds-card-table> + <div class="card-body card-section-body"> + + <ng-container *ngFor="let additionalInfo of additionalInfos"> + <gpds-card-row + [label]="additionalInfo.key" + [value]="additionalInfo.value"> + </gpds-card-row> + </ng-container> + + </div> </ng-template> </gpds-card-section> diff --git a/frontend/src/app/site-card/site-card.component.ts b/frontend/src/app/site-card/site-card.component.ts index d892c85d..0bdb4bd5 100644 --- a/frontend/src/app/site-card/site-card.component.ts +++ b/frontend/src/app/site-card/site-card.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { BrapiService } from '../brapi.service'; import { ActivatedRoute } from '@angular/router'; -import { BrapiLocation } from '../models/brapi.model'; +import {BrapiAdditionalInfo, BrapiLocation} from '../models/brapi.model'; import { KeyValueObject } from '../utils'; @Component({ @@ -28,7 +28,8 @@ export class SiteCardComponent implements OnInit { this.location = response.result; this.additionalInfos = []; if (this.location.additionalInfo) { - this.additionalInfos = KeyValueObject.fromObject(this.location.additionalInfo); + console.log(this.location.additionalInfo); + this.manageAdditionalInfo(KeyValueObject.fromObject(this.location.additionalInfo)); } this.loading = false; } @@ -36,4 +37,44 @@ export class SiteCardComponent implements OnInit { }); } + + manageAdditionalInfo(keyValues: KeyValueObject[]) { + var forbiddenElements: String[] = ['Site status', 'Coordinates precision', 'Slope', 'Exposure', 'Geographical location', 'Distance to city', 'Direction from city', 'Environment type', 'Topography', 'Comment']; + for (const keyValue of keyValues) { + if (!forbiddenElements.includes(keyValue.key)) { + this.additionalInfos.push(keyValue); + } + } + } + + formatCoordinates(decimalDegrees: number, type: string): string { + if (decimalDegrees && type) { + var degree = Math.floor(decimalDegrees); + var decimalMinute = (decimalDegrees - degree) * 60; + var minute = Math.floor(decimalMinute); + var decimalSeconde = (decimalMinute - minute) * 60; + var seconde = Math.floor(decimalSeconde); + + var direction = ''; + if (type == 'latitude') { + if (decimalDegrees >= 0) { + direction = "N"; + } else { + direction = "S"; + } + } + else if (type == 'longitude') { + if (decimalDegrees >= 0) { + direction = "E"; + } else { + direction = "W"; + } + } + return decimalDegrees + "° (" + degree + "° " + minute + "' " + seconde + "'' " + direction + ")"; + } else { + return null; + } + } + } + diff --git a/frontend/src/app/study-card/study-card.component.html b/frontend/src/app/study-card/study-card.component.html index 652a3231..0eed21c1 100644 --- a/frontend/src/app/study-card/study-card.component.html +++ b/frontend/src/app/study-card/study-card.component.html @@ -6,7 +6,7 @@ </h3> <!-- Display the map --> - <gpds-map *ngIf="checkLocation(study.location)" [locations]="[study.location]"></gpds-map> + <gpds-map [locations]="[study.location]"></gpds-map> <!-- Display the study's info --> <gpds-card-section diff --git a/frontend/src/app/study-card/study-card.component.ts b/frontend/src/app/study-card/study-card.component.ts index a8f729b2..84f13ced 100644 --- a/frontend/src/app/study-card/study-card.component.ts +++ b/frontend/src/app/study-card/study-card.component.ts @@ -92,10 +92,6 @@ export class StudyCardComponent implements OnInit { } - checkLocation(location: BrapiLocation) { - return location && location.longitude && location.latitude; - } - isNotURN(pui: string) { return !(pui.substring(0, 3) === 'urn'); } diff --git a/frontend/src/assets/gpds/theme.scss b/frontend/src/assets/gpds/theme.scss index 44791e76..b4fae40f 100644 --- a/frontend/src/assets/gpds/theme.scss +++ b/frontend/src/assets/gpds/theme.scss @@ -36,13 +36,6 @@ $enable-shadows: true; } - -a.btn.popovers { - text-decoration: underline; - //overflow: hidden; - //text-overflow: ellipsis; -} - .popover { max-width: 100%; } diff --git a/frontend/src/tslint.json b/frontend/src/tslint.json index f13a8ca1..7e545ab7 100644 --- a/frontend/src/tslint.json +++ b/frontend/src/tslint.json @@ -15,7 +15,7 @@ ], "template-cyclomatic-complexity": [ true, - 18 + 10 ] } } -- GitLab From cb407e56e2905d454f9bafa6ddce4a18788405ec Mon Sep 17 00:00:00 2001 From: jdestin <jeremy.destin@inra.fr> Date: Mon, 11 Mar 2019 12:23:47 +0100 Subject: [PATCH 12/20] fix: Fix the test. Rename and use the good models. Minor fixes. GNP-5490 --- frontend/src/app/brapi.service.spec.ts | 46 ++++++++++++------- frontend/src/app/brapi.service.ts | 15 +++--- .../germplasm-card.component.html | 5 +- .../germplasm-card.component.spec.ts | 8 +++- .../germplasm-card.component.ts | 20 +++----- frontend/src/app/gnpis.service.spec.ts | 27 ++++------- frontend/src/app/gnpis.service.ts | 2 +- frontend/src/app/models/gnpis.model.ts | 8 ++-- .../document/document.component.html | 4 +- .../src/app/site-card/site-card.component.ts | 41 ++++++++++------- .../study-card/study-card.component.spec.ts | 38 +++++++++++++-- 11 files changed, 127 insertions(+), 87 deletions(-) diff --git a/frontend/src/app/brapi.service.spec.ts b/frontend/src/app/brapi.service.spec.ts index 9bca7064..d1530e5b 100644 --- a/frontend/src/app/brapi.service.spec.ts +++ b/frontend/src/app/brapi.service.spec.ts @@ -1,18 +1,23 @@ import { BrapiService } from './brapi.service'; import { - BrapiContacts, BrapiData, BrapiDonor, - BrapiGermplasm, BrapiGermplasmAttributes, BrapiGermplasmPedigree, BrapiGermplasmProgeny, + BrapiContacts, + BrapiGermplasm, + BrapiGermplasmAttributes, + BrapiGermplasmPedigree, + BrapiGermplasmProgeny, BrapiLocation, BrapiObservationVariable, - BrapiResult, BrapiResults, BrapiSibling, - BrapiStudy, BrapiTaxonIds, + BrapiProgeny, + BrapiResult, + BrapiResults, + BrapiSibling, + BrapiStudy, BrapiTrial } from './models/brapi.model'; import { DataDiscoverySource } from './models/data-discovery.model'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { TestBed } from '@angular/core/testing'; -import {Germplasm, GermplasmInstitute, GermplasmSet, Institute, Site} from "./models/gnpis.model"; -import Result = jasmine.Result; +import { Donor, Germplasm, GermplasmInstitute, GermplasmSet, Institute, Site } from './models/gnpis.model'; describe('BrapiService', () => { @@ -172,7 +177,14 @@ describe('BrapiService', () => { defaultDisplayName: 'frere1' }; + const brapiProgeny: BrapiProgeny = { + germplasmDbId: 'test', + defaultDisplayName: 'progeny1', + parentType: 'parent1' + }; + const brapiGermplasmPedigree: BrapiResult<BrapiGermplasmPedigree> = { + metadata: null, result: { germplasmDbId: 'test', defaultDisplayName: '12', @@ -191,10 +203,11 @@ describe('BrapiService', () => { }; const brapiGermplasmProgeny: BrapiResult<BrapiGermplasmProgeny> = { + metadata: null, result: { germplasmDbId: 'test', defaultDisplayName: '11', - progeny: [brapiSibling] + progeny: [brapiProgeny] } }; @@ -209,9 +222,9 @@ describe('BrapiService', () => { address: '12', logo: null }; - const origin: GermplasmInstitute = { ... institute, + const origin: GermplasmInstitute = { + ...institute, institute: institute, - germplasmPUI: '12', accessionNumber: '12', accessionCreationDate: '1993', materialType: 'feuille', @@ -221,7 +234,7 @@ describe('BrapiService', () => { distributionStatus: null }; - const brapiDonor: BrapiDonor = { + const brapiDonor: Donor = { donorInstitute: institute, donorGermplasmPUI: '12', donorAccessionNumber: '12', @@ -237,10 +250,15 @@ describe('BrapiService', () => { type: 'plan' }; - const brapiGermplasmAttributes: BrapiResult<BrapiData<BrapiGermplasmAttributes[]>> = { + const brapiGermplasmAttributes: BrapiResult<BrapiGermplasmAttributes> = { + metadata: null, result: { + germplasmDbId: 'test', data: [{ + attributeCode: 'att', + attributeDbId: 'attr2', attributeName: 'longueur', + determinedDate: '2019', value: '30' }] } @@ -291,10 +309,6 @@ describe('BrapiService', () => { population: [germplasmSet] }; - const germplasmResultTest = { - result: germplasmTest - }; - let brapiService: BrapiService; let http: HttpTestingController; @@ -408,7 +422,7 @@ describe('BrapiService', () => { it('should fetch the germplasm attributes', () => { - let fetchedGermplasmAttributes: BrapiResult<BrapiData<BrapiGermplasmAttributes[]>>; + let fetchedGermplasmAttributes: BrapiResult<BrapiGermplasmAttributes>; const germplasmDbId: string = germplasmTest.germplasmDbId; brapiService.germplasmAttributes(germplasmDbId).subscribe(response => { fetchedGermplasmAttributes = response; diff --git a/frontend/src/app/brapi.service.ts b/frontend/src/app/brapi.service.ts index 72740e34..1d9897b3 100644 --- a/frontend/src/app/brapi.service.ts +++ b/frontend/src/app/brapi.service.ts @@ -1,9 +1,10 @@ import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { HttpClient } from '@angular/common/http'; -import { Germplasm, GermplasmData, GermplasmResult } from './models/gnpis.germplasm.model'; import { - BrapiGermplasm, BrapiGermplasmAttributes, + BrapiGermplasm, + BrapiGermplasmAttributes, + BrapiGermplasmPedigree, BrapiLocation, BrapiObservationVariable, BrapiResult, @@ -11,7 +12,7 @@ import { BrapiStudy, BrapiTrial } from './models/brapi.model'; -import { BrapiGermplasmPedigree } from './models/brapi.germplasm.model'; +import { Germplasm } from './models/gnpis.model'; export const BASE_URL = 'brapi/v1'; @@ -28,18 +29,18 @@ export class BrapiService { .get<Germplasm>(`${BASE_URL}/germplasm/${germplasmDbId}`); } - germplasmPedigree(germplasmDbId: string): Observable<GermplasmResult<BrapiGermplasmPedigree>> { + germplasmPedigree(germplasmDbId: string): Observable<BrapiResult<BrapiGermplasmPedigree>> { return this.http - .get<GermplasmResult<BrapiGermplasmPedigree>>(`${BASE_URL}/germplasm/${germplasmDbId}/pedigree`); + .get<BrapiResult<BrapiGermplasmPedigree>>(`${BASE_URL}/germplasm/${germplasmDbId}/pedigree`); } /*germplasmProgeny(germplasmDbId: string): Observable<GermplasmResult<BrapiGermplasmProgeny>> { return this.http.get<GermplasmResult<BrapiGermplasmProgeny>>(`${BASE_URL}/germplasm/${germplasmDbId}/progeny`); }*/ - germplasmAttributes(germplasmDbId: string): Observable<GermplasmResult<GermplasmData<BrapiGermplasmAttributes[]>>> { + germplasmAttributes(germplasmDbId: string): Observable<BrapiResult<BrapiGermplasmAttributes>> { return this.http - .get<GermplasmResult<GermplasmData<BrapiGermplasmAttributes[]>>>(`${BASE_URL}/germplasm/${germplasmDbId}/attributes`); + .get<BrapiResult<BrapiGermplasmAttributes>>(`${BASE_URL}/germplasm/${germplasmDbId}/attributes`); } study(studyDbId: string): Observable<BrapiResult<BrapiStudy>> { diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.html b/frontend/src/app/germplasm-card/germplasm-card.component.html index 80c8b030..f7c19c04 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.html +++ b/frontend/src/app/germplasm-card/germplasm-card.component.html @@ -430,10 +430,7 @@ <gpds-card-row label="Accession creation year" - [test]="germplasmGnpis.breeder.accessionCreationDate "> - <ng-template> - {{ germplasmGnpis.breeder.accessionCreationDate }} - </ng-template> + [value]="germplasmGnpis.breeder.accessionCreationDate "> </gpds-card-row> <gpds-card-row diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts b/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts index f3b95ee3..16ca92d0 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts +++ b/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts @@ -14,6 +14,8 @@ import { CardSectionComponent } from '../card-section/card-section.component'; import { CardRowComponent } from '../card-row/card-row.component'; import { CardTableComponent } from '../card-table/card-table.component'; import { MapComponent } from '../map/map.component'; +import { BrapiGermplasmAttributes, BrapiGermplasmPedigree, BrapiResult, BrapiSibling } from '../models/brapi.model'; +import { Donor, Germplasm, GermplasmInstitute, GermplasmSet, Institute, Site } from '../models/gnpis.model'; import { BrapiGermplasmAttributes, BrapiGermplasmPedigree, @@ -111,7 +113,8 @@ describe('GermplasmCardComponent', () => { logo: null }; - const gnpisGermplasmInstitute: GermplasmInstitute = { ... gnpisInstitute, + const gnpisGermplasmInstitute: GermplasmInstitute = { + ...gnpisInstitute, institute: gnpisInstitute, accessionNumber: '12', accessionCreationDate: '1993', @@ -208,7 +211,8 @@ describe('GermplasmCardComponent', () => { providers: [ { provide: BrapiService, useValue: brapiService }, { provide: GnpisService, useValue: gnpisService }, - { provide: ActivatedRoute, + { + provide: ActivatedRoute, useValue: { snapshot: { queryParams: convertToParamMap({ diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.ts b/frontend/src/app/germplasm-card/germplasm-card.component.ts index 760f2060..ca813c0a 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.ts +++ b/frontend/src/app/germplasm-card/germplasm-card.component.ts @@ -2,9 +2,8 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; import { BrapiService } from '../brapi.service'; import { GnpisService } from '../gnpis.service'; -import { Germplasm, Children, Site } from '../models/gnpis.germplasm.model'; -import { BrapiGermplasmPedigree } from '../models/brapi.germplasm.model'; -import { BrapiGermplasmAttributes, BrapiLocation } from '../models/brapi.model'; +import { BrapiAttributeData, BrapiGermplasmPedigree, BrapiLocation } from '../models/brapi.model'; +import { Children, Germplasm, Site } from '../models/gnpis.model'; @Component( { selector: 'gpds-germplasm-card', @@ -32,7 +31,7 @@ export class GermplasmCardComponent implements OnInit { germplasmGnpis: Germplasm; germplasmPedigree: BrapiGermplasmPedigree; germplasmProgeny: Children[]; - germplasmAttributes: BrapiGermplasmAttributes[]; + germplasmAttributes: BrapiAttributeData[]; germplasmLocations: BrapiLocation[] = []; germplasmId: string; germplasmPuid: string; @@ -130,15 +129,11 @@ export class GermplasmCardComponent implements OnInit { checkBreeder() { return (this.germplasmGnpis.breeder) - && (this.germplasmGnpis.breeder.institute.instituteName - || this.germplasmGnpis.breeder.germplasmPUI - || this.germplasmGnpis.breeder.accessionNumber + && (this.germplasmGnpis.breeder.institute || this.germplasmGnpis.breeder.accessionCreationDate - || this.germplasmGnpis.breeder.materialType - || this.germplasmGnpis.breeder.collectors + || this.germplasmGnpis.breeder.accessionNumber || this.germplasmGnpis.breeder.registrationYear - || this.germplasmGnpis.breeder.deregistrationYear - || this.germplasmGnpis.breeder.distributionStatus); + || this.germplasmGnpis.breeder.deregistrationYear); } checkPedigree() { @@ -161,8 +156,7 @@ export class GermplasmCardComponent implements OnInit { checkCollectorInstituteFields() { return (this.germplasmGnpis.collector) && - (this.germplasmGnpis.collector.germplasmPUI - || this.germplasmGnpis.collector.accessionNumber + (this.germplasmGnpis.collector.accessionNumber || this.germplasmGnpis.collector.accessionCreationDate || this.germplasmGnpis.collector.materialType || this.germplasmGnpis.collector.collectors diff --git a/frontend/src/app/gnpis.service.spec.ts b/frontend/src/app/gnpis.service.spec.ts index 07f47f89..13f50d13 100644 --- a/frontend/src/app/gnpis.service.spec.ts +++ b/frontend/src/app/gnpis.service.spec.ts @@ -1,11 +1,9 @@ -import { Germplasm, GermplasmSet, Institute, GermplasmInstitute, Site } from './models/gnpis.germplasm.model'; - import { BASE_URL, BASE_URL_GERMPLASM, GnpisService } from './gnpis.service'; -import {BrapiDonor, BrapiMetaData, BrapiResults} from './models/brapi.model'; +import { BrapiMetaData, BrapiResults } from './models/brapi.model'; import { DataDiscoveryCriteria, DataDiscoverySource } from './models/data-discovery.model'; -import { BrapiDescriptor} from './models/brapi.germplasm.model'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { TestBed } from '@angular/core/testing'; +import { Donor, Germplasm, GermplasmInstitute, GermplasmSet, Institute, Site } from './models/gnpis.model'; describe('GnpisService', () => { @@ -34,12 +32,6 @@ describe('GnpisService', () => { siteType: null }; - const brapiDescriptor: BrapiDescriptor = { - name: 'caracteristique1', - pui: '12', - value: '32' - }; - const brapiInstitute: Institute = { instituteName: 'urgi', instituteCode: 'inra', @@ -51,9 +43,9 @@ describe('GnpisService', () => { logo: null }; - const brapiOrigin: GermplasmInstitute = { ...brapiInstitute, + const germplasmInstitute: GermplasmInstitute = { + ...brapiInstitute, institute: brapiInstitute, - germplasmPUI: '12', accessionNumber: '12', accessionCreationDate: '1993', materialType: 'feuille', @@ -63,7 +55,7 @@ describe('GnpisService', () => { distributionStatus: null }; - const brapiDonor: BrapiDonor = { + const brapiDonor: Donor = { donorInstitute: brapiInstitute, donorGermplasmPUI: '12', donorAccessionNumber: '12', @@ -80,8 +72,6 @@ describe('GnpisService', () => { }; const germplasmTest: Germplasm = { - url: 'www.cirad.fr', - source: 'cirad', germplasmDbId: 'test', defaultDisplayName: 'test', accessionNumber: 'test', @@ -115,13 +105,12 @@ describe('GnpisService', () => { holdingGenbank: brapiInstitute, presenceStatus: null, children: null, - descriptors: [brapiDescriptor], originSite: site, collectingSite: null, evaluationSites: null, - collector: brapiOrigin, - breeder: brapiOrigin, - distributors: [brapiOrigin], + collector: germplasmInstitute, + breeder: germplasmInstitute, + distributors: [germplasmInstitute], panel: [germplasmSet], collection: [germplasmSet], population: [germplasmSet] diff --git a/frontend/src/app/gnpis.service.ts b/frontend/src/app/gnpis.service.ts index 1a7cee82..1abb0482 100644 --- a/frontend/src/app/gnpis.service.ts +++ b/frontend/src/app/gnpis.service.ts @@ -1,10 +1,10 @@ import { Injectable } from '@angular/core'; import { Observable, ReplaySubject, zip } from 'rxjs'; import { HttpClient } from '@angular/common/http'; -import { Germplasm } from './models/gnpis.germplasm.model'; import { DataDiscoveryCriteria, DataDiscoveryFacet, DataDiscoveryResults, DataDiscoverySource } from './models/data-discovery.model'; import { BrapiResults } from './models/brapi.model'; import { map } from 'rxjs/operators'; +import { Germplasm } from './models/gnpis.model'; import { XrefResponse } from './models/xref.model'; diff --git a/frontend/src/app/models/gnpis.model.ts b/frontend/src/app/models/gnpis.model.ts index 41f0a216..061c0d2a 100644 --- a/frontend/src/app/models/gnpis.model.ts +++ b/frontend/src/app/models/gnpis.model.ts @@ -1,4 +1,4 @@ -import {BrapiDonor, BrapiGermplasm} from "./brapi.model"; +import { BrapiDonor, BrapiGermplasm } from './brapi.model'; export interface Germplasm extends BrapiGermplasm { genusSpecies: string; @@ -51,7 +51,7 @@ export interface GermplasmInstitute extends Institute { collectors: string; registrationYear: string; deregistrationYear: string; - distributionStatus: string; + distributionStatus?: string; } export interface Photo { @@ -75,8 +75,8 @@ export interface Children { } -export interface Donor extends BrapiDonor{ - donorInstitute: Institute +export interface Donor extends BrapiDonor { + donorInstitute: Institute; } diff --git a/frontend/src/app/result-page/document/document.component.html b/frontend/src/app/result-page/document/document.component.html index 319bffa6..6d7ac00d 100644 --- a/frontend/src/app/result-page/document/document.component.html +++ b/frontend/src/app/result-page/document/document.component.html @@ -12,10 +12,10 @@ </a> </h5> <h5> - <a class="title" *ngIf="getRouterLink() && document['@type'] == 'Phenotyping Study'" [routerLink]="getRouterLink()"> + <a class="title" *ngIf="getRouterLink() && document['@type'].includes('Phenotyping Study')" [routerLink]="getRouterLink()"> (go to this {{ document["@type"] }} card) </a> - <a class="title" *ngIf="getRouterLink() && document['@type'] != 'Phenotyping Study'" [routerLink]="getRouterLink()" [queryParams]="getQueryParam()"> + <a class="title" *ngIf="getRouterLink() && !document['@type'].includes('Phenotyping Study')" [routerLink]="getRouterLink()" [queryParams]="getQueryParam()"> (go to this {{ document["@type"] }} card) </a> </h5> diff --git a/frontend/src/app/site-card/site-card.component.ts b/frontend/src/app/site-card/site-card.component.ts index 0bdb4bd5..e9f26350 100644 --- a/frontend/src/app/site-card/site-card.component.ts +++ b/frontend/src/app/site-card/site-card.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { BrapiService } from '../brapi.service'; import { ActivatedRoute } from '@angular/router'; -import {BrapiAdditionalInfo, BrapiLocation} from '../models/brapi.model'; +import { BrapiLocation } from '../models/brapi.model'; import { KeyValueObject } from '../utils'; @Component({ @@ -39,7 +39,17 @@ export class SiteCardComponent implements OnInit { } manageAdditionalInfo(keyValues: KeyValueObject[]) { - var forbiddenElements: String[] = ['Site status', 'Coordinates precision', 'Slope', 'Exposure', 'Geographical location', 'Distance to city', 'Direction from city', 'Environment type', 'Topography', 'Comment']; + const forbiddenElements: String[] = [ + 'Site status', + 'Coordinates precision', + 'Slope', + 'Exposure', + 'Geographical location', + 'Distance to city', + 'Direction from city', + 'Environment type', + 'Topography', + 'Comment']; for (const keyValue of keyValues) { if (!forbiddenElements.includes(keyValue.key)) { this.additionalInfos.push(keyValue); @@ -49,28 +59,27 @@ export class SiteCardComponent implements OnInit { formatCoordinates(decimalDegrees: number, type: string): string { if (decimalDegrees && type) { - var degree = Math.floor(decimalDegrees); - var decimalMinute = (decimalDegrees - degree) * 60; - var minute = Math.floor(decimalMinute); - var decimalSeconde = (decimalMinute - minute) * 60; - var seconde = Math.floor(decimalSeconde); + const degree = Math.floor(decimalDegrees); + const decimalMinute = (decimalDegrees - degree) * 60; + const minute = Math.floor(decimalMinute); + const decimalSeconde = (decimalMinute - minute) * 60; + const seconde = Math.floor(decimalSeconde); - var direction = ''; - if (type == 'latitude') { + let direction = ''; + if (type === 'latitude') { if (decimalDegrees >= 0) { - direction = "N"; + direction = 'N'; } else { - direction = "S"; + direction = 'S'; } - } - else if (type == 'longitude') { + } else if (type === 'longitude') { if (decimalDegrees >= 0) { - direction = "E"; + direction = 'E'; } else { - direction = "W"; + direction = 'W'; } } - return decimalDegrees + "° (" + degree + "° " + minute + "' " + seconde + "'' " + direction + ")"; + return decimalDegrees + '° (' + degree + '° ' + minute + '\' ' + seconde + '\'\' ' + direction + ')'; } else { return null; } diff --git a/frontend/src/app/study-card/study-card.component.spec.ts b/frontend/src/app/study-card/study-card.component.spec.ts index e9e0e8cf..0cdcc7b6 100644 --- a/frontend/src/app/study-card/study-card.component.spec.ts +++ b/frontend/src/app/study-card/study-card.component.spec.ts @@ -48,7 +48,7 @@ describe('StudyCardComponent', () => { } get map() { - return this.element('gpds-map'); + return this.element('div #map'); } } @@ -170,18 +170,50 @@ describe('StudyCardComponent', () => { result: { data: [{ germplasmDbId: 'g1', + defaultDisplayName: 'germplam1', accessionNumber: 'G_10', germplasmName: 'germplam1', + germplasmPUI: 'urn_g1', + pedigree: null, + seedSource: 'Versaille Institute', + synonyms: null, + commonCropName: 'cheery', + instituteCode: '78', + instituteName: 'Versaille Institute', + biologicalStatusOfAccessionCode: null, + countryOfOriginCode: 'FR', + typeOfGermplasmStorageCode: null, + taxonIds: null, genus: 'Populus', species: 'x generosa', - subtaxa: '' + speciesAuthority: 'Pop', + subtaxa: 'subsp', + subtaxaAuthority: '', + donors: null, + acquisitionDate: 'yesterday' }, { germplasmDbId: 'g2', + defaultDisplayName: 'germplam2', accessionNumber: 'G_20', germplasmName: 'germplam2', + germplasmPUI: 'urn_g2', + pedigree: null, + seedSource: 'Versaille Institute', + synonyms: null, + commonCropName: 'cheery', + instituteCode: '78', + instituteName: 'Versaille Institute', + biologicalStatusOfAccessionCode: null, + countryOfOriginCode: 'FR', + typeOfGermplasmStorageCode: null, + taxonIds: null, genus: 'Triticum', species: 'aestivum', - subtaxa: 'subsp' + speciesAuthority: 'Trit', + subtaxa: 'subsp', + subtaxaAuthority: '', + donors: null, + acquisitionDate: 'today' }], } }; -- GitLab From 00e8c0eae0abb84d36e81b2b312b3cd508bc332d Mon Sep 17 00:00:00 2001 From: jdestin <jeremy.destin@inra.fr> Date: Tue, 12 Mar 2019 18:33:36 +0100 Subject: [PATCH 13/20] refractor: Swap the position of the gpds-link and the external one. Sort some data display on the card. Manage the missing data in institute popover. Fix the additional information display on site card. Minor fixes. GNP-5490 --- .../src/app/card-row/card-row.component.scss | 2 - .../germplasm-card.component.html | 7 +-- .../germplasm-card.component.scss | 11 ++++ .../germplasm-card.component.ts | 55 ++++++++++++++--- frontend/src/app/map/map.component.ts | 4 +- frontend/src/app/navbar/navbar.component.scss | 4 -- .../document/document.component.html | 13 ++-- .../document/document.component.scss | 4 -- .../document/document.component.spec.ts | 4 +- .../document/document.component.ts | 2 + .../app/site-card/site-card.component.html | 61 ++++++++++++++----- .../src/app/site-card/site-card.component.ts | 3 +- .../app/study-card/study-card.component.html | 6 +- .../app/study-card/study-card.component.scss | 10 +++ .../app/study-card/study-card.component.ts | 60 ++++++++++++++++-- frontend/src/styles.scss | 4 -- 16 files changed, 188 insertions(+), 62 deletions(-) diff --git a/frontend/src/app/card-row/card-row.component.scss b/frontend/src/app/card-row/card-row.component.scss index fba9a857..6ed61f5e 100644 --- a/frontend/src/app/card-row/card-row.component.scss +++ b/frontend/src/app/card-row/card-row.component.scss @@ -4,5 +4,3 @@ font-weight: bold; overflow-wrap: normal; } - - diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.html b/frontend/src/app/germplasm-card/germplasm-card.component.html index f7c19c04..cff8f15f 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.html +++ b/frontend/src/app/germplasm-card/germplasm-card.component.html @@ -124,17 +124,17 @@ <gpds-card-row label="Code" - [value]="germplasmGnpis.collector.instituteCode"> + [value]="germplasmGnpis.collector.institute.instituteCode"> </gpds-card-row> <gpds-card-row label="Acronym" - [value]="germplasmGnpis.collector.acronym"> + [value]="germplasmGnpis.collector.institute.acronym"> </gpds-card-row> <gpds-card-row label="Organisation" - [value]="germplasmGnpis.collector.organisation"> + [value]="germplasmGnpis.collector.institute.organisation"> </gpds-card-row> <gpds-card-row @@ -603,7 +603,6 @@ </td> <td>{{ row.accessionNumber }}</td> <td>{{ row.distributionStatus }}</td> - <!--<td>{{ '' }}</td>--> </tr> </ng-template> diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.scss b/frontend/src/app/germplasm-card/germplasm-card.component.scss index 6a31757b..a2d2d211 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.scss +++ b/frontend/src/app/germplasm-card/germplasm-card.component.scss @@ -1,2 +1,13 @@ @import "theme"; @import '../../styles.scss'; + +a { + color: #0f6fa1; + text-decoration: underline; +} + +a:not([href]):not([tabindex]) { + color: #0f6fa1; + cursor: pointer; + text-decoration: underline; +} diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.ts b/frontend/src/app/germplasm-card/germplasm-card.component.ts index ca813c0a..d096bc70 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.ts +++ b/frontend/src/app/germplasm-card/germplasm-card.component.ts @@ -5,11 +5,11 @@ import { GnpisService } from '../gnpis.service'; import { BrapiAttributeData, BrapiGermplasmPedigree, BrapiLocation } from '../models/brapi.model'; import { Children, Germplasm, Site } from '../models/gnpis.model'; -@Component( { +@Component({ selector: 'gpds-germplasm-card', templateUrl: './germplasm-card.component.html', styleUrls: ['./germplasm-card.component.scss'] -} ) +}) export class GermplasmCardComponent implements OnInit { @@ -46,8 +46,6 @@ export class GermplasmCardComponent implements OnInit { ngOnInit() { - // console.log(this.route.snapshot); - // console.log(this.route); this.germplasmId = this.route.snapshot.queryParams.id; this.germplasmPuid = this.route.snapshot.queryParams.pui; @@ -70,8 +68,8 @@ export class GermplasmCardComponent implements OnInit { const germplasmAttributes$ = this.brapiService.germplasmAttributes(germplasmId).toPromise(); germplasmAttributes$ .then(germplasmAttributes => { - if (germplasmAttributes.result) { - this.germplasmAttributes = germplasmAttributes.result.data; + if (germplasmAttributes.result.data) { + this.germplasmAttributes = germplasmAttributes.result.data.sort(this.compareAttributes); } }); @@ -92,7 +90,18 @@ export class GermplasmCardComponent implements OnInit { germplasm$ .then(germplasmGnpis => { this.germplasmGnpis = germplasmGnpis; - this.germplasmProgeny = germplasmGnpis.children; + if (germplasmGnpis.children) { + this.germplasmProgeny = germplasmGnpis.children.sort(); + } + if (germplasmGnpis.donors) { + this.germplasmGnpis.donors.sort(this.compareDonorInstitutes); + } + if (germplasmGnpis.collection) { + this.germplasmGnpis.collection.sort(this.compareCollectionPanel); + } + if (this.germplasmGnpis.panel) { + this.germplasmGnpis.panel.sort(this.compareCollectionPanel); + } this.siteToBrapiLocation(this.germplasmGnpis.collectingSite); this.siteToBrapiLocation(this.germplasmGnpis.originSite); for (const site of this.germplasmGnpis.evaluationSites) { @@ -129,7 +138,7 @@ export class GermplasmCardComponent implements OnInit { checkBreeder() { return (this.germplasmGnpis.breeder) - && (this.germplasmGnpis.breeder.institute + && ((this.germplasmGnpis.breeder.institute && this.germplasmGnpis.breeder.institute.instituteName) || this.germplasmGnpis.breeder.accessionCreationDate || this.germplasmGnpis.breeder.accessionNumber || this.germplasmGnpis.breeder.registrationYear @@ -172,4 +181,34 @@ export class GermplasmCardComponent implements OnInit { || (this.germplasmGnpis.collectingSite && this.germplasmGnpis.collectingSite.siteName) || (this.checkCollectorInstituteObject() || this.checkCollectorInstituteFields()); } + + compareDonorInstitutes(a, b) { + if (a.donorInstitute.instituteName < b.donorInstitute.instituteName) { + return -1; + } + if (a.donorInstitute.instituteName > b.donorInstitute.instituteName) { + return 1; + } + return 0; + } + + compareAttributes(a, b) { + if (a.attributeName < b.attributeName) { + return -1; + } + if (a.attributeName > b.attributeName) { + return 1; + } + return 0; + } + + compareCollectionPanel(a, b) { + if (a.name < b.name) { + return -1; + } + if (a.name > b.name) { + return 1; + } + return 0; + } } diff --git a/frontend/src/app/map/map.component.ts b/frontend/src/app/map/map.component.ts index a5898c75..d9c95f55 100644 --- a/frontend/src/app/map/map.component.ts +++ b/frontend/src/app/map/map.component.ts @@ -60,7 +60,7 @@ export class MapComponent implements OnInit { getMarkerIconUrl(site: BrapiLocation): string { - if (site.locationType === 'GermplasmInstitute site') { + if (site.locationType === 'Origin site') { return 'assets/gpds/images/marker-icon-red.png'; } if (site.locationType === 'Collecting site') { @@ -74,7 +74,7 @@ export class MapComponent implements OnInit { removeEmptyLocations(locations: BrapiLocation[]) { for (const location of locations) { - if (location.latitude && location.longitude) { + if (location && location.latitude && location.longitude) { this.curatedLocationList.push(location); } } diff --git a/frontend/src/app/navbar/navbar.component.scss b/frontend/src/app/navbar/navbar.component.scss index e3e12a57..75a2c2d3 100644 --- a/frontend/src/app/navbar/navbar.component.scss +++ b/frontend/src/app/navbar/navbar.component.scss @@ -24,9 +24,5 @@ .dropdown-container { position: relative; - text-decoration: none; } -.dropdown-item { - text-decoration: none; -} diff --git a/frontend/src/app/result-page/document/document.component.html b/frontend/src/app/result-page/document/document.component.html index 6d7ac00d..fb84fcfb 100644 --- a/frontend/src/app/result-page/document/document.component.html +++ b/frontend/src/app/result-page/document/document.component.html @@ -7,16 +7,17 @@ <a class="badge badge-source mr-2" [href]="getSourceURL()" target="_blank"> {{ getSource() }} </a> - <a class="title" *ngIf="getURL()" [href]="getURL()"> + <a class="title" *ngIf="getRouterLink() && document['@type'].includes('Phenotyping Study')" [routerLink]="getRouterLink()"> + {{ document["schema:name"] }} + </a> + <a class="title" *ngIf="getRouterLink() && !document['@type'].includes('Phenotyping Study')" [routerLink]="getRouterLink()" [queryParams]="getQueryParam()"> {{ document["schema:name"] }} </a> </h5> + <h5> - <a class="title" *ngIf="getRouterLink() && document['@type'].includes('Phenotyping Study')" [routerLink]="getRouterLink()"> - (go to this {{ document["@type"] }} card) - </a> - <a class="title" *ngIf="getRouterLink() && !document['@type'].includes('Phenotyping Study')" [routerLink]="getRouterLink()" [queryParams]="getQueryParam()"> - (go to this {{ document["@type"] }} card) + <a class="title" *ngIf="getURL()" [href]="getURL()" target="_blank"> + (external link to this {{ document["@type"] }} card) </a> </h5> <span class="text-justify description"> diff --git a/frontend/src/app/result-page/document/document.component.scss b/frontend/src/app/result-page/document/document.component.scss index 940d9b86..fb44cb18 100644 --- a/frontend/src/app/result-page/document/document.component.scss +++ b/frontend/src/app/result-page/document/document.component.scss @@ -1,8 +1,4 @@ -a { - text-decoration: none; -} - .badge-source { background-color: #b54646; color: white; diff --git a/frontend/src/app/result-page/document/document.component.spec.ts b/frontend/src/app/result-page/document/document.component.spec.ts index 5642ec36..95089e95 100644 --- a/frontend/src/app/result-page/document/document.component.spec.ts +++ b/frontend/src/app/result-page/document/document.component.spec.ts @@ -71,7 +71,7 @@ describe('DocumentComponent', () => { expect(tester.source.attr('href')).toEqual('http://dco/url'); expect(tester.title).toContainText('doc_name'); - expect(tester.title.attr('href')).toEqual('http://dco/url'); + expect(tester.title.nativeElement['routerLink']).toEqual('/germplasm'); expect(tester.description).toContainText('description'); @@ -94,7 +94,7 @@ describe('DocumentComponent', () => { tester.detectChanges(); expect(component).toBeTruthy(); - expect(tester.title).toContainText('(go to this Germplasm card)'); + expect(tester.title).toContainText('doc_name'); expect(tester.title.nativeElement['routerLink']).toEqual('/germplasm'); expect(component.getQueryParam().id).toEqual('g1'); diff --git a/frontend/src/app/result-page/document/document.component.ts b/frontend/src/app/result-page/document/document.component.ts index 96e0e571..b041fe5a 100644 --- a/frontend/src/app/result-page/document/document.component.ts +++ b/frontend/src/app/result-page/document/document.component.ts @@ -27,6 +27,8 @@ export class DocumentComponent implements OnInit { return this.document['schema:url'] || ''; } + // TODO: index URGI schema:identifier like the partners + getRouterLink() { const urgiStudy = this.document['schema:includedInDataCatalog']['schema:url'] === 'https://urgi.versailles.inra.fr'; for (const type of this.document['@type']) { diff --git a/frontend/src/app/site-card/site-card.component.html b/frontend/src/app/site-card/site-card.component.html index 20f9dd15..f9234fcd 100644 --- a/frontend/src/app/site-card/site-card.component.html +++ b/frontend/src/app/site-card/site-card.component.html @@ -28,7 +28,10 @@ <gpds-card-row label="Status" - [value]="location.additionalInfo['Site status']"> + [test]="location.additionalInfo['Site status']"> + <ng-template> + {{ location.additionalInfo['Site status'] }} + </ng-template> </gpds-card-row> <gpds-card-row @@ -43,36 +46,44 @@ <gpds-card-row label="Coordinates precision" - [value]="location.additionalInfo['Coordinates precision']"> + [test]="location.additionalInfo['Coordinates precision']"> + <ng-template> + {{ location.additionalInfo['Coordinates precision'] }} + </ng-template> </gpds-card-row> <gpds-card-row label="Latitude" - [value]="location.latitude"> - <!--[value]="formatCoordinates(location.latitude)">--> + [value]="formatCoordinates(location.latitude, 'latitude')"> </gpds-card-row> <gpds-card-row label="Longitude" - [value]="location.longitude"> - <!--[value]="formatCoordinates(location.longitude)">--> + [value]="formatCoordinates(location.longitude, 'longitude')"> </gpds-card-row> <gpds-card-row label="Geographical location" - [value]="location.additionalInfo['Geographical location']"> + [test]="location.additionalInfo['Geographical location']"> + <ng-template> + {{ location.additionalInfo['Geographical location'] }} + </ng-template> </gpds-card-row> <gpds-card-row label="Country name" - [test]="location.countryName && !location.additionalInfo['Geographical location']" - [value]="location.countryName"> + [test]="location.countryName && !location.additionalInfo['Geographical location']"> + <ng-template> + {{ location.countryName }} + </ng-template> </gpds-card-row> <gpds-card-row label="Country code" [test]="location.countryCode && !location.additionalInfo['Geographical location']"> - [value]="location.countryCode"> + <ng-template> + {{ location.countryCode }} + </ng-template> </gpds-card-row> <gpds-card-row @@ -87,32 +98,50 @@ <gpds-card-row label="Exposure" - [value]="location.additionalInfo['Exposure']"> + [test]="location.additionalInfo['Exposure']"> + <ng-template> + {{ location.additionalInfo['Exposure'] }} + </ng-template> </gpds-card-row> <gpds-card-row label="Topography" - [value]="location.additionalInfo['Topography']"> + [test]="location.additionalInfo['Topography']"> + <ng-template> + {{ location.additionalInfo['Topography'] }} + </ng-template> </gpds-card-row> <gpds-card-row label="Environment type" - [value]="location.additionalInfo['Environment type']"> + [test]="location.additionalInfo['Environment type']"> + <ng-template> + {{ location.additionalInfo['Environment type'] }} + </ng-template> </gpds-card-row> <gpds-card-row label="Distance to city" - [value]="location.additionalInfo['Distance to city']"> + [test]="location.additionalInfo['Distance to city']"> + <ng-template> + {{ location.additionalInfo['Distance to city'] }} + </ng-template> </gpds-card-row> <gpds-card-row label="Direction from city" - [value]="location.additionalInfo['Direction from city']"> + [test]="location.additionalInfo['Direction from city']"> + <ng-template> + {{ location.additionalInfo['Direction from city'] }} + </ng-template> </gpds-card-row> <gpds-card-row label="Comment" - [value]="location.additionalInfo['Comment']"> + [test]="location.additionalInfo['Comment']"> + <ng-template> + {{ location.additionalInfo['Comment'] }} + </ng-template> </gpds-card-row> </div> diff --git a/frontend/src/app/site-card/site-card.component.ts b/frontend/src/app/site-card/site-card.component.ts index e9f26350..d5675356 100644 --- a/frontend/src/app/site-card/site-card.component.ts +++ b/frontend/src/app/site-card/site-card.component.ts @@ -28,8 +28,7 @@ export class SiteCardComponent implements OnInit { this.location = response.result; this.additionalInfos = []; if (this.location.additionalInfo) { - console.log(this.location.additionalInfo); - this.manageAdditionalInfo(KeyValueObject.fromObject(this.location.additionalInfo)); + this.manageAdditionalInfo(KeyValueObject.fromObject(this.location.additionalInfo).sort()); } this.loading = false; } diff --git a/frontend/src/app/study-card/study-card.component.html b/frontend/src/app/study-card/study-card.component.html index 0eed21c1..77b7b9ad 100644 --- a/frontend/src/app/study-card/study-card.component.html +++ b/frontend/src/app/study-card/study-card.component.html @@ -221,9 +221,9 @@ <gpds-card-table [headers]="[ 'Role', - 'Name', - 'Email', - 'Institution' + 'Name', + 'Email', + 'Institution' ]" [rows]="study.contacts"> <ng-template let-row> diff --git a/frontend/src/app/study-card/study-card.component.scss b/frontend/src/app/study-card/study-card.component.scss index c04ee673..269e24c9 100644 --- a/frontend/src/app/study-card/study-card.component.scss +++ b/frontend/src/app/study-card/study-card.component.scss @@ -2,3 +2,13 @@ @import '../../styles.scss'; +a { + color: #0f6fa1; + text-decoration: underline; +} + +a:not([href]):not([tabindex]) { + color: #0f6fa1; + cursor: pointer; + text-decoration: underline; +} diff --git a/frontend/src/app/study-card/study-card.component.ts b/frontend/src/app/study-card/study-card.component.ts index 84f13ced..b07577e7 100644 --- a/frontend/src/app/study-card/study-card.component.ts +++ b/frontend/src/app/study-card/study-card.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { BrapiService } from '../brapi.service'; import { ActivatedRoute } from '@angular/router'; -import { BrapiGermplasm, BrapiLocation, BrapiObservationVariable, BrapiStudy, BrapiTrial } from '../models/brapi.model'; +import { BrapiGermplasm, BrapiObservationVariable, BrapiStudy, BrapiTrial } from '../models/brapi.model'; import { GnpisService } from '../gnpis.service'; import { DataDiscoverySource } from '../models/data-discovery.model'; @@ -36,14 +36,20 @@ export class StudyCardComponent implements OnInit { study$ .then(response => { this.study = response.result; + if (this.study.contacts) { + this.study.contacts.sort(this.compareContacts); + } this.additionalInfos = []; if (this.study.additionalInfo) { - this.additionalInfos = KeyValueObject.fromObject(this.study.additionalInfo); + this.additionalInfos = KeyValueObject.fromObject(this.study.additionalInfo).sort(); } // Get study trials - this.trialsIds = this.study.trialDbIds; + if (this.study.trialDbIds) { + this.trialsIds = this.study.trialDbIds.sort(); + } + this.studyDataset = []; if (this.trialsIds && this.trialsIds !== []) { for (const trialsId of this.trialsIds) { @@ -57,6 +63,9 @@ export class StudyCardComponent implements OnInit { this.studyDataset.push(trial); }); } + if (this.studyDataset) { + this.studyDataset.sort(this.compareTrials); + } } // Get study source @@ -65,6 +74,7 @@ export class StudyCardComponent implements OnInit { const source$ = this.gnpisService.getSource(sourceURI); source$ .subscribe(src => { + console.log(src); this.studySource = src; }); } @@ -74,14 +84,14 @@ export class StudyCardComponent implements OnInit { const variable$ = this.brapiService.studyObservationVariables(studyDbId).toPromise(); variable$ .then(response => { - this.studyObservationVariables = response.result.data; + this.studyObservationVariables = response.result.data.sort(this.compareVariables); }); this.studyGermplasms = []; const germplasm$ = this.brapiService.studyGermplasms(studyDbId).toPromise(); germplasm$ .then(studyGermplasm => { - this.studyGermplasms = studyGermplasm.result.data; + this.studyGermplasms = studyGermplasm.result.data.sort(this.compareStudyGermplasm); }); this.loaded = Promise.all([study$, variable$, germplasm$]); @@ -95,4 +105,44 @@ export class StudyCardComponent implements OnInit { isNotURN(pui: string) { return !(pui.substring(0, 3) === 'urn'); } + + compareTrials(a, b) { + if (a.trialName < b.trialName) { + return -1; + } + if (a.trialName > b.trialName) { + return 1; + } + return 0; + } + + compareStudyGermplasm(a, b) { + if (a.germplasmName < b.germplasmName) { + return -1; + } + if (a.germplasmName > b.germplasmName) { + return 1; + } + return 0; + } + + compareVariables(a, b) { + if (a.observationVariableDbId < b.observationVariableDbId) { + return -1; + } + if (a.observationVariableDbId > b.observationVariableDbId) { + return 1; + } + return 0; + } + + compareContacts(a, b) { + if (a.name < b.name) { + return -1; + } + if (a.name > b.name) { + return 1; + } + return 0; + } } diff --git a/frontend/src/styles.scss b/frontend/src/styles.scss index 84ba4d7a..e5b4643c 100644 --- a/frontend/src/styles.scss +++ b/frontend/src/styles.scss @@ -10,10 +10,6 @@ $fa-font-path: '~font-awesome/fonts'; } } -a { - text-decoration: underline; -} - h3 { font-weight: bold; color: #0f6191; -- GitLab From 77d0f51bd910d94e993b9e3e7bb825c394266148 Mon Sep 17 00:00:00 2001 From: jdestin <jeremy.destin@inra.fr> Date: Wed, 13 Mar 2019 14:43:48 +0100 Subject: [PATCH 14/20] fix: Minor fixes on display and link redirection. Change the links on the navbar. GNP-5490 --- .../germplasm-card.component.html | 12 ++--- frontend/src/app/navbar/navbar.component.html | 1 - .../document/document.component.html | 8 ++-- .../app/study-card/study-card.component.html | 10 +---- .../study-card/study-card.component.spec.ts | 3 +- frontend/src/environments/environment.ts | 44 ++++++------------- 6 files changed, 28 insertions(+), 50 deletions(-) diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.html b/frontend/src/app/germplasm-card/germplasm-card.component.html index cff8f15f..a2c20213 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.html +++ b/frontend/src/app/germplasm-card/germplasm-card.component.html @@ -54,7 +54,7 @@ label="Website" [test]="germplasmGnpis.holdingInstitute.webSite"> <ng-template> - <a [href]="germplasmGnpis.breeder.institute.webSite"> + <a [href]="germplasmGnpis.breeder.institute.webSite" target="_blank"> {{ germplasmGnpis.holdingInstitute.webSite }} </a> </ng-template> @@ -103,7 +103,7 @@ label="Website" [test]="germplasmGnpis.breeder.institute.webSite"> <ng-template> - <a [href]="germplasmGnpis.breeder.institute.webSite"> + <a [href]="germplasmGnpis.breeder.institute.webSite" target="_blank"> {{ germplasmGnpis.breeder.institute.webSite }} </a> </ng-template> @@ -146,7 +146,7 @@ label="Website" [test]="germplasmGnpis.collector.institute.webSite"> <ng-template> - <a [href]="germplasmGnpis.collector.institute.webSite"> + <a [href]="germplasmGnpis.collector.institute.webSite" target="_blank"> {{ germplasmGnpis.collector.institute.webSite }} </a> </ng-template> @@ -305,7 +305,7 @@ label="Stock center name" [test]="germplasmGnpis.holdingGenbank.instituteName && germplasmGnpis.holdingGenbank.webSite"> <ng-template> - <a [href]="germplasmGnpis.holdingGenbank.webSite"> + <a [href]="germplasmGnpis.holdingGenbank.webSite" target="_blank"> {{ germplasmGnpis.holdingGenbank.instituteName }} </a> </ng-template> @@ -506,7 +506,7 @@ label="Website" [test]="row.donorInstitute.webSite"> <ng-template> - <a [href]=" row.donorInstitute.webSite "> + <a [href]=" row.donorInstitute.webSite " target="_blank"> {{ row.donorInstitute.webSite }} </a> </ng-template> @@ -587,7 +587,7 @@ label="Website" [test]="row.institute.webSite"> <ng-template> - <a [href]="row.institute.webSite"> + <a [href]="row.institute.webSite" target="_blank"> {{ row.institute.webSite }} </a> </ng-template> diff --git a/frontend/src/app/navbar/navbar.component.html b/frontend/src/app/navbar/navbar.component.html index dca9fd27..b6a3ac0e 100644 --- a/frontend/src/app/navbar/navbar.component.html +++ b/frontend/src/app/navbar/navbar.component.html @@ -38,7 +38,6 @@ </div> </div> </div> - </li> </ul> </div> diff --git a/frontend/src/app/result-page/document/document.component.html b/frontend/src/app/result-page/document/document.component.html index fb84fcfb..af8a669f 100644 --- a/frontend/src/app/result-page/document/document.component.html +++ b/frontend/src/app/result-page/document/document.component.html @@ -7,17 +7,19 @@ <a class="badge badge-source mr-2" [href]="getSourceURL()" target="_blank"> {{ getSource() }} </a> - <a class="title" *ngIf="getRouterLink() && document['@type'].includes('Phenotyping Study')" [routerLink]="getRouterLink()"> + <a class="title" *ngIf="getRouterLink() && document['@type'].includes('Phenotyping Study')" + [routerLink]="getRouterLink()"> {{ document["schema:name"] }} </a> - <a class="title" *ngIf="getRouterLink() && !document['@type'].includes('Phenotyping Study')" [routerLink]="getRouterLink()" [queryParams]="getQueryParam()"> + <a class="title" *ngIf="getRouterLink() && !document['@type'].includes('Phenotyping Study')" + [routerLink]="getRouterLink()" [queryParams]="getQueryParam()"> {{ document["schema:name"] }} </a> </h5> <h5> <a class="title" *ngIf="getURL()" [href]="getURL()" target="_blank"> - (external link to this {{ document["@type"] }} card) + ({{ document['schema:includedInDataCatalog']['schema:identifier'] }} data source link) </a> </h5> <span class="text-justify description"> diff --git a/frontend/src/app/study-card/study-card.component.html b/frontend/src/app/study-card/study-card.component.html index 77b7b9ad..0b51c03e 100644 --- a/frontend/src/app/study-card/study-card.component.html +++ b/frontend/src/app/study-card/study-card.component.html @@ -21,13 +21,7 @@ <gpds-card-row label="Identifier" - [test]="study.studyDbId"> - <ng-template> - {{ study.studyDbId }} - <a target="_blank" *ngIf="studySource && study.documentationURL" [href]="study.documentationURL"> - ( Link to this study on {{ studySource["schema:identifier"] }} ) - </a> - </ng-template> + [value]="study.studyDbId"> </gpds-card-row> <gpds-card-row @@ -52,7 +46,7 @@ [test]="studySource && study.documentationURL"> <ng-template> <a target="_blank" *ngIf="study.documentationURL" [href]="study.documentationURL"> - ( Link to this study on {{ studySource["schema:identifier"] }} ) + Link to this study on {{ studySource["schema:identifier"] }} </a> </ng-template> </gpds-card-row> diff --git a/frontend/src/app/study-card/study-card.component.spec.ts b/frontend/src/app/study-card/study-card.component.spec.ts index 0cdcc7b6..cd61029f 100644 --- a/frontend/src/app/study-card/study-card.component.spec.ts +++ b/frontend/src/app/study-card/study-card.component.spec.ts @@ -266,7 +266,8 @@ describe('StudyCardComponent', () => { expect(tester.cardHeader[0]).toContainText('Identification'); - expect(tester.studyInfo[1]).toContainText('Link to this study on srcId'); + expect(tester.studyInfo[0]).toContainText('study1'); + expect(tester.studyInfo[1]).toContainText('s1'); expect(tester.cardHeader[1]).toContainText('Genotype'); expect(component.studyGermplasms.length).toEqual(2); diff --git a/frontend/src/environments/environment.ts b/frontend/src/environments/environment.ts index 8789a590..31116793 100644 --- a/frontend/src/environments/environment.ts +++ b/frontend/src/environments/environment.ts @@ -18,51 +18,33 @@ export const environment = { ] }, { - label: 'Taxon/Germplasm', + label: 'Genomes & Synteny', url: '#', subMenu: [ - { label: 'Taxon', url: 'https://urgi.versailles.inra.fr/siregal/common/taxon/form.do' }, - { label: 'Accession Simple', url: 'https://urgi.versailles.inra.fr/gnpis-core' }, - { label: 'Accession passport', url: 'https://urgi.versailles.inra.fr/siregal/siregal/accessionForm.do' }, - { label: 'Collections CRB', url: 'https://urgi.versailles.inra.fr/siregal/siregal/grc.do' }, + { label: 'Genomes', url: 'https://urgi.versailles.inra.fr/Data/Genome/Genome-data-access' }, + { label: 'Synteny', url: 'https://urgi.versailles.inra.fr/synteny/synteny/viewer.do#dataset' } ] }, - { label: 'Phenotyping', url: 'https://urgi.versailles.inra.fr/ephesis/ephesis/viewer.do' }, { - label: 'Polymorphism', + label: 'Genetic resources', url: '#', subMenu: [ - { label: 'Genotyping', url: 'https://urgi.versailles.inra.fr/GnpSNP/snp/genotyping/form.do' }, - { label: 'SNP Discovery', url: 'https://urgi.versailles.inra.fr/GnpSNP/snp/welcome.do' }, + { label: 'Plant genetic resources', url: 'https://urgi.versailles.inra.fr/beta/gnpis-core' }, + { label: 'BRC collections', url: 'https://urgi.versailles.inra.fr/beta/siregal/siregal/grc.do' }, ] }, - { label: 'Association', url: 'https://urgi.versailles.inra.fr/association/association/viewer.do#form' }, { - label: 'Map/Marker/QTL', + label: 'Genetic analyses', url: '#', subMenu: [ - { label: 'Map', url: 'https://urgi.versailles.inra.fr/GnpMap/mapping/searchMap.do' }, - { label: 'Loci', url: 'https://urgi.versailles.inra.fr/GnpMap/mapping/loci/queryLociSelect.do' }, - { label: 'QTL', url: 'https://urgi.versailles.inra.fr/GnpMap/mapping/qtl/queryQtlSelect.do' }, - { label: 'MetaQTLs', url: 'https://urgi.versailles.inra.fr/GnpMap/mapping/metaqtl/form.do' }, - { label: 'Marker', url: 'https://urgi.versailles.inra.fr/GnpMap/mapping/marker/markerForm.do' }, - { label: 'Pool', url: 'https://urgi.versailles.inra.fr/GnpMap/mapping/pool/poolForm.do' }, - { label: 'Traits', url: 'https://urgi.versailles.inra.fr/GnpMap/mapping/queryTraitSelect.do' }, - { label: 'Biomercator', url: 'https://urgi.versailles.inra.fr/Tools/BioMercator-V4' }, + { label: 'Genetic maps & QTL', url: 'https://urgi.versailles.inra.fr/beta/GnpMap/mapping/welcome.do' }, + { label: 'GnpAsso', url: 'https://urgi.versailles.inra.fr/beta/association/association/viewer.do#form' }, ] }, - { label: 'Genomes', url: 'https://urgi.versailles.inra.fr/Data/Genome/Genome-data-access' }, - { label: 'Synteny', url: 'https://urgi.versailles.inra.fr/synteny/synteny/viewer.do#dataset' }, - { - label: 'Sequence', - url: '#', - subMenu: [ - { label: 'Sequence', url: 'https://urgi.versailles.inra.fr/sequence/sequence/sequence/form.do' }, - { label: 'Experiment', url: 'https://urgi.versailles.inra.fr/sequence/sequence/experiment/form.do' }, - { label: 'Analysis', url: 'https://urgi.versailles.inra.fr/sequence/sequence/analysis/form.do' }, - { label: 'Project', url: 'https://urgi.versailles.inra.fr/sequence/sequence/project/form.do' }, - ] - } + { label: 'Phenotypes', url: 'https://urgi.versailles.inra.fr/beta/ephesis' }, + { label: 'Polymorphisms', url: 'https://urgi.versailles.inra.fr/beta/GnpSNP/snp/genotyping/form.do' }, + { label: 'Sequences', url: 'https://urgi.versailles.inra.fr/beta/sequence' }, + { label: 'Transcriptomic', url: 'https://urgi.versailles.inra.fr/beta/GnpArray' }, ] } -- GitLab From 9bf1df037c70b6ffcc2e1df3ea1ff6c5b3be607d Mon Sep 17 00:00:00 2001 From: jdestin <jeremy.destin@inra.fr> Date: Fri, 15 Mar 2019 19:16:46 +0100 Subject: [PATCH 15/20] refactor: Change the navbar logo to URGI logo. Change the links on the navbar. Add logo on germplasm and site cards and use GnpIS logo for GnpIS source. Minor fixes. GNP-5490 --- backend/src/main/resources/application.yml | 12 +-- .../gpds/repository/file/datasources.jsonld | 3 +- .../urgi/gpds/repository/file/logos/GnpIS.png | Bin 0 -> 16150 bytes frontend/src/app/app-routing.module.ts | 6 +- frontend/src/app/app.component.html | 3 + .../src/app/card-row/card-row.component.html | 2 +- frontend/src/app/form/form.component.scss | 4 - .../germplasm-card.component.html | 27 ++++++- .../germplasm-card.component.spec.ts | 18 ++++- .../germplasm-card.component.ts | 75 +++++++++++++----- frontend/src/app/map/map.component.ts | 1 - frontend/src/app/navbar/navbar.component.html | 2 +- .../app/site-card/site-card.component.html | 21 +++++ .../app/site-card/site-card.component.spec.ts | 16 ++++ .../src/app/site-card/site-card.component.ts | 22 ++++- .../app/study-card/study-card.component.html | 8 +- .../app/study-card/study-card.component.ts | 61 ++++---------- frontend/src/assets/gpds/logo.png | Bin 5889 -> 26940 bytes frontend/src/environments/environment.ts | 33 +------- 19 files changed, 193 insertions(+), 121 deletions(-) create mode 100644 backend/src/main/resources/fr/inra/urgi/gpds/repository/file/logos/GnpIS.png diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index 3b87c03f..2fda83ac 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -21,17 +21,19 @@ logging.level: gpds: elasticsearch-alias-template: - gnpis_{source}_{documentType}_5432_scratchy-group{groupId} + gnpis_{source}_{documentType}_5432_krusty-group{groupId} elasticsearch-xref-index-name: - urgi_xref + urgi_xref_dev cropOntology-repository-url: https://urgi.versailles.inra.fr/files/ephesis/trait-ontology/data_16.3/ontology-repository.json - # TODO: Remove this and store at document generation directly (in BrAPI `observationVariable.documentationURL` field) - cropOntology-portal-link: - https://urgi.versailles.inra.fr/ephesis/ephesis/ontologyportal.do#termIdentifier= + gnpis-legacy-url: + https://urgi.versailles.inra.fr/ + + siregal-files-url: + /files/siregal/images/ # Provides access to user group WS used to query private data ES aliases security-user-group-ws-url: diff --git a/backend/src/main/resources/fr/inra/urgi/gpds/repository/file/datasources.jsonld b/backend/src/main/resources/fr/inra/urgi/gpds/repository/file/datasources.jsonld index 8a860fa2..5b5ea574 100644 --- a/backend/src/main/resources/fr/inra/urgi/gpds/repository/file/datasources.jsonld +++ b/backend/src/main/resources/fr/inra/urgi/gpds/repository/file/datasources.jsonld @@ -40,7 +40,8 @@ "@id": "https://urgi.versailles.inra.fr", "schema:identifier": "URGI", "schema:name": "URGI GnpIS", - "schema:url": "https://urgi.versailles.inra.fr" + "schema:url": "https://urgi.versailles.inra.fr", + "schema:image": "./logos/GnpIS.png" }, { "@type": "schema:DataCatalog", diff --git a/backend/src/main/resources/fr/inra/urgi/gpds/repository/file/logos/GnpIS.png b/backend/src/main/resources/fr/inra/urgi/gpds/repository/file/logos/GnpIS.png new file mode 100644 index 0000000000000000000000000000000000000000..1c682eaa80e2bb8de17bf9d545608a316dd89833 GIT binary patch literal 16150 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 literal 0 HcmV?d00001 diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts index 3e955fa6..3833afd2 100644 --- a/frontend/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -9,11 +9,7 @@ export const routes: Routes = [ { path: 'studies/:id', component: StudyCardComponent }, { path: 'sites/:id', component: SiteCardComponent }, { path: '', component: ResultPageComponent }, - { - path: 'germplasm', - component: GermplasmCardComponent, - runGuardsAndResolvers: 'paramsOrQueryParamsChange' - } + { path: 'germplasm', component: GermplasmCardComponent } ]; @NgModule({ diff --git a/frontend/src/app/app.component.html b/frontend/src/app/app.component.html index feb91773..1bdaa071 100644 --- a/frontend/src/app/app.component.html +++ b/frontend/src/app/app.component.html @@ -1,4 +1,7 @@ <gpds-navbar></gpds-navbar> +<div class="alert alert-warning text-center mb-4" role="alert"> +This is a <b>beta</b> application. Please <a href="mailto:urgi-contact@inra.fr" class="alert-link" style="text-decoration: underline">contact us</a> for any comments +</div> <div class="container"> <gpds-error></gpds-error> <router-outlet></router-outlet> diff --git a/frontend/src/app/card-row/card-row.component.html b/frontend/src/app/card-row/card-row.component.html index e3d9f258..42301209 100644 --- a/frontend/src/app/card-row/card-row.component.html +++ b/frontend/src/app/card-row/card-row.component.html @@ -1,4 +1,4 @@ -<ng-container *ngIf="test && (value === undefined || value)"> +<ng-container *ngIf="(test && value === undefined) || (value)"> <div class="row row-sep"> <div class="col-4 field my-2"> {{ label }} diff --git a/frontend/src/app/form/form.component.scss b/frontend/src/app/form/form.component.scss index da9bf710..e93197f5 100644 --- a/frontend/src/app/form/form.component.scss +++ b/frontend/src/app/form/form.component.scss @@ -6,10 +6,6 @@ label { } } -.nav-link { - text-decoration: none; -} - .nav-tabs { .nav-link.active { font-weight: bold; diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.html b/frontend/src/app/germplasm-card/germplasm-card.component.html index a2c20213..93124987 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.html +++ b/frontend/src/app/germplasm-card/germplasm-card.component.html @@ -220,6 +220,29 @@ [value]="germplasmGnpis.germplasmPUI"> </gpds-card-row> + <gpds-card-row + label="Source" + [test]="germplasmSource"> + <ng-template> + <a target="_blank" + [href]="germplasmSource['schema:url']"> + <img [src]="germplasmSource['schema:image']" alt="Germplasm source image"/> + </a> + </ng-template> + </gpds-card-row> + + <gpds-card-row + label="Data source" + [test]="germplasmGnpis.documentationURL"> + <ng-template> + <a target="_blank" [href]="germplasmGnpis.documentationURL"> + Link to this study on source + </a> + </ng-template> + </gpds-card-row> + + + <gpds-card-row label="Accession synonyms" [test]="germplasmGnpis.synonyms && germplasmGnpis.synonyms.length > 0"> @@ -452,7 +475,7 @@ </gpds-card-section> <gpds-card-section - header="Donation" + header="Donor" [test]="germplasmGnpis.donors && germplasmGnpis.donors.length > 0"> <ng-template> <gpds-card-table @@ -532,7 +555,7 @@ </gpds-card-section> <gpds-card-section - header="Distribution" + header="Distributor" [test]="germplasmGnpis.distributors && germplasmGnpis.distributors.length>0"> <ng-template> diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts b/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts index 16ca92d0..b0b61a41 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts +++ b/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts @@ -16,6 +16,7 @@ import { CardTableComponent } from '../card-table/card-table.component'; import { MapComponent } from '../map/map.component'; import { BrapiGermplasmAttributes, BrapiGermplasmPedigree, BrapiResult, BrapiSibling } from '../models/brapi.model'; import { Donor, Germplasm, GermplasmInstitute, GermplasmSet, Institute, Site } from '../models/gnpis.model'; +import { DataDiscoverySource } from '../models/data-discovery.model'; import { BrapiGermplasmAttributes, BrapiGermplasmPedigree, @@ -57,7 +58,8 @@ describe('GermplasmCardComponent', () => { const gnpisService = jasmine.createSpyObj( 'GnpisService', [ 'germplasm', - 'germplasmByPuid' + 'germplasmByPuid', + 'getSource' ] ); @@ -200,6 +202,15 @@ describe('GermplasmCardComponent', () => { population: [gnpisGermplasmSet] }; + const source: DataDiscoverySource = { + '@id': 'src1', + '@type': ['schema:DataCatalog'], + 'schema:identifier': 'srcId', + 'schema:name': 'source1', + 'schema:url': 'srcUrl', + 'schema:image': null + }; + beforeEach(async(() => { TestBed.configureTestingModule({ imports: [RouterTestingModule, NgbPopoverModule, MomentModule], @@ -228,6 +239,7 @@ describe('GermplasmCardComponent', () => { gnpisService.germplasm.and.returnValue(of(germplasmTest)); gnpisService.germplasmByPuid.and.returnValue(of(germplasmTest)); + gnpisService.getSource.and.returnValue(of(source)); /*brapiService.germplasmProgeny.and.returnValue(of(brapiGermplasmProgeny));*/ brapiService.germplasmPedigree.and.returnValue(of(brapiGermplasmPedigree)); brapiService.germplasmAttributes.and.returnValue(of(brapiGermplasmAttributes)); @@ -244,8 +256,8 @@ describe('GermplasmCardComponent', () => { expect(tester.cardHeader[1]).toContainText('Holding'); expect(tester.cardHeader[2]).toContainText('Collecting'); expect(tester.cardHeader[3]).toContainText('Breeder'); - expect(tester.cardHeader[4]).toContainText('Donation'); - expect(tester.cardHeader[5]).toContainText('Distribution'); + expect(tester.cardHeader[4]).toContainText('Donor'); + expect(tester.cardHeader[5]).toContainText('Distributor'); expect(tester.cardHeader[6]).toContainText('Evaluation Data'); }); })); diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.ts b/frontend/src/app/germplasm-card/germplasm-card.component.ts index d096bc70..bd7addc1 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.ts +++ b/frontend/src/app/germplasm-card/germplasm-card.component.ts @@ -4,6 +4,7 @@ import { BrapiService } from '../brapi.service'; import { GnpisService } from '../gnpis.service'; import { BrapiAttributeData, BrapiGermplasmPedigree, BrapiLocation } from '../models/brapi.model'; import { Children, Germplasm, Site } from '../models/gnpis.model'; +import { DataDiscoverySource } from '../models/data-discovery.model'; @Component({ selector: 'gpds-germplasm-card', @@ -35,6 +36,7 @@ export class GermplasmCardComponent implements OnInit { germplasmLocations: BrapiLocation[] = []; germplasmId: string; germplasmPuid: string; + germplasmSource: DataDiscoverySource; IMAGES_ACCESSION_URL = 'https://urgi.versailles.inra.fr/files/siregal/images/accession/'; IMAGES_INSTITUTION_URL = 'https://urgi.versailles.inra.fr/files/siregal/images//institution/'; IMAGES_BRC_URL = 'https://urgi.versailles.inra.fr/files/siregal/images/grc/inra_brc_en.png'; @@ -90,36 +92,73 @@ export class GermplasmCardComponent implements OnInit { germplasm$ .then(germplasmGnpis => { this.germplasmGnpis = germplasmGnpis; - if (germplasmGnpis.children) { - this.germplasmProgeny = germplasmGnpis.children.sort(); - } - if (germplasmGnpis.donors) { - this.germplasmGnpis.donors.sort(this.compareDonorInstitutes); - } - if (germplasmGnpis.collection) { - this.germplasmGnpis.collection.sort(this.compareCollectionPanel); - } - if (this.germplasmGnpis.panel) { - this.germplasmGnpis.panel.sort(this.compareCollectionPanel); - } - this.siteToBrapiLocation(this.germplasmGnpis.collectingSite); - this.siteToBrapiLocation(this.germplasmGnpis.originSite); - for (const site of this.germplasmGnpis.evaluationSites) { - this.siteToBrapiLocation(site); - } + // Get germplasm source + const sourceURI = germplasmGnpis['schema:includedInDataCatalog']; + this.getGermplasmSource(sourceURI); + this.reformatData(germplasmGnpis); }); } else { germplasm$ = this.gnpisService.germplasmByPuid(pui).toPromise(); germplasm$ .then(germplasmGnpis => { this.germplasmGnpis = germplasmGnpis; + // Get germplasm source + const sourceURI = germplasmGnpis['schema:includedInDataCatalog']; + this.getGermplasmSource(sourceURI); + this.reformatData(germplasmGnpis); }); } return germplasm$; } + // TODO Remove the condition when the field includedInDataCatalog will be added to URGI study. + getGermplasmSource(sourceURI: string) { + if (sourceURI) { + const source$ = this.gnpisService.getSource(sourceURI); + source$ + .subscribe(src => { + this.germplasmSource = src; + }); + } else { + const urgiURI = 'https://urgi.versailles.inra.fr'; + const source$ = this.gnpisService.getSource(urgiURI); + source$ + .subscribe(src => { + this.germplasmSource = src; + }); + } + } + + + reformatData(germplasmGnpis) { + if (germplasmGnpis.children) { + this.germplasmProgeny = germplasmGnpis.children.sort(); + } + if (germplasmGnpis.donors) { + this.germplasmGnpis.donors.sort(this.compareDonorInstitutes); + } + if (germplasmGnpis.collection) { + this.germplasmGnpis.collection.sort(this.compareCollectionPanel); + } + if (this.germplasmGnpis.panel) { + this.germplasmGnpis.panel.sort(this.compareCollectionPanel); + } + if (this.germplasmGnpis.collectingSite) { + this.siteToBrapiLocation(this.germplasmGnpis.collectingSite); + } + if (this.germplasmGnpis.originSite) { + this.siteToBrapiLocation(this.germplasmGnpis.originSite); + } + if (this.germplasmGnpis.evaluationSites && this.germplasmGnpis.evaluationSites.length > 0) { + for (const site of this.germplasmGnpis.evaluationSites) { + this.siteToBrapiLocation(site); + } + } + } + + siteToBrapiLocation(site: Site) { - if (site.siteId && site.latitude && site.longitude) { + if (site && site.siteId && site.latitude && site.longitude) { this.germplasmLocations.push({ locationDbId: site.siteId, locationName: site.siteName, diff --git a/frontend/src/app/map/map.component.ts b/frontend/src/app/map/map.component.ts index d9c95f55..bc566b84 100644 --- a/frontend/src/app/map/map.component.ts +++ b/frontend/src/app/map/map.component.ts @@ -20,7 +20,6 @@ export class MapComponent implements OnInit { this.removeEmptyLocations(this.locations); if (this.curatedLocationList.length > 0) { - const container = L.DomUtil.get('map'); const map = L.map('map'); // initialize map centered on the first site diff --git a/frontend/src/app/navbar/navbar.component.html b/frontend/src/app/navbar/navbar.component.html index b6a3ac0e..0f8b7fc4 100644 --- a/frontend/src/app/navbar/navbar.component.html +++ b/frontend/src/app/navbar/navbar.component.html @@ -1,4 +1,4 @@ -<nav class="navbar navbar-expand-md navbar-dark py-0 mb-5"> +<nav class="navbar navbar-expand-md navbar-dark py-0 mb-4"> <div class="container px-0"> <a class="navbar-brand d-flex align-items-center mr-0 px-2" routerLink="/"> <img src="assets/logo.png" alt="Logo" title="{{ navbar.title }}" height="60px"/> diff --git a/frontend/src/app/site-card/site-card.component.html b/frontend/src/app/site-card/site-card.component.html index f9234fcd..3af3f6e0 100644 --- a/frontend/src/app/site-card/site-card.component.html +++ b/frontend/src/app/site-card/site-card.component.html @@ -16,6 +16,27 @@ <ng-template> <div class="card-body card-section-body"> + <gpds-card-row + label="Source" + [test]="location"> + <ng-template> + <a target="_blank" + [href]="locationSource['schema:url']"> + <img [src]="locationSource['schema:image']" alt="Location source image"/> + </a> + </ng-template> + </gpds-card-row> + + <gpds-card-row + label="Data source" + [test]="location && location.documentationURL"> + <ng-template> + <a target="_blank" [href]="location.documentationURL"> + Link to this study on {{ location["schema:identifier"] }} + </a> + </ng-template> + </gpds-card-row> + <gpds-card-row label="Abbreviation" [value]="location.abbreviation"> diff --git a/frontend/src/app/site-card/site-card.component.spec.ts b/frontend/src/app/site-card/site-card.component.spec.ts index f33d7f9a..a8d0604c 100644 --- a/frontend/src/app/site-card/site-card.component.spec.ts +++ b/frontend/src/app/site-card/site-card.component.spec.ts @@ -10,6 +10,8 @@ import { CardRowComponent } from '../card-row/card-row.component'; import { LoadingSpinnerComponent } from '../loading-spinner/loading-spinner.component'; import { CardTableComponent } from '../card-table/card-table.component'; import { CardSectionComponent } from '../card-section/card-section.component'; +import { DataDiscoverySource } from '../models/data-discovery.model'; +import { GnpisService } from '../gnpis.service'; import { MockComponent } from 'ng-mocks'; import { XrefsComponent } from '../xrefs/xrefs.component'; @@ -18,6 +20,9 @@ describe('SiteCardComponent', () => { const brapiService = jasmine.createSpyObj( 'BrapiService', ['location'] ); + const gnpisService = jasmine.createSpyObj( + 'GnpisService', ['getSource'] + ); const response: BrapiResult<BrapiLocation> = { metadata: null, result: { @@ -47,6 +52,15 @@ describe('SiteCardComponent', () => { } }; + const source: DataDiscoverySource = { + '@id': 'src1', + '@type': ['schema:DataCatalog'], + 'schema:identifier': 'srcId', + 'schema:name': 'source1', + 'schema:url': 'srcUrl', + 'schema:image': null + }; + beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [ @@ -56,6 +70,7 @@ describe('SiteCardComponent', () => { ], providers: [ { provide: BrapiService, useValue: brapiService }, + { provide: GnpisService, useValue: gnpisService }, { provide: ActivatedRoute, useValue: { @@ -76,6 +91,7 @@ describe('SiteCardComponent', () => { const fixture = TestBed.createComponent(SiteCardComponent); const component = fixture.componentInstance; brapiService.location.and.returnValues(of(response)); + gnpisService.getSource.and.returnValue(of(source)); fixture.detectChanges(); const element = fixture.nativeElement; expect(element.querySelector('h3').textContent).toBe(' Site: site1 '); diff --git a/frontend/src/app/site-card/site-card.component.ts b/frontend/src/app/site-card/site-card.component.ts index d5675356..0705744e 100644 --- a/frontend/src/app/site-card/site-card.component.ts +++ b/frontend/src/app/site-card/site-card.component.ts @@ -3,6 +3,8 @@ import { BrapiService } from '../brapi.service'; import { ActivatedRoute } from '@angular/router'; import { BrapiLocation } from '../models/brapi.model'; import { KeyValueObject } from '../utils'; +import { DataDiscoverySource } from '../models/data-discovery.model'; +import { GnpisService } from '../gnpis.service'; @Component({ selector: 'gpds-site-card', @@ -12,11 +14,11 @@ import { KeyValueObject } from '../utils'; export class SiteCardComponent implements OnInit { location: BrapiLocation; + locationSource: DataDiscoverySource; additionalInfos: KeyValueObject[]; loading = true; - - constructor(private brapiService: BrapiService, private route: ActivatedRoute) { + constructor(private brapiService: BrapiService, private gnpisService: GnpisService, private route: ActivatedRoute) { } ngOnInit() { @@ -30,6 +32,22 @@ export class SiteCardComponent implements OnInit { if (this.location.additionalInfo) { this.manageAdditionalInfo(KeyValueObject.fromObject(this.location.additionalInfo).sort()); } + const sourceURI = location['schema:includedInDataCatalog']; + // TODO Remove the condition when the field includedInDataCatalog will be added to URGI study. + if (sourceURI) { + const source$ = this.gnpisService.getSource(sourceURI); + source$ + .subscribe(src => { + this.locationSource = src; + }); + } else { + const urgiURI = 'https://urgi.versailles.inra.fr'; + const source$ = this.gnpisService.getSource(urgiURI); + source$ + .subscribe(src => { + this.locationSource = src; + }); + } this.loading = false; } ); diff --git a/frontend/src/app/study-card/study-card.component.html b/frontend/src/app/study-card/study-card.component.html index 0b51c03e..7dafa498 100644 --- a/frontend/src/app/study-card/study-card.component.html +++ b/frontend/src/app/study-card/study-card.component.html @@ -45,7 +45,7 @@ label="Data source" [test]="studySource && study.documentationURL"> <ng-template> - <a target="_blank" *ngIf="study.documentationURL" [href]="study.documentationURL"> + <a target="_blank" [href]="study.documentationURL"> Link to this study on {{ studySource["schema:identifier"] }} </a> </ng-template> @@ -102,7 +102,7 @@ [test]="study.dataLinks && study.dataLinks.length != 0"> <ng-template> <div *ngFor="let dataLink of study.dataLinks"> - <a [href]="dataLink.url"> + <a target="_blank" [href]="dataLink.url"> {{ dataLink.name }} </a> </div> @@ -159,7 +159,7 @@ <td> <ng-template #name>{{ row.observationVariableDbId }}</ng-template> <ng-template #link> - <a [href]=row.documentationURL>{{ row.observationVariableDbId }}</a> + <a target="_blank" [href]=row.documentationURL>{{ row.observationVariableDbId }}</a> </ng-template> <ng-container *ngIf="row.documentationURL; then link else name"></ng-container> </td> @@ -189,7 +189,7 @@ <td> <ng-template #name>{{ row.trialName }}</ng-template> <ng-template #link> - <a [href]=row.documentationURL>{{ row.trialName }}</a> + <a target="_blank" [href]=row.documentationURL>{{ row.trialName }}</a> </ng-template> <ng-container *ngIf="row.documentationURL; then link else name"></ng-container> </td> diff --git a/frontend/src/app/study-card/study-card.component.ts b/frontend/src/app/study-card/study-card.component.ts index b07577e7..27188c01 100644 --- a/frontend/src/app/study-card/study-card.component.ts +++ b/frontend/src/app/study-card/study-card.component.ts @@ -37,7 +37,8 @@ export class StudyCardComponent implements OnInit { .then(response => { this.study = response.result; if (this.study.contacts) { - this.study.contacts.sort(this.compareContacts); + this.study.contacts.sort((var1, var2) => + var1.name.localeCompare(var2.name)); } this.additionalInfos = []; @@ -64,17 +65,25 @@ export class StudyCardComponent implements OnInit { }); } if (this.studyDataset) { - this.studyDataset.sort(this.compareTrials); + this.studyDataset.sort((var1, var2) => + var1.trialName.localeCompare(var2.trialName)); } } // Get study source + // TODO Remove the condition when the field includedInDataCatalog will be added to URGI study. const sourceURI = this.study['schema:includedInDataCatalog']; if (sourceURI) { const source$ = this.gnpisService.getSource(sourceURI); source$ .subscribe(src => { - console.log(src); + this.studySource = src; + }); + } else { + const urgiURI = 'https://urgi.versailles.inra.fr'; + const source$ = this.gnpisService.getSource(urgiURI); + source$ + .subscribe(src => { this.studySource = src; }); } @@ -84,14 +93,16 @@ export class StudyCardComponent implements OnInit { const variable$ = this.brapiService.studyObservationVariables(studyDbId).toPromise(); variable$ .then(response => { - this.studyObservationVariables = response.result.data.sort(this.compareVariables); + this.studyObservationVariables = response.result.data.sort((var1, var2) => + var1.observationVariableDbId.localeCompare(var2.observationVariableDbId)); }); this.studyGermplasms = []; const germplasm$ = this.brapiService.studyGermplasms(studyDbId).toPromise(); germplasm$ .then(studyGermplasm => { - this.studyGermplasms = studyGermplasm.result.data.sort(this.compareStudyGermplasm); + this.studyGermplasms = studyGermplasm.result.data.sort((var1, var2) => + var1.germplasmName.localeCompare(var2.germplasmName)); }); this.loaded = Promise.all([study$, variable$, germplasm$]); @@ -105,44 +116,4 @@ export class StudyCardComponent implements OnInit { isNotURN(pui: string) { return !(pui.substring(0, 3) === 'urn'); } - - compareTrials(a, b) { - if (a.trialName < b.trialName) { - return -1; - } - if (a.trialName > b.trialName) { - return 1; - } - return 0; - } - - compareStudyGermplasm(a, b) { - if (a.germplasmName < b.germplasmName) { - return -1; - } - if (a.germplasmName > b.germplasmName) { - return 1; - } - return 0; - } - - compareVariables(a, b) { - if (a.observationVariableDbId < b.observationVariableDbId) { - return -1; - } - if (a.observationVariableDbId > b.observationVariableDbId) { - return 1; - } - return 0; - } - - compareContacts(a, b) { - if (a.name < b.name) { - return -1; - } - if (a.name > b.name) { - return 1; - } - return 0; - } } diff --git a/frontend/src/assets/gpds/logo.png b/frontend/src/assets/gpds/logo.png index 2131327a70020a31bbb43c56da919b9dccdb837c..16d4a77bc231332c1918cb684bcb199a8c0da555 100644 GIT binary patch literal 26940 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 literal 5889 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 diff --git a/frontend/src/environments/environment.ts b/frontend/src/environments/environment.ts index 31116793..081a6813 100644 --- a/frontend/src/environments/environment.ts +++ b/frontend/src/environments/environment.ts @@ -7,7 +7,6 @@ export const environment = { navbar: { title: 'GnpIS Plant Data Search', links: [ - { label: 'INRA', url: 'http://www.inra.fr/' }, { label: 'URGI', url: '#', @@ -17,34 +16,10 @@ export const environment = { { label: 'About us', url: 'https://urgi.versailles.inra.fr/About-us' } ] }, - { - label: 'Genomes & Synteny', - url: '#', - subMenu: [ - { label: 'Genomes', url: 'https://urgi.versailles.inra.fr/Data/Genome/Genome-data-access' }, - { label: 'Synteny', url: 'https://urgi.versailles.inra.fr/synteny/synteny/viewer.do#dataset' } - ] - }, - { - label: 'Genetic resources', - url: '#', - subMenu: [ - { label: 'Plant genetic resources', url: 'https://urgi.versailles.inra.fr/beta/gnpis-core' }, - { label: 'BRC collections', url: 'https://urgi.versailles.inra.fr/beta/siregal/siregal/grc.do' }, - ] - }, - { - label: 'Genetic analyses', - url: '#', - subMenu: [ - { label: 'Genetic maps & QTL', url: 'https://urgi.versailles.inra.fr/beta/GnpMap/mapping/welcome.do' }, - { label: 'GnpAsso', url: 'https://urgi.versailles.inra.fr/beta/association/association/viewer.do#form' }, - ] - }, - { label: 'Phenotypes', url: 'https://urgi.versailles.inra.fr/beta/ephesis' }, - { label: 'Polymorphisms', url: 'https://urgi.versailles.inra.fr/beta/GnpSNP/snp/genotyping/form.do' }, - { label: 'Sequences', url: 'https://urgi.versailles.inra.fr/beta/sequence' }, - { label: 'Transcriptomic', url: 'https://urgi.versailles.inra.fr/beta/GnpArray' }, + { label: 'GNPIS', url: 'https://urgi.versailles.inra.fr/gnpis/' }, + { label: 'CIRAD', url: 'http://tropgenedb.cirad.fr/' }, + { label: 'VIB', url: 'http://pippa.psb.ugent.be' }, + { label: 'IBET', url: 'https://biodata.pt' } ] } -- GitLab From 0def31cce2d9bd931ef3e12a1ebf0b45d32734c1 Mon Sep 17 00:00:00 2001 From: jdestin <jeremy.destin@inra.fr> Date: Mon, 18 Mar 2019 11:30:20 +0100 Subject: [PATCH 16/20] refactor: Rebase from master to add xref. Minor fixes. GNP-5490 --- frontend/package-lock.json | 82 ++++++++++++++----- frontend/package.json | 1 + .../card-section/card-section.component.scss | 2 +- .../germplasm-card.component.html | 4 - .../germplasm-card.component.spec.ts | 10 +-- frontend/src/app/gnpis.service.spec.ts | 10 +-- frontend/src/app/gnpis.service.ts | 15 ++-- 7 files changed, 78 insertions(+), 46 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 098e7f6f..ff0793af 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1189,6 +1189,11 @@ "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", "dev": true }, + "angular-mocks": { + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/angular-mocks/-/angular-mocks-1.7.8.tgz", + "integrity": "sha512-LB13ESBT0eJrhQhfPXyLR9qm4LI9g44hyBFwUqZKEHEA4DpfxVTu0ONipiNoN0zWtmEAezA8u2gjcoaO2TStig==" + }, "ansi-colors": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", @@ -1258,6 +1263,7 @@ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", "dev": true, + "optional": true, "requires": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" @@ -2458,7 +2464,8 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true + "dev": true, + "optional": true }, "constants-browserify": { "version": "1.0.0", @@ -2854,7 +2861,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "dev": true + "dev": true, + "optional": true }, "depd": { "version": "1.1.2", @@ -3821,7 +3829,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -3842,12 +3851,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3862,17 +3873,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -3989,7 +4003,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -4001,6 +4016,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -4015,6 +4031,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -4022,12 +4039,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -4046,6 +4065,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -4126,7 +4146,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -4138,6 +4159,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -4223,7 +4245,8 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -4259,6 +4282,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -4278,6 +4302,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -4321,12 +4346,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true } } }, @@ -4335,6 +4362,7 @@ "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", "dev": true, + "optional": true, "requires": { "graceful-fs": "^4.1.2", "inherits": "~2.0.0", @@ -4347,6 +4375,7 @@ "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, + "optional": true, "requires": { "aproba": "^1.0.3", "console-control-strings": "^1.0.0", @@ -4384,7 +4413,8 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", - "dev": true + "dev": true, + "optional": true }, "get-stream": { "version": "3.0.0", @@ -4564,7 +4594,8 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "dev": true + "dev": true, + "optional": true }, "has-value": { "version": "1.0.0", @@ -5284,7 +5315,8 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "dev": true + "dev": true, + "optional": true }, "is-windows": { "version": "1.0.2", @@ -5927,6 +5959,7 @@ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, + "optional": true, "requires": { "graceful-fs": "^4.1.2", "parse-json": "^2.2.0", @@ -5939,7 +5972,8 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true + "dev": true, + "optional": true } } }, @@ -6214,7 +6248,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true + "dev": true, + "optional": true }, "map-visit": { "version": "1.0.0", @@ -6862,6 +6897,7 @@ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, + "optional": true, "requires": { "are-we-there-yet": "~1.1.2", "console-control-strings": "~1.1.0", @@ -7868,6 +7904,7 @@ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", "dev": true, + "optional": true, "requires": { "load-json-file": "^1.0.0", "normalize-package-data": "^2.3.2", @@ -7879,6 +7916,7 @@ "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", "dev": true, + "optional": true, "requires": { "graceful-fs": "^4.1.2", "pify": "^2.0.0", @@ -7889,7 +7927,8 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true + "dev": true, + "optional": true } } }, @@ -7898,6 +7937,7 @@ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", "dev": true, + "optional": true, "requires": { "find-up": "^1.0.0", "read-pkg": "^1.0.0" @@ -7908,6 +7948,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, + "optional": true, "requires": { "path-exists": "^2.0.0", "pinkie-promise": "^2.0.0" @@ -7918,6 +7959,7 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "dev": true, + "optional": true, "requires": { "pinkie-promise": "^2.0.0" } @@ -9192,6 +9234,7 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "dev": true, + "optional": true, "requires": { "is-utf8": "^0.2.0" } @@ -10548,6 +10591,7 @@ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "dev": true, + "optional": true, "requires": { "string-width": "^1.0.2 || 2" } diff --git a/frontend/package.json b/frontend/package.json index ecf1d222..c95b0fa4 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -24,6 +24,7 @@ "@ng-bootstrap/ng-bootstrap": "4.0.0", "@types/leaflet": "1.2.14", "@types/leaflet.markercluster": "1.0.3", + "angular-mocks": "1.7.8", "bootstrap": "4.1.3", "core-js": "2.5.7", "font-awesome": "4.7.0", diff --git a/frontend/src/app/card-section/card-section.component.scss b/frontend/src/app/card-section/card-section.component.scss index 2e137cc6..78b6d191 100644 --- a/frontend/src/app/card-section/card-section.component.scss +++ b/frontend/src/app/card-section/card-section.component.scss @@ -12,6 +12,6 @@ a { font-size: large; font-weight: bold; color: #f5f5f5; - background-color: #0f6191; + background-image:repeating-linear-gradient(#0f96cd, #0f6191, #0f76a5) ; } diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.html b/frontend/src/app/germplasm-card/germplasm-card.component.html index 93124987..dd68d2be 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.html +++ b/frontend/src/app/germplasm-card/germplasm-card.component.html @@ -849,10 +849,6 @@ </ng-template> </gpds-card-section> - - </div> - - <!--XRefs part --> <gpds-xrefs [xrefId]="germplasmGnpis.germplasmPUI"></gpds-xrefs> </ng-container> diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts b/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts index b0b61a41..5b068168 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts +++ b/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts @@ -17,13 +17,6 @@ import { MapComponent } from '../map/map.component'; import { BrapiGermplasmAttributes, BrapiGermplasmPedigree, BrapiResult, BrapiSibling } from '../models/brapi.model'; import { Donor, Germplasm, GermplasmInstitute, GermplasmSet, Institute, Site } from '../models/gnpis.model'; import { DataDiscoverySource } from '../models/data-discovery.model'; -import { - BrapiGermplasmAttributes, - BrapiGermplasmPedigree, - BrapiResult, - BrapiSibling -} from "../models/brapi.model"; -import {Donor, Germplasm, GermplasmInstitute, GermplasmSet, Institute, Site} from "../models/gnpis.model"; import { MockComponent } from 'ng-mocks'; import { XrefsComponent } from '../xrefs/xrefs.component'; @@ -215,8 +208,7 @@ describe('GermplasmCardComponent', () => { TestBed.configureTestingModule({ imports: [RouterTestingModule, NgbPopoverModule, MomentModule], declarations: [ - GermplasmCardComponent, LoadingSpinnerComponent, MockComponent(XrefsComponent) - GermplasmCardComponent, CardSectionComponent, + GermplasmCardComponent, LoadingSpinnerComponent, MockComponent(XrefsComponent), CardSectionComponent, CardRowComponent, LoadingSpinnerComponent, CardTableComponent, MapComponent ], providers: [ diff --git a/frontend/src/app/gnpis.service.spec.ts b/frontend/src/app/gnpis.service.spec.ts index 13f50d13..04deb8dd 100644 --- a/frontend/src/app/gnpis.service.spec.ts +++ b/frontend/src/app/gnpis.service.spec.ts @@ -1,4 +1,4 @@ -import { BASE_URL, BASE_URL_GERMPLASM, GnpisService } from './gnpis.service'; +import { BASE_URL, GnpisService } from './gnpis.service'; import { BrapiMetaData, BrapiResults } from './models/brapi.model'; import { DataDiscoveryCriteria, DataDiscoverySource } from './models/data-discovery.model'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; @@ -134,7 +134,7 @@ describe('GnpisService', () => { const req = http.expectOne({ method: 'GET', - url: `${BASE_URL}/sources` + url: `${BASE_URL}/datadiscovery/sources` }); req.flush(sources); @@ -157,7 +157,7 @@ describe('GnpisService', () => { }); const req = http.expectOne({ - url: `${BASE_URL}/suggest?field=${field}&text=${text}&fetchSize=${fetchSize}`, + url: `${BASE_URL}/datadiscovery/suggest?field=${field}&text=${text}&fetchSize=${fetchSize}`, method: 'POST' }); req.flush(expectedSuggestions); @@ -173,7 +173,7 @@ describe('GnpisService', () => { gnpisService.germplasm(germplasmDbId).subscribe(response => { fetchedGermplasm = response; }); - http.expectOne(`${BASE_URL_GERMPLASM}/germplasm?id=${germplasmDbId}`) + http.expectOne(`${BASE_URL}/germplasm?id=${germplasmDbId}`) .flush(germplasmTest); expect(fetchedGermplasm).toEqual(germplasmTest); @@ -213,7 +213,7 @@ describe('GnpisService', () => { }); const req = http.expectOne({ - url: `${BASE_URL}/search`, + url: `${BASE_URL}/datadiscovery/search`, method: 'POST' }); req.flush(rawResult); diff --git a/frontend/src/app/gnpis.service.ts b/frontend/src/app/gnpis.service.ts index 1abb0482..7b47607f 100644 --- a/frontend/src/app/gnpis.service.ts +++ b/frontend/src/app/gnpis.service.ts @@ -8,8 +8,7 @@ import { Germplasm } from './models/gnpis.model'; import { XrefResponse } from './models/xref.model'; -export const BASE_URL = 'gnpis/v1/datadiscovery'; -export const BASE_URL_GERMPLASM = 'gnpis/v1'; +export const BASE_URL = 'gnpis/v1'; @Injectable({ providedIn: 'root' @@ -22,7 +21,7 @@ export class GnpisService { } private fetchSources(): void { - this.http.get(`${BASE_URL}/sources`).subscribe( + this.http.get(`${BASE_URL}/datadiscovery/sources`).subscribe( (response: BrapiResults<DataDiscoverySource>) => { const sourceByURI = {}; for (const source of response.result.data) { @@ -49,7 +48,7 @@ export class GnpisService { ): Observable<string[]> { const params = { field, text, fetchSize: fetchSize.toString() }; return this.http.post<string[]>( - `${BASE_URL}/suggest`, criteria, { params } + `${BASE_URL}/datadiscovery/suggest`, criteria, { params } ); } @@ -65,7 +64,7 @@ export class GnpisService { // Get source by URI this.sourceByURI$, // Get documents by criteria - this.http.post<any>(`${BASE_URL}/search`, criteria) + this.http.post<any>(`${BASE_URL}/datadiscovery/search`, criteria) ).pipe(map(([sourceByURI, response]) => { // Extract BrAPI documents from result const documents = response.result.data; @@ -94,11 +93,11 @@ export class GnpisService { } germplasm(germplasmDbId: string): Observable<Germplasm> { - return this.http.get<Germplasm>(`${BASE_URL_GERMPLASM}/germplasm?id=${germplasmDbId}`); + return this.http.get<Germplasm>(`${BASE_URL}/germplasm?id=${germplasmDbId}`); } germplasmByPuid(pui: string): Observable<Germplasm> { - return this.http.get<Germplasm>(`${BASE_URL_GERMPLASM}/germplasm?pui=${pui}`); + return this.http.get<Germplasm>(`${BASE_URL}/germplasm?pui=${pui}`); } /** @@ -109,7 +108,7 @@ export class GnpisService { } xref(xrefId: string): Observable<XrefResponse> { - return this.http.get<XrefResponse>(`gnpis/v1/xref/documentbyfulltextid?linkedRessourcesID=${xrefId}`); + return this.http.get<XrefResponse>(`${BASE_URL}/xref/documentbyfulltextid?linkedRessourcesID=${xrefId}`); } } -- GitLab From 135a8e149da9f77facf03a0dc73d63ea98e8df29 Mon Sep 17 00:00:00 2001 From: jdestin <jeremy.destin@inra.fr> Date: Mon, 18 Mar 2019 15:47:54 +0100 Subject: [PATCH 17/20] fix: Minor fixes. GNP-5490 --- backend/src/main/resources/application.yml | 6 --- .../gpds/repository/file/datasources.jsonld | 2 +- frontend/src/app/brapi.service.spec.ts | 1 + frontend/src/app/brapi.service.ts | 2 +- .../germplasm-card.component.html | 15 ++++-- .../germplasm-card.component.ts | 3 ++ frontend/src/environments/environment.prod.ts | 51 ++----------------- 7 files changed, 20 insertions(+), 60 deletions(-) diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index 2fda83ac..72884e5f 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -29,12 +29,6 @@ gpds: cropOntology-repository-url: https://urgi.versailles.inra.fr/files/ephesis/trait-ontology/data_16.3/ontology-repository.json - gnpis-legacy-url: - https://urgi.versailles.inra.fr/ - - siregal-files-url: - /files/siregal/images/ - # Provides access to user group WS used to query private data ES aliases security-user-group-ws-url: security-user-group-ws-token: diff --git a/backend/src/main/resources/fr/inra/urgi/gpds/repository/file/datasources.jsonld b/backend/src/main/resources/fr/inra/urgi/gpds/repository/file/datasources.jsonld index 5b5ea574..6b319a01 100644 --- a/backend/src/main/resources/fr/inra/urgi/gpds/repository/file/datasources.jsonld +++ b/backend/src/main/resources/fr/inra/urgi/gpds/repository/file/datasources.jsonld @@ -40,7 +40,7 @@ "@id": "https://urgi.versailles.inra.fr", "schema:identifier": "URGI", "schema:name": "URGI GnpIS", - "schema:url": "https://urgi.versailles.inra.fr", + "schema:url": "https://urgi.versailles.inra.fr/gnpis/", "schema:image": "./logos/GnpIS.png" }, { diff --git a/frontend/src/app/brapi.service.spec.ts b/frontend/src/app/brapi.service.spec.ts index d1530e5b..a83f8ef6 100644 --- a/frontend/src/app/brapi.service.spec.ts +++ b/frontend/src/app/brapi.service.spec.ts @@ -406,6 +406,7 @@ describe('BrapiService', () => { }); + // TODO test the progeny call when the information about parent will be added /*it('should fetch the germplasm progeny', () => { let fetchedGermplasmProgeny: GermplasmResult<BrapiGermplasmProgeny>; diff --git a/frontend/src/app/brapi.service.ts b/frontend/src/app/brapi.service.ts index 1d9897b3..a32154a5 100644 --- a/frontend/src/app/brapi.service.ts +++ b/frontend/src/app/brapi.service.ts @@ -33,7 +33,7 @@ export class BrapiService { return this.http .get<BrapiResult<BrapiGermplasmPedigree>>(`${BASE_URL}/germplasm/${germplasmDbId}/pedigree`); } - + // TODO use the progeny call when the information about parent will be added /*germplasmProgeny(germplasmDbId: string): Observable<GermplasmResult<BrapiGermplasmProgeny>> { return this.http.get<GermplasmResult<BrapiGermplasmProgeny>>(`${BASE_URL}/germplasm/${germplasmDbId}/progeny`); }*/ diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.html b/frontend/src/app/germplasm-card/germplasm-card.component.html index dd68d2be..060d95be 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.html +++ b/frontend/src/app/germplasm-card/germplasm-card.component.html @@ -242,12 +242,13 @@ </gpds-card-row> - <gpds-card-row label="Accession synonyms" [test]="germplasmGnpis.synonyms && germplasmGnpis.synonyms.length > 0"> <ng-template> - {{ germplasmGnpis.synonyms.join(', ') }} + <div class="content-overflow"> + {{ germplasmGnpis.synonyms.join(', ') }} + </div> </ng-template> </gpds-card-row> @@ -264,7 +265,9 @@ label="Taxon common names" [test]="germplasmGnpis.taxonCommonNames && germplasmGnpis.taxonCommonNames.length > 0"> <ng-template> - {{ germplasmGnpis.taxonCommonNames.join(', ') }} + <div class="content-overflow"> + {{ germplasmGnpis.taxonCommonNames.join(', ') }} + </div> </ng-template> </gpds-card-row> @@ -272,7 +275,9 @@ label="Taxon synonyms" [test]="germplasmGnpis.taxonSynonyms && germplasmGnpis.taxonSynonyms.length > 0"> <ng-template> - <i>{{ germplasmGnpis.taxonSynonyms.join(', ') }}</i> + <div class="content-overflow"> + <i>{{ germplasmGnpis.taxonSynonyms.join(', ') }}</i> + </div> </ng-template> </gpds-card-row> @@ -850,6 +855,6 @@ </gpds-card-section> <!--XRefs part --> - <gpds-xrefs [xrefId]="germplasmGnpis.germplasmPUI"></gpds-xrefs> + <gpds-xrefs [xrefId]="germplasmGnpis.germplasmPUI"></gpds-xrefs> </ng-container> diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.ts b/frontend/src/app/germplasm-card/germplasm-card.component.ts index bd7addc1..7321f3e0 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.ts +++ b/frontend/src/app/germplasm-card/germplasm-card.component.ts @@ -37,6 +37,8 @@ export class GermplasmCardComponent implements OnInit { germplasmId: string; germplasmPuid: string; germplasmSource: DataDiscoverySource; + + // TODO extract those url in a configuration file. IMAGES_ACCESSION_URL = 'https://urgi.versailles.inra.fr/files/siregal/images/accession/'; IMAGES_INSTITUTION_URL = 'https://urgi.versailles.inra.fr/files/siregal/images//institution/'; IMAGES_BRC_URL = 'https://urgi.versailles.inra.fr/files/siregal/images/grc/inra_brc_en.png'; @@ -55,6 +57,7 @@ export class GermplasmCardComponent implements OnInit { germplasm$.then(result => { const germplasmId = this.germplasmId ? this.germplasmId : result.germplasmDbId; + // TODO use the progeny call when the information about parent will be added. /*const germplasmProgeny$ = this.brapiService.germplasmProgeny(germplasmId).toPromise(); germplasmProgeny$ .then(germplasmProgeny => { diff --git a/frontend/src/environments/environment.prod.ts b/frontend/src/environments/environment.prod.ts index c527bca5..2b34b7fd 100644 --- a/frontend/src/environments/environment.prod.ts +++ b/frontend/src/environments/environment.prod.ts @@ -4,7 +4,6 @@ export const environment = { navbar: { title: 'GnpIS Plant Data Search', links: [ - { label: 'INRA', url: 'http://www.inra.fr/' }, { label: 'URGI', url: '#', @@ -14,52 +13,10 @@ export const environment = { { label: 'About us', url: 'https://urgi.versailles.inra.fr/About-us' } ] }, - { - label: 'Taxon/Germplasm', - url: '#', - subMenu: [ - { label: 'Taxon', url: 'https://urgi.versailles.inra.fr/siregal/common/taxon/form.do' }, - { label: 'Accession Simple', url: 'https://urgi.versailles.inra.fr/gnpis-core' }, - { label: 'Accession passport', url: 'https://urgi.versailles.inra.fr/siregal/siregal/accessionForm.do' }, - { label: 'Collections CRB', url: 'https://urgi.versailles.inra.fr/siregal/siregal/grc.do' }, - ] - }, - { label: 'Phenotyping', url: 'https://urgi.versailles.inra.fr/ephesis/ephesis/viewer.do' }, - { - label: 'Polymorphism', - url: '#', - subMenu: [ - { label: 'Genotyping', url: 'https://urgi.versailles.inra.fr/GnpSNP/snp/genotyping/form.do' }, - { label: 'SNP Discovery', url: 'https://urgi.versailles.inra.fr/GnpSNP/snp/welcome.do' }, - ] - }, - { label: 'Association', url: 'https://urgi.versailles.inra.fr/association/association/viewer.do#form' }, - { - label: 'Map/Marker/QTL', - url: '#', - subMenu: [ - { label: 'Map', url: 'https://urgi.versailles.inra.fr/GnpMap/mapping/searchMap.do' }, - { label: 'Loci', url: 'https://urgi.versailles.inra.fr/GnpMap/mapping/loci/queryLociSelect.do' }, - { label: 'QTL', url: 'https://urgi.versailles.inra.fr/GnpMap/mapping/qtl/queryQtlSelect.do' }, - { label: 'MetaQTLs', url: 'https://urgi.versailles.inra.fr/GnpMap/mapping/metaqtl/form.do' }, - { label: 'Marker', url: 'https://urgi.versailles.inra.fr/GnpMap/mapping/marker/markerForm.do' }, - { label: 'Pool', url: 'https://urgi.versailles.inra.fr/GnpMap/mapping/pool/poolForm.do' }, - { label: 'Traits', url: 'https://urgi.versailles.inra.fr/GnpMap/mapping/queryTraitSelect.do' }, - { label: 'Biomercator', url: 'https://urgi.versailles.inra.fr/Tools/BioMercator-V4' }, - ] - }, - { label: 'Genomes', url: 'https://urgi.versailles.inra.fr/Data/Genome/Genome-data-access' }, - { label: 'Synteny', url: 'https://urgi.versailles.inra.fr/synteny/synteny/viewer.do#dataset' }, - { - label: 'Sequence', - url: '#', - subMenu: [ - { label: 'Sequence', url: 'https://urgi.versailles.inra.fr/sequence/sequence/sequence/form.do' }, - { label: 'Experiment', url: 'https://urgi.versailles.inra.fr/sequence/sequence/experiment/form.do' }, - { label: 'Analysis', url: 'https://urgi.versailles.inra.fr/sequence/sequence/analysis/form.do' }, - { label: 'Project', url: 'https://urgi.versailles.inra.fr/sequence/sequence/project/form.do' }, - ] - } + { label: 'GNPIS', url: 'https://urgi.versailles.inra.fr/gnpis/' }, + { label: 'CIRAD', url: 'http://tropgenedb.cirad.fr/' }, + { label: 'VIB', url: 'http://pippa.psb.ugent.be' }, + { label: 'IBET', url: 'https://biodata.pt' } ] } -- GitLab From e37ced3d2ecc6fe480b13df2f234ae568738cfe7 Mon Sep 17 00:00:00 2001 From: jdestin <jeremy.destin@inra.fr> Date: Tue, 19 Mar 2019 09:14:45 +0100 Subject: [PATCH 18/20] style: Navbar style. GNP-5490 --- frontend/src/app/navbar/navbar.component.scss | 2 +- frontend/src/assets/gpds/theme.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/navbar/navbar.component.scss b/frontend/src/app/navbar/navbar.component.scss index 75a2c2d3..ac17fa6b 100644 --- a/frontend/src/app/navbar/navbar.component.scss +++ b/frontend/src/app/navbar/navbar.component.scss @@ -1,7 +1,7 @@ @import "theme"; .navbar { - background-color: $theme-navbar-bg-color; + background-image: $theme-navbar-bg-color; } .navbar-toggler { diff --git a/frontend/src/assets/gpds/theme.scss b/frontend/src/assets/gpds/theme.scss index b4fae40f..f5969982 100644 --- a/frontend/src/assets/gpds/theme.scss +++ b/frontend/src/assets/gpds/theme.scss @@ -73,7 +73,7 @@ $theme-btn-hover-border-color: $_theme-blue; // custom navbar $theme-navbar-height: 4rem; $theme-navbar-color: $black; -$theme-navbar-bg-color: $_theme-light-gray; +$theme-navbar-bg-color: repeating-linear-gradient(#9b9b9b, #eaeaea, #eaeaea); $theme-navbar-hover-color: $white; $theme-navbar-hover-bg-color: $_theme-gray; -- GitLab From a2d0a8ee2c8f25a635f40f2035cc1f55c572794a Mon Sep 17 00:00:00 2001 From: jdestin <jeremy.destin@inra.fr> Date: Tue, 19 Mar 2019 11:54:14 +0100 Subject: [PATCH 19/20] refactor: Change style for links and navbar. Check if sources exist before display. GNP-5490 --- frontend/package-lock.json | 5 ++++ frontend/package.json | 1 + frontend/src/app/app.module.ts | 4 +++- .../src/app/card-row/card-row.component.scss | 1 + .../germplasm-card.component.html | 4 ++-- .../germplasm-card.component.scss | 8 +++---- .../germplasm-card.component.ts | 24 +++++++------------ frontend/src/app/navbar/navbar.component.scss | 2 +- .../app/site-card/site-card.component.html | 4 ++-- .../app/site-card/site-card.component.scss | 11 +++++---- .../app/study-card/study-card.component.html | 2 +- .../app/study-card/study-card.component.scss | 9 +++---- frontend/src/assets/gpds/theme.scss | 2 +- 13 files changed, 38 insertions(+), 39 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index ff0793af..362fd360 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1189,6 +1189,11 @@ "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", "dev": true }, + "angular-coordinates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/angular-coordinates/-/angular-coordinates-1.0.0.tgz", + "integrity": "sha1-IcuYpv+PTV6LWLjOjvzBP7elnug=" + }, "angular-mocks": { "version": "1.7.8", "resolved": "https://registry.npmjs.org/angular-mocks/-/angular-mocks-1.7.8.tgz", diff --git a/frontend/package.json b/frontend/package.json index c95b0fa4..20b0faab 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -24,6 +24,7 @@ "@ng-bootstrap/ng-bootstrap": "4.0.0", "@types/leaflet": "1.2.14", "@types/leaflet.markercluster": "1.0.3", + "angular-coordinates": "1.0.0", "angular-mocks": "1.7.8", "bootstrap": "4.1.3", "core-js": "2.5.7", diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 8a99e373..a6a37d9d 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -24,6 +24,7 @@ import { LoadingSpinnerComponent } from './loading-spinner/loading-spinner.compo import { CardTableComponent } from './card-table/card-table.component'; import { MomentModule } from 'ngx-moment'; import { XrefsComponent } from './xrefs/xrefs.component'; +import { CoordinatesModule } from 'angular-coordinates'; @NgModule({ @@ -58,7 +59,8 @@ import { XrefsComponent } from './xrefs/xrefs.component'; NgbPopoverModule, FormsModule, ReactiveFormsModule, - MomentModule + MomentModule, + CoordinatesModule ], providers: [ { provide: HTTP_INTERCEPTORS, useExisting: ErrorInterceptorService, multi: true } diff --git a/frontend/src/app/card-row/card-row.component.scss b/frontend/src/app/card-row/card-row.component.scss index 6ed61f5e..d5fab77c 100644 --- a/frontend/src/app/card-row/card-row.component.scss +++ b/frontend/src/app/card-row/card-row.component.scss @@ -4,3 +4,4 @@ font-weight: bold; overflow-wrap: normal; } + diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.html b/frontend/src/app/germplasm-card/germplasm-card.component.html index 060d95be..7e3129e8 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.html +++ b/frontend/src/app/germplasm-card/germplasm-card.component.html @@ -233,10 +233,10 @@ <gpds-card-row label="Data source" - [test]="germplasmGnpis.documentationURL"> + [test]="germplasmSource['schema:identifier'] && germplasmGnpis.documentationURL"> <ng-template> <a target="_blank" [href]="germplasmGnpis.documentationURL"> - Link to this study on source + Link to this study on {{ germplasmSource['schema:identifier'] }} </a> </ng-template> </gpds-card-row> diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.scss b/frontend/src/app/germplasm-card/germplasm-card.component.scss index a2d2d211..f0376501 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.scss +++ b/frontend/src/app/germplasm-card/germplasm-card.component.scss @@ -1,13 +1,11 @@ @import "theme"; @import '../../styles.scss'; -a { - color: #0f6fa1; - text-decoration: underline; -} - a:not([href]):not([tabindex]) { color: #0f6fa1; cursor: pointer; +} + +a:not([href]):not([tabindex]):hover { text-decoration: underline; } diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.ts b/frontend/src/app/germplasm-card/germplasm-card.component.ts index 7321f3e0..fa665b58 100644 --- a/frontend/src/app/germplasm-card/germplasm-card.component.ts +++ b/frontend/src/app/germplasm-card/germplasm-card.component.ts @@ -92,25 +92,17 @@ export class GermplasmCardComponent implements OnInit { let germplasm$: Promise<Germplasm>; if (id) { germplasm$ = this.gnpisService.germplasm(id).toPromise(); - germplasm$ - .then(germplasmGnpis => { - this.germplasmGnpis = germplasmGnpis; - // Get germplasm source - const sourceURI = germplasmGnpis['schema:includedInDataCatalog']; - this.getGermplasmSource(sourceURI); - this.reformatData(germplasmGnpis); - }); } else { germplasm$ = this.gnpisService.germplasmByPuid(pui).toPromise(); - germplasm$ - .then(germplasmGnpis => { - this.germplasmGnpis = germplasmGnpis; - // Get germplasm source - const sourceURI = germplasmGnpis['schema:includedInDataCatalog']; - this.getGermplasmSource(sourceURI); - this.reformatData(germplasmGnpis); - }); } + germplasm$ + .then(germplasmGnpis => { + this.germplasmGnpis = germplasmGnpis; + // Get germplasm source + const sourceURI = germplasmGnpis['schema:includedInDataCatalog']; + this.getGermplasmSource(sourceURI); + this.reformatData(germplasmGnpis); + }); return germplasm$; } diff --git a/frontend/src/app/navbar/navbar.component.scss b/frontend/src/app/navbar/navbar.component.scss index ac17fa6b..75a2c2d3 100644 --- a/frontend/src/app/navbar/navbar.component.scss +++ b/frontend/src/app/navbar/navbar.component.scss @@ -1,7 +1,7 @@ @import "theme"; .navbar { - background-image: $theme-navbar-bg-color; + background-color: $theme-navbar-bg-color; } .navbar-toggler { diff --git a/frontend/src/app/site-card/site-card.component.html b/frontend/src/app/site-card/site-card.component.html index 3af3f6e0..ba9d335e 100644 --- a/frontend/src/app/site-card/site-card.component.html +++ b/frontend/src/app/site-card/site-card.component.html @@ -29,10 +29,10 @@ <gpds-card-row label="Data source" - [test]="location && location.documentationURL"> + [test]="location && location['schema:identifier'] && location.documentationURL"> <ng-template> <a target="_blank" [href]="location.documentationURL"> - Link to this study on {{ location["schema:identifier"] }} + Link to this study on {{ location['schema:identifier'] }} </a> </ng-template> </gpds-card-row> diff --git a/frontend/src/app/site-card/site-card.component.scss b/frontend/src/app/site-card/site-card.component.scss index 55181845..bb109da8 100644 --- a/frontend/src/app/site-card/site-card.component.scss +++ b/frontend/src/app/site-card/site-card.component.scss @@ -1,9 +1,12 @@ +@import "theme"; +@import '../../styles.scss'; -h3 { - font-weight: bold; - color: #0f6191; +a:not([href]):not([tabindex]) { + color: #0f6fa1; + cursor: pointer; } -a { +a:not([href]):not([tabindex]):hover { text-decoration: underline; } + diff --git a/frontend/src/app/study-card/study-card.component.html b/frontend/src/app/study-card/study-card.component.html index 7dafa498..358fd637 100644 --- a/frontend/src/app/study-card/study-card.component.html +++ b/frontend/src/app/study-card/study-card.component.html @@ -43,7 +43,7 @@ <gpds-card-row label="Data source" - [test]="studySource && study.documentationURL"> + [test]="studySource && studySource['schema:identifier'] && study.documentationURL"> <ng-template> <a target="_blank" [href]="study.documentationURL"> Link to this study on {{ studySource["schema:identifier"] }} diff --git a/frontend/src/app/study-card/study-card.component.scss b/frontend/src/app/study-card/study-card.component.scss index 269e24c9..f0376501 100644 --- a/frontend/src/app/study-card/study-card.component.scss +++ b/frontend/src/app/study-card/study-card.component.scss @@ -1,14 +1,11 @@ @import "theme"; @import '../../styles.scss'; - -a { - color: #0f6fa1; - text-decoration: underline; -} - a:not([href]):not([tabindex]) { color: #0f6fa1; cursor: pointer; +} + +a:not([href]):not([tabindex]):hover { text-decoration: underline; } diff --git a/frontend/src/assets/gpds/theme.scss b/frontend/src/assets/gpds/theme.scss index f5969982..b4fae40f 100644 --- a/frontend/src/assets/gpds/theme.scss +++ b/frontend/src/assets/gpds/theme.scss @@ -73,7 +73,7 @@ $theme-btn-hover-border-color: $_theme-blue; // custom navbar $theme-navbar-height: 4rem; $theme-navbar-color: $black; -$theme-navbar-bg-color: repeating-linear-gradient(#9b9b9b, #eaeaea, #eaeaea); +$theme-navbar-bg-color: $_theme-light-gray; $theme-navbar-hover-color: $white; $theme-navbar-hover-bg-color: $_theme-gray; -- GitLab From 7cecf38e6fffa031fa8ebacddf3b1489a11430ab Mon Sep 17 00:00:00 2001 From: Celia Michotey <celia.michotey@inra.fr> Date: Tue, 19 Mar 2019 17:21:35 +0100 Subject: [PATCH 20/20] Add missing 'gnpis' in study source URL check. --- frontend/src/app/result-page/document/document.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/result-page/document/document.component.ts b/frontend/src/app/result-page/document/document.component.ts index b041fe5a..7d5f6b0e 100644 --- a/frontend/src/app/result-page/document/document.component.ts +++ b/frontend/src/app/result-page/document/document.component.ts @@ -30,7 +30,7 @@ export class DocumentComponent implements OnInit { // TODO: index URGI schema:identifier like the partners getRouterLink() { - const urgiStudy = this.document['schema:includedInDataCatalog']['schema:url'] === 'https://urgi.versailles.inra.fr'; + const urgiStudy = this.document['schema:includedInDataCatalog']['schema:url'] === 'https://urgi.versailles.inra.fr/gnpis/'; for (const type of this.document['@type']) { const cardUrl = DocumentComponent.CARD_TYPE[type]; if (cardUrl === 'studies') { -- GitLab