@abi-software/map-side-bar 2.7.2-beta.0 → 2.7.2-beta.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.
@@ -22,28 +22,15 @@
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
- <!-- Connectivity Info -->
33
- <template v-if="tab.type === 'connectivity' && connectivityInfo">
34
- <connectivity-info
35
- :entry="connectivityInfo"
36
- :availableAnatomyFacets="availableAnatomyFacets"
37
- v-if="tab.id === activeTabId"
38
- :envVars="envVars"
39
- :ref="'connectivityTab_' + tab.id"
40
- @show-connectivity="showConnectivity"
41
- @show-reference-connectivities="onShowReferenceConnectivities"
42
- @connectivity-component-click="onConnectivityComponentClick"
43
- />
44
- </template>
45
- <template v-else-if="tab.type === 'annotation'">
46
- <annotation-tool
32
+ <template v-if="tab.type === 'annotation'">
33
+ <AnnotationTool
47
34
  :ref="'annotationTab_' + tab.id"
48
35
  v-show="tab.id === activeTabId"
49
36
  :annotationEntry="annotationEntry"
@@ -54,6 +41,23 @@
54
41
  @confirm-delete="$emit('confirm-delete', $event)"
55
42
  />
56
43
  </template>
44
+ <template v-else-if="tab.type === 'connectivityExplorer'">
45
+ <ConnectivityExplorer
46
+ :ref="'connectivityExplorerTab_' + tab.id"
47
+ v-show="tab.id === activeTabId"
48
+ :connectivityKnowledge="connectivityKnowledge"
49
+ :envVars="envVars"
50
+ :connectivityEntry="connectivityEntry"
51
+ :availableAnatomyFacets="availableAnatomyFacets"
52
+ @search-changed="searchChanged(tab.id, $event)"
53
+ @hover-changed="hoverChanged($event)"
54
+ @show-connectivity="showConnectivity"
55
+ @show-reference-connectivities="onShowReferenceConnectivities"
56
+ @connectivity-clicked="onConnectivityClicked"
57
+ @connectivity-hovered="onConnectivityHovered"
58
+ @connectivity-explorer-clicked="onConnectivityExplorerClicked"
59
+ />
60
+ </template>
57
61
  <template v-else>
58
62
  <SidebarContent
59
63
  class="sidebar-content-container"
@@ -83,7 +87,7 @@ import SidebarContent from './SidebarContent.vue'
83
87
  import EventBus from './EventBus.js'
84
88
  import Tabs from './Tabs.vue'
85
89
  import AnnotationTool from './AnnotationTool.vue'
86
- import ConnectivityInfo from './ConnectivityInfo.vue'
90
+ import ConnectivityExplorer from './ConnectivityExplorer.vue'
87
91
 
88
92
  /**
89
93
  * Aims to provide a sidebar for searching capability for SPARC portal.
@@ -96,8 +100,8 @@ export default {
96
100
  ElIconArrowRight,
97
101
  Drawer,
98
102
  Icon,
99
- ConnectivityInfo,
100
103
  AnnotationTool,
104
+ ConnectivityExplorer,
101
105
  },
102
106
  name: 'SideBar',
103
107
  props: {
@@ -118,24 +122,6 @@ export default {
118
122
  type: Object,
119
123
  default: () => {},
120
124
  },
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
125
  /**
140
126
  * The option to show or hide sidebar on page load.
141
127
  */
@@ -146,16 +132,16 @@ export default {
146
132
  /**
147
133
  * The connectivity info data to show in sidebar.
148
134
  */
149
- connectivityInfo: {
135
+ connectivityEntry: {
150
136
  type: Object,
151
- default: null,
137
+ default: {},
152
138
  },
153
139
  /**
154
140
  * The annotation data to show in sidebar.
155
141
  */
156
142
  annotationEntry: {
157
143
  type: Object,
158
- default: null,
144
+ default: {},
159
145
  },
160
146
  createData: {
161
147
  type: Object,
@@ -166,15 +152,28 @@ export default {
166
152
  x: 0,
167
153
  y: 0,
168
154
  },
169
- }
155
+ },
156
+ connectivityKnowledge: {
157
+ type: Array,
158
+ default: [],
159
+ },
170
160
  },
