@abi-software/simulationvuer 3.0.12 → 3.0.13

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.
@@ -1,14 +1,24 @@
1
1
  <template>
2
- <div class="simulation-vuer" v-loading="showUserMessage" :element-loading-text="userMessage">
2
+ <div
3
+ class="simulation-vuer"
4
+ v-loading="showUserMessage"
5
+ :element-loading-text="userMessage"
6
+ >
3
7
  <div class="container" v-if="opencorOmexFile === null">
4
- <p v-if="!hasValidSimulationUiInfo && !showUserMessage" class="default error"><span class="error">Error:</span> {{ errorMessage }}.</p>
8
+ <p
9
+ v-if="!hasValidSimulationUiInfo && !showUserMessage"
10
+ class="default error"
11
+ >
12
+ <span class="error">Error:</span> {{ errorMessage }}.
13
+ </p>
5
14
  <div class="main" v-if="hasValidSimulationUiInfo">
6
- <div class="main-left" :class="{'with-buttons': uuid}">
15
+ <div class="main-left" :class="{ 'with-buttons': uuid }">
7
16
  <p class="default name">{{ name }}</p>
8
17
  <el-divider></el-divider>
9
18
  <p class="default input-parameters">Input parameters</p>
10
19
  <div class="input scrollbar">
11
- <SimulationVuerInput v-for="(input, index) in simulationUiInfo.input"
20
+ <SimulationVuerInput
21
+ v-for="(input, index) in simulationUiInfo.input"
12
22
  ref="simInput"
13
23
  :defaultValue="input.defaultValue"
14
24
  :key="`input-${index}`"
@@ -21,19 +31,28 @@
21
31
  </div>
22
32
  <div class="buttons-container">
23
33
  <div class="primary-button">
24
- <el-button type="primary" size="small" @click="startSimulation()">Run Simulation</el-button>
34
+ <el-button type="primary" size="small" @click="startSimulation()"
35
+ >Run Simulation</el-button
36
+ >
25
37
  </div>
26
38
  <div class="secondary-button" v-if="uuid">
27
- <el-button size="small" @click="runOnOsparc()">Run on oSPARC</el-button>
39
+ <el-button size="small" @click="runOnOsparc()"
40
+ >Run on oSPARC</el-button
41
+ >
28
42
  </div>
29
43
  <div class="secondary-button">
30
- <el-button size="small" @click="viewDataset()">View Dataset</el-button>
44
+ <el-button size="small" @click="viewDataset()"
45
+ >View Dataset</el-button
46
+ >
31
47
  </div>
32
- <p class="default note" v-if="uuid">Additional parameters are available on oSPARC</p>
48
+ <p class="default note" v-if="uuid">
49
+ Additional parameters are available on oSPARC
50
+ </p>
33
51
  </div>
34
52
  </div>
35
53
  <div class="main-right" ref="output" v-show="isSimulationValid">
36
- <PlotVuer v-for="(_outputPlot, index) in simulationUiInfo.output.plots"
54
+ <PlotVuer
55
+ v-for="(_outputPlot, index) in simulationUiInfo.output.plots"
37
56
  :key="`output-${index}`"
38
57
  :metadata="plotMetadata(index)"
39
58
  :data-source="{ data: simulationResults[index] }"
@@ -43,7 +62,19 @@
43
62
  />
44
63
  </div>
45
64
  <div class="main-right" v-show="!isSimulationValid">
46
- <p class="default error"><span class="error">Error:</span> <span v-html="errorMessage"></span>.</p>
65
+ <p class="default error">
66
+ <span class="error">Error:</span>
67
+ {{ errorMessage }}
68
+ <span v-if="errorStatus">
69
+ (<a
70
+ :href="`https://httpstatuses.com/${errorStatus}`"
71
+ target="_blank"
72
+ rel="noopener noreferrer"
73
+ >
74
+ {{ errorStatus }} </a
75
+ >) </span
76
+ >.
77
+ </p>
47
78
  </div>
