@abi-software/map-side-bar 2.7.1 → 2.7.2-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -22,11 +22,11 @@
22
22
  </div>
23
23
  <div class="sidebar-container">
24
24
  <Tabs
25
- v-if="activeTabs.length > 1"
26
- :tabTitles="activeTabs"
25
+ v-if="tabEntries.length > 1"
26
+ :tabEntries="tabEntries"
27
27
  :activeId="activeTabId"
28
- @titleClicked="tabClicked"
29
- @tab-close="tabClose"
28
+ @tabClicked="tabClicked"
29
+ @tabClosed="tabClosed"
30
30
  />
31
31
  <template v-for="tab in tabs" key="tab.id">
32
32
  <!-- Connectivity Info -->
@@ -39,7 +39,8 @@
39
39
  :ref="'connectivityTab_' + tab.id"
40
40
  @show-connectivity="showConnectivity"
41
41
  @show-reference-connectivities="onShowReferenceConnectivities"
42
- @connectivity-component-click="onConnectivityComponentClick"
42
+ @connectivity-clicked="onConnectivityClicked"
43
+ @connectivity-hovered="onConnectivityHovered"
43
44
  />
44
45
  </template>
45
46
  <template v-else-if="tab.type === 'annotation'">
@@ -54,6 +55,16 @@
54
55
  @confirm-delete="$emit('confirm-delete', $event)"
55
56
  />
56
57
  </template>
58
+ <template v-else-if="tab.type === 'connectivityExplorer'">
59
+ <connectivity-explorer
60
+ :ref="'connectivityExplorerTab_' + tab.id"
61
+ v-show="tab.id === activeTabId"
62
+ :connectivityKnowledge="connectivityKnowledge"
63
+ :envVars="envVars"
64
+ @search-changed="searchChanged(tab.id, $event)"
65
+ @hover-changed="hoverChanged($event)"
66
+ />
67
+ </template>
57
68
  <template v-else>
58
69
  <SidebarContent
59
70
  class="sidebar-content-container"
@@ -84,6 +95,7 @@ import EventBus from './EventBus.js'
84
95
  import Tabs from './Tabs.vue'
85
96
  import AnnotationTool from './AnnotationTool.vue'
86
97
  import ConnectivityInfo from './ConnectivityInfo.vue'
98
+ import ConnectivityExplorer from './ConnectivityExplorer.vue'
87
99
 
88
100
  /**
89
101
  * Aims to provide a sidebar for searching capability for SPARC portal.
@@ -98,6 +110,7 @@ export default {
98
110
  Icon,
99
111
  ConnectivityInfo,
100
112
  AnnotationTool,
113
+ ConnectivityExplorer,
101
114
  },
102
115
  name: 'SideBar',
103
116
  props: {
@@ -118,24 +131,6 @@ export default {
118
131
  type: Object,
119
132
  default: () => {},
120
133
  },
121
- /**
122
- * The array of objects to show multiple sidebar contents.
123
- */
124
- tabs: {
125
- type: Array,
126
- default: () => [
127
- { id: 1, title: 'Search', type: 'search' },
128
- { id: 2, title: 'Connectivity', type: 'connectivity' },
129
- { id: 3, title: 'Annotation', type: 'annotation' }
130
- ],
131
- },
132
- /**
133
- * The active tab id for default tab.
134
- */
135
- activeTabId: {
136
- type: Number,
137
- default: 1,
138
- },
139
134
  /**
140
135
  * The option to show or hide sidebar on page load.
141
136
  */
@@ -166,12 +161,23 @@ export default {
166
161
  x: 0,
167
162
  y: 0,
168
163
  },
169
- }
164
+ },
165
+ connectivityKnowledge: {
166
+ type: Array,
167
+ default: [],
168
+ },
170
169
  },
171
170
  data: function () {
172
171
  return {
173
172
  drawerOpen: false,
174
- availableAnatomyFacets: []
173
+ availableAnatomyFacets: [],
174
+ activeTabId: 1,
175
+ tabs: [
176
+ { title: 'Search', id: 1, type: 'search', closable: false },
177
+ { title: 'Connectivity', id: 2, type: 'connectivity', closable: true },
178
+ { title: 'Annotation', id: 3, type: 'annotation', closable: true },
179
+ { title: 'Connectivity Explorer', id: 4, type: 'connectivityExplorer', closable: false },
180
+ ]
175
181
  }
176
182
  },
