@abi-software/map-side-bar 2.16.0 → 2.17.1-demo.0
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/dist/map-side-bar.js +29210 -26187
- package/dist/map-side-bar.umd.cjs +89 -95
- package/dist/style.css +2 -1
- package/eslint.config.js +23 -0
- package/package.json +44 -33
- package/src/App.vue +12 -8
- package/src/assets/fonts.scss +3 -0
- package/src/assets/pagination.scss +2 -1
- package/src/assets/searchPopover.scss +3 -0
- package/src/assets/styles.scss +2 -3
- package/src/components/CellCard.vue +994 -0
- package/src/components/CellCardExplorer.vue +882 -0
- package/src/components/ConnectivityCard.vue +3 -3
- package/src/components/ConnectivityExplorer.vue +4 -4
- package/src/components/ConnectivityInfo.vue +4 -47
- package/src/components/ContributorItem.vue +2 -2
- package/src/components/DatasetCard.vue +14 -5
- package/src/components/DatasetExplorer.vue +2 -2
- package/src/components/SearchFilters.vue +21 -37
- package/src/components/SearchHistory.vue +3 -15
- package/src/components/SideBar.vue +108 -7
- package/src/components/Tabs.vue +15 -6
- package/src/components/icons/IconOpenExternal.vue +28 -0
- package/src/components/index.js +1 -0
- package/src/components.d.ts +9 -2
- package/src/main.js +1 -0
- package/src/utils/common.js +71 -0
- package/vite.config.js +16 -5
- package/.eslintrc.js +0 -12
- package/static.json +0 -7
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
|
|
29
29
|
<script>
|
|
30
30
|
import EventBus from './EventBus';
|
|
31
|
+
import { capitalise as capitaliseText } from '../utils/common.js';
|
|
31
32
|
|
|
32
33
|
export default {
|
|
33
34
|
name: "ConnectivityCard",
|
|
@@ -78,8 +79,7 @@ export default {
|
|
|
78
79
|
},
|
|
79
80
|
methods: {
|
|
80
81
|
capitalise: function (text) {
|
|
81
|
-
|
|
82
|
-
return "";
|
|
82
|
+
return capitaliseText(text);
|
|
83
83
|
},
|
|
84
84
|
cardClicked: function (data) {
|
|
85
85
|
if (!this.loading) {
|
|
@@ -97,7 +97,7 @@ export default {
|
|
|
97
97
|
</script>
|
|
98
98
|
|
|
99
99
|
<style lang="scss" scoped>
|
|
100
|
-
@
|
|
100
|
+
@use '../assets/connectivity-explorer.scss';
|
|
101
101
|
|
|
102
102
|
.connectivity-card {
|
|
103
103
|
padding-left: 5px;
|
|
@@ -420,7 +420,7 @@ export default {
|
|
|
420
420
|
this.openSearch([], '');
|
|
421
421
|
this.$emit('search-changed', {
|
|
422
422
|
value: [],
|
|
423
|
-
tabType: '
|
|
423
|
+
tabType: 'connectivity',
|
|
424
424
|
type: 'reset-update',
|
|
425
425
|
})
|
|
426
426
|
|
|
@@ -468,7 +468,7 @@ export default {
|
|
|
468
468
|
if (notFoundItems.length) {
|
|
469
469
|
this.$emit('search-changed', {
|
|
470
470
|
value: notFoundItems,
|
|
471
|
-
tabType: '
|
|
471
|
+
tabType: 'connectivity',
|
|
472
472
|
type: 'reset-update',
|
|
473
473
|
})
|
|
474
474
|
}
|
|
@@ -653,8 +653,8 @@ export default {
|
|
|
653
653
|
</script>
|
|
654
654
|
|
|
655
655
|
<style lang="scss" scoped>
|
|
656
|
-
@
|
|
657
|
-
@
|
|
656
|
+
@use '../assets/searchPopover.scss';
|
|
657
|
+
@use '../assets/pagination.scss';
|
|
658
658
|
|
|
659
659
|
.connectivity-card {
|
|
660
660
|
position: relative;
|
|
@@ -355,6 +355,7 @@ import {
|
|
|
355
355
|
ExternalResourceCard,
|
|
356
356
|
} from '@abi-software/map-utilities';
|
|
357
357
|
import '@abi-software/map-utilities/dist/style.css';
|
|
358
|
+
import { capitalise, formatAlertText as formatAlertTextUtil, scrollToRef } from '../utils/common.js'
|
|
358
359
|
|
|
359
360
|
const titleCase = (str) => {
|
|
360
361
|
return str.replace(/\w\S*/g, (t) => {
|
|
@@ -362,11 +363,6 @@ const titleCase = (str) => {
|
|
|
362
363
|
})
|
|
363
364
|
}
|
|
364
365
|
|
|
365
|
-
const capitalise = function (str) {
|
|
366
|
-
if (str) return str.charAt(0).toUpperCase() + str.slice(1)
|
|
367
|
-
return ''
|
|
368
|
-
}
|
|
369
|
-
|
|
370
366
|
export default {
|
|
371
367
|
name: 'ConnectivityInfo',
|
|
372
368
|
components: {
|
|
@@ -1157,49 +1153,10 @@ export default {
|
|
|
1157
1153
|
EventBus.emit('trackEvent', data);
|
|
1158
1154
|
},
|
|
1159
1155
|
showAlertMessage: function () {
|
|
1160
|
-
|
|
1161
|
-
this.$nextTick(() => {
|
|
1162
|
-
const alertElement = this.$refs.alertElement;
|
|
1163
|
-
if (alertElement) {
|
|
1164
|
-
alertElement.scrollIntoView({
|
|
1165
|
-
behavior: 'smooth',
|
|
1166
|
-
block: 'start',
|
|
1167
|
-
inline: 'nearest',
|
|
1168
|
-
});
|
|
1169
|
-
}
|
|
1170
|
-
});
|
|
1156
|
+
scrollToRef(this, 'alertElement');
|
|
1171
1157
|
},
|
|
1172
1158
|
formatAlertText: function (text) {
|
|
1173
|
-
|
|
1174
|
-
const escaped = text
|
|
1175
|
-
.replace(/&/g, '&')
|
|
1176
|
-
.replace(/</g, '<')
|
|
1177
|
-
.replace(/>/g, '>');
|
|
1178
|
-
const linkified = escaped.replace(
|
|
1179
|
-
/(https?:\/\/[^\s"<>\[]+)/g,
|
|
1180
|
-
(url) => {
|
|
1181
|
-
const parts = url.match(/^(.*?)([\].,;:!?]*)$/);
|
|
1182
|
-
const cleanUrl = parts ? parts[1] : url;
|
|
1183
|
-
const suffix = parts ? parts[2] : '';
|
|
1184
|
-
return `<a href="${cleanUrl}" target="_blank" rel="noopener noreferrer">${cleanUrl}</a>${suffix}`;
|
|
1185
|
-
}
|
|
1186
|
-
);
|
|
1187
|
-
|
|
1188
|
-
const normalised = linkified
|
|
1189
|
-
.replace(/\\n/g, '\n')
|
|
1190
|
-
.replace(/\r\n/g, '\n')
|
|
1191
|
-
.replace(/\r/g, '\n');
|
|
1192
|
-
|
|
1193
|
-
return normalised
|
|
1194
|
-
.split('\n')
|
|
1195
|
-
.map((line) => {
|
|
1196
|
-
const withBoldLabel = line.replace(
|
|
1197
|
-
/^\s*([A-Za-z][^:<]{0,120}:)/,
|
|
1198
|
-
'<strong>$1</strong>'
|
|
1199
|
-
);
|
|
1200
|
-
return `<div class="alert-line">${withBoldLabel}</div>`;
|
|
1201
|
-
})
|
|
1202
|
-
.join('\n');
|
|
1159
|
+
return formatAlertTextUtil(text, { formatLines: true });
|
|
1203
1160
|
},
|
|
1204
1161
|
},
|
|
1205
1162
|
mounted: function () {
|
|
@@ -1216,7 +1173,7 @@ export default {
|
|
|
1216
1173
|
</script>
|
|
1217
1174
|
|
|
1218
1175
|
<style lang="scss" scoped>
|
|
1219
|
-
@
|
|
1176
|
+
@use '../assets/connectivity-explorer.scss';
|
|
1220
1177
|
|
|
1221
1178
|
.connectivity-info-title {
|
|
1222
1179
|
padding: 0;
|
|
@@ -57,7 +57,7 @@ export default {
|
|
|
57
57
|
</script>
|
|
58
58
|
|
|
59
59
|
<style lang="scss" scoped>
|
|
60
|
-
@
|
|
60
|
+
@use '../assets/_variables.scss';
|
|
61
61
|
|
|
62
62
|
.contributor-item {
|
|
63
63
|
display: inline;
|
|
@@ -67,7 +67,7 @@ export default {
|
|
|
67
67
|
</style>
|
|
68
68
|
|
|
69
69
|
<style lang="scss">
|
|
70
|
-
@
|
|
70
|
+
@use '../assets/_variables.scss';
|
|
71
71
|
|
|
72
72
|
.contributor-popover.el-popover {
|
|
73
73
|
font-family: $font-family;
|
|
@@ -217,6 +217,7 @@ export default {
|
|
|
217
217
|
},
|
|
218
218
|
createFlatmapItems: function () {
|
|
219
219
|
if (this.entry.flatmaps) {
|
|
220
|
+
const flatmaps = []
|
|
220
221
|
this.entry.flatmaps.forEach((flatmap) => {
|
|
221
222
|
if (flatmap.associated_flatmap?.identifier) {
|
|
222
223
|
const filePath = flatmap.dataset.path
|
|
@@ -245,7 +246,7 @@ export default {
|
|
|
245
246
|
doi: this.entry.doi,
|
|
246
247
|
version: this.version,
|
|
247
248
|
}
|
|
248
|
-
|
|
249
|
+
flatmaps.push({
|
|
249
250
|
id,
|
|
250
251
|
title: baseName(filePath),
|
|
251
252
|
type: 'Flatmap',
|
|
@@ -256,6 +257,7 @@ export default {
|
|
|
256
257
|
})
|
|
257
258
|
}
|
|
258
259
|
})
|
|
260
|
+
this.items['Flatmaps'].push(...flatmaps.sort((a, b) => a.title.localeCompare(b.title)))
|
|
259
261
|
}
|
|
260
262
|
},
|
|
261
263
|
createImageItems: function () {
|
|
@@ -276,6 +278,7 @@ export default {
|
|
|
276
278
|
},
|
|
277
279
|
createPlotItems: function () {
|
|
278
280
|
if (this.entry.plots) {
|
|
281
|
+
const plots = []
|
|
279
282
|
this.entry.plots.forEach((plot) => {
|
|
280
283
|
const filePath = plot.dataset.path
|
|
281
284
|
const id = plot.identifier
|
|
@@ -333,7 +336,7 @@ export default {
|
|
|
333
336
|
discoverId: this.discoverId,
|
|
334
337
|
version: this.version,
|
|
335
338
|
}
|
|
336
|
-
|
|
339
|
+
plots.push({
|
|
337
340
|
id,
|
|
338
341
|
title: baseName(filePath),
|
|
339
342
|
type: 'Plot',
|
|
@@ -343,11 +346,14 @@ export default {
|
|
|
343
346
|
mimetype,
|
|
344
347
|
})
|
|
345
348
|
})
|
|
349
|
+
this.items['Plots'].push(...plots.sort((a, b) => a.title.localeCompare(b.title)))
|
|
350
|
+
|
|
346
351
|
}
|
|
347
352
|
},
|
|
348
353
|
createScaffoldItems: function () {
|
|
349
354
|
if (this.entry.scaffolds) {
|
|
350
355
|
let index = 0
|
|
356
|
+
const scaffolds = []
|
|
351
357
|
this.entry.scaffolds.forEach((scaffold, i) => {
|
|
352
358
|
const filePath = scaffold.dataset.path
|
|
353
359
|
const id = scaffold.identifier
|
|
@@ -381,7 +387,7 @@ export default {
|
|
|
381
387
|
s3uri: this.entry.s3uri,
|
|
382
388
|
contextCardUrl: this.getContextCardUrl(i),
|
|
383
389
|
}
|
|
384
|
-
|
|
390
|
+
scaffolds.push({
|
|
385
391
|
id,
|
|
386
392
|
title: baseName(filePath),
|
|
387
393
|
type: 'Scaffold',
|
|
@@ -391,10 +397,12 @@ export default {
|
|
|
391
397
|
mimetype,
|
|
392
398
|
})
|
|
393
399
|
})
|
|
400
|
+
this.items['Scaffolds'].push(...scaffolds.sort((a, b) => a.title.localeCompare(b.title)))
|
|
394
401
|
}
|
|
395
402
|
},
|
|
396
403
|
createSimulationItems: function () {
|
|
397
404
|
if (this.entry.simulation) {
|
|
405
|
+
const simulations = []
|
|
398
406
|
this.entry.simulation.forEach((simulation) => {
|
|
399
407
|
if (simulation.additional_mimetype.name === "application/x.vnd.abi.simulation+json") {
|
|
400
408
|
let action = {
|
|
@@ -409,7 +417,7 @@ export default {
|
|
|
409
417
|
discoverId: this.discoverId,
|
|
410
418
|
dataset: `${this.envVars.ROOT_URL}/datasets/${this.discoverId}?type=dataset`,
|
|
411
419
|
}
|
|
412
|
-
|
|
420
|
+
simulations.push({
|
|
413
421
|
id: 'simulation',
|
|
414
422
|
title: ' ',
|
|
415
423
|
type: 'Simulation',
|
|
@@ -448,7 +456,7 @@ export default {
|
|
|
448
456
|
doi: this.entry.doi,
|
|
449
457
|
version: this.version,
|
|
450
458
|
}
|
|
451
|
-
|
|
459
|
+
simulations.push({
|
|
452
460
|
id,
|
|
453
461
|
title: baseName(filePath),
|
|
454
462
|
type: 'Simulation',
|
|
@@ -459,6 +467,7 @@ export default {
|
|
|
459
467
|
})
|
|
460
468
|
}
|
|
461
469
|
})
|
|
470
|
+
this.items['Simulations'].push(...simulations.sort((a, b) => a.title.localeCompare(b.title)))
|
|
462
471
|
}
|
|
463
472
|
},
|
|
464
473
|
createVideoItems: function () {
|
|
@@ -573,8 +573,8 @@ export default {
|
|
|
573
573
|
</script>
|
|
574
574
|
|
|
575
575
|
<style lang="scss" scoped>
|
|
576
|
-
@
|
|
577
|
-
@
|
|
576
|
+
@use '../assets/searchPopover.scss';
|
|
577
|
+
@use '../assets/pagination.scss';
|
|
578
578
|
|
|
579
579
|
.dataset-card {
|
|
580
580
|
position: relative;
|
|
@@ -157,10 +157,7 @@ import '@abi-software/svg-sprite/dist/style.css'
|
|
|
157
157
|
import { AlgoliaClient } from '../algolia/algolia.js'
|
|
158
158
|
import { facetPropPathMapping } from '../algolia/utils.js'
|
|
159
159
|
import EventBus from './EventBus.js'
|
|
160
|
-
|
|
161
|
-
const capitalise = function (txt) {
|
|
162
|
-
return txt.charAt(0).toUpperCase() + txt.slice(1)
|
|
163
|
-
}
|
|
160
|
+
import { capitalise } from '../utils/common.js'
|
|
164
161
|
|
|
165
162
|
const convertReadableLabel = function (original) {
|
|
166
163
|
const name = original.toLowerCase()
|
|
@@ -208,6 +205,10 @@ export default {
|
|
|
208
205
|
showFiltersText: true,
|
|
209
206
|
cascadeSelected: [],
|
|
210
207
|
cascadeSelectedWithBoolean: [],
|
|
208
|
+
// Re-entrancy lock: el-cascader can echo an extra @change
|
|
209
|
+
// after we reassign cascadeSelected in setCascader;
|
|
210
|
+
// stays locked until the filterTimeout debounce below unlocks it.
|
|
211
|
+
cascadeEventLocked: false,
|
|
211
212
|
filterTimeout: null,
|
|
212
213
|
numberShown: 10,
|
|
213
214
|
filters: [],
|
|
@@ -258,7 +259,6 @@ export default {
|
|
|
258
259
|
if (this.options.length) {
|
|
259
260
|
this.checkShowAllBoxes()
|
|
260
261
|
// this.setCascader(this.entry.filterFacets)
|
|
261
|
-
this.cssMods()
|
|
262
262
|
this.$emit('cascaderReady')
|
|
263
263
|
}
|
|
264
264
|
})
|
|
@@ -288,18 +288,22 @@ export default {
|
|
|
288
288
|
return value;
|
|
289
289
|
},
|
|
290
290
|
createChildrenCascaderValue: function(children, facet, facets) {
|
|
291
|
+
const parentKey = facet.key;
|
|
292
|
+
|
|
291
293
|
if (children?.length) {
|
|
292
294
|
for (let i = 0; i < children.length; i++) {
|
|
293
295
|
const facetItem = children[i];
|
|
294
296
|
//copy the facets into
|
|
295
297
|
if (children[i].facetPropPath !== 'supportingAwards.consortium.name') {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
298
|
+
// `sourceNomenclatureLabel` is from cell card explorer filters
|
|
299
|
+
if (parentKey === 'sourceNomenclatureLabel') {
|
|
300
|
+
children[i].label = facetItem.label;
|
|
301
|
+
} else {
|
|
302
|
+
children[i].label = convertReadableLabel(facetItem.label);
|
|
303
|
+
}
|
|
299
304
|
}
|
|
300
|
-
if (facetItem.key &&
|
|
305
|
+
if (facetItem.key && parentKey.includes('flatmap.connectivity.source.')) {
|
|
301
306
|
const childKey = facetItem.key;
|
|
302
|
-
const parentKey = facet.key;
|
|
303
307
|
const key = childKey.replace(`${parentKey}.`, '');
|
|
304
308
|
children[i].value = this.createCascaderItemValue([facet.label, key]);
|
|
305
309
|
} else {
|
|
@@ -570,6 +574,12 @@ export default {
|
|
|
570
574
|
},
|
|
571
575
|
// cascadeEvent: initiate searches based off cascader changes
|
|
572
576
|
cascadeEvent: function (eventIn) {
|
|
577
|
+
// Ignore the echoed @change el-cascader fires
|
|
578
|
+
// after we reassign cascadeSelected in setCascader
|
|
579
|
+
if (this.cascadeEventLocked) {
|
|
580
|
+
return
|
|
581
|
+
}
|
|
582
|
+
this.cascadeEventLocked = true
|
|
573
583
|
let event = [...eventIn]
|
|
574
584
|
if (event) {
|
|
575
585
|
// Check for show all in selected cascade options
|
|
@@ -667,7 +677,7 @@ export default {
|
|
|
667
677
|
|
|
668
678
|
this.filterTimeout = setTimeout(() => {
|
|
669
679
|
this.$emit('filterResults', filters) // emit filters for apps above sidebar
|
|
670
|
-
this.
|
|
680
|
+
this.cascadeEventLocked = false // safe to process real cascader changes again
|
|
671
681
|
}, 600);
|
|
672
682
|
}
|
|
673
683
|
},
|
|
@@ -775,7 +785,6 @@ export default {
|
|
|
775
785
|
this.updateListFilters(this.__expandItem__[0])
|
|
776
786
|
}
|
|
777
787
|
this.updateListStyleOrder()
|
|
778
|
-
this.cssMods()
|
|
779
788
|
},
|
|
780
789
|
updateListStyleOrder: function () {
|
|
781
790
|
this.$nextTick(() => {
|
|
@@ -954,30 +963,6 @@ export default {
|
|
|
954
963
|
})
|
|
955
964
|
)
|
|
956
965
|
},
|
|
957
|
-
makeCascadeLabelsClickable: function () {
|
|
958
|
-
// Next tick allows the cascader menu to change
|
|
959
|
-
this.$nextTick(() => {
|
|
960
|
-
document
|
|
961
|
-
.querySelectorAll('.sidebar-cascader-popper .el-cascader-node__label')
|
|
962
|
-
.forEach((el) => {
|
|
963
|
-
// step through each cascade label
|
|
964
|
-
el.onclick = function () {
|
|
965
|
-
const checkbox = this.previousElementSibling
|
|
966
|
-
if (checkbox) {
|
|
967
|
-
if (!checkbox.parentElement.attributes['aria-owns']) {
|
|
968
|
-
// check if we are at the lowest level of cascader
|
|
969
|
-
this.previousElementSibling.click() // Click the checkbox
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
})
|
|
974
|
-
})
|
|
975
|
-
},
|
|
976
|
-
|
|
977
|
-
cssMods: function () {
|
|
978
|
-
this.makeCascadeLabelsClickable()
|
|
979
|
-
},
|
|
980
|
-
|
|
981
966
|
flattenToFilters: function (filter, targetOption, previousMatched = false) {
|
|
982
967
|
let filtersArray = []
|
|
983
968
|
|
|
@@ -1142,7 +1127,6 @@ export default {
|
|
|
1142
1127
|
this.cascaderIsReady = true
|
|
1143
1128
|
this.checkShowAllBoxes()
|
|
1144
1129
|
this.setCascader(this.entry.filterFacets)
|
|
1145
|
-
this.cssMods()
|
|
1146
1130
|
this.$emit('cascaderReady')
|
|
1147
1131
|
})
|
|
1148
1132
|
},
|
|
@@ -147,23 +147,10 @@ import {
|
|
|
147
147
|
} from 'element-plus'
|
|
148
148
|
|
|
149
149
|
import EventBus from './EventBus.js'
|
|
150
|
+
import { generateUUID } from '../utils/common.js';
|
|
150
151
|
|
|
151
152
|
const MAX_SEARCH_HISTORY = 12;
|
|
152
153
|
|
|
153
|
-
function generateUUID() {
|
|
154
|
-
const arr = new Uint8Array(16);
|
|
155
|
-
window.crypto.getRandomValues(arr);
|
|
156
|
-
|
|
157
|
-
arr[6] = (arr[6] & 0x0f) | 0x40;
|
|
158
|
-
arr[8] = (arr[8] & 0x3f) | 0x80;
|
|
159
|
-
|
|
160
|
-
const hex = Array.from(arr)
|
|
161
|
-
.map(byte => byte.toString(16).padStart(2, '0'))
|
|
162
|
-
.join('');
|
|
163
|
-
|
|
164
|
-
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
154
|
export default {
|
|
168
155
|
name: 'SearchHistory',
|
|
169
156
|
components: {
|
|
@@ -347,7 +334,8 @@ export default {
|
|
|
347
334
|
getParentComponentName: function () {
|
|
348
335
|
const isConnectivity = this.localStorageKey?.indexOf('connectivity') !== -1;
|
|
349
336
|
const isDataset = this.localStorageKey?.indexOf('dataset') !== -1;
|
|
350
|
-
const
|
|
337
|
+
const isCellCard = this.localStorageKey?.indexOf('cell-card') !== -1;
|
|
338
|
+
const location = isConnectivity ? 'connectivity' : isDataset ? 'dataset' : isCellCard ? 'cell_card' : '';
|
|
351
339
|
return location;
|
|
352
340
|
},
|
|
353
341
|
search: function (item) {
|
|
@@ -65,6 +65,20 @@
|
|
|
65
65
|
@connectivity-item-close="onConnectivityItemClose"
|
|
66
66
|
/>
|
|
67
67
|
</template>
|
|
68
|
+
<template v-else-if="tab.type === 'cellCardExplorer' && showCellCards">
|
|
69
|
+
<CellCardExplorer
|
|
70
|
+
:ref="'cellCardExplorerTab_' + tab.id"
|
|
71
|
+
class="sidebar-content-container"
|
|
72
|
+
v-show="tab.id === activeTabId"
|
|
73
|
+
:envVars="envVars"
|
|
74
|
+
:activeSpecies="activeSpeciesForEntries"
|
|
75
|
+
@search-changed="searchChanged(tab.id, $event)"
|
|
76
|
+
@dataset-search="openDatasetSearchFromCellCard($event)"
|
|
77
|
+
@connectivity-search="openConnectivitySearch($event.facets, $event.query)"
|
|
78
|
+
@soma-location-hovered="showSomaLocation"
|
|
79
|
+
@soma-locations-ready="onSomaLocationsReady"
|
|
80
|
+
/>
|
|
81
|
+
</template>
|
|
68
82
|
<template v-else>
|
|
69
83
|
<DatasetExplorer
|
|
70
84
|
class="sidebar-content-container"
|
|
@@ -95,6 +109,7 @@ import EventBus from './EventBus.js'
|
|
|
95
109
|
import Tabs from './Tabs.vue'
|
|
96
110
|
import AnnotationTool from './AnnotationTool.vue'
|
|
97
111
|
import ConnectivityExplorer from './ConnectivityExplorer.vue'
|
|
112
|
+
import CellCardExplorer from './CellCardExplorer.vue'
|
|
98
113
|
import { removeShowAllFacets } from '../algolia/utils.js'
|
|
99
114
|
|
|
100
115
|
/**
|
|
@@ -110,6 +125,7 @@ export default {
|
|
|
110
125
|
Icon,
|
|
111
126
|
AnnotationTool,
|
|
112
127
|
ConnectivityExplorer,
|
|
128
|
+
CellCardExplorer,
|
|
113
129
|
},
|
|
114
130
|
name: 'SideBar',
|
|
115
131
|
props: {
|
|
@@ -119,6 +135,7 @@ export default {
|
|
|
119
135
|
{ title: 'Dataset Explorer', id: 1, type: 'datasetExplorer', closable: false },
|
|
120
136
|
{ title: 'Connectivity Explorer', id: 2, type: 'connectivityExplorer', closable: false },
|
|
121
137
|
{ title: 'Annotation', id: 3, type: 'annotation', closable: true },
|
|
138
|
+
{ title: 'Cell Card Explorer', id: 4, type: 'cellCardExplorer', closable: false },
|
|
122
139
|
],
|
|
123
140
|
},
|
|
124
141
|
/**
|
|
@@ -184,6 +201,10 @@ export default {
|
|
|
184
201
|
type: Boolean,
|
|
185
202
|
default: false,
|
|
186
203
|
},
|
|
204
|
+
showCellCards: {
|
|
205
|
+
type: Boolean,
|
|
206
|
+
default: false,
|
|
207
|
+
},
|
|
187
208
|
},
|
|
188
209
|
data: function () {
|
|
189
210
|
return {
|
|
@@ -192,12 +213,17 @@ export default {
|
|
|
192
213
|
activeTabId: 1,
|
|
193
214
|
activeAnnotationData: { tabType: "annotation" },
|
|
194
215
|
activeConnectivityData: { tabType: "connectivity" },
|
|
216
|
+
activeSpeciesForEntries: [],
|
|
195
217
|
state: {
|
|
196
218
|
dataset: {
|
|
197
219
|
search: '',
|
|
198
220
|
filters: [],
|
|
199
221
|
},
|
|
200
|
-
connectivity:
|
|
222
|
+
connectivity: {
|
|
223
|
+
search: '',
|
|
224
|
+
filters: [],
|
|
225
|
+
},
|
|
226
|
+
cellCards: {
|
|
201
227
|
search: '',
|
|
202
228
|
filters: [],
|
|
203
229
|
},
|
|
@@ -235,6 +261,16 @@ export default {
|
|
|
235
261
|
this.activeAnnotationData = data;
|
|
236
262
|
}
|
|
237
263
|
},
|
|
264
|
+
/**
|
|
265
|
+
* This event is emitted when the mouse hover on or off a soma location in cell card explorer.
|
|
266
|
+
* @param name Soma location
|
|
267
|
+
*/
|
|
268
|
+
showSomaLocation: function (name) {
|
|
269
|
+
this.$emit('soma-location-hovered', name);
|
|
270
|
+
},
|
|
271
|
+
onSomaLocationsReady: function (somaLocations) {
|
|
272
|
+
this.$emit('soma-locations-ready', somaLocations);
|
|
273
|
+
},
|
|
238
274
|
/**
|
|
239
275
|
* This event is emitted when the show connectivity button is clicked.
|
|
240
276
|
* @arg featureIds
|
|
@@ -299,6 +335,42 @@ export default {
|
|
|
299
335
|
datasetExplorerTabRef.openSearch(facets, query);
|
|
300
336
|
})
|
|
301
337
|
},
|
|
338
|
+
openCellCardExplorerSearch: function (filters, query) {
|
|
339
|
+
this.drawerOpen = true
|
|
340
|
+
// Because refs are in v-for, nextTick is needed here
|
|
341
|
+
this.$nextTick(() => {
|
|
342
|
+
const cellCardExplorerTabRef = this.getTabRef(undefined, 'cellCardExplorer', true);
|
|
343
|
+
if (cellCardExplorerTabRef && typeof cellCardExplorerTabRef.openSearch === 'function') {
|
|
344
|
+
cellCardExplorerTabRef.openSearch(filters, query);
|
|
345
|
+
}
|
|
346
|
+
})
|
|
347
|
+
},
|
|
348
|
+
openDatasetSearchFromCellCard: function (payload) {
|
|
349
|
+
if (!payload || typeof payload !== 'object') {
|
|
350
|
+
this.openSearch([], payload);
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
const facets = [];
|
|
355
|
+
if (payload.species) {
|
|
356
|
+
facets.push({
|
|
357
|
+
facet: payload.species,
|
|
358
|
+
term: 'Species',
|
|
359
|
+
facetPropPath: 'organisms.primary.species.name',
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (payload.location) {
|
|
364
|
+
facets.push({
|
|
365
|
+
facet: payload.location,
|
|
366
|
+
term: 'Anatomical structure',
|
|
367
|
+
facetPropPath: 'anatomy.organ.category.name',
|
|
368
|
+
AND: true,
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
this.openSearch(facets, '');
|
|
373
|
+
},
|
|
302
374
|
/**
|
|
303
375
|
* Get the ref id of the tab by id and type.
|
|
304
376
|
*/
|
|
@@ -437,6 +509,13 @@ export default {
|
|
|
437
509
|
this.state.connectivity.filters = connectivityExplorerTabRef.getFilters();
|
|
438
510
|
}
|
|
439
511
|
|
|
512
|
+
// Update cell card explorer state if available
|
|
513
|
+
const cellCardExplorerTabRef = this.getTabRef(undefined, 'cellCardExplorer');
|
|
514
|
+
if (cellCardExplorerTabRef) {
|
|
515
|
+
this.state.cellCards.search = cellCardExplorerTabRef.getSearch();
|
|
516
|
+
this.state.cellCards.filters = cellCardExplorerTabRef.getFilters();
|
|
517
|
+
}
|
|
518
|
+
|
|
440
519
|
// Update connectivity entries if available
|
|
441
520
|
if (this.connectivityEntry && this.connectivityEntry.length > 0) {
|
|
442
521
|
this.state.connectivityEntries = this.connectivityEntry.map((entry) => entry.id);
|
|
@@ -466,11 +545,15 @@ export default {
|
|
|
466
545
|
setState: function (state) {
|
|
467
546
|
// if state is not provided or formatted incorrectly, do nothing
|
|
468
547
|
if (!state || !state.dataset || !state.connectivity) return;
|
|
469
|
-
|
|
470
|
-
const
|
|
471
|
-
|
|
472
|
-
const
|
|
473
|
-
const
|
|
548
|
+
// Create a deep copy while preserving the original state structure for future extensibility
|
|
549
|
+
const newState = JSON.parse(JSON.stringify(state));
|
|
550
|
+
this.state = { ...this.state, ...newState };
|
|
551
|
+
const datasetFilters = this.state.dataset.filters;
|
|
552
|
+
const connectivityFilters = this.state.connectivity.filters;
|
|
553
|
+
const datasetSearch = this.state.dataset.search;
|
|
554
|
+
const connectivitySearch = this.state.connectivity.search;
|
|
555
|
+
const cellCardFilters = this.state.cellCards.filters || [];
|
|
556
|
+
const cellCardSearch = this.state.cellCards.search || '';
|
|
474
557
|
|
|
475
558
|
if (datasetFilters.length || datasetSearch) {
|
|
476
559
|
this.openSearch(datasetFilters, datasetSearch);
|
|
@@ -480,6 +563,10 @@ export default {
|
|
|
480
563
|
this.openConnectivitySearch(connectivityFilters, connectivitySearch);
|
|
481
564
|
}
|
|
482
565
|
|
|
566
|
+
if (cellCardFilters.length || cellCardSearch) {
|
|
567
|
+
this.openCellCardExplorerSearch(cellCardFilters, cellCardSearch);
|
|
568
|
+
}
|
|
569
|
+
|
|
483
570
|
if (state.activeTabId) {
|
|
484
571
|
this.$nextTick(() => {
|
|
485
572
|
const hasTab = this.tabEntries.find((t) => t.id === state.activeTabId);
|
|
@@ -501,7 +588,17 @@ export default {
|
|
|
501
588
|
...data,
|
|
502
589
|
};
|
|
503
590
|
this.$emit('trackEvent', taggingData);
|
|
504
|
-
}
|
|
591
|
+
},
|
|
592
|
+
/**
|
|
593
|
+
* @public
|
|
594
|
+
* Update the active species to use in filters.
|
|
595
|
+
* Used by SplitFlow component.
|
|
596
|
+
* @param activeSpecies
|
|
597
|
+
*/
|
|
598
|
+
updateActiveSpeciesForEntries: function (activeSpecies) {
|
|
599
|
+
const speciesEntries = Array.isArray(activeSpecies) ? activeSpecies : [activeSpecies];
|
|
600
|
+
this.activeSpeciesForEntries = [...new Set(speciesEntries.filter(Boolean))];
|
|
601
|
+
},
|
|
505
602
|
},
|
|
506
603
|
computed: {
|
|
507
604
|
// This should respect the information provided by the property
|
|
@@ -513,6 +610,10 @@ export default {
|
|
|
513
610
|
tab.type === "annotation" &&
|
|
514
611
|
this.annotationEntry &&
|
|
515
612
|
this.annotationEntry.length > 0
|
|
613
|
+
) ||
|
|
614
|
+
(
|
|
615
|
+
tab.type === "cellCardExplorer" &&
|
|
616
|
+
this.showCellCards
|
|
516
617
|
)
|
|
517
618
|
);
|
|
518
619
|
},
|
package/src/components/Tabs.vue
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
class="tab"
|
|
5
5
|
v-for="tab in tabs"
|
|
6
6
|
:key="tab.id"
|
|
7
|
-
:class="{ 'active-tab': tab.id == activeId }"
|
|
7
|
+
:class="{ 'active-tab': tab.id == activeId, 'closable-tab': tab.closable }"
|
|
8
8
|
@click="tabClicked(tab)"
|
|
9
9
|
>
|
|
10
10
|
<span class="tab-title">{{ tab.title }} </span>
|
|
@@ -103,14 +103,23 @@ export default {
|
|
|
103
103
|
.tab-title {
|
|
104
104
|
text-align: center;
|
|
105
105
|
font-size: 14px;
|
|
106
|
-
padding: 0
|
|
106
|
+
padding: 0 0.75rem;
|
|
107
|
+
|
|
108
|
+
.closable-tab & {
|
|
109
|
+
padding-right: 0.25rem;
|
|
110
|
+
}
|
|
107
111
|
}
|
|
108
112
|
|
|
109
113
|
.tab-close-icon {
|
|
110
|
-
width:
|
|
111
|
-
height:
|
|
112
|
-
font-size:
|
|
113
|
-
|
|
114
|
+
width: 18px !important;
|
|
115
|
+
height: 18px !important;
|
|
116
|
+
font-size: 18px !important;
|
|
117
|
+
margin-right: 4px !important;
|
|
114
118
|
color: $app-primary-color !important;
|
|
119
|
+
border-radius: 2px;
|
|
120
|
+
|
|
121
|
+
&:hover {
|
|
122
|
+
background-color: rgba($app-primary-color, 0.15) !important;
|
|
123
|
+
}
|
|
115
124
|
}
|
|
116
125
|
</style>
|