48
79
  </div>
49
80
  </div>
@@ -61,23 +92,25 @@
61
92
  <script>
62
93
  import { PlotVuer } from "@abi-software/plotvuer";
63
94
  import "@abi-software/plotvuer/dist/style.css";
64
- import SimulationVuerInput from "./SimulationVuerInput.vue";
65
- import { ElButton, ElDivider, ElLoading } from "element-plus";
95
+ import OpenCOR from "@opencor/opencor";
96
+ import "@opencor/opencor/style.css";
97
+
98
+ import { ElButton, ElDivider } from "element-plus";
99
+ import { create, all } from "mathjs";
100
+
66
101
  import { evaluateValue, finaliseUi, OPENCOR_SOLVER_NAME } from "./common.js";
67
102
  import { validJson } from "./json.js";
68
- import { create, all } from "mathjs";
69
- import OpenCOR from '@opencor/opencor';
70
- import '@opencor/opencor/style.css';
103
+ import SimulationVuerInput from "./SimulationVuerInput.vue";
71
104
 
72
105
  const PMR_URL = "https://models.physiomeproject.org/";
73
106
 
74
107
  const math = create(all, {});
75
108
 
76
109
  const IdType = Object.freeze({
77
- DATASET_ID: 'dataset_id',
78
- DATASET_URL: 'dataset_url',
79
- PMR_PATH: 'pmr_path',
80
- RAW_COMBINE_ARCHIVE: 'raw_combine_archive',
110
+ DATASET_ID: "dataset_id",
111
+ DATASET_URL: "dataset_url",
112
+ PMR_PATH: "pmr_path",
113
+ RAW_COMBINE_ARCHIVE: "raw_combine_archive",
81
114
  });
82
115
 
