From ae5860fc17f8b413cbccb270d6f5827ed90bdc74 Mon Sep 17 00:00:00 2001 From: Gabriel Augendre Date: Sun, 25 Sep 2022 19:51:21 +0200 Subject: [PATCH] Load graphs asynchronously --- poetry.lock | 14 ++++++- pyproject.toml | 1 + src/checkout/settings.py | 2 + .../static/vendor/htmx-1.8.0/htmx.min.js | 1 + src/common/templates/common/base.html | 2 + src/purchase/static/purchase/spinner.gif | Bin 0 -> 5534 bytes src/purchase/templates/purchase/reports.html | 16 ++++---- .../purchase/snippets/htmx_plot.html | 7 ++++ .../templates/purchase/snippets/plots.html | 3 ++ src/purchase/urls.py | 5 ++- src/purchase/views/reports.py | 35 +++++++++++++----- 11 files changed, 66 insertions(+), 20 deletions(-) create mode 100644 src/common/static/vendor/htmx-1.8.0/htmx.min.js create mode 100644 src/purchase/static/purchase/spinner.gif create mode 100644 src/purchase/templates/purchase/snippets/htmx_plot.html create mode 100644 src/purchase/templates/purchase/snippets/plots.html diff --git a/poetry.lock b/poetry.lock index 14bd36e..ba2d41b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -342,6 +342,17 @@ python-versions = ">=3.6" [package.dependencies] Django = ">=3.2" +[[package]] +name = "django-htmx" +version = "1.12.2" +description = "Extensions for using Django with htmx." +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +Django = ">=3.2" + [[package]] name = "factory-boy" version = "3.2.1" @@ -1153,7 +1164,7 @@ h11 = ">=0.9.0,<1" [metadata] lock-version = "1.1" python-versions = "^3.10" -content-hash = "e21ae8f93aefc631a43ccf43b79a3660ca11c6870677d60878b0adc88303953d" +content-hash = "e0332f1446a90fc3a5dc2fa2ca5d1745eb0d90d8f033094d79b2df9376b79639" [metadata.files] ansicon = [] @@ -1276,6 +1287,7 @@ django-environ = [ {file = "django_environ-0.9.0-py2.py3-none-any.whl", hash = "sha256:f21a5ef8cc603da1870bbf9a09b7e5577ab5f6da451b843dbcc721a7bca6b3d9"}, ] django-extensions = [] +django-htmx = [] factory-boy = [] faker = [] filelock = [] diff --git a/pyproject.toml b/pyproject.toml index a9fe6ca..8c2c321 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,6 +21,7 @@ django-crispy-forms = "^1.14.0" crispy-bootstrap5 = "^0.6" matplotlib = "^3.5.1" freezegun = "^1.2.1" +django-htmx = "^1.12.2" [tool.poetry.dev-dependencies] pre-commit = "^2.7" diff --git a/src/checkout/settings.py b/src/checkout/settings.py index 629e7dc..37bf550 100644 --- a/src/checkout/settings.py +++ b/src/checkout/settings.py @@ -89,6 +89,7 @@ INSTALLED_APPS = [ "crispy_forms", "crispy_bootstrap5", "django_extensions", + "django_htmx", ] MIDDLEWARE = [ @@ -102,6 +103,7 @@ MIDDLEWARE = [ "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", "csp.middleware.CSPMiddleware", + "django_htmx.middleware.HtmxMiddleware", ] try: diff --git a/src/common/static/vendor/htmx-1.8.0/htmx.min.js b/src/common/static/vendor/htmx-1.8.0/htmx.min.js new file mode 100644 index 0000000..027cd1e --- /dev/null +++ b/src/common/static/vendor/htmx-1.8.0/htmx.min.js @@ -0,0 +1 @@ +(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=e.htmx||t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var U={onLoad:t,process:vt,on:X,off:F,trigger:$,ajax:nr,find:R,findAll:O,closest:N,values:function(e,t){var r=Pt(e,t||"post");return r.values},remove:q,addClass:L,removeClass:T,toggleClass:A,takeClass:H,defineExtension:fr,removeExtension:cr,logAll:C,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false},parseInterval:v,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])},version:"1.8.0"};var r={addTriggerHandler:st,bodyContains:K,canAccessLocalStorage:E,filterValues:Ut,hasAttribute:o,getAttributeValue:V,getClosestMatch:h,getExpressionVars:Qt,getHeaders:Bt,getInputValues:Pt,getInternalData:W,getSwapSpecification:_t,getTriggerSpecs:Me,getTarget:re,makeFragment:g,mergeObjects:Y,makeSettleInfo:Gt,oobSwap:ae,selectAndSwap:Ee,settleImmediately:Lt,shouldCancel:je,triggerEvent:$,triggerErrorEvent:J,withExtensions:xt};var n=["get","post","put","delete","patch"];var i=n.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function v(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}if(e.slice(-1)=="m"){return parseFloat(e.slice(0,-1))*1e3*60||undefined}return parseFloat(e)||undefined}function f(e,t){return e.getAttribute&&e.getAttribute(t)}function o(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function V(e,t){return f(e,t)||f(e,"data-"+t)}function u(e){return e.parentElement}function _(){return document}function h(e,t){while(e&&!t(e)){e=u(e)}return e?e:null}function a(e,t,r){var n=V(t,r);var i=V(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function z(t,r){var n=null;h(t,function(e){return n=a(t,e,r)});if(n!=="unset"){return n}}function d(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function s(e){var t=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i;var r=t.exec(e);if(r){return r[1].toLowerCase()}else{return""}}function l(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=_().createDocumentFragment()}return i}function g(e){if(U.config.useTemplateFragments){var t=l("",0);return t.querySelector("template").content}else{var r=s(e);switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return l(""+e+"
",1);case"col":return l(""+e+"
",2);case"tr":return l(""+e+"
",2);case"td":case"th":return l(""+e+"
",3);case"script":return l("
"+e+"
",1);default:return l(e,0)}}}function Z(e){if(e){e()}}function p(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function m(e){return p(e,"Function")}function x(e){return p(e,"Object")}function W(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function y(e){var t=[];if(e){for(var r=0;r=0}function K(e){if(e.getRootNode()instanceof ShadowRoot){return _().body.contains(e.getRootNode().host)}else{return _().body.contains(e)}}function w(e){return e.trim().split(/\s+/)}function Y(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function S(e){try{return JSON.parse(e)}catch(e){yt(e);return null}}function E(){var e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function e(e){return Zt(_().body,function(){return eval(e)})}function t(t){var e=U.on("htmx:load",function(e){t(e.detail.elt)});return e}function C(){U.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function R(e,t){if(t){return e.querySelector(t)}else{return R(_(),e)}}function O(e,t){if(t){return e.querySelectorAll(t)}else{return O(_(),e)}}function q(e,t){e=D(e);if(t){setTimeout(function(){q(e)},t)}else{e.parentElement.removeChild(e)}}function L(e,t,r){e=D(e);if(r){setTimeout(function(){L(e,t)},r)}else{e.classList&&e.classList.add(t)}}function T(e,t,r){e=D(e);if(r){setTimeout(function(){T(e,t)},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function A(e,t){e=D(e);e.classList.toggle(t)}function H(e,t){e=D(e);G(e.parentElement.children,function(e){T(e,t)});L(e,t)}function N(e,t){e=D(e);if(e.closest){return e.closest(t)}else{do{if(e==null||d(e,t)){return e}}while(e=e&&u(e))}}function I(e,t){if(t.indexOf("closest ")===0){return[N(e,t.substr(8))]}else if(t.indexOf("find ")===0){return[R(e,t.substr(5))]}else if(t.indexOf("next ")===0){return[k(e,t.substr(5))]}else if(t.indexOf("previous ")===0){return[M(e,t.substr(9))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else{return _().querySelectorAll(t)}}var k=function(e,t){var r=_().querySelectorAll(t);for(var n=0;n=0;n--){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING){return i}}};function Q(e,t){if(t){return I(e,t)[0]}else{return I(_().body,e)[0]}}function D(e){if(p(e,"String")){return R(e)}else{return e}}function P(e,t,r){if(m(t)){return{target:_().body,event:e,listener:t}}else{return{target:D(e),event:t,listener:r}}}function X(t,r,n){dr(function(){var e=P(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=m(r);return e?r:n}function F(t,r,n){dr(function(){var e=P(t,r,n);e.target.removeEventListener(e.event,e.listener)});return m(r)?r:n}var ee=_().createElement("output");function j(e,t){var r=z(e,t);if(r){if(r==="this"){return[te(e,t)]}else{var n=I(e,r);if(n.length===0){yt('The selector "'+r+'" on '+t+" returned no matches!");return[ee]}else{return n}}}}function te(e,t){return h(e,function(e){return V(e,t)!=null})}function re(e){var t=z(e,"hx-target");if(t){if(t==="this"){return te(e,"hx-target")}else{return Q(e,t)}}else{var r=W(e);if(r.boosted){return _().body}else{return e}}}function B(e){var t=U.config.attributesToSettle;for(var r=0;r0){o=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{o=e}var r=_().querySelectorAll(t);if(r){G(r,function(e){var t;var r=i.cloneNode(true);t=_().createDocumentFragment();t.appendChild(r);if(!ie(o,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!$(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){we(o,e,e,t,a)}G(a.elts,function(e){$(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);J(_().body,"htmx:oobErrorNoTarget",{content:i})}return e}function oe(e,t,r){var n=z(e,"hx-select-oob");if(n){var i=n.split(",");for(let e=0;e0){var t=n.querySelector(e.tagName+"[id='"+e.id+"']");if(t&&t!==n){var r=e.cloneNode();ne(e,t);i.tasks.push(function(){ne(e,r)})}}})}function ue(e){return function(){T(e,U.config.addedClass);vt(e);ut(e);fe(e);$(e,"htmx:load")}}function fe(e){var t="[autofocus]";var r=d(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function ce(e,t,r,n){le(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;L(i,U.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(ue(i))}}}function he(t){var e=W(t);if(e.webSocket){e.webSocket.close()}if(e.sseEventSource){e.sseEventSource.close()}$(t,"htmx:beforeCleanupElement");if(e.listenerInfos){G(e.listenerInfos,function(e){if(t!==e.on){e.on.removeEventListener(e.trigger,e.listener)}})}if(t.children){G(t.children,function(e){he(e)})}}function de(e,t,r){if(e.tagName==="BODY"){return ye(e,t,r)}else{var n;var i=e.previousSibling;ce(u(e),e,t,r);if(i==null){n=u(e).firstChild}else{n=i.nextSibling}W(e).replacedWith=n;r.elts=[];while(n&&n!==e){if(n.nodeType===Node.ELEMENT_NODE){r.elts.push(n)}n=n.nextElementSibling}he(e);u(e).removeChild(e)}}function ve(e,t,r){return ce(e,e.firstChild,t,r)}function ge(e,t,r){return ce(u(e),e,t,r)}function pe(e,t,r){return ce(e,null,t,r)}function me(e,t,r){return ce(u(e),e.nextSibling,t,r)}function xe(e,t,r){he(e);return u(e).removeChild(e)}function ye(e,t,r){var n=e.firstChild;ce(e,n,t,r);if(n){while(n.nextSibling){he(n.nextSibling);e.removeChild(n.nextSibling)}he(n);e.removeChild(n)}}function be(e,t){var r=z(e,"hx-select");if(r){var n=_().createDocumentFragment();G(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function we(e,t,r,n,i){switch(e){case"none":return;case"outerHTML":de(r,n,i);return;case"afterbegin":ve(r,n,i);return;case"beforebegin":ge(r,n,i);return;case"beforeend":pe(r,n,i);return;case"afterend":me(r,n,i);return;case"delete":xe(r,n,i);return;default:var a=hr(t);for(var o=0;o-1){var t=e.replace(/]*>|>)([\s\S]*?)<\/svg>/gim,"");var r=t.match(/]*>|>)([\s\S]*?)<\/title>/im);if(r){return r[2]}}}function Ee(e,t,r,n,i){i.title=Se(n);var a=g(n);if(a){oe(r,a,i);a=be(r,a);se(a);return we(e,r,t,a,i)}}function Ce(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=S(n);for(var a in i){if(i.hasOwnProperty(a)){var o=i[a];if(!x(o)){o={value:o}}$(r,a,o)}}}else{$(r,n,[])}}var Re=/\s/;var Oe=/[\s,]/;var qe=/[_$a-zA-Z]/;var Le=/[_$a-zA-Z0-9]/;var Te=['"',"'","/"];var Ae=/[^\s]/;function He(e){var t=[];var r=0;while(r0){var o=t[0];if(o==="]"){n--;if(n===0){if(a===null){i=i+"true"}t.shift();i+=")})";try{var s=Zt(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){J(_().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(o==="["){n++}if(Ne(o,a,r)){i+="(("+r+"."+o+") ? ("+r+"."+o+") : (window."+o+"))"}else{i=i+o}a=t.shift()}}}function c(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var ke="input, textarea, select";function Me(e){var t=V(e,"hx-trigger");var r=[];if(t){var n=He(t);do{c(n,Ae);var f=n.length;var i=c(n,/[,\[\s]/);if(i!==""){if(i==="every"){var a={trigger:"every"};c(n,Ae);a.pollInterval=v(c(n,/[,\[\s]/));c(n,Ae);var o=Ie(e,n,"event");if(o){a.eventFilter=o}r.push(a)}else if(i.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:i.substr(4)})}else{var s={trigger:i};var o=Ie(e,n,"event");if(o){s.eventFilter=o}while(n.length>0&&n[0]!==","){c(n,Ae);var l=n.shift();if(l==="changed"){s.changed=true}else if(l==="once"){s.once=true}else if(l==="consume"){s.consume=true}else if(l==="delay"&&n[0]===":"){n.shift();s.delay=v(c(n,Oe))}else if(l==="from"&&n[0]===":"){n.shift();var u=c(n,Oe);if(u==="closest"||u==="find"||u==="next"||u==="previous"){n.shift();u+=" "+c(n,Oe)}s.from=u}else if(l==="target"&&n[0]===":"){n.shift();s.target=c(n,Oe)}else if(l==="throttle"&&n[0]===":"){n.shift();s.throttle=v(c(n,Oe))}else if(l==="queue"&&n[0]===":"){n.shift();s.queue=c(n,Oe)}else if((l==="root"||l==="threshold")&&n[0]===":"){n.shift();s[l]=c(n,Oe)}else{J(e,"htmx:syntax:error",{token:n.shift()})}}r.push(s)}}if(n.length===f){J(e,"htmx:syntax:error",{token:n.shift()})}c(n,Ae)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(d(e,"form")){return[{trigger:"submit"}]}else if(d(e,'input[type="button"]')){return[{trigger:"click"}]}else if(d(e,ke)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function De(e){W(e).cancelled=true}function Pe(e,t,r){var n=W(e);n.timeout=setTimeout(function(){if(K(e)&&n.cancelled!==true){if(!Ue(r,pt("hx:poll:trigger",{triggerSpec:r,target:e}))){t(e)}Pe(e,t,r)}},r.pollInterval)}function Xe(e){return location.hostname===e.hostname&&f(e,"href")&&f(e,"href").indexOf("#")!==0}function Fe(t,r,e){if(t.tagName==="A"&&Xe(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=f(t,"href")}else{var a=f(t,"method");n=a?a.toLowerCase():"get";if(n==="get"){}i=f(t,"action")}e.forEach(function(e){Ve(t,function(e){ar(n,i,t,e)},r,e,true)})}}function je(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(d(t,'input[type="submit"], button')&&N(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function Be(e,t){return W(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function Ue(e,t){var r=e.eventFilter;if(r){try{return r(t)!==true}catch(e){J(_().body,"htmx:eventFilter:error",{error:e,source:r.source});return true}}return false}function Ve(a,o,e,s,l){var t;if(s.from){t=I(a,s.from)}else{t=[a]}G(t,function(n){var i=function(e){if(!K(a)){n.removeEventListener(s.trigger,i);return}if(Be(a,e)){return}if(l||je(e,a)){e.preventDefault()}if(Ue(s,e)){return}var t=W(e);t.triggerSpec=s;if(t.handledFor==null){t.handledFor=[]}var r=W(a);if(t.handledFor.indexOf(a)<0){t.handledFor.push(a);if(s.consume){e.stopPropagation()}if(s.target&&e.target){if(!d(e.target,s.target)){return}}if(s.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(s.changed){if(r.lastValue===a.value){return}else{r.lastValue=a.value}}if(r.delayed){clearTimeout(r.delayed)}if(r.throttle){return}if(s.throttle){if(!r.throttle){o(a,e);r.throttle=setTimeout(function(){r.throttle=null},s.throttle)}}else if(s.delay){r.delayed=setTimeout(function(){o(a,e)},s.delay)}else{o(a,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:s.trigger,listener:i,on:n});n.addEventListener(s.trigger,i)})}var _e=false;var ze=null;function We(){if(!ze){ze=function(){_e=true};window.addEventListener("scroll",ze);setInterval(function(){if(_e){_e=false;G(_().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){Ge(e)})}},200)}}function Ge(t){if(!o(t,"data-hx-revealed")&&b(t)){t.setAttribute("data-hx-revealed","true");var e=W(t);if(e.initialized){$(t,"revealed")}else{t.addEventListener("htmx:afterProcessNode",function(e){$(t,"revealed")},{once:true})}}}function Je(e,t,r){var n=w(r);for(var i=0;i=0){var t=Ye(n);setTimeout(function(){$e(s,r,n+1)},t)}};t.onopen=function(e){n=0};W(s).webSocket=t;t.addEventListener("message",function(e){if(Ze(s)){return}var t=e.data;xt(s,function(e){t=e.transformResponse(t,null,s)});var r=Gt(s);var n=g(t);var i=y(n.children);for(var a=0;a0){$(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(je(e,u)){e.preventDefault()}})}else{J(u,"htmx:noWebSocketSourceError")}}function Ye(e){var t=U.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}yt('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function Qe(e,t,r){var n=w(r);for(var i=0;iU.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){J(_().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function Et(e){if(!E()){return null}var t=S(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r=200&&this.status<400){$(_().body,"htmx:historyCacheMissLoad",i);var e=g(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=wt();var r=Gt(t);ye(t,e,r);Lt(r.tasks);bt=n;$(_().body,"htmx:historyRestore",{path:n})}else{J(_().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function At(e){Rt();e=e||location.pathname+location.search;var t=Et(e);if(t){var r=g(t.content);var n=wt();var i=Gt(n);ye(n,r,i);Lt(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);bt=e;$(_().body,"htmx:historyRestore",{path:e})}else{if(U.config.refreshOnHistoryMiss){window.location.reload(true)}else{Tt(e)}}}function Ht(e){var t=j(e,"hx-indicator");if(t==null){t=[e]}G(t,function(e){e.classList["add"].call(e.classList,U.config.requestClass)});return t}function Nt(e){G(e,function(e){e.classList["remove"].call(e.classList,U.config.requestClass)})}function It(e,t){for(var r=0;r=0}function _t(e,t){var r=t?t:z(e,"hx-swap");var n={swapStyle:W(e).boosted?"innerHTML":U.config.defaultSwapStyle,swapDelay:U.config.defaultSwapDelay,settleDelay:U.config.defaultSettleDelay};if(W(e).boosted&&!Vt(e)){n["show"]="top"}if(r){var i=w(r);if(i.length>0){n["swapStyle"]=i[0];for(var a=1;a0?l.join(":"):null;n["scroll"]=f;n["scrollTarget"]=u}if(o.indexOf("show:")===0){var c=o.substr(5);var l=c.split(":");var h=l.pop();var u=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=u}if(o.indexOf("focus-scroll:")===0){var d=o.substr("focus-scroll:".length);n["focusScroll"]=d=="true"}}}}return n}function zt(e){return z(e,"hx-encoding")==="multipart/form-data"||d(e,"form")&&f(e,"enctype")==="multipart/form-data"}function Wt(t,r,n){var i=null;xt(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(zt(r)){return jt(n)}else{return Ft(n)}}}function Gt(e){return{tasks:[],elts:[e]}}function Jt(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=Q(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var a=t.showTarget;if(t.showTarget==="window"){a="body"}i=Q(r,a)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:U.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:U.config.scrollBehavior})}}}function $t(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=V(e,t);if(i){var a=i.trim();var o=r;if(a.indexOf("javascript:")===0){a=a.substr(11);o=true}else if(a.indexOf("js:")===0){a=a.substr(3);o=true}if(a.indexOf("{")!==0){a="{"+a+"}"}var s;if(o){s=Zt(e,function(){return Function("return ("+a+")")()},{})}else{s=S(a)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return $t(u(e),t,r,n)}function Zt(e,t,r){if(U.config.allowEval){return t()}else{J(e,"htmx:evalDisallowedError");return r}}function Kt(e,t){return $t(e,"hx-vars",true,t)}function Yt(e,t){return $t(e,"hx-vals",false,t)}function Qt(e){return Y(Kt(e),Yt(e))}function er(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function tr(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){J(_().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function rr(e,t){return e.getAllResponseHeaders().match(t)}function nr(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||p(r,"String")){return ar(e,t,null,null,{targetOverride:D(r),returnPromise:true})}else{return ar(e,t,D(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:D(r.target),swapOverride:r.swap,returnPromise:true})}}else{return ar(e,t,null,null,{returnPromise:true})}}function ir(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function ar(e,t,n,f,r){var c=null;var h=null;r=r!=null?r:{};if(r.returnPromise&&typeof Promise!=="undefined"){var d=new Promise(function(e,t){c=e;h=t})}if(n==null){n=_().body}var v=r.handler||sr;if(!K(n)){return}var g=r.targetOverride||re(n);if(g==null||g==ee){J(n,"htmx:targetError",{target:V(n,"hx-target")});return}var p=n;var i=W(n);var a=z(n,"hx-sync");var m=null;var x=false;if(a){var y=a.split(":");var b=y[0].trim();if(b==="this"){p=te(n,"hx-sync")}else{p=Q(n,b)}a=(y[1]||"drop").trim();i=W(p);if(a==="drop"&&i.xhr&&i.abortable!==true){return}else if(a==="abort"){if(i.xhr){return}else{x=true}}else if(a==="replace"){$(p,"htmx:abort")}else if(a.indexOf("queue")===0){var w=a.split(" ");m=(w[1]||"last").trim()}}if(i.xhr){if(i.abortable){$(p,"htmx:abort")}else{if(m==null){if(f){var S=W(f);if(S&&S.triggerSpec&&S.triggerSpec.queue){m=S.triggerSpec.queue}}if(m==null){m="last"}}if(i.queuedRequests==null){i.queuedRequests=[]}if(m==="first"&&i.queuedRequests.length===0){i.queuedRequests.push(function(){ar(e,t,n,f,r)})}else if(m==="all"){i.queuedRequests.push(function(){ar(e,t,n,f,r)})}else if(m==="last"){i.queuedRequests=[];i.queuedRequests.push(function(){ar(e,t,n,f,r)})}return}}var o=new XMLHttpRequest;i.xhr=o;i.abortable=x;var s=function(){i.xhr=null;i.abortable=false;if(i.queuedRequests!=null&&i.queuedRequests.length>0){var e=i.queuedRequests.shift();e()}};var E=z(n,"hx-prompt");if(E){var C=prompt(E);if(C===null||!$(n,"htmx:prompt",{prompt:C,target:g})){Z(c);s();return d}}var R=z(n,"hx-confirm");if(R){if(!confirm(R)){Z(c);s();return d}}var O=Bt(n,g,C);if(r.headers){O=Y(O,r.headers)}var q=Pt(n,e);var L=q.errors;var T=q.values;if(r.values){T=Y(T,r.values)}var A=Qt(n);var H=Y(T,A);var N=Ut(H,n);if(e!=="get"&&!zt(n)){O["Content-Type"]="application/x-www-form-urlencoded"}if(t==null||t===""){t=_().location.href}var I=$t(n,"hx-request");var l={parameters:N,unfilteredParameters:H,headers:O,target:g,verb:e,errors:L,withCredentials:r.credentials||I.credentials||U.config.withCredentials,timeout:r.timeout||I.timeout||U.config.timeout,path:t,triggeringEvent:f};if(!$(n,"htmx:configRequest",l)){Z(c);s();return d}t=l.path;e=l.verb;O=l.headers;N=l.parameters;L=l.errors;if(L&&L.length>0){$(n,"htmx:validation:halted",l);Z(c);s();return d}var k=t.split("#");var M=k[0];var D=k[1];var P=null;if(e==="get"){P=M;var X=Object.keys(N).length!==0;if(X){if(P.indexOf("?")<0){P+="?"}else{P+="&"}P+=Ft(N);if(D){P+="#"+D}}o.open("GET",P,true)}else{o.open(e.toUpperCase(),t,true)}o.overrideMimeType("text/html");o.withCredentials=l.withCredentials;o.timeout=l.timeout;if(I.noHeaders){}else{for(var F in O){if(O.hasOwnProperty(F)){var j=O[F];er(o,F,j)}}}var u={xhr:o,target:g,requestConfig:l,etc:r,pathInfo:{requestPath:t,finalRequestPath:P||t,anchor:D}};o.onload=function(){try{var e=ir(n);u.pathInfo.responsePath=tr(o);v(n,u);Nt(B);$(n,"htmx:afterRequest",u);$(n,"htmx:afterOnLoad",u);if(!K(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(K(r)){t=r}}if(t){$(t,"htmx:afterRequest",u);$(t,"htmx:afterOnLoad",u)}}Z(c);s()}catch(e){J(n,"htmx:onLoadError",Y({error:e},u));throw e}};o.onerror=function(){Nt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendError",u);Z(h);s()};o.onabort=function(){Nt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:sendAbort",u);Z(h);s()};o.ontimeout=function(){Nt(B);J(n,"htmx:afterRequest",u);J(n,"htmx:timeout",u);Z(h);s()};if(!$(n,"htmx:beforeRequest",u)){Z(c);s();return d}var B=Ht(n);G(["loadstart","loadend","progress","abort"],function(t){G([o,o.upload],function(e){e.addEventListener(t,function(e){$(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});$(n,"htmx:beforeSend",u);o.send(e==="get"?null:Wt(o,n,N));return d}function or(e,t){var r=t.xhr;var n=null;var i=null;if(rr(r,/HX-Push:/i)){n=r.getResponseHeader("HX-Push");i="push"}else if(rr(r,/HX-Push-Url:/i)){n=r.getResponseHeader("HX-Push-Url");i="push"}else if(rr(r,/HX-Replace-Url:/i)){n=r.getResponseHeader("HX-Replace-Url");i="replace"}if(n){if(n==="false"){return{}}else{return{type:i,path:n}}}var a=t.pathInfo.finalRequestPath;var o=t.pathInfo.responsePath;var s=z(e,"hx-push-url");var f=z(e,"hx-replace-url");var c=W(e).boosted;var l=null;var u=null;if(s){l="push";u=s}else if(f){l="replace";u=f}else if(c){l="push";u=o||a}if(u){if(u==="false"){return{}}if(u==="true"){u=o||a}if(t.pathInfo.anchor&&u.indexOf("#")===-1){u=u+"#"+t.pathInfo.anchor}return{type:l,path:u}}else{return{}}}function sr(s,l){var u=l.xhr;var f=l.target;var n=l.etc;if(!$(s,"htmx:beforeOnLoad",l))return;if(rr(u,/HX-Trigger:/i)){Ce(u,"HX-Trigger",s)}if(rr(u,/HX-Location:/i)){Rt();var e=u.getResponseHeader("HX-Location");var c;if(e.indexOf("{")===0){c=S(e);e=c["path"];delete c["path"]}nr("GET",e,c).then(()=>{Ot(e)});return}if(rr(u,/HX-Redirect:/i)){location.href=u.getResponseHeader("HX-Redirect");return}if(rr(u,/HX-Refresh:/i)){if("true"===u.getResponseHeader("HX-Refresh")){location.reload();return}}if(rr(u,/HX-Retarget:/i)){l.target=_().querySelector(u.getResponseHeader("HX-Retarget"))}var h=or(s,l);var i=u.status>=200&&u.status<400&&u.status!==204;var d=u.response;var t=u.status>=400;var r=Y({shouldSwap:i,serverResponse:d,isError:t},l);if(!$(f,"htmx:beforeSwap",r))return;f=r.target;d=r.serverResponse;t=r.isError;l.failed=t;l.successful=!t;if(r.shouldSwap){if(u.status===286){De(s)}xt(s,function(e){d=e.transformResponse(d,u,s)});if(h.type){Rt()}var a=n.swapOverride;if(rr(u,/HX-Reswap:/i)){a=u.getResponseHeader("HX-Reswap")}var c=_t(s,a);f.classList.add(U.config.swappingClass);var o=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var n=Gt(f);Ee(c.swapStyle,f,s,d,n);if(t.elt&&!K(t.elt)&&t.elt.id){var r=document.getElementById(t.elt.id);var i={preventScroll:c.focusScroll!==undefined?!c.focusScroll:!U.config.defaultFocusScroll};if(r){if(t.start&&r.setSelectionRange){r.setSelectionRange(t.start,t.end)}r.focus(i)}}f.classList.remove(U.config.swappingClass);G(n.elts,function(e){if(e.classList){e.classList.add(U.config.settlingClass)}$(e,"htmx:afterSwap",l)});if(rr(u,/HX-Trigger-After-Swap:/i)){var a=s;if(!K(s)){a=_().body}Ce(u,"HX-Trigger-After-Swap",a)}var o=function(){G(n.tasks,function(e){e.call()});G(n.elts,function(e){if(e.classList){e.classList.remove(U.config.settlingClass)}$(e,"htmx:afterSettle",l)});if(h.type){if(h.type==="push"){Ot(h.path);$(_().body,"htmx:pushedIntoHistory",{path:h.path})}else{qt(h.path);$(_().body,"htmx:replacedInHistory",{path:h.path})}}if(l.pathInfo.anchor){var e=R("#"+l.pathInfo.anchor);if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}if(n.title){var t=R("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}Jt(n.elts,c);if(rr(u,/HX-Trigger-After-Settle:/i)){var r=s;if(!K(s)){r=_().body}Ce(u,"HX-Trigger-After-Settle",r)}};if(c.settleDelay>0){setTimeout(o,c.settleDelay)}else{o()}}catch(e){J(s,"htmx:swapError",l);throw e}};if(c.swapDelay>0){setTimeout(o,c.swapDelay)}else{o()}}if(t){J(s,"htmx:responseError",Y({error:"Response Status Error Code "+u.status+" from "+l.pathInfo.path},l))}}var lr={};function ur(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function fr(e,t){if(t.init){t.init(r)}lr[e]=Y(ur(),t)}function cr(e){delete lr[e]}function hr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=V(e,"hx-ext");if(t){G(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=lr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return hr(u(e),r,n)}function dr(e){if(_().readyState!=="loading"){e()}else{_().addEventListener("DOMContentLoaded",e)}}function vr(){if(U.config.includeIndicatorStyles!==false){_().head.insertAdjacentHTML("beforeend","")}}function gr(){var e=_().querySelector('meta[name="htmx-config"]');if(e){return S(e.content)}else{return null}}function pr(){var e=gr();if(e){U.config=Y(U.config,e)}}dr(function(){pr();vr();var e=_().body;vt(e);var t=_().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=W(t);if(r&&r.xhr){r.xhr.abort()}});window.onpopstate=function(e){if(e.state&&e.state.htmx){At();G(t,function(e){$(e,"htmx:restored",{document:_(),triggerEvent:$})})}};setTimeout(function(){$(e,"htmx:load",{})},0)});return U}()}); \ No newline at end of file diff --git a/src/common/templates/common/base.html b/src/common/templates/common/base.html index 81fe6f5..dacc53b 100644 --- a/src/common/templates/common/base.html +++ b/src/common/templates/common/base.html @@ -28,5 +28,7 @@ {% endblock %} + {% block extrascript %} + {% endblock %} diff --git a/src/purchase/static/purchase/spinner.gif b/src/purchase/static/purchase/spinner.gif new file mode 100644 index 0000000000000000000000000000000000000000..db63af8718826d784d407dbe52c538f80d6b8950 GIT binary patch literal 5534 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 literal 0 HcmV?d00001 diff --git a/src/purchase/templates/purchase/reports.html b/src/purchase/templates/purchase/reports.html index 00ed1fd..5db48f7 100644 --- a/src/purchase/templates/purchase/reports.html +++ b/src/purchase/templates/purchase/reports.html @@ -1,7 +1,5 @@ {% extends "common/base.html" %} -{% load static %} -{% load i18n %} -{% load purchase %} +{% load static i18n purchase django_htmx %} {% block extrahead %} @@ -29,18 +27,20 @@ {% endfor %} - {{ by_hour_plot|safe }} + {% include "purchase/snippets/htmx_plot.html" with url='purchase:by_hour_plot' %}

{% translate "Products" %}

{% include "purchase/snippets/report_products.html" %} - {{ products_plot|safe }} - {{ products_sold_pie|safe }} - {{ products_turnover_pie|safe }} + {% include "purchase/snippets/htmx_plot.html" with url='purchase:products_plots' %}

{% translate "Turnover by payment method" %}

{% include "purchase/snippets/report_payment_methods.html" %}

{% translate "Baskets without payment method" %}

{% include "purchase/snippets/report_no_payment_method.html" %} - +{% endblock %} + +{% block extrascript %} + + {% django_htmx_script %} {% endblock %} diff --git a/src/purchase/templates/purchase/snippets/htmx_plot.html b/src/purchase/templates/purchase/snippets/htmx_plot.html new file mode 100644 index 0000000..ebdb331 --- /dev/null +++ b/src/purchase/templates/purchase/snippets/htmx_plot.html @@ -0,0 +1,7 @@ +{% load static %} +
+ Spinner +
diff --git a/src/purchase/templates/purchase/snippets/plots.html b/src/purchase/templates/purchase/snippets/plots.html new file mode 100644 index 0000000..aa9734a --- /dev/null +++ b/src/purchase/templates/purchase/snippets/plots.html @@ -0,0 +1,3 @@ +{% for plot in plots %} + {{ plot|safe }} +{% endfor %} diff --git a/src/purchase/urls.py b/src/purchase/urls.py index 1c70749..ef4545b 100644 --- a/src/purchase/urls.py +++ b/src/purchase/urls.py @@ -1,7 +1,7 @@ from django.urls import path from purchase.views import delete_basket, list_baskets, new_basket, update_basket -from purchase.views.reports import reports +from purchase.views.reports import by_hour_plot_view, products_plots_view, reports app_name = "purchase" urlpatterns = [ @@ -10,4 +10,7 @@ urlpatterns = [ path("/update/", update_basket, name="update"), path("/delete/", delete_basket, name="delete"), path("reports/", reports, name="reports"), + # plots + path("reports/products_plots/", products_plots_view, name="products_plots"), + path("reports/by_hour_plot/", by_hour_plot_view, name="by_hour_plot"), ] diff --git a/src/purchase/views/reports.py b/src/purchase/views/reports.py index fcb51e4..f35fcd6 100644 --- a/src/purchase/views/reports.py +++ b/src/purchase/views/reports.py @@ -7,6 +7,7 @@ import numpy as np from django.conf import settings from django.contrib import messages from django.contrib.auth.decorators import permission_required +from django.shortcuts import render from django.template.response import TemplateResponse from django.utils.translation import gettext as _ from matplotlib import pyplot as plt @@ -18,7 +19,30 @@ from matplotlib.figure import Figure from purchase.models import Basket, PaymentMethod, Product, ProductQuerySet -matplotlib.use("TkAgg") +matplotlib.use("Agg") + + +@permission_required("purchase.view_basket") +def products_plots_view(request): + products = Product.objects.with_turnover().with_sold() + ( + products_plot, + products_sold_pie, + products_turnover_pie, + ) = get_products_plots(products) + context = { + "plots": [products_plot, products_sold_pie, products_turnover_pie], + } + return render(request, "purchase/snippets/plots.html", context) + + +@permission_required("purchase.view_basket") +def by_hour_plot_view(request): + baskets = list(Basket.objects.priced().order_by("created_at")) + context = { + "plots": [by_hour_plot(baskets)], + } + return render(request, "purchase/snippets/plots.html", context) @permission_required("purchase.view_basket") @@ -36,11 +60,6 @@ def reports(request): turnover_by_day = {date: Basket.objects.by_date(date).turnover() for date in dates} products = Product.objects.with_turnover().with_sold() - ( - products_plot, - products_sold_pie, - products_turnover_pie, - ) = get_products_plots(products) context = { "turnover": Basket.objects.turnover(), @@ -48,10 +67,6 @@ def reports(request): "average_basket": Basket.objects.average_basket(), "average_basket_by_day": average_basket_by_day, "products": products, - "products_plot": products_plot, - "products_sold_pie": products_sold_pie, - "products_turnover_pie": products_turnover_pie, - "by_hour_plot": by_hour_plot(baskets), "payment_methods": PaymentMethod.objects.with_turnover().with_sold(), "no_payment_method": Basket.objects.no_payment_method().priced(), }