@abi-software/mapintegratedvuer 1.8.3 → 1.9.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/mapintegratedvuer",
3
- "version": "1.8.3",
3
+ "version": "1.9.0-beta.0",
4
4
  "license": "Apache-2.0",
5
5
  "scripts": {
6
6
  "serve": "vite --host --force",
@@ -50,11 +50,11 @@
50
50
  "*.js"
51
51
  ],
52
52
  "dependencies": {
53
- "@abi-software/flatmapvuer": "^1.8.2",
54
- "@abi-software/map-side-bar": "^2.7.2",
55
- "@abi-software/map-utilities": "^1.4.2",
53
+ "@abi-software/flatmapvuer": "^1.9.0-beta.0",
54
+ "@abi-software/map-side-bar": "^2.7.3-beta.0",
55
+ "@abi-software/map-utilities": "^1.5.0-beta.0",
56
56
  "@abi-software/plotvuer": "^1.0.3",
57
- "@abi-software/scaffoldvuer": "^1.8.0",
57
+ "@abi-software/scaffoldvuer": "^1.9.0-beta.0",
58
58
  "@abi-software/simulationvuer": "1.0.1",
59
59
  "@abi-software/sparc-annotation": "0.3.2",
60
60
  "@abi-software/svg-sprite": "^1.0.1",
@@ -102,6 +102,9 @@
102
102
  "vue-docgen-api": "^4.79.2",
103
103
  "vue-router": "^4.2.5"
104
104
  },
