@abi-software/simulationvuer 2.0.11-beta.0 → 2.0.12

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/simulationvuer",
3
- "version": "2.0.11-beta.0",
3
+ "version": "2.0.12",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "serve": "vite serve --host --force",
package/src/App.vue CHANGED
@@ -2,14 +2,24 @@
2
2
  <div id="app">
3
3
  <div class="app">
4
4
  <h1>SimulationVuer</h1>
5
- <h3>Simulations run on o²S²PARC:</h3>
6
- <el-radio-group v-model="id" size="small">
7
- <el-radio-button :class="className(dataset.id)" v-for="dataset in sparcDatasets" v-bind:key="dataset.id" :label="dataset.label" :value="dataset.id" />
8
- </el-radio-group>
9
- <h3>Simulations run in the browser:</h3>
10
- <el-radio-group v-model="id" size="small">
11
- <el-radio-button :class="className(dataset.id)" v-for="dataset in pmrDatasets" v-bind:key="dataset.id" :label="dataset.label" :value="dataset.id" />
12
- </el-radio-group>
5
+ <div v-if="datasetIds.length !== 0">
6
+ <h3>Dataset IDs (run on o²S²PARC):</h3>
7
+ <el-radio-group v-model="activeResource" size="small">
8
+ <el-radio-button :class="className(datasetId.id)" v-for="datasetId in datasetIds" v-bind:key="datasetId.id" :label="datasetId.label" :value="datasetId.id" />
9
+ </el-radio-group>
10
+ </div>
11
+ <div v-if="datasetUrls.length !== 0">
12
+ <h3>Dataset URLs (run in the browser):</h3>
13
+ <el-radio-group v-model="activeResource" size="small">
14
+ <el-radio-button :class="className(datasetUrl.id)" v-for="datasetUrl in datasetUrls" v-bind:key="datasetUrl.id" :label="datasetUrl.label" :value="datasetUrl.id" />
15
+ </el-radio-group>
16
+ </div>
17
+ <div v-if="pmrPaths.length !== 0">
18
+ <h3>PMR paths (run in the browser):</h3>
19
+ <el-radio-group v-model="activeResource" size="small">
20
+ <el-radio-button :class="className(pmrPath.id)" v-for="pmrPath in pmrPaths" v-bind:key="pmrPath.id" :label="pmrPath.label" :value="pmrPath.id" />
21
+ </el-radio-group>
22
+ </div>
13
23
  <div ref="dropArea" class="drop-area" @dragenter.prevent="onDragEnter" @dragover.prevent @drop.prevent="onDrop" @dragleave.prevent="onDragLeave">
14
24
  You can drag and drop a COMBINE archive here.
15
25
  </div>
@@ -25,20 +35,20 @@
25
35
  </el-dialog>
26
36
  </div>
27
37
  <hr />
28
- <div v-for="dataset in datasets()" v-bind:key="dataset.id">
29
- <div v-if="initialised(dataset.id)" v-show="dataset.id == id">
30
- <div v-if="typeof dataset.id === 'number'">
38
+ <div v-for="resource in resources()" v-bind:key="resource.id">
39
+ <div v-if="isResourceInitialised(resource.id)" v-show="resource.id === activeResource">
40
+ <div v-if="typeof resource.id === 'number'">
31
41
  <span>
32
- <strong>Dataset <a :href="datasetUrl(dataset.id)" target="_blank">{{ dataset.id }}</a>:</strong> {{ dataset.description }}
42
+ <strong>Dataset <a :href="datasetUrl(resource.id)" target="_blank">{{ resource.id }}</a>:</strong> {{ resource.description }}
33
43
  </span>
34
44
  <hr />
35
45
  </div>
36
- <SimulationVuer :apiLocation="apiLocation" :id="dataset.id" style="height: 640px;" />
46
+ <SimulationVuer :apiLocation="apiLocation" :id="resource.id" style="height: 640px;" />
37
47
  </div>
38
48
  </div>
39
- <div v-if="id == -1">
49
+ <div v-if="activeResource === -1">
40
50
  <div v-for="combineArchive in combineArchives" v-bind:key="combineArchive">
41
- <SimulationVuer :apiLocation="apiLocation" :combineArchive="combineArchive" style="height: 640px;" />
51
+ <SimulationVuer :apiLocation="apiLocation" :id="combineArchive" style="height: 640px;" />
42
52
  </div>
43
53
  </div>
44
54
  <hr />
