@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
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
@tags-changed="tagsChangedCallback"
|
|
19
19
|
></custom-cascader>
|
|
20
20
|
<div v-if="showFiltersText" class="filter-default-value">
|
|
21
|
-
<svg-icon icon="noun-filter" class="filter-icon-inside" />Apply
|
|
21
|
+
<svg-icon icon="noun-filter" class="filter-icon-inside" />Apply
|
|
22
|
+
Filters
|
|
22
23
|
</div>
|
|
23
24
|
</span>
|
|
24
25
|
</transition>
|
|
@@ -29,9 +30,14 @@
|
|
|
29
30
|
placeholder="10"
|
|
30
31
|
@change="numberShownChanged($event)"
|
|
31
32
|
>
|
|
32
|
-
<el-option
|
|
33
|
+
<el-option
|
|
34
|
+
v-for="item in numberDatasetsShown"
|
|
35
|
+
:key="item"
|
|
36
|
+
:label="item"
|
|
37
|
+
:value="item"
|
|
38
|
+
></el-option>
|
|
33
39
|
</el-select>
|
|
34
|
-
<span class="dataset-results-feedback">{{this.numberOfResultsText}}</span>
|
|
40
|
+
<span class="dataset-results-feedback">{{ this.numberOfResultsText }}</span>
|
|
35
41
|
</div>
|
|
36
42
|
</template>
|
|
37
43
|
|
|
@@ -46,30 +52,33 @@ import locale from "element-ui/lib/locale";
|
|
|
46
52
|
import speciesMap from "./species-map";
|
|
47
53
|
import { SvgIcon, SvgSpriteColor } from "@abi-software/svg-sprite";
|
|
48
54
|
|
|
55
|
+
import {AlgoliaClient} from "../algolia/algolia.js";
|
|
56
|
+
import { facetPropPathMapping } from "../algolia/utils.js";
|
|
57
|
+
|
|
49
58
|
Vue.component("svg-icon", SvgIcon);
|
|
50
59
|
|
|
51
60
|
locale.use(lang);
|
|
52
61
|
Vue.use(Option);
|
|
53
62
|
Vue.use(Select);
|
|
54
63
|
|
|
55
|
-
const capitalise = function(txt) {
|
|
64
|
+
const capitalise = function (txt) {
|
|
56
65
|
return txt.charAt(0).toUpperCase() + txt.slice(1);
|
|
57
66
|
};
|
|
58
67
|
|
|
59
|
-
const convertReadableLabel = function(original) {
|
|
68
|
+
const convertReadableLabel = function (original) {
|
|
60
69
|
const name = original.toLowerCase();
|
|
61
|
-
if (speciesMap[name]){
|
|
70
|
+
if (speciesMap[name]) {
|
|
62
71
|
return capitalise(speciesMap[name]);
|
|
63
72
|
} else {
|
|
64
73
|
return capitalise(name);
|
|
65
74
|
}
|
|
66
|
-
}
|
|
75
|
+
};
|
|
67
76
|
|
|
68
77
|
export default {
|
|
69
78
|
name: "SearchFilters",
|
|
70
79
|
components: {
|
|
71
80
|
CustomCascader,
|
|
72
|
-
SvgSpriteColor
|
|
81
|
+
SvgSpriteColor,
|
|
73
82
|
},
|
|
74
83
|
props: {
|
|
75
84
|
/**
|
|
@@ -77,19 +86,19 @@ export default {
|
|
|
77
86
|
* the required viewing.
|
|
78
87
|
*/
|
|
79
88
|
entry: Object,
|
|
80
|
-
|
|
81
|
-
type:
|
|
82
|
-
default:
|
|
83
|
-
}
|
|
89
|
+
envVars: {
|
|
90
|
+
type: Object,
|
|
91
|
+
default: ()=>{}
|
|
92
|
+
},
|
|
84
93
|
},
|
|
85
|
-
data: function() {
|
|
94
|
+
data: function () {
|
|
86
95
|
return {
|
|
87
96
|
cascaderIsReady: false,
|
|
88
97
|
previousShowAllChecked: {
|
|
89
98
|
species: false,
|
|
90
99
|
gender: false,
|
|
91
100
|
organ: false,
|
|
92
|
-
datasets: false
|
|
101
|
+
datasets: false,
|
|
93
102
|
},
|
|
94
103
|
showFilters: true,
|
|
95
104
|
showFiltersText: true,
|
|
@@ -103,110 +112,91 @@ export default {
|
|
|
103
112
|
{
|
|
104
113
|
value: "Species",
|
|
105
114
|
label: "Species",
|
|
106
|
-
children: [{}]
|
|
107
|
-
}
|
|
108
|
-
]
|
|
115
|
+
children: [{}],
|
|
116
|
+
},
|
|
117
|
+
],
|
|
109
118
|
};
|
|
110
119
|
},
|
|
111
120
|
computed: {
|
|
112
|
-
numberOfResultsText: function() {
|
|
121
|
+
numberOfResultsText: function () {
|
|
113
122
|
return `${this.entry.numberOfHits} results | Showing`;
|
|
114
|
-
}
|
|
123
|
+
},
|
|
115
124
|
},
|
|
116
125
|
methods: {
|
|
117
|
-
createCascaderItemValue: function(term, facet) {
|
|
126
|
+
createCascaderItemValue: function (term, facet) {
|
|
118
127
|
if (facet) return term + "/" + facet;
|
|
119
128
|
else return term;
|
|
120
129
|
},
|
|
121
|
-
populateCascader: function() {
|
|
122
|
-
return new Promise(resolve => {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
)
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
},
|
|
154
|
-
getFacet: function(facetLabel) {
|
|
155
|
-
if (facetLabel === "Datasets") {
|
|
156
|
-
// The datasets facet doesn't exist on SciCrunch yet, so manually set it
|
|
157
|
-
// for now.
|
|
158
|
-
return new Promise(resolve => {
|
|
159
|
-
resolve([...new Set(["Show all", "Scaffolds", "Simulations"])]);
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
return new Promise(resolve => {
|
|
163
|
-
let facets = ["Show all"]; // Set 'Show all' as our first label
|
|
164
|
-
let facet = facetLabel.toLowerCase();
|
|
165
|
-
this.callSciCrunch(this.apiLocation, this.facetEndpoint, facet).then(
|
|
166
|
-
facet_terms => {
|
|
167
|
-
facet_terms.forEach(element => {
|
|
168
|
-
facets.push(element["key"]); // add facets that scicrunch includes
|
|
130
|
+
populateCascader: function () {
|
|
131
|
+
return new Promise((resolve) => {
|
|
132
|
+
// Algolia facet serach
|
|
133
|
+
this.algoliaClient.getAlgoliaFacets(facetPropPathMapping)
|
|
134
|
+
.then((data) => {
|
|
135
|
+
this.facets = data;
|
|
136
|
+
this.options = data;
|
|
137
|
+
|
|
138
|
+
// create top level of options in cascader
|
|
139
|
+
this.options.forEach((facet, i) => {
|
|
140
|
+
this.options[i].label = convertReadableLabel(facet.label);
|
|
141
|
+
this.options[i].value = this.createCascaderItemValue(
|
|
142
|
+
facet.key,
|
|
143
|
+
undefined
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
// put "Show all" as first option
|
|
147
|
+
this.options[i].children.unshift({
|
|
148
|
+
value: this.createCascaderItemValue("Show all"),
|
|
149
|
+
label: "Show all",
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// populate second level of options
|
|
153
|
+
this.options[i].children.forEach((facetItem, j) => {
|
|
154
|
+
this.options[i].children[j].label = convertReadableLabel(
|
|
155
|
+
facetItem.label
|
|
156
|
+
);
|
|
157
|
+
this.options[i].children[j].value =
|
|
158
|
+
this.createCascaderItemValue(facet.label, facetItem.label);
|
|
159
|
+
});
|
|
169
160
|
});
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
161
|
+
})
|
|
162
|
+
.finally(() => {
|
|
163
|
+
resolve();
|
|
164
|
+
});
|
|
173
165
|
});
|
|
174
166
|
},
|
|
175
|
-
|
|
176
|
-
switchTermToRequest: function(term) {
|
|
177
|
-
return term.split(" ")[0].toLowerCase();
|
|
178
|
-
},
|
|
179
|
-
tagsChangedCallback: function(presentTags) {
|
|
167
|
+
tagsChangedCallback: function (presentTags) {
|
|
180
168
|
if (presentTags.length > 0) {
|
|
181
169
|
this.showFiltersText = false;
|
|
182
170
|
} else {
|
|
183
171
|
this.showFiltersText = true;
|
|
184
172
|
}
|
|
185
173
|
},
|
|
186
|
-
cascadeEvent:
|
|
187
|
-
|
|
174
|
+
// cascadeEvent: initiate searches based off cascader changes
|
|
175
|
+
cascadeEvent: function (event) {
|
|
188
176
|
if (event) {
|
|
189
177
|
// Check for show all in selected cascade options
|
|
190
178
|
event = this.showAllEventModifier(event);
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
179
|
+
|
|
180
|
+
// Move results from arrays to object
|
|
181
|
+
let filters = event.filter( selection => selection !== undefined).map( fs => ({
|
|
182
|
+
facetPropPath: fs[0],
|
|
183
|
+
facet: fs[1].split("/")[1],
|
|
184
|
+
term: fs[1].split("/")[0],
|
|
185
|
+
}))
|
|
186
|
+
|
|
187
|
+
this.$emit('loading', true) // let sidebarcontent wait for the requests
|
|
188
|
+
|
|
189
|
+
this.$emit("filterResults", filters); // emit filters for apps above sidebar
|
|
190
|
+
this.setCascader(filters); //update our cascader v-model if we modified the event
|
|
191
|
+
this.makeCascadeLabelsClickable();
|
|
201
192
|
}
|
|
202
|
-
this.$emit("filterResults", filters);
|
|
203
|
-
this.setCascader(filters); //update our cascader v-model if we modified the event
|
|
204
|
-
this.makeCascadeLabelsClickable();
|
|
205
193
|
},
|
|
206
|
-
showAllEventModifier:
|
|
194
|
+
// showAllEventModifier: Modifies a cascade event to unlick all selections in category if "show all" is clicked. Also unchecks "Show all" if any secection is clicked
|
|
195
|
+
// *NOTE* Does NOT remove 'Show all' selections from showing in 'cascadeSelected'
|
|
196
|
+
showAllEventModifier: function (event) {
|
|
207
197
|
// check if show all is in the cascader checked option list
|
|
208
198
|
let hasShowAll = event
|
|
209
|
-
.map(ev => (ev ? ev[1].toLowerCase().includes("show all") : false))
|
|
199
|
+
.map((ev) => (ev ? ev[1].toLowerCase().includes("show all") : false))
|
|
210
200
|
.includes(true);
|
|
211
201
|
// remove all selected options below the show all if checked
|
|
212
202
|
if (hasShowAll) {
|
|
@@ -217,7 +207,6 @@ export default {
|
|
|
217
207
|
if (facetMaps[event[i][0]] === undefined) facetMaps[event[i][0]] = [];
|
|
218
208
|
facetMaps[event[i][0]].push(event[i]);
|
|
219
209
|
}
|
|
220
|
-
|
|
221
210
|
// go through each facets
|
|
222
211
|
for (const facet in facetMaps) {
|
|
223
212
|
let showAll = undefined;
|
|
@@ -244,59 +233,96 @@ export default {
|
|
|
244
233
|
modifiedEvent.push(...facetMaps[facet]);
|
|
245
234
|
}
|
|
246
235
|
}
|
|
247
|
-
|
|
236
|
+
//Make sure the expanded item are sorted first.
|
|
237
|
+
return modifiedEvent.sort((a, b) => {
|
|
238
|
+
if (this.__expandItem__) {
|
|
239
|
+
if (a[0] == this.__expandItem__) {
|
|
240
|
+
if (b[0] == this.__expandItem__) {
|
|
241
|
+
return 0;
|
|
242
|
+
} else {
|
|
243
|
+
return -1;
|
|
244
|
+
}
|
|
245
|
+
} else if (b[0] == this.__expandItem__) {
|
|
246
|
+
if (a[0] == this.__expandItem__) {
|
|
247
|
+
return 0;
|
|
248
|
+
} else {
|
|
249
|
+
return 1;
|
|
250
|
+
}
|
|
251
|
+
} else {
|
|
252
|
+
return 0;
|
|
253
|
+
}
|
|
254
|
+
} else return 0;
|
|
255
|
+
});
|
|
248
256
|
}
|
|
249
257
|
return event;
|
|
250
258
|
},
|
|
251
|
-
cascadeExpandChange: function() {
|
|
259
|
+
cascadeExpandChange: function (event) {
|
|
260
|
+
//work around as the expand item may change on modifying the cascade props
|
|
261
|
+
this.__expandItem__ = event;
|
|
252
262
|
this.makeCascadeLabelsClickable();
|
|
253
263
|
},
|
|
254
|
-
numberShownChanged: function(event) {
|
|
264
|
+
numberShownChanged: function (event) {
|
|
255
265
|
this.$emit("numberPerPage", parseInt(event));
|
|
256
266
|
},
|
|
257
|
-
|
|
258
|
-
return new Promise(resolve => {
|
|
259
|
-
fetch(apiLocation + endpoint + term)
|
|
260
|
-
.then(response => response.json())
|
|
261
|
-
.then(data => {
|
|
262
|
-
resolve(data);
|
|
263
|
-
});
|
|
264
|
-
});
|
|
265
|
-
},
|
|
266
|
-
updatePreviousShowAllChecked: function(options) {
|
|
267
|
+
updatePreviousShowAllChecked: function (options) {
|
|
267
268
|
//Reset the states
|
|
268
269
|
for (const facet in this.previousShowAllChecked) {
|
|
269
270
|
this.previousShowAllChecked[facet] = false;
|
|
270
271
|
}
|
|
271
|
-
options.forEach(element => {
|
|
272
|
+
options.forEach((element) => {
|
|
272
273
|
if (element[1].toLowerCase().includes("show all"))
|
|
273
274
|
this.previousShowAllChecked[element[0]] = true;
|
|
274
275
|
});
|
|
275
276
|
},
|
|
276
|
-
setCascader:
|
|
277
|
+
// setCascader: Clears previous selections and takes in an array of facets to select: filterFacets
|
|
278
|
+
// facets are in the form:
|
|
279
|
+
// {
|
|
280
|
+
// facetPropPath: 'anatomy.organ.name',
|
|
281
|
+
// term: 'Sex',
|
|
282
|
+
// facet: 'Male'
|
|
283
|
+
// }
|
|
284
|
+
setCascader: function (filterFacets) {
|
|
277
285
|
//Do not set the value unless it is ready
|
|
278
|
-
if (this.cascaderIsReady) {
|
|
279
|
-
this.cascadeSelected =
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
e.term.
|
|
283
|
-
|
|
284
|
-
e.term.toLowerCase(),
|
|
285
|
-
e.facet.toLowerCase()
|
|
286
|
-
)
|
|
287
|
-
]);
|
|
286
|
+
if (this.cascaderIsReady && filterFacets && filterFacets.length != 0) {
|
|
287
|
+
this.cascadeSelected = filterFacets.map(e => {
|
|
288
|
+
return [
|
|
289
|
+
e.facetPropPath,
|
|
290
|
+
this.createCascaderItemValue(capitalise(e.term), e.facet),
|
|
291
|
+
]
|
|
288
292
|
});
|
|
289
293
|
this.updatePreviousShowAllChecked(this.cascadeSelected);
|
|
290
294
|
}
|
|
291
295
|
},
|
|
292
|
-
|
|
296
|
+
addFilter: function (filter) {
|
|
297
|
+
//Do not set the value unless it is ready
|
|
298
|
+
if (this.cascaderIsReady && filter) {
|
|
299
|
+
this.cascadeSelected.filter(f=>f.term != filter.term)
|
|
300
|
+
this.cascadeSelected.push([filter.facetPropPath, this.createCascaderItemValue(filter.term, filter.facet)])
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
initiateSearch: function() {
|
|
304
|
+
this.cascadeEvent(this.cascadeSelected)
|
|
305
|
+
},
|
|
306
|
+
// checkShowAllBoxes: Checks each 'Show all' cascade option by using the setCascader function
|
|
307
|
+
checkShowAllBoxes: function(){
|
|
308
|
+
this.setCascader(
|
|
309
|
+
this.options.map(option => {
|
|
310
|
+
return {
|
|
311
|
+
facetPropPath: option.value,
|
|
312
|
+
term: option.label,
|
|
313
|
+
facet: 'Show all'
|
|
314
|
+
}
|
|
315
|
+
})
|
|
316
|
+
)
|
|
317
|
+
},
|
|
318
|
+
makeCascadeLabelsClickable: function () {
|
|
293
319
|
// Next tick allows the cascader menu to change
|
|
294
320
|
this.$nextTick(() => {
|
|
295
321
|
this.$refs.cascader.$el
|
|
296
322
|
.querySelectorAll(".el-cascader-node__label")
|
|
297
|
-
.forEach(el => {
|
|
323
|
+
.forEach((el) => {
|
|
298
324
|
// step through each cascade label
|
|
299
|
-
el.onclick = function() {
|
|
325
|
+
el.onclick = function () {
|
|
300
326
|
const checkbox = this.previousElementSibling;
|
|
301
327
|
if (checkbox) {
|
|
302
328
|
if (!checkbox.parentElement.attributes["aria-owns"]) {
|
|
@@ -307,19 +333,18 @@ export default {
|
|
|
307
333
|
};
|
|
308
334
|
});
|
|
309
335
|
});
|
|
310
|
-
}
|
|
311
|
-
},
|
|
312
|
-
created: function() {
|
|
313
|
-
//Create non-reactive local variables
|
|
314
|
-
this.facetEndpoint = "get-facets/";
|
|
336
|
+
},
|
|
315
337
|
},
|
|
316
|
-
mounted: function() {
|
|
338
|
+
mounted: function () {
|
|
339
|
+
this.algoliaClient = new AlgoliaClient(this.envVars.ALGOLIA_ID, this.envVars.ALGOLIA_KEY, this.envVars.PENNSIEVE_API_LOCATION);
|
|
340
|
+
this.algoliaClient.initIndex(this.envVars.ALGOLIA_INDEX);
|
|
317
341
|
this.populateCascader().then(() => {
|
|
318
342
|
this.cascaderIsReady = true;
|
|
343
|
+
this.checkShowAllBoxes()
|
|
319
344
|
this.setCascader(this.entry.filterFacets);
|
|
320
345
|
this.makeCascadeLabelsClickable();
|
|
321
346
|
});
|
|
322
|
-
}
|
|
347
|
+
},
|
|
323
348
|
};
|
|
324
349
|
</script>
|
|
325
350
|
|
|
@@ -355,6 +380,10 @@ export default {
|
|
|
355
380
|
padding-bottom: 6px;
|
|
356
381
|
}
|
|
357
382
|
|
|
383
|
+
.cascader >>> .el-cascder-panel {
|
|
384
|
+
max-height: 500px;
|
|
385
|
+
}
|
|
386
|
+
|
|
358
387
|
.cascader >>> .el-scrollbar__wrap {
|
|
359
388
|
overflow-x: hidden;
|
|
360
389
|
margin-bottom: 2px !important;
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
<template v-for="tab in tabs">
|
|
25
25
|
<sidebar-content class="sidebar-content-container"
|
|
26
26
|
v-show="tab.id===activeId" :contextCardEntry="tab.contextCard"
|
|
27
|
-
:
|
|
27
|
+
:envVars="envVars"
|
|
28
28
|
v-bind:key="tab.id" :ref="tab.id"
|
|
29
29
|
@search-changed="searchChanged(tab.id, $event)"/>
|
|
30
30
|
</template>
|
|
@@ -81,9 +81,9 @@ export default {
|
|
|
81
81
|
type: Object,
|
|
82
82
|
default: () => (initial_state)
|
|
83
83
|
},
|
|
84
|
-
|
|
85
|
-
type:
|
|
86
|
-
default:
|
|
84
|
+
envVars: {
|
|
85
|
+
type: Object,
|
|
86
|
+
default: () => {}
|
|
87
87
|
},
|
|
88
88
|
tabs: {
|
|
89
89
|
type: Array,
|
|
@@ -113,10 +113,15 @@ export default {
|
|
|
113
113
|
toggleDrawer: function () {
|
|
114
114
|
this.drawerOpen = !this.drawerOpen;
|
|
115
115
|
},
|
|
116
|
-
openSearch: function(
|
|
116
|
+
openSearch: function(facets, query){
|
|
117
|
+
this.drawerOpen = true;
|
|
118
|
+
// Because refs are in v-for, nextTick is needed here
|
|
119
|
+
Vue.nextTick(()=>{this.$refs[this.activeId][0].openSearch(facets, query)})
|
|
120
|
+
},
|
|
121
|
+
addFilter: function(filter){
|
|
117
122
|
this.drawerOpen = true;
|
|
118
123
|
// Because refs are in v-for, nextTick is needed here
|
|
119
|
-
Vue.nextTick(()=>{this.$refs[this.activeId][0].
|
|
124
|
+
Vue.nextTick(()=>{this.$refs[this.activeId][0].addFilter(filter)})
|
|
120
125
|
},
|
|
121
126
|
openNeuronSearch: function(neuron){
|
|
122
127
|
this.drawerOpen = true;
|