@abi-software/flatmapvuer 1.2.0 → 1.3.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.
@@ -56,6 +56,9 @@
56
56
  @resource-selected="resourceSelected"
57
57
  @ready="FlatmapReady"
58
58
  @pan-zoom-callback="panZoomCallback"
59
+ :connectivityInfoSidebar="connectivityInfoSidebar"
60
+ @connectivity-info-open="onConnectivityInfoOpen"
61
+ @connectivity-info-close="onConnectivityInfoClose"
59
62
  @open-map="
60
63
  /**
61
64
  * This event is emitted when the user chooses a different map option
@@ -261,6 +264,12 @@ export default {
261
264
  */
262
265
  this.$emit('pan-zoom-callback', payload)
263
266
  },
267
+ onConnectivityInfoClose: function () {
268
+ this.$emit('connectivity-info-close');
269
+ },
270
+ onConnectivityInfoOpen: function (entryData) {
271
+ this.$emit('connectivity-info-open', entryData);
272
+ },
264
273
  onSelectionsDataChanged: function (data) {
265
274
  this.$emit('pathway-selection-changed', data);
266
275
  },
@@ -697,7 +706,14 @@ export default {
697
706
  disableUI: {
698
707
  type: Boolean,
699
708
  default: false,
700
- }
709
+ },
710
+ /**
711
+ * The option to show connectivity information in sidebar
712
+ */
713
+ connectivityInfoSidebar: {
714
+ type: Boolean,
715
+ default: false,
716
+ },
701
717
  },
