@opencor/opencor 0.20250814.4 → 0.20250822.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{index-tP7x8zIn.js → index-Bo9Lkhfn.js} +44037 -45095
- package/dist/opencor.css +1 -1
- package/dist/opencor.es.js +1 -1
- package/dist/opencor.umd.js +4510 -4765
- package/dist/{quill-DZsCWNRW.js → quill-BuRGxrCd.js} +1 -1
- package/package.json +13 -13
- package/src/App.vue +4 -22
- package/src/assets/base.css +4 -1
- package/src/common/vueCommon.ts +1 -6
- package/src/components/{LoadOpencorComponent.vue → BlockingMessageComponent.vue} +13 -12
- package/src/components/ContentsComponent.vue +27 -12
- package/src/components/DragNDropComponent.vue +9 -3
- package/src/components/MainMenu.vue +5 -0
- package/src/components/OpenCOR.vue +100 -59
- package/src/components/dialogs/BaseDialog.vue +48 -1
- package/src/components/dialogs/UpdateDownloadProgressDialog.vue +0 -6
- package/src/components/propertyEditors/PropertyEditor.vue +15 -16
- package/src/components/views/IssuesView.vue +19 -6
- package/src/components/views/SimulationExperimentUiView.vue +23 -21
- package/src/components/views/SimulationExperimentView.vue +37 -33
- package/src/components/widgets/GraphPanelWidget.vue +13 -10
- package/src/components/SpinningWheelComponent.vue +0 -15
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as ce, g as gl } from "./index-
|
|
1
|
+
import { c as ce, g as gl } from "./index-Bo9Lkhfn.js";
|
|
2
2
|
var pl = typeof global == "object" && global && global.Object === Object && global, yo = typeof self == "object" && self && self.Object === Object && self, Zt = pl || yo || Function("return this")(), de = Zt.Symbol, ml = Object.prototype, vo = ml.hasOwnProperty, Eo = ml.toString, yr = de ? de.toStringTag : void 0;
|
|
3
3
|
function Ao(n) {
|
|
4
4
|
var t = vo.call(n, yr), e = n[yr];
|
package/package.json
CHANGED
|
@@ -42,40 +42,40 @@
|
|
|
42
42
|
},
|
|
43
43
|
"./style.css": "./dist/opencor.css"
|
|
44
44
|
},
|
|
45
|
-
"version": "0.
|
|
45
|
+
"version": "0.20250822.0",
|
|
46
46
|
"peerDependencies": {
|
|
47
|
-
"vue": "^3.
|
|
47
|
+
"vue": "^3.4.21"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"@primeuix/themes": "^1.2.3",
|
|
51
|
-
"@primevue/auto-import-resolver": "
|
|
52
|
-
"@tailwindcss/postcss": "^4.1.
|
|
53
|
-
"@tailwindcss/vite": "^4.1.
|
|
54
|
-
"@vueuse/core": "
|
|
51
|
+
"@primevue/auto-import-resolver": "4.2.5",
|
|
52
|
+
"@tailwindcss/postcss": "^4.1.12",
|
|
53
|
+
"@tailwindcss/vite": "^4.1.12",
|
|
54
|
+
"@vueuse/core": "12.8.2",
|
|
55
55
|
"js-cookie": "^3.0.5",
|
|
56
56
|
"jsonschema": "^1.5.0",
|
|
57
57
|
"mathjs": "^14.6.0",
|
|
58
|
-
"plotly.js-gl2d-dist-min": "
|
|
58
|
+
"plotly.js-gl2d-dist-min": "3.1.0",
|
|
59
59
|
"primeicons": "^7.0.0",
|
|
60
|
-
"primevue": "
|
|
60
|
+
"primevue": "4.2.5",
|
|
61
61
|
"quill": "^2.0.3",
|
|
62
|
-
"tailwindcss": "^4.1.
|
|
62
|
+
"tailwindcss": "^4.1.12",
|
|
63
63
|
"tailwindcss-primeui": "^0.6.1",
|
|
64
64
|
"ua-parser-js": "^2.0.4"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
67
|
"@types/js-cookie": "^3.0.6",
|
|
68
|
-
"@types/node": "^24.
|
|
69
|
-
"@types/plotly.js": "
|
|
68
|
+
"@types/node": "^24.3.0",
|
|
69
|
+
"@types/plotly.js": "3.0.3",
|
|
70
70
|
"@vitejs/plugin-vue": "^6.0.1",
|
|
71
71
|
"@vue/eslint-config-prettier": "^10.2.0",
|
|
72
72
|
"@vue/eslint-config-typescript": "^14.6.0",
|
|
73
|
-
"@vue/tsconfig": "^0.
|
|
73
|
+
"@vue/tsconfig": "^0.8.1",
|
|
74
74
|
"autoprefixer": "^10.4.21",
|
|
75
75
|
"eslint": "^9.33.0",
|
|
76
76
|
"prettier": "^3.6.2",
|
|
77
77
|
"unplugin-vue-components": "^29.0.0",
|
|
78
|
-
"vite": "^7.1.
|
|
78
|
+
"vite": "^7.1.3"
|
|
79
79
|
},
|
|
80
80
|
"scripts": {
|
|
81
81
|
"build": "vite build",
|
package/src/App.vue
CHANGED
|
@@ -1,27 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div id="app">
|
|
3
3
|
<OpenCOR />
|
|
4
|
-
<!-- <OpenCOR omex="https://raw.githubusercontent.com/opencor/webapp/refs/heads/main/tests/models/lorenz.
|
|
5
|
-
<!-- <OpenCOR omex="https://raw.githubusercontent.com/opencor/webapp/refs/heads/main/tests/models/
|
|
6
|
-
<!-- <OpenCOR omex="https://
|
|
4
|
+
<!-- <OpenCOR omex="https://raw.githubusercontent.com/opencor/webapp/refs/heads/main/tests/models/lorenz.cellml" /> -->
|
|
5
|
+
<!-- <OpenCOR omex="https://raw.githubusercontent.com/opencor/webapp/refs/heads/main/tests/models/lorenz.omex" /> -->
|
|
6
|
+
<!-- <OpenCOR omex="https://raw.githubusercontent.com/opencor/webapp/refs/heads/main/tests/models/ui/lorenz.omex" /> -->
|
|
7
|
+
<!-- <OpenCOR omex="https://models.physiomeproject.org/workspace/b7c/rawfile/e0ae8d2d56aaaa091e23e1ee7e84cacbda1dfb6b/lorenz.omex" /> -->
|
|
7
8
|
</div>
|
|
8
9
|
</template>
|
|
9
|
-
|
|
10
|
-
<script setup lang="ts">
|
|
11
|
-
import OpenCOR from './components/OpenCOR.vue'
|
|
12
|
-
|
|
13
|
-
function updateViewportHeight() {
|
|
14
|
-
document.documentElement.style.setProperty('--vh', `${String(window.innerHeight * 0.01)}px`)
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
window.addEventListener('resize', updateViewportHeight)
|
|
18
|
-
|
|
19
|
-
updateViewportHeight()
|
|
20
|
-
</script>
|
|
21
|
-
|
|
22
|
-
<style scoped>
|
|
23
|
-
#app {
|
|
24
|
-
width: 100%;
|
|
25
|
-
height: calc(100 * var(--vh, 1vh));
|
|
26
|
-
}
|
|
27
|
-
</style>
|
package/src/assets/base.css
CHANGED
package/src/common/vueCommon.ts
CHANGED
|
@@ -51,12 +51,7 @@ export function trackElementHeight(id: string): void {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
const cssVariableName =
|
|
54
|
-
'--' +
|
|
55
|
-
id
|
|
56
|
-
.split('_')[0]
|
|
57
|
-
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
|
58
|
-
.toLowerCase() +
|
|
59
|
-
'-height'
|
|
54
|
+
'--' + (id.split('_')[0] ?? '').replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase() + '-height'
|
|
60
55
|
const oldElementHeight = window.getComputedStyle(document.documentElement).getPropertyValue(cssVariableName)
|
|
61
56
|
|
|
62
57
|
if (oldElementHeight === '' || (elementHeight !== '0px' && oldElementHeight !== elementHeight)) {
|
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
</Message>
|
|
8
|
-
</div>
|
|
2
|
+
<Message class="message" severity="secondary">
|
|
3
|
+
<i class="message-icon pi pi-spin pi-cog" />
|
|
4
|
+
<br />
|
|
5
|
+
<span class="message-text">{{ message }}</span>
|
|
6
|
+
</Message>
|
|
9
7
|
</template>
|
|
10
8
|
|
|
11
|
-
<
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
9
|
+
<script setup lang="ts">
|
|
10
|
+
defineProps<{
|
|
11
|
+
message: string
|
|
12
|
+
}>()
|
|
13
|
+
</script>
|
|
15
14
|
|
|
15
|
+
<style scoped>
|
|
16
16
|
.message {
|
|
17
|
-
position:
|
|
17
|
+
position: absolute;
|
|
18
18
|
top: 50%;
|
|
19
19
|
left: 50%;
|
|
20
20
|
transform: translate(-50%, -50%);
|
|
21
21
|
padding: 1.5rem 1rem 0.75rem;
|
|
22
|
+
z-index: 99999;
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
.message-icon {
|
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div v-if="simulationOnly" class="h-full">
|
|
3
3
|
<div v-for="(fileTab, index) in fileTabs" :key="`tabPanel_${fileTab.file.path()}`" :value="fileTab.file.path()">
|
|
4
|
-
<IssuesView
|
|
4
|
+
<IssuesView
|
|
5
|
+
v-if="fileTab.file.issues().length !== 0"
|
|
6
|
+
:issues="fileTab.file.issues()"
|
|
7
|
+
:simulationOnly="simulationOnly"
|
|
8
|
+
/>
|
|
5
9
|
<SimulationExperimentView
|
|
6
10
|
v-else-if="fileTab.uiJson === undefined"
|
|
7
|
-
:file="fileTabs[index]
|
|
11
|
+
:file="fileTabs[index]?.file"
|
|
8
12
|
:isActiveFile="fileTab.file.path() === activeFile"
|
|
9
13
|
:simulationOnly="true"
|
|
10
14
|
/>
|
|
11
15
|
<SimulationExperimentUiView
|
|
12
16
|
v-else
|
|
13
|
-
:file="fileTabs[index]
|
|
17
|
+
:file="fileTabs[index]?.file"
|
|
14
18
|
:simulationOnly="true"
|
|
15
|
-
:uiJson="fileTabs[index]
|
|
19
|
+
:uiJson="fileTabs[index]?.uiJson"
|
|
16
20
|
/>
|
|
17
21
|
</div>
|
|
18
22
|
</div>
|
|
19
23
|
<div v-else class="h-full">
|
|
20
|
-
<BackgroundComponent v-show="fileTabs.length === 0" />
|
|
21
24
|
<Tabs
|
|
22
25
|
v-show="fileTabs.length !== 0"
|
|
23
26
|
id="fileTabs"
|
|
@@ -54,10 +57,11 @@
|
|
|
54
57
|
<IssuesView v-if="fileTab.file.issues().length !== 0" :issues="fileTab.file.issues()" />
|
|
55
58
|
<SimulationExperimentView
|
|
56
59
|
v-else-if="fileTab.uiJson === undefined"
|
|
57
|
-
:
|
|
60
|
+
:uiEnabled="uiEnabled"
|
|
61
|
+
:file="fileTabs[index]?.file"
|
|
58
62
|
:isActiveFile="fileTab.file.path() === activeFile"
|
|
59
63
|
/>
|
|
60
|
-
<SimulationExperimentUiView v-else :file="fileTabs[index]
|
|
64
|
+
<SimulationExperimentUiView v-else :file="fileTabs[index]?.file" :uiJson="fileTabs[index]?.uiJson" />
|
|
61
65
|
</TabPanel>
|
|
62
66
|
</TabPanels>
|
|
63
67
|
</Tabs>
|
|
@@ -79,7 +83,8 @@ export interface IFileTab {
|
|
|
79
83
|
uiJson?: locApi.IUiJson
|
|
80
84
|
}
|
|
81
85
|
|
|
82
|
-
defineProps<{
|
|
86
|
+
const props = defineProps<{
|
|
87
|
+
uiEnabled: boolean
|
|
83
88
|
simulationOnly?: boolean
|
|
84
89
|
}>()
|
|
85
90
|
defineExpose({ openFile, closeCurrentFile, closeAllFiles, hasFile, hasFiles, selectFile })
|
|
@@ -146,15 +151,21 @@ function selectFile(filePath: string): void {
|
|
|
146
151
|
function selectNextFile(): void {
|
|
147
152
|
const activeFileIndex = fileTabs.value.findIndex((fileTab) => fileTab.file.path() === activeFile.value)
|
|
148
153
|
const nextFileIndex = (activeFileIndex + 1) % fileTabs.value.length
|
|
154
|
+
const nextFileTab = fileTabs.value[nextFileIndex]
|
|
149
155
|
|
|
150
|
-
|
|
156
|
+
if (nextFileTab !== undefined) {
|
|
157
|
+
selectFile(nextFileTab.file.path())
|
|
158
|
+
}
|
|
151
159
|
}
|
|
152
160
|
|
|
153
161
|
function selectPreviousFile(): void {
|
|
154
162
|
const activeFileIndex = fileTabs.value.findIndex((fileTab) => fileTab.file.path() === activeFile.value)
|
|
155
163
|
const nextFileIndex = (activeFileIndex - 1 + fileTabs.value.length) % fileTabs.value.length
|
|
164
|
+
const nextFileTab = fileTabs.value[nextFileIndex]
|
|
156
165
|
|
|
157
|
-
|
|
166
|
+
if (nextFileTab !== undefined) {
|
|
167
|
+
selectFile(nextFileTab.file.path())
|
|
168
|
+
}
|
|
158
169
|
}
|
|
159
170
|
|
|
160
171
|
function closeFile(filePath: string): void {
|
|
@@ -165,7 +176,11 @@ function closeFile(filePath: string): void {
|
|
|
165
176
|
fileTabs.value.splice(activeFileIndex, 1)
|
|
166
177
|
|
|
167
178
|
if (activeFile.value === filePath && fileTabs.value.length > 0) {
|
|
168
|
-
|
|
179
|
+
const nextFileTab = fileTabs.value[Math.min(activeFileIndex, fileTabs.value.length - 1)]
|
|
180
|
+
|
|
181
|
+
if (nextFileTab !== undefined) {
|
|
182
|
+
selectFile(nextFileTab.file.path())
|
|
183
|
+
}
|
|
169
184
|
}
|
|
170
185
|
|
|
171
186
|
electronApi?.fileClosed(filePath)
|
|
@@ -189,7 +204,7 @@ vueCommon.trackElementHeight('fileTablist')
|
|
|
189
204
|
|
|
190
205
|
if (!common.isMobile()) {
|
|
191
206
|
vueusecore.onKeyStroke((event: KeyboardEvent) => {
|
|
192
|
-
if (fileTabs.value.length === 0) {
|
|
207
|
+
if (!props.uiEnabled || fileTabs.value.length === 0) {
|
|
193
208
|
return
|
|
194
209
|
}
|
|
195
210
|
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="drop-area
|
|
3
|
-
<div class="message">
|
|
2
|
+
<div class="drop-area">
|
|
3
|
+
<div class="message">
|
|
4
|
+
CellML files, SED-ML files, and COMBINE archives<br />
|
|
5
|
+
can be dropped here.
|
|
6
|
+
</div>
|
|
4
7
|
</div>
|
|
5
8
|
</template>
|
|
6
9
|
|
|
7
10
|
<style scoped>
|
|
8
11
|
.drop-area {
|
|
12
|
+
position: absolute;
|
|
9
13
|
width: 100%;
|
|
10
14
|
height: 100%;
|
|
11
15
|
border: 0.375rem dashed;
|
|
@@ -15,15 +19,17 @@
|
|
|
15
19
|
|
|
16
20
|
.message {
|
|
17
21
|
font-size: 1.5rem;
|
|
22
|
+
line-height: 1.25;
|
|
18
23
|
text-align: center;
|
|
19
24
|
border-radius: 1rem;
|
|
20
25
|
padding: 0.5rem 1rem;
|
|
21
26
|
background-color: var(--p-primary-color);
|
|
22
27
|
color: var(--p-primary-contrast-color);
|
|
23
28
|
box-shadow: 0 0 0.75rem 0.375rem var(--p-content-border-color);
|
|
24
|
-
position:
|
|
29
|
+
position: absolute;
|
|
25
30
|
top: 50%;
|
|
26
31
|
left: 50%;
|
|
27
32
|
transform: translate(-50%, -50%);
|
|
33
|
+
white-space: nowrap;
|
|
28
34
|
}
|
|
29
35
|
</style>
|
|
@@ -31,6 +31,7 @@ import * as vue from 'vue'
|
|
|
31
31
|
import * as common from '../common/common'
|
|
32
32
|
|
|
33
33
|
const props = defineProps<{
|
|
34
|
+
uiEnabled: boolean
|
|
34
35
|
hasFiles: boolean
|
|
35
36
|
}>()
|
|
36
37
|
|
|
@@ -161,6 +162,10 @@ vue.onMounted(() => {
|
|
|
161
162
|
|
|
162
163
|
if (!common.isMobile()) {
|
|
163
164
|
vueusecore.onKeyStroke((event: KeyboardEvent) => {
|
|
165
|
+
if (!props.uiEnabled) {
|
|
166
|
+
return
|
|
167
|
+
}
|
|
168
|
+
|
|
164
169
|
if (common.isCtrlOrCmd(event) && !event.shiftKey && event.code === 'KeyO') {
|
|
165
170
|
event.preventDefault()
|
|
166
171
|
|
|
@@ -1,9 +1,23 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<
|
|
4
|
-
<
|
|
2
|
+
<BlockUI id="blockUi" :blocked="!uiEnabled" class="h-full">
|
|
3
|
+
<Toast id="toast" :pt:root:style="{ position: 'absolute' }" />
|
|
4
|
+
<BackgroundComponent v-show="loadingOpencorMessageVisible || loadingModelMessageVisible || omex === undefined" />
|
|
5
|
+
<BlockingMessageComponent message="Loading OpenCOR..." v-show="loadingOpencorMessageVisible" />
|
|
6
|
+
<BlockingMessageComponent message="Loading model..." v-show="loadingModelMessageVisible" />
|
|
7
|
+
<IssuesView v-if="issues.length !== 0" class="h-full" :issues="issues" :simulationOnly="omex !== undefined" />
|
|
8
|
+
<div
|
|
9
|
+
v-else
|
|
10
|
+
@dragenter="onDragEnter"
|
|
11
|
+
class="h-full"
|
|
12
|
+
@dragover.prevent
|
|
13
|
+
@drop.prevent="onDrop"
|
|
14
|
+
@dragleave="onDragLeave"
|
|
15
|
+
>
|
|
16
|
+
<input ref="files" type="file" multiple style="display: none" @change="onChange" />
|
|
17
|
+
<DragNDropComponent v-show="dragAndDropCounter > 0" />
|
|
5
18
|
<div v-show="!electronApi && omex === undefined">
|
|
6
19
|
<MainMenu
|
|
20
|
+
:uiEnabled="compUiEnabled"
|
|
7
21
|
:hasFiles="hasFiles"
|
|
8
22
|
@about="onAbout"
|
|
9
23
|
@open="($refs.files as HTMLInputElement).click()"
|
|
@@ -15,35 +29,31 @@
|
|
|
15
29
|
@settings="onSettings"
|
|
16
30
|
/>
|
|
17
31
|
</div>
|
|
18
|
-
<
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
32
|
+
<ContentsComponent ref="contents" :uiEnabled="compUiEnabled" :simulationOnly="omex !== undefined" />
|
|
33
|
+
<OpenRemoteDialog
|
|
34
|
+
v-model:visible="openRemoteVisible"
|
|
35
|
+
@openRemote="onOpenRemote"
|
|
36
|
+
@close="openRemoteVisible = false"
|
|
37
|
+
/>
|
|
38
|
+
<SettingsDialog v-model:visible="settingsVisible" @close="settingsVisible = false" />
|
|
39
|
+
<ResetAllDialog v-model:visible="resetAllVisible" @resetAll="onResetAll" @close="resetAllVisible = false" />
|
|
40
|
+
<AboutDialog v-model:visible="aboutVisible" @close="aboutVisible = false" />
|
|
25
41
|
</div>
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
<UpdateNotAvailableDialog v-model:visible="updateNotAvailableVisible" @close="updateNotAvailableVisible = false" />
|
|
42
|
-
<OpenRemoteDialog v-model:visible="openRemoteVisible" @openRemote="onOpenRemote" @close="openRemoteVisible = false" />
|
|
43
|
-
<ResetAllDialog v-model:visible="resetAllVisible" @resetAll="onResetAll" @close="resetAllVisible = false" />
|
|
44
|
-
<AboutDialog v-model:visible="aboutVisible" @close="aboutVisible = false" />
|
|
45
|
-
<SettingsDialog v-model:visible="settingsVisible" @close="settingsVisible = false" />
|
|
46
|
-
<Toast />
|
|
42
|
+
<UpdateErrorDialog
|
|
43
|
+
v-model:visible="updateErrorVisible"
|
|
44
|
+
:title="updateErrorTitle"
|
|
45
|
+
:issue="updateErrorIssue"
|
|
46
|
+
@close="onUpdateErrorDialogClose"
|
|
47
|
+
/>
|
|
48
|
+
<UpdateAvailableDialog
|
|
49
|
+
v-model:visible="updateAvailableVisible"
|
|
50
|
+
:version="updateVersion"
|
|
51
|
+
@downloadAndInstall="onDownloadAndInstall"
|
|
52
|
+
@close="updateAvailableVisible = false"
|
|
53
|
+
/>
|
|
54
|
+
<UpdateDownloadProgressDialog v-model:visible="updateDownloadProgressVisible" :percent="updateDownloadPercent" />
|
|
55
|
+
<UpdateNotAvailableDialog v-model:visible="updateNotAvailableVisible" @close="updateNotAvailableVisible = false" />
|
|
56
|
+
</BlockUI>
|
|
47
57
|
</template>
|
|
48
58
|
|
|
49
59
|
<script setup lang="ts">
|
|
@@ -74,6 +84,20 @@ const props = defineProps<IOpenCORProps>()
|
|
|
74
84
|
const contents = vue.ref<InstanceType<typeof IContentsComponent> | null>(null)
|
|
75
85
|
const issues = vue.ref<locApi.IIssue[]>([])
|
|
76
86
|
|
|
87
|
+
const compUiEnabled = vue.computed(() => {
|
|
88
|
+
return (
|
|
89
|
+
uiEnabled.value &&
|
|
90
|
+
!openRemoteVisible.value &&
|
|
91
|
+
!settingsVisible.value &&
|
|
92
|
+
!resetAllVisible.value &&
|
|
93
|
+
!aboutVisible.value &&
|
|
94
|
+
!updateErrorVisible.value &&
|
|
95
|
+
!updateAvailableVisible.value &&
|
|
96
|
+
!updateDownloadProgressVisible.value &&
|
|
97
|
+
!updateNotAvailableVisible.value
|
|
98
|
+
)
|
|
99
|
+
})
|
|
100
|
+
|
|
77
101
|
// Get the current Vue app instance to use some PrimeVue components.
|
|
78
102
|
|
|
79
103
|
const getCurrentInstance = vue.getCurrentInstance()
|
|
@@ -181,40 +205,40 @@ vue.watch(hasFiles, (hasFiles) => {
|
|
|
181
205
|
electronApi?.enableDisableFileCloseAndCloseAllMenuItems(hasFiles)
|
|
182
206
|
})
|
|
183
207
|
|
|
184
|
-
// Loading
|
|
208
|
+
// Loading OpenCOR.
|
|
185
209
|
// Note: this is only done if window.locApi is not defined, which means that we are running OpenCOR's Web app.
|
|
186
210
|
|
|
187
|
-
const
|
|
211
|
+
const loadingOpencorMessageVisible = vue.ref<boolean>(false)
|
|
188
212
|
|
|
189
213
|
// @ts-expect-error (window.locApi may or may not be defined which is why we test it)
|
|
190
214
|
if (window.locApi === undefined) {
|
|
191
215
|
enableDisableUi(false)
|
|
192
216
|
|
|
193
|
-
|
|
217
|
+
loadingOpencorMessageVisible.value = true
|
|
194
218
|
|
|
195
219
|
vue.watch(locApiInitialised, (initialised) => {
|
|
196
220
|
if (initialised) {
|
|
197
|
-
|
|
221
|
+
loadingOpencorMessageVisible.value = false
|
|
198
222
|
|
|
199
223
|
enableDisableUi(true)
|
|
200
224
|
}
|
|
201
225
|
})
|
|
202
226
|
}
|
|
203
227
|
|
|
204
|
-
//
|
|
228
|
+
// Loading model.
|
|
205
229
|
|
|
206
|
-
const
|
|
230
|
+
const loadingModelMessageVisible = vue.ref<boolean>(false)
|
|
207
231
|
|
|
208
|
-
function
|
|
232
|
+
function showLoadingModelMessage(): void {
|
|
209
233
|
enableDisableUi(false)
|
|
210
234
|
|
|
211
|
-
|
|
235
|
+
loadingModelMessageVisible.value = true
|
|
212
236
|
}
|
|
213
237
|
|
|
214
|
-
function
|
|
238
|
+
function hideLoadingModelMessage(): void {
|
|
215
239
|
enableDisableUi(true)
|
|
216
240
|
|
|
217
|
-
|
|
241
|
+
loadingModelMessageVisible.value = false
|
|
218
242
|
}
|
|
219
243
|
|
|
220
244
|
// Auto update.
|
|
@@ -318,7 +342,7 @@ function openFile(fileOrFilePath: string | File): void {
|
|
|
318
342
|
// Retrieve a locApi.File object for the given file or file path and add it to the contents.
|
|
319
343
|
|
|
320
344
|
if (locCommon.isRemoteFilePath(filePath)) {
|
|
321
|
-
|
|
345
|
+
showLoadingModelMessage()
|
|
322
346
|
}
|
|
323
347
|
|
|
324
348
|
locCommon
|
|
@@ -326,15 +350,19 @@ function openFile(fileOrFilePath: string | File): void {
|
|
|
326
350
|
.then((file) => {
|
|
327
351
|
const fileType = file.type()
|
|
328
352
|
|
|
329
|
-
if (
|
|
353
|
+
if (
|
|
354
|
+
fileType === locApi.EFileType.IRRETRIEVABLE_FILE ||
|
|
355
|
+
fileType === locApi.EFileType.UNKNOWN_FILE ||
|
|
356
|
+
(props.omex !== undefined && fileType !== locApi.EFileType.COMBINE_ARCHIVE)
|
|
357
|
+
) {
|
|
330
358
|
if (props.omex !== undefined) {
|
|
331
359
|
void vue.nextTick().then(() => {
|
|
332
360
|
issues.value.push({
|
|
333
361
|
type: locApi.EIssueType.ERROR,
|
|
334
362
|
description:
|
|
335
|
-
fileType === locApi.EFileType.
|
|
336
|
-
? '
|
|
337
|
-
: '
|
|
363
|
+
fileType === locApi.EFileType.IRRETRIEVABLE_FILE
|
|
364
|
+
? 'The file could not be retrieved.'
|
|
365
|
+
: 'Only COMBINE archives are supported.'
|
|
338
366
|
})
|
|
339
367
|
})
|
|
340
368
|
} else {
|
|
@@ -344,9 +372,9 @@ function openFile(fileOrFilePath: string | File): void {
|
|
|
344
372
|
detail:
|
|
345
373
|
filePath +
|
|
346
374
|
'\n\n' +
|
|
347
|
-
(fileType === locApi.EFileType.
|
|
348
|
-
? '
|
|
349
|
-
: '
|
|
375
|
+
(fileType === locApi.EFileType.IRRETRIEVABLE_FILE
|
|
376
|
+
? 'The file could not be retrieved.'
|
|
377
|
+
: 'Only CellML files, SED-ML files, and COMBINE archives are supported.'),
|
|
350
378
|
life: TOAST_LIFE
|
|
351
379
|
})
|
|
352
380
|
}
|
|
@@ -357,12 +385,12 @@ function openFile(fileOrFilePath: string | File): void {
|
|
|
357
385
|
}
|
|
358
386
|
|
|
359
387
|
if (locCommon.isRemoteFilePath(filePath)) {
|
|
360
|
-
|
|
388
|
+
hideLoadingModelMessage()
|
|
361
389
|
}
|
|
362
390
|
})
|
|
363
391
|
.catch((error: unknown) => {
|
|
364
392
|
if (locCommon.isRemoteFilePath(filePath)) {
|
|
365
|
-
|
|
393
|
+
hideLoadingModelMessage()
|
|
366
394
|
}
|
|
367
395
|
|
|
368
396
|
if (props.omex !== undefined) {
|
|
@@ -399,22 +427,22 @@ function onChange(event: Event): void {
|
|
|
399
427
|
|
|
400
428
|
// Drag and drop.
|
|
401
429
|
|
|
402
|
-
const
|
|
430
|
+
const dragAndDropCounter = vue.ref<number>(0)
|
|
403
431
|
|
|
404
432
|
function onDragEnter(): void {
|
|
405
|
-
if (props.omex !== undefined) {
|
|
433
|
+
if (!uiEnabled.value || props.omex !== undefined) {
|
|
406
434
|
return
|
|
407
435
|
}
|
|
408
436
|
|
|
409
|
-
|
|
437
|
+
dragAndDropCounter.value += 1
|
|
410
438
|
}
|
|
411
439
|
|
|
412
440
|
function onDrop(event: DragEvent): void {
|
|
413
|
-
if (
|
|
441
|
+
if (dragAndDropCounter.value === 0) {
|
|
414
442
|
return
|
|
415
443
|
}
|
|
416
444
|
|
|
417
|
-
|
|
445
|
+
dragAndDropCounter.value = 0
|
|
418
446
|
|
|
419
447
|
const files = event.dataTransfer?.files
|
|
420
448
|
|
|
@@ -426,11 +454,11 @@ function onDrop(event: DragEvent): void {
|
|
|
426
454
|
}
|
|
427
455
|
|
|
428
456
|
function onDragLeave(): void {
|
|
429
|
-
if (
|
|
457
|
+
if (dragAndDropCounter.value === 0) {
|
|
430
458
|
return
|
|
431
459
|
}
|
|
432
460
|
|
|
433
|
-
|
|
461
|
+
dragAndDropCounter.value -= 1
|
|
434
462
|
}
|
|
435
463
|
|
|
436
464
|
// Open.
|
|
@@ -514,6 +542,10 @@ electronApi?.onSelect((filePath: string) => {
|
|
|
514
542
|
contents.value?.selectFile(filePath)
|
|
515
543
|
})
|
|
516
544
|
|
|
545
|
+
// Track the height of our block UI.
|
|
546
|
+
|
|
547
|
+
vueCommon.trackElementHeight('blockUi')
|
|
548
|
+
|
|
517
549
|
// If a COMBINE archive is provided then open it (and then the Simulation Experiment view will be shown in isolation) or
|
|
518
550
|
// carry as normal (i.e. the whole OpenCOR UI will be shown).
|
|
519
551
|
|
|
@@ -526,7 +558,7 @@ if (props.omex !== undefined) {
|
|
|
526
558
|
}
|
|
527
559
|
})
|
|
528
560
|
} else {
|
|
529
|
-
//
|
|
561
|
+
// (Also) track the height of our main menu.
|
|
530
562
|
|
|
531
563
|
vueCommon.trackElementHeight('mainMenu')
|
|
532
564
|
|
|
@@ -536,6 +568,15 @@ if (props.omex !== undefined) {
|
|
|
536
568
|
// Do what follows with a bit of a delay to give our background (with the OpenCOR logo) time to be renderered.
|
|
537
569
|
|
|
538
570
|
setTimeout(() => {
|
|
571
|
+
// Ensure that our toasts are shown within our container.
|
|
572
|
+
|
|
573
|
+
const toastElement = document.getElementById('toast')
|
|
574
|
+
const blockUiElement = document.getElementById('blockUi')
|
|
575
|
+
|
|
576
|
+
if (toastElement !== null && blockUiElement !== null) {
|
|
577
|
+
blockUiElement.appendChild(toastElement)
|
|
578
|
+
}
|
|
579
|
+
|
|
539
580
|
if (electronApi !== undefined) {
|
|
540
581
|
// Check for updates.
|
|
541
582
|
// Note: the main process will actually check for updates if requested and if OpenCOR is packaged.
|