Parcourir la source

add loading indicator

Daniel Sheffield il y a 1 an
Parent
commit
a2aef3b47a
5 fichiers modifiés avec 110 ajouts et 52 suppressions
  1. 0 51
      app/rest/loading.html
  2. 23 0
      app/rest/loading.tpl
  3. 3 0
      app/rest/progress.tpl
  4. 11 1
      app/rest/pyapi.py
  5. 73 0
      app/rest/static/cloud-gears.css

+ 0 - 51
app/rest/loading.html

@@ -1,51 +0,0 @@
-<html>
-    <head>
-        <style>
-.lds-ring {
-  left: 45vw;
-  top: 45vh;
-  display: inline-block;
-  position: relative;
-  width: 80px;
-  height: 80px;
-}
-.lds-ring div {
-  box-sizing: border-box;
-  display: block;
-  position: absolute;
-  width: 10vh;
-  height: 10vh;
-  margin: 8px;
-  border: 8px solid #000;
-  border-radius: 50%;
-  animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
-  border-color: #000 transparent transparent transparent;
-}
-.lds-ring div:nth-child(1) {
-  animation-delay: -0.45s;
-}
-.lds-ring div:nth-child(2) {
-  animation-delay: -0.3s;
-}
-.lds-ring div:nth-child(3) {
-  animation-delay: -0.15s;
-}
-@keyframes lds-ring {
-  0% {
-    transform: rotate(0deg);
-  }
-  100% {
-    transform: rotate(360deg);
-  }
-}
-iframe {
-    overflow: hidden;
-    pointer-events: none;
-}
-        </style>
-    </head>
-    <body>
-        <div class="lds-ring"><div></div><div></div><div></div><div></div></div>
-        <meta http-equiv="Refresh" content="0;" />
-    </body>
-</html>

+ 23 - 0
app/rest/loading.tpl

@@ -0,0 +1,23 @@
+<html>
+  <head>
+    <link rel="stylesheet" href="/grocery/static/cloud-gears.css"/>
+    <style>
+.loader-container {
+  position: absolute;
+  left: 45vw;
+  top: 45vh;
+}
+    </style>
+  </head>
+  <body>
+    <div class="loader-container">
+      <span class="loader"></span>
+      <%
+      for indicator in progress:
+          include('app/rest/progress', **indicator)
+      end
+      %>
+    </div>
+    <meta http-equiv="Refresh" content="0;" />
+  </body>
+</html>

+ 3 - 0
app/rest/progress.tpl

@@ -0,0 +1,3 @@
+<p>
+{{name}}... {{status}}
+</p>

+ 11 - 1
app/rest/pyapi.py

@@ -174,6 +174,9 @@ def get_form(action, method, filter_data, data):
         )), key=lambda x: x["display"] if "display" in x else x["value"]), # include
     )
 
+@route('/grocery/static/<filename:path>')
+def send_static(filename):
+    return static_file(filename, root='app/rest/static')
 
 @route('/grocery/trend')
 def trend():
@@ -188,9 +191,10 @@ def trend():
     
     CACHE[request.query_string] = trend_internal(path, request.query)
 
-    return static_file("loading.html", root="app/rest")
+    return template("app/rest/loading", progress=[])
 
 def trend_internal(path, query):
+    progress = []
     try:
         with conn.cursor() as cur:
             query_manager = QueryManager(cur, display_mapper)
@@ -199,10 +203,16 @@ def trend_internal(path, query):
             if unit and unit not in ALL_UNITS:
                 raise abort(400, f"Unsupported unit {unit}")
 
+            progress.append({ "name": "Loading data", "status": ""})
+            yield template("app/rest/loading", progress=progress)
             data = get_data(query_manager, **fields)
+            progress[-1]["status"] = "done"
+
             if data.empty:
                 raise abort(404, f"No data for {fields}")
             
