@abi-software/map-side-bar 2.8.3-beta.5 → 2.8.3-beta.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abi-software/map-side-bar",
3
- "version": "2.8.3-beta.5",
3
+ "version": "2.8.3-beta.7",
4
4
  "files": [
5
5
  "dist/*",
6
6
  "src/*",
@@ -39,7 +39,7 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "@abi-software/gallery": "^1.1.2",
42
- "@abi-software/map-utilities": "^1.5.0",
42
+ "@abi-software/map-utilities": "^1.6.0-beta.0",
43
43
  "@abi-software/svg-sprite": "^1.0.1",
44
44
  "@element-plus/icons-vue": "^2.3.1",
45
45
  "algoliasearch": "^4.10.5",
@@ -12,6 +12,7 @@
12
12
  class="annotation-popup"
13
13
  :annotationEntry="annotationEntry"
14
14
  @annotation="$emit('annotation', $event)"
15
+ @hover-changed="$emit('hover-changed', $event)"
15
16
  />
16
17
  <div v-if="createData && createData.toBeDeleted" class="delete-container">
17
18
  <el-row>
@@ -75,6 +76,7 @@ export default {
75
76
  data: function () {
76
77
  return {
77
78
  ElIconDelete: shallowRef(ElIconDelete),
79
+ annotationPopupData: null,
78
80
  };
79
81
  },
80
82
  }
@@ -1,11 +1,7 @@
1
1
  <template>
2
- <el-card
3
- :body-style="bodyStyle"
4
- class="content-card"
5
- @mouseleave="hoverChanged(undefined)"
6
- >
2
+ <el-card :body-style="bodyStyle" class="content-card">
7
3
  <template #header>
8
- <div class="header">
4
+ <div class="header" @mouseleave="hoverChanged(undefined)">
9
5
  <el-input
10
6
  class="search-input"
11
7
  placeholder="Search"
@@ -30,6 +26,10 @@
30
26
  >
31
27
  Reset
32
28
  </el-button>
29
+ <el-radio-group v-model="filterVisibility">
30
+ <el-radio :value="true">Focused</el-radio>
31
+ <el-radio :value="false">Contextual</el-radio>
32
+ </el-radio-group>
33
33
  </div>
34
34
  </template>
35
35
  <SearchFilters
@@ -51,7 +51,7 @@
51
51
  class="content scrollbar"
52
52
  v-loading="loadingCards || initLoading"
53
53
  ref="content"
54
- @mouseleave="hoverChanged(undefined)"
54
+ @mouseleave="onHoverChanged($event, undefined)"
55
55
  >
56
56
  <div class="error-feedback" v-if="results.length === 0 && !loadingCards">
57
57
  No results found - Please change your search / filter criteria.
@@ -61,7 +61,7 @@
61
61
  :key="result.id"
62
62
  :ref="'stepItem-' + result.id"
63
63
  class="step-item"
64
- @mouseenter="hoverChanged(result)"
64
+ @mouseenter="onHoverChanged($event, result)"
65
65
  >
66
66
  <ConnectivityCard
67
67
  v-show="expanded !== result.id"
@@ -78,8 +78,8 @@
78
78
  :availableAnatomyFacets="availableAnatomyFacets"
79
79
  :envVars="envVars"
80
80
  :withCloseButton="true"
81
- @show-connectivity="$emit('show-connectivity', $event)"
82
- @show-reference-connectivities="$emit('show-reference-connectivities', $event)"
81
+ @show-connectivity="onShowConnectivity"
82
+ @show-reference-connectivities="onShowReferenceConnectivities"
83
83
  @connectivity-clicked="onConnectivityClicked"
84
84
  @connectivity-hovered="$emit('connectivity-hovered', $event)"
85
85
  @loaded="onConnectivityInfoLoaded(result)"
@@ -175,9 +175,11 @@ export default {
175
175
  display: "flex",
176
176
  },
177
177
  cascaderIsReady: false,
178
- displayConnectivity: false,
178
+ freezeTimeout: undefined,
179
+ freezed: false,
179
180
  initLoading: true,
180
181
  expanded: "",
182
+ filterVisibility: true,
181
183
  expandedData: null,
182
184
  };
