@abi-software/map-utilities 1.5.0-beta.0 → 1.5.0-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.
- package/dist/map-utilities.js +15810 -10079
- package/dist/map-utilities.umd.cjs +63 -63
- package/dist/style.css +1 -1
- package/package.json +2 -1
- package/src/App.vue +135 -49
- package/src/components/ConnectivityGraph/ConnectivityGraph.vue +48 -16
- package/src/components/ConnectivityGraph/graph.js +9 -5
- package/src/components/ConnectivityList/ConnectivityList.vue +398 -0
- package/src/components/DrawToolbar/DrawToolbar.vue +2 -2
- package/src/components/Tooltip/AnnotationPopup.vue +135 -42
- package/src/components/Tooltip/ProvenancePopup.vue +155 -266
- package/src/components/Tooltip/Tooltip.vue +2 -2
- package/src/components/index.js +2 -0
- package/src/components/utilities.js +7 -0
- package/src/components.d.ts +1 -0
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<el-main class="main">
|
|
3
|
+
<div v-if="annotationEntry.length > 1" class="toggle-button">
|
|
4
|
+
<el-popover width="auto" trigger="hover" :teleported="false">
|
|
5
|
+
<template #reference>
|
|
6
|
+
<el-button
|
|
7
|
+
class="button"
|
|
8
|
+
@click="previous"
|
|
9
|
+
:disabled="this.entryIndex === 0"
|
|
10
|
+
>
|
|
11
|
+
Previous
|
|
12
|
+
</el-button>
|
|
13
|
+
</template>
|
|
14
|
+
<span>{{ previousLabel }}</span>
|
|
15
|
+
</el-popover>
|
|
16
|
+
<el-popover width="auto" trigger="hover" :teleported="false">
|
|
17
|
+
<template #reference>
|
|
18
|
+
<el-button
|
|
19
|
+
class="button"
|
|
20
|
+
@click="next"
|
|
21
|
+
:disabled="this.entryIndex === this.annotationEntry.length - 1"
|
|
22
|
+
>
|
|
23
|
+
Next
|
|
24
|
+
</el-button>
|
|
25
|
+
</template>
|
|
26
|
+
<span>{{ nextLabel }}</span>
|
|
27
|
+
</el-popover>
|
|
28
|
+
</div>
|
|
3
29
|
<div class="block">
|
|
4
30
|
<el-row class="info-field">
|
|
5
31
|
<div class="title">Feature Annotations</div>
|
|
@@ -7,16 +33,16 @@
|
|
|
7
33
|
<copy-to-clipboard :content="updatedCopyContent" />
|
|
8
34
|
</div>
|
|
9
35
|
</el-row>
|
|
10
|
-
<template v-if="
|
|
36
|
+
<template v-if="entry">
|
|
11
37
|
<el-row
|
|
12
38
|
v-for="(key, label) in displayPair"
|
|
13
|
-
v-show="
|
|
39
|
+
v-show="entry[key]"
|
|
14
40
|
class="dialog-text"
|
|
15
41
|
:key="key"
|
|
16
42
|
>
|
|
17
43
|
<strong>{{ label }}: </strong>
|
|
18
|
-
<span v-if="label !== 'Ontology'">{{
|
|
19
|
-
<a v-else :href="ontologyLink" target="_blank">{{
|
|
44
|
+
<span v-if="label !== 'Ontology'">{{ entry[key] }}</span>
|
|
45
|
+
<a v-else :href="ontologyLink" target="_blank">{{ entry[key] }}</a>
|
|
20
46
|
</el-row>
|
|
21
47
|
<template v-if="prevSubs.length > 0">
|
|
22
48
|
<div
|
|
@@ -158,7 +184,7 @@ export default {
|
|
|
158
184
|
name: "AnnotationPopup",
|
|
159
185
|
props: {
|
|
160
186
|
annotationEntry: {
|
|
161
|
-
type:
|
|
187
|
+
type: Array,
|
|
162
188
|
},
|
|
163
189
|
},
|
|
164
190
|
inject: ["$annotator", "userApiKey"],
|
|
@@ -187,41 +213,70 @@ export default {
|
|
|
187
213
|
errorMessage: "",
|
|
188
214
|
creator: undefined,
|
|
189
215
|
copyContent: '',
|
|
216
|
+
entryIndex: 0,
|
|
190
217
|
};
|
|
191
218
|
},
|
|
192
219
|
computed: {
|
|
220
|
+
entry: function () {
|
|
221
|
+
return this.annotationEntry[this.entryIndex];
|
|
222
|
+
},
|
|
223
|
+
previousLabel: function () {
|
|
224
|
+
if (this.entryIndex === 0) {
|
|
225
|
+
return "This is the first item. Click 'Next' to see more information.";
|
|
226
|
+
}
|
|
227
|
+
return this.annotationEntry[this.entryIndex - 1]?.label;
|
|
228
|
+
},
|
|
229
|
+
nextLabel: function () {
|
|
230
|
+
if (this.entryIndex === this.annotationEntry.length - 1) {
|
|
231
|
+
return "This is the last item. Click 'Previous' to see more information.";
|
|
232
|
+
}
|
|
233
|
+
return this.annotationEntry[this.entryIndex + 1]?.label;
|
|
234
|
+
},
|
|
193
235
|
isEditable: function () {
|
|
194
236
|
return (
|
|
195
|
-
this.
|
|
237
|
+
this.entry["resourceId"] && this.entry["featureId"]
|
|
196
238
|
);
|
|
197
239
|
},
|
|
198
240
|
isPositionUpdated: function () {
|
|
199
241
|
return (
|
|
200
|
-
this.
|
|
201
|
-
this.
|
|
202
|
-
this.
|
|
242
|
+
this.entry["resourceId"] &&
|
|
243
|
+
this.entry["type"] === "updated" &&
|
|
244
|
+
this.entry["positionUpdated"]
|
|
203
245
|
);
|
|
204
246
|
},
|
|
205
247
|
isDeleted: function () {
|
|
206
248
|
return (
|
|
207
|
-
this.
|
|
208
|
-
this.
|
|
249
|
+
this.entry["resourceId"] &&
|
|
250
|
+
this.entry["type"] === "deleted"
|
|
209
251
|
);
|
|
210
252
|
},
|
|
211
253
|
ontologyLink: function () {
|
|
212
|
-
const models = this.
|
|
254
|
+
const models = this.entry['models'];
|
|
213
255
|
if (models && models.startsWith("UBERON")) {
|
|
214
|
-
return `http://purl.obolibrary.org/obo/${this.
|
|
256
|
+
return `http://purl.obolibrary.org/obo/${this.entry.models.replace(":", "_")}`;
|
|
215
257
|
}
|
|
216
258
|
},
|
|
217
259
|
updatedCopyContent: function () {
|
|
218
260
|
return this.getUpdateCopyContent();
|
|
219
261
|
},
|
|
220
262
|
offlineAnnotationEnabled: function () {
|
|
221
|
-
|
|
263
|
+
if (this.entry) {
|
|
264
|
+
return this.entry["offline"];
|
|
265
|
+
}
|
|
266
|
+
return false;
|
|
222
267
|
},
|
|
223
268
|
},
|
|
224
269
|
methods: {
|
|
270
|
+
previous: function () {
|
|
271
|
+
if (this.entryIndex !== 0) {
|
|
272
|
+
this.entryIndex = this.entryIndex - 1;
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
next: function () {
|
|
276
|
+
if (this.entryIndex !== this.annotationEntry.length - 1) {
|
|
277
|
+
this.entryIndex = this.entryIndex + 1;
|
|
278
|
+
}
|
|
279
|
+
},
|
|
225
280
|
processEvidences: function(sub) {
|
|
226
281
|
const evidences = [];
|
|
227
282
|
if (sub?.body?.evidence) {
|
|
@@ -269,20 +324,20 @@ export default {
|
|
|
269
324
|
const offlineAnnotations = JSON.parse(sessionStorage.getItem('anonymous-annotation')) || [];
|
|
270
325
|
this.prevSubs = offlineAnnotations.filter((offline) => {
|
|
271
326
|
return (
|
|
272
|
-
offline.resource === this.
|
|
273
|
-
offline.item.id === this.
|
|
327
|
+
offline.resource === this.entry.resourceId &&
|
|
328
|
+
offline.item.id === this.entry.featureId
|
|
274
329
|
)
|
|
275
330
|
});
|
|
276
331
|
} else if (this.$annotator && this.authenticated) {
|
|
277
332
|
if (
|
|
278
|
-
this.
|
|
279
|
-
this.
|
|
333
|
+
this.entry["resourceId"] &&
|
|
334
|
+
this.entry["featureId"]
|
|
280
335
|
) {
|
|
281
336
|
this.$annotator
|
|
282
337
|
?.itemAnnotations(
|
|
283
338
|
this.userApiKey,
|
|
284
|
-
this.
|
|
285
|
-
this.
|
|
339
|
+
this.entry["resourceId"],
|
|
340
|
+
this.entry["featureId"]
|
|
286
341
|
)
|
|
287
342
|
.then((value) => {
|
|
288
343
|
this.prevSubs = value;
|
|
@@ -297,13 +352,13 @@ export default {
|
|
|
297
352
|
// User can either update/delete annotation directly
|
|
298
353
|
// or provide extra comments for update/delete action
|
|
299
354
|
if (
|
|
300
|
-
this.
|
|
301
|
-
this.
|
|
355
|
+
this.entry["type"] === "updated" &&
|
|
356
|
+
this.entry["positionUpdated"]
|
|
302
357
|
) {
|
|
303
358
|
this.comment = this.comment
|
|
304
359
|
? `Position Updated: ${this.comment}`
|
|
305
360
|
: "Position Updated";
|
|
306
|
-
} else if (this.
|
|
361
|
+
} else if (this.entry["type"] === "deleted") {
|
|
307
362
|
this.comment = this.comment
|
|
308
363
|
? `Feature Deleted: ${this.comment}`
|
|
309
364
|
: "Feature Deleted";
|
|
@@ -311,8 +366,8 @@ export default {
|
|
|
311
366
|
|
|
312
367
|
if (this.evidence.length > 0 || this.comment) {
|
|
313
368
|
if (
|
|
314
|
-
this.
|
|
315
|
-
this.
|
|
369
|
+
this.entry["resourceId"] &&
|
|
370
|
+
this.entry["featureId"]
|
|
316
371
|
) {
|
|
317
372
|
const evidenceURLs = [];
|
|
318
373
|
this.evidence.forEach((evidence) => {
|
|
@@ -330,11 +385,11 @@ export default {
|
|
|
330
385
|
}
|
|
331
386
|
});
|
|
332
387
|
const userAnnotation = {
|
|
333
|
-
resource: this.
|
|
388
|
+
resource: this.entry["resourceId"],
|
|
334
389
|
item: Object.assign(
|
|
335
|
-
{ id: this.
|
|
390
|
+
{ id: this.entry["featureId"] },
|
|
336
391
|
Object.fromEntries(
|
|
337
|
-
Object.entries(this.
|
|
392
|
+
Object.entries(this.entry).filter(([key]) =>
|
|
338
393
|
["label", "models"].includes(key)
|
|
339
394
|
)
|
|
340
395
|
)
|
|
@@ -343,10 +398,10 @@ export default {
|
|
|
343
398
|
evidence: evidenceURLs,
|
|
344
399
|
comment: this.comment,
|
|
345
400
|
},
|
|
346
|
-
feature: this.
|
|
401
|
+
feature: this.entry["feature"],
|
|
347
402
|
};
|
|
348
|
-
Object.assign(userAnnotation.body, this.
|
|
349
|
-
if (this.
|
|
403
|
+
Object.assign(userAnnotation.body, this.entry["body"]);
|
|
404
|
+
if (this.entry["type"] === "deleted") {
|
|
350
405
|
userAnnotation.feature = undefined;
|
|
351
406
|
}
|
|
352
407
|
if (this.creator) userAnnotation.creator = this.creator;
|
|
@@ -375,33 +430,33 @@ export default {
|
|
|
375
430
|
this.comment = "";
|
|
376
431
|
},
|
|
377
432
|
getUpdateCopyContent: function () {
|
|
378
|
-
if (!this.
|
|
433
|
+
if (!this.entry) {
|
|
379
434
|
return '';
|
|
380
435
|
}
|
|
381
436
|
|
|
382
437
|
const contentArray = [];
|
|
383
438
|
|
|
384
439
|
// featureId
|
|
385
|
-
if (this.
|
|
386
|
-
contentArray.push(`<div><strong>Feature ID:</strong>${this.
|
|
440
|
+
if (this.entry.featureId) {
|
|
441
|
+
contentArray.push(`<div><strong>Feature ID:</strong>${this.entry.featureId}</div>`);
|
|
387
442
|
}
|
|
388
443
|
|
|
389
444
|
// label
|
|
390
|
-
if (this.
|
|
391
|
-
contentArray.push(`<div><strong>Label:</strong>${this.
|
|
445
|
+
if (this.entry.label) {
|
|
446
|
+
contentArray.push(`<div><strong>Label:</strong>${this.entry.label}</div>`);
|
|
392
447
|
}
|
|
393
448
|
|
|
394
449
|
// models
|
|
395
|
-
if (this.
|
|
396
|
-
contentArray.push(`<div><strong>Ontology:</strong>${this.
|
|
450
|
+
if (this.entry.models) {
|
|
451
|
+
contentArray.push(`<div><strong>Ontology:</strong>${this.entry.models}</div>`);
|
|
397
452
|
if (this.ontologyLink) {
|
|
398
453
|
contentArray.push(`<div><strong>Ontology Link:</strong>${this.ontologyLink}</div>`);
|
|
399
454
|
}
|
|
400
455
|
}
|
|
401
456
|
|
|
402
457
|
// resourceId
|
|
403
|
-
if (this.
|
|
404
|
-
contentArray.push(`<div><strong>Resource:</strong>${this.
|
|
458
|
+
if (this.entry.resourceId) {
|
|
459
|
+
contentArray.push(`<div><strong>Resource:</strong>${this.entry.resourceId}</div>`);
|
|
405
460
|
}
|
|
406
461
|
|
|
407
462
|
if (this.prevSubs.length) {
|
|
@@ -430,14 +485,23 @@ export default {
|
|
|
430
485
|
},
|
|
431
486
|
watch: {
|
|
432
487
|
annotationEntry: {
|
|
488
|
+
deep: true,
|
|
489
|
+
immediate: true,
|
|
433
490
|
handler: function (newVal, oldVal) {
|
|
434
491
|
if (newVal !== oldVal) {
|
|
492
|
+
this.entryIndex = 0;
|
|
493
|
+
}
|
|
494
|
+
},
|
|
495
|
+
},
|
|
496
|
+
entry: {
|
|
497
|
+
deep: true,
|
|
498
|
+
immediate: true,
|
|
499
|
+
handler: function (newVal, oldVal) {
|
|
500
|
+
if (newVal && newVal !== oldVal) {
|
|
435
501
|
this.resetSubmission();
|
|
436
502
|
this.updatePrevSubmissions();
|
|
437
503
|
}
|
|
438
504
|
},
|
|
439
|
-
immediate: false,
|
|
440
|
-
deep: false,
|
|
441
505
|
},
|
|
442
506
|
},
|
|
443
507
|
mounted: function () {
|
|
@@ -456,6 +520,35 @@ export default {
|
|
|
456
520
|
</script>
|
|
457
521
|
|
|
458
522
|
<style lang="scss" scoped>
|
|
523
|
+
.toggle-button {
|
|
524
|
+
display: flex;
|
|
525
|
+
justify-content: space-between;
|
|
526
|
+
|
|
527
|
+
.is-disabled {
|
|
528
|
+
color: #fff !important;
|
|
529
|
+
background-color: #ac76c5 !important;
|
|
530
|
+
border: 1px solid #ac76c5 !important;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
.button {
|
|
534
|
+
margin-left: 0px !important;
|
|
535
|
+
margin-top: 0px !important;
|
|
536
|
+
font-size: 14px !important;
|
|
537
|
+
background-color: $app-primary-color;
|
|
538
|
+
color: #fff;
|
|
539
|
+
|
|
540
|
+
& + .button {
|
|
541
|
+
margin-top: 10px !important;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
&:hover {
|
|
545
|
+
color: #fff !important;
|
|
546
|
+
background: #ac76c5 !important;
|
|
547
|
+
border: 1px solid #ac76c5 !important;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
459
552
|
.info-field {
|
|
460
553
|
padding: 0;
|
|
461
554
|
display: flex;
|