@@ -62,46 +72,58 @@ export default {
62
72
  dropAreaCounter: 0,
63
73
  dragAndDropWarningVisible: false,
64
74
  combineArchives: [],
65
- sparcDatasets: [
66
- { id: 0, label: "0", description: "Non-simulation dataset" },
75
+ datasetIds: [
76
+ { id: 0, label: "Invalid", description: "Non-simulation dataset" },
67
77
  { id: 135, label: "135", description: "Computational analysis of the human sinus node action potential - Model development and effects of mutations" },
68
78
  { id: 157, label: "157", description: "Fabbri-based composite SAN model" },
69
79
  { id: 308, label: "308", description: "Kember Cardiac Nerve Model" },
70
80
  { id: 318, label: "318", description: "Multi-scale rabbit cardiac electrophysiology models" },
71
81
  { id: 320, label: "320", description: "Multi-scale human cardiac electrophysiology models" },
72
82
  ],
73
- pmrDatasets: [
83
+ datasetUrls: [
84
+ { id: "https://raw.githubusercontent.com/opencor/webapp/refs/heads/main/tests/models/ui/invalid.omex", label: "Invalid", description: "COMBINE archive" },
85
+ { id: "https://raw.githubusercontent.com/opencor/webapp/refs/heads/main/tests/models/ui/135.omex", label: "135", description: "COMBINE archive" },
86
+ { id: "https://raw.githubusercontent.com/opencor/webapp/refs/heads/main/tests/models/ui/157.omex", label: "157", description: "COMBINE archive" },
87
+ { id: "https://raw.githubusercontent.com/opencor/webapp/refs/heads/main/tests/models/ui/lorenz.omex", label: "Lorenz", description: "COMBINE archive" },
88
+ { id: "https://raw.githubusercontent.com/opencor/webapp/refs/heads/main/tests/models/ui/tt04.omex", label: "TT04", description: "COMBINE archive" },
89
+ { id: "https://raw.githubusercontent.com/opencor/webapp/refs/heads/main/tests/models/ui/cvs.omex", label: "CVS", description: "COMBINE archive" },
90
+ ],
91
+ pmrPaths: [
92
+ { id: "workspace/b7c/rawfile/e0ae8d2d56aaaa091e23e1ee7e84cacbda1dfb6b/invalid.omex", label: "Invalid", description: "COMBINE archive from PMR" },
74
93
  { id: "workspace/b7c/rawfile/e0ae8d2d56aaaa091e23e1ee7e84cacbda1dfb6b/135.omex", label: "135", description: "COMBINE archive from PMR" },
75
94
  { id: "workspace/b7c/rawfile/e0ae8d2d56aaaa091e23e1ee7e84cacbda1dfb6b/157.omex", label: "157", description: "COMBINE archive from PMR" },
76
95
  { id: "workspace/b7c/rawfile/e0ae8d2d56aaaa091e23e1ee7e84cacbda1dfb6b/lorenz.omex", label: "Lorenz", description: "COMBINE archive from PMR" },
77
96
  { id: "workspace/b7c/rawfile/e0ae8d2d56aaaa091e23e1ee7e84cacbda1dfb6b/tt04.omex", label: "TT04", description: "COMBINE archive from PMR" },
78
- { id: "workspace/b7c/rawfile/e0ae8d2d56aaaa091e23e1ee7e84cacbda1dfb6b/Gee_whiz_Exported.omex", label: "GeeWhiz", description: "COMBINE archive from PMR" },
79
97
  { id: "workspace/b7c/rawfile/e0ae8d2d56aaaa091e23e1ee7e84cacbda1dfb6b/cvs.omex", label: "CVS", description: "COMBINE archive from PMR" },
80
98
  ],
81
- id: 0,
82
- ready: [],
99
+ activeResource: 0,
100
+ initialisedResources: [],
83
101
  };
84
102
  },
85
103
  methods: {
86
104
  className(id) {
87
- return ((id == this.sparcDatasets[0].id) || (id == this.pmrDatasets[0].id)) ? "first-dataset" : "";
105
+ return ( ((this.datasetIds.length !== 0) && (id === this.datasetIds[0].id))
106
+ || ((this.datasetUrls.length !== 0) && (id === this.datasetUrls[0].id))
107
+ || ((this.pmrPaths.length !== 0) && (id === this.pmrPaths[0].id))) ?
108
+ "first-resource" :
109
+ "not-first-resource";
88
110
  },
89
- datasets() {
90
- return this.sparcDatasets.concat(this.pmrDatasets);
111
+ resources() {
112
+ return this.datasetIds.concat(this.datasetUrls).concat(this.pmrPaths);
91
113
  },
92
114
  datasetUrl(id) {
93
115
  return `https://sparc.science/datasets/${id}?type=dataset`;
94
116
  },
95
- initialised(id) {
96
- if (this.ready.includes(id)) {
117
+ isResourceInitialised(resource) {
118
+ if (this.initialisedResources.includes(resource)) {
97
119
  return true;
98
120
  }
99
121
 
100
- if (this.id == id) {
101
- this.ready.push(id);
122
+ if (this.activeResource === resource) {
123
+ this.initialisedResources.push(resource);
102
124
  }
103
125
 
104
- return this.ready.includes(id);
126
+ return this.initialisedResources.includes(resource);
105
127
  },
106
128
  onDragEnter() {
107
129
  this.dropAreaCounter += 1;
@@ -123,7 +145,7 @@ export default {
123
145
  files[0]
124
146
  .arrayBuffer()
125
147
  .then((arrayBuffer) => {
126
- this.id = -1;
148
+ this.activeResource = -1;
127
149
  this.combineArchives = [new Uint8Array(arrayBuffer)];
128
150
  })
129
151
  }
@@ -181,10 +203,14 @@ export default {
181
203
  color: #8300bf;
182
204
  }
183
205
 
184
- .first-dataset>.el-radio-button__inner {
206
+ .first-resource>.el-radio-button__inner {
185
207
  border-left: 1px solid #8300bf !important;
186
208
  }
187
209
 
210
+ .not-first-resource>.el-radio-button__inner {
211
+ border-left: 0 !important;
212
+ }
213
+
188
214
  .el-radio-button__original-radio:checked+.el-radio-button__inner {
189
215
  background-color: #8300bf !important;
190
216
  border-color: #8300bf !important;
@@ -18,17 +18,17 @@
18
18
  :stepValue="input.stepValue"
19
19
  />
20
20
  </div>
21
- <div class="primary-button">
22
- <el-button type="primary" size="small" @click="startSimulation()" v-if="!libopencorSet">Run Simulation</el-button>
21
+ <div class="primary-button" v-if="!libopencorSet">
22
+ <el-button type="primary" size="small" @click="startSimulation()">Run Simulation</el-button>
23
23
  </div>
24
24
  <div class="secondary-button" v-if="uuid">
25
25
  <el-button size="small" @click="runOnOsparc()">Run on oSPARC</el-button>
26
26
  </div>
27
- <div class="secondary-button">
28
- <el-button size="small" @click="viewDataset()" v-if="!libopencorSet">View Dataset</el-button>
27
+ <div class="secondary-button" v-if="!libopencorSet">
28
+ <el-button size="small" @click="viewDataset()">View Dataset</el-button>
29
29
  </div>
30
- <div class="secondary-button">
31
- <el-button size="small" @click="viewWorkspace()" v-if="libopencorSet">View Workspace</el-button>
30
+ <div class="secondary-button" v-if="libopencorSet && idType === 'pmr_path'">
31
+ <el-button size="small" @click="viewWorkspace()">View Workspace</el-button>
32
32
  </div>
33
33
  <p class="default note" v-if="uuid">Additional parameters are available on oSPARC</p>
34
34
  </div>
@@ -66,6 +66,13 @@ const PMR_URL = "https://models.physiomeproject.org/";
66
66
 
67
67
  const math = create(all, {});
68
68
 
69
+ const IdType = Object.freeze({
70
+ DATASET_ID: 'dataset_id',
71
+ DATASET_URL: 'dataset_url',
72
+ PMR_PATH: 'pmr_path',
73
+ RAW_COMBINE_ARCHIVE: 'raw_combine_archive',
74
+ });
75
+
69
76
  /**
70
77
  * SimulationVuer
71
78
  */
@@ -89,27 +96,35 @@ export default {
89
96
  type: String,
90
97
  },
91
98
  /**
92
- * The ID of the simulation-based dataset, if it is a number, or the path
93
- * to a PMR file, if it is a string.
99
+ * The ID for this simulation, i.e. either
100
+ * - the ID (as a number) of a SPARC dataset,
101
+ * - the URL (as a string) of a COMBINE archive located in a SPARC dataset,
102
+ * - the path (as a string) to a COMBINE archive located on PMR, or
103
+ * - a raw COMBINE archive (as a Uint8Array).
94
104
  */
95
105
  id: {
96
- required: false,
97
- type: [Number, String],
98
- default: 0,
99
- },
100
- /**
101
- * A COMBINE archive that was passed directly.
102
- */
103
- combineArchive: {
104
- required: false,
105
- type: Uint8Array,
106
- default: undefined,
106
+ required: true,
107
+ type: [Number, String, Uint8Array],
107
108
  },
108
109
  },
109
110
  data: function () {
111
+ // Determine the ID's type.
112
+
113
+ let idType;
114
+
115
+ if (typeof this.id === "number") {
116
+ idType = IdType.DATASET_ID;
117
+ } else if (this.id instanceof Uint8Array) {
118
+ idType = IdType.RAW_COMBINE_ARCHIVE;
119
+ } else if (this.id.startsWith("https://")) {
120
+ idType = IdType.DATASET_URL;
121
+ } else {
122
+ idType = IdType.PMR_PATH;
123
+ }
124
+
110
125
  // Retrieve some information about the dataset.
111
126
 
112
- if (this.id > 0) {
127
+ if (idType === IdType.DATASET_ID) {
113
128
  const xmlhttp = new XMLHttpRequest();
114
129
 
115
130
  xmlhttp.open("GET", this.apiLocation + "/sim/dataset/" + this.id);
@@ -131,6 +146,7 @@ export default {
131
146
  fileManager: undefined,
132
147
  hasFinalisedUi: false,
133
148
  hasValidSimulationUiInfo: false,
149
+ idType: idType,
134
150
  instance: undefined,
135
151
  isMounted: false,
136
152
  isSimulationValid: true,
@@ -657,7 +673,7 @@ export default {
657
673
  created: function () {
658
674
  // Try to retrieve the UI information.
659
675
 
660
- if (this.id > 0) {
676
+ if (this.idType === IdType.DATASET_ID) {
661
677
  this.userMessage = "Retrieving UI information...";
662
678
  this.showUserMessage = true;
663
679
 
@@ -682,7 +698,33 @@ export default {
682
698
  };
683
699
  xmlhttp.send();
684
700
  });
685
- } else if (this.id !== 0) {
701
+ } else if (this.idType === IdType.DATASET_URL) {
702
+ this.userMessage = "Retrieving COMBINE archive...";
703
+ this.showUserMessage = true;
704
+
705
+ // Retrieve the COMBINE archive, extract the simulation UI JSON file from
706
+ // it and then build the simulation UI.
707
+
708
+ this.$nextTick(() => {
709
+ const xmlhttp = new XMLHttpRequest();
710
+
711
+ xmlhttp.open("GET", this.id);
712
+ xmlhttp.responseType = "arraybuffer";
713
+ xmlhttp.onreadystatechange = () => {
714
+ if (xmlhttp.readyState === 4) {
715
+ if (xmlhttp.status === 200) {
716
+ libOpenCOR().then((libopencor) => {
717
+ this.extractAndBuildSimulationUi(libopencor, new Uint8Array(xmlhttp.response));
718
+ });
719
+ } else {
720
+ this.errorMessage = "the COMBINE archive could not be retrieved";
721
+ this.showUserMessage = false;
722
+ }
723
+ }
724
+ };
725
+ xmlhttp.send();
726
+ });
727
+ } else if (this.idType === IdType.PMR_PATH) {
686
728
  this.userMessage = "Retrieving COMBINE archive from PMR...";
687
729
  this.showUserMessage = true;
688
730
 
@@ -701,14 +743,14 @@ export default {
701
743
  this.extractAndBuildSimulationUi(libopencor, Uint8Array.from(atob(xmlhttp.response), (c) => c.charCodeAt(0)));
702
744
  });
703
745
  } else {
704
- this.errorMessage = "the COMBINE archive chould not be retrieved";
746
+ this.errorMessage = "the COMBINE archive chould not be retrieved from PMR";
705
747
  this.showUserMessage = false;
706
748
  }
707
749
  }
708
750
  };
709
751
  xmlhttp.send(JSON.stringify({ path: this.id }));
710
752
  });
711
- } else if (this.combineArchive !== undefined) {
753
+ } else {
712
754
  // Extract the simulation UI JSON file from the COMBINE archive and build
713
755
  // the simulation UI.
714
756
 
@@ -717,11 +759,9 @@ export default {
717
759
 
718
760
  this.$nextTick(() => {
719
761
  libOpenCOR().then((libopencor) => {
720
- this.extractAndBuildSimulationUi(libopencor, this.combineArchive);
762
+ this.extractAndBuildSimulationUi(libopencor, this.id);
721
763
  });
722
764
  });
723
- } else {
724
- this.errorMessage = "an non-simulation dataset was provided";
725
765
  }
726
766
  },
727
767
  mounted: function () {