177
183
  methods: {
@@ -197,11 +203,21 @@ export default {
197
203
  this.$emit('show-reference-connectivities', refSource);
198
204
  },
199
205
  /**
200
- * This function is triggered after a connectivity component is clicked.
206
+ * This function is triggered after connectivity term is clicked.
207
+ * @arg data
208
+ */
209
+ onConnectivityClicked: function (data) {
210
+ this.$emit('connectivity-clicked', data);
211
+ },
212
+ /**
213
+ * This function is triggered after connectivity term is hovered.
201
214
  * @arg data
202
215
  */
203
- onConnectivityComponentClick: function (data) {
204
- this.$emit('connectivity-component-click', data);
216
+ onConnectivityHovered: function (data) {
217
+ this.$emit('connectivity-hovered', data);
218
+ },
219
+ showNeuronConnection: function (data) {
220
+ this.$emit('neuron-connection-change', data);
205
221
  },
206
222
  /**
207
223
  * This event is emitted when the search filters are changed.
@@ -224,43 +240,31 @@ export default {
224
240
  toggleDrawer: function () {
225
241
  this.drawerOpen = !this.drawerOpen
226
242
  },
243
+ openConnectivitySearch: function (facets, query) {
244
+ this.drawerOpen = true;
245
+ // Because refs are in v-for, nextTick is needed here
246
+ this.$nextTick(() => {
247
+ const connectivityExplorerTabRef = this.getTabRef(4, 'connectivityExplorer', true);
248
+ connectivityExplorerTabRef.openSearch(facets, query);
249
+ })
250
+ },
227
251
  openSearch: function (facets, query) {
228
252
  this.drawerOpen = true
229
253
  // Because refs are in v-for, nextTick is needed here
230
254
  this.$nextTick(() => {
231
- const searchTabRef = this.getSearchTabRefById(1);
255
+ const searchTabRef = this.getTabRef(1, 'search', true);
232
256
  searchTabRef.openSearch(facets, query);
233
257
  })
234
258
  },
235
- /**
236
- * Get the tab object by tab id and type.
237
- * If not found, return the first available tab.
238
- */
239
- getTabByIdAndType: function (id, type) {
240
- const tabId = id || this.activeTabId;
241
- const tabType = type || 'search'; // default to search tab
242
- const tabObj = this.activeTabs.find((tab) => tab.id === tabId && tab.type === tabType);
243
- const firstAvailableTab = this.activeTabs[0];
244
- return tabObj || firstAvailableTab;
245
- },
246
259
  /**
247
260
  * Get the ref id of the tab by id and type.
248
261
  */
249
- getTabRefId: function (id, type) {
250
- let refIdPrefix = 'searchTab_'; // default to search tab
251
- if (type === 'connectivity') {
252
- refIdPrefix = 'connectivityTab_';
253
- } else if (type === 'annotation') {
254
- refIdPrefix = 'annotationTab_';
255
- }
256
- const tabObj = this.getTabByIdAndType(id, type);
257
- const tabRefId = refIdPrefix + tabObj.id;
258
- return tabRefId;
259
- },
260
- getSearchTabRefById: function (id) {
261
- const searchTabId = id || 1; // to use id when there are multiple search tabs
262
- const searchTabRefId = this.getTabRefId(searchTabId, 'search');
263
- return this.$refs[searchTabRefId][0];
262
+ getTabRef: function (id = 1, type = 'search', open = false) {
263
+ const matchedTab = this.tabEntries.filter((tab) => tab.id === id && tab.type === type);
264
+ const tabInfo = matchedTab.length ? matchedTab : this.tabEntries;
265
+ const tabRef = type + 'Tab_' + tabInfo[0].id;
266
+ if (open) this.tabClicked({ id, type });
267
+ return this.$refs[tabRef][0];
264
268
  },
265
269
  /**
266
270
  * The function to add filters to sidebar search.
@@ -274,7 +278,7 @@ export default {
274
278
 
275
279
  // Because refs are in v-for, nextTick is needed here
276
280
  this.$nextTick(() => {
277
- const searchTabRef = this.getSearchTabRefById(1);
281
+ const searchTabRef = this.getTabRef(1, 'search', true);
278
282
  searchTabRef.addFilter(filter)
279
283
  })
280
284
  },
@@ -282,7 +286,7 @@ export default {
282
286
  this.drawerOpen = true
283
287
  // Because refs are in v-for, nextTick is needed here
284
288
  this.$nextTick(() => {
285
- const searchTabRef = this.getSearchTabRefById(1);
289
+ const searchTabRef = this.getTabRef(1, 'search', true);
286
290
  searchTabRef.openSearch(
287
291
  '',
288
292
  undefined,
@@ -292,27 +296,17 @@ export default {
292
296
  })
293
297
  },
294
298
  getAlgoliaFacets: async function () {
295
- const searchTabRef = this.getSearchTabRefById(1);
299
+ const searchTabRef = this.getTabRef(1, 'search');
296
300
  return await searchTabRef.getAlgoliaFacets()
297
301
  },
298
302
  setDrawerOpen: function (value = true) {
299
303
  this.drawerOpen = value
300
304
  },
301
- /**
302
- * The function to emit 'tabClicked' event with tab's `id` and tab's `type`
303
- * when user clicks the sidebar tab.
304
- * @param {Object} {id, type}
305
- * @public
306
- */
307
- tabClicked: function ({id, type}) {
308
- /**
309
- * This event is emitted when user click sidebar's tab.
310
- * @arg {Object} {id, type}
311
- */
312
- this.$emit('tabClicked', {id, type});
305
+ tabClicked: function (tab) {
306
+ this.activeTabId = tab.id
313
307
  },
314
- tabClose: function (id) {
315
- this.$emit('tab-close', id);
308
+ tabClosed: function (tab) {
309
+ this.$emit('tabClosed', tab);
316
310
  },
317
311
  /**
318
312
  * To receive error message for connectivity graph
@@ -324,22 +318,13 @@ export default {
324
318
  },
325
319
  computed: {
326
320
  // This should respect the information provided by the property
327
- activeTabs: function() {
328
- const tabs = []
329
- this.tabs.forEach((tab) => {
330
- if (tab.type === "search") {
331
- tabs.push(tab)
332
- } else if (tab.type === "connectivity") {
333
- if (this.connectivityInfo) {
334
- tabs.push(tab);
335
- }
336
- } else if (tab.type === "annotation") {
337
- if (this.annotationEntry && Object.keys(this.annotationEntry).length > 0) {
338
- tabs.push(tab);
339
- }
340
- }
341
- })
342
- return tabs;
321
+ tabEntries: function () {
322
+ return this.tabs.filter((tab) =>
323
+ tab.type === "search" ||
324
+ tab.type === "connectivityExplorer" ||
325
+ (tab.type === "connectivity" && this.connectivityInfo) ||
326
+ (tab.type === "annotation" && this.annotationEntry && Object.keys(this.annotationEntry).length > 0)
327
+ );
343
328
  },
344
329
  },
345
330
  created: function () {
@@ -396,6 +381,16 @@ export default {
396
381
  this.availableAnatomyFacets = payLoad.find((facet) => facet.label === 'Anatomical Structure').children
397
382
  })
398
383
 
384
+ // Get available anatomy facets for the connectivity info
385
+ EventBus.on('connectivity-explorer-clicked', (payLoad) => {
386
+ this.$emit('connectivity-explorer-clicked', payLoad);
387
+ })
388
+
389
+ // Get available anatomy facets for the connectivity info
390
+ EventBus.on('connectivity-hovered', (payLoad) => {
391
+ this.$emit('connectivity-hovered', payLoad);
392
+ })
393
+
399
394
  },
400
395
  }
401
396
  </script>
@@ -164,7 +164,8 @@ export default {
164
164
  },
165
165
  methods: {
166
166
  hoverChanged: function (data) {
167
- this.$emit('hover-changed', data)
167
+ const payload = data ? { ...data, type: 'dataset' } : data
168
+ this.$emit('hover-changed', payload)
168
169
  },
169
170
  resetSearch: function () {
170
171
  this.numberOfHits = 0
@@ -1,40 +1,35 @@
1
1
  <template>
2
- <div class="tab-container">
2
+ <div class="tabs-container">
3
3
  <div
4
- class="title"
5
- v-for="title in tabTitles"
6
- :key="title.id"
7
- :class="{ 'active-tab': title.id == activeId }"
4
+ class="tab"
5
+ v-for="tab in tabs"
6
+ :key="tab.id"
7
+ :class="{ 'active-tab': tab.id == activeId }"
8
+ @click="tabClicked(tab)"
8
9
  >
9
- <div
10
- class="title-text-table"
11
- v-bind:class="{ highlightText: title.id == activeId }"
12
- v-on:click="titleClicked(title.id, title.type)"
10
+ <span class="tab-title">{{ tab.title }} </span>
11
+ <el-icon
12
+ v-if="tab.closable"
13
+ @click.stop="tabClosed(tab)"
14
+ class="tab-close-icon"
13
15
  >
14
- <div class="title-text">
15
- {{ title.title }}
16
- </div>
17
- </div>
18
- <el-button
19
- v-if="title.id > 1"
20
- @click="tabClose(title.id)"
21
- class="button-tab-close"
22
- aria-label="Close"
23
- >
24
- &times;
25
- <span class="visually-hidden">Close</span>
26
- </el-button>
16
+ <el-icon-close />
17
+ </el-icon>
27
18
  </div>
28
19
  </div>
29
20
  </template>
30
21
 
31
22
  <script>
32
23
  /* eslint-disable no-alert, no-console */
24
+ import { Close as ElIconClose } from "@element-plus/icons-vue";
33
25
 
34
26
  export default {
35
- name: 'Tabs',
27
+ name: "Tabs",
28
+ components: {
29
+ ElIconClose,
30
+ },
36
31
  props: {
37
- tabTitles: {
32
+ tabEntries: {
38
33
  type: Array,
39
34
  default: () => [],
40
35
  },
@@ -42,106 +37,72 @@ export default {
42
37
  type: Number,
43
38
  default: 1,
44
39
  },
40
+ contextArray: {
41
+ type: Array,
42
+ default: () => [],
43
+ },
44
+ },
45
+ computed: {
46
+ tabs: function () {
47
+ // permanent tabs always show in the front
48
+ const permanent = this.tabEntries.filter((t) => !t.closable);
49
+ const temporary = this.tabEntries.filter((t) => t.closable);
50
+ let entries = permanent.concat(temporary);
51
+ if (this.contextArray.length) {
52
+ for (let i in entries) {
53
+ entries[i].contextCard = this.contextArray[i];
54
+ }
55
+ }
56
+ return entries;
57
+ },
45
58
  },
46
59
  methods: {
47
- titleClicked: function (id, type) {
48
- this.$emit('titleClicked', {id, type})
60
+ tabClicked: function (tab) {
61
+ this.$emit("tabClicked", { id: tab.id, type: tab.type });
49
62
  },
50
- tabClose: function (id) {
51
- this.$emit('tab-close', id);
63
+ tabClosed: function (tab) {
64
+ this.$emit("tabClosed", { id: tab.id, type: tab.type });
52
65
  },
53
66
  },
54
- }
67
+ };
55
68
  </script>
56
69
 
57
70
  <style lang="scss" scoped>
58
- $tab-height: 30px;
59
-
60
- .tab-container {
61
- height: $tab-height + 2;
71
+ .tabs-container {
62
72
  display: flex;
63
- flex-direction: row;
64
- position: relative;
65
- z-index: 1;
73
+ flex-wrap: nowrap;
74
+ align-items: center;
66
75
  }
67
76
 
68
- .title {
69
- height: $tab-height;
77
+ .tab {
78
+ height: 30px;
70
79
  border: 1px solid var(--el-border-color);
71
80
  border-top-color: transparent;
72
- background-color: white;
81
+ border-bottom-color: transparent;
73
82
  display: flex;
74
- width: fit-content;
75
83
  align-items: center;
76
- position: relative;
77
84
  cursor: pointer;
78
85
  }
79
86
 
80
- .title-text {
81
- text-align: center;
82
- display: table-cell;
83
- vertical-align: middle;
84
- font-size: 14px;
85
- padding: 0 1rem;
86
- }
87
-
88
- .title-text-table {
89
- display: table;
90
- height: 100%;
91
- width: 100%;
92
- }
93
-
94
- .parent-dialog:hover .title-text {
95
- color: $app-primary-color;
96
- }
97
-
98
- .title:hover,
87
+ .tab:hover,
99
88
  .active-tab {
100
89
  background-color: #f9f2fc;
101
- border: solid #8300bf;
102
- border-width: 1px 1px .125em;
90
+ border: 1px solid #8300bf;
103
91
  color: #8300bf;
104
92
  font-weight: 500;
105
93
  }
106
94
 
107
- .highlightText {
108
- color: $app-primary-color;
95
+ .tab-title {
96
+ text-align: center;
97
+ font-size: 14px;
98
+ padding: 0 1rem;
109
99
  }
110
100
 
111
- .button-tab-close {
101
+ .tab-close-icon {
112
102
  width: 20px !important;
113
103
  height: 20px !important;
114
- line-height: 20px !important;
115
- padding: 0 !important;
104
+ font-size: 20px !important;
116
105
  padding-right: 4px !important;
117
- font-size: 24px !important;
118
106
  color: $app-primary-color !important;
119
- border: 0 none !important;
120
- box-shadow: none !important;
121
- outline: none !important;
122
- background-color: transparent !important;
123
-
124
- :deep(> span) {
125
- height: $tab-height - 2 !important; // tab height minus border
126
- font-family: Arial !important; // to fix font alignment on different browsers
127
- }
128
-
129
- &:hover,
130
- &:focus {
131
- border: 0 none !important;
132
- outline: none !important;
133
- box-shadow: none !important;
134
- background-color: transparent !important;
135
- }
136
- }
137
-
138
- .visually-hidden {
139
- clip: rect(0 0 0 0);
140
- clip-path: inset(50%);
141
- height: 1px;
142
- overflow: hidden;
143
- position: absolute;
144
- white-space: nowrap;
145
- width: 1px;
146
107
  }
147
108
  </style>
@@ -9,6 +9,8 @@ declare module 'vue' {
9
9
  export interface GlobalComponents {
10
10
  AnnotationTool: typeof import('./components/AnnotationTool.vue')['default']
11
11
  BadgesGroup: typeof import('./components/BadgesGroup.vue')['default']
12
+ ConnectivityCard: typeof import('./components/ConnectivityCard.vue')['default']
13
+ ConnectivityExplorer: typeof import('./components/ConnectivityExplorer.vue')['default']
12
14
  ConnectivityInfo: typeof import('./components/ConnectivityInfo.vue')['default']
13
15
  DatasetCard: typeof import('./components/DatasetCard.vue')['default']
14
16
  ElButton: typeof import('element-plus/es')['ElButton']
@@ -23,6 +25,7 @@ declare module 'vue' {
23
25
  ElIconArrowDown: typeof import('@element-plus/icons-vue')['ArrowDown']
24
26
  ElIconArrowLeft: typeof import('@element-plus/icons-vue')['ArrowLeft']
25
27
  ElIconArrowRight: typeof import('@element-plus/icons-vue')['ArrowRight']
28
+ ElIconClose: typeof import('@element-plus/icons-vue')['Close']
26
29
  ElIconDelete: typeof import('@element-plus/icons-vue')['Delete']
27
30
  ElIconLocation: typeof import('@element-plus/icons-vue')['Location']
28
31
  ElIconWarning: typeof import('@element-plus/icons-vue')['Warning']
@@ -287,4 +287,4 @@ export default {
287
287
  "Domestic Pig"
288
288
  ],
289
289
  "knowledge-source": "sckan-2024-03-26-npo",
290
- }
290
+ }
@@ -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
- }