diff --git a/examples/loading/.gitignore b/examples/loading/.gitignore
new file mode 100644
index 0000000..3f68feb
--- /dev/null
+++ b/examples/loading/.gitignore
@@ -0,0 +1 @@
+loading
\ No newline at end of file
diff --git a/examples/loading/loading.py b/examples/loading/loading.py
new file mode 100644
index 0000000..b554feb
--- /dev/null
+++ b/examples/loading/loading.py
@@ -0,0 +1,25 @@
+import os
+from trame.app import get_server
+from trame.widgets import html
+from trame.ui.html import DivLayout
+import time
+
+server = get_server(client_type=os.environ.get("TRAME_CLIENT_TYPE", "vue3"))
+
+# -----------------------------------------------------------------------------
+# Only with Vue3
+# -----------------------------------------------------------------------------
+with DivLayout(server, template_name="error") as layout:
+ html.Div("App disconnected: {{ trame_error_report_msg }}")
+
+with DivLayout(server, template_name="error_reconnect") as layout:
+ html.Div("App disconnected but you can reconnect: {{ trame_error_report_msg }}")
+# -----------------------------------------------------------------------------
+
+with DivLayout(server) as layout:
+ html.Div("App is fully loaded")
+
+# Busy wait
+time.sleep(5)
+
+server.start()
diff --git a/examples/loading/loading_launcher.json b/examples/loading/loading_launcher.json
new file mode 100644
index 0000000..59f7e4c
--- /dev/null
+++ b/examples/loading/loading_launcher.json
@@ -0,0 +1,22 @@
+
+{
+ "configuration": {
+ "host" : "localhost",
+ "port" : 8080,
+ "endpoint": "paraview",
+ "content": "loading/loading_www",
+ "proxy_file" : "loading/proxy-mapping.txt",
+ "sessionURL" : "ws://${host}:${port}/ws",
+ "timeout" : 50,
+ "log_dir" : "loading",
+ "fields" : []
+ },
+ "resources" : [ { "host" : "localhost", "port_range" : [9001, 9020] } ],
+ "properties" : {},
+ "apps" : {
+ "trame" : {
+ "cmd" : ["python", "loading.py", "--port", "$port", "--server", "--authKey", "${secret}"],
+ "ready_line" : "App running at"
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/loading/run_loading.sh b/examples/loading/run_loading.sh
new file mode 100755
index 0000000..e72ecf5
--- /dev/null
+++ b/examples/loading/run_loading.sh
@@ -0,0 +1,7 @@
+# export TRAME_CLIENT_TYPE=vue2
+export TRAME_CLIENT_TYPE=vue3
+
+rm -rf ./loading/
+mkdir -p ./loading/loading_www
+python -m trame.tools.www --client-type "$TRAME_CLIENT_TYPE" --output ./loading/loading_www
+python -m wslink.launcher ./loading_launcher.json
\ No newline at end of file
diff --git a/vue2-app/public/index.html b/vue2-app/public/index.html
index 11cef3c..b309873 100644
--- a/vue2-app/public/index.html
+++ b/vue2-app/public/index.html
@@ -12,106 +12,14 @@
trame is built by Kitware
-
diff --git a/vue2-app/public/loading/index.html b/vue2-app/public/loading/index.html
new file mode 100644
index 0000000..46243a3
--- /dev/null
+++ b/vue2-app/public/loading/index.html
@@ -0,0 +1,101 @@
+
+
+
+
+
+ Loading...
+
+
+
+
+
+
diff --git a/vue3-app/index.html b/vue3-app/index.html
index fd39c12..b526b54 100644
--- a/vue3-app/index.html
+++ b/vue3-app/index.html
@@ -11,103 +11,14 @@
trame is built by Kitware
-
diff --git a/vue3-app/public/loading/index.html b/vue3-app/public/loading/index.html
new file mode 100644
index 0000000..46243a3
--- /dev/null
+++ b/vue3-app/public/loading/index.html
@@ -0,0 +1,101 @@
+
+
+
+
+
+ Loading...
+
+
+
+
+
+
diff --git a/vue3-app/src/main.js b/vue3-app/src/main.js
index 0083827..53aaa02 100644
--- a/vue3-app/src/main.js
+++ b/vue3-app/src/main.js
@@ -1,3 +1,4 @@
+import "./style.css";
import vtkURLExtract from "@kitware/vtk.js/Common/Core/URLExtract";
import wslink from "./core/wslink";
import { handlePageResources } from "./core/trame/setup";
@@ -38,6 +39,7 @@ async function start() {
function reportWsError(message) {
if (trame) {
console.log("about to replace template", message);
+ trame.state.set("trame_error_report_msg", message);
let templateName = "trame__template_main";
if (vtkURLExtract.extractURLParameters().ui) {
templateName = `trame__template_${
@@ -47,10 +49,15 @@ async function start() {
if (config.reconnect) {
trame.state.set(
templateName,
- ``
+ trame.state.get("trame__template_error_reconnect") ||
+ ``
);
} else {
- trame.state.set(templateName, ``);
+ trame.state.set(
+ templateName,
+ trame.state.get("trame__template_error") ||
+ ``
+ );
}
console.log("template replaced", trame.state.get(templateName));
} else {
diff --git a/vue3-app/src/style.css b/vue3-app/src/style.css
new file mode 100644
index 0000000..3a9d9a1
--- /dev/null
+++ b/vue3-app/src/style.css
@@ -0,0 +1,85 @@
+.text-no-select {
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ }
+ .trame__loader {
+ display: block;
+ position: relative;
+ left: 50%;
+ top: calc(50% - 50px);
+ width: 150px;
+ height: 150px;
+ margin: -75px 0 0 -75px;
+ border-radius: 50%;
+ border: 10px solid transparent;
+ border-top-color: #ac262c;
+
+ -webkit-animation: spin 2s linear infinite; /* Chrome, Opera 15+, Safari 5+ */
+ animation: spin 2s linear infinite; /* Chrome, Firefox 16+, IE 10+, Opera */
+ }
+
+ .trame__loader:before {
+ content: "";
+ position: absolute;
+ top: 5px;
+ left: 5px;
+ right: 5px;
+ bottom: 5px;
+ border-radius: 50%;
+ border: 10px solid transparent;
+ border-top-color: #258e44;
+
+ -webkit-animation: spin 3s linear infinite; /* Chrome, Opera 15+, Safari 5+ */
+ animation: spin 3s linear infinite; /* Chrome, Firefox 16+, IE 10+, Opera */
+ }
+
+ .trame__loader:after {
+ content: "";
+ position: absolute;
+ top: 20px;
+ left: 20px;
+ right: 20px;
+ bottom: 20px;
+ border-radius: 50%;
+ border: 10px solid transparent;
+ border-top-color: #1c4678;
+
+ -webkit-animation: spin 1.5s linear infinite; /* Chrome, Opera 15+, Safari 5+ */
+ animation: spin 1.5s linear infinite; /* Chrome, Firefox 16+, IE 10+, Opera */
+ }
+
+ .trame__message {
+ position: absolute;
+ text-align: center;
+ width: 100%;
+ top: calc(50% + 50px);
+ font-size: 200%;
+ user-select: none;
+ }
+
+ @-webkit-keyframes spin {
+ 0% {
+ -webkit-transform: rotate(0deg); /* Chrome, Opera 15+, Safari 3.1+ */
+ -ms-transform: rotate(0deg); /* IE 9 */
+ transform: rotate(0deg); /* Firefox 16+, IE 10+, Opera */
+ }
+ 100% {
+ -webkit-transform: rotate(360deg); /* Chrome, Opera 15+, Safari 3.1+ */
+ -ms-transform: rotate(360deg); /* IE 9 */
+ transform: rotate(360deg); /* Firefox 16+, IE 10+, Opera */
+ }
+ }
+ @keyframes spin {
+ 0% {
+ -webkit-transform: rotate(0deg); /* Chrome, Opera 15+, Safari 3.1+ */
+ -ms-transform: rotate(0deg); /* IE 9 */
+ transform: rotate(0deg); /* Firefox 16+, IE 10+, Opera */
+ }
+ 100% {
+ -webkit-transform: rotate(360deg); /* Chrome, Opera 15+, Safari 3.1+ */
+ -ms-transform: rotate(360deg); /* IE 9 */
+ transform: rotate(360deg); /* Firefox 16+, IE 10+, Opera */
+ }
+ }
\ No newline at end of file