@abi-software/map-side-bar 1.1.2 → 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 +714 -322
- 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 +714 -322
- 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/public/index.html +1 -1
- package/src/App.vue +14 -4
- package/src/algolia/algolia.js +98 -0
- package/src/algolia/utils.js +52 -0
- package/src/components/DatasetCard.vue +93 -21
- package/src/components/SearchFilters.vue +158 -129
- package/src/components/SideBar.vue +11 -6
- package/src/components/SidebarContent.vue +80 -81
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abi-software/map-side-bar",
|
|
3
|
-
"version": "1.1.
|
|
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/public/index.html
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
6
6
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
|
7
7
|
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
|
8
|
-
<title>
|
|
8
|
+
<title>Map Sidebar</title>
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
11
|
<noscript>
|
package/src/App.vue
CHANGED
|
@@ -4,9 +4,10 @@
|
|
|
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
6
|
<el-button @click="openSearch">search 'heart' from refs</el-button>
|
|
7
|
+
<el-button @click="singleFacets">Add to Filter</el-button>
|
|
7
8
|
<el-button @click="multiFacets">multiple facets</el-button>
|
|
8
9
|
<el-button @click="neuronSearch">open neuron search</el-button>
|
|
9
|
-
<SideBar class="side-bar" ref="sideBar" :
|
|
10
|
+
<SideBar :envVars="envVars" class="side-bar" ref="sideBar" :visible="sideBarVisibility"
|
|
10
11
|
:tabs="tabArray" :activeId="activeId" @tabClicked="tabClicked"
|
|
11
12
|
@search-changed="searchChanged($event)" @actionClick="action"/>
|
|
12
13
|
</div>
|
|
@@ -62,7 +63,13 @@ export default {
|
|
|
62
63
|
]
|
|
63
64
|
}],
|
|
64
65
|
sideBarVisibility: true,
|
|
65
|
-
|
|
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
|
+
},
|
|
66
73
|
activeId: 1,
|
|
67
74
|
}
|
|
68
75
|
},
|
|
@@ -77,10 +84,13 @@ export default {
|
|
|
77
84
|
console.log("action fired: ", val)
|
|
78
85
|
},
|
|
79
86
|
openSearch: function(){
|
|
80
|
-
this.$refs.sideBar.openSearch('heart', [
|
|
87
|
+
this.$refs.sideBar.openSearch('heart', [])
|
|
88
|
+
},
|
|
89
|
+
singleFacets: function(){
|
|
90
|
+
this.$refs.sideBar.addFilter({facet: 'Heart', term:'Anatomical structure', facetPropPath: 'anatomy.organ.name'})
|
|
81
91
|
},
|
|
82
92
|
multiFacets: function(){
|
|
83
|
-
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'}])
|
|
84
94
|
},
|
|
85
95
|
neuronSearch: function(){
|
|
86
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
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="dataset-card-container" ref="container">
|
|
3
3
|
<div v-bind:class=" expanded ? 'dataset-card-expanded' : 'dataset-card'" ref="card">
|
|
4
|
-
|
|
4
|
+
<!-- The seperator-path css is set on SidebarContent.vue -->
|
|
5
|
+
<div class="seperator-path"></div>
|
|
5
6
|
<div class="card" >
|
|
6
7
|
<span class="card-left">
|
|
7
8
|
<img svg-inline class="banner-img" :src="thumbnail" @click="openDataset"/>
|
|
@@ -26,6 +27,12 @@
|
|
|
26
27
|
<div>
|
|
27
28
|
<el-button v-if="entry.simulation" @click="openSimulation" size="mini" class="button" icon="el-icon-view">View simulation</el-button>
|
|
28
29
|
</div>
|
|
30
|
+
<div>
|
|
31
|
+
<el-button v-if="entry.segmentation" @click="openSegmentation" size="mini" class="button" icon="el-icon-view">View segmentation</el-button>
|
|
32
|
+
</div>
|
|
33
|
+
<div>
|
|
34
|
+
<el-button v-if="biolucidaData" @click="openImage" size="mini" class="button" icon="el-icon-view">View image</el-button>
|
|
35
|
+
</div>
|
|
29
36
|
</div>
|
|
30
37
|
|
|
31
38
|
</div>
|
|
@@ -61,9 +68,9 @@ export default {
|
|
|
61
68
|
* the required viewing.
|
|
62
69
|
*/
|
|
63
70
|
entry: Object,
|
|
64
|
-
|
|
65
|
-
type:
|
|
66
|
-
default:
|
|
71
|
+
envVars: {
|
|
72
|
+
type: Object,
|
|
73
|
+
default: () => {}
|
|
67
74
|
},
|
|
68
75
|
},
|
|
69
76
|
data: function () {
|
|
@@ -72,7 +79,8 @@ export default {
|
|
|
72
79
|
dataLocation: this.entry.doi,
|
|
73
80
|
discoverId: undefined,
|
|
74
81
|
cardOverflow: false,
|
|
75
|
-
expanded: false
|
|
82
|
+
expanded: false,
|
|
83
|
+
biolucidaData: undefined
|
|
76
84
|
};
|
|
77
85
|
},
|
|
78
86
|
computed: {
|
|
@@ -94,18 +102,28 @@ export default {
|
|
|
94
102
|
},
|
|
95
103
|
samples: function() {
|
|
96
104
|
let text = "";
|
|
97
|
-
if (this.entry.numberSamples === 1) {
|
|
98
|
-
text = this.entry.numberSamples + " sample";
|
|
99
|
-
} else if (this.entry.numberSamples > 1) {
|
|
100
|
-
text = this.entry.numberSamples + " samples";
|
|
101
|
-
}
|
|
102
105
|
if (this.entry.species) {
|
|
103
106
|
if (speciesMap[this.entry.species[0].toLowerCase()]){
|
|
104
|
-
text
|
|
107
|
+
text = `${speciesMap[this.entry.species[0].toLowerCase()]}`;
|
|
105
108
|
} else {
|
|
106
|
-
text
|
|
109
|
+
text = `${this.entry.species}`;
|
|
107
110
|
}
|
|
108
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
|
+
|
|
109
127
|
return text;
|
|
110
128
|
},
|
|
111
129
|
label: function(){
|
|
@@ -148,7 +166,7 @@ export default {
|
|
|
148
166
|
window.open(this.dataLocation,'_blank');
|
|
149
167
|
},
|
|
150
168
|
openRepository: function() {
|
|
151
|
-
let apiLocation = this.
|
|
169
|
+
let apiLocation = this.envVars.API_LOCATION;
|
|
152
170
|
this.entry.additionalLinks.forEach(function(el) {
|
|
153
171
|
if (el.description == "Repository") {
|
|
154
172
|
let xmlhttp = new XMLHttpRequest();
|
|
@@ -193,13 +211,60 @@ export default {
|
|
|
193
211
|
}
|
|
194
212
|
EventBus.$emit("PopoverActionClick", action)
|
|
195
213
|
},
|
|
214
|
+
openSegmentation: function() {
|
|
215
|
+
if (this.entry.segmentation && this.entry.segmentation[0]) {
|
|
216
|
+
const segmentation = this.entry.segmentation[0];
|
|
217
|
+
const filePath = segmentation.dataset.path;
|
|
218
|
+
const datasetId = this.discoverId;
|
|
219
|
+
const datasetVersion = this.version;
|
|
220
|
+
const prefix = 'https://sparc.biolucida.net:8081';
|
|
221
|
+
const resource = {
|
|
222
|
+
share_link: `${prefix}/dataviewer?datasetId=${datasetId}&version=${datasetVersion}&path=${filePath}`
|
|
223
|
+
};
|
|
224
|
+
let action = {
|
|
225
|
+
label: capitalise(this.label),
|
|
226
|
+
resource: resource,
|
|
227
|
+
dataset: this.dataLocation,
|
|
228
|
+
datasetId: this.discoverId,
|
|
229
|
+
title: "View segmentation",
|
|
230
|
+
name: this.entry.name,
|
|
231
|
+
description: this.entry.description,
|
|
232
|
+
type: "Segmentation"
|
|
233
|
+
};
|
|
234
|
+
EventBus.$emit("PopoverActionClick", action);
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
openImage: function() {
|
|
238
|
+
if (this.biolucidaData) {
|
|
239
|
+
const biolucidaData = this.biolucidaData;
|
|
240
|
+
if ('dataset_images' in biolucidaData) {
|
|
241
|
+
const image = biolucidaData['dataset_images'][0];
|
|
242
|
+
const resource = {
|
|
243
|
+
share_link: image.share_link,
|
|
244
|
+
id: image.image_id,
|
|
245
|
+
itemId: image.sourcepkg_id
|
|
246
|
+
}
|
|
247
|
+
let action = {
|
|
248
|
+
label: capitalise(this.label),
|
|
249
|
+
resource: resource,
|
|
250
|
+
dataset: this.dataLocation,
|
|
251
|
+
datasetId: this.discoverId,
|
|
252
|
+
title: "View image",
|
|
253
|
+
name: this.entry.name,
|
|
254
|
+
description: this.entry.description,
|
|
255
|
+
type: "Biolucida"
|
|
256
|
+
};
|
|
257
|
+
EventBus.$emit("PopoverActionClick", action);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
},
|
|
196
261
|
getScaffoldPath: function(discoverId, version, scaffoldPath){
|
|
197
262
|
let id = discoverId
|
|
198
|
-
let path = `${this.
|
|
263
|
+
let path = `${this.envVars.API_LOCATION}s3-resource/${id}/${version}/files/${scaffoldPath}`
|
|
199
264
|
return path
|
|
200
265
|
},
|
|
201
266
|
getFileFromPath: function(discoverId, version, path){
|
|
202
|
-
return `${this.
|
|
267
|
+
return `${this.envVars.API_LOCATION}s3-resource/${discoverId}/${version}/files/${path}`
|
|
203
268
|
},
|
|
204
269
|
isOverflown: function(el){
|
|
205
270
|
return el.clientHeight < el.scrollHeight
|
|
@@ -225,6 +290,7 @@ export default {
|
|
|
225
290
|
this.discoverId = data.id
|
|
226
291
|
this.version = data.version
|
|
227
292
|
this.dataLocation = `https://sparc.science/datasets/${data.id}?type=dataset`
|
|
293
|
+
this.getBiolucidaInfo(this.discoverId)
|
|
228
294
|
})
|
|
229
295
|
.catch(() => {
|
|
230
296
|
//set defaults if we hit an error
|
|
@@ -235,6 +301,17 @@ export default {
|
|
|
235
301
|
lastName: function(fullName){
|
|
236
302
|
return fullName.split(',')[0]
|
|
237
303
|
},
|
|
304
|
+
getBiolucidaInfo: function(id) {
|
|
305
|
+
let apiLocation = this.envVars.API_LOCATION;
|
|
306
|
+
let endpoint = apiLocation + "image_search/" + id;
|
|
307
|
+
// Add parameters if we are sent them
|
|
308
|
+
fetch(endpoint)
|
|
309
|
+
.then(response => response.json())
|
|
310
|
+
.then(data => {
|
|
311
|
+
if (data.status == "success")
|
|
312
|
+
this.biolucidaData = data;
|
|
313
|
+
});
|
|
314
|
+
}
|
|
238
315
|
},
|
|
239
316
|
mounted: function(){
|
|
240
317
|
this.getBanner()
|
|
@@ -259,12 +336,7 @@ export default {
|
|
|
259
336
|
padding-left: 16px;
|
|
260
337
|
position: relative;
|
|
261
338
|
}
|
|
262
|
-
|
|
263
|
-
width: 486px;
|
|
264
|
-
height: 0px;
|
|
265
|
-
border: solid 1px #e4e7ed;
|
|
266
|
-
background-color: #e4e7ed;
|
|
267
|
-
}
|
|
339
|
+
|
|
268
340
|
.title {
|
|
269
341
|
padding-bottom: 5px;
|
|
270
342
|
font-family: Asap;
|