@abi-software/map-utilities 1.4.3-isan.0 → 1.5.0-beta.0

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-utilities",
3
- "version": "1.4.3-isan.0",
3
+ "version": "1.5.0-beta.0",
4
4
  "files": [
5
5
  "dist/*",
6
6
  "src/*",
package/src/App.vue CHANGED
@@ -130,7 +130,7 @@ function onActionClick(value) {
130
130
  * Tooltip
131
131
  */
132
132
  const tooltipDisplay = ref(false);
133
- const tooltipEntry = ref([]);
133
+ const tooltipEntry = ref({});
134
134
  const featuresAlert = ref(undefined);
135
135
  const annotationDisplay = ref(false);
136
136
  const annotationEntry = ref({});
@@ -141,90 +141,33 @@ provide(/* key */ "userApiKey", /* value */ undefined);
141
141
 
142
142
  function addTooltipEntry() {
143
143
  tooltipDisplay.value = true;
144
- tooltipEntry.value = [
145
- {
146
- destinations: ["eccrine sweat gland of the trunk"],
147
- origins: [
148
- "Sixth thoracic ganglion",
149
- "Twelfth thoracic ganglion",
150
- "Fifth thoracic ganglion",
151
- "Ninth thoracic ganglion",
152
- "Seventh thoracic ganglion",
153
- "Eighth thoracic ganglion",
154
- "Fourth thoracic ganglion",
155
- "Tenth thoracic ganglion",
156
- "Eleventh thoracic ganglion",
157
- ],
158
- components: ["nerve"],
159
- destinationsWithDatasets: [
160
- { id: "ILX:0795061", name: "eccrine sweat gland of the trunk" },
161
- ],
162
- originsWithDatasets: [
163
- { id: "ILX:0784378", name: "Ninth thoracic ganglion" },
164
- { id: "ILX:0784569", name: "Tenth thoracic ganglion" },
165
- { id: "ILX:0784721", name: "Eighth thoracic ganglion" },
166
- { id: "ILX:0786141", name: "Fifth thoracic ganglion" },
167
- { id: "ILX:0786272", name: "Fourth thoracic ganglion" },
168
- { id: "ILX:0787009", name: "Twelfth thoracic ganglion" },
169
- { id: "ILX:0787015", name: "Eleventh thoracic ganglion" },
170
- { id: "ILX:0789947", name: "Sixth thoracic ganglion" },
171
- { id: "ILX:0790482", name: "Seventh thoracic ganglion" },
172
- ],
173
- componentsWithDatasets: [{ id: "UBERON:0001021", name: "nerve" }],
174
- title: "neuron type swglnd 161",
175
- featureId: ["ilxtr:sparc-nlp/swglnd/161"],
176
- hyperlinks: [
177
- "https://doi.org/10.1007/s10286-015-0282-1",
178
- "https://doi.org/10.1111/bjd.15808",
179
- "https://doi.org/10.1159/000060678",
180
- ],
181
- provenanceTaxonomy: ["NCBITaxon:9606"],
182
- provenanceTaxonomyLabel: ["Homo sapiens"],
183
- knowledgeSource: "sckan-2024-09-21-npo",
184
- mapId: "rat-flatmap",
185
- mapuuid: "b4ae1699-5690-5640-97b7-d711ae02dcb9",
186
- },
187
- {
188
- destinations: ["intramural ganglion of the kidney"],
189
- origins: ["dorsal motor nucleus of vagus nerve"],
190
- components: [
191
- "renal nerve plexus",
192
- "aortic plexus",
193
- "esophageal vagus trunk",
194
- "vagus X nerve trunk",
195
- "vagus nerve",
196
- ],
197
- destinationsWithDatasets: [
198
- { id: "ILX:0795056", name: "intramural ganglion of the kidney" },
199
- ],
200
- originsWithDatasets: [
201
- { id: "UBERON:0002870", name: "dorsal motor nucleus of vagus nerve" },
202
- ],
203
- componentsWithDatasets: [
204
- { id: "ILX:0794853", name: "esophageal vagus trunk" },
205
- { id: "UBERON:0001759", name: "vagus nerve" },
206
- { id: "UBERON:0003535", name: "vagus X nerve trunk" },
207
- { id: "UBERON:0018676", name: "renal nerve plexus" },
208
- { id: "UBERON:0035772", name: "aortic plexus" },
209
- ],
210
- title:
211
- "dorsal motor nucleus of vagus nerve to intramural ganglia of the kidney via vagus nerve via esophageal vagus trunk via vagal trunks via aortic plexus via renal plexus",
212
- featureId: ["ilxtr:sparc-nlp/kidney/135"],
213
- hyperlinks: [
214
- "https://uilx.org/tgbugs/u/r/isbn-13/978-0323680424",
215
- "https://doi.org/10.1016/j.aanat.2015.11.004",
216
- ],
217
- provenanceTaxonomy: ["NCBITaxon:9606"],
218
- provenanceTaxonomyLabel: ["Homo sapiens"],
219
- knowledgeSource: "sckan-2024-09-21-npo",
220
- mapId: "rat-flatmap",
221
- mapuuid: "b4ae1699-5690-5640-97b7-d711ae02dcb9",
222
- },
223
- ];
144
+ tooltipEntry.value = {
145
+ destinations: [null],
146
+ origins: [null],
147
+ components: ["pudendal nerve"],
148
+ destinationsWithDatasets: [
149
+ { id: "UBERON:0004917", name: "urethral sphincter" },
150
+ ],
151
+ originsWithDatasets: [
152
+ { id: "UBERON:0022278", name: "nucleus of pudendal nerve" },
153
+ ],
154
+ componentsWithDatasets: [{ id: "UBERON:0011390", name: "pudendal nerve" }],
155
+ title:
156
+ "Nucleus of the pudendal nerve to urethral sphincter via pudendal nerve",
157
+ featureId: ["ilxtr:sparc-nlp/mmset1/1"],
158
+ hyperlinks: [
159
+ {
160
+ url: "https://pubmed.ncbi.nlm.nih.gov/?term=%2F%2Fdoi.org%2F10.1155%252F2012%252F816274",
161
+ id: "pubmed",
162
+ },
163
+ ],
164
+ provenanceTaxonomy: ["NCBITaxon:9606"],
165
+ provenanceTaxonomyLabel: ["Homo sapiens"],
166
+ };
224
167
  }
225
168
  function removeTooltipEntry() {
226
169
  tooltipDisplay.value = false;
227
- tooltipEntry.value = [];
170
+ tooltipEntry.value = {};
228
171
  }
229
172
  function addAnnotationEntry() {
230
173
  tooltipDisplay.value = true;
@@ -291,7 +234,7 @@ function setColourField(treeData, nodeData, activeColour) {
291
234
  function setColour(nodeData, value) {
292
235
  if (nodeData && nodeData.isPrimitives) {
293
236
  const activeColour = value ? value : nodeData.defaultColour;
294
- setColourField(treeDataEntry.value, nodeData, activeColour);
237
+ setColourField(treeDataEntry.value, nodeData, activeColour)
295
238
  }
296
239
  }
297
240
  function checkAll(value) {
@@ -320,7 +263,7 @@ const createData = ref({
320
263
  editingIndex: -1,
321
264
  faceIndex: -1,
322
265
  toBeDeleted: false,
323
- });
266
+ })
324
267
  function cancelCreate() {
325
268
  console.log("🚀 ~ CreateTooltipContent : cancelCreate");
326
269
  }
@@ -479,14 +422,14 @@ function confirmCreate(value) {
479
422
  Add Tooltip Entry
480
423
  </el-button>
481
424
  <el-button
482
- v-show="tooltipEntry.length > 0"
425
+ v-show="Object.keys(tooltipEntry).length > 0"
483
426
  @click="removeTooltipEntry"
484
427
  size="small"
485
428
  >
486
429
  Remove Tooltip Entry
487
430
  </el-button>
488
431
  <el-button
489
- v-show="tooltipEntry.length === 0"
432
+ v-show="!Object.keys(tooltipEntry).length > 0"
490
433
  @click="addAnnotationEntry"
491
434
  size="small"
492
435
  >
@@ -506,18 +449,10 @@ function confirmCreate(value) {
506
449
  <h3>TreeControls - {{ mapType }}</h3>
507
450
  </el-col>
508
451
  <el-col>
509
- <el-button
510
- v-show="mapType === 'scaffold'"
511
- @click="switchTreeEntry('flatmap')"
512
- size="small"
513
- >
452
+ <el-button v-show="mapType==='scaffold'" @click="switchTreeEntry('flatmap')" size="small">
514
453
  Display Flatmap Tree
515
454
  </el-button>
516
- <el-button
517
- v-show="mapType === 'flatmap'"
518
- @click="switchTreeEntry('scaffold')"
519
- size="small"
520
- >
455
+ <el-button v-show="mapType==='flatmap'" @click="switchTreeEntry('scaffold')" size="small">
521
456
  Display Scaffold Tree
522
457
  </el-button>
523
458
  </el-col>
@@ -527,10 +462,16 @@ function confirmCreate(value) {
527
462
  <h3>Connectivity Graph</h3>
528
463
  </el-col>
529
464
  <el-col>
530
- <el-button @click="showConnectivityGraph = true" size="small">
465
+ <el-button
466
+ @click="showConnectivityGraph = true"
467
+ size="small"
468
+ >
531
469
  Show connectivity graph
532
470
  </el-button>
533
- <el-button @click="showConnectivityGraph = false" size="small">
471
+ <el-button
472
+ @click="showConnectivityGraph = false"
473
+ size="small"
474
+ >
534
475
  Hide connectivity graph
535
476
  </el-button>
536
477
  </el-col>
@@ -627,9 +568,9 @@ function confirmCreate(value) {
627
568
  top: calc(50% - 100px);
628
569
  left: calc(50% - 200px);
629
570
  }
630
- .annotation-popup {
571
+ .annotation-popup{
631
572
  margin-top: 8px;
632
- width: 400px;
573
+ width:400px;
633
574
  border-style: solid;
634
575
  border-width: 1px;
635
576
  border-color: black;
@@ -160,10 +160,6 @@ export default {
160
160
  type: Array,
161
161
  default: [],
162
162
  },
163
- connectivityFromMap: {
164
- type: Object,
165
- default: () => null,
166
- },
167
163
  },
168
164
  data: function () {
169
165
  return {
@@ -188,20 +184,26 @@ export default {
188
184
  connectivityGraphContainer: null,
189
185
  };
190
186
  },
191
- watch: {
192
- connectivityFromMap: function (oldVal, newVal) {
193
- if (oldVal != newVal) {
194
- this.showSpinner();
195
- this.start();
196
- }
197
- }
198
- },
199
187
  mounted() {
200
188
  this.showSpinner();
201
189
  this.updateTooltipContainer();
202
190
  this.refreshCache();
203
191
  this.loadCacheData();
204
- this.start();
192
+ this.run()
193
+ .then((res) => {
194
+ if (res?.success) {
195
+ this.showGraph(this.entry);
196
+ } else if (res?.error) {
197
+ this.loadingError = res.error;
198
+ } else {
199
+ this.loadingError = 'Loading error!';
200
+ }
201
+ this.hideSpinner();
202
+ })
203
+ .catch((error) => {
204
+ this.loadingError = 'Loading error!';
205
+ this.hideSpinner();
206
+ });
205
207
  },
206
208
  methods: {
207
209
  updateTooltipContainer: function () {
@@ -273,22 +275,6 @@ export default {
273
275
 
274
276
  sessionStorage.setItem('connectivity-graph-expiry', expiry);
275
277
  },
276
- start: function () {
277
- this.run()
278
- .then((res) => {
279
- if (res?.success) {
280
- this.showGraph(this.entry);
281
- } else if (res?.error) {
282
- this.loadingError = res.error;
283
- } else {
284
- this.loadingError = 'Loading error!';
285
- }
286
- })
287
- .catch((error) => {
288
- this.loadingError = 'Loading error!';
289
- this.hideSpinner();
290
- });
291
- },
292
278
  run: async function () {
293
279
  if (!this.schemaVersion) {
294
280
  this.schemaVersion = await this.getSchemaVersion();
@@ -319,24 +305,8 @@ export default {
319
305
  showGraph: async function (neuronPath) {
320
306
  const graphCanvas = this.$refs.graphCanvas;
321
307
 
322
- // Update label data
323
- if (this.connectivityFromMap) {
324
- this.cacheLabels(this.connectivityFromMap);
325
- await this.getCachedTermLabels();
326
- }
327
-
328
308
  this.connectivityGraph = new ConnectivityGraph(this.labelCache, graphCanvas);
329
- const connectivityInfo = this.knowledgeByPath.get(neuronPath);
330
-
331
- // Update connectivity
332
- if (this.connectivityFromMap) {
333
- connectivityInfo.axons = this.connectivityFromMap.axons;
334
- connectivityInfo.connectivity = this.connectivityFromMap.connectivity;
335
- connectivityInfo.dendrites = this.connectivityFromMap.dendrites;
336
- connectivityInfo.somas = this.connectivityFromMap.somas;
337
- }
338
-
339
- await this.connectivityGraph.addConnectivity(connectivityInfo);
309
+ await this.connectivityGraph.addConnectivity(this.knowledgeByPath.get(neuronPath));
340
310
 
341
311
  this.connectivityGraph.showConnectivity(graphCanvas);
342
312
 
@@ -352,8 +322,6 @@ export default {
352
322
  */
353
323
  this.$emit('tap-node', data);
354
324
  });
355
-
356
- this.hideSpinner();
357
325
  },
358
326
  query: async function (sql, params) {
359
327
  const url = `${this.mapServer}knowledge/query/`;
@@ -41,7 +41,7 @@
41
41
  <strong class="sub-title">Previous submissions:</strong>
42
42
  </el-row>
43
43
  <div class="entry" v-for="(sub, index) in prevSubs" :key="index">
44
- <el-row class="dialog-text">
44
+ <el-row class="dialog-text" v-if="sub.creator">
45
45
  <strong>{{ formatTime(sub.created) }}</strong>
46
46
  {{ sub.creator.name }}
47
47
  </el-row>
@@ -65,7 +65,7 @@
65
65
  </div>
66
66
  </template>
67
67
  </template>
68
- <template v-if="authenticated">
68
+ <template v-if="authenticated || offlineAnnotationEnabled">
69
69
  <template v-if="isEditable">
70
70
  <el-row class="dialog-spacer"></el-row>
71
71
  <el-row v-if="!editing">
@@ -217,6 +217,9 @@ export default {
217
217
  updatedCopyContent: function () {
218
218
  return this.getUpdateCopyContent();
219
219
  },
220
+ offlineAnnotationEnabled: function () {
221
+ return this.annotationEntry["offline"];
222
+ },
220
223
  },
221
224
  methods: {
222
225
  processEvidences: function(sub) {
@@ -262,7 +265,15 @@ export default {
262
265
  return new Date(dateString).toLocaleDateString(undefined, options);
263
266
  },
264
267
  updatePrevSubmissions: function () {
265
- if (this.$annotator && this.authenticated) {
268
+ if (this.offlineAnnotationEnabled) {
269
+ const offlineAnnotations = JSON.parse(sessionStorage.getItem('anonymous-annotation')) || [];
270
+ this.prevSubs = offlineAnnotations.filter((offline) => {
271
+ return (
272
+ offline.resource === this.annotationEntry.resourceId &&
273
+ offline.item.id === this.annotationEntry.featureId
274
+ )
275
+ });
276
+ } else if (this.$annotator && this.authenticated) {
266
277
  if (
267
278
  this.annotationEntry["resourceId"] &&
268
279
  this.annotationEntry["featureId"]
@@ -342,7 +353,6 @@ export default {
342
353
  this.$annotator
343
354
  ?.addAnnotation(this.userApiKey, userAnnotation)
344
355
  .then(() => {
345
- this.$emit("annotation", userAnnotation);
346
356
  this.errorMessage = "";
347
357
  this.resetSubmission();
348
358
  this.updatePrevSubmissions();
@@ -351,6 +361,7 @@ export default {
351
361
  this.errorMessage =
352
362
  "There is a problem with the submission, please try again later";
353
363
  });
364
+ this.$emit("annotation", userAnnotation);
354
365
  }
355
366
  }
356
367
  },
@@ -396,9 +407,11 @@ export default {
396
407
  if (this.prevSubs.length) {
397
408
  let annotationContent = '<div><strong>Annotations:</strong></div>\n<br>';
398
409
  this.prevSubs.map((sub, index) => {
399
- annotationContent += `<div><strong>Created:</strong>${this.formatTime(sub.created)}</div>\n<br>`;
400
- annotationContent += `<div><strong>Creator:</strong>${sub.creator.name}</div>\n<br>`;
401
- annotationContent += `<div><strong>Email:</strong>${sub.creator.email}</div>\n<br>`;
410
+ if (sub.creator) {
411
+ annotationContent += `<div><strong>Created:</strong>${this.formatTime(sub.created)}</div>\n<br>`;
412
+ annotationContent += `<div><strong>Creator:</strong>${sub.creator.name}</div>\n<br>`;
413
+ annotationContent += `<div><strong>Email:</strong>${sub.creator.email}</div>\n<br>`;
414
+ }
402
415
  if (sub.body.evidence.length) {
403
416
  let evidenceContent = '';
404
417
  sub.body.evidence.forEach((evi, index) => {
@@ -433,10 +446,10 @@ export default {
433
446
  this.creator = userData;
434
447
  if (!userData.orcid) this.creator.orcid = "0000-0000-0000-0000";
435
448
  this.authenticated = true;
436
- this.updatePrevSubmissions();
437
449
  } else {
438
450
  this.errorMessage = "";
439
451
  }
452
+ this.updatePrevSubmissions();
440
453
  });
441
454
  },
442
455
  };
@@ -22,8 +22,8 @@
22
22
  v-for="reference of pubMedReferences"
23
23
  :key="reference.id"
24
24
  :class="{
25
- 'loading': reference.citation && !reference.citation.error && reference.citation[citationType] === '',
26
- 'error': reference.citation && reference.citation.error
25
+ 'loading': isCitationLoading(reference.citation),
26
+ 'error': isCitationError(reference.citation),
27
27
  }"
28
28
  >
29
29
  <template v-if="reference.citation">
@@ -50,49 +50,34 @@
50
50
  <template v-else>
51
51
  <span v-html="reference.citation[citationType]"></span>
52
52
 
53
- <div class="reference-button-container">
54
- <el-button
55
- class="reference-icon-button"
56
- size="small"
57
- @click="showRelatedConnectivities(reference.resource)"
58
- >
59
- Show related connectivities
60
- </el-button>
61
- </div>
53
+ <RelatedConnectivitiesButton
54
+ :resource="reference.resource"
55
+ @show-related-connectivities="showRelatedConnectivities"
56
+ />
62
57
 
63
58
  <CopyToClipboard :content="reference.citation[citationType]" />
64
59
  </template>
65
60
  </template>
66
61
  </li>
67
62
 
68
- <li v-for="reference of openLibReferences">
63
+ <li v-for="reference of openLibReferences" :key="reference.id">
69
64
  <div v-html="formatCopyReference(reference)"></div>
70
65
 
71
- <div class="reference-button-container">
72
- <el-button
73
- class="reference-icon-button"
74
- size="small"
75
- @click="showRelatedConnectivities(reference.resource)"
76
- >
77
- Show related connectivities
78
- </el-button>
79
- </div>
66
+ <RelatedConnectivitiesButton
67
+ :resource="reference.resource"
68
+ @show-related-connectivities="showRelatedConnectivities"
69
+ />
80
70
 
81
71
  <CopyToClipboard :content="formatCopyReference(reference)" />
82
72
  </li>
83
73
 
84
- <li v-for="reference of isbnDBReferences">
74
+ <li v-for="reference of isbnDBReferences" :key="reference.id">
85
75
  <a :href="reference.url" target="_blank">{{ reference.url }}</a>
86
76
 
87
- <div class="reference-button-container">
88
- <el-button
89
- class="reference-icon-button"
90
- size="small"
91
- @click="showRelatedConnectivities(reference.resource)"
92
- >
93
- Show related connectivities
94
- </el-button>
95
- </div>
77
+ <RelatedConnectivitiesButton
78
+ :resource="reference.resource"
79
+ @show-related-connectivities="showRelatedConnectivities"
80
+ />
96
81
 
97
82
  <CopyToClipboard :content="reference.url" />
98
83
  </li>
@@ -103,6 +88,7 @@
103
88
  <script>
104
89
  import CopyToClipboard from '../CopyToClipboard/CopyToClipboard.vue';
105
90
  import { delay } from '../utilities';
91
+ import RelatedConnectivitiesButton from './RelatedConnectivitiesButton.vue';
106
92
 
107
93
  const CROSSCITE_API_HOST = 'https://citation.doi.org';
108
94
  const CITATION_OPTIONS = [
@@ -128,6 +114,10 @@ const LOADING_DELAY = 600;
128
114
 
129
115
  export default {
130
116
  name: "ExternalResourceCard",
117
+ components: {
118
+ CopyToClipboard,
119
+ RelatedConnectivitiesButton,
120
+ },
131
121
  props: {
132
122
  resources: {
133
123
  type: Array,
@@ -411,6 +401,12 @@ export default {
411
401
  reloadCitation: function (reference) {
412
402
  this.generateCitationText(reference, this.citationType);
413
403
  },
404
+ isCitationLoading: function (citation) {
405
+ return citation && !citation[this.citationType] && !citation.error;
406
+ },
407
+ isCitationError: function (citation) {
408
+ return citation && citation.error;
409
+ },
414
410
  updateCopyContents: function () {
415
411
  const citationTypeObj = this.citationOptions.find((item) => item.value === this.citationType);
416
412
  let citationFormatStyle = '';
@@ -611,7 +607,7 @@ export default {
611
607
  &.loading {
612
608
  padding: 1rem;
613
609
 
614
- &::before {
610
+ &::after {
615
611
  content: "";
616
612
  display: block;
617
613
  width: 100%;
@@ -691,20 +687,6 @@ export default {
691
687
  cursor: pointer;
692
688
  }
693
689
 
694
- .reference-button-container {
695
- margin-top: 0.5rem;
696
- }
697
-
698
- .reference-icon-button {
699
- color: $app-primary-color !important;
700
- background-color: #f9f2fc !important;
701
- border-color: $app-primary-color !important;
702
-
703
- &:hover {
704
- background-color: transparent !important;
705
- }
706
- }
707
-
708
690
  @keyframes loadingAnimation {
709
691
  0% {
710
692
  background-position: -30vw 0;