83
116
  function isWebProtocol(urlString) {
@@ -101,7 +134,6 @@ export default {
101
134
  SimulationVuerInput,
102
135
  ElButton,
103
136
  ElDivider,
104
- ElLoading,
105
137
  OpenCOR,
106
138
  },
107
139
  props: {
@@ -144,14 +176,17 @@ export default {
144
176
  if (idType === IdType.DATASET_ID) {
145
177
  const xmlhttp = new XMLHttpRequest();
146
178
 
147
- xmlhttp.open("GET", this.apiLocation + "/sim/dataset/" + this.id);
179
+ xmlhttp.open("GET", `${this.apiLocation}/sim/dataset/${this.id}`);
148
180
  xmlhttp.onreadystatechange = () => {
149
181
  if (xmlhttp.readyState === 4) {
150
182
  if (xmlhttp.status === 200) {
151
183
  const datasetInfo = JSON.parse(xmlhttp.responseText);
152
184
 
153
185
  this.name = datasetInfo.name;
154
- this.uuid = (datasetInfo.study !== undefined) ? datasetInfo.study.uuid : undefined;
186
+ this.uuid =
187
+ datasetInfo.study !== undefined
188
+ ? datasetInfo.study.uuid
189
+ : undefined;
155
190
  }
156
191
  }
157
192
  };
@@ -160,6 +195,7 @@ export default {
160
195
 
161
196
  return {
162
197
  errorMessage: "",
198
+ errorStatus: null,
163
199
  fileManager: undefined,
164
200
  hasFinalisedUi: false,
165
201
  hasValidSimulationUiInfo: false,
@@ -191,40 +227,48 @@ export default {
191
227
  /**
192
228
  * @public
193
229
  * Add a data subscription.
194
- * @arg `subscription `
230
+ * @param `subscription`
195
231
  */
196
232
  addDataSubscription(subscription) {
197
233
  // Check that the subscription is valid.
198
234
 
199
- if (!subscription || typeof subscription !== 'object') {
200
- console.error('addDataSubscription: subscription must be an object.');
235
+ if (!subscription || typeof subscription !== "object") {
236
+ console.warn(
237
+ "SimulationVuer: addDataSubscription: subscription must be an object.",
238
+ );
201
239
 
202
240
  return;
203
241
  }
204
242
 
205
243
  // Check that the subscription has the expected ID.
206
244
 
207
- const EXPECTED_ID = 'nz.ac.auckland.simulation-data-request';
245
+ const EXPECTED_ID = "nz.ac.auckland.simulation-data-request";
208
246
  const EXPECTED_MAJOR_VERSION = 0;
209
247
 
210
248
  if (subscription.id !== EXPECTED_ID) {
211
- console.warn(`addDataSubscription: invalid ID (expected '${EXPECTED_ID}' but got '${subscription.id}').`);
249
+ console.warn(
250
+ `SimulationVuer: addDataSubscription: invalid ID (expected '${EXPECTED_ID}' but got '${subscription.id}').`,
251
+ );
212
252
 
213
253
  return;
214
254
  }
215
255
 
216
256
  // Check that the version is valid and compatible with what we expect.
217
257
 
218
- if (typeof subscription.version !== 'string') {
219
- console.warn(`addDataSubscription: missing or non-string version ('${subscription.version}').`);
258
+ if (typeof subscription.version !== "string") {
259
+ console.warn(
260
+ `SimulationVuer: addDataSubscription: missing or non-string version ('${subscription.version}').`,
261
+ );
220
262
 
221
263
  return;
222
264
  }
223
265
 
224
- const versionParts = subscription.version.split('.');
266
+ const versionParts = subscription.version.split(".");
225
267
 
226
268
  if (versionParts.length < 1 || !/^[0-9]+$/.test(versionParts[0])) {
227
- console.warn(`addDataSubscription: malformed version ('${subscription.version}').`);
269
+ console.warn(
270
+ `SimulationVuer: addDataSubscription: malformed version ('${subscription.version}').`,
271
+ );
228
272
 
229
273
  return;
230
274
  }
@@ -232,13 +276,17 @@ export default {
232
276
  const subscriptionMajorVersion = parseInt(versionParts[0], 10);
233
277
 
234
278
  if (Number.isNaN(subscriptionMajorVersion)) {
235
- console.warn(`addDataSubscription: could not parse the major version from ('${subscription.version}')`);
279
+ console.warn(
280
+ `SimulationVuer: addDataSubscription: could not parse the major version from ('${subscription.version}')`,
281
+ );
236
282
 
237
283
  return;
238
284
  }
239
285
 
240
286
  if (subscriptionMajorVersion !== EXPECTED_MAJOR_VERSION) {
241
- console.warn(`addDataSubscription: version mismatch (expected v${EXPECTED_MAJOR_VERSION}.y.z but got v${subscription.version}).`);
287
+ console.warn(
288
+ `SimulationVuer: addDataSubscription: version mismatch (expected v${EXPECTED_MAJOR_VERSION}.y.z but got v${subscription.version}).`,
289
+ );
242
290
 
243
291
  return;
244
292
  }
@@ -249,23 +297,25 @@ export default {
249
297
  const missing = [];
250
298
 
251
299
  if (payload.windowId == null) {
252
- missing.push('windowId');
300
+ missing.push("windowId");
253
301
  }
254
302
 
255
303
  if (payload.ownerId == null) {
256
- missing.push('ownerId');
304
+ missing.push("ownerId");
257
305
  }
258
306
 
259
307
  if (!payload.component) {
260
- missing.push('component');
308
+ missing.push("component");
261
309
  }
262
310
 
263
311
  if (!payload.variable) {
264
- missing.push('variable');
312
+ missing.push("variable");
265
313
  }
266
314
 
267
315
  if (missing.length) {
268
- console.warn(`addDataSubscription: payload missing fields: ${missing.join(', ')}.`);
316
+ console.warn(
317
+ `SimulationVuer: addDataSubscription: payload missing fields: ${missing.join(", ")}.`,
318
+ );
269
319
 
270
320
  return;
271
321
  }
@@ -280,52 +330,69 @@ export default {
280
330
  const modelParameters = [];
281
331
 
282
332
  if (subscription.payload?.withVOI) {
283
- modelParameters.push('VOI');
333
+ modelParameters.push("VOI");
284
334
  }
285
335
 
286
- modelParameters.push(`${subscription.payload?.component}/${subscription.payload?.variable}`);
336
+ modelParameters.push(
337
+ `${subscription.payload?.component}/${subscription.payload?.variable}`,
338
+ );
287
339
 
288
340
  this.$refs.opencorRef?.trackSimulationData(modelParameters);
289
341
  },
290
342
  /**
291
343
  * @public
292
344
  * Remove a data subscription.
293
- * @arg `subscriptionId `
345
+ * @param `subscriptionId`
294
346
  */
295
347
  removeDataSubscription(subscriptionId) {
296
348
  // Ask OpenCOR to stop tracking the simulation data associated with the subscription's component and variable (and
297
349
  // the VOI, if requested and unless it's requested by another subscription).
298
350
 
299
- const subscription = this.activeSubscriptions.find((activeSubscription) => {
300
- return activeSubscription.windowId === subscriptionId;
301
- });
351
+ const subscription = this.activeSubscriptions.find(
352
+ (activeSubscription) => {
353
+ return activeSubscription.windowId === subscriptionId;
354
+ },
355
+ );
302
356
 
303
357
  if (!subscription) {
304
- console.warn(`removeDataSubscription: no active subscription found for id ${subscriptionId}.`);
358
+ console.warn(
359
+ `SimulationVuer: removeDataSubscription: no active subscription found for id ${subscriptionId}.`,
360
+ );
305
361
 
306
362
  return;
307
363
  }
308
364
 
309
- const isVoiTrackedByAnotherSubscription = this.activeSubscriptions.some((activeSubscription) => {
310
- return activeSubscription.windowId !== subscriptionId && activeSubscription.withVOI;
311
- });
312
- const isModelParameterTrackedByAnotherSubscription = this.activeSubscriptions.some((activeSubscription) => {
313
- return (
314
- activeSubscription.windowId !== subscriptionId &&
315
- activeSubscription.component === subscription.component &&
316
- activeSubscription.variable === subscription.variable
317
- );
318
- });
365
+ const isVoiTrackedByAnotherSubscription = this.activeSubscriptions.some(
366
+ (activeSubscription) => {
367
+ return (
368
+ activeSubscription.windowId !== subscriptionId &&
369
+ activeSubscription.withVOI
370
+ );
371
+ },
372
+ );
373
+ const isModelParameterTrackedByAnotherSubscription =
374
+ this.activeSubscriptions.some((activeSubscription) => {
375
+ return (
376
+ activeSubscription.windowId !== subscriptionId &&
377
+ activeSubscription.component === subscription.component &&
378
+ activeSubscription.variable === subscription.variable
379
+ );
380
+ });
319
381
 
320
- if (!isVoiTrackedByAnotherSubscription || !isModelParameterTrackedByAnotherSubscription) {
382
+ if (
383
+ !isVoiTrackedByAnotherSubscription ||
384
+ !isModelParameterTrackedByAnotherSubscription
385
+ ) {
321
386
  const modelParameters = [];
322
387
 
323
388
  if (subscription.withVOI && !isVoiTrackedByAnotherSubscription) {
324
- modelParameters.push('VOI');
389
+ modelParameters.push("VOI");
325
390
  }
326
391
 
327
392
  if (!isModelParameterTrackedByAnotherSubscription) {
328
- modelParameters.push(`${subscription.component}/${subscription.variable}`);
393
+ modelParameters.push(
394
+ `${subscription.component}/${subscription.variable}`,
395
+ );
329
396
  }
330
397
 
331
398
  if (modelParameters.length) {
@@ -335,14 +402,16 @@ export default {
335
402
 
336
403
  // Remove the subscription from our list of active subscriptions.
337
404
 
338
- this.activeSubscriptions = this.activeSubscriptions.filter((activeSubscription) => {
339
- return activeSubscription.windowId !== subscriptionId;
340
- });
405
+ this.activeSubscriptions = this.activeSubscriptions.filter(
406
+ (activeSubscription) => {
407
+ return activeSubscription.windowId !== subscriptionId;
408
+ },
409
+ );
341
410
  },
342
411
  /**
343
412
  * @public
344
413
  * Let the outside world know that we have received some simulation data from OpenCOR by emitting a `data-notification` event.
345
- * @arg `event`
414
+ * @param `event`
346
415
  */
347
416
  onSimulationData(event) {
348
417
  const simulationData = event.simulationData || {};
@@ -352,31 +421,33 @@ export default {
352
421
  const modelParameter = `${activeSubscription.component}/${activeSubscription.variable}`;
353
422
 
354
423
  if (simulationData[modelParameter] == null) {
355
- console.warn(`onSimulationData: no data for ${modelParameter}.`);
424
+ console.warn(
425
+ `SimulationVuer: onSimulationData: no data for ${modelParameter}.`,
426
+ );
356
427
 
357
428
  return;
358
429
  }
359
430
 
360
431
  const data = {
361
- y: Array.from(simulationData[modelParameter]),
432
+ y: simulationData[modelParameter],
362
433
  title: `${activeSubscription.component}.${activeSubscription.variable}`,
363
434
  };
364
435
 
365
436
  if (activeSubscription.withVOI) {
366
437
  if (simulationData.VOI == null) {
367
- console.warn('onSimulationData: no data for VOI.');
438
+ console.warn("SimulationVuer: onSimulationData: no data for VOI.");
368
439
 
369
440
  return;
370
441
  } else {
371
- voi ??= Array.from(simulationData.VOI);
442
+ voi ??= simulationData.VOI;
372
443
 
373
444
  data.x = voi;
374
445
  }
375
446
  }
376
447
 
377
- this.$emit('data-notification', {
378
- id: 'nz.ac.auckland.simulation-data-response',
379
- version: '0.1.0',
448
+ this.$emit("data-notification", {
449
+ id: "nz.ac.auckland.simulation-data-response",
450
+ version: "0.1.0",
380
451
  payload: {
381
452
  windowId: activeSubscription.windowId,
382
453
  ownerId: activeSubscription.ownerId,
@@ -388,7 +459,7 @@ export default {
388
459
  /**
389
460
  * @public
390
461
  * Generate the metadata associated with the plot which `index` is given.
391
- * @arg `index`
462
+ * @param `index`
392
463
  */
393
464
  plotMetadata(index) {
394
465
  return {
@@ -403,7 +474,7 @@ export default {
403
474
  /**
404
475
  * @public
405
476
  * Build the simulation UI using `simulationUiInfo`, a JSON object that describes the contents of the simulation UI.
406
- * @arg `simulationUiInfo`
477
+ * @param `simulationUiInfo`
407
478
  */
408
479
  buildSimulationUi(simulationUiInfo) {
409
480
  // Keep track of the simulation UI information.
@@ -423,7 +494,7 @@ export default {
423
494
  // Retrieve and keep track of the solver to be used for the simulation.
424
495
 
425
496
  this.simulationUiInfo.simulation.solvers.forEach((solver) => {
426
- if ((solver.if === undefined) || evaluateValue(this, solver.if)) {
497
+ if (solver.if === undefined || evaluateValue(this, solver.if)) {
427
498
  this.solver = solver;
428
499
  }
429
500
  });
@@ -493,6 +564,25 @@ export default {
493
564
  finaliseUi(this);
494
565
  });
495
566
  },
567
+ /**
568
+ * @private
569
+ * Open the given `url` in a new browser tab, making sure to do so safely.
570
+ * @param `url`
571
+ */
572
+ openUrl(url) {
573
+ const a = document.createElement("a");
574
+
575
+ a.href = url;
576
+ a.target = "_blank";
577
+ a.rel = "noopener noreferrer";
578
+ a.style.display = "none";
579
+
580
+ document.body.appendChild(a);
581
+
582
+ a.click();
583
+
584
+ document.body.removeChild(a);
585
+ },
496
586
  /**
497
587
  * @public
498
588
  * Run the simulation-based dataset directly on oSPARC. Not all simulation-based datasets can be run directly on
@@ -500,7 +590,7 @@ export default {
500
590
  * method.
501
591
  */
502
592
  runOnOsparc() {
503
- window.open(`https://osparc.io/study/${this.uuid}`, "_blank");
593
+ this.openUrl(`https://osparc.io/study/${this.uuid}`);
504
594
  },
505
595
  /**
506
596
  * @public
@@ -508,7 +598,7 @@ export default {
508
598
  * clicked, calls this method.
509
599
  */
510
600
  viewDataset() {
511
- window.open(`https://sparc.science/datasets/${this.id}?type=dataset`, "_blank");
601
+ this.openUrl(`https://sparc.science/datasets/${this.id}?type=dataset`);
512
602
  },
513
603
  /**
514
604
  * @public
@@ -517,8 +607,7 @@ export default {
517
607
  */
518
608
  viewWorkspace() {
519
609
  const url = PMR_URL + this.id;
520
-
521
- window.open(url.substring(0, url.lastIndexOf("/")), "_blank");
610
+ this.openUrl(url.substring(0, url.lastIndexOf("/")));
522
611
  },
523
612
  /**
524
613
  * @public
@@ -556,7 +645,7 @@ export default {
556
645
  */
557
646
  retrieveRequest() {
558
647
  const request = {
559
- solver: this.solver
648
+ solver: this.solver,
560
649
  };
561
650
 
562
651
  if (this.opencorBasedSimulation) {
@@ -565,11 +654,15 @@ export default {
565
654
  json_config: {},
566
655
  };
567
656
 
568
- if ((this.simulationUiInfo.simulation.opencor.endingPoint !== undefined)
569
- && (this.simulationUiInfo.simulation.opencor.pointInterval !== undefined)) {
657
+ if (
658
+ this.simulationUiInfo.simulation.opencor.endingPoint !== undefined &&
659
+ this.simulationUiInfo.simulation.opencor.pointInterval !== undefined
660
+ ) {
570
661
  request.opencor.json_config.simulation = {
571
- "Ending point": this.simulationUiInfo.simulation.opencor.endingPoint,
572
- "Point interval": this.simulationUiInfo.simulation.opencor.pointInterval,
662
+ "Ending point":
663
+ this.simulationUiInfo.simulation.opencor.endingPoint,
664
+ "Point interval":
665
+ this.simulationUiInfo.simulation.opencor.pointInterval,
573
666
  };
574
667
  }
575
668
 
@@ -592,13 +685,13 @@ export default {
592
685
  * @public
593
686
  * Process the simulation results retrieved by `checkSimulation`. The simulation results are post-processed, if
594
687
  * needed, and then readied for use by `PlotVuer`.
595
- * @arg `results`
688
+ * @param `results`
596
689
  */
597
690
  processSimulationResults(results) {
598
691
  // Convert, if needed, the results to a JSON format that is compatible
599
692
  // with our OpenCOR results.
600
693
 
601
- if (typeof (results) === "string") {
694
+ if (typeof results === "string") {
602
695
  const SPACES = /[ \t]+/g;
603
696
  const lines = results.trim().split("\n");
604
697
  const iMax = lines[0].trim().split(SPACES).length;
@@ -646,26 +739,27 @@ export default {
646
739
  /**
647
740
  * @public
648
741
  * Show an HTTP issue using the given `xmlhttp`.
649
- * @arg `xmlhttp`
742
+ * @param `xmlhttp`
650
743
  */
651
744
  showHttpIssue(xmlhttp) {
652
745
  this.isSimulationValid = false;
653
746
  this.showUserMessage = false;
654
- this.errorMessage = xmlhttp.statusText.toLowerCase() + " (<a href='https://httpstatuses.com/" + xmlhttp.status + "/' target='_blank'>" + xmlhttp.status + "</a>)";
747
+ this.errorMessage = xmlhttp.statusText.toLowerCase();
748
+ this.errorStatus = xmlhttp.status;
655
749
  },
656
750
  /**
657
751
  * @public
658
752
  * Check the progress of the simulation using the given `data`, a JSON object that contains the simulation job ID,
659
753
  * as well as the solver name and version. This method is first called by `startSimulation` and then every second by
660
754
  * itself until the simulation is finished.
661
- * @arg `data`
755
+ * @param `data`
662
756
  */
663
757
  checkSimulation(data) {
664
758
  // Check the simulation.
665
759
 
666
760
  const xmlhttp = new XMLHttpRequest();
667
761
 
668
- xmlhttp.open("POST", this.apiLocation + "/check_simulation");
762
+ xmlhttp.open("POST", `${this.apiLocation}/check_simulation`);
669
763
  xmlhttp.setRequestHeader("Content-type", "application/json");
670
764
  xmlhttp.onreadystatechange = () => {
671
765
  if (xmlhttp.readyState === 4) {
@@ -687,13 +781,14 @@ export default {
687
781
 
688
782
  let that = this;
689
783
 
690
- setTimeout(function () {
784
+ setTimeout(() => {
691
785
  that.checkSimulation(data);
692
786
  }, 1000);
693
787
  }
694
788
  } else {
695
789
  this.showUserMessage = false;
696
790
  this.errorMessage = response.description;
791
+ this.errorStatus = null;
697
792
  }
698
793
  } else {
699
794
  this.showHttpIssue(xmlhttp);
@@ -719,7 +814,7 @@ export default {
719
814
 
720
815
  const xmlhttp = new XMLHttpRequest();
721
816
 
722
- xmlhttp.open("POST", this.apiLocation + "/start_simulation");
817
+ xmlhttp.open("POST", `${this.apiLocation}/start_simulation`);
723
818
  xmlhttp.setRequestHeader("Content-type", "application/json");
724
819
  xmlhttp.onreadystatechange = () => {
725
820
  if (xmlhttp.readyState === 4) {
@@ -733,6 +828,7 @@ export default {
733
828
  } else {
734
829
  this.showUserMessage = false;
735
830
  this.errorMessage = response.description;
831
+ this.errorStatus = null;
736
832
  }
737
833
  } else {
738
834
  this.showHttpIssue(xmlhttp);
@@ -755,7 +851,10 @@ export default {
755
851
  this.$nextTick(() => {
756
852
  const xmlhttp = new XMLHttpRequest();
757
853
 
758
- xmlhttp.open("GET", this.apiLocation + "/simulation_ui_file/" + this.id);
854
+ xmlhttp.open(
855
+ "GET",
856
+ `${this.apiLocation}/simulation_ui_file/${this.id}`,
857
+ );
759
858
  xmlhttp.onreadystatechange = () => {
760
859
  if (xmlhttp.readyState === 4) {
761
860
  this.showUserMessage = false;
@@ -765,7 +864,9 @@ export default {
765
864
  this.buildSimulationUi(JSON.parse(xmlhttp.responseText));
766
865
  });
767
866
  } else {
768
- this.errorMessage = "the simulation dataset could not be retrieved";
867
+ this.errorMessage =
868
+ "the simulation dataset could not be retrieved";
869
+ this.errorStatus = null;
769
870
  }
770
871
  }
771
872
  };
@@ -774,8 +875,9 @@ export default {
774
875
  } else if (this.idType === IdType.DATASET_URL) {
775
876
  this.opencorOmexFile = this.id;
776
877
  } else if (this.idType === IdType.PMR_PATH) {
777
- this.opencorOmexFile = PMR_URL + this.id;
778
- } else { // IdType.RAW_COMBINE_ARCHIVE
878
+ this.opencorOmexFile = `${PMR_URL}${this.id}`;
879
+ } else {
880
+ // IdType.RAW_COMBINE_ARCHIVE
779
881
  this.opencorOmexFile = this.id;
780
882
  }
781
883
  },
@@ -795,10 +897,10 @@ export default {
795
897
  <!-- Add "scoped" attribute to limit CSS to this component only -->
796
898
  <style scoped lang="scss">
797
899
  .simulation-vuer {
798
- --el-color-primary: #8300BF;
799
- --el-color-primary-light-7: #DAB3EC;
800
- --el-color-primary-light-8: #E6CCF2;
801
- --el-color-primary-light-9: #F3E6F9;
900
+ --el-color-primary: #8300bf;
901
+ --el-color-primary-light-7: #dab3ec;
902
+ --el-color-primary-light-8: #e6ccf2;
903
+ --el-color-primary-light-9: #f3e6f9;
802
904
  }
803
905
 
804
906
  :deep(.el-button:hover) {
@@ -812,12 +914,12 @@ export default {
812
914
 
813
915
  :deep(.el-loading-spinner) {
814
916
  .path {
815
- stroke: #8300BF;
917
+ stroke: #8300bf;
816
918
  }
817
919
 
818
920
  i,
819
921
  .el-loading-text {
820
- color: #8300BF;
922
+ color: #8300bf;
821
923
  }
822
924
  }
823
925
 
@@ -825,23 +927,23 @@ export default {
825
927
  :deep(.p-floatlabel:has(input:-webkit-autofill)) label,
826
928
  :deep(.p-floatlabel:has(textarea:focus)) label,
827
929
  :deep(.p-floatlabel:has(.p-inputwrapper-focus)) label {
828
- color: #8300BF;
930
+ color: #8300bf;
829
931
  }
830
932
 
831
933
  :deep(.p-inputtext:enabled:focus) {
832
- border-color: #8300BF;
934
+ border-color: #8300bf;
833
935
  }
834
936
 
835
937
  :deep(.p-progressbar-value) {
836
- background-color: #8300BF !important;
938
+ background-color: #8300bf !important;
837
939
  }
838
940
 
839
941
  :deep(.p-select:not(.p-disabled).p-focus) {
840
- border-color: #8300BF;
942
+ border-color: #8300bf;
841
943
  }
842
944
 
843
945
  :deep(.p-slider-range) {
844
- background-color: #8300BF;
946
+ background-color: #8300bf;
845
947
  }
846
948
 
847
949
  div.input {
@@ -1045,21 +1147,33 @@ span.error {
1045
1147
 
1046
1148
  .p-contextmenu-item-label,
1047
1149
  .p-select-option-label {
1048
- font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
1049
- font-size: 0.875rem;
1150
+ font-family:
1151
+ Inter,
1152
+ -apple-system,
1153
+ BlinkMacSystemFont,
1154
+ "Segoe UI",
1155
+ Roboto,
1156
+ Oxygen,
1157
+ Ubuntu,
1158
+ Cantarell,
1159
+ "Fira Sans",
1160
+ "Droid Sans",
1161
+ "Helvetica Neue",
1162
+ sans-serif;
1163
+ font-size: 0.875rem;
1050
1164
  }
1051
1165
 
1052
1166
  .p-select-option:not(.p-select-option-selected):not(.p-disabled).p-focus {
1053
- background: #F5F7FA !important;
1167
+ background: #f5f7fa !important;
1054
1168
  }
1055
1169
 
1056
1170
  .p-select-option.p-select-option-selected.p-focus {
1057
- background: #F5F7FA !important;
1058
- color: #8300BF !important;
1171
+ background: #f5f7fa !important;
1172
+ color: #8300bf !important;
1059
1173
  }
1060
1174
 
1061
1175
  .p-select-option.p-select-option-selected {
1062
- background: white !important;
1063
- color: #8300BF !important;
1176
+ background: white !important;
1177
+ color: #8300bf !important;
1064
1178
  }
1065
1179
  </style>