@abi-software/map-side-bar 2.4.0-isan-2 → 2.4.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abi-software/map-side-bar",
3
- "version": "2.4.0-isan-2",
3
+ "version": "2.4.1",
4
4
  "files": [
5
5
  "dist/*",
6
6
  "src/*",
@@ -39,6 +39,7 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "@abi-software/gallery": "^1.1.1",
42
+ "@abi-software/map-utilities": "^1.1.0",
42
43
  "@abi-software/svg-sprite": "^1.0.0",
43
44
  "@element-plus/icons-vue": "^2.3.1",
44
45
  "algoliasearch": "^4.10.5",
package/src/App.vue CHANGED
@@ -6,7 +6,6 @@
6
6
  />
7
7
  <div class="options-container">
8
8
  <div>Click arrow to open sidebar</div>
9
- <el-button @click="openPMRSearch">PMR Search</el-button>
10
9
  <el-button @click="openSearch">search Uberon from refs</el-button>
11
10
  <el-button @click="singleFacets">Add heart to Filter</el-button>
12
11
  <el-button @click="addStomach">Add stomach to Filter</el-button>
@@ -113,7 +112,6 @@ export default {
113
112
  BL_SERVER_URL: import.meta.env.VITE_APP_BL_SERVER_URL,
114
113
  NL_LINK_PREFIX: import.meta.env.VITE_APP_NL_LINK_PREFIX,
115
114
  ROOT_URL: import.meta.env.VITE_APP_ROOT_URL,
116
- FLATMAP_API_LOCATION: import.meta.env.VITE_APP_FLATMAP_API_LOCATION,
117
115
  },
118
116
  connectivityInput: exampleConnectivityInput,
119
117
  activeId: 1,
@@ -121,7 +119,7 @@ export default {
121
119
  },
122
120
  methods: {
123
121
  hoverChanged: function (data) {
124
- // console.log('hoverChanged', data)
122
+ console.log('hoverChanged', data)
125
123
  },
126
124
  searchChanged: function (data) {
127
125
  console.log(data)
@@ -133,31 +131,17 @@ export default {
133
131
  action: function (action) {
134
132
  console.log('action fired: ', action)
135
133
  let facets = [];
136
- if (action.labels) {
137
- facets.push(
138
- ...action.labels.map(val => ({
139
- facet: capitalise(val),
140
- term: "Anatomical structure",
141
- facetPropPath: "anatomy.organ.category.name",
142
- }))
143
- );
144
- if (this.$refs.sideBar) {
145
- console.log('openSearch', facets)
146
- this.$refs.sideBar.openSearch(facets, "");
147
- }
148
- }
149
- },
150
- openPMRSearch: function () {
151
- this.$refs.sideBar.openSearch(
152
- [
153
- {
154
- facet: "PMR",
155
- term: "Data type",
156
- facetPropPath: "item.types.name",
157
- }
158
- ],
159
- 'cardiovascular multiscale model'
134
+ facets.push(
135
+ ...action.labels.map(val => ({
136
+ facet: capitalise(val),
137
+ term: "Anatomical structure",
138
+ facetPropPath: "anatomy.organ.category.name",
139
+ }))
160
140
  );
141
+ if (this.$refs.sideBar) {
142
+ console.log('openSearch', facets)
143
+ this.$refs.sideBar.openSearch(facets, "");
144
+ }
161
145
  },
162
146
  openSearch: function () {
163
147
  this.$refs.sideBar.openSearch(
@@ -100,7 +100,6 @@ export class AlgoliaClient {
100
100
  for (let res of results) {
101
101
  newResult = { ...res }
102
102
  newResult = {
103
- dataSource: 'SPARC',
104
103
  anatomy: res.anatomy ? res.anatomy.organ.map((organ => organ.curie)) : undefined,
105
104
  doi: res.item.curie.split(':')[1],
106
105
  name: res.item.name,
@@ -153,48 +152,35 @@ export class AlgoliaClient {
153
152
  * Get Search results
154
153
  * This is using fetch from the Algolia API
155
154
  */
156
- search(filter, query = '', offset = 0, length = 8) {
157
- console.log('searching', filter, query, offset, length)
158
- // If the length is 0, return an empty result
159
- if (length === 0) {
160
- return new Promise(resolve => {
161
- resolve({
162
- items: [],
163
- total: 0,
164
- discoverIds: [],
165
- dois: []
155
+ search(filter, query = '', hitsperPage = 10, page = 1) {
156
+ return new Promise(resolve => {
157
+ this.index
158
+ .search(query, {
159
+ facets: ['*'],
160
+ hitsPerPage: hitsperPage,
161
+ page: page - 1,
162
+ filters: filter,
163
+ attributesToHighlight: [],
164
+ attributesToRetrieve: [
165
+ 'pennsieve.publishDate',
166
+ 'pennsieve.updatedAt',
167
+ 'item.curie',
168
+ 'item.name',
169
+ 'item.description',
170
+ 'objectID',
171
+ 'anatomy.organ.curie'
172
+ ],
166
173
  })
167
- })
168
- } else {
169
- return new Promise(resolve => {
170
- this.index
171
- .search(query, {
172
- facets: ['*'],
173
- offset: offset,
174
- length: length,
175
- filters: filter,
176
- attributesToHighlight: [],
177
- attributesToRetrieve: [
178
- 'pennsieve.publishDate',
179
- 'pennsieve.updatedAt',
180
- 'item.curie',
181
- 'item.name',
182
- 'item.description',
183
- 'objectID',
184
- 'anatomy.organ.curie'
185
- ],
186
- })
187
- .then(response => {
188
- let searchData = {
189
- items: this._processResultsForCards(response.hits),
190
- total: response.nbHits,
191
- discoverIds: response.hits.map(r => r.pennsieve ? r.pennsieve.identifier : r.objectID),
192
- dois: response.hits.map(r => r.item.curie.split(':')[1])
193
- }
194
- resolve(searchData)
195
- })
196
- })
197
- }
174
+ .then(response => {
175
+ let searchData = {
176
+ items: this._processResultsForCards(response.hits),
177
+ total: response.nbHits,
178
+ discoverIds: response.hits.map(r => r.pennsieve ? r.pennsieve.identifier : r.objectID),
179
+ dois: response.hits.map(r => r.item.curie.split(':')[1])
180
+ }
181
+ resolve(searchData)
182
+ })
183
+ })
198
184
  }
199
185
 
200
186
  /**
@@ -60,13 +60,8 @@ export function getFilters(selectedFacetArray=undefined) {
60
60
  return 'NOT item.published.status:embargo'
61
61
  }
62
62
 
63
- // Switch the 'term' attribute to 'label' if 'label' does not exist. Use facet2 if available
64
- selectedFacetArray.forEach(f=>{
65
- f.label=f.facet
66
- if (f.facet2) {
67
- f.label = f.facet2
68
- }
69
- })
63
+ // Switch the 'term' attribute to 'label' if 'label' does not exist
64
+ selectedFacetArray.forEach(f=>f.label=f.facet)
70
65
 
71
66
 
72
67
  let facets = removeShowAllFacets(selectedFacetArray)
@@ -4,7 +4,24 @@
4
4
  <div class="connectivity-info-title">
5
5
  <div>
6
6
  <div class="block" v-if="entry.title">
7
- <div class="title">{{ capitalise(entry.title) }}</div>
7
+ <div class="title">
8
+ {{ capitalise(entry.title) }}
9
+ <template v-if="entry.featuresAlert">
10
+ <el-popover
11
+ width="250"
12
+ trigger="hover"
13
+ :teleported="false"
14
+ popper-class="popover-origin-help"
15
+ >
16
+ <template #reference>
17
+ <el-icon class="alert"><el-icon-warn-triangle-filled /></el-icon>
18
+ </template>
19
+ <span style="word-break: keep-all">
20
+ {{ entry.featuresAlert }}
21
+ </span>
22
+ </el-popover>
23
+ </template>
24
+ </div>
8
25
  <div
9
26
  v-if="
10
27
  entry.provenanceTaxonomyLabel &&
@@ -20,12 +37,12 @@
20
37
  </div>
21
38
  <external-resource-card :resources="resources"></external-resource-card>
22
39
  </div>
23
- <div>
40
+ <div class="title-buttons">
24
41
  <el-popover
25
- width="200"
42
+ width="auto"
26
43
  trigger="hover"
27
44
  :teleported="false"
28
- popper-class="popover-origin-help"
45
+ popper-class="popover-map-pin"
29
46
  >
30
47
  <template #reference>
31
48
  <el-button class="button-circle" circle @click="showConnectivity(entry)">
@@ -38,24 +55,9 @@
38
55
  Show connectivity on map
39
56
  </span>
40
57
  </el-popover>
58
+ <CopyToClipboard :content="updatedCopyContent" />
41
59
  </div>
42
60
  </div>
43
- <div v-if="featuresAlert" class="attribute-title-container">
44
- <span class="attribute-title">Alert</span>
45
- <el-popover
46
- width="250"
47
- trigger="hover"
48
- :teleported="false"
49
- popper-class="popover-origin-help"
50
- >
51
- <template #reference>
52
- <el-icon class="info"><el-icon-warning /></el-icon>
53
- </template>
54
- <span style="word-break: keep-all">
55
- {{ featuresAlert }}
56
- </span>
57
- </el-popover>
58
- </div>
59
61
  <div class="content-container scrollbar">
60
62
  {{ entry.paths }}
61
63
  <div v-if="entry.origins && entry.origins.length > 0" class="block">
@@ -191,6 +193,8 @@ import {
191
193
  } from 'element-plus'
192
194
  import ExternalResourceCard from './ExternalResourceCard.vue'
193
195
  import EventBus from './EventBus.js'
196
+ import { CopyToClipboard } from '@abi-software/map-utilities';
197
+ import '@abi-software/map-utilities/dist/style.css';
194
198
 
195
199
  const titleCase = (str) => {
196
200
  return str.replace(/\w\S*/g, (t) => {
@@ -213,6 +217,7 @@ export default {
213
217
  ElIconArrowDown,
214
218
  ElIconWarning,
215
219
  ExternalResourceCard,
220
+ CopyToClipboard,
216
221
  },
217
222
  props: {
218
223
  entry: {
@@ -225,6 +230,7 @@ export default {
225
230
  originsWithDatasets: [],
226
231
  componentsWithDatasets: [],
227
232
  resource: undefined,
233
+ featuresAlert: undefined,
228
234
  }),
229
235
  },
230
236
  availableAnatomyFacets: {
@@ -232,7 +238,6 @@ export default {
232
238
  default: () => [],
233
239
  },
234
240
  },
235
- // inject: ['getFeaturesAlert'],
236
241
  data: function () {
237
242
  return {
238
243
  controller: undefined,
@@ -260,6 +265,9 @@ export default {
260
265
  },
261
266
  },
262
267
  computed: {
268
+ updatedCopyContent: function () {
269
+ return this.getUpdateCopyContent();
270
+ },
263
271
  resources: function () {
264
272
  let resources = [];
265
273
  if (this.entry && this.entry.hyperlinks) {
@@ -267,9 +275,6 @@ export default {
267
275
  }
268
276
  return resources;
269
277
  },
270
- featuresAlert() {
271
- // return this.getFeaturesAlert()
272
- },
273
278
  originDescription: function () {
274
279
  if (
275
280
  this.entry &&
@@ -347,6 +352,100 @@ export default {
347
352
  // connected to flatmapvuer > moveMap(featureIds) function
348
353
  this.$emit('show-connectivity', featureIds);
349
354
  },
355
+ getUpdateCopyContent: function () {
356
+ if (!this.entry) {
357
+ return '';
358
+ }
359
+
360
+ const contentArray = [];
361
+
362
+ // Use <div> instead of <h1>..<h6> or <p>
363
+ // to avoid default formatting on font size and margin
364
+
365
+ // Title
366
+ if (this.entry.title) {
367
+ contentArray.push(`<div><strong>${capitalise(this.entry.title)}</strong></div>`);
368
+ } else {
369
+ contentArray.push(`<div><strong>${this.entry.featureId}</strong></div>`);
370
+ }
371
+
372
+ // Description
373
+ if (this.entry.provenanceTaxonomyLabel?.length) {
374
+ contentArray.push(`<div>${this.provSpeciesDescription}</div>`);
375
+ }
376
+
377
+ // PubMed URL
378
+ if (this.resources?.length) {
379
+ const pubmedContents = [];
380
+ this.resources.forEach((resource) => {
381
+ let pubmedContent = '';
382
+ if (resource.id === 'pubmed') {
383
+ pubmedContent += `<div><strong>PubMed URL:</strong></div>`;
384
+ pubmedContent += '\n';
385
+ pubmedContent += `<div><a href="${resource.url}">${resource.url}</a></div>`;
386
+ }
387
+ pubmedContents.push(pubmedContent);
388
+ });
389
+ contentArray.push(pubmedContents.join('\n\n<br>'));
390
+ }
391
+
392
+ // entry.paths
393
+ if (this.entry.paths) {
394
+ contentArray.push(`<div>${this.entry.paths}</div>`);
395
+ }
396
+
397
+ function transformData(title, items, itemsWithDatasets = []) {
398
+ let contentString = `<div><strong>${title}</strong></div>`;
399
+ const transformedItems = [];
400
+ items.forEach((item) => {
401
+ let itemNames = [];
402
+ item.split(',').forEach((name) => {
403
+ const match = itemsWithDatasets.find((a) => a.name === name.trim());
404
+ if (match) {
405
+ itemNames.push(`${capitalise(name)} (${match.id})`);
406
+ } else {
407
+ itemNames.push(`${capitalise(name)}`);
408
+ }
409
+ });
410
+ transformedItems.push(itemNames.join(','));
411
+ });
412
+ const contentList = transformedItems
413
+ .map((item) => `<li>${item}</li>`)
414
+ .join('\n');
415
+ contentString += '\n';
416
+ contentString += `<ul>${contentList}</ul>`;
417
+ return contentString;
418
+ }
419
+
420
+ // Origins
421
+ if (this.entry.origins?.length) {
422
+ const title = 'Origin';
423
+ const origins = this.entry.origins;
424
+ const originsWithDatasets = this.entry.originsWithDatasets;
425
+ const transformedOrigins = transformData(title, origins, originsWithDatasets);
426
+ contentArray.push(transformedOrigins);
427
+ }
428
+
429
+ // Components
430
+ if (this.entry.components?.length) {
431
+ const title = 'Components';
432
+ const components = this.entry.components;
433
+ const componentsWithDatasets = this.entry.componentsWithDatasets;
434
+ const transformedComponents = transformData(title, components, componentsWithDatasets);
435
+ contentArray.push(transformedComponents);
436
+ }
437
+
438
+ // Destination
439
+ if (this.entry.destinations?.length) {
440
+ const title = 'Destination';
441
+ const destinations = this.entry.destinations;
442
+ const destinationsWithDatasets = this.entry.destinationsWithDatasets;
443
+ const transformedDestinations = transformData(title, destinations, destinationsWithDatasets);
444
+ contentArray.push(transformedDestinations);
445
+ }
446
+
447
+ return contentArray.join('\n\n<br>');
448
+ },
350
449
  },
351
450
  }
352
451
  </script>
@@ -390,6 +489,7 @@ export default {
390
489
  }
391
490
 
392
491
  .button-circle {
492
+ margin: 0;
393
493
  width: 24px !important;
394
494
  height: 24px !important;
395
495
 
@@ -415,6 +515,9 @@ export default {
415
515
  :deep(.popover-origin-help.el-popover) {
416
516
  text-transform: none !important; // need to overide the tooltip text transform
417
517
  border: 1px solid $app-primary-color;
518
+ font-weight: 400;
519
+ font-family: Asap, sans-serif, Helvetica;
520
+
418
521
  .el-popper__arrow {
419
522
  &:before {
420
523
  border-color: $app-primary-color;
@@ -423,12 +526,27 @@ export default {
423
526
  }
424
527
  }
425
528
 
529
+ .info,
530
+ .alert {
531
+ color: #8300bf;
532
+ }
533
+
426
534
  .info {
427
535
  transform: rotate(180deg);
428
- color: #8300bf;
429
536
  margin-left: 8px;
430
537
  }
431
538
 
539
+ .alert {
540
+ margin-left: 5px;
541
+ vertical-align: text-bottom;
542
+
543
+ &,
544
+ > svg {
545
+ width: 1.25rem;
546
+ height: 1.25rem;
547
+ }
548
+ }
549
+
432
550
  .seperator {
433
551
  width: 90%;
434
552
  height: 1px;
@@ -616,4 +734,36 @@ export default {
616
734
  .tooltip-container::after {
617
735
  top: 99.4%;
618
736
  }
737
+
738
+ .title-buttons {
739
+ display: flex;
740
+ flex-direction: row;
741
+ gap: 0.5rem;
742
+
743
+ :deep(.copy-clipboard-button) {
744
+ &,
745
+ &:hover,
746
+ &:focus {
747
+ border-color: $app-primary-color !important;
748
+ border-radius: 50%;
749
+ }
750
+ }
751
+ }
752
+
753
+ :deep(.el-popper.popover-map-pin) {
754
+ padding: 4px 10px;
755
+ min-width: max-content;
756
+ font-family: Asap;
757
+ font-size: 12px;
758
+ line-height: inherit;
759
+ color: inherit;
760
+ background: #f3ecf6 !important;
761
+ border: 1px solid $app-primary-color;
762
+
763
+ & .el-popper__arrow::before {
764
+ border: 1px solid;
765
+ border-color: $app-primary-color;
766
+ background: #f3ecf6;
767
+ }
768
+ }
619
769
  </style>
@@ -19,7 +19,6 @@
19
19
  />
20
20
  </span>
21
21
  <div class="card-right">
22
- <el-tag type="primary" class="source-tag">SPARC Dataset</el-tag>
23
22
  <div class="title" @click="cardClicked">{{ entry.name }}</div>
24
23
  <div class="details">
25
24
  {{ contributors }} {{ entry.publishDate ? `(${publishYear})` : '' }}
@@ -47,6 +46,11 @@
47
46
  @categoryChanged="categoryChanged"
48
47
  />
49
48
  </div>
49
+
50
+ <!-- Copy to clipboard button container -->
51
+ <div class="float-button-container">
52
+ <CopyToClipboard :content="copyContent" />
53
+ </div>
50
54
  </div>
51
55
  </div>
52
56
  </div>
@@ -65,6 +69,8 @@ import EventBus from './EventBus.js'
65
69
  import speciesMap from './species-map.js'
66
70
  import ImageGallery from './ImageGallery.vue'
67
71
  import MissingImage from '@/../assets/missing-image.svg'
72
+ import { CopyToClipboard } from '@abi-software/map-utilities';
73
+ import '@abi-software/map-utilities/dist/style.css';
68
74
 
69
75
  export default {
70
76
  data() {
@@ -77,7 +83,8 @@ export default {
77
83
  BadgesGroup,
78
84
  ImageGallery,
79
85
  Button,
80
- Icon
86
+ Icon,
87
+ CopyToClipboard,
81
88
  },
82
89
  props: {
83
90
  /**
@@ -103,6 +110,7 @@ export default {
103
110
  lastDoi: undefined,
104
111
  biolucidaData: undefined,
105
112
  currentCategory: 'All',
113
+ copyContent: '',
106
114
  }
107
115
  },
108
116
  computed: {
@@ -155,6 +163,9 @@ export default {
155
163
  return this.entry.publishDate.split('-')[0]
156
164
  },
157
165
  },
166
+ mounted: function () {
167
+ this.updateCopyContent();
168
+ },
158
169
  methods: {
159
170
  cardClicked: function () {
160
171
  this.openDataset()
@@ -227,6 +238,7 @@ export default {
227
238
  this.dataLocation = `https://sparc.science/datasets/${data.id}?type=dataset`
228
239
  this.getBiolucidaInfo(this.discoverId)
229
240
  this.loading = false
241
+ this.updateCopyContent();
230
242
  })
231
243
  .catch(() => {
232
244
  //set defaults if we hit an error
@@ -249,6 +261,66 @@ export default {
249
261
  if (data.status == 'success') this.biolucidaData = data
250
262
  })
251
263
  },
264
+ updateCopyContent: function () {
265
+ const contentArray = [];
266
+
267
+ // Use <div> instead of <h1>..<h6> or <p>
268
+ // to avoid default formatting on font size and margin
269
+
270
+ // Title
271
+ if (this.entry.name) {
272
+ contentArray.push(`<div><strong>${this.entry.name}</strong></div>`);
273
+ }
274
+
275
+ // Contributors and Publish Date
276
+ if (this.contributors) {
277
+ let details = this.contributors;
278
+
279
+ if (this.entry.publishDate) {
280
+ details += ` (${this.publishYear})`;
281
+ }
282
+ contentArray.push(`<div>${details}</div>`);
283
+ }
284
+
285
+ // samples
286
+ if (this.samples) {
287
+ contentArray.push(`<div>${this.samples}</div>`);
288
+ }
289
+
290
+ // DOI
291
+ if (this.entry.doi) {
292
+ let doiContent = `<div><strong>DOI:</strong></div>`;
293
+ doiContent += `\n`;
294
+ doiContent += `<a href="${this.entry.doi}">${this.entry.doi}</a>`;
295
+ contentArray.push(`<div>${doiContent}</div>`);
296
+ }
297
+
298
+ // Dataset ID
299
+ if (this.entry.datasetId) {
300
+ let datasetIdContent = `<div><strong>Dataset ID:</strong></div>`;
301
+ datasetIdContent += `\n`;
302
+ datasetIdContent += `${this.entry.datasetId}`;
303
+ contentArray.push(`<div>${datasetIdContent}</div>`);
304
+ }
305
+
306
+ // Dataset URL
307
+ if (this.dataLocation) {
308
+ let dataLocationContent = `<div><strong>Dataset URL:</strong></div>`;
309
+ dataLocationContent += `\n`;
310
+ dataLocationContent += `<a href="${this.dataLocation}">${this.dataLocation}</a>`;
311
+ contentArray.push(`<div>${dataLocationContent}</div>`);
312
+ }
313
+
314
+ // Dataset version
315
+ if (this.version) {
316
+ let versionContent = `<div><strong>Dataset version:</strong></div>`;
317
+ versionContent += `\n`;
318
+ versionContent += `${this.version}`;
319
+ contentArray.push(`<div>${versionContent}</div>`);
320
+ }
321
+
322
+ this.copyContent = contentArray.join('\n\n<br>');
323
+ },
252
324
  },
253
325
  created: function () {
254
326
  this.getBanner()
@@ -283,15 +355,6 @@ export default {
283
355
  color: #484848;
284
356
  cursor: pointer;
285
357
  }
286
-
287
- .source-tag {
288
- margin-bottom: 0.75rem;
289
- margin-right: 2rem;
290
- position: absolute;
291
- bottom: 0;
292
- right: 0;
293
- }
294
-
295
358
  .card {
296
359
  padding-top: 18px;
297
360
  position: relative;
@@ -364,4 +427,17 @@ export default {
364
427
  .loading-icon :deep(.el-loading-spinner .path) {
365
428
  stroke: $app-primary-color;
366
429
  }
430
+
431
+ .float-button-container {
432
+ position: absolute;
433
+ bottom: 8px;
434
+ right: 16px;
435
+ opacity: 0;
436
+ visibility: hidden;
437
+
438
+ .card:hover & {
439
+ opacity: 1;
440
+ visibility: visible;
441
+ }
442
+ }
367
443
  </style>