@abi-software/map-side-bar 1.1.5-beta-0 → 1.1.5-beta-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -2
- package/dist/map-side-bar.common.js +607 -318
- package/dist/map-side-bar.common.js.map +1 -1
- package/dist/map-side-bar.css +1 -1
- package/dist/map-side-bar.umd.js +607 -318
- package/dist/map-side-bar.umd.js.map +1 -1
- package/dist/map-side-bar.umd.min.js +1 -1
- package/dist/map-side-bar.umd.min.js.map +1 -1
- package/package-lock.json +384 -146
- package/package.json +3 -1
- package/src/App.vue +13 -10
- package/src/algolia/algolia.js +98 -0
- package/src/algolia/utils.js +52 -0
- package/src/components/DatasetCard.vue +25 -14
- package/src/components/SearchFilters.vue +137 -128
- package/src/components/SideBar.vue +11 -6
- package/src/components/SidebarContent.vue +58 -70
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abi-software/map-side-bar",
|
|
3
|
-
"version": "1.1.5-beta-
|
|
3
|
+
"version": "1.1.5-beta-1",
|
|
4
4
|
"main": "./dist/map-side-bar.common.js",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist/*",
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@abi-software/svg-sprite": "^0.1.12",
|
|
21
|
+
"algoliasearch": "^4.10.5",
|
|
21
22
|
"element-ui": "^2.13.0",
|
|
22
23
|
"vue": "^2.6.10"
|
|
23
24
|
},
|
|
@@ -32,6 +33,7 @@
|
|
|
32
33
|
"file-loader": "^5.0.2",
|
|
33
34
|
"raw-loader": "^0.5.1",
|
|
34
35
|
"transform-loader": "^0.2.4",
|
|
36
|
+
"typescript": "^4.4.3",
|
|
35
37
|
"vue-custom-element": "^3.3.0",
|
|
36
38
|
"vue-template-compiler": "^2.6.10",
|
|
37
39
|
"webpack-node-externals": "^2.5.2"
|
package/src/App.vue
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
<link rel="stylesheet"
|
|
4
4
|
href="https://fonts.googleapis.com/css?family=Asap:400,400i,500,600,700&display=swap">
|
|
5
5
|
Click arrow to open sidebar
|
|
6
|
-
<el-button @click="openSearch">search '
|
|
7
|
-
<el-button @click="singleFacets">
|
|
6
|
+
<el-button @click="openSearch">search 'heart' from refs</el-button>
|
|
7
|
+
<el-button @click="singleFacets">Add to Filter</el-button>
|
|
8
8
|
<el-button @click="multiFacets">multiple facets</el-button>
|
|
9
9
|
<el-button @click="neuronSearch">open neuron search</el-button>
|
|
10
|
-
<SideBar class="side-bar" ref="sideBar" :
|
|
10
|
+
<SideBar :envVars="envVars" class="side-bar" ref="sideBar" :visible="sideBarVisibility"
|
|
11
11
|
:tabs="tabArray" :activeId="activeId" @tabClicked="tabClicked"
|
|
12
12
|
@search-changed="searchChanged($event)" @actionClick="action"/>
|
|
13
13
|
</div>
|
|
@@ -63,7 +63,13 @@ export default {
|
|
|
63
63
|
]
|
|
64
64
|
}],
|
|
65
65
|
sideBarVisibility: true,
|
|
66
|
-
|
|
66
|
+
envVars: {
|
|
67
|
+
API_LOCATION: process.env.VUE_APP_API_LOCATION,
|
|
68
|
+
ALGOLIA_KEY: process.env.VUE_APP_ALGOLIA_KEY,
|
|
69
|
+
ALGOLIA_ID: process.env.VUE_APP_ALGOLIA_ID,
|
|
70
|
+
ALGOLIA_INDEX: process.env.VUE_APP_ALGOLIA_INDEX,
|
|
71
|
+
PENNSIEVE_API_LOCATION: process.env.VUE_APP_PENNSIEVE_API_LOCATION
|
|
72
|
+
},
|
|
67
73
|
activeId: 1,
|
|
68
74
|
}
|
|
69
75
|
},
|
|
@@ -78,16 +84,13 @@ export default {
|
|
|
78
84
|
console.log("action fired: ", val)
|
|
79
85
|
},
|
|
80
86
|
openSearch: function(){
|
|
81
|
-
this.$refs.sideBar.openSearch('
|
|
82
|
-
{facet: "show all", term:'species'},
|
|
83
|
-
{facet: "show all", term:'gender'},
|
|
84
|
-
{facet: "show all", term:'datasets'}] )
|
|
87
|
+
this.$refs.sideBar.openSearch('heart', [])
|
|
85
88
|
},
|
|
86
89
|
singleFacets: function(){
|
|
87
|
-
this.$refs.sideBar.
|
|
90
|
+
this.$refs.sideBar.addFilter({facet: 'Heart', term:'Anatomical structure', facetPropPath: 'anatomy.organ.name'})
|
|
88
91
|
},
|
|
89
92
|
multiFacets: function(){
|
|
90
|
-
this.$refs.sideBar.openSearch('', [{facet: '
|
|
93
|
+
this.$refs.sideBar.openSearch('', [{facet: 'Male', term:'Sex', facetPropPath:'attributes.subject.sex.value'}, {facet: 'Heart', term:'Anatomical structure', facetPropPath: 'anatomy.organ.name'}])
|
|
91
94
|
},
|
|
92
95
|
neuronSearch: function(){
|
|
93
96
|
this.$refs.sideBar.openNeuronSearch('neuron-type-keast-10')
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/* eslint-disable no-alert, no-console */
|
|
2
|
+
import algoliasearch from 'algoliasearch'
|
|
3
|
+
|
|
4
|
+
// export `createAlgoliaClient` to use it in page components
|
|
5
|
+
export class AlgoliaClient {
|
|
6
|
+
constructor(algoliaId, algoliaKey, PENNSIEVE_API_LOCATION='https://api.pennsieve.io') {
|
|
7
|
+
this.client = algoliasearch(
|
|
8
|
+
algoliaId,
|
|
9
|
+
algoliaKey
|
|
10
|
+
)
|
|
11
|
+
this.PENNSIEVE_API_LOCATION = PENNSIEVE_API_LOCATION
|
|
12
|
+
}
|
|
13
|
+
initIndex(ALGOLIA_INDEX) {
|
|
14
|
+
this.index = this.client.initIndex(ALGOLIA_INDEX);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
getAlgoliaFacets (propPathMapping) {
|
|
18
|
+
const map = new Map(Object.entries(propPathMapping));
|
|
19
|
+
const facetPropPaths = Array.from(map.keys() );
|
|
20
|
+
let facetData = []
|
|
21
|
+
let facetId = 0
|
|
22
|
+
return this.index
|
|
23
|
+
.search('', {
|
|
24
|
+
sortFacetValuesBy: 'alpha',
|
|
25
|
+
facets: facetPropPaths
|
|
26
|
+
})
|
|
27
|
+
.then(response => {
|
|
28
|
+
facetPropPaths.map((facetPropPath) => {
|
|
29
|
+
var children = []
|
|
30
|
+
const responseFacets = response.facets
|
|
31
|
+
if (responseFacets === undefined) {return}
|
|
32
|
+
const responseFacetChildren =
|
|
33
|
+
responseFacets[facetPropPath] == undefined
|
|
34
|
+
? {}
|
|
35
|
+
: responseFacets[facetPropPath]
|
|
36
|
+
Object.keys(responseFacetChildren).map(facet => {
|
|
37
|
+
children.push({
|
|
38
|
+
label: facet,
|
|
39
|
+
id: facetId++,
|
|
40
|
+
facetPropPath: facetPropPath
|
|
41
|
+
})
|
|
42
|
+
})
|
|
43
|
+
if (children.length > 0) {
|
|
44
|
+
facetData.push({
|
|
45
|
+
label: map.get(facetPropPath),
|
|
46
|
+
id: facetId++,
|
|
47
|
+
children: children,
|
|
48
|
+
key: facetPropPath
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
return facetData
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Returns all DOIs of all versions for a given discover dataset
|
|
57
|
+
_discoverAllDois (discoverId, PENNSIEVE_API_LOCATION='https://api.pennsieve.io') {
|
|
58
|
+
return new Promise(resolve => {
|
|
59
|
+
fetch(`${PENNSIEVE_API_LOCATION}/discover/datasets/${discoverId}/versions`).then(r=>r.json()).then(dataset => {
|
|
60
|
+
resolve(dataset.map(version => version.doi))
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Get all dois given a list of discoverIds
|
|
66
|
+
_expandDois (discoverIds, PENNSIEVE_API_LOCATION='https://api.pennsieve.io') {
|
|
67
|
+
return new Promise(resolve => {
|
|
68
|
+
let promiseList = discoverIds.map(discoverId => this._discoverAllDois(discoverId, PENNSIEVE_API_LOCATION))
|
|
69
|
+
Promise.all(promiseList).then((values) => {
|
|
70
|
+
resolve(values.flat())
|
|
71
|
+
});
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Get Search results
|
|
77
|
+
* This is using fetch from the Algolia API
|
|
78
|
+
*/
|
|
79
|
+
search (filter, query='', hitsperPage=10, page=1) {
|
|
80
|
+
return new Promise(resolve => {
|
|
81
|
+
this.index
|
|
82
|
+
.search(query, {
|
|
83
|
+
facets:['*'],
|
|
84
|
+
hitsPerPage: hitsperPage,
|
|
85
|
+
page: page-1,
|
|
86
|
+
filters: filter
|
|
87
|
+
})
|
|
88
|
+
.then(response => {
|
|
89
|
+
let searchData = {
|
|
90
|
+
items: response.hits,
|
|
91
|
+
total: response.nbHits,
|
|
92
|
+
discoverIds: response.hits.map(r=>r.pennsieve.identifier)
|
|
93
|
+
}
|
|
94
|
+
resolve(searchData)
|
|
95
|
+
})
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/* eslint-disable no-alert, no-console */
|
|
2
|
+
|
|
3
|
+
// Mapping between display categories and their Algolia index property path
|
|
4
|
+
// Used for populating the Dataset Search Results facet menu dynamically
|
|
5
|
+
export const facetPropPathMapping = {
|
|
6
|
+
'anatomy.organ.name' : 'Anatomical Structure',
|
|
7
|
+
'organisms.primary.species.name' : 'Species',
|
|
8
|
+
'item.modalities.keyword' : 'Experimental Approach',
|
|
9
|
+
'attributes.subject.sex.value' : 'Sex',
|
|
10
|
+
'attributes.subject.ageCategory.value' : 'Age Categories',
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/* Returns filter for searching algolia. All facets of the same category are joined with OR,
|
|
14
|
+
* and each of those results is then joined with an AND.
|
|
15
|
+
* i.e. (color:blue OR color:red) AND (shape:circle OR shape:red) */
|
|
16
|
+
export function getFilters(selectedFacetArray=undefined) {
|
|
17
|
+
|
|
18
|
+
// return all datasets if no filter
|
|
19
|
+
if (selectedFacetArray === undefined) {
|
|
20
|
+
return 'NOT item.published.status:embargo'
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Switch the 'term' attribute to 'label' if 'label' does not exist
|
|
24
|
+
selectedFacetArray.forEach(f=>f.label=f.facet)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
let facets = removeShowAllFacets(selectedFacetArray)
|
|
28
|
+
|
|
29
|
+
let filters = "NOT item.published.status:embargo";
|
|
30
|
+
filters = `(${filters}) AND `;
|
|
31
|
+
|
|
32
|
+
const facetPropPaths = Object.keys(facetPropPathMapping);
|
|
33
|
+
facetPropPaths.map((facetPropPath) => {
|
|
34
|
+
const facetsToOr = facets.filter(
|
|
35
|
+
(facet) => facet.facetPropPath == facetPropPath
|
|
36
|
+
);
|
|
37
|
+
var filter = "";
|
|
38
|
+
facetsToOr.map((facet) => {
|
|
39
|
+
filter += `"${facetPropPath}":"${facet.label}" OR `;
|
|
40
|
+
});
|
|
41
|
+
if (filter == "") {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
filter = `(${filter.substring(0, filter.lastIndexOf(" OR "))})`;
|
|
45
|
+
filters += `${filter} AND `;
|
|
46
|
+
});
|
|
47
|
+
return filters.substring(0, filters.lastIndexOf(" AND "));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function removeShowAllFacets(facetArray){
|
|
51
|
+
return facetArray.filter( f => f.label !== 'Show all')
|
|
52
|
+
}
|
|
@@ -68,9 +68,9 @@ export default {
|
|
|
68
68
|
* the required viewing.
|
|
69
69
|
*/
|
|
70
70
|
entry: Object,
|
|
71
|
-
|
|
72
|
-
type:
|
|
73
|
-
default:
|
|
71
|
+
envVars: {
|
|
72
|
+
type: Object,
|
|
73
|
+
default: () => {}
|
|
74
74
|
},
|
|
75
75
|
},
|
|
76
76
|
data: function () {
|
|
@@ -102,18 +102,28 @@ export default {
|
|
|
102
102
|
},
|
|
103
103
|
samples: function() {
|
|
104
104
|
let text = "";
|
|
105
|
-
if (this.entry.numberSamples === 1) {
|
|
106
|
-
text = this.entry.numberSamples + " sample";
|
|
107
|
-
} else if (this.entry.numberSamples > 1) {
|
|
108
|
-
text = this.entry.numberSamples + " samples";
|
|
109
|
-
}
|
|
110
105
|
if (this.entry.species) {
|
|
111
106
|
if (speciesMap[this.entry.species[0].toLowerCase()]){
|
|
112
|
-
text
|
|
107
|
+
text = `${speciesMap[this.entry.species[0].toLowerCase()]}`;
|
|
113
108
|
} else {
|
|
114
|
-
text
|
|
109
|
+
text = `${this.entry.species}`;
|
|
115
110
|
}
|
|
116
111
|
}
|
|
112
|
+
if (this.entry.numberSamples > 0) {
|
|
113
|
+
text += " (";
|
|
114
|
+
if (this.entry.numberSamples === 1) {
|
|
115
|
+
text += `${this.entry.numberSamples} sample`;
|
|
116
|
+
} else if (this.entry.numberSamples > 1) {
|
|
117
|
+
text += `${this.entry.numberSamples} samples`;
|
|
118
|
+
}
|
|
119
|
+
if (this.entry.numberSubjects === 1) {
|
|
120
|
+
text += ` from ${this.entry.numberSubjects} subject`;
|
|
121
|
+
} else if (this.entry.numberSamples > 1) {
|
|
122
|
+
text += ` from ${this.entry.numberSubjects} subjects`;
|
|
123
|
+
}
|
|
124
|
+
text += ")";
|
|
125
|
+
}
|
|
126
|
+
|
|
117
127
|
return text;
|
|
118
128
|
},
|
|
119
129
|
label: function(){
|
|
@@ -156,7 +166,7 @@ export default {
|
|
|
156
166
|
window.open(this.dataLocation,'_blank');
|
|
157
167
|
},
|
|
158
168
|
openRepository: function() {
|
|
159
|
-
let apiLocation = this.
|
|
169
|
+
let apiLocation = this.envVars.API_LOCATION;
|
|
160
170
|
this.entry.additionalLinks.forEach(function(el) {
|
|
161
171
|
if (el.description == "Repository") {
|
|
162
172
|
let xmlhttp = new XMLHttpRequest();
|
|
@@ -250,11 +260,11 @@ export default {
|
|
|
250
260
|
},
|
|
251
261
|
getScaffoldPath: function(discoverId, version, scaffoldPath){
|
|
252
262
|
let id = discoverId
|
|
253
|
-
let path = `${this.
|
|
263
|
+
let path = `${this.envVars.API_LOCATION}s3-resource/${id}/${version}/files/${scaffoldPath}`
|
|
254
264
|
return path
|
|
255
265
|
},
|
|
256
266
|
getFileFromPath: function(discoverId, version, path){
|
|
257
|
-
return `${this.
|
|
267
|
+
return `${this.envVars.API_LOCATION}s3-resource/${discoverId}/${version}/files/${path}`
|
|
258
268
|
},
|
|
259
269
|
isOverflown: function(el){
|
|
260
270
|
return el.clientHeight < el.scrollHeight
|
|
@@ -292,7 +302,8 @@ export default {
|
|
|
292
302
|
return fullName.split(',')[0]
|
|
293
303
|
},
|
|
294
304
|
getBiolucidaInfo: function(id) {
|
|
295
|
-
let
|
|
305
|
+
let apiLocation = this.envVars.API_LOCATION;
|
|
306
|
+
let endpoint = apiLocation + "image_search/" + id;
|
|
296
307
|
// Add parameters if we are sent them
|
|
297
308
|
fetch(endpoint)
|
|
298
309
|
.then(response => response.json())
|