@abi-software/map-side-bar 2.2.1-beta.2 → 2.2.1-beta.4

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.2.1-beta.2",
3
+ "version": "2.2.1-beta.4",
4
4
  "files": [
5
5
  "dist/*",
6
6
  "src/*",
package/src/App.vue CHANGED
@@ -4,22 +4,25 @@
4
4
  rel="stylesheet"
5
5
  href="https://fonts.googleapis.com/css?family=Asap:400,400i,500,600,700&display=swap"
6
6
  />
7
- Click arrow to open sidebar
8
- <el-button @click="openSearch">search Uberon from refs</el-button>
9
- <el-button @click="singleFacets">Add heart to Filter</el-button>
10
- <el-button @click="addStomach">Add stomach to Filter</el-button>
11
- <el-button @click="addInvalidTerm">Add invalid term to Filter</el-button>
12
- <el-button @click="multiFacets">multiple facets</el-button>
13
- <el-button @click="neuronSearch">open neuron search</el-button>
14
- <el-button @click="keywordSearch">keyword search</el-button>
15
- <el-button @click="getFacets">Get facets</el-button>
7
+ <div class="options-container">
8
+ <div>Click arrow to open sidebar</div>
9
+ <el-button @click="openSearch">search Uberon from refs</el-button>
10
+ <el-button @click="singleFacets">Add heart to Filter</el-button>
11
+ <el-button @click="addStomach">Add stomach to Filter</el-button>
12
+ <el-button @click="addInvalidTerm">Add invalid term to Filter</el-button>
13
+ <el-button @click="multiFacets">multiple facets</el-button>
14
+ <el-button @click="neuronSearch">open neuron search</el-button>
15
+ <el-button @click="keywordSearch">keyword search</el-button>
16
+ <el-button @click="getFacets">Get facets</el-button>
17
+ </div>
16
18
  <SideBar
17
19
  :envVars="envVars"
18
20
  class="side-bar"
19
21
  ref="sideBar"
20
22
  :visible="sideBarVisibility"
21
23
  :tabs="tabs"
22
- :activeId="activeId"
24
+ :activeTabId="activeId"
25
+ :connectivityInfo="connectivityInput"
23
26
  @tabClicked="tabClicked"
24
27
  @search-changed="searchChanged($event)"
25
28
  @hover-changed="hoverChanged($event)"
@@ -33,6 +36,9 @@
33
36
  // optionally import default styles
34
37
  import SideBar from './components/SideBar.vue'
35
38
  import EventBus from './components/EventBus.js'
39
+ import exampleConnectivityInput from './exampleConnectivityInput.js'
40
+
41
+ const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
36
42
 
37
43
  // let testContext = {
38
44
  // "description": "3D digital tracings of the enteric plexus obtained from seven subjects (M11, M16, M162, M163, M164, M168) are mapped randomly on mouse proximal colon. The data depicts individual neural wiring patterns in enteric microcircuits, and revealed both neuron and fiber units wired in a complex organization.",
@@ -94,8 +100,8 @@ export default {
94
100
  },
95
101
  data: function () {
96
102
  return {
97
- tabArray: [{ title: 'Flatmap', id: 1 }],
98
- contextArray: [null, null, null],
103
+ contextArray: [null, null],
104
+ tabArray: [{ title: 'Flatmap', id: 1, type: 'search'}, { title: 'Connectivity', id: 2, type: 'connectivity' }],
99
105
  sideBarVisibility: true,
100
106
  envVars: {
101
107
  API_LOCATION: import.meta.env.VITE_APP_API_LOCATION,
@@ -107,6 +113,7 @@ export default {
107
113
  NL_LINK_PREFIX: import.meta.env.VITE_APP_NL_LINK_PREFIX,
108
114
  ROOT_URL: import.meta.env.VITE_APP_ROOT_URL,
109
115
  },
116
+ connectivityInput: exampleConnectivityInput,
110
117
  activeId: 1,
111
118
  }
112
119
  },
@@ -117,11 +124,24 @@ export default {
117
124
  searchChanged: function (data) {
118
125
  console.log(data)
119
126
  },
120
- tabClicked: function (id) {
121
- this.activeId = id
127
+ tabClicked: function (tab) {
128
+ this.activeId = tab.id
122
129
  },
123
- action: function (val) {
124
- console.log('action fired: ', val)
130
+ // For connectivity input actions
131
+ action: function (action) {
132
+ console.log('action fired: ', action)
133
+ let facets = [];
134
+ facets.push(
135
+ ...action.labels.map(val => ({
136
+ facet: capitalise(val),
137
+ term: "Anatomical structure",
138
+ facetPropPath: "anatomy.organ.category.name",
139
+ }))
140
+ );
141
+ if (this.$refs.sideBar) {
142
+ console.log('openSearch', facets)
143
+ this.$refs.sideBar.openSearch(facets, "");
144
+ }
125
145
  },
126
146
  openSearch: function () {
127
147
  this.$refs.sideBar.openSearch(
@@ -230,4 +250,16 @@ body {
230
250
  .map-icon {
231
251
  color: $app-primary-color;
232
252
  }
253
+ .options-container {
254
+ position: absolute;
255
+ top: 0;
256
+ left: 0;
257
+ width: calc(100% - 600px);
258
+ padding: 1rem;
259
+ display: flex;
260
+ flex-direction: row;
261
+ flex-wrap: wrap;
262
+ align-items: center;
263
+ gap: 0.5rem;
264
+ }
233
265
  </style>
@@ -93,7 +93,6 @@ export function getFilters(selectedFacetArray=undefined) {
93
93
 
94
94
  filters = filters.split('()AND ').join(''); // Handle case where there where no OR facets
95
95
  });
96
- console.log('filters about to be applied:', filters)
97
96
  return filters.substring(0, filters.lastIndexOf(" AND "));
98
97
  }
99
98
 
@@ -68,7 +68,8 @@
68
68
  </div>
69
69
  <el-button
70
70
  v-show="
71
- entry.originsWithDatasets && entry.originsWithDatasets.length > 0
71
+ entry.originsWithDatasets && entry.originsWithDatasets.length > 0 &&
72
+ shouldShowExploreButton(entry.originsWithDatasets)
72
73
  "
73
74
  class="button"
74
75
  id="open-dendrites-button"
@@ -132,7 +133,8 @@
132
133
  <el-button
133
134
  v-show="
134
135
  entry.destinationsWithDatasets &&
135
- entry.destinationsWithDatasets.length > 0
136
+ entry.destinationsWithDatasets.length > 0 &&
137
+ shouldShowExploreButton(entry.destinationsWithDatasets)
136
138
  "
137
139
  class="button"
138
140
  @click="openAxons"
@@ -144,7 +146,8 @@
144
146
  <el-button
145
147
  v-show="
146
148
  entry.componentsWithDatasets &&
147
- entry.componentsWithDatasets.length > 0
149
+ entry.componentsWithDatasets.length > 0 &&
150
+ shouldShowExploreButton(entry.componentsWithDatasets)
148
151
  "
149
152
  class="button"
150
153
  @click="openAll"
@@ -168,7 +171,7 @@ import {
168
171
  ElIcon as Icon,
169
172
  } from 'element-plus'
170
173
  import ExternalResourceCard from './ExternalResourceCard.vue'
171
- import EventBus from './EventBus'
174
+ import EventBus from './EventBus.js'
172
175
 
173
176
  const titleCase = (str) => {
174
177
  return str.replace(/\w\S*/g, (t) => {
@@ -205,6 +208,10 @@ export default {
205
208
  resource: undefined,
206
209
  }),
207
210
  },
211
+ availableAnatomyFacets: {
212
+ type: Array,
213
+ default: () => [],
214
+ },
208
215
  },
209
216
  // inject: ['getFeaturesAlert'],
210
217
  data: function () {
@@ -213,6 +220,7 @@ export default {
213
220
  activeSpecies: undefined,
214
221
  pubmedSearchUrl: '',
215
222
  loading: false,
223
+ facetList: [],
216
224
  showToolip: false,
217
225
  showDetails: false,
218
226
  originDescriptions: {
@@ -223,6 +231,15 @@ export default {
223
231
  uberons: [{ id: undefined, name: undefined }],
224
232
  }
225
233
  },
234
+ watch: {
235
+ availableAnatomyFacets: {
236
+ handler: function (val) {
237
+ this.convertFacetsToList(val)
238
+ },
239
+ immediate: true,
240
+ deep: true,
241
+ },
242
+ },
226
243
  computed: {
227
244
  resources: function () {
228
245
  let resources = [];
@@ -268,19 +285,38 @@ export default {
268
285
  openAll: function () {
269
286
  EventBus.emit('onConnectivityActionClick', {
270
287
  type: 'Facets',
271
- labels: this.entry.componentsWithDatasets.map((a) => a.name),
288
+ labels: this.entry.componentsWithDatasets.map((a) => a.name.toLowerCase()),
272
289
  })
273
290
  },
274
291
  openAxons: function () {
275
292
  EventBus.emit('onConnectivityActionClick', {
276
293
  type: 'Facets',
277
- labels: this.entry.destinationsWithDatasets.map((a) => a.name),
294
+ labels: this.entry.destinationsWithDatasets.map((a) => a.name.toLowerCase()),
295
+ })
296
+ },
297
+ // shouldShowExploreButton: Checks if the feature is in the list of available anatomy facets
298
+ shouldShowExploreButton: function (features) {
299
+ for (let i = 0; i < features.length; i++) {
300
+ if (this.facetList.includes(features[i].name.toLowerCase())) {
301
+ return true
302
+ }
303
+ }
304
+ return false
305
+ },
306
+ // convertFacetsToList: Converts the available anatomy facets to a list for easy searching
307
+ convertFacetsToList: function (facets) {
308
+ facets.forEach((facet) => {
309
+ if(facet.children) {
310
+ this.convertFacetsToList(facet.children)
311
+ } else {
312
+ this.facetList.push(facet.label.toLowerCase())
313
+ }
278
314
  })
279
315
  },
280
316
  openDendrites: function () {
281
317
  EventBus.emit('onConnectivityActionClick', {
282
318
  type: 'Facets',
283
- labels: this.entry.originsWithDatasets.map((a) => a.name),
319
+ labels: this.entry.originsWithDatasets.map((a) => a.name.toLowerCase()),
284
320
  })
285
321
  },
286
322
  pubmedSearchUrlUpdate: function (val) {
@@ -508,6 +544,10 @@ export default {
508
544
 
509
545
  .block {
510
546
  padding-top: 0.5em;
547
+
548
+ + .block {
549
+ margin-top: 1rem;
550
+ }
511
551
  }
512
552
 
513
553
  .connectivity-info-title ~ & {
@@ -264,7 +264,8 @@ export default {
264
264
 
265
265
  <style lang="scss" scoped>
266
266
  .dataset-card {
267
- padding-left: 15px;
267
+ padding-left: 5px;
268
+ padding-right: 5px;
268
269
  position: relative;
269
270
  min-height: 17rem;
270
271
  }
@@ -118,6 +118,7 @@ import '@abi-software/svg-sprite/dist/style.css'
118
118
 
119
119
  import { AlgoliaClient } from '../algolia/algolia.js'
120
120
  import { facetPropPathMapping } from '../algolia/utils.js'
121
+ import EventBus from './EventBus.js'
121
122
 
122
123
  const capitalise = function (txt) {
123
124
  return txt.charAt(0).toUpperCase() + txt.slice(1)
@@ -217,6 +218,7 @@ export default {
217
218
  .getAlgoliaFacets(facetPropPathMapping)
218
219
  .then((data) => {
219
220
  this.facets = data
221
+ EventBus.emit('available-facets', data)
220
222
  this.options = data
221
223
 
222
224
  // create top level of options in cascader
@@ -24,26 +24,27 @@
24
24
  <Tabs
25
25
  v-if="tabs.length > 1 && connectivityInfo"
26
26
  :tabTitles="tabs"
27
- :activeId="activeId"
27
+ :activeId="activeTabId"
28
28
  @titleClicked="tabClicked"
29
29
  @tab-close="tabClose"
30
30
  />
31
31
  <template v-for="tab in tabs" key="tab.id">
32
32
  <!-- Connectivity Info -->
33
- <template v-if="tab.id === 2">
33
+ <template v-if="tab.type === 'connectivity'">
34
34
  <connectivity-info
35
35
  :entry="connectivityInfo"
36
- v-show="tab.id === activeId"
37
- :ref="tab.id"
36
+ :availableAnatomyFacets="availableAnatomyFacets"
37
+ v-show="tab.id === activeTabId"
38
+ :ref="'connectivityTab_' + tab.id"
38
39
  />
39
40
  </template>
40
41
  <template v-else>
41
42
  <SidebarContent
42
43
  class="sidebar-content-container"
43
- v-show="tab.id === activeId"
44
+ v-show="tab.id === activeTabId"
44
45
  :contextCardEntry="tab.contextCard"
45
46
  :envVars="envVars"
46
- :ref="tab.id"
47
+ :ref="'searchTab_' + tab.id"
47
48
  @search-changed="searchChanged(tab.id, $event)"
48
49
  @hover-changed="hoverChanged($event)"
49
50
  />
@@ -105,14 +106,14 @@ export default {
105
106
  tabs: {
106
107
  type: Array,
107
108
  default: () => [
108
- { title: 'Search', id: 1 },
109
- { title: 'Connectivity', id: 2 }
109
+ { id: 1, title: 'Search', type: 'search' },
110
+ { id: 2, title: 'Connectivity', type: 'connectivity' }
110
111
  ],
111
112
  },
112
113
  /**
113
114
  * The active tab id for default tab.
114
115
  */
115
- activeId: {
116
+ activeTabId: {
116
117
  type: Number,
117
118
  default: 1,
118
119
  },
@@ -134,6 +135,7 @@ export default {
134
135
  data: function () {
135
136
  return {
136
137
  drawerOpen: false,
138
+
137
139
  }
138
140
  },
139
141
  methods: {
@@ -169,10 +171,38 @@ export default {
169
171
  this.drawerOpen = true
170
172
  // Because refs are in v-for, nextTick is needed here
171
173
  this.$nextTick(() => {
172
- // TODO: refs[1] is for `search` which should be renamed
173
- this.$refs[1][0].openSearch(facets, query)
174
+ const searchTabRef = this.getSearchTabRefById(1);
175
+ searchTabRef.openSearch(facets, query);
174
176
  })
175
177
  },
178
+ /**
179
+ * Get the tab object by tab id and type.
180
+ * If not found, return the first available tab.
181
+ */
182
+ getTabByIdAndType: function (id, type) {
183
+ const tabId = id || this.activeTabId;
184
+ const tabType = type || 'search'; // default to search tab
185
+ const tabObj = this.tabs.find((tab) => tab.id === tabId && tab.type === tabType);
186
+ const firstAvailableTab = this.tabs[0];
187
+ return tabObj || firstAvailableTab;
188
+ },
189
+ /**
190
+ * Get the ref id of the tab by id and type.
191
+ */
192
+ getTabRefId: function (id, type) {
193
+ let refIdPrefix = 'searchTab_'; // default to search tab
194
+ if (type === 'connectivity') {
195
+ refIdPrefix = 'connectivityTab_';
196
+ }
197
+ const tabObj = this.getTabByIdAndType(id, type);
198
+ const tabRefId = refIdPrefix + tabObj.id;
199
+ return tabRefId;
200
+ },
201
+ getSearchTabRefById: function (id) {
202
+ const searchTabId = id || 1; // to use id when there are multiple search tabs
203
+ const searchTabRefId = this.getTabRefId(searchTabId, 'search');
204
+ return this.$refs[searchTabRefId][0];
205
+ },
176
206
  /**
177
207
  * @vuese
178
208
  * The function to add filters to sidebar search.
@@ -184,14 +214,16 @@ export default {
184
214
 
185
215
  // Because refs are in v-for, nextTick is needed here
186
216
  this.$nextTick(() => {
187
- this.$refs[this.activeId][0].addFilter(filter)
217
+ const searchTabRef = this.getSearchTabRefById(1);
218
+ searchTabRef.addFilter(filter)
188
219
  })
189
220
  },
190
221
  openNeuronSearch: function (neuron) {
191
222
  this.drawerOpen = true
192
223
  // Because refs are in v-for, nextTick is needed here
193
224
  this.$nextTick(() => {
194
- this.$refs[this.activeId][0].openSearch(
225
+ const searchTabRef = this.getSearchTabRefById(1);
226
+ searchTabRef.openSearch(
195
227
  '',
196
228
  undefined,
197
229
  'scicrunch-query-string/',
@@ -200,22 +232,24 @@ export default {
200
232
  })
201
233
  },
202
234
  getAlgoliaFacets: async function () {
203
- return await this.$refs[this.activeId][0].getAlgoliaFacets()
235
+ const searchTabRef = this.getSearchTabRefById(1);
236
+ return await searchTabRef.getAlgoliaFacets()
204
237
  },
205
238
  setDrawerOpen: function (value = true) {
206
239
  this.drawerOpen = value
207
240
  },
208
241
  /**
209
242
  * @vuese
210
- * The function to emit 'tabClicked' event with tab's `id` when user clicks the sidebar tab.
211
- * @arg id
243
+ * The function to emit 'tabClicked' event with tab's `id` and tab's `type`
244
+ * when user clicks the sidebar tab.
245
+ * @arg {id, type}
212
246
  */
213
- tabClicked: function (id) {
247
+ tabClicked: function ({id, type}) {
214
248
  /**
215
249
  * This event is emitted when user click sidebar's tab.
216
- * @arg id
250
+ * @arg {id, type}
217
251
  */
218
- this.$emit('tabClicked', id)
252
+ this.$emit('tabClicked', {id, type});
219
253
  },
220
254
  tabClose: function (id) {
221
255
  this.$emit('connectivity-info-close');
@@ -265,9 +299,16 @@ export default {
265
299
  this.$emit('datalink-clicked', payLoad);
266
300
  })
267
301
  EventBus.on('onConnectivityActionClick', (payLoad) => {
268
- this.tabClicked(1);
302
+ // switch to search tab with tab id: 1
303
+ this.tabClicked({id: 1, type: 'search'});
269
304
  this.$emit('actionClick', payLoad);
270
305
  })
306
+
307
+ // Get available anatomy facets for the connectivity info
308
+ EventBus.on('available-facets', (payLoad) => {
309
+ this.availableAnatomyFacets = payLoad.find((facet) => facet.label === 'Anatomical Structure').children
310
+ })
311
+
271
312
  },
272
313
  }
273
314
  </script>
@@ -458,10 +458,27 @@ export default {
458
458
  </script>
459
459
 
460
460
  <style lang="scss" scoped>
461
- .dataset-card:hover {
462
- border-style: solid;
463
- border-color: var(--el-color-primary);
464
- border-radius: 5px;
461
+ .dataset-card {
462
+ position: relative;
463
+
464
+ &::before {
465
+ content: "";
466
+ display: block;
467
+ width: calc(100% - 15px);
468
+ height: 100%;
469
+ position: absolute;
470
+ top: 7px;
471
+ left: 7px;
472
+ border-style: solid;
473
+ border-radius: 5px;
474
+ border-color: transparent;
475
+ }
476
+
477
+ &:hover {
478
+ &::before {
479
+ border-color: var(--el-color-primary);
480
+ }
481
+ }
465
482
  }
466
483
 
467
484
  .content-card {
@@ -9,7 +9,7 @@
9
9
  <div
10
10
  class="title-text-table"
11
11
  v-bind:class="{ highlightText: title.id == activeId }"
12
- v-on:click="titleClicked(title.id)"
12
+ v-on:click="titleClicked(title.id, title.type)"
13
13
  >
14
14
  <div class="title-text">
15
15
  {{ title.title }}
@@ -44,8 +44,8 @@ export default {
44
44
  },
45
45
  },
46
46
  methods: {
47
- titleClicked: function (id) {
48
- this.$emit('titleClicked', id)
47
+ titleClicked: function (id, type) {
48
+ this.$emit('titleClicked', {id, type})
49
49
  },
50
50
  tabClose: function (id) {
51
51
  this.$emit('tab-close', id);