+            progress.append({ "name": "Loading chart", "status": ""})
+            yield template("app/rest/loading", progress=progress)
             pivot = data.pivot_table(index=['ts_raw',], columns=['product',], values=['$/unit'], aggfunc='mean')
             pivot.columns = pivot.columns.droplevel()
             plt.figure(figsize=[16, 9])

+ 73 - 0
app/rest/static/cloud-gears.css

@@ -0,0 +1,73 @@
+.loader {
+    width: 175px;
+    height: 80px;
+    display: block;
+    margin:auto;
+    background-image:
+     radial-gradient(circle 25px at 25px 25px, #adadad 100%, transparent 0),
+     radial-gradient(circle 50px at 50px 50px, #adadad 100%, transparent 0),
+     radial-gradient(circle 25px at 25px 25px, #adadad 100%, transparent 0),
+     linear-gradient(#adadad 50px, transparent 0);
+    background-size: 50px 50px, 100px 76px, 50px 50px, 120px 40px;
+    background-position: 0px 30px, 37px 0px, 122px 30px, 25px 40px;
+    background-repeat: no-repeat;
+    position: relative;
+    box-sizing: border-box;
+  }
+  .loader::before {
+    content: '';  
+    left: 60px;
+    bottom: 18px;
+    position: absolute;
+    width: 36px;
+    height: 36px;
+    border-radius: 50%;
+    background-color: #404040;
+    background-image:
+     radial-gradient(circle 8px at 18px 18px, #adadad 100%, transparent 0),
+     radial-gradient(circle 4px at 18px 0px, #adadad 100%, transparent 0),
+     radial-gradient(circle 4px at 0px 18px, #adadad 100%, transparent 0),
+     radial-gradient(circle 4px at 36px 18px, #adadad 100%, transparent 0),
+     radial-gradient(circle 4px at 18px 36px, #adadad 100%, transparent 0),
+     radial-gradient(circle 4px at 30px 5px, #adadad 100%, transparent 0),
+     radial-gradient(circle 4px at 30px 5px, #adadad 100%, transparent 0),
+     radial-gradient(circle 4px at 30px 30px, #adadad 100%, transparent 0),
+     radial-gradient(circle 4px at 5px 30px, #adadad 100%, transparent 0),
+     radial-gradient(circle 4px at 5px 5px, #adadad 100%, transparent 0);
+    background-repeat: no-repeat;
+    box-sizing: border-box;
+    animation: rotationBack 3s linear infinite;
+  }
+  .loader::after {
+    content: '';  
+    left: 94px;
+    bottom: 15px;
+    position: absolute;
+    width: 24px;
+    height: 24px;
+    border-radius: 50%;
+    background-color: #404040;
+    background-image:
+     radial-gradient(circle 5px at 12px 12px, #adadad 100%, transparent 0),
+     radial-gradient(circle 2.5px at 12px 0px, #adadad 100%, transparent 0),
+     radial-gradient(circle 2.5px at 0px 12px, #adadad 100%, transparent 0),
+     radial-gradient(circle 2.5px at 24px 12px, #adadad 100%, transparent 0),
+     radial-gradient(circle 2.5px at 12px 24px, #adadad 100%, transparent 0),
+     radial-gradient(circle 2.5px at 20px 3px, #adadad 100%, transparent 0),
+     radial-gradient(circle 2.5px at 20px 3px, #adadad 100%, transparent 0),
+     radial-gradient(circle 2.5px at 20px 20px, #adadad 100%, transparent 0),
+     radial-gradient(circle 2.5px at 3px 20px, #adadad 100%, transparent 0),
+     radial-gradient(circle 2.5px at 3px 3px, #adadad 100%, transparent 0);
+    background-repeat: no-repeat;
+    box-sizing: border-box;
+    animation: rotationBack 4s linear infinite reverse;
+  }
+  
+  @keyframes rotationBack {
+    0% {
+      transform: rotate(0deg);
+    }
+    100% {
+      transform: rotate(-360deg);
+    }
+  }