@abi-software/map-side-bar 2.3.1 → 2.4.0-alpha-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/.eslintrc.js +12 -12
- package/.postcssrc.json +5 -5
- package/LICENSE +201 -201
- package/README.md +168 -168
- package/cypress.config.js +23 -23
- package/dist/data/pmr-sample.json +3181 -0
- package/dist/map-side-bar.js +15142 -9024
- package/dist/map-side-bar.umd.cjs +50 -103
- package/dist/style.css +1 -1
- package/package.json +77 -77
- package/public/data/pmr-sample.json +3181 -0
- package/reporter-config.json +9 -9
- package/src/App.vue +266 -265
- package/src/algolia/algolia.js +255 -242
- package/src/algolia/utils.js +100 -100
- package/src/assets/_variables.scss +43 -43
- package/src/assets/styles.scss +6 -6
- package/src/components/BadgesGroup.vue +124 -124
- package/src/components/ConnectivityInfo.vue +619 -619
- package/src/components/DatasetCard.vue +367 -357
- package/src/components/EventBus.js +3 -3
- package/src/components/ExternalResourceCard.vue +113 -113
- package/src/components/FlatmapDatasetCard.vue +171 -0
- package/src/components/ImageGallery.vue +542 -542
- package/src/components/PMRDatasetCard.vue +237 -0
- package/src/components/SearchFilters.vue +1023 -1006
- package/src/components/SearchHistory.vue +175 -175
- package/src/components/SideBar.vue +436 -436
- package/src/components/SidebarContent.vue +730 -603
- package/src/components/Tabs.vue +145 -145
- package/src/components/allPaths.js +5928 -0
- package/src/components/index.js +8 -8
- package/src/components/pmrTest.js +4 -0
- package/src/components/species-map.js +8 -8
- package/src/components.d.ts +2 -0
- package/src/exampleConnectivityInput.js +291 -291
- package/src/flatmapQueries/flatmapQueries.js +169 -0
- package/src/main.js +9 -9
- package/src/mixins/S3Bucket.vue +37 -37
- package/src/mixins/mixedPageCalculation.vue +78 -0
- package/static.json +6 -6
- package/vite.config.js +55 -55
- package/vuese-generator.js +65 -65
|
@@ -1,436 +1,436 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div ref="container">
|
|
3
|
-
<div v-if="!drawerOpen" @click="toggleDrawer" class="open-tab">
|
|
4
|
-
<el-icon><el-icon-arrow-left /></el-icon>
|
|
5
|
-
</div>
|
|
6
|
-
<el-drawer
|
|
7
|
-
class="side-bar my-drawer"
|
|
8
|
-
v-model="drawerOpen"
|
|
9
|
-
:teleported="false"
|
|
10
|
-
:modal-append-to-body="false"
|
|
11
|
-
size="584"
|
|
12
|
-
:with-header="false"
|
|
13
|
-
:wrapperClosable="false"
|
|
14
|
-
:modal="false"
|
|
15
|
-
modal-class="sidebar-body"
|
|
16
|
-
:z-index="10"
|
|
17
|
-
:lock-scroll="false"
|
|
18
|
-
>
|
|
19
|
-
<div class="box-card">
|
|
20
|
-
<div v-if="drawerOpen" @click="close" class="close-tab">
|
|
21
|
-
<el-icon><el-icon-arrow-right /></el-icon>
|
|
22
|
-
</div>
|
|
23
|
-
<div class="sidebar-container">
|
|
24
|
-
<Tabs
|
|
25
|
-
v-if="tabs.length > 1 && connectivityInfo"
|
|
26
|
-
:tabTitles="tabs"
|
|
27
|
-
:activeId="activeTabId"
|
|
28
|
-
@titleClicked="tabClicked"
|
|
29
|
-
@tab-close="tabClose"
|
|
30
|
-
/>
|
|
31
|
-
<template v-for="tab in tabs" key="tab.id">
|
|
32
|
-
<!-- Connectivity Info -->
|
|
33
|
-
<template v-if="tab.type === 'connectivity'">
|
|
34
|
-
<connectivity-info
|
|
35
|
-
:entry="connectivityInfo"
|
|
36
|
-
:availableAnatomyFacets="availableAnatomyFacets"
|
|
37
|
-
v-show="tab.id === activeTabId"
|
|
38
|
-
:ref="'connectivityTab_' + tab.id"
|
|
39
|
-
@show-connectivity="showConnectivity"
|
|
40
|
-
/>
|
|
41
|
-
</template>
|
|
42
|
-
<template v-else>
|
|
43
|
-
<SidebarContent
|
|
44
|
-
class="sidebar-content-container"
|
|
45
|
-
v-show="tab.id === activeTabId"
|
|
46
|
-
:contextCardEntry="tab.contextCard"
|
|
47
|
-
:envVars="envVars"
|
|
48
|
-
:ref="'searchTab_' + tab.id"
|
|
49
|
-
@search-changed="searchChanged(tab.id, $event)"
|
|
50
|
-
@hover-changed="hoverChanged($event)"
|
|
51
|
-
/>
|
|
52
|
-
</template>
|
|
53
|
-
</template>
|
|
54
|
-
</div>
|
|
55
|
-
</div>
|
|
56
|
-
</el-drawer>
|
|
57
|
-
</div>
|
|
58
|
-
</template>
|
|
59
|
-
|
|
60
|
-
<script>
|
|
61
|
-
import {
|
|
62
|
-
ArrowLeft as ElIconArrowLeft,
|
|
63
|
-
ArrowRight as ElIconArrowRight,
|
|
64
|
-
} from '@element-plus/icons-vue'
|
|
65
|
-
/* eslint-disable no-alert, no-console */
|
|
66
|
-
import { ElDrawer as Drawer, ElIcon as Icon } from 'element-plus'
|
|
67
|
-
import SidebarContent from './SidebarContent.vue'
|
|
68
|
-
import EventBus from './EventBus.js'
|
|
69
|
-
import Tabs from './Tabs.vue'
|
|
70
|
-
import ConnectivityInfo from './ConnectivityInfo.vue'
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Aims to provide a sidebar for searching capability for SPARC portal.
|
|
74
|
-
*/
|
|
75
|
-
export default {
|
|
76
|
-
components: {
|
|
77
|
-
SidebarContent,
|
|
78
|
-
Tabs,
|
|
79
|
-
ElIconArrowLeft,
|
|
80
|
-
ElIconArrowRight,
|
|
81
|
-
Drawer,
|
|
82
|
-
Icon,
|
|
83
|
-
ConnectivityInfo,
|
|
84
|
-
},
|
|
85
|
-
name: 'SideBar',
|
|
86
|
-
props: {
|
|
87
|
-
/**
|
|
88
|
-
* The option to show side bar.
|
|
89
|
-
*/
|
|
90
|
-
visible: {
|
|
91
|
-
type: Boolean,
|
|
92
|
-
default: false,
|
|
93
|
-
},
|
|
94
|
-
/**
|
|
95
|
-
* The environment variables object with
|
|
96
|
-
* `API_LOCATION`, `ALGOLIA_KEY`, `ALGOLIA_ID`,
|
|
97
|
-
* `ALGOLIA_INDEX`, `PENNSIEVE_API_LOCATION`, `BL_SERVER_URL`,
|
|
98
|
-
* `NL_LINK_PREFIX`, `ROOT_URL`
|
|
99
|
-
*/
|
|
100
|
-
envVars: {
|
|
101
|
-
type: Object,
|
|
102
|
-
default: () => {},
|
|
103
|
-
},
|
|
104
|
-
/**
|
|
105
|
-
* The array of objects to show multiple sidebar contents.
|
|
106
|
-
*/
|
|
107
|
-
tabs: {
|
|
108
|
-
type: Array,
|
|
109
|
-
default: () => [
|
|
110
|
-
{ id: 1, title: 'Search', type: 'search' },
|
|
111
|
-
{ id: 2, title: 'Connectivity', type: 'connectivity' }
|
|
112
|
-
],
|
|
113
|
-
},
|
|
114
|
-
/**
|
|
115
|
-
* The active tab id for default tab.
|
|
116
|
-
*/
|
|
117
|
-
activeTabId: {
|
|
118
|
-
type: Number,
|
|
119
|
-
default: 1,
|
|
120
|
-
},
|
|
121
|
-
/**
|
|
122
|
-
* The option to show or hide sidebar on page load.
|
|
123
|
-
*/
|
|
124
|
-
openAtStart: {
|
|
125
|
-
type: Boolean,
|
|
126
|
-
default: false,
|
|
127
|
-
},
|
|
128
|
-
/**
|
|
129
|
-
* The connectivity info data to show in sidebar.
|
|
130
|
-
*/
|
|
131
|
-
connectivityInfo: {
|
|
132
|
-
type: Object,
|
|
133
|
-
default: null,
|
|
134
|
-
},
|
|
135
|
-
},
|
|
136
|
-
data: function () {
|
|
137
|
-
return {
|
|
138
|
-
drawerOpen: false,
|
|
139
|
-
availableAnatomyFacets: []
|
|
140
|
-
}
|
|
141
|
-
},
|
|
142
|
-
methods: {
|
|
143
|
-
/**
|
|
144
|
-
* This event is emitted when the mouse hover are changed.
|
|
145
|
-
* @arg data
|
|
146
|
-
*/
|
|
147
|
-
hoverChanged: function (data) {
|
|
148
|
-
this.$emit('hover-changed', data)
|
|
149
|
-
},
|
|
150
|
-
/**
|
|
151
|
-
* This event is emitted when the show connectivity button is clicked.
|
|
152
|
-
* @arg featureIds
|
|
153
|
-
*/
|
|
154
|
-
showConnectivity: function (featureIds) {
|
|
155
|
-
this.$emit('show-connectivity', featureIds);
|
|
156
|
-
},
|
|
157
|
-
/**
|
|
158
|
-
* This event is emitted when the search filters are changed.
|
|
159
|
-
* @arg `obj` {data, id}
|
|
160
|
-
*/
|
|
161
|
-
searchChanged: function (id, data) {
|
|
162
|
-
this.$emit('search-changed', { ...data, id: id })
|
|
163
|
-
},
|
|
164
|
-
/**
|
|
165
|
-
* @vuese
|
|
166
|
-
* The function to close sidebar.
|
|
167
|
-
*/
|
|
168
|
-
close: function () {
|
|
169
|
-
this.drawerOpen = false
|
|
170
|
-
},
|
|
171
|
-
/**
|
|
172
|
-
* @vuese
|
|
173
|
-
* The function to toggle (open and close) sidebar.
|
|
174
|
-
*/
|
|
175
|
-
toggleDrawer: function () {
|
|
176
|
-
this.drawerOpen = !this.drawerOpen
|
|
177
|
-
},
|
|
178
|
-
openSearch: function (facets, query) {
|
|
179
|
-
this.drawerOpen = true
|
|
180
|
-
// Because refs are in v-for, nextTick is needed here
|
|
181
|
-
this.$nextTick(() => {
|
|
182
|
-
const searchTabRef = this.getSearchTabRefById(1);
|
|
183
|
-
searchTabRef.openSearch(facets, query);
|
|
184
|
-
})
|
|
185
|
-
},
|
|
186
|
-
/**
|
|
187
|
-
* Get the tab object by tab id and type.
|
|
188
|
-
* If not found, return the first available tab.
|
|
189
|
-
*/
|
|
190
|
-
getTabByIdAndType: function (id, type) {
|
|
191
|
-
const tabId = id || this.activeTabId;
|
|
192
|
-
const tabType = type || 'search'; // default to search tab
|
|
193
|
-
const tabObj = this.tabs.find((tab) => tab.id === tabId && tab.type === tabType);
|
|
194
|
-
const firstAvailableTab = this.tabs[0];
|
|
195
|
-
return tabObj || firstAvailableTab;
|
|
196
|
-
},
|
|
197
|
-
/**
|
|
198
|
-
* Get the ref id of the tab by id and type.
|
|
199
|
-
*/
|
|
200
|
-
getTabRefId: function (id, type) {
|
|
201
|
-
let refIdPrefix = 'searchTab_'; // default to search tab
|
|
202
|
-
if (type === 'connectivity') {
|
|
203
|
-
refIdPrefix = 'connectivityTab_';
|
|
204
|
-
}
|
|
205
|
-
const tabObj = this.getTabByIdAndType(id, type);
|
|
206
|
-
const tabRefId = refIdPrefix + tabObj.id;
|
|
207
|
-
return tabRefId;
|
|
208
|
-
},
|
|
209
|
-
getSearchTabRefById: function (id) {
|
|
210
|
-
const searchTabId = id || 1; // to use id when there are multiple search tabs
|
|
211
|
-
const searchTabRefId = this.getTabRefId(searchTabId, 'search');
|
|
212
|
-
return this.$refs[searchTabRefId][0];
|
|
213
|
-
},
|
|
214
|
-
/**
|
|
215
|
-
* @vuese
|
|
216
|
-
* The function to add filters to sidebar search.
|
|
217
|
-
* @arg filter `object`
|
|
218
|
-
*/
|
|
219
|
-
addFilter: function (filter) {
|
|
220
|
-
this.drawerOpen = true
|
|
221
|
-
filter.AND = true // When we add a filter external, it is currently only with an AND boolean
|
|
222
|
-
|
|
223
|
-
// Because refs are in v-for, nextTick is needed here
|
|
224
|
-
this.$nextTick(() => {
|
|
225
|
-
const searchTabRef = this.getSearchTabRefById(1);
|
|
226
|
-
searchTabRef.addFilter(filter)
|
|
227
|
-
})
|
|
228
|
-
},
|
|
229
|
-
openNeuronSearch: function (neuron) {
|
|
230
|
-
this.drawerOpen = true
|
|
231
|
-
// Because refs are in v-for, nextTick is needed here
|
|
232
|
-
this.$nextTick(() => {
|
|
233
|
-
const searchTabRef = this.getSearchTabRefById(1);
|
|
234
|
-
searchTabRef.openSearch(
|
|
235
|
-
'',
|
|
236
|
-
undefined,
|
|
237
|
-
'scicrunch-query-string/',
|
|
238
|
-
{ field: '*organ.curie', curie: neuron }
|
|
239
|
-
)
|
|
240
|
-
})
|
|
241
|
-
},
|
|
242
|
-
getAlgoliaFacets: async function () {
|
|
243
|
-
const searchTabRef = this.getSearchTabRefById(1);
|
|
244
|
-
return await searchTabRef.getAlgoliaFacets()
|
|
245
|
-
},
|
|
246
|
-
setDrawerOpen: function (value = true) {
|
|
247
|
-
this.drawerOpen = value
|
|
248
|
-
},
|
|
249
|
-
/**
|
|
250
|
-
* @vuese
|
|
251
|
-
* The function to emit 'tabClicked' event with tab's `id` and tab's `type`
|
|
252
|
-
* when user clicks the sidebar tab.
|
|
253
|
-
* @arg {id, type}
|
|
254
|
-
*/
|
|
255
|
-
tabClicked: function ({id, type}) {
|
|
256
|
-
/**
|
|
257
|
-
* This event is emitted when user click sidebar's tab.
|
|
258
|
-
* @arg {id, type}
|
|
259
|
-
*/
|
|
260
|
-
this.$emit('tabClicked', {id, type});
|
|
261
|
-
},
|
|
262
|
-
tabClose: function (id) {
|
|
263
|
-
this.$emit('connectivity-info-close');
|
|
264
|
-
},
|
|
265
|
-
},
|
|
266
|
-
created: function () {
|
|
267
|
-
this.drawerOpen = this.openAtStart
|
|
268
|
-
},
|
|
269
|
-
mounted: function () {
|
|
270
|
-
EventBus.on('PopoverActionClick', (payLoad) => {
|
|
271
|
-
/**
|
|
272
|
-
* This event is emitted when the image is clicked on or the button below the image is clicked on.
|
|
273
|
-
* @arg payLoad
|
|
274
|
-
*/
|
|
275
|
-
this.$emit('actionClick', payLoad)
|
|
276
|
-
})
|
|
277
|
-
EventBus.on('number-of-datasets-for-anatomies', (payLoad) => {
|
|
278
|
-
/**
|
|
279
|
-
* This emits a object with keys as anatomy and values as number of datasets for that anatomy.
|
|
280
|
-
* @arg payload
|
|
281
|
-
*/
|
|
282
|
-
this.$emit('number-of-datasets-for-anatomies', payLoad)
|
|
283
|
-
})
|
|
284
|
-
EventBus.on('anatomy-in-datasets', (payLoad) => {
|
|
285
|
-
/**
|
|
286
|
-
* This emits a lis of datasets, with the anatomy for each one. Used by flatmap for markers
|
|
287
|
-
* @arg payload
|
|
288
|
-
*/
|
|
289
|
-
this.$emit('anatomy-in-datasets', payLoad)
|
|
290
|
-
})
|
|
291
|
-
|
|
292
|
-
EventBus.on('contextUpdate', (payLoad) => {
|
|
293
|
-
/**
|
|
294
|
-
* This event is emitted when the context card is updated.
|
|
295
|
-
* Example, context card update on first load.
|
|
296
|
-
* @arg payload
|
|
297
|
-
*/
|
|
298
|
-
this.$emit('contextUpdate', payLoad)
|
|
299
|
-
})
|
|
300
|
-
EventBus.on('datalink-clicked', (payLoad) => {
|
|
301
|
-
/**
|
|
302
|
-
* This event is emitted
|
|
303
|
-
* when the dataset button or dataset image thumbnail
|
|
304
|
-
* from the gallery component is clicked.
|
|
305
|
-
* @arg payload
|
|
306
|
-
*/
|
|
307
|
-
this.$emit('datalink-clicked', payLoad);
|
|
308
|
-
})
|
|
309
|
-
EventBus.on('onConnectivityActionClick', (payLoad) => {
|
|
310
|
-
// switch to search tab with tab id: 1
|
|
311
|
-
this.tabClicked({id: 1, type: 'search'});
|
|
312
|
-
this.$emit('actionClick', payLoad);
|
|
313
|
-
})
|
|
314
|
-
|
|
315
|
-
// Get available anatomy facets for the connectivity info
|
|
316
|
-
EventBus.on('available-facets', (payLoad) => {
|
|
317
|
-
this.availableAnatomyFacets = payLoad.find((facet) => facet.label === 'Anatomical Structure').children
|
|
318
|
-
})
|
|
319
|
-
|
|
320
|
-
},
|
|
321
|
-
}
|
|
322
|
-
</script>
|
|
323
|
-
|
|
324
|
-
<style lang="scss" scoped>
|
|
325
|
-
.box-card {
|
|
326
|
-
flex: 3;
|
|
327
|
-
height: 100%;
|
|
328
|
-
overflow: hidden;
|
|
329
|
-
pointer-events: auto;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
.side-bar {
|
|
333
|
-
position: relative;
|
|
334
|
-
height: 100%;
|
|
335
|
-
pointer-events: none;
|
|
336
|
-
width:600px;
|
|
337
|
-
float: right;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
:deep(.sidebar-body) {
|
|
341
|
-
position: absolute !important;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
.side-bar :deep(.el-drawer:focus) {
|
|
345
|
-
outline: none;
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
.sidebar-container {
|
|
349
|
-
height: 100%;
|
|
350
|
-
flex-flow: column;
|
|
351
|
-
display: flex;
|
|
352
|
-
background-color: white;
|
|
353
|
-
box-shadow: var(--el-box-shadow-light);
|
|
354
|
-
border-radius: var(--el-card-border-radius);
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
.open-tab {
|
|
358
|
-
width: 20px;
|
|
359
|
-
height: 40px;
|
|
360
|
-
z-index: 8;
|
|
361
|
-
position: absolute;
|
|
362
|
-
top: calc(50vh - 80px);
|
|
363
|
-
right: 0px;
|
|
364
|
-
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.06);
|
|
365
|
-
border: solid 1px $app-primary-color;
|
|
366
|
-
background-color: #f9f2fc;
|
|
367
|
-
text-align: center;
|
|
368
|
-
vertical-align: middle;
|
|
369
|
-
cursor: pointer;
|
|
370
|
-
pointer-events: auto;
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
.el-icon svg {
|
|
374
|
-
font-weight: 600;
|
|
375
|
-
margin-top: 24px;
|
|
376
|
-
color: $app-primary-color;
|
|
377
|
-
cursor: pointer;
|
|
378
|
-
pointer-events: auto;
|
|
379
|
-
transform: scaleY(2);
|
|
380
|
-
text-align: center;
|
|
381
|
-
vertical-align: middle;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
.close-tab {
|
|
385
|
-
float: left;
|
|
386
|
-
flex: 1;
|
|
387
|
-
width: 20px;
|
|
388
|
-
height: 40px;
|
|
389
|
-
z-index: 8;
|
|
390
|
-
margin-top: calc(50vh - 80px);
|
|
391
|
-
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.06);
|
|
392
|
-
border: solid 1px $app-primary-color;
|
|
393
|
-
background-color: #f9f2fc;
|
|
394
|
-
text-align: center;
|
|
395
|
-
vertical-align: middle;
|
|
396
|
-
cursor: pointer;
|
|
397
|
-
pointer-events: auto;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
:deep(.my-drawer) {
|
|
401
|
-
background: rgba(0, 0, 0, 0);
|
|
402
|
-
box-shadow: none;
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
:deep(.my-drawer .el-drawer__body) {
|
|
406
|
-
height: 100%;
|
|
407
|
-
padding: 0;
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
.sidebar-content-container {
|
|
411
|
-
flex: 1 1 auto;
|
|
412
|
-
|
|
413
|
-
.tab-container ~ & {
|
|
414
|
-
border-radius: 0;
|
|
415
|
-
border: 0 none;
|
|
416
|
-
position: relative;
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
</style>
|
|
420
|
-
|
|
421
|
-
<style lang="scss">
|
|
422
|
-
.side-bar {
|
|
423
|
-
--el-color-primary: #8300BF;
|
|
424
|
-
--el-color-primary-light-7: #DAB3EC;
|
|
425
|
-
--el-color-primary-light-8: #e6ccf2;
|
|
426
|
-
--el-color-primary-light-9: #f3e6f9;
|
|
427
|
-
--el-color-primary-light-3: #f3e6f9;
|
|
428
|
-
--el-color-primary-dark-2: #7600AC;
|
|
429
|
-
}
|
|
430
|
-
.el-button--primary {
|
|
431
|
-
--el-button-hover-text-color: var(--el-color-primary);
|
|
432
|
-
--el-button-hover-link-text-color: var(--el-color-primary-light-5);
|
|
433
|
-
--el-button-hover-bg-color: var(--el-color-primary-light-3);
|
|
434
|
-
--el-button-hover-border-color: var(--el-color-primary-light-3);
|
|
435
|
-
}
|
|
436
|
-
</style>
|
|
1
|
+
<template>
|
|
2
|
+
<div ref="container">
|
|
3
|
+
<div v-if="!drawerOpen" @click="toggleDrawer" class="open-tab">
|
|
4
|
+
<el-icon><el-icon-arrow-left /></el-icon>
|
|
5
|
+
</div>
|
|
6
|
+
<el-drawer
|
|
7
|
+
class="side-bar my-drawer"
|
|
8
|
+
v-model="drawerOpen"
|
|
9
|
+
:teleported="false"
|
|
10
|
+
:modal-append-to-body="false"
|
|
11
|
+
size="584"
|
|
12
|
+
:with-header="false"
|
|
13
|
+
:wrapperClosable="false"
|
|
14
|
+
:modal="false"
|
|
15
|
+
modal-class="sidebar-body"
|
|
16
|
+
:z-index="10"
|
|
17
|
+
:lock-scroll="false"
|
|
18
|
+
>
|
|
19
|
+
<div class="box-card">
|
|
20
|
+
<div v-if="drawerOpen" @click="close" class="close-tab">
|
|
21
|
+
<el-icon><el-icon-arrow-right /></el-icon>
|
|
22
|
+
</div>
|
|
23
|
+
<div class="sidebar-container">
|
|
24
|
+
<Tabs
|
|
25
|
+
v-if="tabs.length > 1 && connectivityInfo"
|
|
26
|
+
:tabTitles="tabs"
|
|
27
|
+
:activeId="activeTabId"
|
|
28
|
+
@titleClicked="tabClicked"
|
|
29
|
+
@tab-close="tabClose"
|
|
30
|
+
/>
|
|
31
|
+
<template v-for="tab in tabs" key="tab.id">
|
|
32
|
+
<!-- Connectivity Info -->
|
|
33
|
+
<template v-if="tab.type === 'connectivity'">
|
|
34
|
+
<connectivity-info
|
|
35
|
+
:entry="connectivityInfo"
|
|
36
|
+
:availableAnatomyFacets="availableAnatomyFacets"
|
|
37
|
+
v-show="tab.id === activeTabId"
|
|
38
|
+
:ref="'connectivityTab_' + tab.id"
|
|
39
|
+
@show-connectivity="showConnectivity"
|
|
40
|
+
/>
|
|
41
|
+
</template>
|
|
42
|
+
<template v-else>
|
|
43
|
+
<SidebarContent
|
|
44
|
+
class="sidebar-content-container"
|
|
45
|
+
v-show="tab.id === activeTabId"
|
|
46
|
+
:contextCardEntry="tab.contextCard"
|
|
47
|
+
:envVars="envVars"
|
|
48
|
+
:ref="'searchTab_' + tab.id"
|
|
49
|
+
@search-changed="searchChanged(tab.id, $event)"
|
|
50
|
+
@hover-changed="hoverChanged($event)"
|
|
51
|
+
/>
|
|
52
|
+
</template>
|
|
53
|
+
</template>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
</el-drawer>
|
|
57
|
+
</div>
|
|
58
|
+
</template>
|
|
59
|
+
|
|
60
|
+
<script>
|
|
61
|
+
import {
|
|
62
|
+
ArrowLeft as ElIconArrowLeft,
|
|
63
|
+
ArrowRight as ElIconArrowRight,
|
|
64
|
+
} from '@element-plus/icons-vue'
|
|
65
|
+
/* eslint-disable no-alert, no-console */
|
|
66
|
+
import { ElDrawer as Drawer, ElIcon as Icon } from 'element-plus'
|
|
67
|
+
import SidebarContent from './SidebarContent.vue'
|
|
68
|
+
import EventBus from './EventBus.js'
|
|
69
|
+
import Tabs from './Tabs.vue'
|
|
70
|
+
import ConnectivityInfo from './ConnectivityInfo.vue'
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Aims to provide a sidebar for searching capability for SPARC portal.
|
|
74
|
+
*/
|
|
75
|
+
export default {
|
|
76
|
+
components: {
|
|
77
|
+
SidebarContent,
|
|
78
|
+
Tabs,
|
|
79
|
+
ElIconArrowLeft,
|
|
80
|
+
ElIconArrowRight,
|
|
81
|
+
Drawer,
|
|
82
|
+
Icon,
|
|
83
|
+
ConnectivityInfo,
|
|
84
|
+
},
|
|
85
|
+
name: 'SideBar',
|
|
86
|
+
props: {
|
|
87
|
+
/**
|
|
88
|
+
* The option to show side bar.
|
|
89
|
+
*/
|
|
90
|
+
visible: {
|
|
91
|
+
type: Boolean,
|
|
92
|
+
default: false,
|
|
93
|
+
},
|
|
94
|
+
/**
|
|
95
|
+
* The environment variables object with
|
|
96
|
+
* `API_LOCATION`, `ALGOLIA_KEY`, `ALGOLIA_ID`,
|
|
97
|
+
* `ALGOLIA_INDEX`, `PENNSIEVE_API_LOCATION`, `BL_SERVER_URL`,
|
|
98
|
+
* `NL_LINK_PREFIX`, `ROOT_URL`
|
|
99
|
+
*/
|
|
100
|
+
envVars: {
|
|
101
|
+
type: Object,
|
|
102
|
+
default: () => {},
|
|
103
|
+
},
|
|
104
|
+
/**
|
|
105
|
+
* The array of objects to show multiple sidebar contents.
|
|
106
|
+
*/
|
|
107
|
+
tabs: {
|
|
108
|
+
type: Array,
|
|
109
|
+
default: () => [
|
|
110
|
+
{ id: 1, title: 'Search', type: 'search' },
|
|
111
|
+
{ id: 2, title: 'Connectivity', type: 'connectivity' }
|
|
112
|
+
],
|
|
113
|
+
},
|
|
114
|
+
/**
|
|
115
|
+
* The active tab id for default tab.
|
|
116
|
+
*/
|
|
117
|
+
activeTabId: {
|
|
118
|
+
type: Number,
|
|
119
|
+
default: 1,
|
|
120
|
+
},
|
|
121
|
+
/**
|
|
122
|
+
* The option to show or hide sidebar on page load.
|
|
123
|
+
*/
|
|
124
|
+
openAtStart: {
|
|
125
|
+
type: Boolean,
|
|
126
|
+
default: false,
|
|
127
|
+
},
|
|
128
|
+
/**
|
|
129
|
+
* The connectivity info data to show in sidebar.
|
|
130
|
+
*/
|
|
131
|
+
connectivityInfo: {
|
|
132
|
+
type: Object,
|
|
133
|
+
default: null,
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
data: function () {
|
|
137
|
+
return {
|
|
138
|
+
drawerOpen: false,
|
|
139
|
+
availableAnatomyFacets: []
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
methods: {
|
|
143
|
+
/**
|
|
144
|
+
* This event is emitted when the mouse hover are changed.
|
|
145
|
+
* @arg data
|
|
146
|
+
*/
|
|
147
|
+
hoverChanged: function (data) {
|
|
148
|
+
this.$emit('hover-changed', data)
|
|
149
|
+
},
|
|
150
|
+
/**
|
|
151
|
+
* This event is emitted when the show connectivity button is clicked.
|
|
152
|
+
* @arg featureIds
|
|
153
|
+
*/
|
|
154
|
+
showConnectivity: function (featureIds) {
|
|
155
|
+
this.$emit('show-connectivity', featureIds);
|
|
156
|
+
},
|
|
157
|
+
/**
|
|
158
|
+
* This event is emitted when the search filters are changed.
|
|
159
|
+
* @arg `obj` {data, id}
|
|
160
|
+
*/
|
|
161
|
+
searchChanged: function (id, data) {
|
|
162
|
+
this.$emit('search-changed', { ...data, id: id })
|
|
163
|
+
},
|
|
164
|
+
/**
|
|
165
|
+
* @vuese
|
|
166
|
+
* The function to close sidebar.
|
|
167
|
+
*/
|
|
168
|
+
close: function () {
|
|
169
|
+
this.drawerOpen = false
|
|
170
|
+
},
|
|
171
|
+
/**
|
|
172
|
+
* @vuese
|
|
173
|
+
* The function to toggle (open and close) sidebar.
|
|
174
|
+
*/
|
|
175
|
+
toggleDrawer: function () {
|
|
176
|
+
this.drawerOpen = !this.drawerOpen
|
|
177
|
+
},
|
|
178
|
+
openSearch: function (facets, query) {
|
|
179
|
+
this.drawerOpen = true
|
|
180
|
+
// Because refs are in v-for, nextTick is needed here
|
|
181
|
+
this.$nextTick(() => {
|
|
182
|
+
const searchTabRef = this.getSearchTabRefById(1);
|
|
183
|
+
searchTabRef.openSearch(facets, query);
|
|
184
|
+
})
|
|
185
|
+
},
|
|
186
|
+
/**
|
|
187
|
+
* Get the tab object by tab id and type.
|
|
188
|
+
* If not found, return the first available tab.
|
|
189
|
+
*/
|
|
190
|
+
getTabByIdAndType: function (id, type) {
|
|
191
|
+
const tabId = id || this.activeTabId;
|
|
192
|
+
const tabType = type || 'search'; // default to search tab
|
|
193
|
+
const tabObj = this.tabs.find((tab) => tab.id === tabId && tab.type === tabType);
|
|
194
|
+
const firstAvailableTab = this.tabs[0];
|
|
195
|
+
return tabObj || firstAvailableTab;
|
|
196
|
+
},
|
|
197
|
+
/**
|
|
198
|
+
* Get the ref id of the tab by id and type.
|
|
199
|
+
*/
|
|
200
|
+
getTabRefId: function (id, type) {
|
|
201
|
+
let refIdPrefix = 'searchTab_'; // default to search tab
|
|
202
|
+
if (type === 'connectivity') {
|
|
203
|
+
refIdPrefix = 'connectivityTab_';
|
|
204
|
+
}
|
|
205
|
+
const tabObj = this.getTabByIdAndType(id, type);
|
|
206
|
+
const tabRefId = refIdPrefix + tabObj.id;
|
|
207
|
+
return tabRefId;
|
|
208
|
+
},
|
|
209
|
+
getSearchTabRefById: function (id) {
|
|
210
|
+
const searchTabId = id || 1; // to use id when there are multiple search tabs
|
|
211
|
+
const searchTabRefId = this.getTabRefId(searchTabId, 'search');
|
|
212
|
+
return this.$refs[searchTabRefId][0];
|
|
213
|
+
},
|
|
214
|
+
/**
|
|
215
|
+
* @vuese
|
|
216
|
+
* The function to add filters to sidebar search.
|
|
217
|
+
* @arg filter `object`
|
|
218
|
+
*/
|
|
219
|
+
addFilter: function (filter) {
|
|
220
|
+
this.drawerOpen = true
|
|
221
|
+
filter.AND = true // When we add a filter external, it is currently only with an AND boolean
|
|
222
|
+
|
|
223
|
+
// Because refs are in v-for, nextTick is needed here
|
|
224
|
+
this.$nextTick(() => {
|
|
225
|
+
const searchTabRef = this.getSearchTabRefById(1);
|
|
226
|
+
searchTabRef.addFilter(filter)
|
|
227
|
+
})
|
|
228
|
+
},
|
|
229
|
+
openNeuronSearch: function (neuron) {
|
|
230
|
+
this.drawerOpen = true
|
|
231
|
+
// Because refs are in v-for, nextTick is needed here
|
|
232
|
+
this.$nextTick(() => {
|
|
233
|
+
const searchTabRef = this.getSearchTabRefById(1);
|
|
234
|
+
searchTabRef.openSearch(
|
|
235
|
+
'',
|
|
236
|
+
undefined,
|
|
237
|
+
'scicrunch-query-string/',
|
|
238
|
+
{ field: '*organ.curie', curie: neuron }
|
|
239
|
+
)
|
|
240
|
+
})
|
|
241
|
+
},
|
|
242
|
+
getAlgoliaFacets: async function () {
|
|
243
|
+
const searchTabRef = this.getSearchTabRefById(1);
|
|
244
|
+
return await searchTabRef.getAlgoliaFacets()
|
|
245
|
+
},
|
|
246
|
+
setDrawerOpen: function (value = true) {
|
|
247
|
+
this.drawerOpen = value
|
|
248
|
+
},
|
|
249
|
+
/**
|
|
250
|
+
* @vuese
|
|
251
|
+
* The function to emit 'tabClicked' event with tab's `id` and tab's `type`
|
|
252
|
+
* when user clicks the sidebar tab.
|
|
253
|
+
* @arg {id, type}
|
|
254
|
+
*/
|
|
255
|
+
tabClicked: function ({id, type}) {
|
|
256
|
+
/**
|
|
257
|
+
* This event is emitted when user click sidebar's tab.
|
|
258
|
+
* @arg {id, type}
|
|
259
|
+
*/
|
|
260
|
+
this.$emit('tabClicked', {id, type});
|
|
261
|
+
},
|
|
262
|
+
tabClose: function (id) {
|
|
263
|
+
this.$emit('connectivity-info-close');
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
created: function () {
|
|
267
|
+
this.drawerOpen = this.openAtStart
|
|
268
|
+
},
|
|
269
|
+
mounted: function () {
|
|
270
|
+
EventBus.on('PopoverActionClick', (payLoad) => {
|
|
271
|
+
/**
|
|
272
|
+
* This event is emitted when the image is clicked on or the button below the image is clicked on.
|
|
273
|
+
* @arg payLoad
|
|
274
|
+
*/
|
|
275
|
+
this.$emit('actionClick', payLoad)
|
|
276
|
+
})
|
|
277
|
+
EventBus.on('number-of-datasets-for-anatomies', (payLoad) => {
|
|
278
|
+
/**
|
|
279
|
+
* This emits a object with keys as anatomy and values as number of datasets for that anatomy.
|
|
280
|
+
* @arg payload
|
|
281
|
+
*/
|
|
282
|
+
this.$emit('number-of-datasets-for-anatomies', payLoad)
|
|
283
|
+
})
|
|
284
|
+
EventBus.on('anatomy-in-datasets', (payLoad) => {
|
|
285
|
+
/**
|
|
286
|
+
* This emits a lis of datasets, with the anatomy for each one. Used by flatmap for markers
|
|
287
|
+
* @arg payload
|
|
288
|
+
*/
|
|
289
|
+
this.$emit('anatomy-in-datasets', payLoad)
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
EventBus.on('contextUpdate', (payLoad) => {
|
|
293
|
+
/**
|
|
294
|
+
* This event is emitted when the context card is updated.
|
|
295
|
+
* Example, context card update on first load.
|
|
296
|
+
* @arg payload
|
|
297
|
+
*/
|
|
298
|
+
this.$emit('contextUpdate', payLoad)
|
|
299
|
+
})
|
|
300
|
+
EventBus.on('datalink-clicked', (payLoad) => {
|
|
301
|
+
/**
|
|
302
|
+
* This event is emitted
|
|
303
|
+
* when the dataset button or dataset image thumbnail
|
|
304
|
+
* from the gallery component is clicked.
|
|
305
|
+
* @arg payload
|
|
306
|
+
*/
|
|
307
|
+
this.$emit('datalink-clicked', payLoad);
|
|
308
|
+
})
|
|
309
|
+
EventBus.on('onConnectivityActionClick', (payLoad) => {
|
|
310
|
+
// switch to search tab with tab id: 1
|
|
311
|
+
this.tabClicked({id: 1, type: 'search'});
|
|
312
|
+
this.$emit('actionClick', payLoad);
|
|
313
|
+
})
|
|
314
|
+
|
|
315
|
+
// Get available anatomy facets for the connectivity info
|
|
316
|
+
EventBus.on('available-facets', (payLoad) => {
|
|
317
|
+
this.availableAnatomyFacets = payLoad.find((facet) => facet.label === 'Anatomical Structure').children
|
|
318
|
+
})
|
|
319
|
+
|
|
320
|
+
},
|
|
321
|
+
}
|
|
322
|
+
</script>
|
|
323
|
+
|
|
324
|
+
<style lang="scss" scoped>
|
|
325
|
+
.box-card {
|
|
326
|
+
flex: 3;
|
|
327
|
+
height: 100%;
|
|
328
|
+
overflow: hidden;
|
|
329
|
+
pointer-events: auto;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
.side-bar {
|
|
333
|
+
position: relative;
|
|
334
|
+
height: 100%;
|
|
335
|
+
pointer-events: none;
|
|
336
|
+
width:600px;
|
|
337
|
+
float: right;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
:deep(.sidebar-body) {
|
|
341
|
+
position: absolute !important;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
.side-bar :deep(.el-drawer:focus) {
|
|
345
|
+
outline: none;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
.sidebar-container {
|
|
349
|
+
height: 100%;
|
|
350
|
+
flex-flow: column;
|
|
351
|
+
display: flex;
|
|
352
|
+
background-color: white;
|
|
353
|
+
box-shadow: var(--el-box-shadow-light);
|
|
354
|
+
border-radius: var(--el-card-border-radius);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
.open-tab {
|
|
358
|
+
width: 20px;
|
|
359
|
+
height: 40px;
|
|
360
|
+
z-index: 8;
|
|
361
|
+
position: absolute;
|
|
362
|
+
top: calc(50vh - 80px);
|
|
363
|
+
right: 0px;
|
|
364
|
+
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.06);
|
|
365
|
+
border: solid 1px $app-primary-color;
|
|
366
|
+
background-color: #f9f2fc;
|
|
367
|
+
text-align: center;
|
|
368
|
+
vertical-align: middle;
|
|
369
|
+
cursor: pointer;
|
|
370
|
+
pointer-events: auto;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
.el-icon svg {
|
|
374
|
+
font-weight: 600;
|
|
375
|
+
margin-top: 24px;
|
|
376
|
+
color: $app-primary-color;
|
|
377
|
+
cursor: pointer;
|
|
378
|
+
pointer-events: auto;
|
|
379
|
+
transform: scaleY(2);
|
|
380
|
+
text-align: center;
|
|
381
|
+
vertical-align: middle;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
.close-tab {
|
|
385
|
+
float: left;
|
|
386
|
+
flex: 1;
|
|
387
|
+
width: 20px;
|
|
388
|
+
height: 40px;
|
|
389
|
+
z-index: 8;
|
|
390
|
+
margin-top: calc(50vh - 80px);
|
|
391
|
+
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.06);
|
|
392
|
+
border: solid 1px $app-primary-color;
|
|
393
|
+
background-color: #f9f2fc;
|
|
394
|
+
text-align: center;
|
|
395
|
+
vertical-align: middle;
|
|
396
|
+
cursor: pointer;
|
|
397
|
+
pointer-events: auto;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
:deep(.my-drawer) {
|
|
401
|
+
background: rgba(0, 0, 0, 0);
|
|
402
|
+
box-shadow: none;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
:deep(.my-drawer .el-drawer__body) {
|
|
406
|
+
height: 100%;
|
|
407
|
+
padding: 0;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
.sidebar-content-container {
|
|
411
|
+
flex: 1 1 auto;
|
|
412
|
+
|
|
413
|
+
.tab-container ~ & {
|
|
414
|
+
border-radius: 0;
|
|
415
|
+
border: 0 none;
|
|
416
|
+
position: relative;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
</style>
|
|
420
|
+
|
|
421
|
+
<style lang="scss">
|
|
422
|
+
.side-bar {
|
|
423
|
+
--el-color-primary: #8300BF;
|
|
424
|
+
--el-color-primary-light-7: #DAB3EC;
|
|
425
|
+
--el-color-primary-light-8: #e6ccf2;
|
|
426
|
+
--el-color-primary-light-9: #f3e6f9;
|
|
427
|
+
--el-color-primary-light-3: #f3e6f9;
|
|
428
|
+
--el-color-primary-dark-2: #7600AC;
|
|
429
|
+
}
|
|
430
|
+
.el-button--primary {
|
|
431
|
+
--el-button-hover-text-color: var(--el-color-primary);
|
|
432
|
+
--el-button-hover-link-text-color: var(--el-color-primary-light-5);
|
|
433
|
+
--el-button-hover-bg-color: var(--el-color-primary-light-3);
|
|
434
|
+
--el-button-hover-border-color: var(--el-color-primary-light-3);
|
|
435
|
+
}
|
|
436
|
+
</style>
|