183
185
  },
@@ -188,7 +190,11 @@ export default {
188
190
  numberOfHits: this.numberOfHits,
189
191
  filterFacets: this.filter,
190
192
  options: this.connectivityFilterOptions,
191
- showFilters: true
193
+ showFilters: true,
194
+ helper: {
195
+ within: "'CNS' OR 'Local circuit neuron'",
196
+ between: "'Somatic lower motor' AND 'Human'"
197
+ }
192
198
  };
193
199
  },
194
200
  paginatedResults: function () {
@@ -232,8 +238,29 @@ export default {
232
238
  paginatedResults: function () {
233
239
  this.loadingCards = false;
234
240
  },
241
+ filterVisibility: function (state) {
242
+ this.filterVisibility = state;
243
+ this.$emit('filter-visibility', this.filterVisibility);
244
+ },
235
245
  },
236
246
  methods: {
247
+ freezeHoverChange: function () {
248
+ this.freezed = true;
249
+ if (this.freezeTimeout) {
250
+ clearTimeout(this.freezeTimeout);
251
+ }
252
+ this.freezeTimeout = setTimeout(() => {
253
+ this.freezed = false;
254
+ }, 3000)
255
+ },
256
+ onShowConnectivity: function (data) {
257
+ this.freezeHoverChange();
258
+ this.$emit('show-connectivity', data);
259
+ },
260
+ onShowReferenceConnectivities: function (data) {
261
+ this.freezeHoverChange();
262
+ this.$emit('show-reference-connectivities', data);
263
+ },
237
264
  onConnectivityClicked: function (data) {
238
265
  this.searchInput = data.query;
239
266
  this.filter = data.filter;
@@ -262,16 +289,28 @@ export default {
262
289
  });
263
290
  }
264
291
  },
