Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
urgi-is
FAIDARE
Commits
d920184b
Commit
d920184b
authored
Jan 04, 2019
by
Jérémy Destin
Committed by
Guillaume Cornut
Jan 25, 2019
Browse files
feat: Add links in the navbar. Add the spinner during loading. Minor fixes.
GNP-5430
.
parent
a7cec011
Changes
14
Expand all
Hide whitespace changes
Inline
Side-by-side
frontend/package-lock.json
View file @
d920184b
This diff is collapsed.
Click to expand it.
frontend/package.json
View file @
d920184b
...
...
@@ -27,13 +27,14 @@
"bootstrap"
:
"4.1.3"
,
"core-js"
:
"2.5.7"
,
"font-awesome"
:
"4.7.0"
,
"ngx-spinner"
:
"6.1.2"
,
"jquery"
:
"^3.3.1"
,
"leaflet"
:
"^1.3.4"
,
"leaflet.markercluster"
:
"^1.4.1"
,
"popper"
:
"^1.0.1"
,
"rxjs"
:
"6.3.3"
,
"
zone.js"
:
"0.8.26
"
,
"
trait-ontology-widget"
:
"git+https://github.com/gnpis/trait-ontology-widget.git#npm_import
"
"
trait-ontology-widget"
:
"git+https://github.com/gnpis/trait-ontology-widget.git#npm_import
"
,
"
zone.js"
:
"0.8.26
"
},
"devDependencies"
:
{
"@angular-devkit/build-angular"
:
"^0.12.2"
,
...
...
frontend/src/app/app.module.ts
View file @
d920184b
...
...
@@ -13,13 +13,15 @@ import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import
{
NavbarComponent
}
from
'
./navbar/navbar.component
'
;
import
{
MapComponent
}
from
'
./map/map.component
'
;
import
{
NgbAlertModule
,
NgbPaginationModule
,
NgbTabsetModule
,
NgbTypeaheadModule
}
from
'
@ng-bootstrap/ng-bootstrap
'
;
import
{
ReactiveFormsModule
}
from
'
@angular/forms
'
;
import
{
FormsModule
,
ReactiveFormsModule
}
from
'
@angular/forms
'
;
import
{
SuggestionFieldComponent
}
from
'
./form/suggestion-field/suggestion-field.component
'
;
import
{
DocumentComponent
}
from
'
./result-page/document/document.component
'
;
import
{
ErrorComponent
}
from
'
./error/error.component
'
;
import
{
ErrorInterceptorService
}
from
'
./error-interceptor.service
'
;
import
{
TraitOntologyWidgetComponent
}
from
'
./form/trait-ontology-widget/trait-ontology-widget.component
'
;
import
{
FacetsComponent
}
from
'
./result-page/facets/facets.component
'
;
import
{
NgxSpinnerModule
}
from
'
ngx-spinner
'
;
@
NgModule
({
declarations
:
[
...
...
@@ -45,8 +47,11 @@ import { FacetsComponent } from './result-page/facets/facets.component';
NgbPaginationModule
,
NgbTabsetModule
,
NgbAlertModule
,
FormsModule
,
ReactiveFormsModule
,
HttpClientModule
HttpClientModule
,
NgxSpinnerModule
],
providers
:
[
{
provide
:
HTTP_INTERCEPTORS
,
useExisting
:
ErrorInterceptorService
,
multi
:
true
}
...
...
frontend/src/app/form/suggestion-field/suggestion-field.component.spec.ts
View file @
d920184b
...
...
@@ -5,7 +5,7 @@ import { ReactiveFormsModule } from '@angular/forms';
import
{
NgbTypeaheadModule
}
from
'
@ng-bootstrap/ng-bootstrap
'
;
import
{
GnpisService
}
from
'
../../gnpis.service
'
;
import
{
BehaviorSubject
,
of
}
from
'
rxjs
'
;
import
{
empt
yCriteria
}
from
'
../../model/data-discovery.model
'
;
import
{
DataDiscover
yCriteria
Utils
}
from
'
../../model/data-discovery.model
'
;
describe
(
'
SuggestionFieldComponent
'
,
()
=>
{
...
...
@@ -33,13 +33,13 @@ describe('SuggestionFieldComponent', () => {
});
it
(
'
should create
'
,
()
=>
{
component
.
criteria$
=
new
BehaviorSubject
(
emptyCriteria
());
component
.
criteria$
=
new
BehaviorSubject
(
DataDiscoveryCriteriaUtils
.
emptyCriteria
());
fixture
.
detectChanges
();
expect
(
component
).
toBeTruthy
();
});
it
(
'
should fetch suggestion on text change
'
,
async
(()
=>
{
const
criteria
=
emptyCriteria
();
const
criteria
=
DataDiscoveryCriteriaUtils
.
emptyCriteria
();
component
.
criteria$
=
new
BehaviorSubject
(
criteria
);
component
.
criteriaField
=
'
crops
'
;
fixture
.
detectChanges
();
...
...
@@ -59,7 +59,7 @@ describe('SuggestionFieldComponent', () => {
it
(
'
should display the selected criteria as pills
'
,
()
=>
{
component
.
criteriaField
=
'
crops
'
;
const
criteria
=
{
...
emptyCriteria
(),
crops
:
[
'
Zea
'
,
'
Wheat
'
]
};
const
criteria
=
{
...
DataDiscoveryCriteriaUtils
.
emptyCriteria
(),
crops
:
[
'
Zea
'
,
'
Wheat
'
]
};
component
.
criteria$
=
new
BehaviorSubject
(
criteria
);
fixture
.
detectChanges
();
...
...
@@ -75,7 +75,7 @@ describe('SuggestionFieldComponent', () => {
it
(
'
should fetch suggestion
'
,
async
(()
=>
{
component
.
criteriaField
=
'
crops
'
;
const
selectedCrops
=
[
'
Zea
'
,
'
Wheat
'
];
const
criteria
=
{
...
emptyCriteria
(),
crops
:
selectedCrops
};
const
criteria
=
{
...
DataDiscoveryCriteriaUtils
.
emptyCriteria
(),
crops
:
selectedCrops
};
component
.
criteria$
=
new
BehaviorSubject
(
criteria
);
const
allSuggestions
=
[
'
Zea
'
,
'
Wheat
'
,
'
Vitis
'
,
'
Grapevine
'
];
...
...
frontend/src/app/form/trait-ontology-widget/trait-ontology-widget.component.spec.ts
View file @
d920184b
...
...
@@ -3,7 +3,7 @@ import { TestBed } from '@angular/core/testing';
import
{
CropOntologyWidgetFactory
,
TraitOntologyWidgetComponent
}
from
'
./trait-ontology-widget.component
'
;
import
{
GnpisService
}
from
'
../../gnpis.service
'
;
import
{
BehaviorSubject
}
from
'
rxjs
'
;
import
{
empt
yCriteria
}
from
'
../../model/data-discovery.model
'
;
import
{
DataDiscover
yCriteria
Utils
}
from
'
../../model/data-discovery.model
'
;
describe
(
'
TraitOntologyWidgetComponent
'
,
()
=>
{
const
service
=
jasmine
.
createSpyObj
(
...
...
@@ -61,14 +61,14 @@ describe('TraitOntologyWidgetComponent', () => {
it
(
'
should create
'
,
()
=>
{
component
.
criteria$
=
new
BehaviorSubject
(
emptyCriteria
());
component
.
criteria$
=
new
BehaviorSubject
(
DataDiscoveryCriteriaUtils
.
emptyCriteria
());
fixture
.
detectChanges
();
expect
(
component
).
toBeTruthy
();
});
it
(
'
should initialize selection from criteria
'
,
()
=>
{
const
criteria
=
emptyCriteria
();
const
criteria
=
DataDiscoveryCriteriaUtils
.
emptyCriteria
();
criteria
.
topSelectedTraitOntologyIds
=
fakeWidget
.
jsTreePanel
.
jstree
.
get_top_selected
();
const
expectedBottomIds
=
fakeWidget
.
jsTreePanel
.
jstree
.
get_bottom_selected
();
...
...
frontend/src/app/gnpis.service.spec.ts
View file @
d920184b
...
...
@@ -3,7 +3,7 @@ import { TestBed } from '@angular/core/testing';
import
{
GnpisService
}
from
'
./gnpis.service
'
;
import
{
HttpClientTestingModule
,
HttpTestingController
}
from
'
@angular/common/http/testing
'
;
import
{
BrapiMetaData
,
BrapiResults
}
from
'
./model/brapi.model
'
;
import
{
DataDiscoveryCriteria
,
DataDiscoverySource
}
from
'
./model/data-discovery.model
'
;
import
{
DataDiscoveryCriteria
,
DataDiscoveryResults
,
DataDiscoverySource
}
from
'
./model/data-discovery.model
'
;
describe
(
'
GnpisService
'
,
()
=>
{
let
service
:
GnpisService
;
...
...
@@ -11,7 +11,7 @@ describe('GnpisService', () => {
const
source1
:
DataDiscoverySource
=
{
'
@id
'
:
'
id1
'
,
'
@type
'
:
[
'
s
ource
'
],
'
@type
'
:
[
'
s
chema:DataCatalog
'
],
'
schema:identifier
'
:
'
ID 1
'
,
'
schema:name
'
:
'
source 1
'
,
'
schema:url
'
:
'
http://source1.com
'
,
...
...
@@ -19,7 +19,7 @@ describe('GnpisService', () => {
};
const
source2
:
DataDiscoverySource
=
{
'
@id
'
:
'
id2
'
,
'
@type
'
:
[
'
s
ource
'
],
'
@type
'
:
[
'
s
chema:DataCatalog
'
],
'
schema:identifier
'
:
'
ID 2
'
,
'
schema:name
'
:
'
source 2
'
,
'
schema:url
'
:
'
http://source2.com
'
,
...
...
@@ -80,7 +80,7 @@ describe('GnpisService', () => {
it
(
'
should search documents with criteria
'
,
()
=>
{
const
expectedResult
:
Brapi
Results
<
any
>
=
{
const
expectedResult
:
DataDiscovery
Results
=
{
metadata
:
{}
as
BrapiMetaData
,
result
:
{
data
:
[{
...
...
@@ -90,7 +90,7 @@ describe('GnpisService', () => {
'
schema:name
'
:
'
doc_name
'
,
'
schema:url
'
:
'
http://dco/url
'
,
'
schema:description
'
:
'
description
'
,
'
schema:includedInDataCatalog
'
:
'
id1
'
'
schema:includedInDataCatalog
'
:
source1
},
{
'
@type
'
:
[
'
Phenotyping Study
'
],
'
@id
'
:
'
urn
'
,
...
...
@@ -98,9 +98,10 @@ describe('GnpisService', () => {
'
schema:name
'
:
'
doc_name
'
,
'
schema:url
'
:
'
http://dco/url
'
,
'
schema:description
'
:
'
description
'
,
'
schema:includedInDataCatalog
'
:
'
id2
'
'
schema:includedInDataCatalog
'
:
source2
}]
}
},
facets
:
[]
};
const
criteria
=
{
crops
:
[
'
d
'
]
}
as
DataDiscoveryCriteria
;
...
...
frontend/src/app/navbar/navbar.component.html
View file @
d920184b
...
...
@@ -9,7 +9,30 @@
<div
id=
"navbar"
class=
"collapse navbar-collapse"
[class.collapse]=
"navbarCollapsed"
>
<ul
class=
"navbar-nav mr-auto"
>
<li
class=
"nav-item"
*ngFor=
"let link of navbar.links"
>
<a
class=
"nav-link d-flex align-items-center"
[href]=
"link.url"
target=
"_blank"
>
{{ link.label }}
</a>
<div
*ngIf=
"!link.subMenu"
>
<a
class=
"nav-link d-flex align-items-center"
[href]=
"link.url"
target=
"_blank"
>
{{ link.label }}
</a>
</div>
<!-- Dropdown -->
<div
*ngIf=
"link.subMenu"
class=
"dropdown-container"
>
<a
class=
"nav-link d-flex align-items-center dropdown-toggle"
data-toggle=
"dropdown"
[href]=
"link.url"
role=
"button"
aria-haspopup=
"true"
aria-expanded=
"false"
target=
"_blank"
>
{{ link.label }}
</a>
<div
class=
"dropdown-menu"
>
<div
*ngFor=
"let subItem of link.subMenu"
>
<a
class=
"dropdown-item"
href=
"{{ subItem.url }}"
>
{{ subItem.label }}
</a>
</div>
</div>
</div>
</li>
</ul>
</div>
...
...
frontend/src/app/navbar/navbar.component.scss
View file @
d920184b
...
...
@@ -19,3 +19,7 @@
background-color
:
$theme-navbar-hover-bg-color
;
}
}
.dropdown-container
{
position
:
relative
;
}
frontend/src/app/result-page/result-page.component.html
View file @
d920184b
...
...
@@ -39,7 +39,7 @@
<span
class=
"col-4"
id=
"result-part"
>
Results :
</span>
<span
*ngIf=
"pagination.totalResult"
class=
"col-8 text-right small text-muted
p
t-
1
"
>
<span
*ngIf=
"pagination.totalResult"
class=
"col-8 text-right small text-muted
m
t-
3
"
>
From {{ pagination.startResult | number }} to {{ pagination.endResult | number }}
over {{ pagination.totalResult | number }} documents
<span
*ngIf=
"pagination.totalResult > pagination.maxResults"
>
...
...
@@ -86,6 +86,15 @@
</div>
</div>
<ngx-spinner
bdColor=
"rgba(51,51,51,0.6)"
size=
"large"
color=
"#fff"
type=
"ball-spin-clockwise"
></ngx-spinner>
<!-- else we display a simple message -->
<div
*ngIf=
"pagination.totalResult == 0"
id=
"no-results"
class=
"text-center"
>
<div
class=
"no-result-icon"
>
...
...
frontend/src/app/result-page/result-page.component.scss
View file @
d920184b
...
...
@@ -6,13 +6,14 @@
}
.result
{
border-top
:
3
px
solid
#c2c2c2
;
border-top
:
4
.5
px
solid
#c2c2c2
;
border-bottom
:
1px
solid
#c2c2c2
;
}
#result-part
{
font-size
:
1
.2rem
;
font-weight
:
bold
;
margin-top
:
0
.5em
;
display
:
block
;
}
...
...
frontend/src/app/result-page/result-page.component.spec.ts
View file @
d920184b
...
...
@@ -74,14 +74,15 @@ describe('ResultPageComponent', () => {
],
schemas
:
[
NO_ERRORS_SCHEMA
],
});
fixture
=
TestBed
.
createComponent
(
ResultPageComponent
);
component
=
fixture
.
componentInstance
;
}));
it
(
'
should generate criteria from URL
'
,
()
=>
{
fixture
.
detectChanges
();
fixture
.
detectChanges
();
component
.
criteria$
.
subscribe
(
criteria
=>
{
expect
(
criteria
.
crops
).
toEqual
([
params
.
crops
]);
expect
(
criteria
.
germplasmLists
).
toEqual
(
params
.
germplasmLists
);
...
...
@@ -116,6 +117,5 @@ describe('ResultPageComponent', () => {
expect
(
component
.
documents
).
not
.
toBe
(
null
);
});
})
;
frontend/src/app/result-page/result-page.component.ts
View file @
d920184b
...
...
@@ -12,6 +12,7 @@ import { BehaviorSubject } from 'rxjs';
import
{
GnpisService
}
from
'
../gnpis.service
'
;
import
{
filter
}
from
'
rxjs/operators
'
;
import
{
FormComponent
}
from
'
../form/form.component
'
;
import
{
NgxSpinnerService
}
from
'
ngx-spinner
'
;
@
Component
({
...
...
@@ -38,7 +39,8 @@ export class ResultPageComponent implements OnInit {
constructor
(
private
route
:
ActivatedRoute
,
private
router
:
Router
,
private
gnpisService
:
GnpisService
private
gnpisService
:
GnpisService
,
private
spinner
:
NgxSpinnerService
)
{
}
...
...
@@ -49,7 +51,8 @@ export class ResultPageComponent implements OnInit {
this
.
documents
=
result
.
data
;
this
.
updatePagination
(
metadata
.
pagination
);
this
.
facets
=
facets
;
});
this
.
spinner
.
hide
();
},
error
=>
this
.
spinner
.
hide
());
}
private
updatePagination
({
currentPage
,
pageSize
,
totalCount
,
totalPages
})
{
...
...
@@ -62,6 +65,7 @@ export class ResultPageComponent implements OnInit {
}
ngOnInit
():
void
{
this
.
spinner
.
show
();
const
queryParams
=
this
.
route
.
snapshot
.
queryParams
;
// Parse criteria from URL query params
...
...
frontend/src/environments/environment.ts
View file @
d920184b
...
...
@@ -6,7 +6,65 @@ export const environment = {
production
:
false
,
navbar
:
{
title
:
'
GnpIS Plant Data Search
'
,
links
:
[{
label
:
'
URGI
'
,
url
:
'
http://urgi.versailles.inra.fr
'
}]
links
:
[
{
label
:
'
INRA
'
,
url
:
'
http://www.inra.fr/
'
},
{
label
:
'
URGI
'
,
url
:
'
#
'
,
subMenu
:
[
{
label
:
'
Home
'
,
url
:
'
https://urgi.versailles.inra.fr
'
},
{
label
:
'
News
'
,
url
:
'
https://urgi.versailles.inra.fr/About-us/News
'
},
{
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
'
},
]
}
]
}
};
...
...
frontend/src/index.html
View file @
d920184b
...
...
@@ -10,5 +10,15 @@
</head>
<body>
<gpds-root></gpds-root>
<!-- Required for the dropdown menu see : https://getbootstrap.com/docs/4.0/getting-started/introduction/#js -->
<script
src=
"https://code.jquery.com/jquery-3.2.1.slim.min.js"
integrity=
"sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN"
crossorigin=
"anonymous"
></script>
<script
src=
"https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
integrity=
"sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
crossorigin=
"anonymous"
></script>
<script
src=
"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
integrity=
"sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
crossorigin=
"anonymous"
></script>
</body>
</html>
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment