@abi-software/simulationvuer 3.0.10-beta.0 → 3.0.10
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/dist/favicon.ico +0 -0
- package/dist/index.html +17 -0
- package/dist/simulationvuer.js +71717 -0
- package/dist/simulationvuer.umd.cjs +4787 -0
- package/dist/style.css +1 -0
- package/package.json +2 -2
- package/src/App.vue +1 -1
- package/src/components/SimulationVuer.vue +343 -305
- package/src/components.d.ts +0 -3
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="simulation-vuer" v-loading="showUserMessage" :element-loading-text="userMessage">
|
|
3
3
|
<div class="container" v-if="opencorOmexFile === null">
|
|
4
|
-
<p v-if="!hasValidSimulationUiInfo && !showUserMessage" class="default error">
|
|
5
|
-
<span class="error">Error:</span> {{ errorMessage }}.
|
|
6
|
-
</p>
|
|
4
|
+
<p v-if="!hasValidSimulationUiInfo && !showUserMessage" class="default error"><span class="error">Error:</span> {{ errorMessage }}.</p>
|
|
7
5
|
<div class="main" v-if="hasValidSimulationUiInfo">
|
|
8
|
-
<div class="main-left" :class="{
|
|
6
|
+
<div class="main-left" :class="{'with-buttons': uuid}">
|
|
9
7
|
<p class="default name">{{ name }}</p>
|
|
10
8
|
<el-divider></el-divider>
|
|
11
9
|
<p class="default input-parameters">Input parameters</p>
|
|
12
10
|
<div class="input scrollbar">
|
|
13
|
-
<SimulationVuerInput
|
|
14
|
-
v-for="(input, index) in simulationUiInfo.input"
|
|
11
|
+
<SimulationVuerInput v-for="(input, index) in simulationUiInfo.input"
|
|
15
12
|
ref="simInput"
|
|
16
13
|
:defaultValue="input.defaultValue"
|
|
17
14
|
:key="`input-${index}`"
|
|
@@ -36,8 +33,7 @@
|
|
|
36
33
|
</div>
|
|
37
34
|
</div>
|
|
38
35
|
<div class="main-right" ref="output" v-show="isSimulationValid">
|
|
39
|
-
<PlotVuer
|
|
40
|
-
v-for="(_outputPlot, index) in simulationUiInfo.output.plots"
|
|
36
|
+
<PlotVuer v-for="(_outputPlot, index) in simulationUiInfo.output.plots"
|
|
41
37
|
:key="`output-${index}`"
|
|
42
38
|
:metadata="plotMetadata(index)"
|
|
43
39
|
:data-source="{ data: simulationResults[index] }"
|
|
@@ -47,155 +43,51 @@
|
|
|
47
43
|
/>
|
|
48
44
|
</div>
|
|
49
45
|
<div class="main-right" v-show="!isSimulationValid">
|
|
50
|
-
<p class="default error">
|
|
51
|
-
<span class="error">Error:</span>
|
|
52
|
-
<span v-html="errorMessage"></span>.
|
|
53
|
-
</p>
|
|
46
|
+
<p class="default error"><span class="error">Error:</span> <span v-html="errorMessage"></span>.</p>
|
|
54
47
|
</div>
|
|
55
48
|
</div>
|
|
56
49
|
</div>
|
|
57
50
|
<div v-else class="opencor">
|
|
58
|
-
<OpenCOR
|
|
51
|
+
<OpenCOR
|
|
52
|
+
ref="opencorRef"
|
|
53
|
+
:omex="opencorOmexFile"
|
|
54
|
+
theme="light"
|
|
55
|
+
@simulationData="onSimulationData($event)"
|
|
56
|
+
/>
|
|
59
57
|
</div>
|
|
60
58
|
</div>
|
|
61
59
|
</template>
|
|
62
60
|
|
|
63
|
-
<script setup>
|
|
64
|
-
import { onMounted, onUnmounted, ref } from 'vue'
|
|
65
|
-
|
|
66
|
-
const emit = defineEmits(['data-notification'])
|
|
67
|
-
|
|
68
|
-
const activeSubscriptions = ref([])
|
|
69
|
-
// Only for demonstration purposes.
|
|
70
|
-
let intervalTimer = null
|
|
71
|
-
|
|
72
|
-
// Only for demonstration purposes.
|
|
73
|
-
function getMockValue(type, tick) {
|
|
74
|
-
if (type === 'sine') return Math.sin(tick * 0.1) * 10
|
|
75
|
-
if (type === 'linear') return tick
|
|
76
|
-
return Math.random() * 10
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Only for demonstration purposes.
|
|
80
|
-
function mockType(req) {
|
|
81
|
-
return Math.random() < 0.5 ? 'sine' : 'random'
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Only for demonstration purposes.
|
|
85
|
-
function generateMockSeries(type, length = 100) {
|
|
86
|
-
const data = []
|
|
87
|
-
for (let i = 0; i < length; i++) {
|
|
88
|
-
data.push(getMockValue(type, i))
|
|
89
|
-
}
|
|
90
|
-
return data
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function addDataSubscription(subscription) {
|
|
94
|
-
if (!subscription || typeof subscription !== 'object') {
|
|
95
|
-
console.error('addDataSubscription: Subscription must be an object.')
|
|
96
|
-
return
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const EXPECTED_ID = 'nz.ac.auckland.simulation-data-request'
|
|
100
|
-
const EXPECTED_MAJOR_VERSION = 0
|
|
101
|
-
|
|
102
|
-
if (subscription.id !== EXPECTED_ID) {
|
|
103
|
-
console.warn(`Request ignored: Invalid ID '${subscription.id}'`)
|
|
104
|
-
return
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const subscriptionMajorVersion = parseInt(subscription.version.split('.')[0])
|
|
108
|
-
if (subscriptionMajorVersion !== EXPECTED_MAJOR_VERSION) {
|
|
109
|
-
console.warn(
|
|
110
|
-
`Request ignored: Version mismatch. Expected v${EXPECTED_MAJOR_VERSION}.x, got v${subscription.version}`
|
|
111
|
-
)
|
|
112
|
-
return
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
activeSubscriptions.value.push(subscription.payload)
|
|
116
|
-
sendDataForSubscription(subscription.payload)
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function sendDataForSubscription(dataSubscription) {
|
|
120
|
-
// Only for demonstration purposes.
|
|
121
|
-
const type = mockType(dataSubscription)
|
|
122
|
-
let data = {
|
|
123
|
-
y: generateMockSeries(type, 100),
|
|
124
|
-
title: `${dataSubscription.component}.${dataSubscription.variable}`,
|
|
125
|
-
}
|
|
126
|
-
if (dataSubscription.withVOI) {
|
|
127
|
-
const voi_type = 'linear'
|
|
128
|
-
data.x = generateMockSeries(voi_type, 100)
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const response = {
|
|
132
|
-
id: 'nz.ac.auckland.simulation-data-response',
|
|
133
|
-
version: '0.1.0',
|
|
134
|
-
payload: {
|
|
135
|
-
windowId: dataSubscription.windowId,
|
|
136
|
-
ownerId: dataSubscription.ownerId,
|
|
137
|
-
data: data,
|
|
138
|
-
},
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
emit('data-notification', response)
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function removeDataSubscription(subscriptionId) {
|
|
145
|
-
activeSubscriptions.value = activeSubscriptions.value.filter(
|
|
146
|
-
(sub) => sub.windowId !== subscriptionId
|
|
147
|
-
)
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
defineExpose({ addDataSubscription, removeDataSubscription })
|
|
151
|
-
|
|
152
|
-
// Only for demonstration purposes.
|
|
153
|
-
onMounted(() => {
|
|
154
|
-
intervalTimer = setInterval(() => {
|
|
155
|
-
if (activeSubscriptions.value.length === 0) return
|
|
156
|
-
|
|
157
|
-
activeSubscriptions.value.forEach((subscription) => {
|
|
158
|
-
sendDataForSubscription(subscription)
|
|
159
|
-
})
|
|
160
|
-
}, 3000)
|
|
161
|
-
})
|
|
162
|
-
|
|
163
|
-
// Only for demonstration purposes.
|
|
164
|
-
onUnmounted(() => {
|
|
165
|
-
if (intervalTimer) clearInterval(intervalTimer)
|
|
166
|
-
})
|
|
167
|
-
</script>
|
|
168
|
-
|
|
169
61
|
<script>
|
|
170
|
-
import { PlotVuer } from
|
|
171
|
-
import
|
|
172
|
-
import SimulationVuerInput from
|
|
173
|
-
import { ElButton, ElDivider, ElLoading } from
|
|
174
|
-
import { evaluateValue, finaliseUi, OPENCOR_SOLVER_NAME } from
|
|
175
|
-
import { validJson } from
|
|
176
|
-
import { create, all } from
|
|
177
|
-
import OpenCOR from '@opencor/opencor'
|
|
178
|
-
import '@opencor/opencor/style.css'
|
|
62
|
+
import { PlotVuer } from "@abi-software/plotvuer";
|
|
63
|
+
import "@abi-software/plotvuer/dist/style.css";
|
|
64
|
+
import SimulationVuerInput from "./SimulationVuerInput.vue";
|
|
65
|
+
import { ElButton, ElDivider, ElLoading } from "element-plus";
|
|
66
|
+
import { evaluateValue, finaliseUi, OPENCOR_SOLVER_NAME } from "./common.js";
|
|
67
|
+
import { validJson } from "./json.js";
|
|
68
|
+
import { create, all } from "mathjs";
|
|
69
|
+
import OpenCOR from '@opencor/opencor';
|
|
70
|
+
import '@opencor/opencor/style.css';
|
|
179
71
|
|
|
180
|
-
const PMR_URL =
|
|
72
|
+
const PMR_URL = "https://models.physiomeproject.org/";
|
|
181
73
|
|
|
182
|
-
const math = create(all, {})
|
|
74
|
+
const math = create(all, {});
|
|
183
75
|
|
|
184
76
|
const IdType = Object.freeze({
|
|
185
77
|
DATASET_ID: 'dataset_id',
|
|
186
78
|
DATASET_URL: 'dataset_url',
|
|
187
79
|
PMR_PATH: 'pmr_path',
|
|
188
80
|
RAW_COMBINE_ARCHIVE: 'raw_combine_archive',
|
|
189
|
-
})
|
|
81
|
+
});
|
|
190
82
|
|
|
191
83
|
function isWebProtocol(urlString) {
|
|
192
84
|
try {
|
|
193
|
-
const url = new URL(urlString)
|
|
85
|
+
const url = new URL(urlString);
|
|
194
86
|
// Protocol property includes the colon, e.g., "https:".
|
|
195
|
-
return url.protocol ===
|
|
87
|
+
return url.protocol === "http:" || url.protocol === "https:";
|
|
196
88
|
} catch (_err) {
|
|
197
89
|
// String was not a valid URL.
|
|
198
|
-
return false
|
|
90
|
+
return false;
|
|
199
91
|
}
|
|
200
92
|
}
|
|
201
93
|
|
|
@@ -203,7 +95,7 @@ function isWebProtocol(urlString) {
|
|
|
203
95
|
* SimulationVuer
|
|
204
96
|
*/
|
|
205
97
|
export default {
|
|
206
|
-
name:
|
|
98
|
+
name: "SimulationVuer",
|
|
207
99
|
components: {
|
|
208
100
|
PlotVuer,
|
|
209
101
|
SimulationVuerInput,
|
|
@@ -235,39 +127,39 @@ export default {
|
|
|
235
127
|
data: function () {
|
|
236
128
|
// Determine the ID's type.
|
|
237
129
|
|
|
238
|
-
let idType
|
|
130
|
+
let idType;
|
|
239
131
|
|
|
240
|
-
if (typeof this.id ===
|
|
241
|
-
idType = IdType.DATASET_ID
|
|
132
|
+
if (typeof this.id === "number") {
|
|
133
|
+
idType = IdType.DATASET_ID;
|
|
242
134
|
} else if (this.id instanceof Uint8Array) {
|
|
243
|
-
idType = IdType.RAW_COMBINE_ARCHIVE
|
|
135
|
+
idType = IdType.RAW_COMBINE_ARCHIVE;
|
|
244
136
|
} else if (isWebProtocol(this.id)) {
|
|
245
|
-
idType = IdType.DATASET_URL
|
|
137
|
+
idType = IdType.DATASET_URL;
|
|
246
138
|
} else {
|
|
247
|
-
idType = IdType.PMR_PATH
|
|
139
|
+
idType = IdType.PMR_PATH;
|
|
248
140
|
}
|
|
249
141
|
|
|
250
142
|
// Retrieve some information about the dataset.
|
|
251
143
|
|
|
252
144
|
if (idType === IdType.DATASET_ID) {
|
|
253
|
-
const xmlhttp = new XMLHttpRequest()
|
|
145
|
+
const xmlhttp = new XMLHttpRequest();
|
|
254
146
|
|
|
255
|
-
xmlhttp.open(
|
|
147
|
+
xmlhttp.open("GET", this.apiLocation + "/sim/dataset/" + this.id);
|
|
256
148
|
xmlhttp.onreadystatechange = () => {
|
|
257
149
|
if (xmlhttp.readyState === 4) {
|
|
258
150
|
if (xmlhttp.status === 200) {
|
|
259
|
-
const datasetInfo = JSON.parse(xmlhttp.responseText)
|
|
151
|
+
const datasetInfo = JSON.parse(xmlhttp.responseText);
|
|
260
152
|
|
|
261
|
-
this.name = datasetInfo.name
|
|
262
|
-
this.uuid = datasetInfo.study !== undefined ? datasetInfo.study.uuid : undefined
|
|
153
|
+
this.name = datasetInfo.name;
|
|
154
|
+
this.uuid = (datasetInfo.study !== undefined) ? datasetInfo.study.uuid : undefined;
|
|
263
155
|
}
|
|
264
156
|
}
|
|
265
|
-
}
|
|
266
|
-
xmlhttp.send()
|
|
157
|
+
};
|
|
158
|
+
xmlhttp.send();
|
|
267
159
|
}
|
|
268
160
|
|
|
269
161
|
return {
|
|
270
|
-
errorMessage:
|
|
162
|
+
errorMessage: "",
|
|
271
163
|
fileManager: undefined,
|
|
272
164
|
hasFinalisedUi: false,
|
|
273
165
|
hasValidSimulationUiInfo: false,
|
|
@@ -289,12 +181,167 @@ export default {
|
|
|
289
181
|
simulationResultsId: {},
|
|
290
182
|
simulationUiInfo: {},
|
|
291
183
|
solver: undefined,
|
|
292
|
-
userMessage:
|
|
184
|
+
userMessage: "",
|
|
293
185
|
ui: null,
|
|
294
186
|
uuid: null,
|
|
295
|
-
|
|
187
|
+
activeSubscriptions: [],
|
|
188
|
+
};
|
|
296
189
|
},
|
|
297
190
|
methods: {
|
|
191
|
+
/**
|
|
192
|
+
* @public
|
|
193
|
+
* Add a data subscription.
|
|
194
|
+
* @arg `subscription `
|
|
195
|
+
*/
|
|
196
|
+
addDataSubscription(subscription) {
|
|
197
|
+
// Check that the subscription is valid.
|
|
198
|
+
|
|
199
|
+
if (!subscription || typeof subscription !== 'object') {
|
|
200
|
+
console.error('addDataSubscription: subscription must be an object.');
|
|
201
|
+
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Check that the subscription has the expected ID.
|
|
206
|
+
|
|
207
|
+
const EXPECTED_ID = 'nz.ac.auckland.simulation-data-request';
|
|
208
|
+
const EXPECTED_MAJOR_VERSION = 0;
|
|
209
|
+
|
|
210
|
+
if (subscription.id !== EXPECTED_ID) {
|
|
211
|
+
console.warn(`addDataSubscription: invalid ID (expected '${EXPECTED_ID}' but got '${subscription.id}').`);
|
|
212
|
+
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Check that the version is valid and compatible with what we expect.
|
|
217
|
+
|
|
218
|
+
if (typeof subscription.version !== 'string') {
|
|
219
|
+
console.warn(`addDataSubscription: missing or non-string version ('${subscription.version}').`);
|
|
220
|
+
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const versionParts = subscription.version.split('.');
|
|
225
|
+
|
|
226
|
+
if (versionParts.length < 1 || !/^[0-9]+$/.test(versionParts[0])) {
|
|
227
|
+
console.warn(`addDataSubscription: malformed version ('${subscription.version}').`);
|
|
228
|
+
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const subscriptionMajorVersion = parseInt(versionParts[0], 10);
|
|
233
|
+
|
|
234
|
+
if (Number.isNaN(subscriptionMajorVersion)) {
|
|
235
|
+
console.warn(`addDataSubscription: could not parse the major version from ('${subscription.version}')`);
|
|
236
|
+
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (subscriptionMajorVersion !== EXPECTED_MAJOR_VERSION) {
|
|
241
|
+
console.warn(`addDataSubscription: version mismatch (expected v${EXPECTED_MAJOR_VERSION}.y.z but got v${subscription.version}).`);
|
|
242
|
+
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Check that the payload contains the required fields.
|
|
247
|
+
|
|
248
|
+
const payload = subscription.payload || {};
|
|
249
|
+
const missing = [];
|
|
250
|
+
|
|
251
|
+
if (payload.windowId == null) {
|
|
252
|
+
missing.push('windowId');
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (payload.ownerId == null) {
|
|
256
|
+
missing.push('ownerId');
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (!payload.component) {
|
|
260
|
+
missing.push('component');
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (!payload.variable) {
|
|
264
|
+
missing.push('variable');
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (missing.length) {
|
|
268
|
+
console.warn(`addDataSubscription: payload missing fields: ${missing.join(', ')}.`);
|
|
269
|
+
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// The subscription is valid, so add it to our list of active subscriptions.
|
|
274
|
+
|
|
275
|
+
this.activeSubscriptions.push(payload);
|
|
276
|
+
|
|
277
|
+
// Build the list of model parameters to be tracked for this subscription.
|
|
278
|
+
|
|
279
|
+
const modelParameters = [];
|
|
280
|
+
|
|
281
|
+
if (subscription.payload?.withVOI) {
|
|
282
|
+
modelParameters.push('VOI');
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
modelParameters.push(`${subscription.payload?.component}/${subscription.payload?.variable}`);
|
|
286
|
+
|
|
287
|
+
this.$refs.opencorRef?.trackSimulationData(modelParameters);
|
|
288
|
+
},
|
|
289
|
+
/**
|
|
290
|
+
* @public
|
|
291
|
+
* Remove a data subscription.
|
|
292
|
+
* @arg `subscriptionId `
|
|
293
|
+
*/
|
|
294
|
+
removeDataSubscription(subscriptionId) {
|
|
295
|
+
this.activeSubscriptions = this.activeSubscriptions.filter((activeSubscription) => {
|
|
296
|
+
return activeSubscription.windowId !== subscriptionId;
|
|
297
|
+
});
|
|
298
|
+
},
|
|
299
|
+
/**
|
|
300
|
+
* @public
|
|
301
|
+
* Let the outside world know that we have received some simulation data from OpenCOR by emitting a `data-notification` event.
|
|
302
|
+
* @arg `event`
|
|
303
|
+
*/
|
|
304
|
+
onSimulationData(event) {
|
|
305
|
+
const simulationData = event.simulationData || {};
|
|
306
|
+
let voi;
|
|
307
|
+
|
|
308
|
+
this.activeSubscriptions.forEach((activeSubscription) => {
|
|
309
|
+
const modelParameter = `${activeSubscription.component}/${activeSubscription.variable}`;
|
|
310
|
+
|
|
311
|
+
if (simulationData[modelParameter] == null) {
|
|
312
|
+
console.warn(`onSimulationData: no data for ${modelParameter}.`);
|
|
313
|
+
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const data = {
|
|
318
|
+
y: Array.from(simulationData[modelParameter]),
|
|
319
|
+
title: `${activeSubscription.component}.${activeSubscription.variable}`,
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
if (activeSubscription.withVOI) {
|
|
323
|
+
if (simulationData.VOI == null) {
|
|
324
|
+
console.warn('onSimulationData: no data for VOI.');
|
|
325
|
+
|
|
326
|
+
return;
|
|
327
|
+
} else {
|
|
328
|
+
voi ??= Array.from(simulationData.VOI);
|
|
329
|
+
|
|
330
|
+
data.x = voi;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
this.$emit('data-notification', {
|
|
335
|
+
id: 'nz.ac.auckland.simulation-data-response',
|
|
336
|
+
version: '0.1.0',
|
|
337
|
+
payload: {
|
|
338
|
+
windowId: activeSubscription.windowId,
|
|
339
|
+
ownerId: activeSubscription.ownerId,
|
|
340
|
+
data,
|
|
341
|
+
},
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
},
|
|
298
345
|
/**
|
|
299
346
|
* @public
|
|
300
347
|
* Generate the metadata associated with the plot which `index` is given.
|
|
@@ -302,13 +349,13 @@ export default {
|
|
|
302
349
|
*/
|
|
303
350
|
plotMetadata(index) {
|
|
304
351
|
return {
|
|
305
|
-
version:
|
|
306
|
-
type:
|
|
352
|
+
version: "1.1.0",
|
|
353
|
+
type: "plot",
|
|
307
354
|
attrs: {
|
|
308
|
-
style:
|
|
355
|
+
style: "timeseries",
|
|
309
356
|
layout: this.layout[index],
|
|
310
357
|
},
|
|
311
|
-
}
|
|
358
|
+
};
|
|
312
359
|
},
|
|
313
360
|
/**
|
|
314
361
|
* @public
|
|
@@ -318,49 +365,49 @@ export default {
|
|
|
318
365
|
buildSimulationUi(simulationUiInfo) {
|
|
319
366
|
// Keep track of the simulation UI information.
|
|
320
367
|
|
|
321
|
-
this.simulationUiInfo = simulationUiInfo
|
|
368
|
+
this.simulationUiInfo = simulationUiInfo;
|
|
322
369
|
|
|
323
370
|
// Make sure that the simulation UI information is valid.
|
|
324
371
|
|
|
325
|
-
this.hasValidSimulationUiInfo = validJson(this.simulationUiInfo)
|
|
372
|
+
this.hasValidSimulationUiInfo = validJson(this.simulationUiInfo);
|
|
326
373
|
|
|
327
374
|
if (!this.hasValidSimulationUiInfo) {
|
|
328
|
-
this.errorMessage =
|
|
375
|
+
this.errorMessage = "the simulation.json file is malformed";
|
|
329
376
|
|
|
330
|
-
return
|
|
377
|
+
return;
|
|
331
378
|
}
|
|
332
379
|
|
|
333
380
|
// Retrieve and keep track of the solver to be used for the simulation.
|
|
334
381
|
|
|
335
382
|
this.simulationUiInfo.simulation.solvers.forEach((solver) => {
|
|
336
|
-
if (solver.if === undefined || evaluateValue(this, solver.if)) {
|
|
337
|
-
this.solver = solver
|
|
383
|
+
if ((solver.if === undefined) || evaluateValue(this, solver.if)) {
|
|
384
|
+
this.solver = solver;
|
|
338
385
|
}
|
|
339
|
-
})
|
|
386
|
+
});
|
|
340
387
|
|
|
341
388
|
if (this.solver === undefined) {
|
|
342
|
-
this.hasValidSimulationUiInfo = false
|
|
343
|
-
this.errorMessage =
|
|
389
|
+
this.hasValidSimulationUiInfo = false;
|
|
390
|
+
this.errorMessage = "no solver name and/or solver version specified";
|
|
344
391
|
|
|
345
|
-
return
|
|
392
|
+
return;
|
|
346
393
|
}
|
|
347
394
|
|
|
348
|
-
this.opencorBasedSimulation = this.solver.name === OPENCOR_SOLVER_NAME
|
|
395
|
+
this.opencorBasedSimulation = this.solver.name === OPENCOR_SOLVER_NAME;
|
|
349
396
|
|
|
350
397
|
// Initialise our UI.
|
|
351
398
|
|
|
352
399
|
this.simulationUiInfo.output.data.forEach((data) => {
|
|
353
|
-
this.simulationResultsId[data.id] = data.name
|
|
354
|
-
})
|
|
400
|
+
this.simulationResultsId[data.id] = data.name;
|
|
401
|
+
});
|
|
355
402
|
|
|
356
|
-
let index = -1
|
|
403
|
+
let index = -1;
|
|
357
404
|
|
|
358
405
|
this.simulationUiInfo.output.plots.forEach((outputPlot) => {
|
|
359
|
-
++index
|
|
406
|
+
++index;
|
|
360
407
|
|
|
361
408
|
this.layout[index] = {
|
|
362
|
-
paper_bgcolor:
|
|
363
|
-
plot_bgcolor:
|
|
409
|
+
paper_bgcolor: "rgba(0, 0, 0, 0)",
|
|
410
|
+
plot_bgcolor: "rgba(0, 0, 0, 0)",
|
|
364
411
|
autosize: true,
|
|
365
412
|
margin: {
|
|
366
413
|
t: 25,
|
|
@@ -374,7 +421,7 @@ export default {
|
|
|
374
421
|
responsive: true,
|
|
375
422
|
scrollZoom: true,
|
|
376
423
|
},
|
|
377
|
-
dragmode:
|
|
424
|
+
dragmode: "pan",
|
|
378
425
|
xaxis: {
|
|
379
426
|
title: {
|
|
380
427
|
text: outputPlot.xAxisTitle,
|
|
@@ -391,8 +438,8 @@ export default {
|
|
|
391
438
|
},
|
|
392
439
|
},
|
|
393
440
|
},
|
|
394
|
-
}
|
|
395
|
-
})
|
|
441
|
+
};
|
|
442
|
+
});
|
|
396
443
|
|
|
397
444
|
// Finalise our UI.
|
|
398
445
|
// Note: we try both here and in the mounted() function since we have no
|
|
@@ -400,8 +447,8 @@ export default {
|
|
|
400
447
|
// information.
|
|
401
448
|
|
|
402
449
|
this.$nextTick(() => {
|
|
403
|
-
finaliseUi(this)
|
|
404
|
-
})
|
|
450
|
+
finaliseUi(this);
|
|
451
|
+
});
|
|
405
452
|
},
|
|
406
453
|
/**
|
|
407
454
|
* @public
|
|
@@ -410,7 +457,7 @@ export default {
|
|
|
410
457
|
* method.
|
|
411
458
|
*/
|
|
412
459
|
runOnOsparc() {
|
|
413
|
-
window.open(`https://osparc.io/study/${this.uuid}`,
|
|
460
|
+
window.open(`https://osparc.io/study/${this.uuid}`, "_blank");
|
|
414
461
|
},
|
|
415
462
|
/**
|
|
416
463
|
* @public
|
|
@@ -418,7 +465,7 @@ export default {
|
|
|
418
465
|
* clicked, calls this method.
|
|
419
466
|
*/
|
|
420
467
|
viewDataset() {
|
|
421
|
-
window.open(`https://sparc.science/datasets/${this.id}?type=dataset`,
|
|
468
|
+
window.open(`https://sparc.science/datasets/${this.id}?type=dataset`, "_blank");
|
|
422
469
|
},
|
|
423
470
|
/**
|
|
424
471
|
* @public
|
|
@@ -426,22 +473,22 @@ export default {
|
|
|
426
473
|
* calls this method.
|
|
427
474
|
*/
|
|
428
475
|
viewWorkspace() {
|
|
429
|
-
const url = PMR_URL + this.id
|
|
476
|
+
const url = PMR_URL + this.id;
|
|
430
477
|
|
|
431
|
-
window.open(url.substring(0, url.lastIndexOf(
|
|
478
|
+
window.open(url.substring(0, url.lastIndexOf("/")), "_blank");
|
|
432
479
|
},
|
|
433
480
|
/**
|
|
434
481
|
* @public
|
|
435
482
|
* Data needed to set a model's parameters.
|
|
436
483
|
*/
|
|
437
484
|
parametersData() {
|
|
438
|
-
const res = {}
|
|
485
|
+
const res = {};
|
|
439
486
|
|
|
440
487
|
this.simulationUiInfo.parameters.forEach((parameter) => {
|
|
441
|
-
res[parameter.name] = evaluateValue(this, parameter.value)
|
|
442
|
-
})
|
|
488
|
+
res[parameter.name] = evaluateValue(this, parameter.value);
|
|
489
|
+
});
|
|
443
490
|
|
|
444
|
-
return res
|
|
491
|
+
return res;
|
|
445
492
|
},
|
|
446
493
|
/**
|
|
447
494
|
* @public
|
|
@@ -450,15 +497,15 @@ export default {
|
|
|
450
497
|
outputData() {
|
|
451
498
|
if (this.output === undefined) {
|
|
452
499
|
if (this.simulationUiInfo.output.data !== undefined) {
|
|
453
|
-
this.output = []
|
|
500
|
+
this.output = [];
|
|
454
501
|
|
|
455
502
|
this.simulationUiInfo.output.data.forEach((output) => {
|
|
456
|
-
this.output.push(output.name)
|
|
457
|
-
})
|
|
503
|
+
this.output.push(output.name);
|
|
504
|
+
});
|
|
458
505
|
}
|
|
459
506
|
}
|
|
460
507
|
|
|
461
|
-
return this.output
|
|
508
|
+
return this.output;
|
|
462
509
|
},
|
|
463
510
|
/**
|
|
464
511
|
* @public
|
|
@@ -466,39 +513,37 @@ export default {
|
|
|
466
513
|
*/
|
|
467
514
|
retrieveRequest() {
|
|
468
515
|
const request = {
|
|
469
|
-
solver: this.solver
|
|
470
|
-
}
|
|
516
|
+
solver: this.solver
|
|
517
|
+
};
|
|
471
518
|
|
|
472
519
|
if (this.opencorBasedSimulation) {
|
|
473
520
|
request.opencor = {
|
|
474
521
|
model_url: this.simulationUiInfo.simulation.opencor.resource,
|
|
475
522
|
json_config: {},
|
|
476
|
-
}
|
|
523
|
+
};
|
|
477
524
|
|
|
478
|
-
if (
|
|
479
|
-
this.simulationUiInfo.simulation.opencor.
|
|
480
|
-
this.simulationUiInfo.simulation.opencor.pointInterval !== undefined
|
|
481
|
-
) {
|
|
525
|
+
if ((this.simulationUiInfo.simulation.opencor.endingPoint !== undefined)
|
|
526
|
+
&& (this.simulationUiInfo.simulation.opencor.pointInterval !== undefined)) {
|
|
482
527
|
request.opencor.json_config.simulation = {
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
}
|
|
528
|
+
"Ending point": this.simulationUiInfo.simulation.opencor.endingPoint,
|
|
529
|
+
"Point interval": this.simulationUiInfo.simulation.opencor.pointInterval,
|
|
530
|
+
};
|
|
486
531
|
}
|
|
487
532
|
|
|
488
|
-
request.opencor.json_config.parameters = this.parametersData()
|
|
533
|
+
request.opencor.json_config.parameters = this.parametersData();
|
|
489
534
|
|
|
490
|
-
const output = this.outputData()
|
|
535
|
+
const output = this.outputData();
|
|
491
536
|
|
|
492
537
|
if (output !== undefined) {
|
|
493
|
-
request.opencor.json_config.output = output
|
|
538
|
+
request.opencor.json_config.output = output;
|
|
494
539
|
}
|
|
495
540
|
} else {
|
|
496
|
-
request.osparc = {}
|
|
541
|
+
request.osparc = {};
|
|
497
542
|
|
|
498
|
-
request.osparc.job_inputs = this.parametersData()
|
|
543
|
+
request.osparc.job_inputs = this.parametersData();
|
|
499
544
|
}
|
|
500
545
|
|
|
501
|
-
return request
|
|
546
|
+
return request;
|
|
502
547
|
},
|
|
503
548
|
/**
|
|
504
549
|
* @public
|
|
@@ -510,50 +555,50 @@ export default {
|
|
|
510
555
|
// Convert, if needed, the results to a JSON format that is compatible
|
|
511
556
|
// with our OpenCOR results.
|
|
512
557
|
|
|
513
|
-
if (typeof results ===
|
|
514
|
-
const SPACES = /[ \t]+/g
|
|
515
|
-
const lines = results.trim().split(
|
|
516
|
-
const iMax = lines[0].trim().split(SPACES).length
|
|
558
|
+
if (typeof (results) === "string") {
|
|
559
|
+
const SPACES = /[ \t]+/g;
|
|
560
|
+
const lines = results.trim().split("\n");
|
|
561
|
+
const iMax = lines[0].trim().split(SPACES).length;
|
|
517
562
|
|
|
518
|
-
results = {}
|
|
563
|
+
results = {};
|
|
519
564
|
|
|
520
565
|
for (let i = 0; i < iMax; ++i) {
|
|
521
|
-
results[i] = []
|
|
566
|
+
results[i] = [];
|
|
522
567
|
}
|
|
523
568
|
|
|
524
|
-
let i = -1
|
|
569
|
+
let i = -1;
|
|
525
570
|
|
|
526
571
|
lines.forEach((line) => {
|
|
527
|
-
++i
|
|
572
|
+
++i;
|
|
528
573
|
|
|
529
|
-
let j = -1
|
|
530
|
-
const values = line.trim().split(SPACES)
|
|
574
|
+
let j = -1;
|
|
575
|
+
const values = line.trim().split(SPACES);
|
|
531
576
|
|
|
532
577
|
values.forEach((value) => {
|
|
533
|
-
results[++j][i] = Number(value)
|
|
534
|
-
})
|
|
535
|
-
})
|
|
578
|
+
results[++j][i] = Number(value);
|
|
579
|
+
});
|
|
580
|
+
});
|
|
536
581
|
}
|
|
537
582
|
|
|
538
583
|
// Get the results ready for plotting.
|
|
539
584
|
|
|
540
|
-
const parser = new math.parser()
|
|
585
|
+
const parser = new math.parser();
|
|
541
586
|
|
|
542
587
|
Object.keys(this.simulationResultsId).forEach((id) => {
|
|
543
|
-
parser.set(id, results[this.simulationResultsId[id]])
|
|
544
|
-
})
|
|
588
|
+
parser.set(id, results[this.simulationResultsId[id]]);
|
|
589
|
+
});
|
|
545
590
|
|
|
546
|
-
let index = -1
|
|
591
|
+
let index = -1;
|
|
547
592
|
|
|
548
593
|
this.simulationUiInfo.output.plots.forEach((outputPlot) => {
|
|
549
594
|
this.simulationResults[++index] = [
|
|
550
595
|
{
|
|
551
596
|
x: parser.evaluate(outputPlot.xValue),
|
|
552
597
|
y: parser.evaluate(outputPlot.yValue),
|
|
553
|
-
type:
|
|
598
|
+
type: "scatter",
|
|
554
599
|
},
|
|
555
|
-
]
|
|
556
|
-
})
|
|
600
|
+
];
|
|
601
|
+
});
|
|
557
602
|
},
|
|
558
603
|
/**
|
|
559
604
|
* @public
|
|
@@ -561,15 +606,9 @@ export default {
|
|
|
561
606
|
* @arg `xmlhttp`
|
|
562
607
|
*/
|
|
563
608
|
showHttpIssue(xmlhttp) {
|
|
564
|
-
this.isSimulationValid = false
|
|
565
|
-
this.showUserMessage = false
|
|
566
|
-
this.errorMessage =
|
|
567
|
-
xmlhttp.statusText.toLowerCase() +
|
|
568
|
-
" (<a href='https://httpstatuses.com/" +
|
|
569
|
-
xmlhttp.status +
|
|
570
|
-
"/' target='_blank'>" +
|
|
571
|
-
xmlhttp.status +
|
|
572
|
-
'</a>)'
|
|
609
|
+
this.isSimulationValid = false;
|
|
610
|
+
this.showUserMessage = false;
|
|
611
|
+
this.errorMessage = xmlhttp.statusText.toLowerCase() + " (<a href='https://httpstatuses.com/" + xmlhttp.status + "/' target='_blank'>" + xmlhttp.status + "</a>)";
|
|
573
612
|
},
|
|
574
613
|
/**
|
|
575
614
|
* @public
|
|
@@ -581,44 +620,44 @@ export default {
|
|
|
581
620
|
checkSimulation(data) {
|
|
582
621
|
// Check the simulation.
|
|
583
622
|
|
|
584
|
-
const xmlhttp = new XMLHttpRequest()
|
|
623
|
+
const xmlhttp = new XMLHttpRequest();
|
|
585
624
|
|
|
586
|
-
xmlhttp.open(
|
|
587
|
-
xmlhttp.setRequestHeader(
|
|
625
|
+
xmlhttp.open("POST", this.apiLocation + "/check_simulation");
|
|
626
|
+
xmlhttp.setRequestHeader("Content-type", "application/json");
|
|
588
627
|
xmlhttp.onreadystatechange = () => {
|
|
589
628
|
if (xmlhttp.readyState === 4) {
|
|
590
629
|
if (xmlhttp.status === 200) {
|
|
591
|
-
let response = JSON.parse(xmlhttp.responseText)
|
|
630
|
+
let response = JSON.parse(xmlhttp.responseText);
|
|
592
631
|
|
|
593
|
-
this.isSimulationValid = response.status ===
|
|
632
|
+
this.isSimulationValid = response.status === "ok";
|
|
594
633
|
|
|
595
634
|
if (this.isSimulationValid) {
|
|
596
635
|
if (response.results !== undefined) {
|
|
597
636
|
// The simulation is finished, so process its results.
|
|
598
637
|
|
|
599
|
-
this.showUserMessage = false
|
|
638
|
+
this.showUserMessage = false;
|
|
600
639
|
|
|
601
|
-
this.processSimulationResults(response.results)
|
|
640
|
+
this.processSimulationResults(response.results);
|
|
602
641
|
} else {
|
|
603
642
|
// The simulation is not yet finished, so check again in a
|
|
604
643
|
// second.
|
|
605
644
|
|
|
606
|
-
let that = this
|
|
645
|
+
let that = this;
|
|
607
646
|
|
|
608
647
|
setTimeout(function () {
|
|
609
|
-
that.checkSimulation(data)
|
|
610
|
-
}, 1000)
|
|
648
|
+
that.checkSimulation(data);
|
|
649
|
+
}, 1000);
|
|
611
650
|
}
|
|
612
651
|
} else {
|
|
613
|
-
this.showUserMessage = false
|
|
614
|
-
this.errorMessage = response.description
|
|
652
|
+
this.showUserMessage = false;
|
|
653
|
+
this.errorMessage = response.description;
|
|
615
654
|
}
|
|
616
655
|
} else {
|
|
617
|
-
this.showHttpIssue(xmlhttp)
|
|
656
|
+
this.showHttpIssue(xmlhttp);
|
|
618
657
|
}
|
|
619
658
|
}
|
|
620
|
-
}
|
|
621
|
-
xmlhttp.send(JSON.stringify(data))
|
|
659
|
+
};
|
|
660
|
+
xmlhttp.send(JSON.stringify(data));
|
|
622
661
|
},
|
|
623
662
|
/**
|
|
624
663
|
* @public
|
|
@@ -629,73 +668,72 @@ export default {
|
|
|
629
668
|
// Start the simulation (after resetting our previous simulation data, in
|
|
630
669
|
// case there were sonme).
|
|
631
670
|
|
|
632
|
-
this.userMessage =
|
|
633
|
-
this.showUserMessage = true
|
|
671
|
+
this.userMessage = "Loading simulation results...";
|
|
672
|
+
this.showUserMessage = true;
|
|
634
673
|
|
|
635
674
|
this.$nextTick(() => {
|
|
636
|
-
this.simulationResults = {}
|
|
675
|
+
this.simulationResults = {};
|
|
637
676
|
|
|
638
|
-
const xmlhttp = new XMLHttpRequest()
|
|
677
|
+
const xmlhttp = new XMLHttpRequest();
|
|
639
678
|
|
|
640
|
-
xmlhttp.open(
|
|
641
|
-
xmlhttp.setRequestHeader(
|
|
679
|
+
xmlhttp.open("POST", this.apiLocation + "/start_simulation");
|
|
680
|
+
xmlhttp.setRequestHeader("Content-type", "application/json");
|
|
642
681
|
xmlhttp.onreadystatechange = () => {
|
|
643
682
|
if (xmlhttp.readyState === 4) {
|
|
644
683
|
if (xmlhttp.status === 200) {
|
|
645
|
-
let response = JSON.parse(xmlhttp.responseText)
|
|
684
|
+
let response = JSON.parse(xmlhttp.responseText);
|
|
646
685
|
|
|
647
|
-
this.isSimulationValid = response.status ===
|
|
686
|
+
this.isSimulationValid = response.status === "ok";
|
|
648
687
|
|
|
649
688
|
if (this.isSimulationValid) {
|
|
650
|
-
this.checkSimulation(response.data)
|
|
689
|
+
this.checkSimulation(response.data);
|
|
651
690
|
} else {
|
|
652
|
-
this.showUserMessage = false
|
|
653
|
-
this.errorMessage = response.description
|
|
691
|
+
this.showUserMessage = false;
|
|
692
|
+
this.errorMessage = response.description;
|
|
654
693
|
}
|
|
655
694
|
} else {
|
|
656
|
-
this.showHttpIssue(xmlhttp)
|
|
695
|
+
this.showHttpIssue(xmlhttp);
|
|
657
696
|
}
|
|
658
697
|
}
|
|
659
|
-
}
|
|
660
|
-
xmlhttp.send(JSON.stringify(this.retrieveRequest()))
|
|
661
|
-
})
|
|
698
|
+
};
|
|
699
|
+
xmlhttp.send(JSON.stringify(this.retrieveRequest()));
|
|
700
|
+
});
|
|
662
701
|
},
|
|
663
702
|
},
|
|
664
703
|
created: function () {
|
|
665
704
|
// Try to retrieve the UI information.
|
|
666
705
|
|
|
667
706
|
if (this.idType === IdType.DATASET_ID) {
|
|
668
|
-
this.userMessage =
|
|
669
|
-
this.showUserMessage = true
|
|
707
|
+
this.userMessage = "Retrieving UI information...";
|
|
708
|
+
this.showUserMessage = true;
|
|
670
709
|
|
|
671
710
|
// Retrieve and build the simulation UI.
|
|
672
711
|
|
|
673
712
|
this.$nextTick(() => {
|
|
674
|
-
const xmlhttp = new XMLHttpRequest()
|
|
713
|
+
const xmlhttp = new XMLHttpRequest();
|
|
675
714
|
|
|
676
|
-
xmlhttp.open(
|
|
715
|
+
xmlhttp.open("GET", this.apiLocation + "/simulation_ui_file/" + this.id);
|
|
677
716
|
xmlhttp.onreadystatechange = () => {
|
|
678
717
|
if (xmlhttp.readyState === 4) {
|
|
679
|
-
this.showUserMessage = false
|
|
718
|
+
this.showUserMessage = false;
|
|
680
719
|
|
|
681
720
|
if (xmlhttp.status === 200) {
|
|
682
721
|
this.$nextTick(() => {
|
|
683
|
-
this.buildSimulationUi(JSON.parse(xmlhttp.responseText))
|
|
684
|
-
})
|
|
722
|
+
this.buildSimulationUi(JSON.parse(xmlhttp.responseText));
|
|
723
|
+
});
|
|
685
724
|
} else {
|
|
686
|
-
this.errorMessage =
|
|
725
|
+
this.errorMessage = "the simulation dataset could not be retrieved";
|
|
687
726
|
}
|
|
688
727
|
}
|
|
689
|
-
}
|
|
690
|
-
xmlhttp.send()
|
|
691
|
-
})
|
|
728
|
+
};
|
|
729
|
+
xmlhttp.send();
|
|
730
|
+
});
|
|
692
731
|
} else if (this.idType === IdType.DATASET_URL) {
|
|
693
|
-
this.opencorOmexFile = this.id
|
|
732
|
+
this.opencorOmexFile = this.id;
|
|
694
733
|
} else if (this.idType === IdType.PMR_PATH) {
|
|
695
|
-
this.opencorOmexFile = PMR_URL + this.id
|
|
696
|
-
} else {
|
|
697
|
-
|
|
698
|
-
this.opencorOmexFile = this.id
|
|
734
|
+
this.opencorOmexFile = PMR_URL + this.id;
|
|
735
|
+
} else { // IdType.RAW_COMBINE_ARCHIVE
|
|
736
|
+
this.opencorOmexFile = this.id;
|
|
699
737
|
}
|
|
700
738
|
},
|
|
701
739
|
mounted: function () {
|
|
@@ -704,20 +742,20 @@ export default {
|
|
|
704
742
|
// idea how long it's going to take to retrieve the simulation UI
|
|
705
743
|
// information.
|
|
706
744
|
|
|
707
|
-
this.isMounted = true
|
|
745
|
+
this.isMounted = true;
|
|
708
746
|
|
|
709
|
-
finaliseUi(this)
|
|
747
|
+
finaliseUi(this);
|
|
710
748
|
},
|
|
711
|
-
}
|
|
749
|
+
};
|
|
712
750
|
</script>
|
|
713
751
|
|
|
714
752
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
|
715
753
|
<style scoped lang="scss">
|
|
716
754
|
.simulation-vuer {
|
|
717
|
-
--el-color-primary: #
|
|
718
|
-
--el-color-primary-light-7: #
|
|
719
|
-
--el-color-primary-light-8: #
|
|
720
|
-
--el-color-primary-light-9: #
|
|
755
|
+
--el-color-primary: #8300BF;
|
|
756
|
+
--el-color-primary-light-7: #DAB3EC;
|
|
757
|
+
--el-color-primary-light-8: #E6CCF2;
|
|
758
|
+
--el-color-primary-light-9: #F3E6F9;
|
|
721
759
|
}
|
|
722
760
|
|
|
723
761
|
:deep(.el-button:hover) {
|
|
@@ -731,32 +769,29 @@ export default {
|
|
|
731
769
|
|
|
732
770
|
:deep(.el-loading-spinner) {
|
|
733
771
|
.path {
|
|
734
|
-
stroke: #
|
|
772
|
+
stroke: #8300BF;
|
|
735
773
|
}
|
|
736
774
|
|
|
737
775
|
i,
|
|
738
776
|
.el-loading-text {
|
|
739
|
-
color: #
|
|
777
|
+
color: #8300BF;
|
|
740
778
|
}
|
|
741
779
|
}
|
|
742
780
|
|
|
743
|
-
:deep(.p-floatlabel:has(input:focus)) label,
|
|
744
|
-
:
|
|
745
|
-
:deep(.p-floatlabel:has(textarea:focus)) label,
|
|
746
|
-
:deep(.p-floatlabel:has(.p-inputwrapper-focus)) label {
|
|
747
|
-
color: #8300bf;
|
|
781
|
+
:deep(.p-floatlabel:has(input:focus)) label, :deep(.p-floatlabel:has(input:-webkit-autofill)) label, :deep(.p-floatlabel:has(textarea:focus)) label, :deep(.p-floatlabel:has(.p-inputwrapper-focus)) label {
|
|
782
|
+
color: #8300BF;
|
|
748
783
|
}
|
|
749
784
|
|
|
750
785
|
:deep(.p-inputtext:enabled:focus) {
|
|
751
|
-
|
|
786
|
+
border-color: #8300BF;
|
|
752
787
|
}
|
|
753
788
|
|
|
754
789
|
:deep(.p-select:not(.p-disabled).p-focus) {
|
|
755
|
-
|
|
790
|
+
border-color: #8300BF;
|
|
756
791
|
}
|
|
757
792
|
|
|
758
793
|
:deep(.p-slider-range) {
|
|
759
|
-
background-color: #
|
|
794
|
+
background-color: #8300BF;
|
|
760
795
|
}
|
|
761
796
|
|
|
762
797
|
div.input {
|
|
@@ -958,23 +993,26 @@ span.error {
|
|
|
958
993
|
<style>
|
|
959
994
|
/* Note: not sure why, but the following rules need to be global!? */
|
|
960
995
|
|
|
996
|
+
.p-progressbar-value {
|
|
997
|
+
background-color: #8300BF !important;
|
|
998
|
+
}
|
|
999
|
+
|
|
961
1000
|
.p-select-option:not(.p-select-option-selected):not(.p-disabled).p-focus {
|
|
962
|
-
|
|
1001
|
+
background: #F5F7FA !important;
|
|
963
1002
|
}
|
|
964
1003
|
|
|
965
1004
|
.p-select-option.p-select-option-selected.p-focus {
|
|
966
|
-
|
|
967
|
-
|
|
1005
|
+
background: #F5F7FA !important;
|
|
1006
|
+
color: #8300BF !important;
|
|
968
1007
|
}
|
|
969
1008
|
|
|
970
1009
|
.p-select-option.p-select-option-selected {
|
|
971
|
-
|
|
972
|
-
|
|
1010
|
+
background: white !important;
|
|
1011
|
+
color: #8300BF !important;
|
|
973
1012
|
}
|
|
974
1013
|
|
|
975
1014
|
.p-select-option-label {
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
font-size: 0.875rem;
|
|
1015
|
+
font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
|
1016
|
+
font-size: 0.875rem;
|
|
979
1017
|
}
|
|
980
1018
|
</style>
|