From 2b6ce25954fe05d56ece944117c95c85a1fdeafa Mon Sep 17 00:00:00 2001 From: Frederick Michielssen Date: Fri, 11 Aug 2017 16:54:02 +0200 Subject: [PATCH] Added animated loading feedback while container is launching --- .../controllers/AppController.java | 33 +++++++++++++----- .../controllers/BaseController.java | 13 +++++++ .../openanalytics/services/DockerService.java | 4 +-- src/main/resources/static/css/default.css | 15 ++++++++ src/main/resources/static/img/loading.gif | Bin 0 -> 4799 bytes src/main/resources/templates/app.html | 16 +++++++++ 6 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 src/main/resources/static/img/loading.gif diff --git a/src/main/java/eu/openanalytics/controllers/AppController.java b/src/main/java/eu/openanalytics/controllers/AppController.java index db48cb40..92f34489 100644 --- a/src/main/java/eu/openanalytics/controllers/AppController.java +++ b/src/main/java/eu/openanalytics/controllers/AppController.java @@ -26,6 +26,8 @@ import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; import eu.openanalytics.ShinyProxyApplication; import eu.openanalytics.services.AppService; @@ -40,23 +42,36 @@ public class AppController extends BaseController { @Inject AppService appService; - @RequestMapping("/app/*") + @RequestMapping(value="/app/*", method=RequestMethod.GET) String app(ModelMap map, HttpServletRequest request) { prepareMap(map, request); - String mapping = dockerService.getMapping(getUserName(request), getAppName(request)); - - String queryString = request.getQueryString(); - if (queryString == null) queryString = ""; - else queryString = "?" + queryString; - + String mapping = dockerService.getMapping(getUserName(request), getAppName(request), false); String contextPath = ShinyProxyApplication.getContextPath(environment); - String containerPath = contextPath + "/" + mapping + environment.getProperty("shiny.proxy.landing-page") + queryString; - map.put("container", containerPath); + map.put("appTitle", getAppTitle(request)); + map.put("container", buildContainerPath(mapping, request)); map.put("heartbeatRate", environment.getProperty("shiny.proxy.heartbeat-rate", "10000")); map.put("heartbeatPath", contextPath + "/heartbeat"); return "app"; } + + @RequestMapping(value="/app/*", method=RequestMethod.POST) + @ResponseBody + String startApp(HttpServletRequest request) { + String mapping = dockerService.getMapping(getUserName(request), getAppName(request), true); + return buildContainerPath(mapping, request); + } + + private String buildContainerPath(String mapping, HttpServletRequest request) { + if (mapping == null) return ""; + + String queryString = request.getQueryString(); + queryString = (queryString == null) ? "" : "?" + queryString; + + String contextPath = ShinyProxyApplication.getContextPath(environment); + String containerPath = contextPath + "/" + mapping + environment.getProperty("shiny.proxy.landing-page") + queryString; + return containerPath; + } } diff --git a/src/main/java/eu/openanalytics/controllers/BaseController.java b/src/main/java/eu/openanalytics/controllers/BaseController.java index f7c975d4..1383fed7 100644 --- a/src/main/java/eu/openanalytics/controllers/BaseController.java +++ b/src/main/java/eu/openanalytics/controllers/BaseController.java @@ -40,10 +40,15 @@ import org.springframework.ui.ModelMap; import org.springframework.util.StreamUtils; +import eu.openanalytics.services.AppService; import eu.openanalytics.services.UserService; +import eu.openanalytics.services.AppService.ShinyApp; public abstract class BaseController { + @Inject + AppService appService; + @Inject UserService userService; @@ -70,6 +75,14 @@ protected String getAppName(String uri) { return appName; } + protected String getAppTitle(HttpServletRequest request) { + String appName = getAppName(request); + if (appName == null || appName.isEmpty()) return ""; + ShinyApp app = appService.getApp(appName); + if (app == null || app.getDisplayName() == null || app.getDisplayName().isEmpty()) return appName; + else return app.getDisplayName(); + } + protected void prepareMap(ModelMap map, HttpServletRequest request) { map.put("title", environment.getProperty("shiny.proxy.title")); if (logoURI == null) logoURI = toAccessibleURI(environment.getProperty("shiny.proxy.logo-url")); diff --git a/src/main/java/eu/openanalytics/services/DockerService.java b/src/main/java/eu/openanalytics/services/DockerService.java index cda4813f..d7d18b6a 100644 --- a/src/main/java/eu/openanalytics/services/DockerService.java +++ b/src/main/java/eu/openanalytics/services/DockerService.java @@ -178,10 +178,10 @@ public List listProxies() { } } - public String getMapping(String userName, String appName) { + public String getMapping(String userName, String appName, boolean startNew) { waitForLaunchingProxy(userName, appName); Proxy proxy = findProxy(userName, appName); - if (proxy == null) { + if (proxy == null && startNew) { // The user has no proxy yet. proxy = startProxy(userName, appName); } diff --git a/src/main/resources/static/css/default.css b/src/main/resources/static/css/default.css index d94af585..cb5fbf3c 100644 --- a/src/main/resources/static/css/default.css +++ b/src/main/resources/static/css/default.css @@ -48,4 +48,19 @@ body > div#navbar { padding-top: 0px; } #error { padding-left: 15px; +} + +.loading { + display: none; + position: fixed; + top: 150px; + width: 100%; + z-index: 9999; + background: url(../img/loading.gif) center no-repeat #fff; +} + +.loading-txt { + text-align: center; + font-size: 24px; + margin-top: -50px; } \ No newline at end of file diff --git a/src/main/resources/static/img/loading.gif b/src/main/resources/static/img/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..98218271f56841295547959676187cc79d0b94ed GIT binary patch literal 4799 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 Qg#uqHr%#|IAfRpk13idq>Hq)$ literal 0 HcmV?d00001 diff --git a/src/main/resources/templates/app.html b/src/main/resources/templates/app.html index 1ecda2c2..b339f843 100644 --- a/src/main/resources/templates/app.html +++ b/src/main/resources/templates/app.html @@ -37,6 +37,7 @@ +
Launching ...