@abi-software/simulationvuer 3.0.12 → 3.0.14

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 || {};
@@ -350,33 +419,36 @@ export default {
350
419
 
351
420
  this.activeSubscriptions.forEach((activeSubscription) => {
352
421
  const modelParameter = `${activeSubscription.component}/${activeSubscription.variable}`;
422
+ const simData = simulationData[modelParameter];
353
423
 
354
- if (simulationData[modelParameter] == null) {
355
- console.warn(`onSimulationData: no data for ${modelParameter}.`);
424
+ if (simData == null) {
425
+ console.warn(
426
+ `SimulationVuer: onSimulationData: no data for ${modelParameter}.`,
427
+ );
356
428
 
357
429
  return;
358
430
  }
359
431
 
360
432
  const data = {
361
- y: Array.from(simulationData[modelParameter]),
362
- title: `${activeSubscription.component}.${activeSubscription.variable}`,
433
+ y: simData.data,
434
+ title: `${activeSubscription.component}.${activeSubscription.variable} (${simData.unit})`,
363
435
  };
364
436
 
365
437
  if (activeSubscription.withVOI) {
366
438
  if (simulationData.VOI == null) {
367
- console.warn('onSimulationData: no data for VOI.');
439
+ console.warn("SimulationVuer: onSimulationData: no data for VOI.");
368
440
 
369
441
  return;
370
442
  } else {
371
- voi ??= Array.from(simulationData.VOI);
443
+ voi ??= simulationData.VOI;
372
444
 
373
445
  data.x = voi;
374
446
  }
375
447
  }
376
448
 
377
- this.$emit('data-notification', {
378
- id: 'nz.ac.auckland.simulation-data-response',
379
- version: '0.1.0',
449
+ this.$emit("data-notification", {
450
+ id: "nz.ac.auckland.simulation-data-response",
451
+ version: "0.1.0",
380
452
  payload: {
381
453
  windowId: activeSubscription.windowId,
382
454
  ownerId: activeSubscription.ownerId,
@@ -388,7 +460,7 @@ export default {
388
460
  /**
389
461
  * @public
390
462
  * Generate the metadata associated with the plot which `index` is given.
391
- * @arg `index`
463
+ * @param `index`
392
464
  */
393
465
  plotMetadata(index) {
394
466
  return {
@@ -403,7 +475,7 @@ export default {
403
475
  /**
404
476
  * @public
405
477
  * Build the simulation UI using `simulationUiInfo`, a JSON object that describes the contents of the simulation UI.
406
- * @arg `simulationUiInfo`
478
+ * @param `simulationUiInfo`
407
479
  */
408
480
  buildSimulationUi(simulationUiInfo) {
409
481
  // Keep track of the simulation UI information.
@@ -423,7 +495,7 @@ export default {
423
495
  // Retrieve and keep track of the solver to be used for the simulation.
424
496
 
425
497
  this.simulationUiInfo.simulation.solvers.forEach((solver) => {
426
- if ((solver.if === undefined) || evaluateValue(this, solver.if)) {
498
+ if (solver.if === undefined || evaluateValue(this, solver.if)) {
427
499
  this.solver = solver;
428
500
  }
429
501
  });
@@ -493,6 +565,25 @@ export default {
493
565
  finaliseUi(this);
494
566
  });
495
567
  },
568
+ /**
569
+ * @private
570
+ * Open the given `url` in a new browser tab, making sure to do so safely.
571
+ * @param `url`
572
+ */
573
+ openUrl(url) {
574
+ const a = document.createElement("a");
575
+
576
+ a.href = url;
577
+ a.target = "_blank";
578
+ a.rel = "noopener noreferrer";
579
+ a.style.display = "none";
580
+
581
+ document.body.appendChild(a);
582
+
583
+ a.click();
584
+
585
+ document.body.removeChild(a);
586
+ },
496
587
  /**
497
588
  * @public
498
589
  * Run the simulation-based dataset directly on oSPARC. Not all simulation-based datasets can be run directly on
@@ -500,7 +591,7 @@ export default {
500
591
  * method.
501
592
  */
502
593
  runOnOsparc() {
503
- window.open(`https://osparc.io/study/${this.uuid}`, "_blank");
594
+ this.openUrl(`https://osparc.io/study/${this.uuid}`);
504
595
  },
505
596
  /**
506
597
  * @public
@@ -508,7 +599,7 @@ export default {
508
599
  * clicked, calls this method.
509
600
  */
510
601
  viewDataset() {
511
- window.open(`https://sparc.science/datasets/${this.id}?type=dataset`, "_blank");
602
+ this.openUrl(`https://sparc.science/datasets/${this.id}?type=dataset`);
512
603
  },
513
604
  /**
514
605
  * @public
@@ -517,8 +608,7 @@ export default {
517
608
  */
518
609
  viewWorkspace() {
519
610
  const url = PMR_URL + this.id;
520
-
521
- window.open(url.substring(0, url.lastIndexOf("/")), "_blank");
611
+ this.openUrl(url.substring(0, url.lastIndexOf("/")));
522
612
  },
523
613
  /**
524
614
  * @public
@@ -556,7 +646,7 @@ export default {
556
646
  */
557
647
  retrieveRequest() {
558
648
  const request = {
559
- solver: this.solver
649
+ solver: this.solver,
560
650
  };
561
651
 
562
652
  if (this.opencorBasedSimulation) {
@@ -565,11 +655,15 @@ export default {
565
655
  json_config: {},
566
656
  };
567
657
 
568
- if ((this.simulationUiInfo.simulation.opencor.endingPoint !== undefined)
569
- && (this.simulationUiInfo.simulation.opencor.pointInterval !== undefined)) {
658
+ if (
659
+ this.simulationUiInfo.simulation.opencor.endingPoint !== undefined &&
660
+ this.simulationUiInfo.simulation.opencor.pointInterval !== undefined
661
+ ) {
570
662
  request.opencor.json_config.simulation = {
571
- "Ending point": this.simulationUiInfo.simulation.opencor.endingPoint,
572
- "Point interval": this.simulationUiInfo.simulation.opencor.pointInterval,
663
+ "Ending point":
664
+ this.simulationUiInfo.simulation.opencor.endingPoint,
665
+ "Point interval":
666
+ this.simulationUiInfo.simulation.opencor.pointInterval,
573
667
  };
574
668
  }
575
669
 
@@ -592,13 +686,13 @@ export default {
592
686
  * @public
593
687
  * Process the simulation results retrieved by `checkSimulation`. The simulation results are post-processed, if
594
688
  * needed, and then readied for use by `PlotVuer`.
595
- * @arg `results`
689
+ * @param `results`
596
690
  */
597
691
  processSimulationResults(results) {
598
692
  // Convert, if needed, the results to a JSON format that is compatible
599
693
  // with our OpenCOR results.
600
694
 
601
- if (typeof (results) === "string") {
695
+ if (typeof results === "string") {
602
696
  const SPACES = /[ \t]+/g;
603
697
  const lines = results.trim().split("\n");
604
698
  const iMax = lines[0].trim().split(SPACES).length;
@@ -646,26 +740,27 @@ export default {
646
740
  /**
647
741
  * @public
648
742
  * Show an HTTP issue using the given `xmlhttp`.
649
- * @arg `xmlhttp`
743
+ * @param `xmlhttp`
650
744
  */
651
745
  showHttpIssue(xmlhttp) {
652
746
  this.isSimulationValid = false;
653
747
  this.showUserMessage = false;
654
- this.errorMessage = xmlhttp.statusText.toLowerCase() + " (<a href='https://httpstatuses.com/" + xmlhttp.status + "/' target='_blank'>" + xmlhttp.status + "</a>)";
748
+ this.errorMessage = xmlhttp.statusText.toLowerCase();
749
+ this.errorStatus = xmlhttp.status;
655
750
  },
656
751
  /**
657
752
  * @public
658
753
  * Check the progress of the simulation using the given `data`, a JSON object that contains the simulation job ID,
659
754
  * as well as the solver name and version. This method is first called by `startSimulation` and then every second by
660
755
  * itself until the simulation is finished.
661
- * @arg `data`
756
+ * @param `data`
662
757
  */
663
758
  checkSimulation(data) {
664
759
  // Check the simulation.
665
760
 
666
761
  const xmlhttp = new XMLHttpRequest();
667
762
 
668
- xmlhttp.open("POST", this.apiLocation + "/check_simulation");
763
+ xmlhttp.open("POST", `${this.apiLocation}/check_simulation`);
669
764
  xmlhttp.setRequestHeader("Content-type", "application/json");
670
765
  xmlhttp.onreadystatechange = () => {
671
766
  if (xmlhttp.readyState === 4) {
@@ -687,13 +782,14 @@ export default {
687
782
 
688
783
  let that = this;
689
784
 
690
- setTimeout(function () {
785
+ setTimeout(() => {
691
786
  that.checkSimulation(data);
692
787
  }, 1000);
693
788
  }
694
789
  } else {
695
790
  this.showUserMessage = false;
696
791
  this.errorMessage = response.description;
792
+ this.errorStatus = null;
697
793
  }
698
794
  } else {
699
795
  this.showHttpIssue(xmlhttp);
@@ -719,7 +815,7 @@ export default {
719
815
 
720
816
  const xmlhttp = new XMLHttpRequest();
721
817
 
722
- xmlhttp.open("POST", this.apiLocation + "/start_simulation");
818
+ xmlhttp.open("POST", `${this.apiLocation}/start_simulation`);
723
819
  xmlhttp.setRequestHeader("Content-type", "application/json");
724
820
  xmlhttp.onreadystatechange = () => {
725
821
  if (xmlhttp.readyState === 4) {
@@ -733,6 +829,7 @@ export default {
733
829
  } else {
734
830
  this.showUserMessage = false;
735
831
  this.errorMessage = response.description;
832
+ this.errorStatus = null;
736
833
  }
737
834
  } else {
738
835
  this.showHttpIssue(xmlhttp);
@@ -755,7 +852,10 @@ export default {
755
852
  this.$nextTick(() => {
756
853
  const xmlhttp = new XMLHttpRequest();
757
854
 
758
- xmlhttp.open("GET", this.apiLocation + "/simulation_ui_file/" + this.id);
855
+ xmlhttp.open(
856
+ "GET",
857
+ `${this.apiLocation}/simulation_ui_file/${this.id}`,
858
+ );
759
859
  xmlhttp.onreadystatechange = () => {
760
860
  if (xmlhttp.readyState === 4) {
761
861
  this.showUserMessage = false;
@@ -765,7 +865,9 @@ export default {
765
865
  this.buildSimulationUi(JSON.parse(xmlhttp.responseText));
766
866
  });
767
867
  } else {
768
- this.errorMessage = "the simulation dataset could not be retrieved";
868
+ this.errorMessage =
869
+ "the simulation dataset could not be retrieved";
870
+ this.errorStatus = null;
769
871
  }
770
872
  }
771
873
  };
@@ -774,8 +876,9 @@ export default {
774
876
  } else if (this.idType === IdType.DATASET_URL) {
775
877
  this.opencorOmexFile = this.id;
776
878
  } else if (this.idType === IdType.PMR_PATH) {
777
- this.opencorOmexFile = PMR_URL + this.id;
778
- } else { // IdType.RAW_COMBINE_ARCHIVE
879
+ this.opencorOmexFile = `${PMR_URL}${this.id}`;
880
+ } else {
881
+ // IdType.RAW_COMBINE_ARCHIVE
779
882
  this.opencorOmexFile = this.id;
780
883
  }
781
884
  },
@@ -795,10 +898,10 @@ export default {
795
898
  <!-- Add "scoped" attribute to limit CSS to this component only -->
796
899
  <style scoped lang="scss">
797
900
  .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;
901
+ --el-color-primary: #8300bf;
902
+ --el-color-primary-light-7: #dab3ec;
903
+ --el-color-primary-light-8: #e6ccf2;
904
+ --el-color-primary-light-9: #f3e6f9;
802
905
  }
803
906
 
804
907
  :deep(.el-button:hover) {
@@ -812,12 +915,12 @@ export default {
812
915
 
813
916
  :deep(.el-loading-spinner) {
814
917
  .path {
815
- stroke: #8300BF;
918
+ stroke: #8300bf;
816
919
  }
817
920
 
818
921
  i,
819
922
  .el-loading-text {
820
- color: #8300BF;
923
+ color: #8300bf;
821
924
  }
822
925
  }
823
926
 
@@ -825,23 +928,23 @@ export default {
825
928
  :deep(.p-floatlabel:has(input:-webkit-autofill)) label,
826
929
  :deep(.p-floatlabel:has(textarea:focus)) label,
827
930
  :deep(.p-floatlabel:has(.p-inputwrapper-focus)) label {
828
- color: #8300BF;
931
+ color: #8300bf;
829
932
  }
830
933
 
831
934
  :deep(.p-inputtext:enabled:focus) {
832
- border-color: #8300BF;
935
+ border-color: #8300bf;
833
936
  }
834
937
 
835
938
  :deep(.p-progressbar-value) {
836
- background-color: #8300BF !important;
939
+ background-color: #8300bf !important;
837
940
  }
838
941
 
839
942
  :deep(.p-select:not(.p-disabled).p-focus) {
840
- border-color: #8300BF;
943
+ border-color: #8300bf;
841
944
  }
842
945
 
843
946
  :deep(.p-slider-range) {
844
- background-color: #8300BF;
947
+ background-color: #8300bf;
845
948
  }
846
949
 
847
950
  div.input {
@@ -1045,21 +1148,33 @@ span.error {
1045
1148
 
1046
1149
  .p-contextmenu-item-label,
1047
1150
  .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;
1151
+ font-family:
1152
+ Inter,
1153
+ -apple-system,
1154
+ BlinkMacSystemFont,
1155
+ "Segoe UI",
1156
+ Roboto,
1157
+ Oxygen,
1158
+ Ubuntu,
1159
+ Cantarell,
1160
+ "Fira Sans",
1161
+ "Droid Sans",
1162
+ "Helvetica Neue",
1163
+ sans-serif;
1164
+ font-size: 0.875rem;
1050
1165
  }
1051
1166
 
1052
1167
  .p-select-option:not(.p-select-option-selected):not(.p-disabled).p-focus {
1053
- background: #F5F7FA !important;
1168
+ background: #f5f7fa !important;
1054
1169
  }
1055
1170
 
1056
1171
  .p-select-option.p-select-option-selected.p-focus {
1057
- background: #F5F7FA !important;
1058
- color: #8300BF !important;
1172
+ background: #f5f7fa !important;
1173
+ color: #8300bf !important;
1059
1174
  }
1060
1175
 
1061
1176
  .p-select-option.p-select-option-selected {
1062
- background: white !important;
1063
- color: #8300BF !important;
1177
+ background: white !important;
1178
+ color: #8300bf !important;
1064
1179
  }
1065
1180
  </style>