702
718
  data: function () {
703
719
  return {
@@ -1,8 +1,6 @@
1
1
  // The Vue build version to load with the `import` command
2
2
  // (runtime-only or standalone) has been set in webpack.base.conf with an alias.
3
- import FlatmapVuer from './FlatmapVuer.vue'
4
- import MultiFlatmapVuer from './MultiFlatmapVuer.vue'
5
- import Tooltip from './Tooltip.vue'
6
- import HelpModeDialog from './HelpModeDialog.vue'
3
+ import FlatmapVuer from "./FlatmapVuer.vue";
4
+ import MultiFlatmapVuer from "./MultiFlatmapVuer.vue";
7
5
 
8
- export { FlatmapVuer, MultiFlatmapVuer, Tooltip, HelpModeDialog }
6
+ export { FlatmapVuer, MultiFlatmapVuer };
@@ -7,44 +7,26 @@ export {}
7
7
 
8
8
  declare module 'vue' {
9
9
  export interface GlobalComponents {
10
- AnnotationTool: typeof import('./components/AnnotationTool.vue')['default']
11
- ConnectionDialog: typeof import('./components/ConnectionDialog.vue')['default']
12
- DrawTool: typeof import('./components/DrawTool.vue')['default']
13
10
  DynamicLegends: typeof import('./components/legends/DynamicLegends.vue')['default']
14
11
  ElButton: typeof import('element-plus/es')['ElButton']
15
- ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']
16
- ElCard: typeof import('element-plus/es')['ElCard']
17
12
  ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
18
13
  ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
19
14
  ElCol: typeof import('element-plus/es')['ElCol']
20
15
  ElIcon: typeof import('element-plus/es')['ElIcon']
21
16
  ElIconArrowDown: typeof import('@element-plus/icons-vue')['ArrowDown']
22
17
  ElIconArrowLeft: typeof import('@element-plus/icons-vue')['ArrowLeft']
23
- ElIconArrowUp: typeof import('@element-plus/icons-vue')['ArrowUp']
24
- ElIconClose: typeof import('@element-plus/icons-vue')['Close']
25
- ElIconDelete: typeof import('@element-plus/icons-vue')['Delete']
26
- ElIconEdit: typeof import('@element-plus/icons-vue')['Edit']
27
- ElIconFinished: typeof import('@element-plus/icons-vue')['Finished']
28
18
  ElIconWarning: typeof import('@element-plus/icons-vue')['Warning']
29
19
  ElIconWarningFilled: typeof import('@element-plus/icons-vue')['WarningFilled']
30
- ElInput: typeof import('element-plus/es')['ElInput']
31
- ElMain: typeof import('element-plus/es')['ElMain']
32
20
  ElOption: typeof import('element-plus/es')['ElOption']
33
21
  ElPopover: typeof import('element-plus/es')['ElPopover']
34
22
  ElRadio: typeof import('element-plus/es')['ElRadio']
35
23
  ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
36
24
  ElRow: typeof import('element-plus/es')['ElRow']
37
25
  ElSelect: typeof import('element-plus/es')['ElSelect']
38
- ElTree: typeof import('element-plus/es')['ElTree']
39
- ExternalResourceCard: typeof import('./components/ExternalResourceCard.vue')['default']
40
26
  FlatmapVuer: typeof import('./components/FlatmapVuer.vue')['default']
41
- HelpModeDialog: typeof import('./components/HelpModeDialog.vue')['default']
42
27
  MultiFlatmapVuer: typeof import('./components/MultiFlatmapVuer.vue')['default']
43
- ProvenancePopup: typeof import('./components/ProvenancePopup.vue')['default']
44
28
  SelectionsGroup: typeof import('./components/SelectionsGroup.vue')['default']
45
29
  SvgLegends: typeof import('./components/legends/SvgLegends.vue')['default']
46
- Tooltip: typeof import('./components/Tooltip.vue')['default']
47
- TreeControls: typeof import('./components/TreeControls.vue')['default']
48
30
  }
49
31
  export interface ComponentCustomProperties {
50
32
  vLoading: typeof import('element-plus/es')['ElLoadingDirective']
@@ -222,7 +222,7 @@ let FlatmapQueries = function () {
222
222
  this.origins = []
223
223
  this.components = []
224
224
  if (!keastIds || keastIds.length == 0) return
225
-
225
+
226
226
  let prom1 = this.queryForConnectivity(keastIds, signal) // This on returns a promise so dont need 'await'
227
227
  let prom2 = await this.pubmedQueryOnIds(eventData)
228
228
  let results = await Promise.all([prom1, prom2])
@@ -281,10 +281,10 @@ let FlatmapQueries = function () {
281
281
  if (node.length === 1) { // If the node is in the form [id]
282
282
  console.error("Server returns a single node", node)
283
283
  return node[0]
284
- } else {
284
+ } else {
285
285
  if (node.length === 2 && node[1].length === 0) { // If the node is in the form [id, []]
286
286
  return node[0]
287
- } else {
287
+ } else {
288
288
  return false // If the node is in the form [id, [id1, id2]]
289
289
  }
290
290
  }
@@ -294,7 +294,7 @@ let FlatmapQueries = function () {
294
294
 
295
295
  // Check if the node is a single node or a node with multiple children
296
296
  let nodeIsSingle = this.findIfNodeIsSingle(node)
297
-
297
+
298
298
  // Case where node is in the form [id]
299
299
  if (nodeIsSingle) {
300
300
  return lookUp[nodeIsSingle]
@@ -467,7 +467,8 @@ let FlatmapQueries = function () {
467
467
  this.pubmedSearchUrl = function (ids) {
468
468
  let url = 'https://pubmed.ncbi.nlm.nih.gov/?'
469
469
  let params = new URLSearchParams()
470
- params.append('term', ids)
470
+ const decodedIDs = ids.map((id) => decodeURIComponent(id));
471
+ params.append('term', decodedIDs);
471
472
  return url + params.toString()
472
473
  }
473
474
  }
package/vite.config.js CHANGED
@@ -50,11 +50,12 @@ export default defineConfig(({ command, mode }) => {
50
50
  fileName: 'flatmapvuer',
51
51
  },
52
52
  rollupOptions: {
53
- external: ["vue", "@abi-software/svg-sprite"],
53
+ external: ["vue", "@abi-software/svg-sprite", "@abi-software/map-utilities"],
54
54
  output: {
55
55
  globals: {
56
56
  vue: "Vue",
57
- "@abi-software/svg-sprite": "@abi-software/svg-sprite"
57
+ "@abi-software/svg-sprite": "@abi-software/svg-sprite",
58
+ "@abi-software/map-utilities": "@abi-software/map-utilities"
58
59
  },
59
60
  },
60
61
  },
@@ -1,501 +0,0 @@
1
- <template>
2
- <el-main class="main">
3
- <div class="block">
4
- <el-row class="info-field">
5
- <div class="title">Feature Annotations</div>
6
- </el-row>
7
- <template v-if="annotationEntry">
8
- <el-row
9
- v-for="(key, label) in displayPair"
10
- v-show="annotationEntry[key]"
11
- class="dialog-text"
12
- :key="key"
13
- >
14
- <strong>{{ label }}: </strong>&nbsp;{{ annotationEntry[key] }}
15
- </el-row>
16
- <template v-if="prevSubs.length > 0">
17
- <div
18
- v-show="showSubmissions"
19
- class="hide"
20
- @click="showSubmissions = false"
21
- >
22
- Hide previous submissions
23
- <el-icon><el-icon-arrow-up /></el-icon>
24
- </div>
25
- <div
26
- v-show="!showSubmissions"
27
- class="hide"
28
- @click="showSubmissions = true"
29
- >
30
- Show previous {{ prevSubs.length }} submission(s)
31
- <el-icon><el-icon-arrow-down /></el-icon>
32
- </div>
33
- <template v-if="showSubmissions">
34
- <el-row class="dialog-spacer"></el-row>
35
- <el-row class="dialog-text">
36
- <strong class="sub-title">Previous submissions:</strong>
37
- </el-row>
38
- <div class="entry" v-for="(sub, index) in prevSubs" :key="index">
39
- <el-row class="dialog-text">
40
- <strong>{{ formatTime(sub.created) }}</strong>
41
- {{ sub.creator.name }}
42
- </el-row>
43
- <el-row class="dialog-text">
44
- <strong>Evidence: </strong>
45
- <el-row
46
- v-for="evidence in sub.body.evidence"
47
- :key="evidence"
48
- class="dialog-text"
49
- >
50
- <a :href="evidence" target="_blank"> {{ evidence }}</a>
51
- </el-row>
52
- </el-row>
53
- <el-row class="dialog-text">
54
- <strong>Comment: </strong> {{ sub.body.comment }}
55
- </el-row>
56
- </div>
57
- </template>
58
- </template>
59
- <template v-if="authenticated">
60
- <template v-if="isEditable">
61
- <el-row class="dialog-spacer"></el-row>
62
- <el-row v-if="!editing">
63
- <el-icon class="standard-icon">
64
- <el-icon-edit @click="editing = true" />
65
- </el-icon>
66
- <el-icon
67
- class="standard-icon"
68
- v-if="isDeleted"
69
- >
70
- <el-icon-delete @click="submit"/>
71
- </el-icon>
72
- <el-icon
73
- class="standard-icon"
74
- v-else-if="isPositionUpdated"
75
- >
76
- <el-icon-finished @click="submit" />
77
- </el-icon>
78
- </el-row>
79
- <template v-else>
80
- <el-row class="dialog-text">
81
- <strong class="sub-title">Suggest changes:</strong>
82
- </el-row>
83
- <template v-if="!isDeleted">
84
- <el-row class="dialog-text">
85
- <strong>Evidence:</strong>
86
- </el-row>
87
- <el-row v-for="(value, index) in evidence" :key="value">
88
- <el-col :span="20">
89
- {{ evidence[index] }}
90
- </el-col>
91
- <el-col :span="4">
92
- <el-icon class="standard-icon">
93
- <el-icon-close @click="removeEvidence(index)" />
94
- </el-icon>
95
- </el-col>
96
- </el-row>
97
- <el-row>
98
- <el-input
99
- size="small"
100
- placeholder="Enter"
101
- v-model="newEvidence"
102
- @change="evidenceEntered($event)"
103
- >
104
- <template #prepend>
105
- <el-select
106
- :teleported="false"
107
- v-model="evidencePrefix"
108
- placeholder="Select"
109
- class="select-box"
110
- popper-class="flatmap_dropdown"
111
- >
112
- <el-option
113
- v-for="item in evidencePrefixes"
114
- :key="item"
115
- :label="item"
116
- :value="item"
117
- >
118
- <el-row>
119
- <el-col :span="12">{{ item }}</el-col>
120
- </el-row>
121
- </el-option>
122
- </el-select>
123
- </template>
124
- </el-input>
125
- </el-row>
126
- </template>
127
- <el-row>
128
- <strong>Comment:</strong>
129
- </el-row>
130
- <el-row class="dialog-text">
131
- <el-input
132
- type="textarea"
133
- :autosize="{ minRows: 2, maxRows: 4 }"
134
- placeholder="Enter"
135
- v-model="comment"
136
- />
137
- </el-row>
138
- <el-row class="dialog-text">
139
- <el-button class="button" type="primary" plain @click="submit">
140
- Submit
141
- </el-button>
142
- </el-row>
143
- </template>
144
- <el-row class="dialog-text" v-if="errorMessage">
145
- <strong class="sub-title"> {{ errorMessage }} </strong>
146
- </el-row>
147
- </template>
148
- </template>
149
- </template>
150
- </div>
151
- </el-main>
152
- </template>
153
-
154
- <script>
155
- import {
156
- ArrowUp as ElIconArrowUp,
157
- ArrowDown as ElIconArrowDown,
158
- Edit as ElIconEdit,
159
- Close as ElIconClose,
160
- Delete as ElIconDelete,
161
- Finished as ElIconFinished,
162
- } from '@element-plus/icons-vue'
163
- /* eslint-disable no-alert, no-console */
164
- import {
165
- ElButton as Button,
166
- ElCol as Col,
167
- ElInput as Input,
168
- ElMain as Main,
169
- ElRow as Row,
170
- ElSelect as Select,
171
- } from 'element-plus'
172
-
173
- export default {
174
- name: 'AnnotationTool',
175
- components: {
176
- Button,
177
- Col,
178
- Input,
179
- Main,
180
- Row,
181
- Select,
182
- ElIconArrowUp,
183
- ElIconArrowDown,
184
- ElIconEdit,
185
- ElIconClose,
186
- },
187
- props: {
188
- annotationEntry: {
189
- type: Object,
190
- },
191
- },
192
- inject: ['flatmapAPI', '$annotator', 'userApiKey'],
193
- data: function () {
194
- return {
195
- displayPair: {
196
- 'Feature ID': 'featureId',
197
- Tooltip: 'label',
198
- Models: 'models',
199
- Name: 'name',
200
- Resource: 'resourceId',
201
- },
202
- editing: false,
203
- evidencePrefixes: ['DOI:', 'PMID:'],
204
- evidencePrefix: 'DOI:',
205
- evidence: [],
206
- authenticated: false,
207
- newEvidence: '',
208
- comment: '',
209
- prevSubs: [],
210
- showSubmissions: true,
211
- errorMessage: '',
212
- creator: undefined
213
- }
214
- },
215
- computed: {
216
- isEditable: function () {
217
- return (
218
- this.annotationEntry['resourceId'] &&
219
- this.annotationEntry['featureId']
220
- )
221
- },
222
- isPositionUpdated: function () {
223
- return (
224
- this.annotationEntry['resourceId'] &&
225
- this.annotationEntry['type'] === 'updated' &&
226
- this.annotationEntry['positionUpdated']
227
- )
228
- },
229
- isDeleted: function () {
230
- return (
231
- this.annotationEntry['resourceId'] &&
232
- this.annotationEntry['type'] === 'deleted'
233
- )
234
- }
235
- },
236
- methods: {
237
- evidenceEntered: function (value) {
238
- if (value) {
239
- this.evidence.push(this.evidencePrefix + value)
240
- this.newEvidence = ''
241
- }
242
- },
243
- formatTime: function (dateString) {
244
- const options = {
245
- year: 'numeric',
246
- month: 'long',
247
- day: 'numeric',
248
- hour: 'numeric',
249
- minute: 'numeric',
250
- second: 'numeric',
251
- }
252
- return new Date(dateString).toLocaleDateString(undefined, options)
253
- },
254
- updatePrevSubmissions: function () {
255
- if (this.$annotator && this.authenticated) {
256
- if (
257
- this.annotationEntry['resourceId'] &&
258
- this.annotationEntry['featureId']
259
- ) {
260
- this.$annotator
261
- .itemAnnotations(
262
- this.userApiKey,
263
- this.annotationEntry['resourceId'],
264
- this.annotationEntry['featureId']
265
- )
266
- .then((value) => {
267
- this.prevSubs = value
268
- })
269
- .catch((reason) => {
270
- console.log(reason) // Error!
271
- })
272
- }
273
- }
274
- },
275
- submit: function () {
276
- // User can either update/delete annotation directly
277
- // or provide extra comments for update/delete action
278
- if (
279
- this.annotationEntry['type'] === 'updated' &&
280
- this.annotationEntry['positionUpdated']
281
- ) {
282
- this.comment = this.comment ?
283
- `Position Updated: ${this.comment}` :
284
- 'Position Updated'
285
- } else if (this.annotationEntry['type'] === 'deleted') {
286
- this.comment = this.comment ?
287
- `Feature Deleted: ${this.comment}` :
288
- 'Feature Deleted'
289
- }
290
-
291
- if (this.evidence.length > 0 || this.comment) {
292
- if (
293
- this.annotationEntry['resourceId'] &&
294
- this.annotationEntry['featureId']
295
- ) {
296
- const evidenceURLs = []
297
- this.evidence.forEach((evidence) => {
298
- if (evidence.includes('DOI:')) {
299
- const link = evidence.replace('DOI:', 'https://doi.org/')
300
- evidenceURLs.push(new URL(link))
301
- } else if (evidence.includes('PMID:')) {
302
- const link = evidence.replace(
303
- 'PMID:',
304
- 'https://pubmed.ncbi.nlm.nih.gov/'
305
- )
306
- evidenceURLs.push(new URL(link))
307
- }
308
- })
309
- const userAnnotation = {
310
- resource: this.annotationEntry['resourceId'],
311
- item: Object.assign({id: this.annotationEntry['featureId']},
312
- Object.fromEntries(
313
- Object.entries(this.annotationEntry)
314
- .filter(([key]) => ['label', 'models'].includes(key)))),
315
- body: {
316
- evidence: evidenceURLs,
317
- comment: this.comment,
318
- },
319
- feature: this.annotationEntry['feature']
320
- }
321
- Object.assign(userAnnotation.body, this.annotationEntry['body'])
322
- if (this.annotationEntry['type'] === 'deleted') {
323
- userAnnotation.feature = undefined
324
- }
325
- if (this.creator) userAnnotation.creator = this.creator
326
- this.$annotator
327
- .addAnnotation(this.userApiKey, userAnnotation)
328
- .then(() => {
329
- this.$emit('annotation', userAnnotation)
330
- this.errorMessage = ''
331
- this.resetSubmission()
332
- this.updatePrevSubmissions()
333
- })
334
- .catch(() => {
335
- this.errorMessage =
336
- 'There is a problem with the submission, please try again later'
337
- })
338
- }
339
- }
340
- },
341
- removeEvidence: function (index) {
342
- this.evidence.splice(index, 1)
343
- },
344
- resetSubmission: function () {
345
- this.editing = false
346
- this.evidence = []
347
- this.newFeature = ''
348
- this.comment = ''
349
- },
350
- },
351
- watch: {
352
- annotationEntry: {
353
- handler: function (newVal, oldVal) {
354
- if (newVal !== oldVal) {
355
- this.resetSubmission()
356
- this.updatePrevSubmissions()
357
- }
358
- },
359
- immediate: false,
360
- deep: false,
361
- },
362
- },
363
- mounted: function () {
364
- this.$annotator.authenticate(this.userApiKey).then((userData) => {
365
- if (userData.name && userData.email) {
366
- this.creator = userData
367
- if (!userData.orcid) this.creator.orcid = '0000-0000-0000-0000'
368
- this.authenticated = true
369
- this.updatePrevSubmissions()
370
- } else {
371
- this.errorMessage = ''
372
- }
373
- })
374
- },
375
- }
376
- </script>
377
-
378
- <style lang="scss" scoped>
379
-
380
- .info-field {
381
- display: flex;
382
- }
383
-
384
- .block {
385
- margin-bottom: 0.5em;
386
-
387
- .main > &:first-of-type {
388
- margin-right: 0.5em;
389
- }
390
- }
391
-
392
- .button {
393
- padding-top: 5px;
394
- padding-bottom: 5px;
395
- }
396
-
397
- .standard-icon {
398
- color: $app-primary-color;
399
- &:hover {
400
- cursor: pointer;
401
- }
402
- }
403
-
404
- .dialog-text {
405
- color: rgb(48, 49, 51);
406
- font-size: 14px;
407
- font-weight: normal;
408
- line-height: 20px;
409
- }
410
-
411
- .main {
412
- font-size: 14px;
413
- text-align: left;
414
- line-height: 1.5em;
415
- font-family: Asap, sans-serif, Helvetica;
416
- font-weight: 400;
417
- /* outline: thin red solid; */
418
- padding: 1em !important;
419
- overflow-x: hidden;
420
- overflow-y: auto;
421
- min-width: 300px; // .maplibregl-popup max-width
422
- max-height: 400px;
423
- scrollbar-width: thin;
424
-
425
- &::-webkit-scrollbar {
426
- width: 4px;
427
- }
428
-
429
- &::-webkit-scrollbar-thumb {
430
- border-radius: 10px;
431
- box-shadow: inset 0 0 6px #c0c4cc;
432
- }
433
- }
434
-
435
- .title {
436
- font-size: 18px;
437
- font-weight: 500;
438
- font-weight: bold;
439
- padding-bottom: 8px;
440
- color: rgb(131, 0, 191);
441
- }
442
-
443
- .sub-title {
444
- font-size: 16px;
445
- }
446
-
447
- .dialog-spacer {
448
- border-bottom: 1px solid #e4e7ed;
449
- margin-bottom: 10px;
450
- }
451
-
452
- .submit {
453
- color: $app-primary-color;
454
- &:hover {
455
- cursor: pointer;
456
- }
457
- }
458
-
459
- .entry ~ .entry {
460
- border-top: 1px solid #e4e7ed;
461
- margin-top: 10px;
462
- }
463
-
464
- .hide {
465
- color: $app-primary-color;
466
- cursor: pointer;
467
- margin-right: 6px;
468
- margin-top: 3px;
469
- }
470
-
471
- :deep(.el-input__inner),
472
- :deep(.el-textarea__inner) {
473
- font-family: Asap, sans-serif;
474
- }
475
-
476
- .select-box {
477
- width: 80px;
478
- background-color: var(--white);
479
- font-weight: 500;
480
- color: rgb(48, 49, 51);
481
- :deep(.el-input__inner) {
482
- height: 30px;
483
- color: rgb(48, 49, 51);
484
- }
485
- :deep(.el-input__icon) {
486
- line-height: 30px;
487
- }
488
- }
489
-
490
- :deep(.flatmap_dropdown) {
491
- min-width: 80px !important;
492
- .el-select-dropdown__item {
493
- white-space: nowrap;
494
- text-align: left;
495
- &.selected {
496
- color: $app-primary-color;
497
- font-weight: normal;
498
- }
499
- }
500
- }
501
- </style>