105
+ "optionalDependencies": {
106
+ "@esbuild/darwin-arm64": "^0.25.3"
107
+ },
105
108
  "eslintConfig": {
106
109
  "root": true,
107
110
  "env": {
package/src/App.vue CHANGED
@@ -64,6 +64,80 @@ import {
64
64
  ElRow as Row,
65
65
  } from 'element-plus';
66
66
 
67
+
68
+ const getAnnotationId = (api, withAnnotation) => {
69
+ return new Promise((resolve) => {
70
+ let offlineAnnotations = JSON.parse(sessionStorage.getItem('anonymous-annotation')) || undefined;
71
+ console.log(withAnnotation)
72
+ if (withAnnotation && offlineAnnotations) {
73
+ let maxRetry = 3
74
+ const annotationUrl = api + '/annotation/getshareid';
75
+ const getId = (attempt) => {
76
+ fetch(annotationUrl, {
77
+ method: 'POST',
78
+ headers: {
79
+ 'Content-type': 'application/json',
80
+ },
81
+ body: JSON.stringify({ state: offlineAnnotations }),
82
+ }).then((response) => {
83
+ if (response.ok) {
84
+ return response.json();
85
+ }
86
+ throw new Error('Unsuccessful attempt to get annotation id')
87
+ })
88
+ .then((data) => {
89
+ resolve(data.uuid);
90
+ })
91
+ .catch((error) => {
92
+ console.log(`Unable to create permalink: attempt ${attempt} of ${maxRetry}`)
93
+ if (maxRetry > attempt) {
94
+ getId(attempt + 1);
95
+ } else {
96
+ resolve(undefined);
97
+ }
98
+ })
99
+ }
100
+ getId(1);
101
+ } else {
102
+ resolve(undefined);
103
+ }
104
+ });
105
+ }
106
+
107
+ const getAnnotationState = (api, annotationId) => {
108
+ return new Promise((resolve) => {
109
+ let maxRetry = 3
110
+ const annotationUrl = api + '/annotation/getstate';
111
+ const getState = (attempt) => {
112
+ fetch(annotationUrl, {
113
+ method: 'POST',
114
+ headers: {
115
+ 'Content-type': 'application/json',
116
+ },
117
+ body: JSON.stringify({ uuid: annotationId }),
118
+ }).then((response) => {
119
+ if (response.ok) {
120
+ return response.json()
121
+ }
122
+ throw new Error('Unsuccessful attempt to get annotations')
123
+ })
124
+ .then((data) => {
125
+ resolve(data);
126
+ })
127
+ .catch((error) => {
128
+ console.log(error)
129
+ console.log(`Unable to get annotation state: attempt ${attempt} of ${maxRetry}`)
130
+ if (maxRetry > attempt) {
131
+ getState(attempt + 1);
132
+ } else {
133
+ resolve(undefined);
134
+ }
135
+ })
136
+ }
137
+ getState(1);
138
+ });
139
+ }
140
+
67
141
  export default {
68
142
  name: 'app',
69
143
  components: {
@@ -118,20 +192,42 @@ export default {
118
192
  if (this.mapSettings.length > 0)
119
193
  this.$refs.map.setState(this.mapSettings.pop());
120
194
  },
121
- updateUUID: function() {
122
- let xmlhttp = new XMLHttpRequest();
195
+ updateUUID: function(withAnnotation) {
123
196
  let url = this.api + 'map/getshareid';
124
- let state = this.$refs.map.getState();
125
- xmlhttp.open('POST', url, true);
126
- //Send the proper header information along with the request
127
- xmlhttp.setRequestHeader('Content-type', 'application/json');
128
- xmlhttp.onreadystatechange = () => {//Call a function when the state changes.
129
- if(xmlhttp.readyState == 4 && xmlhttp.status == 200) {
130
- let state = JSON.parse(xmlhttp.responseText);
131
- this.uuid = state.uuid;
197
+ let state = this.$refs.map.getState(false);
198
+
199
+ const maxRetry = 3;
200
+ const getShareLink = (attempt) => {
201
+ fetch(url, {
202
+ method: 'POST',
203
+ headers: {
204
+ 'Content-type': 'application/json',
205
+ },
206
+ body: JSON.stringify({ state: state }),
207
+ })
208
+ .then((response) => {
209
+ if (response.ok) {
210
+ return response.json()
132
211
  }
212
+ throw new Error('Unsuccessful attempt to get shareid')
213
+ })
214
+ .then((data) => {
215
+ this.uuid = data.uuid
216
+ })
217
+ .catch((error) => {
218
+ console.log(`Unable to create permalink: attempt ${attempt} of ${maxRetry}`)
219
+ if (maxRetry > attempt) {
220
+ getShareLink(attempt + 1)
221
+ }
222
+ })
133
223
  }
134
- xmlhttp.send(JSON.stringify({"state": state}));
224
+ getAnnotationId(this.api, withAnnotation).then((annotationId) => {
225
+ if (annotationId) {
226
+ state.annotationId = annotationId;
227
+ }
228
+ console.log(state)
229
+ getShareLink(1)
230
+ });
135
231
 
136
232
  },
137
233
  setFlatmap: function() {
@@ -213,7 +309,21 @@ export default {
213
309
  xmlhttp.onreadystatechange = () => {//Call a function when the state changes.
214
310
  if(xmlhttp.readyState == 4 && xmlhttp.status == 200) {
215
311
  let state = JSON.parse(xmlhttp.responseText);
216
- this.state = state.state;
312
+ console.log(state)
313
+ if (state?.state?.annotationId) {
314
+ getAnnotationState(this.api, state.state.annotationId).
315
+ then((data) => {
316
+ console.log(data)
317
+ if (data) {
318
+ sessionStorage.setItem('anonymous-annotation', JSON.stringify(data.state))
319
+ }
320
+ this.state = state.state;
321
+ });
322
+ } else {
323
+ this.state = state.state;
324
+ }
325
+
326
+ console.log(state)
217
327
  }
218
328
  }
219
329
  xmlhttp.send(JSON.stringify({"uuid": this.uuid}));
@@ -111,31 +111,84 @@
111
111
  popper-class="link-popover"
112
112
  virtual-triggering
113
113
  >
114
- <el-row :gutter="20"
115
- v-loading="loadingLink"
116
- element-loading-text="Creating link...">
117
- <el-col :span="20">
118
- <el-input
119
- class="link-input"
120
- size="small"
121
- placeholder="Permanant Link Here"
122
- :readonly=true
123
- v-model="shareLink"
124
- ref="linkInput">
125
- </el-input>
126
- </el-col>
127
- <el-col :span="4">
128
- <el-popover class="tooltip" content="Copy link" placement="bottom-end"
129
- :show-after="helpDelay" :teleported=false trigger="hover"
130
- popper-class="header-popper">
131
- <template #reference>
132
- <el-button class="copy-button"
133
- :icon="ElIconCopyDocument" size="small"
134
- @click="copyShareLink"></el-button>
135
- </template>
136
- </el-popover>
137
- </el-col>
114
+ <template v-if="displayShareOptions">
115
+ <el-row>
116
+ <el-col :span="8">
117
+ <el-popover class="tooltip"
118
+ content="Create a permanent link for current views and settings."
119
+ placement="bottom-end"
120
+ :show-after="helpDelay" :teleported=false trigger="hover"
121
+ popper-class="header-popper"
122
+ >
123
+ <template #reference>
124
+ <el-button
125
+ type="primary"
126
+ size="small"
127
+ @click="getShareLink(false)"
128
+ class="share-options"
129
+ >
130
+ Settings Only
131
+ </el-button>
132
+ </template>
133
+ </el-popover>
134
+ </el-col>
135
+ <el-col :span="14">
136
+ <el-popover class="tooltip"
137
+ placement="bottom-end"
138
+ :show-after="helpDelay" :teleported=false trigger="hover"
139
+ popper-class="header-popper"
140
+ >
141
+ <template #reference>
142
+ <el-button
143
+ type="primary"
144
+ size="small"
145
+ @click="getShareLink(true)"
146
+ class="share-options"
147
+ >
148
+ Settings with Annotations
149
+ (Valid for 30 days)
150
+ </el-button>
151
+ </template>
152
+ <template #default>
153
+ Create a link for current views settings
154
+ <br>
155
+ and anonymous annotations.
156
+ <br>
157
+ NOTE: Annotations will only be stored for
158
+ <br>
159
+ 30 days on the server.
160
+ </template>
161
+ </el-popover>
162
+ </el-col>
138
163
  </el-row>
164
+ </template>
165
+ <template v-else>
166
+ <el-row :gutter="20"
167
+ v-loading="loadingLink"
168
+ element-loading-text="Creating link...">
169
+ <el-col :span="20">
170
+ <el-input
171
+ class="link-input"
172
+ size="small"
173
+ placeholder="Permanant Link Here"
174
+ :readonly=true
175
+ v-model="shareLink"
176
+ ref="linkInput">
177
+ </el-input>
178
+ </el-col>
179
+ <el-col :span="4">
180
+ <el-popover class="tooltip" content="Copy link" placement="bottom-end"
181
+ :show-after="helpDelay" :teleported=false trigger="hover"
182
+ popper-class="header-popper">
183
+ <template #reference>
184
+ <el-button class="copy-button"
185
+ :icon="ElIconCopyDocument" size="small"
186
+ @click="copyShareLink"></el-button>
187
+ </template>
188
+ </el-popover>
189
+ </el-col>
190
+ </el-row>
191
+ </template>
139
192
  </el-popover>
140
193
  <el-popover class="tooltip" content="Get permalink" placement="bottom-end"
141
194
  :show-after="helpDelay" :teleported=false trigger="hover"
@@ -145,7 +198,7 @@
145
198
  <map-svg-icon icon="permalink"
146
199
  ref="permalinkRef"
147
200
  class="header-icon"
148
- @click="getShareLink"
201
+ @click="requestShareLink"
149
202
  v-show="shareLink"
150
203
  />
151
204
  </template>
@@ -156,7 +209,6 @@
156
209
  <map-svg-icon icon="close" class="header-icon" @click="close" v-show="showIcons"/>
157
210
  </template>
158
211
  </el-popover>
159
-
160
212
  </el-row>
161
213
  </div>
162
214
  </template>
@@ -260,7 +312,7 @@ export default {
260
312
  return {
261
313
  isFullscreen: false,
262
314
  loadingLink: true,
263
- shareLinkDisplay: false,
315
+ displayShareOptions: false,
264
316
  independent: true,
265
317
  failedSearch: undefined,
266
318
  activeViewRef: undefined,
@@ -309,10 +361,17 @@ export default {
309
361
  setFailedSearch: function(result) {
310
362
  this.failedSearch = result;
311
363
  },
312
- getShareLink: function() {
364
+ requestShareLink: function() {
365
+ if (sessionStorage.getItem('anonymous-annotation')) {
366
+ this.displayShareOptions = true;
367
+ } else {
368
+ this.getShareLink(false);
369
+ }
370
+ },
371
+ getShareLink: function(withAnnotation) {
372
+ this.displayShareOptions = false;
313
373
  this.loadingLink = true;
314
- this.shareLinkDisplay = true;
315
- EventBus.emit("updateShareLinkRequested");
374
+ EventBus.emit("updateShareLinkRequested", withAnnotation);
316
375
  },
317
376
  viewClicked: function(view) {
318
377
  this.splitFlowStore.updateActiveView({
@@ -364,6 +423,17 @@ export default {
364
423
  height:32px;
365
424
  }
366
425
 
426
+ .share-options.el-button {
427
+ font-family: inherit;
428
+
429
+ &:hover,
430
+ &:focus {
431
+ background: $app-primary-color;
432
+ box-shadow: -3px 2px 4px #00000040;
433
+ color: #fff;
434
+ }
435
+ }
436
+
367
437
  :deep(.header-popper.el-popover.el-popper) {
368
438
  padding: 6px 4px;
369
439
  font-size:12px;
@@ -372,6 +442,7 @@ export default {
372
442
  border: 1px solid $app-primary-color;
373
443
  white-space: nowrap;
374
444
  min-width: unset;
445
+
375
446
  .el-popper__arrow {
376
447
  &:before {
377
448
  border-color: $app-primary-color;
@@ -196,11 +196,26 @@ export default {
196
196
  containerB.append(teleportedPopover);
197
197
  });
198
198
  },
199
+ /**
200
+ * @public
201
+ * Restore state of the map viewer from a state provided in the
202
+ * state argument, use the getState method to get the current state.
203
+ *
204
+ * @arg `state`
205
+ */
199
206
  setState: function(state){
200
207
  return this.$refs.flow.setState(state);
201
208
  },
202
- getState: function(){
203
- return this.$refs.flow.getState();
209
+ /**
210
+ * @public
211
+ * Get the current state of the map viewer, these states can be used to
212
+ * restore settings and viewers using the setState method.
213
+ * Set offlineAnnotations to true if the user would like to perserve the
214
+ * state of offline annotations.
215
+ * @arg `offlineAnnotations`
216
+ */
217
+ getState: function(offlineAnnotations = false){
218
+ return this.$refs.flow.getState(offlineAnnotations);
204
219
  },
205
220
  /**
206
221
  * @public
@@ -358,11 +373,11 @@ export default {
358
373
  this.splitFlowStore?.getAvailableTerms(this.settingsStore.sparcApi);
359
374
  },
360
375
  mounted: async function() {
361
- EventBus.on("updateShareLinkRequested", () => {
376
+ EventBus.on("updateShareLinkRequested", (data) => {
362
377
  /**
363
378
  * This event emits when the share link is requested.
364
379
  */
365
- this.$emit("updateShareLinkRequested");
380
+ this.$emit("updateShareLinkRequested", data);
366
381
  });
367
382
  EventBus.on('trackEvent', (taggingData) => {
368
383
  /**
@@ -126,6 +126,7 @@ export default {
126
126
  confirmCreateCallback: undefined,
127
127
  cancelCreateCallback: undefined,
128
128
  confirmDeleteCallback: undefined,
129
+ confirmCommentCallback: undefined,
129
130
  createData: {},
130
131
  }
131
132
  },
@@ -464,7 +465,7 @@ export default {
464
465
  if (state.splitFlow) this.splitFlowStore.setState(state.splitFlow);
465
466
  else this.entries.forEach(entry => this.splitFlowStore.setIdToPrimaryPane(entry.id));
466
467
  },
467
- getState: function () {
468
+ getState: function (offlineAnnotations = false) {
468
469
  let state = JSON.parse(JSON.stringify(this.entriesStore.$state));
469
470
  let splitdialog = this.$refs.splitdialog;
470
471
  let dialogStates = splitdialog.getContentsState();
@@ -477,6 +478,13 @@ export default {
477
478
  delete entry.viewUrl;
478
479
  if (entry.type === "MultiFlatmap" && "uberonId" in entry)
479
480
  delete entry.uberonId;
481
+ if (offlineAnnotations === false) {
482
+ if (entry.type === "Scaffold" && entry?.state?.offlineAnnotations) {
483
+ delete entry.state.offlineAnnotations;
484
+ } else if (entry?.state?.state?.offlineAnnotations) {
485
+ delete entry.state.state.offlineAnnotations;
486
+ }
487
+ }
480
488
  }
481
489
  }
482
490
  state.splitFlow = this.splitFlowStore.getState();
@@ -541,6 +549,8 @@ export default {
541
549
  onAnnotationSubmitted: function(annotation) {
542
550
  if (this.annotationCallback) {
543
551
  this.annotationCallback(annotation);
552
+ } else if (this.confirmCommentCallback) {
553
+ this.confirmCommentCallback(annotation)
544
554
  }
545
555
  },
546
556
  onConfirmCreate: function(payload) {
@@ -591,6 +601,7 @@ export default {
591
601
  this.confirmCreateCallback = markRaw(payload.confirmCreate);
592
602
  this.cancelCreateCallback = markRaw(payload.cancelCreate);
593
603
  this.confirmDeleteCallback = markRaw(payload.confirmDelete);
604
+ this.confirmCommentCallback = markRaw(payload.confirmComment);
594
605
  if (this.$refs.sideBar) {
595
606
  this.tabClicked({id: 3, type: 'annotation'});
596
607
  this.$refs.sideBar.setDrawerOpen(true);