@abi-software/mapintegratedvuer 1.21.1 → 1.21.2
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 +23 -5
- package/assets/location-icon.html +33 -1
- package/assets/styleguide.css +18 -18
- package/cypress.config.js +7 -9
- package/dist/{ConnectivityGraph-CZMROk9r.js → ConnectivityGraph-DrSaFEDd.js} +3 -3
- package/dist/{ContentMixin-Vn34n5t2.js → ContentMixin-Xg0PjBqG.js} +2 -2
- package/dist/{DynamicMarkerMixin-BS6t7w_i.js → DynamicMarkerMixin-D5Ruu_hd.js} +1 -1
- package/dist/{Flatmap-BejxA0uz.js → Flatmap-CxN8TbnS.js} +4 -4
- package/dist/{Iframe-BWbhTjCR.js → Iframe-CkgbLfJt.js} +4 -4
- package/dist/{MultiFlatmap-nlmsH-Ib.js → MultiFlatmap-CkejvAJe.js} +4 -4
- package/dist/{Plot-ChbPsDZX.js → Plot-BfwoipSl.js} +2 -2
- package/dist/{Scaffold-C6f7c7Ha.js → Scaffold-DCqsTKpg.js} +4 -4
- package/dist/{Simulation-DcJScRYo.js → Simulation-BOtU3kTT.js} +2 -2
- package/dist/{connectivities-UXTqf7_0.js → connectivities-DyeS8w0c.js} +126 -95
- package/dist/index.html +9 -6
- package/dist/mapintegratedvuer.js +5489 -5578
- package/dist/mapintegratedvuer.umd.cjs +196 -196
- package/dist/style.css +1 -1
- package/eslint.config.js +39 -15
- package/package.json +11 -5
- package/public/index.html +9 -6
- package/src/App.vue +234 -249
- package/src/assets/_variables.scss +12 -10
- package/src/assets/header-icon.scss +8 -9
- package/src/assets/mapicon-species-style.css +10 -8
- package/src/assets/styles.scss +1 -1
- package/src/components/ContentBar.vue +98 -106
- package/src/components/ContentVuer.vue +36 -39
- package/src/components/ContextCard.vue +238 -199
- package/src/components/ContextHelp.vue +22 -26
- package/src/components/CustomSplitter.vue +32 -43
- package/src/components/DatasetHeader.vue +37 -41
- package/src/components/DialogToolbarContent.vue +292 -256
- package/src/components/FlatmapContextCard.vue +52 -57
- package/src/components/MapContent.vue +90 -86
- package/src/components/ResizeSensor.vue +8 -13
- package/src/components/SearchControls.vue +26 -35
- package/src/components/SimulatedData.js +196 -219
- package/src/components/SplitDialog.vue +139 -129
- package/src/components/SplitFlow.vue +421 -237
- package/src/components/index.js +1 -3
- package/src/components/scripts/simulation_data.js +393 -397
- package/src/components/scripts/utilities.js +108 -78
- package/src/components/viewers/CellDLViewer.vue +9 -9
- package/src/components/viewers/ConnectivityGraph.vue +9 -12
- package/src/components/viewers/Flatmap.vue +23 -25
- package/src/components/viewers/Iframe.vue +8 -10
- package/src/components/viewers/MultiFlatmap.vue +59 -69
- package/src/components/viewers/Plot.vue +6 -7
- package/src/components/viewers/Scaffold.vue +73 -63
- package/src/components/viewers/Simulation.vue +10 -15
- package/src/main.js +16 -21
- package/src/mixins/ContentMixin.js +208 -178
- package/src/mixins/DynamicMarkerMixin.js +14 -18
- package/src/mixins/RetrieveContextCardMixin.js +35 -30
- package/src/mixins/S3Bucket.vue +10 -13
- package/src/services/knowledgeMapping.js +53 -53
- package/src/services/tagging.js +4 -4
- package/src/stores/connectivities.js +46 -8
- package/src/stores/entries.js +7 -9
- package/src/stores/index.js +7 -7
- package/src/stores/settings.js +23 -31
- package/src/stores/splitFlow.js +364 -298
- package/vite.bundle-build.js +24 -26
- package/vite.config.js +22 -21
- package/vite.static-build.js +4 -4
- package/vitest.workspace.js +1 -3
- package/vuese-generator.js +47 -55
|
@@ -15,9 +15,7 @@
|
|
|
15
15
|
/>
|
|
16
16
|
</el-header>
|
|
17
17
|
<el-main class="dialog-main">
|
|
18
|
-
<div
|
|
19
|
-
style="width: 100%; height: 100%; position: relative; overflow: hidden"
|
|
20
|
-
>
|
|
18
|
+
<div style="width: 100%; height: 100%; position: relative; overflow: hidden">
|
|
21
19
|
<SideBar
|
|
22
20
|
ref="sideBar"
|
|
23
21
|
:envVars="envVars"
|
|
@@ -66,36 +64,28 @@
|
|
|
66
64
|
</template>
|
|
67
65
|
|
|
68
66
|
<script>
|
|
69
|
-
/* eslint-disable no-alert, no-console */
|
|
70
67
|
import { provide, markRaw, computed } from 'vue';
|
|
71
68
|
import Tagging from '../services/tagging.js';
|
|
72
|
-
import DialogToolbarContent from
|
|
73
|
-
import EventBus from
|
|
74
|
-
import SplitDialog from
|
|
69
|
+
import DialogToolbarContent from './DialogToolbarContent.vue';
|
|
70
|
+
import EventBus from './EventBus';
|
|
71
|
+
import SplitDialog from './SplitDialog.vue';
|
|
75
72
|
// import contextCards from './context-cards'
|
|
76
|
-
import { SideBar } from
|
|
77
|
-
import
|
|
78
|
-
import {
|
|
79
|
-
queryForwardBackwardConnections
|
|
80
|
-
} from '@abi-software/map-utilities';
|
|
73
|
+
import { SideBar } from '@abi-software/map-side-bar';
|
|
74
|
+
import '@abi-software/map-side-bar/dist/style.css';
|
|
75
|
+
import { queryForwardBackwardConnections } from '@abi-software/map-utilities';
|
|
81
76
|
import {
|
|
82
77
|
capitalise,
|
|
83
78
|
getNewMapEntry,
|
|
84
79
|
initialDefaultState,
|
|
85
80
|
intersectArrays,
|
|
86
|
-
} from
|
|
87
|
-
import { AnnotationService } from '@abi-software/sparc-annotation'
|
|
81
|
+
} from './scripts/utilities.js';
|
|
82
|
+
import { AnnotationService } from '@abi-software/sparc-annotation';
|
|
88
83
|
import { mapStores } from 'pinia';
|
|
89
84
|
import { useEntriesStore } from '../stores/entries';
|
|
90
|
-
import { useMainStore } from '../stores/index'
|
|
85
|
+
import { useMainStore } from '../stores/index';
|
|
91
86
|
import { useSettingsStore } from '../stores/settings';
|
|
92
87
|
import { useSplitFlowStore } from '../stores/splitFlow';
|
|
93
88
|
import { useConnectivitiesStore } from '../stores/connectivities';
|
|
94
|
-
import {
|
|
95
|
-
ElContainer as Container,
|
|
96
|
-
ElHeader as Header,
|
|
97
|
-
ElMain as Main,
|
|
98
|
-
} from "element-plus";
|
|
99
89
|
|
|
100
90
|
const getAllFacetLabels = (children) => {
|
|
101
91
|
const labels = [];
|
|
@@ -108,12 +98,12 @@ const getAllFacetLabels = (children) => {
|
|
|
108
98
|
});
|
|
109
99
|
}
|
|
110
100
|
return labels;
|
|
111
|
-
}
|
|
101
|
+
};
|
|
112
102
|
|
|
113
103
|
const getFacetsFromAction = (action) => {
|
|
114
104
|
const actionFacets = action.facets ? action.facets : action.labels ? action.labels : [];
|
|
115
105
|
return actionFacets;
|
|
116
|
-
}
|
|
106
|
+
};
|
|
117
107
|
|
|
118
108
|
const getAnatomyTermsForFilters = (action, availableNameCurieMapping) => {
|
|
119
109
|
const facets = [];
|
|
@@ -126,17 +116,14 @@ const getAnatomyTermsForFilters = (action, availableNameCurieMapping) => {
|
|
|
126
116
|
}
|
|
127
117
|
}
|
|
128
118
|
return facets;
|
|
129
|
-
}
|
|
119
|
+
};
|
|
130
120
|
|
|
131
121
|
/**
|
|
132
122
|
* Component of the floating dialogs.
|
|
133
123
|
*/
|
|
134
124
|
export default {
|
|
135
|
-
name:
|
|
125
|
+
name: 'SplitFlow',
|
|
136
126
|
components: {
|
|
137
|
-
Container,
|
|
138
|
-
Header,
|
|
139
|
-
Main,
|
|
140
127
|
DialogToolbarContent,
|
|
141
128
|
SplitDialog,
|
|
142
129
|
SideBar,
|
|
@@ -147,8 +134,11 @@ export default {
|
|
|
147
134
|
let annotator = markRaw(new AnnotationService(`${settings.flatmapAPI}annotator`));
|
|
148
135
|
provide('userApiKey', mainStore.userToken);
|
|
149
136
|
provide('$annotator', annotator);
|
|
150
|
-
provide(
|
|
151
|
-
|
|
137
|
+
provide(
|
|
138
|
+
'showLongLabel',
|
|
139
|
+
computed(() => props.showLongLabel),
|
|
140
|
+
);
|
|
141
|
+
return { annotator };
|
|
152
142
|
},
|
|
153
143
|
props: {
|
|
154
144
|
state: {
|
|
@@ -168,6 +158,11 @@ export default {
|
|
|
168
158
|
startUp: true,
|
|
169
159
|
sidebarStateRestored: false,
|
|
170
160
|
sidebarAnnotationState: false,
|
|
161
|
+
// true while a permalink's sidebar.connectivityEntries are being resolved across the active viewers,
|
|
162
|
+
// used to avoid flashing the full/unfiltered connectivity list
|
|
163
|
+
// or dropping entries resolved by other viewers.
|
|
164
|
+
restoringConnectivityState: false,
|
|
165
|
+
restoreAttempts: 0,
|
|
171
166
|
search: '',
|
|
172
167
|
expanded: '',
|
|
173
168
|
filterTriggered: false,
|
|
@@ -187,7 +182,7 @@ export default {
|
|
|
187
182
|
filterVisibility: true,
|
|
188
183
|
filterOptions: [],
|
|
189
184
|
annotationHighlight: [],
|
|
190
|
-
}
|
|
185
|
+
};
|
|
191
186
|
},
|
|
192
187
|
watch: {
|
|
193
188
|
state: {
|
|
@@ -218,29 +213,27 @@ export default {
|
|
|
218
213
|
const filterExpression = {
|
|
219
214
|
OR: [
|
|
220
215
|
{ NOT: { 'tile-layer': 'pathways' } },
|
|
221
|
-
{ NOT: {
|
|
216
|
+
{ NOT: { HAS: 'nerves' } },
|
|
222
217
|
{
|
|
223
|
-
AND: [
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
]
|
|
227
|
-
}
|
|
228
|
-
]
|
|
218
|
+
AND: [{ 'tile-layer': 'pathways' }, { models: this.connectivityHighlight }],
|
|
219
|
+
},
|
|
220
|
+
],
|
|
229
221
|
};
|
|
230
222
|
const validFilter = this.filterVisibility && this.connectivityProcessed;
|
|
231
223
|
const payload = validFilter ? filterExpression : undefined;
|
|
232
224
|
EventBus.emit('filter-visibility', payload);
|
|
233
225
|
},
|
|
234
226
|
onConnectivityCollapseChange: function (payload) {
|
|
235
|
-
this.expanded = payload.id
|
|
227
|
+
this.expanded = payload.id;
|
|
236
228
|
const splitdialog = this.$refs.splitdialog;
|
|
237
229
|
if (splitdialog) {
|
|
238
230
|
const activeContents = splitdialog.getActiveContents();
|
|
239
|
-
const hasFlatmap = activeContents.find(c => c.viewerType.includes('Flatmap'));
|
|
240
|
-
const hasHumanMaleFlatmap = activeContents.find(c => c.activeSpecies ===
|
|
241
|
-
let nonFlatmapLoad = false
|
|
242
|
-
activeContents.forEach(content => {
|
|
243
|
-
const isFlatmap =
|
|
231
|
+
const hasFlatmap = activeContents.find((c) => c.viewerType.includes('Flatmap'));
|
|
232
|
+
const hasHumanMaleFlatmap = activeContents.find((c) => c.activeSpecies === 'Human Male');
|
|
233
|
+
let nonFlatmapLoad = false;
|
|
234
|
+
activeContents.forEach((content) => {
|
|
235
|
+
const isFlatmap =
|
|
236
|
+
content.viewerType === 'Flatmap' || content.viewerType === 'MultiFlatmap';
|
|
244
237
|
// minimise connectivity detail fetch
|
|
245
238
|
const shouldLoad =
|
|
246
239
|
(hasFlatmap && isFlatmap) ||
|
|
@@ -265,7 +258,7 @@ export default {
|
|
|
265
258
|
if (splitdialog) {
|
|
266
259
|
const activeContents = splitdialog.getActiveContents();
|
|
267
260
|
|
|
268
|
-
activeContents.forEach(content => {
|
|
261
|
+
activeContents.forEach((content) => {
|
|
269
262
|
if (content?.$refs['viewer']) {
|
|
270
263
|
const contentViewer = content.$refs['viewer'];
|
|
271
264
|
const flatmapRef = contentViewer.flatmapRef;
|
|
@@ -273,7 +266,8 @@ export default {
|
|
|
273
266
|
let flatmap = null;
|
|
274
267
|
|
|
275
268
|
if (flatmapRef) flatmap = flatmapRef;
|
|
276
|
-
if (multiflatmapRef
|
|
269
|
+
if (multiflatmapRef && contentViewer.flatmapIsReady())
|
|
270
|
+
flatmap = multiflatmapRef.getCurrentFlatmap();
|
|
277
271
|
|
|
278
272
|
if (flatmap) {
|
|
279
273
|
activeFlatmaps.push(flatmap);
|
|
@@ -283,12 +277,31 @@ export default {
|
|
|
283
277
|
}
|
|
284
278
|
return activeFlatmaps;
|
|
285
279
|
},
|
|
280
|
+
// Scaffold viewers are not Flatmap/MultiFlatmap instances so they're not returned by getActiveFlatmaps,
|
|
281
|
+
// but their own nervesKnowledge (populated once loadConnectivityExplorerConfig resolves)
|
|
282
|
+
// carries the nerve-label data needed to restore their connectivity entries.
|
|
283
|
+
getActiveScaffolds: function () {
|
|
284
|
+
const activeScaffolds = [];
|
|
285
|
+
let splitdialog = this.$refs.splitdialog;
|
|
286
|
+
|
|
287
|
+
if (splitdialog) {
|
|
288
|
+
const activeContents = splitdialog.getActiveContents();
|
|
289
|
+
|
|
290
|
+
activeContents.forEach((content) => {
|
|
291
|
+
const contentViewer = content?.$refs['viewer'];
|
|
292
|
+
if (contentViewer?.scaffoldRef) {
|
|
293
|
+
activeScaffolds.push(contentViewer);
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
return activeScaffolds;
|
|
298
|
+
},
|
|
286
299
|
/**
|
|
287
300
|
* Callback when an action is performed (open new dialogs).
|
|
288
301
|
*/
|
|
289
302
|
actionClick: function (action) {
|
|
290
303
|
if (action) {
|
|
291
|
-
if (!this.availableFacets ||
|
|
304
|
+
if (!this.availableFacets || this.availableFacets.length === 0) {
|
|
292
305
|
const availableFacetsRaw = localStorage.getItem('available-anatomy-facets');
|
|
293
306
|
const availableFacetsAll = availableFacetsRaw ? JSON.parse(availableFacetsRaw) : [];
|
|
294
307
|
|
|
@@ -296,7 +309,10 @@ export default {
|
|
|
296
309
|
this.availableFacets = markRaw([...new Set(getAllFacetLabels(availableFacetsAll))]);
|
|
297
310
|
}
|
|
298
311
|
|
|
299
|
-
if (
|
|
312
|
+
if (
|
|
313
|
+
!this.availableNameCurieMapping ||
|
|
314
|
+
Object.keys(this.availableNameCurieMapping).length === 0
|
|
315
|
+
) {
|
|
300
316
|
const availableDataRaw = localStorage.getItem('available-name-curie-mapping');
|
|
301
317
|
const availableData = availableDataRaw ? JSON.parse(availableDataRaw) : {};
|
|
302
318
|
|
|
@@ -304,7 +320,7 @@ export default {
|
|
|
304
320
|
this.availableNameCurieMapping = markRaw(availableData);
|
|
305
321
|
}
|
|
306
322
|
|
|
307
|
-
if (action.type ==
|
|
323
|
+
if (action.type == 'Search') {
|
|
308
324
|
if (action.nervePath) {
|
|
309
325
|
this.openSearch([action.filter], action.label);
|
|
310
326
|
} else {
|
|
@@ -315,67 +331,67 @@ export default {
|
|
|
315
331
|
? 'portal_maps_featured_dataset_search'
|
|
316
332
|
: 'portal_maps_action_search';
|
|
317
333
|
Tagging.sendEvent({
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
334
|
+
event: 'interaction_event',
|
|
335
|
+
event_name: eventName,
|
|
336
|
+
category: action.term || 'filter',
|
|
337
|
+
location: 'map_location_pin',
|
|
322
338
|
});
|
|
323
339
|
this.filterTriggered = true;
|
|
324
340
|
}
|
|
325
|
-
} else if (action.type ==
|
|
326
|
-
window.open(action.resource,
|
|
327
|
-
} else if (action.type ==
|
|
341
|
+
} else if (action.type == 'URL') {
|
|
342
|
+
window.open(action.resource, '_blank');
|
|
343
|
+
} else if (action.type == 'Facet') {
|
|
328
344
|
if (this.$refs.sideBar) {
|
|
329
345
|
const sendAction = {
|
|
330
|
-
facetPropPath:
|
|
331
|
-
facetSubPropPath:
|
|
332
|
-
term:
|
|
346
|
+
facetPropPath: 'anatomy.organ.category.name',
|
|
347
|
+
facetSubPropPath: 'anatomy.organ.name',
|
|
348
|
+
term: 'Anatomical structure',
|
|
333
349
|
};
|
|
334
350
|
const filters = [];
|
|
335
351
|
const facets = getAnatomyTermsForFilters(action, this.availableNameCurieMapping);
|
|
336
352
|
const actionFacets = getFacetsFromAction(action);
|
|
337
353
|
const facetString = actionFacets.join(', ');
|
|
338
|
-
facets.forEach(facet => filters.push({...sendAction, facet}));
|
|
354
|
+
facets.forEach((facet) => filters.push({ ...sendAction, facet }));
|
|
339
355
|
this.$refs.sideBar.addFilter(filters);
|
|
340
356
|
// GA Tagging
|
|
341
357
|
// Event tracking for map action search/filter data
|
|
342
358
|
Tagging.sendEvent({
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
359
|
+
event: 'interaction_event',
|
|
360
|
+
event_name: 'portal_maps_action_filter',
|
|
361
|
+
category: facetString || 'filter_reset',
|
|
362
|
+
location: 'map_location_pin',
|
|
347
363
|
});
|
|
348
364
|
this.filterTriggered = true;
|
|
349
365
|
}
|
|
350
|
-
} else if (action.type ==
|
|
366
|
+
} else if (action.type == 'Facets') {
|
|
351
367
|
const facets = [];
|
|
352
368
|
const facetsArray = getAnatomyTermsForFilters(action, this.availableNameCurieMapping);
|
|
353
369
|
const filterValuesArray = intersectArrays(this.availableFacets, facetsArray);
|
|
354
370
|
const filterValues = filterValuesArray.join(', ');
|
|
355
371
|
|
|
356
|
-
this.settingsStore.facets.species.forEach(e => {
|
|
372
|
+
this.settingsStore.facets.species.forEach((e) => {
|
|
357
373
|
facets.push({
|
|
358
374
|
facet: capitalise(e),
|
|
359
|
-
term:
|
|
360
|
-
facetPropPath:
|
|
375
|
+
term: 'Species',
|
|
376
|
+
facetPropPath: 'organisms.primary.species.name',
|
|
361
377
|
});
|
|
362
378
|
});
|
|
363
379
|
facets.push(
|
|
364
|
-
...filterValuesArray.map(val => ({
|
|
380
|
+
...filterValuesArray.map((val) => ({
|
|
365
381
|
facet: capitalise(val),
|
|
366
|
-
term:
|
|
367
|
-
facetPropPath:
|
|
368
|
-
facetSubPropPath:
|
|
369
|
-
}))
|
|
382
|
+
term: 'Anatomical structure',
|
|
383
|
+
facetPropPath: 'anatomy.organ.category.name',
|
|
384
|
+
facetSubPropPath: 'anatomy.organ.name',
|
|
385
|
+
})),
|
|
370
386
|
);
|
|
371
|
-
this.openSearch(facets,
|
|
387
|
+
this.openSearch(facets, '');
|
|
372
388
|
// GA Tagging
|
|
373
389
|
// Event tracking for map action search/filter data
|
|
374
390
|
Tagging.sendEvent({
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
391
|
+
event: 'interaction_event',
|
|
392
|
+
event_name: 'portal_maps_action_filter',
|
|
393
|
+
category: filterValues || 'filter_reset',
|
|
394
|
+
location: 'map_popup_button',
|
|
379
395
|
});
|
|
380
396
|
this.filterTriggered = true;
|
|
381
397
|
} else {
|
|
@@ -393,7 +409,7 @@ export default {
|
|
|
393
409
|
if (type) categoryValues.push(type);
|
|
394
410
|
if (datasetId) categoryValues.push('(' + id + ')');
|
|
395
411
|
if (resource) {
|
|
396
|
-
if (type ===
|
|
412
|
+
if (type === 'Plot') {
|
|
397
413
|
filePath = resource.dataSource.url;
|
|
398
414
|
} else {
|
|
399
415
|
filePath = typeof resource === 'string' ? resource : resource.share_link;
|
|
@@ -403,12 +419,12 @@ export default {
|
|
|
403
419
|
// GA Tagging
|
|
404
420
|
// Event tracking for map sidebar gallery click
|
|
405
421
|
Tagging.sendEvent({
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
422
|
+
event: 'interaction_event',
|
|
423
|
+
event_name: 'portal_maps_gallery_click',
|
|
424
|
+
category: categoryValues.join(' '),
|
|
425
|
+
location: 'map_sidebar_gallery',
|
|
426
|
+
dataset_id: id ? id + '' : '', // change to string format
|
|
427
|
+
file_path: filePath,
|
|
412
428
|
});
|
|
413
429
|
},
|
|
414
430
|
onDisplaySearch: function (payload, tracking = true) {
|
|
@@ -417,7 +433,7 @@ export default {
|
|
|
417
433
|
let splitdialog = this.$refs.splitdialog;
|
|
418
434
|
if (splitdialog) {
|
|
419
435
|
const activeContents = splitdialog.getActiveContents();
|
|
420
|
-
activeContents.forEach(content => {
|
|
436
|
+
activeContents.forEach((content) => {
|
|
421
437
|
if (content.search(payload.term)) {
|
|
422
438
|
searchFound = true;
|
|
423
439
|
}
|
|
@@ -429,29 +445,31 @@ export default {
|
|
|
429
445
|
// GA Tagging
|
|
430
446
|
// Event tracking for map on display search
|
|
431
447
|
Tagging.sendEvent({
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
448
|
+
event: 'interaction_event',
|
|
449
|
+
event_name: 'portal_maps_display_search',
|
|
450
|
+
category: payload.term,
|
|
451
|
+
location: 'map_toolbar',
|
|
436
452
|
});
|
|
437
453
|
}
|
|
438
454
|
},
|
|
439
|
-
fetchSuggestions: function(payload) {
|
|
455
|
+
fetchSuggestions: function (payload) {
|
|
440
456
|
const suggestions = [];
|
|
441
457
|
//Search all active viewers when global callback is on
|
|
442
458
|
let splitdialog = this.$refs.splitdialog;
|
|
443
459
|
const activeContents = splitdialog.getActiveContents();
|
|
444
460
|
//Push new suggestions into the pre-existing suggestions array
|
|
445
|
-
activeContents.forEach(content =>
|
|
461
|
+
activeContents.forEach((content) =>
|
|
462
|
+
content.searchSuggestions(payload.data.term, suggestions),
|
|
463
|
+
);
|
|
446
464
|
const parsed = [];
|
|
447
465
|
//Remove double quote as it is used as a speical character
|
|
448
|
-
suggestions.forEach(suggestion => {
|
|
449
|
-
parsed.push(suggestion.replaceAll("
|
|
466
|
+
suggestions.forEach((suggestion) => {
|
|
467
|
+
parsed.push(suggestion.replaceAll('"', ''));
|
|
450
468
|
});
|
|
451
469
|
const unique = new Set(parsed);
|
|
452
470
|
suggestions.length = 0;
|
|
453
471
|
for (const item of unique) {
|
|
454
|
-
suggestions.push({
|
|
472
|
+
suggestions.push({ value: '"' + item + '"' });
|
|
455
473
|
}
|
|
456
474
|
payload.data.cb(suggestions);
|
|
457
475
|
},
|
|
@@ -467,7 +485,7 @@ export default {
|
|
|
467
485
|
// offset sidebar only on singlepanel and 2horpanel views
|
|
468
486
|
EventBus.emit('show-connectivity', {
|
|
469
487
|
featureIds: featureIds,
|
|
470
|
-
offset: activeView === 'singlepanel' || activeView === '2horpanel'
|
|
488
|
+
offset: activeView === 'singlepanel' || activeView === '2horpanel',
|
|
471
489
|
});
|
|
472
490
|
}
|
|
473
491
|
},
|
|
@@ -475,23 +493,25 @@ export default {
|
|
|
475
493
|
// expand connectivity card and show connectivity info
|
|
476
494
|
// if expanded exist, payload should be an array of one element
|
|
477
495
|
// skip payload not match the expanded in multiple views
|
|
478
|
-
const isMatched = payload.some(entry => entry.featureId[0] === this.expanded);
|
|
496
|
+
const isMatched = payload.some((entry) => entry.featureId[0] === this.expanded);
|
|
479
497
|
if (this.expanded && this.connectivityExplorerClicked.length && !isMatched) {
|
|
480
498
|
this.connectivityExplorerClicked.pop();
|
|
481
499
|
return;
|
|
482
500
|
}
|
|
483
501
|
|
|
484
502
|
// Remove duplicate items from payload
|
|
485
|
-
const uniquePayload = [
|
|
486
|
-
|
|
503
|
+
const uniquePayload = [
|
|
504
|
+
...new Map(payload.map((entry) => [entry.featureId[0], entry])).values(),
|
|
505
|
+
];
|
|
506
|
+
const mappedPayload = uniquePayload.map((entry) => {
|
|
487
507
|
let result = {
|
|
488
508
|
...entry,
|
|
489
509
|
label: entry.title,
|
|
490
510
|
id: entry.featureId[0],
|
|
491
|
-
}
|
|
492
|
-
const ck = this.connectivityKnowledge.find(ck => ck.id === result.id);
|
|
511
|
+
};
|
|
512
|
+
const ck = this.connectivityKnowledge.find((ck) => ck.id === result.id);
|
|
493
513
|
if (entry.ready) {
|
|
494
|
-
result['nerve-label'] = entry['nerve-label'] || ck['nerve-label'];
|
|
514
|
+
result['nerve-label'] = entry['nerve-label'] || (ck && ck['nerve-label']);
|
|
495
515
|
}
|
|
496
516
|
if (ck && ck['long-label']) {
|
|
497
517
|
result['long-label'] = ck['long-label'];
|
|
@@ -502,13 +522,56 @@ export default {
|
|
|
502
522
|
return result;
|
|
503
523
|
});
|
|
504
524
|
|
|
525
|
+
// While restoring a permalink's sidebar connectivityEntries,
|
|
526
|
+
// popups from multiple active viewers (e.g. two MultiFlatmaps + a Scaffold)
|
|
527
|
+
// resolve concurrently and each only reports the subset it recognises.
|
|
528
|
+
// Merge by id (keeping richer fields like nerve-label/long-label, e.g. from a Scaffold viewer,
|
|
529
|
+
// if a later duplicate for the same id lacks them) instead of replacing,
|
|
530
|
+
// so entries resolved by one viewer are not dropped or downgraded when another viewer's payload arrives.
|
|
531
|
+
if (this.restoringConnectivityState) {
|
|
532
|
+
const merged = new Map(this.connectivityEntry.map((entry) => [entry.id, entry]));
|
|
533
|
+
mappedPayload.forEach((entry) => {
|
|
534
|
+
const existing = merged.get(entry.id);
|
|
535
|
+
merged.set(
|
|
536
|
+
entry.id,
|
|
537
|
+
existing
|
|
538
|
+
? {
|
|
539
|
+
...existing,
|
|
540
|
+
...entry,
|
|
541
|
+
// Viewers emit placeholders (ready: false) before their resolved entries (ready: true),
|
|
542
|
+
// so a late placeholder from one viewer must not downgrade an entry another viewer already resolved.
|
|
543
|
+
ready: existing.ready || entry.ready,
|
|
544
|
+
'nerve-label': entry['nerve-label'] || existing['nerve-label'],
|
|
545
|
+
'long-label': entry['long-label'] || existing['long-label'],
|
|
546
|
+
'expert-consultants':
|
|
547
|
+
entry['expert-consultants'] || existing['expert-consultants'],
|
|
548
|
+
}
|
|
549
|
+
: entry,
|
|
550
|
+
);
|
|
551
|
+
});
|
|
552
|
+
this.connectivityEntry = Array.from(merged.values());
|
|
553
|
+
// Entries resolve asynchronously via connectivity-info-open,
|
|
554
|
+
// which is not tied to connectivity-knowledge ticks, so re-run the restore completion check here.
|
|
555
|
+
// Otherwise the last entries becoming ready never re-evaluates allEntriesReady
|
|
556
|
+
// and the restore never finalises.
|
|
557
|
+
this.checkConnectivityRestoreComplete(this.state?.sidebar);
|
|
558
|
+
} else {
|
|
559
|
+
this.connectivityEntry = mappedPayload;
|
|
560
|
+
}
|
|
561
|
+
|
|
505
562
|
// Fetch long-label from global connectivities if not exist in the payload,
|
|
506
563
|
// this is for the case when user click on the flatmap paths/features directly without going through sidebar list,
|
|
507
|
-
// which will only have id and label in the payload
|
|
508
|
-
|
|
509
|
-
|
|
564
|
+
// which will only have id and label in the payload.
|
|
565
|
+
// Skipped while restoring since connectivityEntry[0] may not relate to the entries just merged in above.
|
|
566
|
+
if (
|
|
567
|
+
!this.restoringConnectivityState &&
|
|
568
|
+
!this.connectivityEntry[0]['long-label'] &&
|
|
569
|
+
this.connectivityEntry[0].mapuuid
|
|
570
|
+
) {
|
|
571
|
+
const connectivityData =
|
|
572
|
+
this.connectivitiesStore.globalConnectivities[this.connectivityEntry[0].mapuuid] || [];
|
|
510
573
|
if (connectivityData.length) {
|
|
511
|
-
const ck = connectivityData.find(ck => ck.id === this.connectivityEntry[0].id);
|
|
574
|
+
const ck = connectivityData.find((ck) => ck.id === this.connectivityEntry[0].id);
|
|
512
575
|
if (ck && ck['long-label']) {
|
|
513
576
|
this.connectivityEntry[0]['long-label'] = ck['long-label'];
|
|
514
577
|
}
|
|
@@ -517,13 +580,13 @@ export default {
|
|
|
517
580
|
|
|
518
581
|
if (this.connectivityExplorerClicked.length) {
|
|
519
582
|
// only remove clicked if not placeholder entry
|
|
520
|
-
if (this.connectivityEntry.every(entry => entry.ready)) {
|
|
583
|
+
if (this.connectivityEntry.every((entry) => entry.ready)) {
|
|
521
584
|
this.connectivityExplorerClicked.pop();
|
|
522
585
|
}
|
|
523
586
|
} else {
|
|
524
587
|
// click on the flatmap paths/features directly
|
|
525
588
|
// or onDisplaySearch is performed
|
|
526
|
-
const connectivityEntries = this.connectivityEntry.map(entry => entry.id);
|
|
589
|
+
const connectivityEntries = this.connectivityEntry.map((entry) => entry.id);
|
|
527
590
|
const flatmapAPI = this.settingsStore.flatmapAPI;
|
|
528
591
|
const { viewingMode } = this.settingsStore.globalSettings;
|
|
529
592
|
const knowledgeSource = this.connectivityEntry[0].mapuuid || '';
|
|
@@ -532,11 +595,12 @@ export default {
|
|
|
532
595
|
|
|
533
596
|
// fetch forward/backward connections on Neuron Connection mode
|
|
534
597
|
if (viewingMode === 'Neuron Connection' && connectivityEntries.length && knowledgeSource) {
|
|
535
|
-
forwardBackwardConnections = await queryForwardBackwardConnections(
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
598
|
+
forwardBackwardConnections = await queryForwardBackwardConnections(
|
|
599
|
+
flatmapAPI,
|
|
600
|
+
knowledgeSource,
|
|
601
|
+
connectivityEntries,
|
|
602
|
+
);
|
|
603
|
+
const allConnections = [...connectivityEntries, ...forwardBackwardConnections];
|
|
540
604
|
const availableConnectivities = this.connectivitiesStore.getUniqueConnectivitiesByKeys;
|
|
541
605
|
mappedConnections = allConnections.map((connId) => {
|
|
542
606
|
return availableConnectivities.find((ac) => ac.id === connId);
|
|
@@ -547,12 +611,12 @@ export default {
|
|
|
547
611
|
if (forwardBackwardConnections.length) {
|
|
548
612
|
this.connectivityEntry = [];
|
|
549
613
|
this.connectivityKnowledge = mappedConnections;
|
|
550
|
-
this.connectivityHighlight = this.connectivityKnowledge.map(ck => ck.id);
|
|
614
|
+
this.connectivityHighlight = this.connectivityKnowledge.map((ck) => ck.id);
|
|
551
615
|
this.connectivityProcessed = true;
|
|
552
616
|
} else {
|
|
553
617
|
this.connectivityKnowledge = this.connectivityEntry;
|
|
554
|
-
if (this.connectivityKnowledge.every(ck => ck.ready)) {
|
|
555
|
-
this.connectivityHighlight = this.connectivityKnowledge.map(ck => ck.id);
|
|
618
|
+
if (this.connectivityKnowledge.every((ck) => ck.ready)) {
|
|
619
|
+
this.connectivityHighlight = this.connectivityKnowledge.map((ck) => ck.id);
|
|
556
620
|
this.connectivityProcessed = true;
|
|
557
621
|
}
|
|
558
622
|
}
|
|
@@ -567,7 +631,7 @@ export default {
|
|
|
567
631
|
this.annotationEntry = payload.annotationEntry;
|
|
568
632
|
// If drawing, `entry.models` may be undefined; use an empty array instead of [undefined]
|
|
569
633
|
// to prevent errors on highlight
|
|
570
|
-
this.annotationHighlight = this.annotationEntry.map(entry => entry.models).filter(Boolean);
|
|
634
|
+
this.annotationHighlight = this.annotationEntry.map((entry) => entry.models).filter(Boolean);
|
|
571
635
|
if (payload.commitCallback) {
|
|
572
636
|
this.annotationCallback = markRaw(payload.commitCallback);
|
|
573
637
|
}
|
|
@@ -589,7 +653,7 @@ export default {
|
|
|
589
653
|
this.confirmCommentCallback = markRaw(payload.confirmComment);
|
|
590
654
|
}
|
|
591
655
|
if (this.$refs.sideBar) {
|
|
592
|
-
this.$refs.sideBar.tabClicked({id: 3, type: 'annotation'});
|
|
656
|
+
this.$refs.sideBar.tabClicked({ id: 3, type: 'annotation' });
|
|
593
657
|
this.$refs.sideBar.setDrawerOpen(true);
|
|
594
658
|
}
|
|
595
659
|
},
|
|
@@ -609,74 +673,95 @@ export default {
|
|
|
609
673
|
connectivityInfo: data.connectivityInfo,
|
|
610
674
|
resource: data.entry,
|
|
611
675
|
type: 'ConnectivityGraph',
|
|
612
|
-
label: data.title || data.label || data.entry ||'Connectivity Graph',
|
|
676
|
+
label: data.title || data.label || data.entry || 'Connectivity Graph',
|
|
613
677
|
graphPayload: { ...data },
|
|
614
678
|
mapServer: this.settingsStore.flatmapAPI,
|
|
615
679
|
sckanVersion: data.sckanVersion,
|
|
616
680
|
});
|
|
617
681
|
|
|
618
|
-
this.splitFlowStore.updateActiveView(
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
682
|
+
this.splitFlowStore.updateActiveView(
|
|
683
|
+
{
|
|
684
|
+
view: '2vertpanel',
|
|
685
|
+
entries: this.entries,
|
|
686
|
+
},
|
|
687
|
+
false,
|
|
688
|
+
);
|
|
622
689
|
|
|
623
690
|
if (previousPrimaryId && previousPrimaryId !== connectivityGraphId) {
|
|
624
|
-
this.splitFlowStore.assignOrSwapPaneWithIds(
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
691
|
+
this.splitFlowStore.assignOrSwapPaneWithIds(
|
|
692
|
+
{
|
|
693
|
+
source: connectivityGraphId,
|
|
694
|
+
target: previousPrimaryId,
|
|
695
|
+
},
|
|
696
|
+
false,
|
|
697
|
+
);
|
|
628
698
|
}
|
|
629
699
|
|
|
630
700
|
const secondPaneId = this.splitFlowStore.customLayout?.['pane-2']?.id;
|
|
631
701
|
if (secondPaneId && secondPaneId !== connectivityGraphId) {
|
|
632
|
-
this.splitFlowStore.assignOrSwapPaneWithIds(
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
702
|
+
this.splitFlowStore.assignOrSwapPaneWithIds(
|
|
703
|
+
{
|
|
704
|
+
source: connectivityGraphId,
|
|
705
|
+
target: secondPaneId,
|
|
706
|
+
},
|
|
707
|
+
false,
|
|
708
|
+
);
|
|
636
709
|
}
|
|
637
710
|
this.splitFlowStore.updateSplitPanels();
|
|
638
711
|
},
|
|
639
712
|
hoverChanged: function (data) {
|
|
640
|
-
let hoverAnatomies = [],
|
|
713
|
+
let hoverAnatomies = [],
|
|
714
|
+
hoverOrgans = [],
|
|
715
|
+
hoverDOI = '',
|
|
716
|
+
hoverConnectivity = [];
|
|
641
717
|
if (data.tabType === 'dataset') {
|
|
642
718
|
hoverAnatomies = data.anatomy ? data.anatomy : [];
|
|
643
719
|
hoverOrgans = data.organs ? data.organs : [];
|
|
644
720
|
hoverDOI = data.doi ? data.doi : '';
|
|
645
721
|
} else if (data.tabType === 'connectivity') {
|
|
646
722
|
hoverConnectivity = data.id ? [data.id] : this.connectivityHighlight;
|
|
647
|
-
hoverOrgans = data['nerve-label']
|
|
723
|
+
hoverOrgans = data['nerve-label']
|
|
724
|
+
? data['nerve-label'].flatMap((nerve) => nerve.subNerves)
|
|
725
|
+
: [];
|
|
648
726
|
} else if (data.tabType === 'annotation') {
|
|
649
727
|
hoverConnectivity = data.models ? [data.models] : this.annotationHighlight;
|
|
650
728
|
}
|
|
651
|
-
this.settingsStore.updateHoverFeatures(
|
|
652
|
-
|
|
729
|
+
this.settingsStore.updateHoverFeatures(
|
|
730
|
+
hoverAnatomies,
|
|
731
|
+
hoverOrgans,
|
|
732
|
+
hoverDOI,
|
|
733
|
+
hoverConnectivity,
|
|
734
|
+
);
|
|
735
|
+
EventBus.emit('hoverUpdate', { connectivityProcessed: this.connectivityProcessed });
|
|
653
736
|
},
|
|
654
737
|
searchChanged: function (data) {
|
|
655
738
|
if (data.tabType === 'dataset') {
|
|
656
|
-
if (data && data.type ==
|
|
739
|
+
if (data && data.type == 'reset-update') {
|
|
657
740
|
this.settingsStore.updateAppliedFacets([]);
|
|
658
741
|
}
|
|
659
|
-
if (data && data.type ==
|
|
742
|
+
if (data && data.type == 'query-update') {
|
|
660
743
|
this.search = data.value;
|
|
661
744
|
if (this.search && !this.filterTriggered) {
|
|
662
745
|
// GA Tagging
|
|
663
746
|
// Event tracking for map action search/filter data
|
|
664
747
|
Tagging.sendEvent({
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
748
|
+
event: 'interaction_event',
|
|
749
|
+
event_name: 'portal_maps_action_search',
|
|
750
|
+
category: this.search,
|
|
751
|
+
location: 'map_sidebar_dataset_search',
|
|
669
752
|
});
|
|
670
753
|
}
|
|
671
754
|
this.filterTriggered = false; // reset for next action
|
|
672
755
|
}
|
|
673
|
-
if (data && data.type ==
|
|
756
|
+
if (data && data.type == 'filter-update') {
|
|
674
757
|
this.settingsStore.updateFacets(data.value);
|
|
675
758
|
// Remove filter event from maps' popup
|
|
676
759
|
if (!this.filterTriggered) {
|
|
677
|
-
const filterValuesArray = data.value
|
|
678
|
-
|
|
679
|
-
|
|
760
|
+
const filterValuesArray = data.value
|
|
761
|
+
.filter((val) => {
|
|
762
|
+
return val.facet && val.facet.toLowerCase() !== 'show all';
|
|
763
|
+
})
|
|
764
|
+
.map((val) => val.facet);
|
|
680
765
|
const labels = filterValuesArray.map((val) => val.toLowerCase());
|
|
681
766
|
const newFacets = [...new Set([...labels])];
|
|
682
767
|
this.settingsStore.updateAppliedFacets(newFacets);
|
|
@@ -684,16 +769,16 @@ export default {
|
|
|
684
769
|
// GA Tagging
|
|
685
770
|
// Event tracking for map action search/filter data
|
|
686
771
|
Tagging.sendEvent({
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
772
|
+
event: 'interaction_event',
|
|
773
|
+
event_name: 'portal_maps_action_filter',
|
|
774
|
+
category: filterValues || 'filter_reset',
|
|
775
|
+
location: 'map_sidebar_dataset_filter',
|
|
691
776
|
});
|
|
692
777
|
}
|
|
693
778
|
this.filterTriggered = false; // reset for next action
|
|
694
779
|
}
|
|
695
780
|
} else if (data.tabType === 'connectivity') {
|
|
696
|
-
if (data && data.type ==
|
|
781
|
+
if (data && data.type == 'reset-update') {
|
|
697
782
|
const activeFlatmaps = this.getActiveFlatmaps();
|
|
698
783
|
activeFlatmaps.forEach((activeFlatmap) => {
|
|
699
784
|
activeFlatmap.resetConnectivityfilters(data.value);
|
|
@@ -706,28 +791,29 @@ export default {
|
|
|
706
791
|
activeFlatmaps.forEach((activeFlatmap) => {
|
|
707
792
|
activeFlatmap.updateConnectivityFilters(data.filter);
|
|
708
793
|
});
|
|
709
|
-
EventBus.emit(
|
|
794
|
+
EventBus.emit('connectivity-query-filter', data);
|
|
710
795
|
|
|
711
|
-
const filterValues = data.filter
|
|
796
|
+
const filterValues = data.filter
|
|
797
|
+
.filter((f) => f.facet && f.facet.toLowerCase() !== 'show all')
|
|
712
798
|
.map((f) => f.tagLabel)
|
|
713
799
|
.join(', ');
|
|
714
800
|
const searchValue = data.query;
|
|
715
801
|
|
|
716
802
|
if (filterValues) {
|
|
717
803
|
Tagging.sendEvent({
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
804
|
+
event: 'interaction_event',
|
|
805
|
+
event_name: 'portal_maps_action_filter',
|
|
806
|
+
category: filterValues,
|
|
807
|
+
location: 'map_sidebar_connectivity_filter',
|
|
722
808
|
});
|
|
723
809
|
}
|
|
724
810
|
|
|
725
811
|
if (searchValue) {
|
|
726
812
|
Tagging.sendEvent({
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
813
|
+
event: 'interaction_event',
|
|
814
|
+
event_name: 'portal_maps_action_search',
|
|
815
|
+
category: searchValue,
|
|
816
|
+
location: 'map_sidebar_connectivity_search',
|
|
731
817
|
});
|
|
732
818
|
}
|
|
733
819
|
}
|
|
@@ -735,14 +821,14 @@ export default {
|
|
|
735
821
|
},
|
|
736
822
|
updateMarkers: function (data) {
|
|
737
823
|
this.settingsStore.updateMarkers(data);
|
|
738
|
-
EventBus.emit(
|
|
824
|
+
EventBus.emit('markerUpdate');
|
|
739
825
|
},
|
|
740
826
|
updateScaffoldMarkers: function (data) {
|
|
741
827
|
this.settingsStore.updateNumberOfDatasetsForFacets(data);
|
|
742
828
|
},
|
|
743
|
-
getNewEntryId: function() {
|
|
829
|
+
getNewEntryId: function () {
|
|
744
830
|
if (this.entries.length) {
|
|
745
|
-
return
|
|
831
|
+
return this.entries[this.entries.length - 1].id + 1;
|
|
746
832
|
}
|
|
747
833
|
return 1;
|
|
748
834
|
},
|
|
@@ -755,7 +841,7 @@ export default {
|
|
|
755
841
|
newEntry.viewUrl = undefined;
|
|
756
842
|
newEntry.state = undefined;
|
|
757
843
|
Object.assign(newEntry, data);
|
|
758
|
-
newEntry.mode =
|
|
844
|
+
newEntry.mode = 'normal';
|
|
759
845
|
newEntry.id = this.getNewEntryId();
|
|
760
846
|
newEntry.discoverId = data.discoverId;
|
|
761
847
|
this.entriesStore.addNewEntry(newEntry);
|
|
@@ -771,7 +857,7 @@ export default {
|
|
|
771
857
|
const entry = await getNewMapEntry(type, this.settingsStore.sparcApi);
|
|
772
858
|
this.createNewEntry(entry);
|
|
773
859
|
if (entry.contextCard) {
|
|
774
|
-
EventBus.emit(
|
|
860
|
+
EventBus.emit('contextUpdate', entry.contextCard);
|
|
775
861
|
}
|
|
776
862
|
},
|
|
777
863
|
openSearch: function (facets, query) {
|
|
@@ -784,12 +870,12 @@ export default {
|
|
|
784
870
|
this._facets = facets;
|
|
785
871
|
if (this.$refs && this.$refs.sideBar) {
|
|
786
872
|
this.$refs.sideBar.openSearch(facets, query);
|
|
787
|
-
this.$refs.sideBar.tabClicked({id:
|
|
873
|
+
this.$refs.sideBar.tabClicked({ id: 1, type: 'datasetExplorer' });
|
|
788
874
|
}
|
|
789
875
|
this.startUp = false;
|
|
790
876
|
},
|
|
791
877
|
onFullscreen: function (val) {
|
|
792
|
-
this.$emit(
|
|
878
|
+
this.$emit('onFullscreen', val);
|
|
793
879
|
},
|
|
794
880
|
resetApp: function () {
|
|
795
881
|
this.setState(initialDefaultState());
|
|
@@ -800,39 +886,118 @@ export default {
|
|
|
800
886
|
restoreConnectivityEntries: function (connectivityEntries) {
|
|
801
887
|
const activeFlatmaps = this.getActiveFlatmaps();
|
|
802
888
|
activeFlatmaps.forEach((activeFlatmap) => {
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
889
|
+
if (!activeFlatmap.mapImp) return;
|
|
890
|
+
const featureIds = connectivityEntries.reduce((acc, entry) => {
|
|
891
|
+
// A given flatmap may not contain every restored connectivity id
|
|
892
|
+
// (e.g. it belongs to another species/map); skip those instead of
|
|
893
|
+
// throwing, which would otherwise abort processing for this map
|
|
894
|
+
// entirely and leave its other entries stuck loading forever.
|
|
895
|
+
try {
|
|
896
|
+
const featureId = activeFlatmap.mapImp.modelFeatureIds(entry)[0];
|
|
897
|
+
if (!featureId) return acc;
|
|
898
|
+
const feature = activeFlatmap.mapImp.featureProperties(featureId);
|
|
899
|
+
if (!feature) return acc;
|
|
900
|
+
acc.push({
|
|
901
|
+
resource: [feature.models],
|
|
902
|
+
feature: feature,
|
|
903
|
+
label: feature.label,
|
|
904
|
+
provenanceTaxonomy: feature.taxons,
|
|
905
|
+
alert: feature.alert,
|
|
906
|
+
});
|
|
907
|
+
} catch (_error) {
|
|
908
|
+
// ignore entries that cannot be resolved in this map
|
|
909
|
+
}
|
|
910
|
+
return acc;
|
|
911
|
+
}, []);
|
|
912
|
+
if (featureIds.length) {
|
|
913
|
+
activeFlatmap.checkAndCreatePopups(featureIds, true);
|
|
914
|
+
}
|
|
816
915
|
});
|
|
916
|
+
|
|
917
|
+
// Restore Scaffold-only connectivity entries (e.g. carrying nerve-label)
|
|
918
|
+
// via each Scaffold's own resolved knowledge, since Scaffolds aren't
|
|
919
|
+
// flatmaps and are otherwise never asked to restore their entries.
|
|
920
|
+
const activeScaffolds = this.getActiveScaffolds();
|
|
921
|
+
activeScaffolds.forEach((scaffold) => {
|
|
922
|
+
const matched = (scaffold.nervesKnowledge || []).filter((knowledge) =>
|
|
923
|
+
connectivityEntries.includes(knowledge.id),
|
|
924
|
+
);
|
|
925
|
+
if (matched.length) {
|
|
926
|
+
scaffold.getKnowledgeTooltip({ data: matched, type: scaffold.entry });
|
|
927
|
+
}
|
|
928
|
+
});
|
|
929
|
+
},
|
|
930
|
+
// Maps a sidebar activeTabId to the tab 'type' expected by tabClicked.
|
|
931
|
+
getSidebarTabType: function (tabId) {
|
|
932
|
+
if (tabId === 1) return 'datasetExplorer';
|
|
933
|
+
if (tabId === 3) return 'annotation';
|
|
934
|
+
return 'connectivityExplorer';
|
|
935
|
+
},
|
|
936
|
+
// Called once every restored connectivityEntry has resolved (or we've
|
|
937
|
+
// given up retrying): shows only the restored/filtered connectivities
|
|
938
|
+
// (not the full knowledge list) and opens the sidebar on the tab stored
|
|
939
|
+
// in the permalink state.
|
|
940
|
+
finalizeConnectivityRestore: function (sidebarState) {
|
|
941
|
+
this.restoringConnectivityState = false;
|
|
942
|
+
this.connectivityKnowledge = this.connectivityEntry;
|
|
943
|
+
if (this.connectivityEntry.every((entry) => entry.ready)) {
|
|
944
|
+
this.connectivityHighlight = this.connectivityEntry.map((entry) => entry.id);
|
|
945
|
+
this.connectivityProcessed = true;
|
|
946
|
+
}
|
|
947
|
+
if (this.$refs.sideBar) {
|
|
948
|
+
const tabId = sidebarState?.activeTabId ?? 2;
|
|
949
|
+
this.$refs.sideBar.tabClicked({ id: tabId, type: this.getSidebarTabType(tabId) });
|
|
950
|
+
this.$refs.sideBar.setDrawerOpen(true);
|
|
951
|
+
}
|
|
952
|
+
},
|
|
953
|
+
// Shared completion check for the connectivity restore loop:
|
|
954
|
+
// finalises the restore once every restored entry has resolved,
|
|
955
|
+
// or gives up after enough retry attempts (an id may never be resolvable by any active viewer).
|
|
956
|
+
// Called both from the connectivity-knowledge retry ticks and from openConnectivityInfo,
|
|
957
|
+
// since entries resolve asynchronously through connectivity-info-open rather than the knowledge events.
|
|
958
|
+
checkConnectivityRestoreComplete: function (sidebarState) {
|
|
959
|
+
if (this.sidebarStateRestored || !sidebarState?.connectivityEntries?.length) {
|
|
960
|
+
return;
|
|
961
|
+
}
|
|
962
|
+
// Multiple viewers resolve connectivity knowledge independently,
|
|
963
|
+
// so keep retrying until all restored entries have resolved.
|
|
964
|
+
// A becoming-active flatmap alone is not enough (its knowledge may still be loading),
|
|
965
|
+
// so only finalise on that basis after enough attempts
|
|
966
|
+
// to avoid getting stuck if an id can never be resolved by any viewer.
|
|
967
|
+
const allEntriesReady =
|
|
968
|
+
this.connectivityEntry.length >= sidebarState.connectivityEntries.length &&
|
|
969
|
+
this.connectivityEntry.every((entry) => entry.ready);
|
|
970
|
+
const giveUp = this.restoreAttempts >= 30;
|
|
971
|
+
if (allEntriesReady || giveUp) {
|
|
972
|
+
this.sidebarStateRestored = true;
|
|
973
|
+
this.finalizeConnectivityRestore(sidebarState);
|
|
974
|
+
}
|
|
817
975
|
},
|
|
818
976
|
restoreSidebarState: function (state) {
|
|
819
977
|
// Restore sidebar state only if
|
|
820
978
|
// - there is sidebar state
|
|
821
979
|
// - sidebar component is loaded
|
|
822
|
-
// - connectivity knowledge is loaded
|
|
823
980
|
// - if sidebar state is not restored yet
|
|
824
981
|
const sidebarState = state?.sidebar;
|
|
825
|
-
if (
|
|
982
|
+
if (
|
|
983
|
+
!this.sidebarStateRestored &&
|
|
984
|
+
sidebarState &&
|
|
985
|
+
this.$refs.sideBar &&
|
|
986
|
+
this.connectivityKnowledge?.length
|
|
987
|
+
) {
|
|
826
988
|
if (sidebarState.connectivityEntries?.length) {
|
|
827
989
|
this.restoreConnectivityEntries(sidebarState.connectivityEntries);
|
|
990
|
+
this.restoreAttempts += 1;
|
|
991
|
+
this.checkConnectivityRestoreComplete(sidebarState);
|
|
828
992
|
} else if (sidebarState.annotationEntries?.length && state.annotationId) {
|
|
829
993
|
// Restore annotation state only if the state has annotationId
|
|
830
994
|
this.restoreConnectivityEntries(sidebarState.annotationEntries);
|
|
831
995
|
this.sidebarAnnotationState = true;
|
|
996
|
+
this.sidebarStateRestored = true;
|
|
832
997
|
} else {
|
|
833
998
|
this.$refs.sideBar.setState(sidebarState);
|
|
999
|
+
this.sidebarStateRestored = true;
|
|
834
1000
|
}
|
|
835
|
-
this.sidebarStateRestored = true;
|
|
836
1001
|
}
|
|
837
1002
|
},
|
|
838
1003
|
setState: function (state) {
|
|
@@ -840,9 +1005,23 @@ export default {
|
|
|
840
1005
|
//Support both old and new permalink.
|
|
841
1006
|
if (state.splitFlow) {
|
|
842
1007
|
this.splitFlowStore.setState(state.splitFlow);
|
|
1008
|
+
} else {
|
|
1009
|
+
this.entries.forEach((entry) => this.splitFlowStore.setIdToPrimaryPane(entry.id));
|
|
843
1010
|
}
|
|
844
|
-
|
|
845
|
-
|
|
1011
|
+
|
|
1012
|
+
// Seed placeholder (not-ready) connectivity entries immediately so the
|
|
1013
|
+
// sidebar shows a loading count right away, instead of either an empty
|
|
1014
|
+
// list or a flash of the full/unfiltered connectivity knowledge while
|
|
1015
|
+
// the active viewers and their connectivity knowledge are still loading.
|
|
1016
|
+
if (state?.sidebar?.connectivityEntries?.length && !this.sidebarStateRestored) {
|
|
1017
|
+
this.restoringConnectivityState = true;
|
|
1018
|
+
this.connectivityEntry = state.sidebar.connectivityEntries.map((id) => ({
|
|
1019
|
+
id,
|
|
1020
|
+
label: '',
|
|
1021
|
+
featureId: [id],
|
|
1022
|
+
ready: false,
|
|
1023
|
+
}));
|
|
1024
|
+
this.connectivityKnowledge = this.connectivityEntry;
|
|
846
1025
|
}
|
|
847
1026
|
|
|
848
1027
|
this.restoreSidebarState(state);
|
|
@@ -857,12 +1036,10 @@ export default {
|
|
|
857
1036
|
const entry = state.entries[i];
|
|
858
1037
|
entry.state = dialogStates[i];
|
|
859
1038
|
//We do not want to serialise the following properties
|
|
860
|
-
if (entry.type ===
|
|
861
|
-
|
|
862
|
-
if (entry.type === "MultiFlatmap" && "uberonId" in entry)
|
|
863
|
-
delete entry.uberonId;
|
|
1039
|
+
if (entry.type === 'Scaffold' && 'viewUrl' in entry) delete entry.viewUrl;
|
|
1040
|
+
if (entry.type === 'MultiFlatmap' && 'uberonId' in entry) delete entry.uberonId;
|
|
864
1041
|
if (anonymousAnnotations === false) {
|
|
865
|
-
if (entry.type ===
|
|
1042
|
+
if (entry.type === 'Scaffold' && entry?.state?.offlineAnnotations) {
|
|
866
1043
|
delete entry.state.offlineAnnotations;
|
|
867
1044
|
} else if (entry?.state?.state?.offlineAnnotations) {
|
|
868
1045
|
delete entry.state.state.offlineAnnotations;
|
|
@@ -882,20 +1059,20 @@ export default {
|
|
|
882
1059
|
this.entriesStore.destroyEntry(index);
|
|
883
1060
|
},
|
|
884
1061
|
resourceSelected: function (result) {
|
|
885
|
-
this.$emit(
|
|
1062
|
+
this.$emit('resource-selected', result);
|
|
886
1063
|
},
|
|
887
|
-
speciesChanged: function (
|
|
1064
|
+
speciesChanged: function (_species) {
|
|
888
1065
|
if (this.$refs.sideBar) {
|
|
889
1066
|
// Use to update the connectivity when switch species
|
|
890
1067
|
// Wait for provenance info with uuid update
|
|
891
1068
|
this.$nextTick(() => {
|
|
892
1069
|
EventBus.emit('species-layout-connectivity-update');
|
|
893
1070
|
this.$refs.sideBar.close();
|
|
894
|
-
})
|
|
1071
|
+
});
|
|
895
1072
|
}
|
|
896
1073
|
},
|
|
897
1074
|
contextUpdate: function (payload) {
|
|
898
|
-
EventBus.emit(
|
|
1075
|
+
EventBus.emit('contextUpdate', payload);
|
|
899
1076
|
},
|
|
900
1077
|
datalinkClicked: function (payload) {
|
|
901
1078
|
// payload is dataset URL
|
|
@@ -904,37 +1081,37 @@ export default {
|
|
|
904
1081
|
const substringB = '?type=dataset';
|
|
905
1082
|
const datasetId = datasetURL.substring(
|
|
906
1083
|
datasetURL.indexOf(substringA) + substringA.length,
|
|
907
|
-
datasetURL.indexOf(substringB)
|
|
1084
|
+
datasetURL.indexOf(substringB),
|
|
908
1085
|
);
|
|
909
1086
|
|
|
910
1087
|
// GA Tagging
|
|
911
1088
|
// Event tracking for map sidebar gallery dataset click
|
|
912
1089
|
Tagging.sendEvent({
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
1090
|
+
event: 'interaction_event',
|
|
1091
|
+
event_name: 'portal_maps_gallery_click',
|
|
1092
|
+
category: datasetURL,
|
|
1093
|
+
location: 'map_sidebar_gallery',
|
|
1094
|
+
dataset_id: datasetId || '',
|
|
918
1095
|
});
|
|
919
1096
|
},
|
|
920
|
-
onAnnotationSubmitted: function(annotation) {
|
|
1097
|
+
onAnnotationSubmitted: function (annotation) {
|
|
921
1098
|
if (this.annotationCallback) {
|
|
922
1099
|
this.annotationCallback(annotation);
|
|
923
1100
|
} else if (this.confirmCommentCallback) {
|
|
924
|
-
this.confirmCommentCallback(annotation)
|
|
1101
|
+
this.confirmCommentCallback(annotation);
|
|
925
1102
|
}
|
|
926
1103
|
},
|
|
927
|
-
onConfirmCreate: function(payload) {
|
|
1104
|
+
onConfirmCreate: function (payload) {
|
|
928
1105
|
if (this.confirmCreateCallback) {
|
|
929
1106
|
this.confirmCreateCallback(payload);
|
|
930
1107
|
}
|
|
931
1108
|
},
|
|
932
|
-
onCancelCreate: function() {
|
|
1109
|
+
onCancelCreate: function () {
|
|
933
1110
|
if (this.cancelCreateCallback) {
|
|
934
1111
|
this.cancelCreateCallback();
|
|
935
1112
|
}
|
|
936
1113
|
},
|
|
937
|
-
onConfirmDelete: function(payload) {
|
|
1114
|
+
onConfirmDelete: function (payload) {
|
|
938
1115
|
if (this.confirmDeleteCallback) {
|
|
939
1116
|
this.confirmDeleteCallback(payload);
|
|
940
1117
|
}
|
|
@@ -954,7 +1131,7 @@ export default {
|
|
|
954
1131
|
this.$refs.dialogToolbar.loadGlobalSettings();
|
|
955
1132
|
},
|
|
956
1133
|
onSidebarTabClosed: function (tab) {
|
|
957
|
-
if (tab.id === 3 && tab.type ===
|
|
1134
|
+
if (tab.id === 3 && tab.type === 'annotation') {
|
|
958
1135
|
EventBus.emit('sidebar-annotation-close');
|
|
959
1136
|
}
|
|
960
1137
|
},
|
|
@@ -979,16 +1156,16 @@ export default {
|
|
|
979
1156
|
this._externalStateSet = false;
|
|
980
1157
|
},
|
|
981
1158
|
mounted: function () {
|
|
982
|
-
EventBus.on(
|
|
1159
|
+
EventBus.on('CreateNewEntry', (newView) => {
|
|
983
1160
|
this.createNewEntry(newView);
|
|
984
1161
|
});
|
|
985
|
-
EventBus.on(
|
|
1162
|
+
EventBus.on('RemoveEntryRequest', (id) => {
|
|
986
1163
|
this.removeEntry(id);
|
|
987
1164
|
});
|
|
988
|
-
EventBus.on(
|
|
1165
|
+
EventBus.on('PopoverActionClick', (payload) => {
|
|
989
1166
|
this.actionClick(payload);
|
|
990
1167
|
});
|
|
991
|
-
EventBus.on('annotation-open', payload => {
|
|
1168
|
+
EventBus.on('annotation-open', (payload) => {
|
|
992
1169
|
this.openAnnotation(payload);
|
|
993
1170
|
});
|
|
994
1171
|
EventBus.on('sidebar-annotation-close', () => {
|
|
@@ -1000,7 +1177,7 @@ export default {
|
|
|
1000
1177
|
// open the anootation tab and return.
|
|
1001
1178
|
if (this.sidebarAnnotationState && viewingMode === 'Annotation') {
|
|
1002
1179
|
this.sidebarAnnotationState = false;
|
|
1003
|
-
this.$refs.sideBar.tabClicked({id: 3, type: 'annotation'});
|
|
1180
|
+
this.$refs.sideBar.tabClicked({ id: 3, type: 'annotation' });
|
|
1004
1181
|
return;
|
|
1005
1182
|
}
|
|
1006
1183
|
|
|
@@ -1008,10 +1185,10 @@ export default {
|
|
|
1008
1185
|
this.createData = {};
|
|
1009
1186
|
|
|
1010
1187
|
if (this.$refs.sideBar) {
|
|
1011
|
-
if (interactiveMode ===
|
|
1012
|
-
this.$refs.sideBar.tabClicked({id:
|
|
1013
|
-
} else if (interactiveMode ===
|
|
1014
|
-
this.$refs.sideBar.tabClicked({id:
|
|
1188
|
+
if (interactiveMode === 'dataset') {
|
|
1189
|
+
this.$refs.sideBar.tabClicked({ id: 1, type: 'datasetExplorer' });
|
|
1190
|
+
} else if (interactiveMode === 'connectivity') {
|
|
1191
|
+
this.$refs.sideBar.tabClicked({ id: 2, type: 'connectivityExplorer' });
|
|
1015
1192
|
}
|
|
1016
1193
|
|
|
1017
1194
|
this.$refs.sideBar.closeConnectivity();
|
|
@@ -1021,21 +1198,21 @@ export default {
|
|
|
1021
1198
|
EventBus.on('update-offline-annotation-enabled', (payload) => {
|
|
1022
1199
|
this.settingsStore.updateOfflineAnnotationEnabled(payload);
|
|
1023
1200
|
});
|
|
1024
|
-
EventBus.on('connectivity-info-open', payload => {
|
|
1201
|
+
EventBus.on('connectivity-info-open', (payload) => {
|
|
1025
1202
|
this.openConnectivityInfo(payload);
|
|
1026
1203
|
});
|
|
1027
|
-
EventBus.on('connectivity-info-close',
|
|
1204
|
+
EventBus.on('connectivity-info-close', (_payload) => {
|
|
1028
1205
|
if (this.$refs.sideBar) {
|
|
1029
1206
|
this.connectivityProcessed = false;
|
|
1030
1207
|
this.$refs.sideBar.resetConnectivitySearch();
|
|
1031
1208
|
}
|
|
1032
1209
|
});
|
|
1033
|
-
EventBus.on('connectivity-error', payload => {
|
|
1210
|
+
EventBus.on('connectivity-error', (payload) => {
|
|
1034
1211
|
if (this.$refs.sideBar) {
|
|
1035
1212
|
this.$refs.sideBar.updateConnectivityError(payload.data);
|
|
1036
1213
|
}
|
|
1037
1214
|
});
|
|
1038
|
-
EventBus.on('neuron-connection-feature-click', payload => {
|
|
1215
|
+
EventBus.on('neuron-connection-feature-click', (payload) => {
|
|
1039
1216
|
if (this.$refs.sideBar) {
|
|
1040
1217
|
const { filters, search } = payload;
|
|
1041
1218
|
this.$refs.sideBar.openConnectivitySearch(filters, search);
|
|
@@ -1043,36 +1220,44 @@ export default {
|
|
|
1043
1220
|
this.$refs.sideBar.setDrawerOpen(true);
|
|
1044
1221
|
}
|
|
1045
1222
|
});
|
|
1046
|
-
EventBus.on(
|
|
1223
|
+
EventBus.on('OpenNewMap', (type) => {
|
|
1047
1224
|
this.updateFlatmapMinimap();
|
|
1048
1225
|
this.openNewMap(type);
|
|
1049
1226
|
});
|
|
1050
|
-
EventBus.on(
|
|
1227
|
+
EventBus.on('startHelp', () => {
|
|
1051
1228
|
if (this.$refs.sideBar) {
|
|
1052
1229
|
this.$refs.sideBar.close();
|
|
1053
1230
|
}
|
|
1054
1231
|
});
|
|
1055
|
-
EventBus.on(
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1232
|
+
EventBus.on('connectivity-knowledge', (payload) => {
|
|
1233
|
+
// Ignore the default/global connectivity dump (emitted when no active
|
|
1234
|
+
// viewer's map/species keys are resolved yet) while restoring a
|
|
1235
|
+
// permalink's sidebar connectivityEntries, otherwise the sidebar would
|
|
1236
|
+
// briefly flash the entire, unfiltered connectivity list.
|
|
1237
|
+
if (!(payload.isDefaultKnowledge && this.restoringConnectivityState)) {
|
|
1238
|
+
this.connectivityKnowledge = payload.data;
|
|
1239
|
+
this.connectivityHighlight = payload.highlight;
|
|
1240
|
+
this.connectivityProcessed = payload.processed;
|
|
1241
|
+
}
|
|
1059
1242
|
|
|
1060
1243
|
// Restore sidebar state if it exists and not restored yet
|
|
1061
1244
|
// after loading connectivity knowledge
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
this.$refs.sideBar.tabClicked({id:
|
|
1245
|
+
if (!this.sidebarStateRestored) {
|
|
1246
|
+
this.restoreSidebarState(this.state);
|
|
1247
|
+
}
|
|
1248
|
+
});
|
|
1249
|
+
EventBus.on('modeUpdate', (payload) => {
|
|
1250
|
+
if (payload === 'dataset') {
|
|
1251
|
+
this.$refs.sideBar.tabClicked({ id: 1, type: 'datasetExplorer' });
|
|
1252
|
+
} else if (payload === 'connectivity') {
|
|
1253
|
+
this.$refs.sideBar.tabClicked({ id: 2, type: 'connectivityExplorer' });
|
|
1069
1254
|
}
|
|
1070
|
-
})
|
|
1071
|
-
EventBus.on(
|
|
1255
|
+
});
|
|
1256
|
+
EventBus.on('connectivity-filter-options', (payload) => {
|
|
1072
1257
|
this.filterOptions = payload;
|
|
1073
|
-
})
|
|
1258
|
+
});
|
|
1074
1259
|
this.$nextTick(() => {
|
|
1075
|
-
if (this.search ===
|
|
1260
|
+
if (this.search === '' && this._facets.length === 0) {
|
|
1076
1261
|
if (this.$refs.sideBar) {
|
|
1077
1262
|
this.$refs.sideBar.close();
|
|
1078
1263
|
}
|
|
@@ -1095,7 +1280,7 @@ export default {
|
|
|
1095
1280
|
FLATMAPAPI_LOCATION: this.settingsStore.flatmapAPI,
|
|
1096
1281
|
};
|
|
1097
1282
|
},
|
|
1098
|
-
entries: function() {
|
|
1283
|
+
entries: function () {
|
|
1099
1284
|
return this.entriesStore.entries;
|
|
1100
1285
|
},
|
|
1101
1286
|
},
|
|
@@ -1139,5 +1324,4 @@ export default {
|
|
|
1139
1324
|
}
|
|
1140
1325
|
}
|
|
1141
1326
|
}
|
|
1142
|
-
|
|
1143
1327
|
</style>
|