265
- hoverChanged: function (data) {
266
- let payload = { tabType: "connectivity" };
292
+ onHoverChanged: function (event, data) {
293
+ const { target } = event;
267
294
 
268
- if (data) {
269
- payload = {...payload, ...data};
270
- } else if (this.expandedData) {
271
- payload = {...payload, ...this.expandedData};
295
+ // mouseleave event won't trigger if the connectivity explorer tab is not in view
296
+ // e.g., switching to annotation tab on item click
297
+ if (data || (target && target.checkVisibility())) {
298
+ this.hoverChanged(data)
299
+ }
300
+ },
301
+ hoverChanged: function (data) {
302
+ // disable hover changes when show connectivity is clicked
303
+ if (!this.freezed) {
304
+ let payload = { tabType: "connectivity" };
305
+
306
+ if (data) {
307
+ payload = {...payload, ...data};
308
+ } else if (this.expandedData) {
309
+ payload = {...payload, ...this.expandedData};
310
+ }
311
+
312
+ this.$emit("hover-changed", payload);
272
313
  }
273
-
274
- this.$emit("hover-changed", payload);
275
314
  },
276
315
  resetSearch: function () {
277
316
  this.numberOfHits = 0;
@@ -280,7 +319,7 @@ export default {
280
319
  },
281
320
  resetSearchIfNoActiveSearch: function() {
282
321
  const hasValidFacet = this.filter.some(f => f.facet !== "Show all");
283
- if (!this.searchInput && !hasValidFacet) {
322
+ if ((!this.searchInput && !hasValidFacet) || this.numberOfHits === 0) {
284
323
  this.openSearch([], '');
285
324
  }
286
325
  },
@@ -495,6 +534,9 @@ export default {
495
534
  }
496
535
 
497
536
  .header {
537
+ display: flex;
538
+ align-items: center;
539
+
498
540
  .el-button {
499
541
  font-family: inherit;
500
542
 
@@ -502,7 +544,19 @@ export default {
502
544
  &:focus {
503
545
  background: $app-primary-color;
504
546
  box-shadow: -3px 2px 4px #00000040;
505
- color: #fff;
547
+ color: #ffffff;
548
+ }
549
+ }
550
+
551
+ .el-radio-group {
552
+ display: flex;
553
+ flex-direction: column;
554
+ align-items: flex-start;
555
+
556
+ .el-radio {
557
+ color: #ffffff;
558
+ margin-left: 20px;
559
+ height: 20px;
506
560
  }
507
561
  }
508
562
  }
@@ -9,7 +9,7 @@
9
9
  closable
10
10
  @close="cascadeTagClose(presentTags[0])"
11
11
  >
12
- <p class="tag-text">{{ presentTags[0] }}</p>
12
+ <span class="tag-text">{{ presentTags[0] }}</span>
13
13
  </el-tag>
14
14
  <el-popover
15
15
  v-if="presentTags.length > 1"
@@ -61,7 +61,20 @@
61
61
  @expand-change="cascadeExpandChange"
62
62
  :show-all-levels="true"
63
63
  popper-class="sidebar-cascader-popper"
64
- />
64
+ >
65
+ <template #default="{ node, data }">
66
+ <el-row>
67
+ <el-col :span="4" v-if="hasLineStyles(data)">
68
+ <div class="path-visual" :style="getLineStyles(data)"></div>
69
+ </el-col>
70
+ <el-col :span="20">
71
+ <div :style="getBackgroundStyles(data)">
72
+ {{ data.label }}
73
+ </div>
74
+ </el-col>
75
+ </el-row>
76
+ </template>
77
+ </el-cascader>
65
78
  <div v-if="showFiltersText" class="filter-default-value">Filters</div>
66
79
  <el-popover
67
80
  title="How do filters work?"
@@ -75,12 +88,12 @@
75
88
  <div>
76
89
  <strong>Within categories:</strong> OR
77
90
  <br />
78
- example: 'heart' OR 'colon'
91
+ example: {{ entry.helper.within }}
79
92
  <br />
80
93
  <br />
81
94
  <strong>Between categories:</strong> AND
82
95
  <br />
83
- example: 'rat' AND 'lung'
96
+ example: {{ entry.helper.between }}
84
97
  </div>
85
98
  </el-popover>
86
99
  </span>
@@ -834,8 +847,8 @@ export default {
834
847
  result.push(validatedFilter)
835
848
  terms.push(validatedFilter.term)
836
849
  }
837
- })
838
- // make sure unused filter terms' show all checkbox is always checked
850
+ })
851
+ // make sure unused filter terms' show all checkbox is always checked
839
852
  this.options.forEach((option)=>{
840
853
  if (!terms.includes(option.label)) {
841
854
  result.push({
@@ -851,6 +864,26 @@ export default {
851
864
  }
852
865
  return []
853
866
  },
867
+ hasLineStyles: function(item) {
868
+ return 'colour' in item && item.colourStyle === 'line'
869
+ },
870
+ getLineStyles: function (item) {
871
+ if ('colour' in item && item.colourStyle === 'line') {
872
+ if ('dashed' in item && item.dashed === true) {
873
+ const background = `repeating-linear-gradient(90deg,${item.colour},${item.colour} 6px,transparent 0,transparent 9px)`
874
+ return { background }
875
+ } else {
876
+ return { background: item.colour }
877
+ }
878
+ }
879
+ return { display: 'None' }
880
+ },
881
+ getBackgroundStyles: function (item) {
882
+ if ('colour' in item && item.colourStyle === 'background') {
883
+ return { background: item.colour }
884
+ }
885
+ return {}
886
+ },
854
887
  },
855
888
  mounted: function () {
856
889
  this.algoliaClient = markRaw(new AlgoliaClient(
@@ -886,6 +919,7 @@ export default {
886
919
  }
887
920
 
888
921
  .tag-text {
922
+ display: block;
889
923
  max-width: 75px;
890
924
  white-space: nowrap;
891
925
  overflow: hidden;
@@ -1079,4 +1113,11 @@ export default {
1079
1113
  border-right-color: transparent !important;
1080
1114
  }
1081
1115
  }
1116
+ .path-visual {
1117
+ margin: 3px 0;
1118
+ height: 3px;
1119
+ width: 25px;
1120
+ margin-right: 5px;
1121
+ display: inline-block;
1122
+ }
1082
1123
  </style>
@@ -39,6 +39,7 @@
39
39
  @confirm-create="$emit('confirm-create', $event)"
40
40
  @cancel-create="$emit('cancel-create')"
41
41
  @confirm-delete="$emit('confirm-delete', $event)"
42
+ @hover-changed="hoverChanged(tab.id, $event)"
42
43
  />
43
44
  </template>
44
45
  <template v-else-if="tab.type === 'connectivityExplorer'">
@@ -50,6 +51,7 @@
50
51
  :connectivityEntry="connectivityEntry"
51
52
  :availableAnatomyFacets="availableAnatomyFacets"
52
53
  :connectivityFilterOptions="filterOptions"
54
+ @filter-visibility="$emit('filter-visibility', $event)"
53
55
  @search-changed="searchChanged(tab.id, $event)"
54
56
  @hover-changed="hoverChanged(tab.id, $event)"
55
57
  @show-connectivity="showConnectivity"
@@ -176,6 +178,8 @@ export default {
176
178
  drawerOpen: false,
177
179
  availableAnatomyFacets: [],
178
180
  activeTabId: 1,
181
+ activeAnnotationData: { tabType: "annotation" },
182
+ activeConnectivityData: { tabType: "connectivity" },
179
183
  }
180
184
  },
181
185
  methods: {
@@ -196,6 +200,15 @@ export default {
196
200
  */
197
201
  hoverChanged: function (id, data) {
198
202
  this.$emit('hover-changed', {...data, tabId: id })
203
+
204
+ const activeTabType = this.getActiveTabTypeById(id);
205
+ // save the last highlighted data for connectivity and annotation tabs
206
+ if (activeTabType === 'connectivityExplorer') {
207
+ this.activeConnectivityData = data;
208
+ }
209
+ if (activeTabType === 'annotation') {
210
+ this.activeAnnotationData = data;
211
+ }
199
212
  },
200
213
  /**
201
214
  * This event is emitted when the show connectivity button is clicked.
@@ -317,9 +330,41 @@ export default {
317
330
  const tabInfo = matchedTab.length ? matchedTab : this.tabEntries;
318
331
  this.activeTabId = tabInfo[0].id;
319
332
  },
333
+ getActiveTabTypeById: function (id) {
334
+ const foundTab = this.tabs.find((tab) => tab.id === id);
335
+ if (foundTab) {
336
+ return foundTab.type;
337
+ }
338
+ return '';
339
+ },
340
+ highlightActiveTabData: function (tab) {
341
+ let data = null;
342
+
343
+ if (tab.type === 'connectivityExplorer') {
344
+ const connectivityExplorerTabRef = this.getTabRef(undefined, 'connectivityExplorer', true);
345
+ // check if any opened item
346
+ // if no opened item, highlight items will be based on the results in explorer
347
+ if (connectivityExplorerTabRef && !connectivityExplorerTabRef.expanded) {
348
+ data = { tabType: 'connectivity' };
349
+ } else {
350
+ data = {...this.activeConnectivityData};
351
+ }
352
+ } else if (tab.type === 'annotation') {
353
+ data = {...this.activeAnnotationData};
354
+ } else {
355
+ // switching to dataset explorer tab will not highlight
356
+ // the highlight is from the last tab
357
+ // if needed, to update it here
358
+ }
359
+
360
+ if (data) {
361
+ this.$emit('hover-changed', {...data, tabId: tab.id })
362
+ }
363
+ },
320
364
  tabClicked: function (tab) {
321
365
  this.setActiveTab(tab);
322
366
  this.$emit('tabClicked', tab);
367
+ this.highlightActiveTabData(tab);
323
368
  },
324
369
  tabClosed: function (tab) {
325
370
  this.$emit('tabClosed', tab);
@@ -167,7 +167,11 @@ export default {
167
167
  return {
168
168
  numberOfHits: this.numberOfHits,
169
169
  filterFacets: this.filter,
170
- showFilters: true
170
+ showFilters: true,
171
+ helper: {
172
+ within: "'heart' OR 'colon'",
173
+ between: "'rat' AND 'lung'"
174
+ }
171
175
  }
172
176
  },
173
177
  },
@@ -1,94 +0,0 @@
1
- async function getReferenceConnectivitiesFromStorage(resource) {
2
- const flatmapKnowledgeRaw = sessionStorage.getItem('flatmap-knowledge');
3
-
4
- if (flatmapKnowledgeRaw) {
5
- const flatmapKnowledge = JSON.parse(flatmapKnowledgeRaw);
6
- const dataWithRefs = flatmapKnowledge.filter((x) => x.references && x.references.length);
7
- const foundData = dataWithRefs.filter((x) => x.references.includes(resource));
8
-
9
- if (foundData.length) {
10
- const featureIds = foundData.map((x) => x.id);
11
- return featureIds;
12
- }
13
- }
14
- return [];
15
- }
16
-
17
- async function getReferenceConnectivitiesByAPI(mapImp, resource, flatmapQueries) {
18
- const knowledgeSource = getKnowledgeSource(mapImp);
19
- const sql = `select knowledge from knowledge
20
- where source="${knowledgeSource}" and
21
- knowledge like "%${resource}%" order by source desc`;
22
- console.log(sql)
23
- const response = await flatmapQueries.flatmapQuery(sql);
24
- const mappedData = response.values.map((x) => x[0]);
25
- const parsedData = mappedData.map((x) => JSON.parse(x));
26
- const featureIds = parsedData.map((x) => x.id);
27
- return featureIds;
28
- }
29
-
30
- function getKnowledgeSource(mapImp) {
31
- let mapKnowledgeSource = '';
32
- if (mapImp.provenance?.connectivity) {
33
- const sckanProvenance = mapImp.provenance.connectivity;
34
- if ('knowledge-source' in sckanProvenance) {
35
- mapKnowledgeSource = sckanProvenance['knowledge-source'];
36
- } else if ('npo' in sckanProvenance) {
37
- mapKnowledgeSource = `${sckanProvenance.npo.release}-npo`;
38
- }
39
- }
40
-
41
- return mapKnowledgeSource;
42
- }
43
-
44
- function loadAndStoreKnowledge(mapImp, flatmapQueries) {
45
- const knowledgeSource = getKnowledgeSource(mapImp);
46
- const sql = `select knowledge from knowledge
47
- where source="${knowledgeSource}"
48
- order by source desc`;
49
- const flatmapKnowledge = sessionStorage.getItem('flatmap-knowledge');
50
-
51
- if (!flatmapKnowledge) {
52
- flatmapQueries.flatmapQuery(sql).then((response) => {
53
- const mappedData = response.values.map(x => x[0]);
54
- const parsedData = mappedData.map(x => JSON.parse(x));
55
- sessionStorage.setItem('flatmap-knowledge', JSON.stringify(parsedData));
56
- updateFlatmapKnowledgeCache();
57
- });
58
- }
59
- }
60
-
61
- function updateFlatmapKnowledgeCache() {
62
- const CACHE_LIFETIME = 24 * 60 * 60 * 1000; // One day
63
- const now = new Date();
64
- const expiry = now.getTime() + CACHE_LIFETIME;
65
-
66
- sessionStorage.setItem('flatmap-knowledge-expiry', expiry);
67
- }
68
-
69
- function removeFlatmapKnowledgeCache() {
70
- const keys = [
71
- 'flatmap-knowledge',
72
- 'flatmap-knowledge-expiry',
73
- ];
74
- keys.forEach((key) => {
75
- sessionStorage.removeItem(key);
76
- });
77
- }
78
-
79
- function refreshFlatmapKnowledgeCache() {
80
- const expiry = sessionStorage.getItem('flatmap-knowledge-expiry');
81
- const now = new Date();
82
-
83
- if (now.getTime() > expiry) {
84
- removeFlatmapKnowledgeCache();
85
- }
86
- }
87
-
88
- export {
89
- getReferenceConnectivitiesFromStorage,
90
- getReferenceConnectivitiesByAPI,
91
- loadAndStoreKnowledge,
92
- getKnowledgeSource,
93
- refreshFlatmapKnowledgeCache,
94
- }