171
161
  data: function () {
172
162
  return {
173
163
  drawerOpen: false,
174
- availableAnatomyFacets: []
164
+ availableAnatomyFacets: [],
165
+ activeTabId: 1,
166
+ tabs: [
167
+ { title: 'Search', id: 1, type: 'search', closable: false },
168
+ { title: 'Connectivity Explorer', id: 2, type: 'connectivityExplorer', closable: false },
169
+ { title: 'Annotation', id: 3, type: 'annotation', closable: true },
170
+ ]
175
171
  }
176
172
  },
177
173
  methods: {
174
+ onConnectivityExplorerClicked: function (data) {
175
+ this.$emit('connectivity-explorer-clicked', data)
176
+ },
178
177
  /**
179
178
  * This event is emitted when the mouse hover are changed.
180
179
  * @arg data
@@ -197,11 +196,18 @@ export default {
197
196
  this.$emit('show-reference-connectivities', refSource);
198
197
  },
199
198
  /**
200
- * This function is triggered after a connectivity component is clicked.
199
+ * This function is triggered after connectivity term is clicked.
200
+ * @arg data
201
+ */
202
+ onConnectivityClicked: function (data) {
203
+ this.$emit('connectivity-clicked', data);
204
+ },
205
+ /**
206
+ * This function is triggered after connectivity term is hovered.
201
207
  * @arg data
202
208
  */
203
- onConnectivityComponentClick: function (data) {
204
- this.$emit('connectivity-component-click', data);
209
+ onConnectivityHovered: function (data) {
210
+ this.$emit('connectivity-hovered', data);
205
211
  },
206
212
  /**
207
213
  * This event is emitted when the search filters are changed.
@@ -224,43 +230,31 @@ export default {
224
230
  toggleDrawer: function () {
225
231
  this.drawerOpen = !this.drawerOpen
226
232
  },
233
+ openConnectivitySearch: function (facets, query) {
234
+ this.drawerOpen = true;
235
+ // Because refs are in v-for, nextTick is needed here
236
+ this.$nextTick(() => {
237
+ const connectivityExplorerTabRef = this.getTabRef(2, 'connectivityExplorer', true);
238
+ connectivityExplorerTabRef.openSearch(facets, query);
239
+ })
240
+ },
227
241
  openSearch: function (facets, query) {
228
242
  this.drawerOpen = true
229
243
  // Because refs are in v-for, nextTick is needed here
230
244
  this.$nextTick(() => {
231
- const searchTabRef = this.getSearchTabRefById(1);
245
+ const searchTabRef = this.getTabRef(1, 'search', true);
232
246
  searchTabRef.openSearch(facets, query);
233
247
  })
234
248
  },
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
249
  /**
247
250
  * Get the ref id of the tab by id and type.
248
251
  */
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];
252
+ getTabRef: function (id = 1, type = 'search', open = false) {
253
+ const matchedTab = this.tabEntries.filter((tab) => tab.id === id && tab.type === type);
254
+ const tabInfo = matchedTab.length ? matchedTab : this.tabEntries;
255
+ const tabRef = type + 'Tab_' + tabInfo[0].id;
256
+ if (open) this.tabClicked({ id, type });
257
+ return this.$refs[tabRef][0];
264
258
  },
265
259
  /**
266
260
  * The function to add filters to sidebar search.
@@ -274,7 +268,7 @@ export default {
274
268
 
275
269
  // Because refs are in v-for, nextTick is needed here
276
270
  this.$nextTick(() => {
277
- const searchTabRef = this.getSearchTabRefById(1);
271
+ const searchTabRef = this.getTabRef(1, 'search', true);
278
272
  searchTabRef.addFilter(filter)
279
273
  })
280
274
  },
@@ -282,7 +276,7 @@ export default {
282
276
  this.drawerOpen = true
283
277
  // Because refs are in v-for, nextTick is needed here
284
278
  this.$nextTick(() => {
285
- const searchTabRef = this.getSearchTabRefById(1);
279
+ const searchTabRef = this.getTabRef(1, 'search', true);
286
280
  searchTabRef.openSearch(
287
281
  '',
288
282
  undefined,
@@ -292,27 +286,17 @@ export default {
292
286
  })
293
287
  },
294
288
  getAlgoliaFacets: async function () {
295
- const searchTabRef = this.getSearchTabRefById(1);
289
+ const searchTabRef = this.getTabRef(1, 'search');
296
290
  return await searchTabRef.getAlgoliaFacets()
297
291
  },
298
292
  setDrawerOpen: function (value = true) {
299
293
  this.drawerOpen = value
300
294
  },
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});
295
+ tabClicked: function (tab) {
296
+ this.activeTabId = tab.id
313
297
  },
314
- tabClose: function (id) {
315
- this.$emit('tab-close', id);
298
+ tabClosed: function (tab) {
299
+ this.$emit('tabClosed', tab);
316
300
  },
317
301
  /**
318
302
  * To receive error message for connectivity graph
@@ -324,22 +308,12 @@ export default {
324
308
  },
325
309
  computed: {
326
310
  // 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;
311
+ tabEntries: function () {
312
+ return this.tabs.filter((tab) =>
313
+ tab.type === "search" ||
314
+ tab.type === "connectivityExplorer" ||
315
+ (tab.type === "annotation" && this.annotationEntry && Object.keys(this.annotationEntry).length > 0)
316
+ );
343
317
  },
344
318
  },
345
319
  created: function () {
@@ -395,7 +369,6 @@ export default {
395
369
  EventBus.on('available-facets', (payLoad) => {
396
370
  this.availableAnatomyFacets = payLoad.find((facet) => facet.label === 'Anatomical Structure').children
397
371
  })
398
-
399
372
  },
400
373
  }
401
374
  </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,31 +9,14 @@ 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
- ElButton: typeof import('element-plus/es')['ElButton']
15
- ElCard: typeof import('element-plus/es')['ElCard']
16
- ElCascader: typeof import('element-plus/es')['ElCascader']
17
- ElCol: typeof import('element-plus/es')['ElCol']
18
16
  ElDrawer: typeof import('element-plus/es')['ElDrawer']
19
- ElDropdown: typeof import('element-plus/es')['ElDropdown']
20
- ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
21
- ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
22
17
  ElIcon: typeof import('element-plus/es')['ElIcon']
23
- ElIconArrowDown: typeof import('@element-plus/icons-vue')['ArrowDown']
24
18
  ElIconArrowLeft: typeof import('@element-plus/icons-vue')['ArrowLeft']
25
19
  ElIconArrowRight: typeof import('@element-plus/icons-vue')['ArrowRight']
26
- ElIconDelete: typeof import('@element-plus/icons-vue')['Delete']
27
- ElIconLocation: typeof import('@element-plus/icons-vue')['Location']
28
- ElIconWarning: typeof import('@element-plus/icons-vue')['Warning']
29
- ElIconWarnTriangleFilled: typeof import('@element-plus/icons-vue')['WarnTriangleFilled']
30
- ElInput: typeof import('element-plus/es')['ElInput']
31
- ElOption: typeof import('element-plus/es')['ElOption']
32
- ElPagination: typeof import('element-plus/es')['ElPagination']
33
- ElPopover: typeof import('element-plus/es')['ElPopover']
34
- ElRow: typeof import('element-plus/es')['ElRow']
35
- ElSelect: typeof import('element-plus/es')['ElSelect']
36
- ElTag: typeof import('element-plus/es')['ElTag']
37
20
  ImageGallery: typeof import('./components/ImageGallery.vue')['default']
38
21
  SearchFilters: typeof import('./components/SearchFilters.vue')['default']
39
22
  SearchHistory: typeof import('./components/SearchHistory.vue')['default']
@@ -41,7 +24,4 @@ declare module 'vue' {
41
24
  SidebarContent: typeof import('./components/SidebarContent.vue')['default']
42
25
  Tabs: typeof import('./components/Tabs.vue')['default']
43
26
  }
44
- export interface ComponentCustomProperties {
45
- vLoading: typeof import('element-plus/es')['ElLoadingDirective']
46
- }
47
27
  }
@@ -287,4 +287,4 @@ export default {
287
287
  "Domestic Pig"
288
288
  ],
289
289
  "knowledge-source": "sckan-2024-03-26-npo",
290
- }
290
+ }