@abi-software/map-side-bar 1.3.17 → 1.3.20
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/del.json +27 -0
- package/dist/map-side-bar.common.js +255 -115
- 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 +255 -115
- 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.json +1 -1
- package/src/App.vue +9 -4
- package/src/components/ContextCard.vue +54 -7
- package/src/components/SearchFilters.vue +43 -10
- package/src/components/SidebarContent.vue +49 -21
- package/src/components/delte.json +27 -0
package/package.json
CHANGED
package/src/App.vue
CHANGED
|
@@ -3,9 +3,10 @@
|
|
|
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
|
|
6
|
+
<el-button @click="openSearch">search Uberon from refs</el-button>
|
|
7
7
|
<el-button @click="singleFacets">Add heart to Filter</el-button>
|
|
8
|
-
|
|
8
|
+
<el-button @click="addStomach">Add stomach to Filter</el-button>
|
|
9
|
+
<el-button @click="AddInvalidTerm">Add invalid term to Filter</el-button>
|
|
9
10
|
<el-button @click="multiFacets">multiple facets</el-button>
|
|
10
11
|
<el-button @click="neuronSearch">open neuron search</el-button>
|
|
11
12
|
<el-button @click="keywordSearch">keyword search</el-button>
|
|
@@ -113,10 +114,14 @@ export default {
|
|
|
113
114
|
this.$refs.sideBar.addFilter({facet: 'Heart', term:'Anatomical structure', facetPropPath: 'anatomy.organ.name', AND: true})
|
|
114
115
|
},
|
|
115
116
|
addStomach: function(){
|
|
116
|
-
this.$refs.sideBar.addFilter({facet: 'Stomach', term:'Anatomical structure', facetPropPath: 'anatomy.organ.name', AND:
|
|
117
|
+
this.$refs.sideBar.addFilter({facet: 'Stomach', term:'Anatomical structure', facetPropPath: 'anatomy.organ.name', AND: false})
|
|
118
|
+
},
|
|
119
|
+
addInvalidTerm: function(){
|
|
120
|
+
this.$refs.sideBar.addFilter({facet: 'Invalid', term:'Anatomical structure', facetPropPath: 'anatomy.organ.name', AND: true})
|
|
117
121
|
},
|
|
118
122
|
multiFacets: function(){
|
|
119
|
-
this.$refs.sideBar.openSearch([{facet: 'Male', term:'Sex', facetPropPath:'attributes.subject.sex.value'}, {facet: 'Heart', term:'Anatomical structure', facetPropPath: 'anatomy.organ.name'}
|
|
123
|
+
this.$refs.sideBar.openSearch([{facet: 'Male', term:'Sex', facetPropPath:'attributes.subject.sex.value'}, {facet: 'Heart', term:'Anatomical structure', facetPropPath: 'anatomy.organ.name'},
|
|
124
|
+
{facet: 'Not correct', term:'Anatomical structure', facetPropPath: 'anatomy.organ.name'}], '')
|
|
120
125
|
},
|
|
121
126
|
keywordSearch: function(){
|
|
122
127
|
this.$refs.sideBar.addFilter({type: 'Facet', label: undefined, facet: '3d model', facetPropPath: 'item.keywords.keyword', term: 'Keywords', AND: true})
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
<div class="view-description">{{view.description}}<i class="el-icon-warning-outline info"></i> </div>
|
|
49
49
|
</span>
|
|
50
50
|
<div v-if="sampleDetails[i]" v-html="samplesMatching(view.id).description" :key="i+'_2'"/>
|
|
51
|
-
<a v-bind:key="i+'_5'" v-if="sampleDetails[i]" :href="generateFileLink(samplesMatching(view.id)
|
|
51
|
+
<a v-bind:key="i+'_5'" v-if="sampleDetails[i]" :href="generateFileLink(samplesMatching(view.id))" target="_blank">View Source</a>
|
|
52
52
|
<div :key="i" class="padding"/>
|
|
53
53
|
|
|
54
54
|
<!-- Extra padding if sample details is open -->
|
|
@@ -79,6 +79,26 @@ Vue.use(Button);
|
|
|
79
79
|
Vue.use(Select);
|
|
80
80
|
Vue.use(Input);
|
|
81
81
|
|
|
82
|
+
const addFilesToPathIfMissing = function(path){
|
|
83
|
+
if (!path.includes('files')){
|
|
84
|
+
return 'files/' + path
|
|
85
|
+
} else {
|
|
86
|
+
return path
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const convertBackslashToForwardSlash = function(path){
|
|
91
|
+
path = path.replaceAll('\\','/')
|
|
92
|
+
path = path.replaceAll('\\\\', '/')
|
|
93
|
+
return path
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// const switchPathToDirectory = function(path){
|
|
97
|
+
// let newPath = path.split('/')
|
|
98
|
+
// newPath.pop()
|
|
99
|
+
// return newPath.join('/')
|
|
100
|
+
// }
|
|
101
|
+
|
|
82
102
|
|
|
83
103
|
export default {
|
|
84
104
|
name: "contextCard",
|
|
@@ -88,6 +108,7 @@ export default {
|
|
|
88
108
|
* the required viewing.
|
|
89
109
|
*/
|
|
90
110
|
entry: Object,
|
|
111
|
+
envVars: Object,
|
|
91
112
|
},
|
|
92
113
|
data: function () {
|
|
93
114
|
return {
|
|
@@ -162,9 +183,11 @@ export default {
|
|
|
162
183
|
.then((data) => {
|
|
163
184
|
this.contextData = data
|
|
164
185
|
this.loading = false
|
|
186
|
+
this.addDiscoverIdsToContextData()
|
|
165
187
|
})
|
|
166
|
-
.catch(() => {
|
|
188
|
+
.catch((err) => {
|
|
167
189
|
//set defaults if we hit an error
|
|
190
|
+
console.error('caught error!', err)
|
|
168
191
|
this.thumbnail = require('@/../assets/missing-image.svg')
|
|
169
192
|
this.discoverId = undefined
|
|
170
193
|
this.loading = false
|
|
@@ -192,15 +215,39 @@ export default {
|
|
|
192
215
|
return path
|
|
193
216
|
}
|
|
194
217
|
path = this.removeDoubleFilesPath(path)
|
|
195
|
-
return `${this.
|
|
218
|
+
return `${this.envVars.API_LOCATION}s3-resource/${this.entry.discoverId}/${this.entry.version}/files/${path}`
|
|
196
219
|
},
|
|
197
|
-
generateFileLink
|
|
198
|
-
|
|
220
|
+
// This is used later when generateing links to the resource on sparc.science (see generateFileLink)
|
|
221
|
+
addDiscoverIdsToContextData(){
|
|
222
|
+
this.contextData.samples.forEach((sample, i)=>{
|
|
223
|
+
if (sample && sample.doi && sample.doi !== ""){
|
|
224
|
+
fetch(`${this.envVars.PENNSIEVE_API_LOCATION}/discover/datasets/doi/${this.splitDoiFromUrl(sample.doi)}`)
|
|
225
|
+
.then((response) => response.json())
|
|
226
|
+
.then((data) => {
|
|
227
|
+
this.contextData.samples[i].discoverId = data.id
|
|
228
|
+
this.contextData.samples[i].version = data.version
|
|
229
|
+
})
|
|
230
|
+
} else {
|
|
231
|
+
this.contextData.samples[i].discoverId = this.entry.discoverId
|
|
232
|
+
this.contextData.samples[i].version = this.entry.version
|
|
233
|
+
}
|
|
234
|
+
})
|
|
235
|
+
},
|
|
236
|
+
processPathForUrl(path){
|
|
237
|
+
path = convertBackslashToForwardSlash(path)
|
|
238
|
+
path = addFilesToPathIfMissing(path)
|
|
239
|
+
return encodeURI(path)
|
|
240
|
+
},
|
|
241
|
+
splitDoiFromUrl(url){
|
|
242
|
+
return url.split('https://doi.org/').pop()
|
|
243
|
+
},
|
|
244
|
+
generateFileLink(sample){
|
|
245
|
+
return `${this.envVars.ROOT_URL}/file/${sample.discoverId}/${sample.version}?path=${this.processPathForUrl(sample.path)}`
|
|
199
246
|
|
|
200
247
|
},
|
|
201
248
|
openViewFile: function(view){
|
|
202
249
|
// note that we assume that the view file is in the same directory as the scaffold (viewUrls take relative paths)
|
|
203
|
-
this.entry.viewUrl = `${this.
|
|
250
|
+
this.entry.viewUrl = `${this.envVars.API_LOCATION}s3-resource/${this.entry.discoverId}/${this.entry.version}/${view.path}`
|
|
204
251
|
this.entry.type = 'Scaffold View'
|
|
205
252
|
EventBus.$emit("PopoverActionClick", this.entry)
|
|
206
253
|
}
|
|
@@ -237,7 +284,7 @@ export default {
|
|
|
237
284
|
|
|
238
285
|
.view-image {
|
|
239
286
|
width: 34px;
|
|
240
|
-
height:
|
|
287
|
+
height: 34px;
|
|
241
288
|
flex: 1;
|
|
242
289
|
margin-right: 4px;
|
|
243
290
|
}
|
|
@@ -178,7 +178,7 @@ export default {
|
|
|
178
178
|
this.createCascaderItemValue(facet.label, facetItem.label);
|
|
179
179
|
});
|
|
180
180
|
});
|
|
181
|
-
this.createDataTypeFacet()
|
|
181
|
+
this.createDataTypeFacet();
|
|
182
182
|
})
|
|
183
183
|
.finally(() => {
|
|
184
184
|
resolve();
|
|
@@ -225,7 +225,7 @@ export default {
|
|
|
225
225
|
this.makeCascadeLabelsClickable();
|
|
226
226
|
}
|
|
227
227
|
},
|
|
228
|
-
// showAllEventModifier: Modifies a cascade event to
|
|
228
|
+
// showAllEventModifier: Modifies a cascade event to unclick all selections in category if "show all" is clicked. Also unchecks "Show all" if any secection is clicked
|
|
229
229
|
// *NOTE* Does NOT remove 'Show all' selections from showing in 'cascadeSelected'
|
|
230
230
|
showAllEventModifier: function (event) {
|
|
231
231
|
// check if show all is in the cascader checked option list
|
|
@@ -363,13 +363,13 @@ export default {
|
|
|
363
363
|
addFilter: function (filter) {
|
|
364
364
|
//Do not set the value unless it is ready
|
|
365
365
|
if (this.cascaderIsReady && filter) {
|
|
366
|
-
this.
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
366
|
+
if (this.validateFilter(filter)) {
|
|
367
|
+
this.cascadeSelected.filter(f=>f.term != filter.term)
|
|
368
|
+
this.cascadeSelected.push([filter.facetPropPath, this.createCascaderItemValue(filter.term, filter.facet), filter.AND])
|
|
369
|
+
this.cascadeSelectedWithBoolean.push([filter.facetPropPath, this.createCascaderItemValue(filter.term, filter.facet), filter.AND])
|
|
370
|
+
// The 'AND' her is to set the boolean value when we search on the filters. It can be undefined without breaking anything
|
|
371
|
+
return true;
|
|
372
|
+
}
|
|
373
373
|
}
|
|
374
374
|
},
|
|
375
375
|
initiateSearch: function() {
|
|
@@ -406,15 +406,48 @@ export default {
|
|
|
406
406
|
});
|
|
407
407
|
});
|
|
408
408
|
},
|
|
409
|
+
/**
|
|
410
|
+
* Validate ther filter term to make sure the term is correct
|
|
411
|
+
*/
|
|
412
|
+
validateFilter: function(filter) {
|
|
413
|
+
if (filter && filter.facet && filter.term) {
|
|
414
|
+
const item = this.createCascaderItemValue(filter.term, filter.facet);
|
|
415
|
+
const facet = this.options.find(element => element.value === filter.facetPropPath);
|
|
416
|
+
if (facet) {
|
|
417
|
+
const filter = facet.children.find(element => element.value === item);
|
|
418
|
+
if (filter)
|
|
419
|
+
return true;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
return false;
|
|
423
|
+
},
|
|
424
|
+
/**
|
|
425
|
+
* Return a list of valid filers given a list of filters,
|
|
426
|
+
*/
|
|
427
|
+
getValidatedFilters: function (filters) {
|
|
428
|
+
if (filters) {
|
|
429
|
+
if (this.cascaderIsReady) {
|
|
430
|
+
const result = [];
|
|
431
|
+
filters.forEach(filter => {
|
|
432
|
+
if (this.validateFilter(filter)) {
|
|
433
|
+
result.push(filter);
|
|
434
|
+
}
|
|
435
|
+
});
|
|
436
|
+
return result;
|
|
437
|
+
} else return filters;
|
|
438
|
+
}
|
|
439
|
+
return [];
|
|
440
|
+
},
|
|
409
441
|
},
|
|
410
442
|
mounted: function () {
|
|
411
443
|
this.algoliaClient = new AlgoliaClient(this.envVars.ALGOLIA_ID, this.envVars.ALGOLIA_KEY, this.envVars.PENNSIEVE_API_LOCATION);
|
|
412
444
|
this.algoliaClient.initIndex(this.envVars.ALGOLIA_INDEX);
|
|
413
445
|
this.populateCascader().then(() => {
|
|
414
446
|
this.cascaderIsReady = true;
|
|
415
|
-
this.checkShowAllBoxes()
|
|
447
|
+
this.checkShowAllBoxes();
|
|
416
448
|
this.setCascader(this.entry.filterFacets);
|
|
417
449
|
this.makeCascadeLabelsClickable();
|
|
450
|
+
this.$emit("cascaderReady");
|
|
418
451
|
});
|
|
419
452
|
},
|
|
420
453
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<el-card :body-style="bodyStyle" class="content-card">
|
|
3
3
|
<div slot="header" class="header">
|
|
4
|
-
<context-card v-if="contextCardEntry && contextCardEnabled" :entry="contextCardEntry" />
|
|
4
|
+
<context-card v-if="contextCardEntry && contextCardEnabled" :entry="contextCardEntry" :envVars="envVars"/>
|
|
5
5
|
<el-input
|
|
6
6
|
class="search-input"
|
|
7
7
|
placeholder="Search"
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
@filterResults="filterUpdate"
|
|
21
21
|
@numberPerPage="numberPerPageUpdate"
|
|
22
22
|
@loading="filtersLoading"
|
|
23
|
+
@cascaderReady="cascaderReady"
|
|
23
24
|
></SearchFilters>
|
|
24
25
|
<div class="content scrollbar" v-loading="loadingCards" ref="content">
|
|
25
26
|
<div
|
|
@@ -125,10 +126,6 @@ export default {
|
|
|
125
126
|
type: Object,
|
|
126
127
|
default: () => {}
|
|
127
128
|
},
|
|
128
|
-
firstSearch: {
|
|
129
|
-
type: String,
|
|
130
|
-
default: ""
|
|
131
|
-
}
|
|
132
129
|
},
|
|
133
130
|
data: function() {
|
|
134
131
|
return {
|
|
@@ -137,7 +134,8 @@ export default {
|
|
|
137
134
|
flex: "1 1 auto",
|
|
138
135
|
"flex-flow": "column",
|
|
139
136
|
display: "flex"
|
|
140
|
-
}
|
|
137
|
+
},
|
|
138
|
+
cascaderIsReady: false,
|
|
141
139
|
};
|
|
142
140
|
},
|
|
143
141
|
computed: {
|
|
@@ -153,22 +151,58 @@ export default {
|
|
|
153
151
|
contextCardUpdate: function(val){
|
|
154
152
|
this.contextCardEntry = val
|
|
155
153
|
},
|
|
154
|
+
resetSearch: function() {
|
|
155
|
+
this.numberOfHits = 0
|
|
156
|
+
this.discoverIds = []
|
|
157
|
+
this._dois = []
|
|
158
|
+
this.results = []
|
|
159
|
+
this.loadingCards = false
|
|
160
|
+
},
|
|
156
161
|
openSearch: function(filter, search='') {
|
|
157
162
|
this.searchInput = search;
|
|
158
163
|
this.resetPageNavigation();
|
|
159
|
-
|
|
160
|
-
if (
|
|
161
|
-
this.filter =
|
|
162
|
-
|
|
164
|
+
//Proceed normally if cascader is ready
|
|
165
|
+
if (this.cascaderIsReady) {
|
|
166
|
+
this.filter = this.$refs.filtersRef.getValidatedFilters(filter);
|
|
167
|
+
//Facets provided but cannot find at least one valid
|
|
168
|
+
//facet. Tell the users the search is invalid and reset
|
|
169
|
+
//facets check boxes.
|
|
170
|
+
if ((filter && filter.length > 0) &&
|
|
171
|
+
(this.filter && this.filter.length === 0)) {
|
|
172
|
+
this.$refs.filtersRef.checkShowAllBoxes();
|
|
173
|
+
this.resetSearch();
|
|
174
|
+
} else if (this.filter) {
|
|
175
|
+
this.searchAlgolia(this.filter, search);
|
|
176
|
+
this.$refs.filtersRef.setCascader(this.filter);
|
|
177
|
+
}
|
|
178
|
+
} else {
|
|
179
|
+
//cascader is not ready, perform search if no filter is set,
|
|
180
|
+
//otherwise waith for cascader to be ready
|
|
181
|
+
this.filter = filter;
|
|
182
|
+
if (!filter || filter.length == 0) {
|
|
183
|
+
this.searchAlgolia(this.filter, search);
|
|
184
|
+
}
|
|
163
185
|
}
|
|
164
186
|
},
|
|
165
187
|
addFilter: function(filter) {
|
|
166
|
-
this.
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
188
|
+
if (this.cascaderIsReady) {
|
|
189
|
+
this.resetPageNavigation();
|
|
190
|
+
if (filter) {
|
|
191
|
+
if (this.$refs.filtersRef.addFilter(filter))
|
|
192
|
+
this.$refs.filtersRef.initiateSearch();
|
|
193
|
+
}
|
|
194
|
+
} else {
|
|
195
|
+
if (Array.isArray(this.filter)) {
|
|
196
|
+
this.filter.push(filter);
|
|
197
|
+
} else {
|
|
198
|
+
this.filter = [filter];
|
|
199
|
+
}
|
|
170
200
|
}
|
|
171
201
|
},
|
|
202
|
+
cascaderReady: function() {
|
|
203
|
+
this.cascaderIsReady = true;
|
|
204
|
+
this.openSearch(this.filter, this.searchInput);
|
|
205
|
+
},
|
|
172
206
|
clearSearchClicked: function() {
|
|
173
207
|
this.searchInput = "";
|
|
174
208
|
this.resetPageNavigation();
|
|
@@ -346,13 +380,7 @@ export default {
|
|
|
346
380
|
// initialise algolia
|
|
347
381
|
this.algoliaClient = new AlgoliaClient(this.envVars.ALGOLIA_ID, this.envVars.ALGOLIA_KEY, this.envVars.PENNSIEVE_API_LOCATION);
|
|
348
382
|
this.algoliaClient.initIndex(this.envVars.ALGOLIA_INDEX);
|
|
349
|
-
|
|
350
|
-
// temporarily disable flatmap search since there are no datasets
|
|
351
|
-
if (this.firstSearch === "Flatmap" || this.firstSearch === "flatmap") {
|
|
352
|
-
this.openSearch(undefined, '')
|
|
353
|
-
} else {
|
|
354
|
-
this.openSearch(undefined, '');
|
|
355
|
-
}
|
|
383
|
+
this.openSearch(undefined, '');
|
|
356
384
|
},
|
|
357
385
|
created: function() {
|
|
358
386
|
//Create non-reactive local variables
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Mean luminal pressure (represented by a color field with red as high pressure and blue as low pressure) recorded from the proximal, transverse and distal sections of the pig colon are mapped on the scaffold. \n\nBaseline data was collected for 30min, followed by 15min of stimulation and 30min of post-stimulation.",
|
|
3
|
+
"heading": "Direct proximal colon stimulation",
|
|
4
|
+
"id": "sparc.science.context_data",
|
|
5
|
+
"samples": [
|
|
6
|
+
{
|
|
7
|
+
"annotation": "",
|
|
8
|
+
"description": "Manometry data recorded from pigs under direct proximal colon stimulation.",
|
|
9
|
+
"doi": "https://doi.org/10.26275/up27-ibcr",
|
|
10
|
+
"heading": "Proximal direct stimulation samples",
|
|
11
|
+
"id": "Sample 1",
|
|
12
|
+
"path": "derivative\\stim_proximal-colon_manometry.csv",
|
|
13
|
+
"view": "View 1"
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"version": "0.1.0",
|
|
17
|
+
"views": [
|
|
18
|
+
{
|
|
19
|
+
"annotation": "--",
|
|
20
|
+
"description": "Sections of pig colon scaffold with mapped manometry data where the data are collected from. ",
|
|
21
|
+
"id": "View 1",
|
|
22
|
+
"path": "colon_Layout1_view.json",
|
|
23
|
+
"sample": "Sample 1",
|
|
24
|
+
"thumbnail": "derivative\\pig_colon_main_thumbnail.jpeg"
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}
|